tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsDisplayList.cpp (335287B)


      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 #include "nsDisplayList.h"
     14 
     15 #include <stdint.h>
     16 
     17 #include <algorithm>
     18 #include <limits>
     19 
     20 #include "ActiveLayerTracker.h"
     21 #include "BorderConsts.h"
     22 #include "ImageContainer.h"
     23 #include "LayerAnimationInfo.h"
     24 #include "StickyScrollContainer.h"
     25 #include "TextDrawTarget.h"
     26 #include "UnitTransforms.h"
     27 #include "gfxContext.h"
     28 #include "gfxMatrix.h"
     29 #include "gfxUtils.h"
     30 #include "imgIContainer.h"
     31 #include "mozilla/AnimationPerformanceWarning.h"
     32 #include "mozilla/AnimationUtils.h"
     33 #include "mozilla/AutoRestore.h"
     34 #include "mozilla/DisplayPortUtils.h"
     35 #include "mozilla/EffectCompositor.h"
     36 #include "mozilla/EffectSet.h"
     37 #include "mozilla/EventStateManager.h"
     38 #include "mozilla/Likely.h"
     39 #include "mozilla/LookAndFeel.h"
     40 #include "mozilla/OperatorNewExtensions.h"
     41 #include "mozilla/Preferences.h"
     42 #include "mozilla/PresShell.h"
     43 #include "mozilla/ProfilerLabels.h"
     44 #include "mozilla/ProfilerMarkers.h"
     45 #include "mozilla/SVGClipPathFrame.h"
     46 #include "mozilla/SVGIntegrationUtils.h"
     47 #include "mozilla/SVGMaskFrame.h"
     48 #include "mozilla/SVGObserverUtils.h"
     49 #include "mozilla/SVGUtils.h"
     50 #include "mozilla/ScrollContainerFrame.h"
     51 #include "mozilla/ServoBindings.h"
     52 #include "mozilla/ShapeUtils.h"
     53 #include "mozilla/StaticPrefs_apz.h"
     54 #include "mozilla/StaticPrefs_gfx.h"
     55 #include "mozilla/StaticPrefs_layers.h"
     56 #include "mozilla/StaticPrefs_layout.h"
     57 #include "mozilla/StaticPrefs_print.h"
     58 #include "mozilla/StyleAnimationValue.h"
     59 #include "mozilla/UniquePtr.h"
     60 #include "mozilla/ViewportFrame.h"
     61 #include "mozilla/ViewportUtils.h"
     62 #include "mozilla/dom/BrowserChild.h"
     63 #include "mozilla/dom/HTMLCanvasElement.h"
     64 #include "mozilla/dom/PerformanceMainThread.h"
     65 #include "mozilla/dom/RemoteBrowser.h"
     66 #include "mozilla/dom/SVGElement.h"
     67 #include "mozilla/dom/Selection.h"
     68 #include "mozilla/dom/ServiceWorkerRegistrar.h"
     69 #include "mozilla/dom/ServiceWorkerRegistration.h"
     70 #include "mozilla/dom/TouchEvent.h"
     71 #include "mozilla/dom/ViewTransition.h"
     72 #include "mozilla/gfx/2D.h"
     73 #include "mozilla/gfx/gfxVars.h"
     74 #include "mozilla/glean/GfxMetrics.h"
     75 #include "mozilla/layers/AnimationHelper.h"
     76 #include "mozilla/layers/CompositorThread.h"
     77 #include "mozilla/layers/InputAPZContext.h"
     78 #include "mozilla/layers/RenderRootStateManager.h"
     79 #include "mozilla/layers/StackingContextHelper.h"
     80 #include "mozilla/layers/TreeTraversal.h"
     81 #include "mozilla/layers/WebRenderBridgeChild.h"
     82 #include "mozilla/layers/WebRenderLayerManager.h"
     83 #include "mozilla/layers/WebRenderMessages.h"
     84 #include "mozilla/layers/WebRenderScrollData.h"
     85 #include "nsCSSProps.h"
     86 #include "nsCSSRendering.h"
     87 #include "nsCSSRenderingGradients.h"
     88 #include "nsCanvasFrame.h"
     89 #include "nsCaret.h"
     90 #include "nsCaseTreatment.h"
     91 #include "nsDOMTokenList.h"
     92 #include "nsEscape.h"
     93 #include "nsFocusManager.h"
     94 #include "nsIFrameInlines.h"
     95 #include "nsImageFrame.h"
     96 #include "nsLayoutUtils.h"
     97 #include "nsPresContextInlines.h"
     98 #include "nsPrintfCString.h"
     99 #include "nsRefreshDriver.h"
    100 #include "nsRegion.h"
    101 #include "nsSliderFrame.h"
    102 #include "nsStyleConsts.h"
    103 #include "nsStyleStructInlines.h"
    104 #include "nsStyleTransformMatrix.h"
    105 #include "nsSubDocumentFrame.h"
    106 #include "nsTableCellFrame.h"
    107 #include "nsTableColFrame.h"
    108 #include "nsTextFrame.h"
    109 #include "nsTextPaintStyle.h"
    110 #include "nsTransitionManager.h"
    111 
    112 namespace mozilla {
    113 
    114 using namespace dom;
    115 using namespace gfx;
    116 using namespace layout;
    117 using namespace layers;
    118 using namespace image;
    119 
    120 LazyLogModule sContentDisplayListLog("dl.content");
    121 LazyLogModule sParentDisplayListLog("dl.parent");
    122 
    123 LazyLogModule& GetLoggerByProcess() {
    124  return XRE_IsContentProcess() ? sContentDisplayListLog
    125                                : sParentDisplayListLog;
    126 }
    127 
    128 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    129 void AssertUniqueItem(nsDisplayItem* aItem) {
    130  for (nsDisplayItem* i : aItem->Frame()->DisplayItems()) {
    131    if (i != aItem && !i->HasDeletedFrame() && i->Frame() == aItem->Frame() &&
    132        i->GetPerFrameKey() == aItem->GetPerFrameKey()) {
    133      if (i->IsPreProcessedItem() || i->IsPreProcessed()) {
    134        continue;
    135      }
    136      MOZ_DIAGNOSTIC_CRASH("Duplicate display item!");
    137    }
    138  }
    139 }
    140 #endif
    141 
    142 bool ShouldBuildItemForEvents(const DisplayItemType aType) {
    143  return aType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO ||
    144         aType == DisplayItemType::TYPE_REMOTE ||
    145         (GetDisplayItemFlagsForType(aType) & TYPE_IS_CONTAINER);
    146 }
    147 
    148 static bool ItemTypeSupportsHitTesting(const DisplayItemType aType) {
    149  switch (aType) {
    150    case DisplayItemType::TYPE_BACKGROUND:
    151    case DisplayItemType::TYPE_BACKGROUND_COLOR:
    152    case DisplayItemType::TYPE_THEMED_BACKGROUND:
    153      return true;
    154    default:
    155      return false;
    156  }
    157 }
    158 
    159 void InitializeHitTestInfo(nsDisplayListBuilder* aBuilder,
    160                           nsPaintedDisplayItem* aItem,
    161                           const DisplayItemType aType) {
    162  if (ItemTypeSupportsHitTesting(aType)) {
    163    aItem->InitializeHitTestInfo(aBuilder);
    164  }
    165 }
    166 
    167 /* static */
    168 already_AddRefed<ActiveScrolledRoot> ActiveScrolledRoot::GetOrCreateASRForFrame(
    169    const ActiveScrolledRoot* aParent,
    170    ScrollContainerFrame* aScrollContainerFrame,
    171    nsTArray<RefPtr<ActiveScrolledRoot>>& aActiveScrolledRoots) {
    172  RefPtr<ActiveScrolledRoot> asr =
    173      aScrollContainerFrame->GetProperty(ActiveScrolledRootCache());
    174 
    175 #ifdef DEBUG
    176  if (asr && aActiveScrolledRoots.Contains(asr)) {
    177    // If this is the second time we are called for this frame in this same
    178    // paint, assert that we aren't changing any of the values. (The values can
    179    // change *between* paints, but not during one paint.)
    180    MOZ_ASSERT(asr->mParent == aParent);
    181    MOZ_ASSERT(asr->mFrame == aScrollContainerFrame);
    182    MOZ_ASSERT(asr->mKind == ASRKind::Scroll);
    183    MOZ_ASSERT(asr->mDepth == (aParent ? aParent->mDepth + 1 : 1));
    184  }
    185 #endif
    186 
    187  if (!asr) {
    188    asr = new ActiveScrolledRoot();
    189 
    190    RefPtr<ActiveScrolledRoot> ref = asr;
    191    aScrollContainerFrame->SetProperty(ActiveScrolledRootCache(),
    192                                       ref.forget().take());
    193    aActiveScrolledRoots.AppendElement(asr);
    194  }
    195  asr->mParent = aParent;
    196  asr->mFrame = aScrollContainerFrame;
    197  asr->mKind = ASRKind::Scroll;
    198  asr->mDepth = aParent ? aParent->mDepth + 1 : 1;
    199 
    200  return asr.forget();
    201 }
    202 
    203 /* static */
    204 already_AddRefed<ActiveScrolledRoot>
    205 ActiveScrolledRoot::GetOrCreateASRForStickyFrame(
    206    const ActiveScrolledRoot* aParent, nsIFrame* aStickyFrame,
    207    nsTArray<RefPtr<ActiveScrolledRoot>>& aActiveScrolledRoots) {
    208  aStickyFrame = aStickyFrame->FirstContinuation();
    209 
    210  RefPtr<ActiveScrolledRoot> asr =
    211      aStickyFrame->GetProperty(StickyActiveScrolledRootCache());
    212 
    213 #ifdef DEBUG
    214  if (asr && aActiveScrolledRoots.Contains(asr)) {
    215    // If this is the second time we are called for this frame in this same
    216    // paint, assert that we aren't changing any of the values. (The values can
    217    // change *between* paints, but not during one paint.)
    218    MOZ_ASSERT(asr->mParent == aParent);
    219    MOZ_ASSERT(asr->mFrame == aStickyFrame);
    220    MOZ_ASSERT(asr->mKind == ASRKind::Sticky);
    221    MOZ_ASSERT(asr->mDepth == (aParent ? aParent->mDepth + 1 : 1));
    222  }
    223 #endif
    224 
    225  if (!asr) {
    226    asr = new ActiveScrolledRoot();
    227 
    228    RefPtr<ActiveScrolledRoot> ref = asr;
    229    aStickyFrame->SetProperty(StickyActiveScrolledRootCache(),
    230                              ref.forget().take());
    231    aActiveScrolledRoots.AppendElement(asr);
    232  }
    233 
    234  asr->mParent = aParent;
    235  asr->mFrame = aStickyFrame;
    236  asr->mKind = ASRKind::Sticky;
    237  asr->mDepth = aParent ? aParent->mDepth + 1 : 1;
    238 
    239  return asr.forget();
    240 }
    241 
    242 /* static */
    243 bool ActiveScrolledRoot::IsAncestor(const ActiveScrolledRoot* aAncestor,
    244                                    const ActiveScrolledRoot* aDescendant) {
    245  if (!aAncestor) {
    246    // nullptr is the root
    247    return true;
    248  }
    249  if (Depth(aAncestor) > Depth(aDescendant)) {
    250    return false;
    251  }
    252  const ActiveScrolledRoot* asr = aDescendant;
    253  while (asr) {
    254    if (asr == aAncestor) {
    255      return true;
    256    }
    257    asr = asr->mParent;
    258  }
    259  return false;
    260 }
    261 
    262 /* static */
    263 bool ActiveScrolledRoot::IsProperAncestor(
    264    const ActiveScrolledRoot* aAncestor,
    265    const ActiveScrolledRoot* aDescendant) {
    266  return aAncestor != aDescendant && IsAncestor(aAncestor, aDescendant);
    267 }
    268 
    269 ScrollContainerFrame* ActiveScrolledRoot::ScrollFrameOrNull() const {
    270  if (mKind == ASRKind::Scroll) {
    271    ScrollContainerFrame* scrollFrame =
    272        static_cast<ScrollContainerFrame*>(mFrame);
    273    MOZ_ASSERT(scrollFrame);
    274    return scrollFrame;
    275  }
    276  return nullptr;
    277 }
    278 
    279 const ActiveScrolledRoot* ActiveScrolledRoot::GetNearestScrollASR() const {
    280  const ActiveScrolledRoot* ret = this;
    281 
    282  while (ret && ret->mKind != ASRKind::Scroll) {
    283    ret = ret->mParent;
    284  }
    285 
    286  if (!ret || ret->mKind != ASRKind::Scroll) {
    287    return nullptr;
    288  }
    289 
    290  return ret;
    291 }
    292 
    293 layers::ScrollableLayerGuid::ViewID
    294 ActiveScrolledRoot::GetNearestScrollASRViewId() const {
    295  const ActiveScrolledRoot* scrollASR = GetNearestScrollASR();
    296  if (scrollASR) {
    297    return scrollASR->GetViewId();
    298  }
    299  return ScrollableLayerGuid::NULL_SCROLL_ID;
    300 }
    301 
    302 /* static */
    303 const ActiveScrolledRoot* ActiveScrolledRoot::GetStickyASRFromFrame(
    304    nsIFrame* aStickyFrame) {
    305  return aStickyFrame->FirstContinuation()->GetProperty(
    306      StickyActiveScrolledRootCache());
    307 }
    308 
    309 /* static */
    310 nsCString ActiveScrolledRoot::ToString(
    311    const ActiveScrolledRoot* aActiveScrolledRoot) {
    312  nsAutoCString str;
    313  if (!aActiveScrolledRoot) {
    314    str.AppendPrintf("null");
    315    return str;
    316  }
    317  if (aActiveScrolledRoot->mKind == ASRKind::Sticky) {
    318    str.AppendPrintf("sticky ");
    319  }
    320  for (const auto* asr = aActiveScrolledRoot; asr; asr = asr->mParent) {
    321    str.AppendPrintf("<0x%p>", asr->mFrame);
    322    if (asr->mParent) {
    323      str.AppendLiteral(", ");
    324    }
    325  }
    326  return std::move(str);
    327 }
    328 
    329 ScrollableLayerGuid::ViewID ActiveScrolledRoot::ComputeViewId() const {
    330  const ActiveScrolledRoot* scrollASR = GetNearestScrollASR();
    331  MOZ_ASSERT(scrollASR,
    332             "ComputeViewId() called on ASR with no enclosing scroll frame");
    333  nsIContent* content = scrollASR->ScrollFrame()->GetContent();
    334  return nsLayoutUtils::FindOrCreateIDFor(content);
    335 }
    336 
    337 ActiveScrolledRoot::~ActiveScrolledRoot() {
    338  if (mFrame) {
    339    mFrame->RemoveProperty(mKind == ASRKind::Sticky
    340                               ? StickyActiveScrolledRootCache()
    341                               : ActiveScrolledRootCache());
    342  }
    343 }
    344 
    345 static uint64_t AddAnimationsForWebRender(
    346    nsDisplayItem* aItem, RenderRootStateManager* aManager,
    347    nsDisplayListBuilder* aDisplayListBuilder,
    348    const Maybe<LayoutDevicePoint>& aPosition = Nothing()) {
    349  auto* effects = EffectSet::GetForFrame(aItem->Frame(), aItem->GetType());
    350  if (!effects || effects->IsEmpty()) {
    351    // If there is no animation on the nsIFrame, that means
    352    //  1) we've never created any animations on this frame or
    353    //  2) the frame was reconstruced or
    354    //  3) all animations on the frame have finished
    355    // in such cases we don't need do anything here.
    356    //
    357    // Even if there is a WebRenderAnimationData for the display item type on
    358    // this frame, it's going to be discarded since it's not marked as being
    359    // used.
    360    return 0;
    361  }
    362 
    363  RefPtr<WebRenderAnimationData> animationData =
    364      aManager->CommandBuilder()
    365          .CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(aItem);
    366  AnimationInfo& animationInfo = animationData->GetAnimationInfo();
    367  nsIFrame* frame = aItem->Frame();
    368  animationInfo.AddAnimationsForDisplayItem(
    369      frame, aDisplayListBuilder, aItem, aItem->GetType(),
    370      aManager->LayerManager(), aPosition);
    371 
    372  // Note that animationsId can be 0 (uninitialized in AnimationInfo) if there
    373  // are no active animations.
    374  uint64_t animationsId = animationInfo.GetCompositorAnimationsId();
    375  if (!animationInfo.GetAnimations().IsEmpty()) {
    376    OpAddCompositorAnimations anim(
    377        CompositorAnimations(animationInfo.GetAnimations(), animationsId));
    378    aManager->WrBridge()->AddWebRenderParentCommand(anim);
    379    aManager->AddActiveCompositorAnimationId(animationsId);
    380  } else if (animationsId) {
    381    aManager->AddCompositorAnimationsIdForDiscard(animationsId);
    382    animationsId = 0;
    383  }
    384 
    385  return animationsId;
    386 }
    387 
    388 static bool GenerateAndPushTextMask(nsIFrame* aFrame, gfxContext* aContext,
    389                                    const nsRect& aFillRect,
    390                                    nsDisplayListBuilder* aBuilder) {
    391  if (aBuilder->IsForGenerateGlyphMask()) {
    392    return false;
    393  }
    394 
    395  SVGObserverUtils::GetAndObserveBackgroundClip(aFrame);
    396 
    397  // The main function of enabling background-clip:text property value.
    398  // When a nsDisplayBackgroundImage detects "text" bg-clip style, it will call
    399  // this function to
    400  // 1. Generate a mask by all descendant text frames
    401  // 2. Push the generated mask into aContext.
    402 
    403  gfxContext* sourceCtx = aContext;
    404  LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
    405      aFillRect, aFrame->PresContext()->AppUnitsPerDevPixel());
    406 
    407  // Create a mask surface.
    408  RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
    409  RefPtr<DrawTarget> maskDT = sourceTarget->CreateClippedDrawTarget(
    410      bounds.ToUnknownRect(), SurfaceFormat::A8);
    411  if (!maskDT || !maskDT->IsValid()) {
    412    return false;
    413  }
    414  gfxContext maskCtx(maskDT, /* aPreserveTransform */ true);
    415  maskCtx.Multiply(Matrix::Translation(bounds.TopLeft().ToUnknownPoint()));
    416 
    417  // Shade text shape into mask A8 surface.
    418  nsLayoutUtils::PaintFrame(
    419      &maskCtx, aFrame, nsRect(nsPoint(0, 0), aFrame->GetSize()),
    420      NS_RGB(255, 255, 255), nsDisplayListBuilderMode::GenerateGlyph);
    421 
    422  // Push the generated mask into aContext, so that the caller can pop and
    423  // blend with it.
    424 
    425  Matrix currentMatrix = sourceCtx->CurrentMatrix();
    426  Matrix invCurrentMatrix = currentMatrix;
    427  invCurrentMatrix.Invert();
    428 
    429  RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
    430  sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0,
    431                                   maskSurface, invCurrentMatrix);
    432 
    433  return true;
    434 }
    435 
    436 nsDisplayWrapper* nsDisplayWrapList::CreateShallowCopy(
    437    nsDisplayListBuilder* aBuilder) {
    438  const nsDisplayWrapList* wrappedItem = AsDisplayWrapList();
    439  MOZ_ASSERT(wrappedItem);
    440 
    441  // Create a new nsDisplayWrapList using a copy-constructor. This is done
    442  // to preserve the information about bounds.
    443  nsDisplayWrapper* wrapper =
    444      new (aBuilder) nsDisplayWrapper(aBuilder, *wrappedItem);
    445  wrapper->SetType(nsDisplayWrapper::ItemType());
    446  MOZ_ASSERT(wrapper);
    447 
    448  // Set the display list pointer of the new wrapper item to the display list
    449  // of the wrapped item.
    450  wrapper->mListPtr = wrappedItem->mListPtr;
    451  return wrapper;
    452 }
    453 
    454 nsDisplayWrapList* nsDisplayListBuilder::MergeItems(
    455    nsTArray<nsDisplayItem*>& aItems) {
    456  // For merging, we create a temporary item by cloning the last item of the
    457  // mergeable items list. This ensures that the temporary item will have the
    458  // correct frame and bounds.
    459  nsDisplayWrapList* last = aItems.PopLastElement()->AsDisplayWrapList();
    460  MOZ_ASSERT(last);
    461  nsDisplayWrapList* merged = last->Clone(this);
    462  MOZ_ASSERT(merged);
    463  AddTemporaryItem(merged);
    464 
    465  // Create nsDisplayWrappers that point to the internal display lists of the
    466  // items we are merging. These nsDisplayWrappers are added to the display list
    467  // of the temporary item.
    468  for (nsDisplayItem* item : aItems) {
    469    MOZ_ASSERT(item);
    470    MOZ_ASSERT(merged->CanMerge(item));
    471    merged->Merge(item);
    472    MOZ_ASSERT(item->AsDisplayWrapList());
    473    merged->GetChildren()->AppendToTop(
    474        static_cast<nsDisplayWrapList*>(item)->CreateShallowCopy(this));
    475  }
    476 
    477  merged->GetChildren()->AppendToTop(last->CreateShallowCopy(this));
    478 
    479  return merged;
    480 }
    481 
    482 // FIXME(emilio): This whole business should ideally not be needed at all, but
    483 // there are a variety of hard-to-deal-with caret invalidation issues, like
    484 // bug 1888583, and caret changes are relatively uncommon, enough that it
    485 // probably isn't worth chasing all them down.
    486 void nsDisplayListBuilder::InvalidateCaretFramesIfNeeded() {
    487  if (mPaintedCarets.IsEmpty()) {
    488    return;
    489  }
    490  size_t i = mPaintedCarets.Length();
    491  while (i--) {
    492    nsCaret* caret = mPaintedCarets[i];
    493    nsIFrame* oldCaret = caret->GetLastPaintedFrame();
    494    nsIFrame* currentCaret = caret->GetPaintGeometry();
    495    if (oldCaret == currentCaret) {
    496      // Keep tracking this caret, it hasn't changed.
    497      continue;
    498    }
    499    if (oldCaret) {
    500      oldCaret->MarkNeedsDisplayItemRebuild();
    501    }
    502    if (currentCaret) {
    503      currentCaret->MarkNeedsDisplayItemRebuild();
    504    }
    505    // If / when we paint this caret, we'll track it again.
    506    caret->SetLastPaintedFrame(nullptr);
    507    mPaintedCarets.RemoveElementAt(i);
    508  }
    509 }
    510 
    511 void nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::
    512    SetCurrentActiveScrolledRoot(
    513        const ActiveScrolledRoot* aActiveScrolledRoot) {
    514  MOZ_ASSERT(!mUsed);
    515 
    516  // Set the builder's mCurrentActiveScrolledRoot.
    517  mBuilder->mCurrentActiveScrolledRoot = aActiveScrolledRoot;
    518 
    519  // We also need to adjust the builder's mCurrentContainerASR.
    520  // mCurrentContainerASR needs to be an ASR that all the container's
    521  // contents have finite bounds with respect to. If aActiveScrolledRoot
    522  // is an ancestor ASR of mCurrentContainerASR, that means we need to
    523  // set mCurrentContainerASR to aActiveScrolledRoot, because otherwise
    524  // the items that will be created with aActiveScrolledRoot wouldn't
    525  // have finite bounds with respect to mCurrentContainerASR. There's one
    526  // exception, in the case where there's a content clip on the builder
    527  // that is scrolled by a descendant ASR of aActiveScrolledRoot. This
    528  // content clip will clip all items that are created while this
    529  // AutoCurrentActiveScrolledRootSetter exists. This means that the items
    530  // created during our lifetime will have finite bounds with respect to
    531  // the content clip's ASR, even if the items' actual ASR is an ancestor
    532  // of that. And it also means that mCurrentContainerASR only needs to be
    533  // set to the content clip's ASR and not all the way to aActiveScrolledRoot.
    534  // This case is tested by fixed-pos-scrolled-clip-opacity-layerize.html
    535  // and fixed-pos-scrolled-clip-opacity-inside-layerize.html.
    536 
    537  // finiteBoundsASR is the leafmost ASR that all items created during
    538  // object's lifetime have finite bounds with respect to.
    539  // TODO(bug 2001862): Explanation may need revising.
    540  const ActiveScrolledRoot* finiteBoundsASR = aActiveScrolledRoot;
    541  if (!mBuilder->IsInViewTransitionCapture()) {
    542    finiteBoundsASR =
    543        ActiveScrolledRoot::IsAncestor(aActiveScrolledRoot, mContentClipASR)
    544            ? mContentClipASR
    545            : aActiveScrolledRoot;
    546  }
    547 
    548  // mCurrentContainerASR is adjusted so that it's still an ancestor of
    549  // finiteBoundsASR.
    550  mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor(
    551      mBuilder->mCurrentContainerASR, finiteBoundsASR);
    552 
    553  // If we are entering out-of-flow content inside a CSS filter, mark
    554  // scroll frames wrt. which the content is fixed as containing such content.
    555  if (mBuilder->mFilterASR && ActiveScrolledRoot::IsAncestor(
    556                                  aActiveScrolledRoot, mBuilder->mFilterASR)) {
    557    for (const ActiveScrolledRoot* asr = mBuilder->mFilterASR;
    558         asr && asr != aActiveScrolledRoot; asr = asr->mParent) {
    559      if (ScrollContainerFrame* scrollFrame = asr->ScrollFrameOrNull()) {
    560        scrollFrame->SetHasOutOfFlowContentInsideFilter();
    561      }
    562    }
    563  }
    564 
    565  mUsed = true;
    566 }
    567 
    568 void nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::
    569    InsertScrollFrame(ScrollContainerFrame* aScrollContainerFrame) {
    570  MOZ_ASSERT(!mUsed);
    571  size_t descendantsEndIndex = mBuilder->mActiveScrolledRoots.Length();
    572  const ActiveScrolledRoot* parentASR = mBuilder->mCurrentActiveScrolledRoot;
    573  const ActiveScrolledRoot* asr =
    574      mBuilder->GetOrCreateActiveScrolledRoot(parentASR, aScrollContainerFrame);
    575  mBuilder->mCurrentActiveScrolledRoot = asr;
    576 
    577  // All child ASRs of parentASR that were created while this
    578  // AutoCurrentActiveScrolledRootSetter object was on the stack belong to us
    579  // now. Reparent them to asr.
    580  for (size_t i = mDescendantsStartIndex; i < descendantsEndIndex; i++) {
    581    ActiveScrolledRoot* descendantASR = mBuilder->mActiveScrolledRoots[i];
    582    if (ActiveScrolledRoot::IsAncestor(parentASR, descendantASR)) {
    583      descendantASR->IncrementDepth();
    584      if (descendantASR->mParent == parentASR) {
    585        descendantASR->mParent = asr;
    586      }
    587    }
    588  }
    589 
    590  mUsed = true;
    591 }
    592 
    593 nsDisplayListBuilder::AutoContainerASRTracker::AutoContainerASRTracker(
    594    nsDisplayListBuilder* aBuilder)
    595    : mBuilder(aBuilder), mSavedContainerASR(aBuilder->mCurrentContainerASR) {
    596  mBuilder->mCurrentContainerASR = mBuilder->mCurrentActiveScrolledRoot;
    597 }
    598 
    599 nsPresContext* nsDisplayListBuilder::CurrentPresContext() {
    600  return CurrentPresShellState()->mPresShell->GetPresContext();
    601 }
    602 
    603 /* static */
    604 nsRect nsDisplayListBuilder::OutOfFlowDisplayData::ComputeVisibleRectForFrame(
    605    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
    606    const nsRect& aVisibleRect, const nsRect& aDirtyRect,
    607    nsRect* aOutDirtyRect) {
    608  nsRect visible = aVisibleRect;
    609  nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
    610 
    611  bool inPartialUpdate =
    612      aBuilder->IsRetainingDisplayList() && aBuilder->IsPartialUpdate();
    613  if (MOZ_LIKELY(StaticPrefs::apz_allow_zooming()) &&
    614      aBuilder->IsPaintingToWindow() && !inPartialUpdate &&
    615      DisplayPortUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
    616    dirtyRectRelativeToDirtyFrame =
    617        nsRect(nsPoint(0, 0), aFrame->GetParent()->GetSize());
    618 
    619    // If there's a visual viewport size set, restrict the amount of the
    620    // fixed-position element we paint to the visual viewport. (In general
    621    // the fixed-position element can be as large as the layout viewport,
    622    // which at a high zoom level can cause us to paint too large of an
    623    // area.)
    624    PresShell* presShell = aFrame->PresShell();
    625    if (presShell->IsVisualViewportSizeSet()) {
    626      dirtyRectRelativeToDirtyFrame =
    627          nsRect(presShell->GetVisualViewportOffsetRelativeToLayoutViewport(),
    628                 presShell->GetVisualViewportSize());
    629      // But if we have a displayport, expand it to the displayport, so
    630      // that async-scrolling the visual viewport within the layout viewport
    631      // will not checkerboard.
    632      if (nsIFrame* rootScrollContainerFrame =
    633              presShell->GetRootScrollContainerFrame()) {
    634        nsRect displayport;
    635        // Note that the displayport here is already in the right coordinate
    636        // space: it's relative to the scroll port (= layout viewport), but
    637        // covers the visual viewport with some margins around it, which is
    638        // exactly what we want.
    639        if (DisplayPortUtils::GetDisplayPort(
    640                rootScrollContainerFrame->GetContent(), &displayport,
    641                DisplayPortOptions().With(ContentGeometryType::Fixed))) {
    642          dirtyRectRelativeToDirtyFrame = displayport;
    643        }
    644      }
    645    }
    646    visible = dirtyRectRelativeToDirtyFrame;
    647    if (StaticPrefs::apz_test_logging_enabled() &&
    648        presShell->GetDocument()->IsContentDocument()) {
    649      nsLayoutUtils::LogAdditionalTestData(
    650          aBuilder, "fixedPosDisplayport",
    651          ToString(CSSSize::FromAppUnits(visible)));
    652    }
    653  }
    654 
    655  *aOutDirtyRect = dirtyRectRelativeToDirtyFrame - aFrame->GetPosition();
    656  visible -= aFrame->GetPosition();
    657 
    658  nsRect overflowRect = aFrame->InkOverflowRect();
    659 
    660  if (aFrame->IsTransformed() && EffectCompositor::HasAnimationsForCompositor(
    661                                     aFrame, DisplayItemType::TYPE_TRANSFORM)) {
    662    /**
    663     * Add a fuzz factor to the overflow rectangle so that elements only
    664     * just out of view are pulled into the display list, so they can be
    665     * prerendered if necessary.
    666     */
    667    overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
    668  }
    669 
    670  visible.IntersectRect(visible, overflowRect);
    671  aOutDirtyRect->IntersectRect(*aOutDirtyRect, overflowRect);
    672 
    673  return visible;
    674 }
    675 
    676 nsDisplayListBuilder::Linkifier::Linkifier(nsDisplayListBuilder* aBuilder,
    677                                           nsIFrame* aFrame,
    678                                           nsDisplayList* aList)
    679    : mList(aList) {
    680  // Find the element that we need to check for link-ness, bailing out if
    681  // we can't find one.
    682  Element* elem = Element::FromNodeOrNull(aFrame->GetContent());
    683  if (!elem) {
    684    return;
    685  }
    686 
    687  // If the element has an id and/or name attribute, generate a destination
    688  // for possible internal linking.
    689  auto maybeGenerateDest = [&](const nsAtom* aAttr) {
    690    nsAutoString attrValue;
    691    elem->GetAttr(aAttr, attrValue);
    692    if (!attrValue.IsEmpty()) {
    693      NS_ConvertUTF16toUTF8 dest(attrValue);
    694      // Ensure that we only emit a given destination once, although there may
    695      // be multiple frames associated with a given element; we'll simply use
    696      // the first of them as the target of any links to it.
    697      // XXX(jfkthame) This prevents emitting duplicate destinations *on the
    698      // same page*, but does not prevent duplicates on subsequent pages, as
    699      // each new page is handled by a new temporary DisplayListBuilder. This
    700      // seems to be harmless in practice, though a bit wasteful of space. To
    701      // fix, we need to maintain the set of already-seen destinations globally
    702      // for the print job, rather than attached to the (per-page) builder.
    703      if (aBuilder->mDestinations.EnsureInserted(dest)) {
    704        auto* destination = MakeDisplayItem<nsDisplayDestination>(
    705            aBuilder, aFrame, dest.get(), aFrame->GetRect().TopLeft());
    706        mList->AppendToTop(destination);
    707      }
    708    }
    709  };
    710 
    711  if (StaticPrefs::print_save_as_pdf_internal_destinations_enabled()) {
    712    if (elem->HasID()) {
    713      maybeGenerateDest(nsGkAtoms::id);
    714    }
    715    if (elem->HasName()) {
    716      maybeGenerateDest(nsGkAtoms::name);
    717    }
    718  }
    719 
    720  // Links don't nest, so if the builder already has a destination, no need to
    721  // check for a link element here.
    722  if (!aBuilder->mLinkURI.IsEmpty() || !aBuilder->mLinkDest.IsEmpty()) {
    723    return;
    724  }
    725 
    726  // Check if we have actually found a link.
    727  if (!elem->IsLink()) {
    728    return;
    729  }
    730 
    731  nsCOMPtr<nsIURI> uri = elem->GetHrefURI();
    732  if (!uri) {
    733    return;
    734  }
    735 
    736  // Is it potentially a local (in-document) destination?
    737  bool hasRef, eqExRef;
    738  nsIURI* docURI;
    739  if (StaticPrefs::print_save_as_pdf_internal_destinations_enabled() &&
    740      NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef &&
    741      (docURI = aFrame->PresContext()->Document()->GetDocumentURI()) &&
    742      NS_SUCCEEDED(uri->EqualsExceptRef(docURI, &eqExRef)) && eqExRef) {
    743    // Try to get a local destination name. If this fails, we'll leave the
    744    // mLinkDest string empty, but still try to set mLinkURI below.
    745    if (NS_FAILED(uri->GetRef(aBuilder->mLinkDest))) {
    746      aBuilder->mLinkDest.Truncate();
    747    }
    748    // The destination name is simply a string; we don't want URL-escaping
    749    // applied to it.
    750    if (!aBuilder->mLinkDest.IsEmpty()) {
    751      NS_UnescapeURL(aBuilder->mLinkDest);
    752    }
    753  }
    754 
    755  if (NS_FAILED(uri->GetSpec(aBuilder->mLinkURI))) {
    756    aBuilder->mLinkURI.Truncate();
    757  }
    758 
    759  // If we didn't get either kind of destination, we won't try to linkify at
    760  // this level.
    761  if (aBuilder->mLinkDest.IsEmpty() && aBuilder->mLinkURI.IsEmpty()) {
    762    return;
    763  }
    764 
    765  // Record that we need to reset the builder's state on destruction.
    766  mBuilderToReset = aBuilder;
    767 }
    768 
    769 void nsDisplayListBuilder::Linkifier::MaybeAppendLink(
    770    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
    771  // Note that we may generate a link here even if the constructor bailed out
    772  // without updating aBuilder->mLinkURI/Dest, because it may have been set by
    773  // an ancestor that was associated with a link element.
    774  if (!aBuilder->mLinkURI.IsEmpty() || !aBuilder->mLinkDest.IsEmpty()) {
    775    auto* link = MakeDisplayItem<nsDisplayLink>(
    776        aBuilder, aFrame, aBuilder->mLinkDest.get(), aBuilder->mLinkURI.get(),
    777        aFrame->GetRect());
    778    mList->AppendToTop(link);
    779  }
    780 }
    781 
    782 uint32_t nsDisplayListBuilder::sPaintSequenceNumber(1);
    783 
    784 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
    785                                           nsDisplayListBuilderMode aMode,
    786                                           bool aBuildCaret,
    787                                           bool aRetainingDisplayList)
    788    : mReferenceFrame(aReferenceFrame),
    789      mIgnoreScrollFrame(nullptr),
    790      mCurrentActiveScrolledRoot(nullptr),
    791      mCurrentContainerASR(nullptr),
    792      mCurrentFrame(aReferenceFrame),
    793      mCurrentReferenceFrame(aReferenceFrame),
    794      mScrollInfoItemsForHoisting(nullptr),
    795      mFirstClipChainToDestroy(nullptr),
    796      mTableBackgroundSet(nullptr),
    797      mCurrentScrollParentId(ScrollableLayerGuid::NULL_SCROLL_ID),
    798      mCurrentScrollbarTarget(ScrollableLayerGuid::NULL_SCROLL_ID),
    799      mFilterASR(nullptr),
    800      mDirtyRect(-1, -1, -1, -1),
    801      mMode(aMode),
    802      mIsBuildingScrollbar(false),
    803      mCurrentScrollbarWillHaveLayer(false),
    804      mBuildCaret(aBuildCaret),
    805      mRetainingDisplayList(aRetainingDisplayList),
    806      mPartialUpdate(false),
    807      mIgnoreSuppression(false),
    808      mIncludeAllOutOfFlows(false),
    809      mDescendIntoSubdocuments(true),
    810      mSelectedFramesOnly(false),
    811      mAllowMergingAndFlattening(true),
    812      mInTransform(false),
    813      mInEventsOnly(false),
    814      mInFilter(false),
    815      mInViewTransitionCapture(false),
    816      mIsInChromePresContext(false),
    817      mSyncDecodeImages(false),
    818      mIsPaintingToWindow(false),
    819      mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)),
    820      mUseHighQualityScaling(false),
    821      mIsPaintingForWebRender(false),
    822      mAncestorHasApzAwareEventHandler(false),
    823      mHaveScrollableDisplayPort(false),
    824      mWindowDraggingAllowed(false),
    825      mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
    826      mForceLayerForScrollParent(false),
    827      mContainsNonMinimalDisplayPort(false),
    828      mBuildingInvisibleItems(false),
    829      mIsBuilding(false),
    830      mInInvalidSubtree(false),
    831      mDisablePartialUpdates(false),
    832      mPartialBuildFailed(false),
    833      mIsInActiveDocShell(false),
    834      mBuildAsyncZoomContainer(false),
    835      mIsRelativeToLayoutViewport(false),
    836      mUseOverlayScrollbars(false),
    837      mAlwaysLayerizeScrollbars(false),
    838      mIsDestroying(false) {
    839  MOZ_COUNT_CTOR(nsDisplayListBuilder);
    840 
    841  ShouldRebuildDisplayListDueToPrefChange();
    842 
    843  mUseOverlayScrollbars =
    844      !!LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars);
    845 
    846  mAlwaysLayerizeScrollbars =
    847      StaticPrefs::layout_scrollbars_always_layerize_track();
    848 
    849  static_assert(
    850      static_cast<uint32_t>(DisplayItemType::TYPE_MAX) < (1 << TYPE_BITS),
    851      "Check TYPE_MAX should not overflow");
    852 
    853  mIsReusingStackingContextItems =
    854      mRetainingDisplayList && StaticPrefs::layout_display_list_retain_sc();
    855 }
    856 
    857 void nsDisplayListBuilder::BeginFrame() {
    858  nsCSSRendering::BeginFrameTreesLocked();
    859 
    860  mIsPaintingToWindow = false;
    861  mUseHighQualityScaling = false;
    862  mIgnoreSuppression = false;
    863  mInTransform = false;
    864  mInFilter = false;
    865  mSyncDecodeImages = false;
    866 }
    867 
    868 void nsDisplayListBuilder::EndFrame() {
    869  NS_ASSERTION(!mInInvalidSubtree,
    870               "Someone forgot to cleanup mInInvalidSubtree!");
    871  mCurrentContainerASR = nullptr;
    872  mActiveScrolledRoots.Clear();
    873  FreeClipChains();
    874  FreeTemporaryItems();
    875  mAsyncScrollsWithAnchor.Clear();
    876  nsCSSRendering::EndFrameTreesLocked();
    877 }
    878 
    879 void nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame,
    880                                               const nsIFrame* aStopAtFrame) {
    881  mFramesMarkedForDisplay.AppendElement(aFrame);
    882  for (nsIFrame* f = aFrame; f;
    883       f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
    884    if (f->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
    885      return;
    886    }
    887    f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
    888    if (f == aStopAtFrame) {
    889      // we've reached a frame that we know will be painted, so we can stop.
    890      break;
    891    }
    892  }
    893 }
    894 
    895 void nsDisplayListBuilder::AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame) {
    896  mFramesMarkedForDisplayIfVisible.AppendElement(aFrame);
    897 }
    898 
    899 static void MarkFrameForDisplayIfVisibleInternal(nsIFrame* aFrame,
    900                                                 const nsIFrame* aStopAtFrame) {
    901  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetDisplayListParent(f)) {
    902    if (f->ForceDescendIntoIfVisible()) {
    903      return;
    904    }
    905    f->SetForceDescendIntoIfVisible(true);
    906 
    907    // This condition must match the condition in
    908    // nsLayoutUtils::GetParentOrPlaceholderFor which is used by
    909    // nsLayoutUtils::GetDisplayListParent
    910    if (f->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) && !f->GetPrevInFlow()) {
    911      nsIFrame* parent = f->GetParent();
    912      if (parent && !parent->ForceDescendIntoIfVisible()) {
    913        // If the GetDisplayListParent call is going to walk to a placeholder,
    914        // in rare cases the placeholder might be contained in a different
    915        // continuation from the oof. So we have to make sure to mark the oofs
    916        // parent. In the common case this doesn't make us do any extra work,
    917        // just changes the order in which we visit the frames since walking
    918        // through placeholders will walk through the parent, and we stop when
    919        // we find a ForceDescendIntoIfVisible bit set.
    920        MarkFrameForDisplayIfVisibleInternal(parent, aStopAtFrame);
    921      }
    922    }
    923 
    924    if (f == aStopAtFrame) {
    925      // we've reached a frame that we know will be painted, so we can stop.
    926      break;
    927    }
    928  }
    929 }
    930 
    931 void nsDisplayListBuilder::MarkFrameForDisplayIfVisible(
    932    nsIFrame* aFrame, const nsIFrame* aStopAtFrame) {
    933  AddFrameMarkedForDisplayIfVisible(aFrame);
    934 
    935  MarkFrameForDisplayIfVisibleInternal(aFrame, aStopAtFrame);
    936 }
    937 
    938 void nsDisplayListBuilder::SetIsRelativeToLayoutViewport() {
    939  mIsRelativeToLayoutViewport = true;
    940  UpdateShouldBuildAsyncZoomContainer();
    941 }
    942 
    943 void nsDisplayListBuilder::ForceLayerForScrollParent() {
    944  mForceLayerForScrollParent = true;
    945  mNumActiveScrollframesEncountered++;
    946 }
    947 
    948 void nsDisplayListBuilder::UpdateShouldBuildAsyncZoomContainer() {
    949  const Document* document = mReferenceFrame->PresContext()->Document();
    950  mBuildAsyncZoomContainer = !mIsRelativeToLayoutViewport &&
    951                             !document->Fullscreen() &&
    952                             nsLayoutUtils::AllowZoomingForDocument(document);
    953 
    954  // If mIsRelativeToLayoutViewport == false, hit-testing on this
    955  // display list will take into account the pres shell resolution.
    956  // If we're not building an async zoom container (meaning, the
    957  // resolution will not take effect visually), the resolution better
    958  // be 1.0, otherwise rendering and hit-testing are out of sync.
    959 #ifdef DEBUG
    960  if (!mIsRelativeToLayoutViewport && !mBuildAsyncZoomContainer) {
    961    MOZ_ASSERT(document->GetPresShell()->GetResolution() == 1.0f);
    962  }
    963 #endif
    964 }
    965 
    966 // Certain prefs may cause display list items to be added or removed when they
    967 // are toggled. In those cases, we need to fully rebuild the display list.
    968 bool nsDisplayListBuilder::ShouldRebuildDisplayListDueToPrefChange() {
    969  // If we transition between wrapping the RCD-RSF contents into an async
    970  // zoom container vs. not, we need to rebuild the display list. This only
    971  // happens when the zooming or container scrolling prefs are toggled
    972  // (manually by the user, or during test setup).
    973  bool didBuildAsyncZoomContainer = mBuildAsyncZoomContainer;
    974  UpdateShouldBuildAsyncZoomContainer();
    975 
    976  bool hadOverlayScrollbarsLastTime = mUseOverlayScrollbars;
    977  mUseOverlayScrollbars =
    978      !!LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars);
    979 
    980  bool alwaysLayerizedScrollbarsLastTime = mAlwaysLayerizeScrollbars;
    981  mAlwaysLayerizeScrollbars =
    982      StaticPrefs::layout_scrollbars_always_layerize_track();
    983 
    984  bool oldShouldActivateAllScrollFrames = mShouldActivateAllScrollFrames;
    985  mShouldActivateAllScrollFrames =
    986      ScrollContainerFrame::ShouldActivateAllScrollFrames(nullptr,
    987                                                          mReferenceFrame);
    988 
    989  if (didBuildAsyncZoomContainer != mBuildAsyncZoomContainer) {
    990    return true;
    991  }
    992 
    993  if (hadOverlayScrollbarsLastTime != mUseOverlayScrollbars) {
    994    return true;
    995  }
    996 
    997  if (alwaysLayerizedScrollbarsLastTime != mAlwaysLayerizeScrollbars) {
    998    return true;
    999  }
   1000 
   1001  if (oldShouldActivateAllScrollFrames != mShouldActivateAllScrollFrames) {
   1002    return true;
   1003  }
   1004 
   1005  return false;
   1006 }
   1007 
   1008 void nsDisplayListBuilder::AddScrollContainerFrameToNotify(
   1009    ScrollContainerFrame* aScrollContainerFrame) {
   1010  mScrollContainerFramesToNotify.insert(aScrollContainerFrame);
   1011 }
   1012 
   1013 void nsDisplayListBuilder::NotifyAndClearScrollContainerFrames() {
   1014  for (const auto& it : mScrollContainerFramesToNotify) {
   1015    it->NotifyApzTransaction();
   1016  }
   1017  mScrollContainerFramesToNotify.clear();
   1018 }
   1019 
   1020 bool nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(
   1021    nsIFrame* aDirtyFrame, nsIFrame* aFrame, const nsRect& aVisibleRect,
   1022    const nsRect& aDirtyRect) {
   1023  MOZ_ASSERT(aFrame->GetParent() == aDirtyFrame);
   1024  nsRect dirty;
   1025  nsRect visible = OutOfFlowDisplayData::ComputeVisibleRectForFrame(
   1026      this, aFrame, aVisibleRect, aDirtyRect, &dirty);
   1027  if (!aFrame->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) &&
   1028      visible.IsEmpty()) {
   1029    return false;
   1030  }
   1031 
   1032  // Only MarkFrameForDisplay if we're dirty. If this is a nested out-of-flow
   1033  // frame, then it will also mark any outer frames to ensure that building
   1034  // reaches the dirty feame.
   1035  if (!dirty.IsEmpty() || aFrame->ForceDescendIntoIfVisible()) {
   1036    MarkFrameForDisplay(aFrame, aDirtyFrame);
   1037  }
   1038 
   1039  return true;
   1040 }
   1041 
   1042 static void UnmarkFrameForDisplay(nsIFrame* aFrame,
   1043                                  const nsIFrame* aStopAtFrame) {
   1044  for (nsIFrame* f = aFrame; f;
   1045       f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
   1046    if (!f->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
   1047      return;
   1048    }
   1049    f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   1050    if (f == aStopAtFrame) {
   1051      // we've reached a frame that we know will be painted, so we can stop.
   1052      break;
   1053    }
   1054  }
   1055 }
   1056 
   1057 static void UnmarkFrameForDisplayIfVisible(nsIFrame* aFrame) {
   1058  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetDisplayListParent(f)) {
   1059    if (!f->ForceDescendIntoIfVisible()) {
   1060      return;
   1061    }
   1062    f->SetForceDescendIntoIfVisible(false);
   1063 
   1064    // This condition must match the condition in
   1065    // nsLayoutUtils::GetParentOrPlaceholderFor which is used by
   1066    // nsLayoutUtils::GetDisplayListParent
   1067    if (f->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) && !f->GetPrevInFlow()) {
   1068      nsIFrame* parent = f->GetParent();
   1069      if (parent && parent->ForceDescendIntoIfVisible()) {
   1070        // If the GetDisplayListParent call is going to walk to a placeholder,
   1071        // in rare cases the placeholder might be contained in a different
   1072        // continuation from the oof. So we have to make sure to mark the oofs
   1073        // parent. In the common case this doesn't make us do any extra work,
   1074        // just changes the order in which we visit the frames since walking
   1075        // through placeholders will walk through the parent, and we stop when
   1076        // we find a ForceDescendIntoIfVisible bit set.
   1077        UnmarkFrameForDisplayIfVisible(f);
   1078      }
   1079    }
   1080  }
   1081 }
   1082 
   1083 nsDisplayListBuilder::~nsDisplayListBuilder() {
   1084  NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
   1085               "All frames should have been unmarked");
   1086  NS_ASSERTION(mFramesWithOOFData.Length() == 0,
   1087               "All OOF data should have been removed");
   1088  NS_ASSERTION(mPresShellStates.Length() == 0,
   1089               "All presshells should have been exited");
   1090 
   1091  DisplayItemClipChain* c = mFirstClipChainToDestroy;
   1092  while (c) {
   1093    DisplayItemClipChain* next = c->mNextClipChainToDestroy;
   1094    c->DisplayItemClipChain::~DisplayItemClipChain();
   1095    c = next;
   1096  }
   1097 
   1098  MOZ_COUNT_DTOR(nsDisplayListBuilder);
   1099 }
   1100 
   1101 uint32_t nsDisplayListBuilder::GetBackgroundPaintFlags() {
   1102  uint32_t flags = 0;
   1103  if (mSyncDecodeImages) {
   1104    flags |= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES;
   1105  }
   1106  if (mIsPaintingToWindow) {
   1107    flags |= nsCSSRendering::PAINTBG_TO_WINDOW;
   1108  }
   1109  if (mUseHighQualityScaling) {
   1110    flags |= nsCSSRendering::PAINTBG_HIGH_QUALITY_SCALING;
   1111  }
   1112  return flags;
   1113 }
   1114 
   1115 // TODO(emilio): Maybe unify BackgroundPaintFlags and IamgeRendererFlags.
   1116 uint32_t nsDisplayListBuilder::GetImageRendererFlags() const {
   1117  uint32_t flags = 0;
   1118  if (mSyncDecodeImages) {
   1119    flags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
   1120  }
   1121  if (mIsPaintingToWindow) {
   1122    flags |= nsImageRenderer::FLAG_PAINTING_TO_WINDOW;
   1123  }
   1124  if (mUseHighQualityScaling) {
   1125    flags |= nsImageRenderer::FLAG_HIGH_QUALITY_SCALING;
   1126  }
   1127  return flags;
   1128 }
   1129 
   1130 uint32_t nsDisplayListBuilder::GetImageDecodeFlags() const {
   1131  uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
   1132  if (mSyncDecodeImages) {
   1133    flags |= imgIContainer::FLAG_SYNC_DECODE;
   1134  } else {
   1135    flags |= imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
   1136  }
   1137  if (mIsPaintingToWindow || mUseHighQualityScaling) {
   1138    flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
   1139  }
   1140  return flags;
   1141 }
   1142 
   1143 nsCaret* nsDisplayListBuilder::GetCaret() {
   1144  RefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret();
   1145  return caret;
   1146 }
   1147 
   1148 void nsDisplayListBuilder::IncrementPresShellPaintCount(PresShell* aPresShell) {
   1149  if (mIsPaintingToWindow) {
   1150    aPresShell->IncrementPaintCount();
   1151  }
   1152 }
   1153 
   1154 void nsDisplayListBuilder::EnterPresShell(const nsIFrame* aReferenceFrame,
   1155                                          bool aPointerEventsNoneDoc) {
   1156  PresShellState* state = mPresShellStates.AppendElement();
   1157  state->mPresShell = aReferenceFrame->PresShell();
   1158  state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
   1159  state->mFirstFrameWithOOFData = mFramesWithOOFData.Length();
   1160 
   1161  ScrollContainerFrame* sf = state->mPresShell->GetRootScrollContainerFrame();
   1162  if (sf && IsInSubdocument()) {
   1163    // We are forcing a rebuild of nsDisplayCanvasBackgroundColor to make sure
   1164    // that the canvas background color will be set correctly, and that only one
   1165    // unscrollable item will be created.
   1166    // This is done to avoid, for example, a case where only scrollbar frames
   1167    // are invalidated - we would skip creating nsDisplayCanvasBackgroundColor
   1168    // and possibly end up with an extra nsDisplaySolidColor item.
   1169    // We skip this for the root document, since we don't want to use
   1170    // MarkFrameForDisplayIfVisible before ComputeRebuildRegion. We'll
   1171    // do it manually there.
   1172    nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
   1173    if (canvasFrame) {
   1174      MarkFrameForDisplayIfVisible(canvasFrame, aReferenceFrame);
   1175    }
   1176  }
   1177 
   1178 #ifdef DEBUG
   1179  state->mAutoLayoutPhase.emplace(aReferenceFrame->PresContext(),
   1180                                  nsLayoutPhase::DisplayListBuilding);
   1181 #endif
   1182 
   1183  if (!IsForEventDelivery()) {
   1184    state->mPresShell->UpdateCanvasBackground();
   1185  }
   1186 
   1187  bool buildCaret = mBuildCaret;
   1188  if (mIgnoreSuppression || !state->mPresShell->IsPaintingSuppressed()) {
   1189    state->mIsBackgroundOnly = false;
   1190  } else {
   1191    state->mIsBackgroundOnly = true;
   1192    buildCaret = false;
   1193  }
   1194 
   1195  bool pointerEventsNone = aPointerEventsNoneDoc;
   1196  if (IsInSubdocument()) {
   1197    pointerEventsNone |= mPresShellStates[mPresShellStates.Length() - 2]
   1198                             .mInsidePointerEventsNoneDoc;
   1199  }
   1200  state->mInsidePointerEventsNoneDoc = pointerEventsNone;
   1201 
   1202  state->mPresShellIgnoreScrollFrame =
   1203      state->mPresShell->IgnoringViewportScrolling()
   1204          ? state->mPresShell->GetRootScrollContainerFrame()
   1205          : nullptr;
   1206 
   1207  nsPresContext* pc = aReferenceFrame->PresContext();
   1208  mIsInChromePresContext = pc->IsChrome();
   1209  nsIDocShell* docShell = pc->GetDocShell();
   1210 
   1211  if (docShell) {
   1212    docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
   1213  }
   1214 
   1215  state->mTouchEventPrefEnabledDoc = dom::TouchEvent::PrefEnabled(docShell);
   1216 
   1217  if (auto* vt = pc->Document()->GetActiveViewTransition()) {
   1218    // We must ensure captured view transition elements, including offscreen
   1219    // elements, are reached for display list building.
   1220    AutoTArray<nsIFrame*, 32> capturedFrames;
   1221    vt->GetCapturedFrames(capturedFrames);
   1222    for (const auto& frame : capturedFrames) {
   1223      MarkFrameForDisplay(frame, aReferenceFrame);
   1224    }
   1225  }
   1226 
   1227  if (!buildCaret) {
   1228    return;
   1229  }
   1230 
   1231  state->mCaretFrame = [&]() -> nsIFrame* {
   1232    RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
   1233    nsIFrame* currentCaret = caret->GetPaintGeometry(&mCaretRect);
   1234    if (!currentCaret) {
   1235      return nullptr;
   1236    }
   1237 
   1238    // Check if the display root for the caret matches the display root that
   1239    // we're painting, and only use it if it matches. Likely we only need this
   1240    // for carets inside popups.
   1241    if (nsLayoutUtils::GetDisplayRootFrame(currentCaret) !=
   1242        nsLayoutUtils::GetDisplayRootFrame(aReferenceFrame)) {
   1243      return nullptr;
   1244    }
   1245 
   1246    // Caret frames add visual area to their frame, but we don't update the
   1247    // overflow area. Use flags to make sure we build display items for that
   1248    // frame instead.
   1249    MOZ_ASSERT(currentCaret->PresShell() == state->mPresShell);
   1250    MarkFrameForDisplay(currentCaret, aReferenceFrame);
   1251    caret->SetLastPaintedFrame(currentCaret);
   1252    if (!mPaintedCarets.Contains(caret)) {
   1253      mPaintedCarets.AppendElement(std::move(caret));
   1254    }
   1255    return currentCaret;
   1256  }();
   1257 }
   1258 
   1259 // A non-blank paint is a paint that does not just contain the canvas
   1260 // background.
   1261 static bool DisplayListIsNonBlank(nsDisplayList* aList) {
   1262  for (nsDisplayItem* i : *aList) {
   1263    switch (i->GetType()) {
   1264      case DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO:
   1265      case DisplayItemType::TYPE_CANVAS_BACKGROUND_IMAGE:
   1266        continue;
   1267      case DisplayItemType::TYPE_SOLID_COLOR:
   1268      case DisplayItemType::TYPE_BACKGROUND:
   1269      case DisplayItemType::TYPE_BACKGROUND_COLOR:
   1270        if (i->Frame()->IsCanvasFrame()) {
   1271          continue;
   1272        }
   1273        return true;
   1274      default:
   1275        return true;
   1276    }
   1277  }
   1278  return false;
   1279 }
   1280 
   1281 // A contentful paint is a paint that does contains DOM content (text,
   1282 // images, non-blank canvases, SVG): "First Contentful Paint entry
   1283 // contains a DOMHighResTimeStamp reporting the time when the browser
   1284 // first rendered any text, image (including background images),
   1285 // non-white canvas or SVG. This excludes any content of iframes, but
   1286 // includes text with pending webfonts. This is the first time users
   1287 // could start consuming page content."
   1288 static bool DisplayListIsContentful(nsDisplayListBuilder* aBuilder,
   1289                                    nsDisplayList* aList) {
   1290  for (nsDisplayItem* i : *aList) {
   1291    DisplayItemType type = i->GetType();
   1292    nsDisplayList* children = i->GetChildren();
   1293 
   1294    switch (type) {
   1295      case DisplayItemType::TYPE_SUBDOCUMENT:  // iframes are ignored
   1296        break;
   1297      // CANVASes check if they may have been modified (as a stand-in
   1298      // actually tracking all modifications)
   1299      default:
   1300        if (i->IsContentful()) {
   1301          bool dummy;
   1302          nsRect bound = i->GetBounds(aBuilder, &dummy);
   1303          if (!bound.IsEmpty()) {
   1304            return true;
   1305          }
   1306        }
   1307        if (children) {
   1308          if (DisplayListIsContentful(aBuilder, children)) {
   1309            return true;
   1310          }
   1311        }
   1312        break;
   1313    }
   1314  }
   1315  return false;
   1316 }
   1317 
   1318 void nsDisplayListBuilder::LeavePresShell(const nsIFrame* aReferenceFrame,
   1319                                          nsDisplayList* aPaintedContents) {
   1320  NS_ASSERTION(
   1321      CurrentPresShellState()->mPresShell == aReferenceFrame->PresShell(),
   1322      "Presshell mismatch");
   1323 
   1324  if (mIsPaintingToWindow && aPaintedContents) {
   1325    nsPresContext* pc = aReferenceFrame->PresContext();
   1326    if (!pc->HadNonBlankPaint()) {
   1327      if (!CurrentPresShellState()->mIsBackgroundOnly &&
   1328          DisplayListIsNonBlank(aPaintedContents)) {
   1329        pc->NotifyNonBlankPaint();
   1330      }
   1331    }
   1332    nsRootPresContext* rootPresContext = pc->GetRootPresContext();
   1333    if (!pc->HasStoppedGeneratingLCP() && rootPresContext) {
   1334      if (!CurrentPresShellState()->mIsBackgroundOnly) {
   1335        if (pc->HasEverBuiltInvisibleText() ||
   1336            DisplayListIsContentful(this, aPaintedContents)) {
   1337          pc->NotifyContentfulPaint();
   1338        }
   1339      }
   1340    }
   1341  }
   1342 
   1343  ResetMarkedFramesForDisplayList(aReferenceFrame);
   1344  mPresShellStates.RemoveLastElement();
   1345 
   1346  if (!mPresShellStates.IsEmpty()) {
   1347    nsPresContext* pc = CurrentPresContext();
   1348    nsIDocShell* docShell = pc->GetDocShell();
   1349    if (docShell) {
   1350      docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
   1351    }
   1352    mIsInChromePresContext = pc->IsChrome();
   1353  } else {
   1354    for (uint32_t i = 0; i < mFramesMarkedForDisplayIfVisible.Length(); ++i) {
   1355      UnmarkFrameForDisplayIfVisible(mFramesMarkedForDisplayIfVisible[i]);
   1356    }
   1357    mFramesMarkedForDisplayIfVisible.SetLength(0);
   1358  }
   1359 }
   1360 
   1361 void nsDisplayListBuilder::FreeClipChains() {
   1362  // Iterate the clip chains from newest to oldest (forward
   1363  // iteration), so that we destroy descendants first which
   1364  // will drop the ref count on their ancestors.
   1365  DisplayItemClipChain** indirect = &mFirstClipChainToDestroy;
   1366 
   1367  while (*indirect) {
   1368    if (!(*indirect)->mRefCount) {
   1369      DisplayItemClipChain* next = (*indirect)->mNextClipChainToDestroy;
   1370 
   1371      mClipDeduplicator.erase(*indirect);
   1372      (*indirect)->DisplayItemClipChain::~DisplayItemClipChain();
   1373      Destroy(DisplayListArenaObjectId::CLIPCHAIN, *indirect);
   1374 
   1375      *indirect = next;
   1376    } else {
   1377      indirect = &(*indirect)->mNextClipChainToDestroy;
   1378    }
   1379  }
   1380 }
   1381 
   1382 void nsDisplayListBuilder::FreeTemporaryItems() {
   1383  for (nsDisplayItem* i : mTemporaryItems) {
   1384    // Temporary display items are not added to the frames.
   1385    MOZ_ASSERT(i->Frame());
   1386    i->RemoveFrame(i->Frame());
   1387    i->Destroy(this);
   1388  }
   1389 
   1390  mTemporaryItems.Clear();
   1391 }
   1392 
   1393 void nsDisplayListBuilder::ResetMarkedFramesForDisplayList(
   1394    const nsIFrame* aReferenceFrame) {
   1395  // Unmark and pop off the frames marked for display in this pres shell.
   1396  uint32_t firstFrameForShell =
   1397      CurrentPresShellState()->mFirstFrameMarkedForDisplay;
   1398  for (uint32_t i = firstFrameForShell; i < mFramesMarkedForDisplay.Length();
   1399       ++i) {
   1400    UnmarkFrameForDisplay(mFramesMarkedForDisplay[i], aReferenceFrame);
   1401  }
   1402  mFramesMarkedForDisplay.SetLength(firstFrameForShell);
   1403 
   1404  firstFrameForShell = CurrentPresShellState()->mFirstFrameWithOOFData;
   1405  for (uint32_t i = firstFrameForShell; i < mFramesWithOOFData.Length(); ++i) {
   1406    mFramesWithOOFData[i]->RemoveProperty(OutOfFlowDisplayDataProperty());
   1407  }
   1408  mFramesWithOOFData.SetLength(firstFrameForShell);
   1409 }
   1410 
   1411 void nsDisplayListBuilder::ClearFixedBackgroundDisplayData() {
   1412  CurrentPresShellState()->mFixedBackgroundDisplayData = Nothing();
   1413 }
   1414 
   1415 void nsDisplayListBuilder::MarkFramesForDisplayList(
   1416    nsIFrame* aDirtyFrame, const nsFrameList& aFrames) {
   1417  nsRect visibleRect = GetVisibleRect();
   1418  nsRect dirtyRect = GetDirtyRect();
   1419 
   1420  // If we are entering content that is fixed to the RCD-RSF, we are
   1421  // crossing the async zoom container boundary, and need to convert from
   1422  // visual to layout coordinates.
   1423  if (ViewportFrame* viewportFrame = do_QueryFrame(aDirtyFrame)) {
   1424    if (IsForEventDelivery() && ShouldBuildAsyncZoomContainer() &&
   1425        viewportFrame->PresContext()->IsRootContentDocumentCrossProcess()) {
   1426      if (viewportFrame->PresShell()->GetRootScrollContainerFrame()) {
   1427 #ifdef DEBUG
   1428        for (nsIFrame* f : aFrames) {
   1429          MOZ_ASSERT(ViewportUtils::IsZoomedContentRoot(f));
   1430        }
   1431 #endif
   1432        visibleRect = ViewportUtils::VisualToLayout(visibleRect,
   1433                                                    viewportFrame->PresShell());
   1434        dirtyRect = ViewportUtils::VisualToLayout(dirtyRect,
   1435                                                  viewportFrame->PresShell());
   1436      }
   1437 #ifdef DEBUG
   1438      else {
   1439        // This is an edge case that should only happen if we are in a
   1440        // document with a XUL root element so that it does not have a root
   1441        // scroll frame but it has fixed pos content and all of the frames in
   1442        // aFrames are that fixed pos content.
   1443        for (nsIFrame* f : aFrames) {
   1444          MOZ_ASSERT(!ViewportUtils::IsZoomedContentRoot(f) &&
   1445                     f->GetParent() == aDirtyFrame &&
   1446                     f->StyleDisplay()->mPosition ==
   1447                         StylePositionProperty::Fixed);
   1448        }
   1449        // There's no root scroll frame so there can't be any zooming or async
   1450        // panning so we don't need to adjust the visible and dirty rects.
   1451      }
   1452 #endif
   1453    }
   1454  }
   1455 
   1456  bool markedFrames = false;
   1457  for (nsIFrame* e : aFrames) {
   1458    // Skip the AccessibleCaret frame when building no caret.
   1459    if (!IsBuildingCaret()) {
   1460      nsIContent* content = e->GetContent();
   1461      if (content && content->IsInNativeAnonymousSubtree() &&
   1462          content->IsElement()) {
   1463        const nsAttrValue* classes = content->AsElement()->GetClasses();
   1464        if (classes &&
   1465            classes->Contains(nsGkAtoms::mozAccessiblecaret, eCaseMatters)) {
   1466          continue;
   1467        }
   1468      }
   1469    }
   1470    if (MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, visibleRect, dirtyRect)) {
   1471      markedFrames = true;
   1472    }
   1473  }
   1474 
   1475  if (markedFrames) {
   1476    // mClipState.GetClipChainForContainingBlockDescendants can return pointers
   1477    // to objects on the stack, so we need to clone the chain.
   1478    const DisplayItemClipChain* clipChain =
   1479        CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
   1480    const DisplayItemClipChain* combinedClipChain =
   1481        mClipState.GetCurrentCombinedClipChain(this);
   1482    const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
   1483 
   1484    OutOfFlowDisplayData* data = new OutOfFlowDisplayData(
   1485        clipChain, combinedClipChain, asr, mCurrentScrollParentId, visibleRect,
   1486        dirtyRect, mInViewTransitionCapture);
   1487    aDirtyFrame->SetProperty(
   1488        nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
   1489    mFramesWithOOFData.AppendElement(aDirtyFrame);
   1490  }
   1491 
   1492  if (!aDirtyFrame->GetParent()) {
   1493    // This is the viewport frame of aDirtyFrame's presshell.
   1494    // Store the current display data so that it can be used for fixed
   1495    // background images.
   1496    NS_ASSERTION(
   1497        CurrentPresShellState()->mPresShell == aDirtyFrame->PresShell(),
   1498        "Presshell mismatch");
   1499    MOZ_ASSERT(!CurrentPresShellState()->mFixedBackgroundDisplayData,
   1500               "already traversed this presshell's root frame?");
   1501 
   1502    const DisplayItemClipChain* clipChain =
   1503        CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
   1504    const DisplayItemClipChain* combinedClipChain =
   1505        mClipState.GetCurrentCombinedClipChain(this);
   1506    const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
   1507    CurrentPresShellState()->mFixedBackgroundDisplayData.emplace(
   1508        clipChain, combinedClipChain, asr, mCurrentScrollParentId,
   1509        GetVisibleRect(), GetDirtyRect(), mInViewTransitionCapture);
   1510  }
   1511 }
   1512 
   1513 /**
   1514 * Mark all preserve-3d children with
   1515 * NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO to make sure
   1516 * nsIFrame::BuildDisplayListForChild() would visit them.  Also compute
   1517 * dirty rect for preserve-3d children.
   1518 *
   1519 * @param aDirtyFrame is the frame to mark children extending context.
   1520 */
   1521 void nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(
   1522    nsIFrame* aDirtyFrame) {
   1523  for (const auto& childList : aDirtyFrame->ChildLists()) {
   1524    for (nsIFrame* child : childList.mList) {
   1525      if (child->Combines3DTransformWithAncestors()) {
   1526        MarkFrameForDisplay(child, aDirtyFrame);
   1527      }
   1528 
   1529      if (child->IsBlockWrapper()) {
   1530        // Mark preserve-3d frames inside the block wrapper.
   1531        MarkPreserve3DFramesForDisplayList(child);
   1532      }
   1533    }
   1534  }
   1535 }
   1536 
   1537 ActiveScrolledRoot* nsDisplayListBuilder::GetOrCreateActiveScrolledRoot(
   1538    const ActiveScrolledRoot* aParent,
   1539    ScrollContainerFrame* aScrollContainerFrame) {
   1540  RefPtr<ActiveScrolledRoot> asr = ActiveScrolledRoot::GetOrCreateASRForFrame(
   1541      aParent, aScrollContainerFrame, mActiveScrolledRoots);
   1542  return asr;
   1543 }
   1544 
   1545 ActiveScrolledRoot*
   1546 nsDisplayListBuilder::GetOrCreateActiveScrolledRootForSticky(
   1547    const ActiveScrolledRoot* aParent, nsIFrame* aStickyFrame) {
   1548  RefPtr<ActiveScrolledRoot> asr =
   1549      ActiveScrolledRoot::GetOrCreateASRForStickyFrame(aParent, aStickyFrame,
   1550                                                       mActiveScrolledRoots);
   1551  return asr;
   1552 }
   1553 
   1554 const DisplayItemClipChain* nsDisplayListBuilder::AllocateDisplayItemClipChain(
   1555    const DisplayItemClip& aClip, const ActiveScrolledRoot* aASR,
   1556    const DisplayItemClipChain* aParent) {
   1557  MOZ_DIAGNOSTIC_ASSERT(!(aParent && aParent->mOnStack));
   1558  void* p = Allocate(sizeof(DisplayItemClipChain),
   1559                     DisplayListArenaObjectId::CLIPCHAIN);
   1560  DisplayItemClipChain* c = new (KnownNotNull, p)
   1561      DisplayItemClipChain(aClip, aASR, aParent, mFirstClipChainToDestroy);
   1562 #if defined(DEBUG) || defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
   1563  c->mOnStack = false;
   1564 #endif
   1565  auto result = mClipDeduplicator.insert(c);
   1566  if (!result.second) {
   1567    // An equivalent clip chain item was already created, so let's return that
   1568    // instead. Destroy the one we just created.
   1569    // Note that this can cause clip chains from different coordinate systems to
   1570    // collapse into the same clip chain object, because clip chains do not keep
   1571    // track of the reference frame that they were created in.
   1572    c->DisplayItemClipChain::~DisplayItemClipChain();
   1573    Destroy(DisplayListArenaObjectId::CLIPCHAIN, c);
   1574    return *(result.first);
   1575  }
   1576  mFirstClipChainToDestroy = c;
   1577  return c;
   1578 }
   1579 
   1580 struct ClipChainItem {
   1581  DisplayItemClip clip;
   1582  const ActiveScrolledRoot* asr;
   1583 };
   1584 
   1585 static const DisplayItemClipChain* FindCommonAncestorClipForIntersection(
   1586    const DisplayItemClipChain* aOne, const DisplayItemClipChain* aTwo) {
   1587  for (const ActiveScrolledRoot* asr =
   1588           ActiveScrolledRoot::PickDescendant(aOne->mASR, aTwo->mASR);
   1589       asr; asr = asr->mParent) {
   1590    if (aOne == aTwo) {
   1591      return aOne;
   1592    }
   1593    if (aOne->mASR == asr) {
   1594      aOne = aOne->mParent;
   1595    }
   1596    if (aTwo->mASR == asr) {
   1597      aTwo = aTwo->mParent;
   1598    }
   1599    if (!aOne) {
   1600      return aTwo;
   1601    }
   1602    if (!aTwo) {
   1603      return aOne;
   1604    }
   1605  }
   1606  return nullptr;
   1607 }
   1608 
   1609 const DisplayItemClipChain* nsDisplayListBuilder::CreateClipChainIntersection(
   1610    const DisplayItemClipChain* aAncestor,
   1611    const DisplayItemClipChain* aLeafClip1,
   1612    const DisplayItemClipChain* aLeafClip2) {
   1613  AutoTArray<ClipChainItem, 8> intersectedClips;
   1614 
   1615  const DisplayItemClipChain* clip1 = aLeafClip1;
   1616  const DisplayItemClipChain* clip2 = aLeafClip2;
   1617 
   1618  const ActiveScrolledRoot* asr = ActiveScrolledRoot::PickDescendant(
   1619      clip1 ? clip1->mASR : nullptr, clip2 ? clip2->mASR : nullptr);
   1620 
   1621  // Build up the intersection from the leaf to the root and put it into
   1622  // intersectedClips. The loop below will convert intersectedClips into an
   1623  // actual DisplayItemClipChain.
   1624  // (We need to do this in two passes because we need the parent clip in order
   1625  // to create the DisplayItemClipChain object, but the parent clip has not
   1626  // been created at that point.)
   1627  while (!aAncestor || asr != aAncestor->mASR) {
   1628    if (clip1 && clip1->mASR == asr) {
   1629      if (clip2 && clip2->mASR == asr) {
   1630        DisplayItemClip intersection = clip1->mClip;
   1631        intersection.IntersectWith(clip2->mClip);
   1632        intersectedClips.AppendElement(ClipChainItem{intersection, asr});
   1633        clip2 = clip2->mParent;
   1634      } else {
   1635        intersectedClips.AppendElement(ClipChainItem{clip1->mClip, asr});
   1636      }
   1637      clip1 = clip1->mParent;
   1638    } else if (clip2 && clip2->mASR == asr) {
   1639      intersectedClips.AppendElement(ClipChainItem{clip2->mClip, asr});
   1640      clip2 = clip2->mParent;
   1641    }
   1642    if (!asr) {
   1643      MOZ_ASSERT(!aAncestor, "We should have exited this loop earlier");
   1644      break;
   1645    }
   1646    asr = asr->mParent;
   1647  }
   1648 
   1649  // Convert intersectedClips into a DisplayItemClipChain.
   1650  const DisplayItemClipChain* parentSC = aAncestor;
   1651  for (auto& sc : Reversed(intersectedClips)) {
   1652    parentSC = AllocateDisplayItemClipChain(sc.clip, sc.asr, parentSC);
   1653  }
   1654  return parentSC;
   1655 }
   1656 
   1657 const DisplayItemClipChain* nsDisplayListBuilder::CreateClipChainIntersection(
   1658    const DisplayItemClipChain* aLeafClip1,
   1659    const DisplayItemClipChain* aLeafClip2) {
   1660  // aLeafClip2 might be a reference to a clip on the stack. We need to make
   1661  // sure that CreateClipChainIntersection will allocate the actual intersected
   1662  // clip in the builder's arena, so for the aLeafClip1 == nullptr case,
   1663  // we supply nullptr as the common ancestor so that
   1664  // CreateClipChainIntersection clones the whole chain.
   1665  const DisplayItemClipChain* ancestorClip =
   1666      aLeafClip1 ? FindCommonAncestorClipForIntersection(aLeafClip1, aLeafClip2)
   1667                 : nullptr;
   1668 
   1669  return CreateClipChainIntersection(ancestorClip, aLeafClip1, aLeafClip2);
   1670 }
   1671 
   1672 const DisplayItemClipChain* nsDisplayListBuilder::CopyWholeChain(
   1673    const DisplayItemClipChain* aClipChain) {
   1674  return CreateClipChainIntersection(nullptr, aClipChain, nullptr);
   1675 }
   1676 
   1677 const nsIFrame* nsDisplayListBuilder::FindReferenceFrameFor(
   1678    const nsIFrame* aFrame, nsPoint* aOffset) const {
   1679  auto MaybeApplyAdditionalOffset = [&]() {
   1680    if (auto offset = AdditionalOffset()) {
   1681      *aOffset += *offset;
   1682    }
   1683  };
   1684 
   1685  if (aFrame == mCurrentFrame) {
   1686    if (aOffset) {
   1687      *aOffset = mCurrentOffsetToReferenceFrame;
   1688    }
   1689    return mCurrentReferenceFrame;
   1690  }
   1691 
   1692  for (const nsIFrame* f = aFrame; f;
   1693       f = nsLayoutUtils::GetCrossDocParentFrameInProcess(f)) {
   1694    if (f == mReferenceFrame || f->IsTransformed()) {
   1695      if (aOffset) {
   1696        *aOffset = aFrame->GetOffsetToCrossDoc(f);
   1697        MaybeApplyAdditionalOffset();
   1698      }
   1699      return f;
   1700    }
   1701  }
   1702 
   1703  if (aOffset) {
   1704    *aOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
   1705    MaybeApplyAdditionalOffset();
   1706  }
   1707 
   1708  return mReferenceFrame;
   1709 }
   1710 
   1711 // Sticky frames are active if their nearest scrollable frame is also active.
   1712 static bool IsStickyFrameActive(nsDisplayListBuilder* aBuilder,
   1713                                nsIFrame* aFrame) {
   1714  MOZ_ASSERT(aFrame->StyleDisplay()->mPosition ==
   1715             StylePositionProperty::Sticky);
   1716 
   1717  auto* ssc = StickyScrollContainer::GetOrCreateForFrame(aFrame);
   1718  return ssc && ssc->ScrollContainer()->IsMaybeAsynchronouslyScrolled();
   1719 }
   1720 
   1721 bool nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame,
   1722                                                  nsIFrame** aParent) {
   1723  if (aFrame == mReferenceFrame) {
   1724    return true;
   1725  }
   1726 
   1727  if (!IsPaintingToWindow()) {
   1728    if (aParent) {
   1729      *aParent = nsLayoutUtils::GetCrossDocParentFrameInProcess(aFrame);
   1730    }
   1731    return false;
   1732  }
   1733 
   1734  nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(aFrame);
   1735  if (!parent) {
   1736    return true;
   1737  }
   1738  *aParent = parent;
   1739 
   1740  if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Sticky &&
   1741      IsStickyFrameActive(this, aFrame)) {
   1742    return true;
   1743  }
   1744 
   1745  if (aFrame->IsTransformed()) {
   1746    if (EffectCompositor::HasAnimationsForCompositor(
   1747            aFrame, DisplayItemType::TYPE_TRANSFORM)) {
   1748      return true;
   1749    }
   1750  }
   1751 
   1752  if (parent->IsScrollContainerOrSubclass()) {
   1753    ScrollContainerFrame* sf = do_QueryFrame(parent);
   1754    if (sf->GetScrolledFrame() == aFrame) {
   1755      MOZ_ASSERT(!aFrame->IsTransformed());
   1756      return sf->IsMaybeAsynchronouslyScrolled();
   1757    }
   1758  }
   1759 
   1760  return false;
   1761 }
   1762 
   1763 nsIFrame* nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(
   1764    nsIFrame* aFrame) {
   1765  MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDocInProcess(
   1766      RootReferenceFrame(), aFrame));
   1767  nsIFrame* cursor = aFrame;
   1768  while (cursor != RootReferenceFrame()) {
   1769    nsIFrame* next;
   1770    if (IsAnimatedGeometryRoot(cursor, &next)) {
   1771      return cursor;
   1772    }
   1773    cursor = next;
   1774  }
   1775  return cursor;
   1776 }
   1777 
   1778 static nsRect ApplyAllClipNonRoundedIntersection(
   1779    const DisplayItemClipChain* aClipChain, const nsRect& aRect) {
   1780  nsRect result = aRect;
   1781  while (aClipChain) {
   1782    result = aClipChain->mClip.ApplyNonRoundedIntersection(result);
   1783    aClipChain = aClipChain->mParent;
   1784  }
   1785  return result;
   1786 }
   1787 
   1788 void nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame) {
   1789  if (!mWindowDraggingAllowed || !IsForPainting()) {
   1790    return;
   1791  }
   1792 
   1793  const nsStyleUIReset* styleUI = aFrame->StyleUIReset();
   1794  if (styleUI->mWindowDragging == StyleWindowDragging::Default) {
   1795    // This frame has the default value and doesn't influence the window
   1796    // dragging region.
   1797    return;
   1798  }
   1799 
   1800  if (!aFrame->StyleVisibility()->IsVisible()) {
   1801    // Invisible frames don't influence the window dragging region.
   1802    return;
   1803  }
   1804 
   1805  LayoutDeviceToLayoutDeviceMatrix4x4 referenceFrameToRootReferenceFrame;
   1806 
   1807  // The const_cast is for nsLayoutUtils::GetTransformToAncestor.
   1808  nsIFrame* referenceFrame =
   1809      const_cast<nsIFrame*>(FindReferenceFrameFor(aFrame));
   1810 
   1811  if (IsInTransform()) {
   1812    // Only support 2d rectilinear transforms. Transform support is needed for
   1813    // the horizontal flip transform that's applied to the urlbar textbox in
   1814    // RTL mode - it should be able to exclude itself from the draggable region.
   1815    referenceFrameToRootReferenceFrame =
   1816        ViewAs<LayoutDeviceToLayoutDeviceMatrix4x4>(
   1817            nsLayoutUtils::GetTransformToAncestor(RelativeTo{referenceFrame},
   1818                                                  RelativeTo{mReferenceFrame})
   1819                .GetMatrix());
   1820    Matrix referenceFrameToRootReferenceFrame2d;
   1821    if (!referenceFrameToRootReferenceFrame.Is2D(
   1822            &referenceFrameToRootReferenceFrame2d) ||
   1823        !referenceFrameToRootReferenceFrame2d.IsRectilinear()) {
   1824      return;
   1825    }
   1826  } else {
   1827    MOZ_ASSERT(referenceFrame == mReferenceFrame,
   1828               "referenceFrameToRootReferenceFrame needs to be adjusted");
   1829  }
   1830 
   1831  // We do some basic visibility checking on the frame's border box here.
   1832  // We intersect it both with the current dirty rect and with the current
   1833  // clip. Either one is just a conservative approximation on its own, but
   1834  // their intersection luckily works well enough for our purposes, so that
   1835  // we don't have to do full-blown visibility computations.
   1836  // The most important case we need to handle is the scrolled-off tab:
   1837  // If the tab bar overflows, tab parts that are clipped by the scrollbox
   1838  // should not be allowed to interfere with the window dragging region. Using
   1839  // just the current DisplayItemClip is not enough to cover this case
   1840  // completely because clips are reset while building stacking context
   1841  // contents, so for example we'd fail to clip frames that have a clip path
   1842  // applied to them. But the current dirty rect doesn't get reset in that
   1843  // case, so we use it to make this case work.
   1844  nsRect borderBox = aFrame->GetRectRelativeToSelf().Intersect(mVisibleRect);
   1845  borderBox += ToReferenceFrame(aFrame);
   1846  const DisplayItemClipChain* clip =
   1847      ClipState().GetCurrentCombinedClipChain(this);
   1848  borderBox = ApplyAllClipNonRoundedIntersection(clip, borderBox);
   1849  if (borderBox.IsEmpty()) {
   1850    return;
   1851  }
   1852 
   1853  LayoutDeviceRect devPixelBorderBox = LayoutDevicePixel::FromAppUnits(
   1854      borderBox, aFrame->PresContext()->AppUnitsPerDevPixel());
   1855 
   1856  LayoutDeviceRect transformedDevPixelBorderBox =
   1857      TransformBy(referenceFrameToRootReferenceFrame, devPixelBorderBox);
   1858  transformedDevPixelBorderBox.Round();
   1859  LayoutDeviceIntRect transformedDevPixelBorderBoxInt;
   1860 
   1861  if (!transformedDevPixelBorderBox.ToIntRect(
   1862          &transformedDevPixelBorderBoxInt)) {
   1863    return;
   1864  }
   1865 
   1866  LayoutDeviceIntRegion& region =
   1867      styleUI->mWindowDragging == StyleWindowDragging::Drag
   1868          ? mWindowDraggingRegion
   1869          : mWindowNoDraggingRegion;
   1870 
   1871  if (!IsRetainingDisplayList()) {
   1872    region.OrWith(transformedDevPixelBorderBoxInt);
   1873    return;
   1874  }
   1875 
   1876  gfx::IntRect rect(transformedDevPixelBorderBoxInt.ToUnknownRect());
   1877  if (styleUI->mWindowDragging == StyleWindowDragging::Drag) {
   1878    mRetainedWindowDraggingRegion.Add(aFrame, rect);
   1879  } else {
   1880    mRetainedWindowNoDraggingRegion.Add(aFrame, rect);
   1881  }
   1882 }
   1883 
   1884 LayoutDeviceIntRegion nsDisplayListBuilder::GetWindowDraggingRegion() const {
   1885  LayoutDeviceIntRegion result;
   1886  if (!IsRetainingDisplayList()) {
   1887    result.Sub(mWindowDraggingRegion, mWindowNoDraggingRegion);
   1888    return result;
   1889  }
   1890 
   1891  LayoutDeviceIntRegion dragRegion =
   1892      mRetainedWindowDraggingRegion.ToLayoutDeviceIntRegion();
   1893 
   1894  LayoutDeviceIntRegion noDragRegion =
   1895      mRetainedWindowNoDraggingRegion.ToLayoutDeviceIntRegion();
   1896 
   1897  result.Sub(dragRegion, noDragRegion);
   1898  return result;
   1899 }
   1900 
   1901 void nsDisplayTransform::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
   1902  nsPaintedDisplayItem::AddSizeOfExcludingThis(aSizes);
   1903  aSizes.mLayoutRetainedDisplayListSize +=
   1904      aSizes.mState.mMallocSizeOf(mTransformPreserves3D.get());
   1905 }
   1906 
   1907 void nsDisplayListBuilder::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
   1908  mPool.AddSizeOfExcludingThis(aSizes, Arena::ArenaKind::DisplayList);
   1909 
   1910  size_t n = 0;
   1911  MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
   1912  n += mDocumentWillChangeBudgets.ShallowSizeOfExcludingThis(mallocSizeOf);
   1913  n += mFrameWillChangeBudgets.ShallowSizeOfExcludingThis(mallocSizeOf);
   1914  n += mRetainedWindowDraggingRegion.SizeOfExcludingThis(mallocSizeOf);
   1915  n += mRetainedWindowNoDraggingRegion.SizeOfExcludingThis(mallocSizeOf);
   1916  n += mRetainedWindowOpaqueRegion.SizeOfExcludingThis(mallocSizeOf);
   1917  // XXX can't measure mClipDeduplicator since it uses std::unordered_set.
   1918 
   1919  aSizes.mLayoutRetainedDisplayListSize += n;
   1920 }
   1921 
   1922 void RetainedDisplayList::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
   1923  for (nsDisplayItem* item : *this) {
   1924    item->AddSizeOfExcludingThis(aSizes);
   1925    if (RetainedDisplayList* children = item->GetChildren()) {
   1926      children->AddSizeOfExcludingThis(aSizes);
   1927    }
   1928  }
   1929 
   1930  size_t n = 0;
   1931 
   1932  n += mDAG.mDirectPredecessorList.ShallowSizeOfExcludingThis(
   1933      aSizes.mState.mMallocSizeOf);
   1934  n += mDAG.mNodesInfo.ShallowSizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
   1935  n += mOldItems.ShallowSizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
   1936 
   1937  aSizes.mLayoutRetainedDisplayListSize += n;
   1938 }
   1939 
   1940 size_t nsDisplayListBuilder::WeakFrameRegion::SizeOfExcludingThis(
   1941    MallocSizeOf aMallocSizeOf) const {
   1942  size_t n = 0;
   1943  n += mFrames.ShallowSizeOfExcludingThis(aMallocSizeOf);
   1944  for (const auto& frame : mFrames) {
   1945    const UniquePtr<WeakFrame>& weakFrame = frame.mWeakFrame;
   1946    n += aMallocSizeOf(weakFrame.get());
   1947  }
   1948  n += mRects.ShallowSizeOfExcludingThis(aMallocSizeOf);
   1949  return n;
   1950 }
   1951 
   1952 /**
   1953 * Removes modified frames and rects from this WeakFrameRegion.
   1954 */
   1955 void nsDisplayListBuilder::WeakFrameRegion::RemoveModifiedFramesAndRects() {
   1956  MOZ_ASSERT(mFrames.Length() == mRects.Length());
   1957 
   1958  uint32_t i = 0;
   1959  uint32_t length = mFrames.Length();
   1960 
   1961  while (i < length) {
   1962    auto& wrapper = mFrames[i];
   1963 
   1964    if (!wrapper.mWeakFrame->IsAlive() ||
   1965        AnyContentAncestorModified(wrapper.mWeakFrame->GetFrame())) {
   1966      // To avoid multiple O(n) shifts in the array, move the last element of
   1967      // the array to the current position and decrease the array length.
   1968      mFrameSet.Remove(wrapper.mFrame);
   1969      mFrames[i] = std::move(mFrames[length - 1]);
   1970      mRects[i] = std::move(mRects[length - 1]);
   1971      length--;
   1972    } else {
   1973      i++;
   1974    }
   1975  }
   1976 
   1977  mFrames.TruncateLength(length);
   1978  mRects.TruncateLength(length);
   1979 }
   1980 
   1981 void nsDisplayListBuilder::RemoveModifiedWindowRegions() {
   1982  mRetainedWindowDraggingRegion.RemoveModifiedFramesAndRects();
   1983  mRetainedWindowNoDraggingRegion.RemoveModifiedFramesAndRects();
   1984  mRetainedWindowOpaqueRegion.RemoveModifiedFramesAndRects();
   1985 }
   1986 
   1987 void nsDisplayListBuilder::ClearRetainedWindowRegions() {
   1988  mRetainedWindowDraggingRegion.Clear();
   1989  mRetainedWindowNoDraggingRegion.Clear();
   1990  mRetainedWindowOpaqueRegion.Clear();
   1991 }
   1992 
   1993 const uint32_t gWillChangeAreaMultiplier = 3;
   1994 static uint32_t GetLayerizationCost(const nsSize& aSize) {
   1995  // There's significant overhead for each layer created from Gecko
   1996  // (IPC+Shared Objects) and from the backend (like an OpenGL texture).
   1997  // Therefore we set a minimum cost threshold of a 64x64 area.
   1998  const int minBudgetCost = 64 * 64;
   1999 
   2000  const uint32_t budgetCost = std::max(
   2001      minBudgetCost, nsPresContext::AppUnitsToIntCSSPixels(aSize.width) *
   2002                         nsPresContext::AppUnitsToIntCSSPixels(aSize.height));
   2003 
   2004  return budgetCost;
   2005 }
   2006 
   2007 bool nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
   2008                                                 const nsSize& aSize) {
   2009  MOZ_ASSERT(IsForPainting());
   2010 
   2011  if (aFrame->MayHaveWillChangeBudget()) {
   2012    // The frame is already in the will-change budget.
   2013    return true;
   2014  }
   2015 
   2016  const nsPresContext* presContext = aFrame->PresContext();
   2017  const nsRect area = presContext->GetVisibleArea();
   2018  const uint32_t budgetLimit =
   2019      nsPresContext::AppUnitsToIntCSSPixels(area.width) *
   2020      nsPresContext::AppUnitsToIntCSSPixels(area.height);
   2021  const uint32_t cost = GetLayerizationCost(aSize);
   2022 
   2023  DocumentWillChangeBudget& documentBudget =
   2024      mDocumentWillChangeBudgets.LookupOrInsert(presContext);
   2025 
   2026  const bool onBudget =
   2027      (documentBudget + cost) / gWillChangeAreaMultiplier < budgetLimit;
   2028 
   2029  if (onBudget) {
   2030    documentBudget += cost;
   2031    mFrameWillChangeBudgets.InsertOrUpdate(
   2032        aFrame, FrameWillChangeBudget(presContext, cost));
   2033    aFrame->SetMayHaveWillChangeBudget(true);
   2034  }
   2035 
   2036  return onBudget;
   2037 }
   2038 
   2039 bool nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame,
   2040                                                const nsSize& aSize) {
   2041  if (!IsForPainting()) {
   2042    // If this nsDisplayListBuilder is not for painting, the layerization should
   2043    // not matter. Do the simple thing and return false.
   2044    return false;
   2045  }
   2046 
   2047  const bool onBudget = AddToWillChangeBudget(aFrame, aSize);
   2048  if (onBudget) {
   2049    return true;
   2050  }
   2051 
   2052  auto* pc = aFrame->PresContext();
   2053  auto* doc = pc->Document();
   2054  if (!doc->HasWarnedAbout(Document::eIgnoringWillChangeOverBudget)) {
   2055    AutoTArray<nsString, 2> params;
   2056    params.AppendElement()->AppendInt(gWillChangeAreaMultiplier);
   2057 
   2058    nsRect area = pc->GetVisibleArea();
   2059    uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
   2060                           nsPresContext::AppUnitsToIntCSSPixels(area.height);
   2061    params.AppendElement()->AppendInt(budgetLimit);
   2062 
   2063    doc->WarnOnceAbout(Document::eIgnoringWillChangeOverBudget, false, params);
   2064  }
   2065 
   2066  return false;
   2067 }
   2068 
   2069 void nsDisplayListBuilder::ClearWillChangeBudgetStatus(nsIFrame* aFrame) {
   2070  MOZ_ASSERT(IsForPainting());
   2071 
   2072  if (!aFrame->MayHaveWillChangeBudget()) {
   2073    return;
   2074  }
   2075 
   2076  aFrame->SetMayHaveWillChangeBudget(false);
   2077  RemoveFromWillChangeBudgets(aFrame);
   2078 }
   2079 
   2080 void nsDisplayListBuilder::RemoveFromWillChangeBudgets(const nsIFrame* aFrame) {
   2081  if (auto entry = mFrameWillChangeBudgets.Lookup(aFrame)) {
   2082    const FrameWillChangeBudget& frameBudget = entry.Data();
   2083 
   2084    auto documentBudget =
   2085        mDocumentWillChangeBudgets.Lookup(frameBudget.mPresContext);
   2086 
   2087    if (documentBudget) {
   2088      *documentBudget -= frameBudget.mUsage;
   2089    }
   2090 
   2091    entry.Remove();
   2092  }
   2093 }
   2094 
   2095 void nsDisplayListBuilder::ClearWillChangeBudgets() {
   2096  mFrameWillChangeBudgets.Clear();
   2097  mDocumentWillChangeBudgets.Clear();
   2098 }
   2099 
   2100 void nsDisplayListBuilder::EnterSVGEffectsContents(
   2101    nsIFrame* aEffectsFrame, nsDisplayList* aHoistedItemsStorage) {
   2102  MOZ_ASSERT(aHoistedItemsStorage);
   2103  if (mSVGEffectsFrames.IsEmpty()) {
   2104    MOZ_ASSERT(!mScrollInfoItemsForHoisting);
   2105    mScrollInfoItemsForHoisting = aHoistedItemsStorage;
   2106  }
   2107  mSVGEffectsFrames.AppendElement(aEffectsFrame);
   2108 }
   2109 
   2110 void nsDisplayListBuilder::ExitSVGEffectsContents() {
   2111  MOZ_ASSERT(!mSVGEffectsFrames.IsEmpty());
   2112  mSVGEffectsFrames.RemoveLastElement();
   2113  MOZ_ASSERT(mScrollInfoItemsForHoisting);
   2114  if (mSVGEffectsFrames.IsEmpty()) {
   2115    mScrollInfoItemsForHoisting = nullptr;
   2116  }
   2117 }
   2118 
   2119 bool nsDisplayListBuilder::ShouldBuildScrollInfoItemsForHoisting() const {
   2120  /*
   2121   * Note: if changing the conditions under which scroll info layers
   2122   * are created, make a corresponding change to
   2123   * ScrollFrameWillBuildScrollInfoLayer() in nsSliderFrame.cpp.
   2124   */
   2125  for (nsIFrame* frame : mSVGEffectsFrames) {
   2126    if (SVGIntegrationUtils::UsesSVGEffectsNotSupportedInCompositor(frame)) {
   2127      return true;
   2128    }
   2129  }
   2130  return false;
   2131 }
   2132 
   2133 void nsDisplayListBuilder::AppendNewScrollInfoItemForHoisting(
   2134    nsDisplayScrollInfoLayer* aScrollInfoItem) {
   2135  MOZ_ASSERT(ShouldBuildScrollInfoItemsForHoisting());
   2136  MOZ_ASSERT(mScrollInfoItemsForHoisting);
   2137  mScrollInfoItemsForHoisting->AppendToTop(aScrollInfoItem);
   2138 }
   2139 
   2140 void nsDisplayListBuilder::BuildCompositorHitTestInfoIfNeeded(
   2141    nsIFrame* aFrame, nsDisplayList* aList) {
   2142  MOZ_ASSERT(aFrame);
   2143  MOZ_ASSERT(aList);
   2144 
   2145  if (!BuildCompositorHitTestInfo()) {
   2146    return;
   2147  }
   2148 
   2149  const CompositorHitTestInfo info = aFrame->GetCompositorHitTestInfo(this);
   2150  if (info != CompositorHitTestInvisibleToHit) {
   2151    aList->AppendNewToTop<nsDisplayCompositorHitTestInfo>(this, aFrame);
   2152  }
   2153 }
   2154 
   2155 void nsDisplayListBuilder::AddReusableDisplayItem(nsDisplayItem* aItem) {
   2156  mReuseableItems.Insert(aItem);
   2157 }
   2158 
   2159 void nsDisplayListBuilder::RemoveReusedDisplayItem(nsDisplayItem* aItem) {
   2160  MOZ_ASSERT(aItem->IsReusedItem());
   2161  mReuseableItems.Remove(aItem);
   2162 }
   2163 
   2164 void nsDisplayListBuilder::ClearReuseableDisplayItems() {
   2165  const size_t total = mReuseableItems.Count();
   2166 
   2167  size_t reused = 0;
   2168  for (auto* item : mReuseableItems) {
   2169    if (item->IsReusedItem()) {
   2170      reused++;
   2171      item->SetReusable();
   2172    } else {
   2173      item->Destroy(this);
   2174    }
   2175  }
   2176 
   2177  DL_LOGI("RDL - Reused %zu of %zu SC display items", reused, total);
   2178  mReuseableItems.Clear();
   2179 }
   2180 
   2181 void nsDisplayListBuilder::ReuseDisplayItem(nsDisplayItem* aItem) {
   2182  const auto* previous = mCurrentContainerASR;
   2183  const auto* asr = aItem->GetActiveScrolledRoot();
   2184  mCurrentContainerASR =
   2185      ActiveScrolledRoot::PickAncestor(asr, mCurrentContainerASR);
   2186 
   2187  if (previous != mCurrentContainerASR) {
   2188    DL_LOGV("RDL - Changed mCurrentContainerASR from %p to %p", previous,
   2189            mCurrentContainerASR);
   2190  }
   2191 
   2192  aItem->SetReusedItem();
   2193 }
   2194 
   2195 void nsDisplayListSet::CopyTo(const nsDisplayListSet& aDestination) const {
   2196  for (size_t i = 0; i < mLists.size(); ++i) {
   2197    auto* from = mLists[i];
   2198    auto* to = aDestination.mLists[i];
   2199 
   2200    from->CopyTo(to);
   2201  }
   2202 }
   2203 
   2204 void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const {
   2205  aDestination.BorderBackground()->AppendToTop(BorderBackground());
   2206  aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
   2207  aDestination.Floats()->AppendToTop(Floats());
   2208  aDestination.Content()->AppendToTop(Content());
   2209  aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
   2210  aDestination.Outlines()->AppendToTop(Outlines());
   2211 }
   2212 
   2213 nsRect nsDisplayList::GetClippedBounds(nsDisplayListBuilder* aBuilder) const {
   2214  nsRect bounds;
   2215  for (nsDisplayItem* i : *this) {
   2216    bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
   2217  }
   2218  return bounds;
   2219 }
   2220 
   2221 nsRect nsDisplayList::GetClippedBoundsWithRespectToASR(
   2222    nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR,
   2223    nsRect* aBuildingRect) const {
   2224  nsRect bounds;
   2225  for (nsDisplayItem* i : *this) {
   2226    nsRect r = i->GetClippedBounds(aBuilder);
   2227    if (aASR != i->GetActiveScrolledRoot() && !r.IsEmpty()) {
   2228      if (Maybe<nsRect> clip = i->GetClipWithRespectToASR(aBuilder, aASR)) {
   2229        r = clip.ref();
   2230      }
   2231    }
   2232    if (aBuildingRect) {
   2233      aBuildingRect->UnionRect(*aBuildingRect, i->GetBuildingRect());
   2234    }
   2235    bounds.UnionRect(bounds, r);
   2236  }
   2237  return bounds;
   2238 }
   2239 
   2240 nsRect nsDisplayList::GetBuildingRect() const {
   2241  nsRect result;
   2242  for (nsDisplayItem* i : *this) {
   2243    result.UnionRect(result, i->GetBuildingRect());
   2244  }
   2245  return result;
   2246 }
   2247 
   2248 WindowRenderer* nsDisplayListBuilder::GetWidgetWindowRenderer() {
   2249  if (RootReferenceFrame() !=
   2250      nsLayoutUtils::GetDisplayRootFrame(RootReferenceFrame())) {
   2251    return nullptr;
   2252  }
   2253  if (nsIWidget* window = RootReferenceFrame()->GetNearestWidget()) {
   2254    return window->GetWindowRenderer();
   2255  }
   2256  return nullptr;
   2257 }
   2258 
   2259 WebRenderLayerManager* nsDisplayListBuilder::GetWidgetLayerManager() {
   2260  if (WindowRenderer* renderer = GetWidgetWindowRenderer()) {
   2261    return renderer->AsWebRender();
   2262  }
   2263  return nullptr;
   2264 }
   2265 
   2266 void nsDisplayList::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
   2267                          int32_t aAppUnitsPerDevPixel) {
   2268  FlattenedDisplayListIterator iter(aBuilder, this);
   2269  while (iter.HasNext()) {
   2270    nsPaintedDisplayItem* item = iter.GetNextItem()->AsPaintedDisplayItem();
   2271    if (!item) {
   2272      continue;
   2273    }
   2274 
   2275    nsRect visible = item->GetClippedBounds(aBuilder);
   2276    visible = visible.Intersect(item->GetPaintRect(aBuilder, aCtx));
   2277    if (visible.IsEmpty()) {
   2278      continue;
   2279    }
   2280 
   2281    DisplayItemClip currentClip = item->GetClip();
   2282    if (currentClip.HasClip()) {
   2283      aCtx->Save();
   2284      if (currentClip.IsRectClippedByRoundedCorner(visible)) {
   2285        currentClip.ApplyTo(aCtx, aAppUnitsPerDevPixel);
   2286      } else {
   2287        currentClip.ApplyRectTo(aCtx, aAppUnitsPerDevPixel);
   2288      }
   2289    }
   2290    aCtx->NewPath();
   2291 
   2292    item->Paint(aBuilder, aCtx);
   2293 
   2294    if (currentClip.HasClip()) {
   2295      aCtx->Restore();
   2296    }
   2297  }
   2298 }
   2299 
   2300 /**
   2301 * We paint by executing a layer manager transaction, constructing a
   2302 * single layer representing the display list, and then making it the
   2303 * root of the layer manager, drawing into the PaintedLayers.
   2304 */
   2305 void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
   2306                              uint32_t aFlags,
   2307                              Maybe<double> aDisplayListBuildTime) {
   2308  AUTO_PROFILER_LABEL("nsDisplayList::PaintRoot", GRAPHICS);
   2309 
   2310  RefPtr<WebRenderLayerManager> layerManager;
   2311  WindowRenderer* renderer = nullptr;
   2312  bool widgetTransaction = false;
   2313  bool doBeginTransaction = true;
   2314  if (aFlags & PAINT_USE_WIDGET_LAYERS) {
   2315    renderer = aBuilder->GetWidgetWindowRenderer();
   2316    if (renderer) {
   2317      // The fallback renderer doesn't retain any content, so it's
   2318      // not meaningful to use it when drawing to an external context.
   2319      if (aCtx && renderer->AsFallback()) {
   2320        MOZ_ASSERT(!(aFlags & PAINT_EXISTING_TRANSACTION));
   2321        renderer = nullptr;
   2322      } else {
   2323        layerManager = renderer->AsWebRender();
   2324        doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
   2325        widgetTransaction = true;
   2326      }
   2327    }
   2328  }
   2329 
   2330  nsIFrame* frame = aBuilder->RootReferenceFrame();
   2331  nsPresContext* presContext = frame->PresContext();
   2332  PresShell* presShell = presContext->PresShell();
   2333  Document* document = presShell->GetDocument();
   2334 
   2335  ScopeExit g([&]() {
   2336 #ifdef DEBUG
   2337    MOZ_ASSERT(!layerManager || !layerManager->GetTarget());
   2338 #endif
   2339 
   2340    // For layers-free mode, we check the invalidation state bits in the
   2341    // EndTransaction. So we clear the invalidation state bits after
   2342    // EndTransaction.
   2343    if (widgetTransaction ||
   2344        // SVG-as-an-image docs don't paint as part of the retained layer tree,
   2345        // but they still need the invalidation state bits cleared in order for
   2346        // invalidation for CSS/SMIL animation to work properly.
   2347        (document && document->IsBeingUsedAsImage())) {
   2348      DL_LOGD("Clearing invalidation state bits");
   2349      frame->ClearInvalidationStateBits();
   2350    }
   2351  });
   2352 
   2353  if (!renderer) {
   2354    if (!aCtx) {
   2355      NS_WARNING("Nowhere to paint into");
   2356      return;
   2357    }
   2358    Paint(aBuilder, aCtx, presContext->AppUnitsPerDevPixel());
   2359 
   2360    return;
   2361  }
   2362 
   2363  if (renderer->GetBackendType() == LayersBackend::LAYERS_WR) {
   2364    MOZ_ASSERT(layerManager);
   2365    if (doBeginTransaction) {
   2366      if (aCtx) {
   2367        if (!layerManager->BeginTransactionWithTarget(aCtx, nsCString())) {
   2368          return;
   2369        }
   2370      } else {
   2371        if (!layerManager->BeginTransaction(nsCString())) {
   2372          return;
   2373        }
   2374      }
   2375    }
   2376 
   2377    layerManager->SetTransactionIdAllocator(presContext->RefreshDriver());
   2378 
   2379    bool sent = false;
   2380    if (aFlags & PAINT_IDENTICAL_DISPLAY_LIST) {
   2381      MOZ_ASSERT(!aCtx);
   2382      sent = layerManager->EndEmptyTransaction();
   2383    }
   2384 
   2385    if (!sent) {
   2386      auto* wrManager = static_cast<WebRenderLayerManager*>(layerManager.get());
   2387 
   2388      nsIDocShell* docShell = presContext->GetDocShell();
   2389      WrFiltersHolder wrFilters;
   2390      gfx::Matrix5x4* colorMatrix =
   2391          nsDocShell::Cast(docShell)->GetColorMatrix();
   2392      if (colorMatrix) {
   2393        // Note: This color matrix was added here in for accessibility in
   2394        // https://bugzilla.mozilla.org/show_bug.cgi?id=1431466 , it could be
   2395        // done with regular SVG in the document as long as it is accelerated,
   2396        // and it's probably best to do this in linearRGB, now that it is
   2397        // feasible to do so
   2398        // TODO(ahale): Make sure to test this works correctly before enabling
   2399        if (StaticPrefs::gfx_webrender_svg_filter_effects() &&
   2400            StaticPrefs::
   2401                gfx_webrender_svg_filter_effects_also_use_for_docshell_fecolormatrix()) {
   2402          // WebRender SVGFE code needs a valid filter region, so use 1<<30 as
   2403          // rendering will already be heavily degraded at that range.
   2404          static constexpr float kExtent = 1024.0f * 1024.0f * 1024.0f;
   2405          wr::LayoutRect subregion = {{-kExtent, -kExtent}, {kExtent, kExtent}};
   2406          auto node = wr::FilterOpGraphNode{};
   2407          node.input.buffer_id = wr::FilterOpGraphPictureBufferId::None();
   2408          node.input2.buffer_id = wr::FilterOpGraphPictureBufferId::None();
   2409          node.subregion = subregion;
   2410          wrFilters.filters.AppendElement(
   2411              wr::FilterOp::SVGFESourceGraphic(node));
   2412          node.input.buffer_id = wr::FilterOpGraphPictureBufferId::BufferId(0);
   2413          wrFilters.filters.AppendElement(
   2414              wr::FilterOp::SVGFEColorMatrix(node, colorMatrix->components));
   2415        } else {
   2416          wrFilters.filters.AppendElement(
   2417              wr::FilterOp::ColorMatrix(colorMatrix->components));
   2418        }
   2419      }
   2420 
   2421      wrManager->EndTransactionWithoutLayer(this, aBuilder,
   2422                                            std::move(wrFilters), nullptr,
   2423                                            aDisplayListBuildTime.valueOr(0.0),
   2424                                            aFlags & PAINT_COMPOSITE_OFFSCREEN);
   2425    }
   2426 
   2427    if (presContext->RefreshDriver()->IsInRefresh() ||
   2428        presContext->RefreshDriver()->IsPaintPending()) {
   2429      presContext->NotifyInvalidation(layerManager->GetLastTransactionId(),
   2430                                      frame->GetRect());
   2431    }
   2432    return;
   2433  }
   2434 
   2435  FallbackRenderer* fallback = renderer->AsFallback();
   2436  MOZ_ASSERT(fallback);
   2437 
   2438  if (doBeginTransaction) {
   2439    MOZ_ASSERT(!aCtx);
   2440    if (!fallback->BeginTransaction()) {
   2441      return;
   2442    }
   2443  }
   2444 
   2445  fallback->EndTransactionWithList(aBuilder, this,
   2446                                   presContext->AppUnitsPerDevPixel(),
   2447                                   WindowRenderer::END_DEFAULT);
   2448 }
   2449 
   2450 void nsDisplayList::DeleteAll(nsDisplayListBuilder* aBuilder) {
   2451  for (auto* item : TakeItems()) {
   2452    item->Destroy(aBuilder);
   2453  }
   2454 }
   2455 
   2456 static bool IsFrameReceivingPointerEvents(nsIFrame* aFrame) {
   2457  return aFrame->Style()->PointerEvents() != StylePointerEvents::None;
   2458 }
   2459 
   2460 // A list of frames, and their z depth. Used for sorting
   2461 // the results of hit testing.
   2462 struct FramesWithDepth {
   2463  explicit FramesWithDepth(float aDepth) : mDepth(aDepth) {}
   2464 
   2465  bool operator<(const FramesWithDepth& aOther) const {
   2466    // We want to sort so that the shallowest item (highest depth value) is
   2467    // first. Round to have some error tolerance (multiply with 8 translates
   2468    // effectively to <<3).
   2469    double lDepth = round(mDepth * 8.);
   2470    double rDepth = round(aOther.mDepth * 8.);
   2471    return lDepth > rDepth;
   2472  }
   2473  bool operator==(const FramesWithDepth& aOther) const {
   2474    return this == &aOther;
   2475  }
   2476 
   2477  float mDepth;
   2478  nsTArray<nsIFrame*> mFrames;
   2479 };
   2480 
   2481 // Sort the frames by depth and then moves all the contained frames to the
   2482 // destination
   2483 static void FlushFramesArray(nsTArray<FramesWithDepth>& aSource,
   2484                             nsTArray<nsIFrame*>* aDest) {
   2485  if (aSource.IsEmpty()) {
   2486    return;
   2487  }
   2488  aSource.StableSort();
   2489  uint32_t length = aSource.Length();
   2490  for (uint32_t i = 0; i < length; i++) {
   2491    aDest->AppendElements(std::move(aSource[i].mFrames));
   2492  }
   2493  aSource.Clear();
   2494 }
   2495 
   2496 void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   2497                            nsDisplayItem::HitTestState* aState,
   2498                            nsTArray<nsIFrame*>* aOutFrames) const {
   2499  nsDisplayItem* item;
   2500 
   2501  if (aState->mGatheringPreserves3DLeaves) {
   2502    // Collect leaves of the current 3D rendering context.
   2503    for (nsDisplayItem* item : *this) {
   2504      auto itemType = item->GetType();
   2505      if (itemType != DisplayItemType::TYPE_TRANSFORM ||
   2506          !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
   2507        item->HitTest(aBuilder, aRect, aState, aOutFrames);
   2508      } else {
   2509        // One of leaves in the current 3D rendering context.
   2510        aState->mItemBuffer.AppendElement(item);
   2511      }
   2512    }
   2513    return;
   2514  }
   2515 
   2516  int32_t itemBufferStart = aState->mItemBuffer.Length();
   2517  for (nsDisplayItem* item : *this) {
   2518    aState->mItemBuffer.AppendElement(item);
   2519  }
   2520 
   2521  AutoTArray<FramesWithDepth, 16> temp;
   2522  for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart;
   2523       --i) {
   2524    // Pop element off the end of the buffer. We want to shorten the buffer
   2525    // so that recursive calls to HitTest have more buffer space.
   2526    item = aState->mItemBuffer[i];
   2527    aState->mItemBuffer.SetLength(i);
   2528 
   2529    bool snap;
   2530    nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect);
   2531    auto itemType = item->GetType();
   2532    bool same3DContext =
   2533        (itemType == DisplayItemType::TYPE_TRANSFORM &&
   2534         static_cast<nsDisplayTransform*>(item)->IsParticipating3DContext()) ||
   2535        (itemType == DisplayItemType::TYPE_PERSPECTIVE &&
   2536         item->Frame()->Extend3DContext());
   2537    if (same3DContext &&
   2538        (itemType != DisplayItemType::TYPE_TRANSFORM ||
   2539         !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext())) {
   2540      if (!item->GetClip().MayIntersect(aRect)) {
   2541        continue;
   2542      }
   2543      AutoTArray<nsIFrame*, 1> neverUsed;
   2544      // Start gathering leaves of the 3D rendering context, and
   2545      // append leaves at the end of mItemBuffer.  Leaves are
   2546      // processed at following iterations.
   2547      aState->mGatheringPreserves3DLeaves = true;
   2548      item->HitTest(aBuilder, aRect, aState, &neverUsed);
   2549      aState->mGatheringPreserves3DLeaves = false;
   2550      i = aState->mItemBuffer.Length();
   2551      continue;
   2552    }
   2553 
   2554    if (!same3DContext && !item->GetClip().MayIntersect(r)) {
   2555      continue;
   2556    }
   2557 
   2558    const bool savedTransformHasBackfaceVisible =
   2559        aState->mTransformHasBackfaceVisible;
   2560    if (aState->mTransformHasBackfaceVisible &&
   2561        !item->Combines3DTransformWithAncestors()) {
   2562      // exiting a preserve 3d context, the transform is no longer applied to
   2563      // this item, so reset the tracking var
   2564      aState->mTransformHasBackfaceVisible = false;
   2565    }
   2566    AutoTArray<nsIFrame*, 16> outFrames;
   2567    item->HitTest(aBuilder, aRect, aState, &outFrames);
   2568    MOZ_ASSERT(!aState->mTransformHasBackfaceVisible ||
   2569               !item->In3DContextAndBackfaceIsHidden() ||
   2570               !outFrames.Contains(item->Frame()));
   2571    aState->mTransformHasBackfaceVisible = savedTransformHasBackfaceVisible;
   2572 
   2573    // For 3d transforms with preserve-3d we add hit frames into the temp list
   2574    // so we can sort them later, otherwise we add them directly to the output
   2575    // list.
   2576    nsTArray<nsIFrame*>* writeFrames = aOutFrames;
   2577    if (item->GetType() == DisplayItemType::TYPE_TRANSFORM &&
   2578        static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
   2579      if (outFrames.Length()) {
   2580        nsDisplayTransform* transform = static_cast<nsDisplayTransform*>(item);
   2581        nsPoint point = aRect.TopLeft();
   2582        // A 1x1 rect means a point, otherwise use the center of the rect
   2583        if (aRect.width != 1 || aRect.height != 1) {
   2584          point = aRect.Center();
   2585        }
   2586        temp.AppendElement(
   2587            FramesWithDepth(transform->GetHitDepthAtPoint(aBuilder, point)));
   2588        writeFrames = &temp[temp.Length() - 1].mFrames;
   2589      }
   2590    } else {
   2591      // We may have just finished a run of consecutive preserve-3d
   2592      // transforms, so flush these into the destination array before
   2593      // processing our frame list.
   2594      FlushFramesArray(temp, aOutFrames);
   2595    }
   2596 
   2597    for (uint32_t j = 0; j < outFrames.Length(); j++) {
   2598      nsIFrame* f = outFrames.ElementAt(j);
   2599      // Filter out some frames depending on the type of hittest
   2600      // we are doing. For visibility tests, pass through all frames.
   2601      // For pointer tests, only pass through frames that are styled
   2602      // to receive pointer events.
   2603      if (aBuilder->HitTestIsForVisibility() ||
   2604          IsFrameReceivingPointerEvents(f)) {
   2605        writeFrames->AppendElement(f);
   2606      }
   2607    }
   2608 
   2609    if (aBuilder->HitTestIsForVisibility()) {
   2610      aState->mHitOccludingItem = [&] {
   2611        if (aState->mHitOccludingItem) {
   2612          // We already hit something before.
   2613          return true;
   2614        }
   2615        if (aState->mCurrentOpacity == 1.0f &&
   2616            item->GetOpaqueRegion(aBuilder, &snap).Contains(aRect)) {
   2617          // An opaque item always occludes everything. Note that we need to
   2618          // check wrapping opacity and such as well.
   2619          return true;
   2620        }
   2621        float threshold = aBuilder->VisibilityThreshold();
   2622        if (threshold == 1.0f) {
   2623          return false;
   2624        }
   2625        float itemOpacity = [&] {
   2626          switch (item->GetType()) {
   2627            case DisplayItemType::TYPE_OPACITY:
   2628              return static_cast<nsDisplayOpacity*>(item)->GetOpacity();
   2629            case DisplayItemType::TYPE_BACKGROUND_COLOR:
   2630              return static_cast<nsDisplayBackgroundColor*>(item)->GetOpacity();
   2631            default:
   2632              // Be conservative and assume it won't occlude other items.
   2633              return 0.0f;
   2634          }
   2635        }();
   2636        return itemOpacity * aState->mCurrentOpacity >= threshold;
   2637      }();
   2638 
   2639      if (aState->mHitOccludingItem) {
   2640        // We're exiting early, so pop the remaining items off the buffer.
   2641        aState->mItemBuffer.TruncateLength(itemBufferStart);
   2642        break;
   2643      }
   2644    }
   2645  }
   2646  // Clear any remaining preserve-3d transforms.
   2647  FlushFramesArray(temp, aOutFrames);
   2648  NS_ASSERTION(aState->mItemBuffer.Length() == uint32_t(itemBufferStart),
   2649               "How did we forget to pop some elements?");
   2650 }
   2651 
   2652 static nsIContent* FindContentInDocument(nsDisplayItem* aItem, Document* aDoc) {
   2653  nsIFrame* f = aItem->Frame();
   2654  while (f) {
   2655    nsPresContext* pc = f->PresContext();
   2656    if (pc->Document() == aDoc) {
   2657      return f->GetContent();
   2658    }
   2659    f = nsLayoutUtils::GetCrossDocParentFrameInProcess(
   2660        pc->PresShell()->GetRootFrame());
   2661  }
   2662  return nullptr;
   2663 }
   2664 
   2665 struct ZSortItem {
   2666  nsDisplayItem* item;
   2667  int32_t zIndex;
   2668 
   2669  explicit ZSortItem(nsDisplayItem* aItem)
   2670      : item(aItem), zIndex(aItem->ZIndex()) {}
   2671 
   2672  operator nsDisplayItem*() { return item; }
   2673 };
   2674 
   2675 struct ZOrderComparator {
   2676  bool LessThan(const ZSortItem& aLeft, const ZSortItem& aRight) const {
   2677    return aLeft.zIndex < aRight.zIndex;
   2678  }
   2679 };
   2680 
   2681 void nsDisplayList::SortByZOrder() { Sort<ZSortItem>(ZOrderComparator()); }
   2682 
   2683 struct ContentComparator {
   2684  nsIContent* mCommonAncestor;
   2685 
   2686  explicit ContentComparator(nsIContent* aCommonAncestor)
   2687      : mCommonAncestor(aCommonAncestor) {}
   2688 
   2689  bool LessThan(nsDisplayItem* aLeft, nsDisplayItem* aRight) const {
   2690    // It's possible that the nsIContent for aItem1 or aItem2 is in a
   2691    // subdocument of commonAncestor, because display items for subdocuments
   2692    // have been mixed into the same list. Ensure that we're looking at content
   2693    // in commonAncestor's document.
   2694    Document* commonAncestorDoc = mCommonAncestor->OwnerDoc();
   2695    nsIContent* content1 = FindContentInDocument(aLeft, commonAncestorDoc);
   2696    nsIContent* content2 = FindContentInDocument(aRight, commonAncestorDoc);
   2697    if (!content1 || !content2) {
   2698      NS_ERROR("Document trees are mixed up!");
   2699      // Something weird going on
   2700      return true;
   2701    }
   2702    return content1 != content2 &&
   2703           nsContentUtils::CompareTreePosition<TreeKind::Flat>(
   2704               content1, content2, mCommonAncestor) < 0;
   2705  }
   2706 };
   2707 
   2708 void nsDisplayList::SortByContentOrder(nsIContent* aCommonAncestor) {
   2709  Sort<nsDisplayItem*>(ContentComparator(aCommonAncestor));
   2710 }
   2711 
   2712 #if !defined(DEBUG) && !defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
   2713 static_assert(sizeof(nsDisplayItem) <= 176, "nsDisplayItem has grown");
   2714 #endif
   2715 
   2716 nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
   2717    : nsDisplayItem(aBuilder, aFrame, aBuilder->CurrentActiveScrolledRoot()) {}
   2718 
   2719 nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   2720                             const ActiveScrolledRoot* aActiveScrolledRoot)
   2721    : mFrame(aFrame), mActiveScrolledRoot(aActiveScrolledRoot) {
   2722  MOZ_COUNT_CTOR(nsDisplayItem);
   2723  MOZ_ASSERT(mFrame);
   2724  if (aBuilder->IsRetainingDisplayList()) {
   2725    mFrame->AddDisplayItem(this);
   2726  }
   2727 
   2728  aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
   2729  NS_ASSERTION(
   2730      aBuilder->GetVisibleRect().width >= 0 || !aBuilder->IsForPainting(),
   2731      "visible rect not set");
   2732 
   2733  mClipChain = aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
   2734 
   2735  // The visible rect is for mCurrentFrame, so we have to use
   2736  // mCurrentOffsetToReferenceFrame
   2737  nsRect visible = aBuilder->GetVisibleRect() +
   2738                   aBuilder->GetCurrentFrameOffsetToReferenceFrame();
   2739  SetBuildingRect(visible);
   2740 
   2741  const nsStyleDisplay* disp = mFrame->StyleDisplay();
   2742  if (mFrame->BackfaceIsHidden(disp)) {
   2743    mItemFlags += ItemFlag::BackfaceHidden;
   2744  }
   2745  if (mFrame->Combines3DTransformWithAncestors()) {
   2746    mItemFlags += ItemFlag::Combines3DTransformWithAncestors;
   2747  }
   2748 }
   2749 
   2750 void nsDisplayItem::SetDeletedFrame() { mItemFlags += ItemFlag::DeletedFrame; }
   2751 
   2752 const ActiveScrolledRoot* nsDisplayItem::GetNearestScrollASR() const {
   2753  const ActiveScrolledRoot* asr = GetActiveScrolledRoot();
   2754  if (asr) {
   2755    return asr->GetNearestScrollASR();
   2756  }
   2757  return nullptr;
   2758 }
   2759 
   2760 bool nsDisplayItem::HasDeletedFrame() const {
   2761  bool retval = mItemFlags.contains(ItemFlag::DeletedFrame) ||
   2762                (GetType() == DisplayItemType::TYPE_REMOTE &&
   2763                 !static_cast<const nsDisplayRemote*>(this)->GetFrameLoader());
   2764  MOZ_ASSERT(retval || mFrame);
   2765  return retval;
   2766 }
   2767 
   2768 /* static */
   2769 bool nsDisplayItem::ForceActiveLayers() {
   2770  return StaticPrefs::layers_force_active();
   2771 }
   2772 
   2773 int32_t nsDisplayItem::ZIndex() const { return mFrame->ZIndex().valueOr(0); }
   2774 
   2775 void nsDisplayItem::SetClipChain(const DisplayItemClipChain* aClipChain,
   2776                                 bool aStore) {
   2777  mClipChain = aClipChain;
   2778 }
   2779 
   2780 Maybe<nsRect> nsDisplayItem::GetClipWithRespectToASR(
   2781    nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR) const {
   2782  if (const DisplayItemClip* clip =
   2783          DisplayItemClipChain::ClipForASR(GetClipChain(), aASR)) {
   2784    return Some(clip->GetClipRect());
   2785  }
   2786 
   2787  return Nothing();
   2788 }
   2789 
   2790 const DisplayItemClip& nsDisplayItem::GetClip() const {
   2791  const DisplayItemClip* clip =
   2792      DisplayItemClipChain::ClipForASR(mClipChain, mActiveScrolledRoot);
   2793  return clip ? *clip : DisplayItemClip::NoClip();
   2794 }
   2795 
   2796 void nsDisplayItem::IntersectClip(nsDisplayListBuilder* aBuilder,
   2797                                  const DisplayItemClipChain* aOther,
   2798                                  bool aStore) {
   2799  if (!aOther || mClipChain == aOther) {
   2800    return;
   2801  }
   2802 
   2803  // aOther might be a reference to a clip on the stack. We need to make sure
   2804  // that CreateClipChainIntersection will allocate the actual intersected
   2805  // clip in the builder's arena, so for the mClipChain == nullptr case,
   2806  // we supply nullptr as the common ancestor so that
   2807  // CreateClipChainIntersection clones the whole chain.
   2808  const DisplayItemClipChain* ancestorClip =
   2809      mClipChain ? FindCommonAncestorClipForIntersection(mClipChain, aOther)
   2810                 : nullptr;
   2811 
   2812  SetClipChain(
   2813      aBuilder->CreateClipChainIntersection(ancestorClip, mClipChain, aOther),
   2814      aStore);
   2815 }
   2816 
   2817 nsRect nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder) const {
   2818  bool snap;
   2819  nsRect r = GetBounds(aBuilder, &snap);
   2820  return GetClip().ApplyNonRoundedIntersection(r);
   2821 }
   2822 
   2823 nsDisplayContainer::nsDisplayContainer(
   2824    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   2825    const ActiveScrolledRoot* aActiveScrolledRoot,
   2826    ContainerASRType aContainerASRType, nsDisplayList* aList)
   2827    : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot),
   2828      mChildren(aBuilder),
   2829      mFrameASR(aContainerASRType == ContainerASRType::AncestorOfContained
   2830                    ? aBuilder->CurrentActiveScrolledRoot()
   2831                    : nullptr),
   2832      mContainerASRType(aContainerASRType) {
   2833  MOZ_COUNT_CTOR(nsDisplayContainer);
   2834  mChildren.AppendToTop(aList);
   2835  UpdateBounds(aBuilder);
   2836 
   2837  // Clear and store the clip chain set by nsDisplayItem constructor.
   2838  nsDisplayItem::SetClipChain(nullptr, true);
   2839 }
   2840 
   2841 nsRect nsDisplayItem::GetPaintRect(nsDisplayListBuilder* aBuilder,
   2842                                   gfxContext* aCtx) {
   2843  bool dummy;
   2844  nsRect result = GetBounds(aBuilder, &dummy);
   2845  if (aCtx) {
   2846    result.IntersectRect(result,
   2847                         nsLayoutUtils::RoundGfxRectToAppRect(
   2848                             aCtx->GetClipExtents(),
   2849                             mFrame->PresContext()->AppUnitsPerDevPixel()));
   2850  }
   2851  return result;
   2852 }
   2853 
   2854 bool nsDisplayContainer::CreateWebRenderCommands(
   2855    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   2856    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   2857    nsDisplayListBuilder* aDisplayListBuilder) {
   2858  aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
   2859      GetChildren(), this, aDisplayListBuilder, aSc, aBuilder, aResources,
   2860      false);
   2861  return true;
   2862 }
   2863 
   2864 nsRect nsDisplayContainer::GetBounds(nsDisplayListBuilder* aBuilder,
   2865                                     bool* aSnap) const {
   2866  *aSnap = false;
   2867  return mBounds;
   2868 }
   2869 
   2870 nsRect nsDisplayContainer::GetComponentAlphaBounds(
   2871    nsDisplayListBuilder* aBuilder) const {
   2872  return mChildren.GetComponentAlphaBounds(aBuilder);
   2873 }
   2874 
   2875 static nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   2876                                nsDisplayList* aList,
   2877                                const nsRect& aListBounds) {
   2878  return aList->GetOpaqueRegion(aBuilder);
   2879 }
   2880 
   2881 nsRegion nsDisplayContainer::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   2882                                             bool* aSnap) const {
   2883  return ::mozilla::GetOpaqueRegion(aBuilder, GetChildren(),
   2884                                    GetBounds(aBuilder, aSnap));
   2885 }
   2886 
   2887 Maybe<nsRect> nsDisplayContainer::GetClipWithRespectToASR(
   2888    nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR) const {
   2889  // Our children should have finite bounds with respect to |aASR|.
   2890  if (aASR == mActiveScrolledRoot) {
   2891    return Some(mBounds);
   2892  }
   2893 
   2894  return Some(mChildren.GetClippedBoundsWithRespectToASR(aBuilder, aASR));
   2895 }
   2896 
   2897 void nsDisplayContainer::HitTest(nsDisplayListBuilder* aBuilder,
   2898                                 const nsRect& aRect, HitTestState* aState,
   2899                                 nsTArray<nsIFrame*>* aOutFrames) {
   2900  mChildren.HitTest(aBuilder, aRect, aState, aOutFrames);
   2901 }
   2902 
   2903 void nsDisplayContainer::UpdateBounds(nsDisplayListBuilder* aBuilder) {
   2904  // Container item bounds are expected to be clipped.
   2905  mBounds =
   2906      mChildren.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot);
   2907 }
   2908 
   2909 nsRect nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder,
   2910                                      bool* aSnap) const {
   2911  *aSnap = true;
   2912  return mBounds;
   2913 }
   2914 
   2915 void nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
   2916                                gfxContext* aCtx) {
   2917  if (!NS_GET_A(mColor)) {
   2918    return;
   2919  }
   2920  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   2921  DrawTarget* drawTarget = aCtx->GetDrawTarget();
   2922  Rect rect = NSRectToSnappedRect(GetPaintRect(aBuilder, aCtx),
   2923                                  appUnitsPerDevPixel, *drawTarget);
   2924  drawTarget->FillRect(rect, ColorPattern(ToDeviceColor(mColor)));
   2925 }
   2926 
   2927 void nsDisplaySolidColor::WriteDebugInfo(std::stringstream& aStream) {
   2928  aStream << " (rgba " << (int)NS_GET_R(mColor) << "," << (int)NS_GET_G(mColor)
   2929          << "," << (int)NS_GET_B(mColor) << "," << (int)NS_GET_A(mColor)
   2930          << ")";
   2931 }
   2932 
   2933 bool nsDisplaySolidColor::CreateWebRenderCommands(
   2934    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   2935    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   2936    nsDisplayListBuilder* aDisplayListBuilder) {
   2937  if (!NS_GET_A(mColor)) {
   2938    return true;
   2939  }
   2940  LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
   2941      mBounds, mFrame->PresContext()->AppUnitsPerDevPixel());
   2942  wr::LayoutRect r = wr::ToLayoutRect(bounds);
   2943  aBuilder.PushRect(r, r, !BackfaceIsHidden(), false, mIsCheckerboardBackground,
   2944                    wr::ToColorF(ToDeviceColor(mColor)));
   2945 
   2946  return true;
   2947 }
   2948 
   2949 nsRect nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder,
   2950                                            bool* aSnap) const {
   2951  *aSnap = true;
   2952  return mRegion.GetBounds();
   2953 }
   2954 
   2955 void nsDisplaySolidColorRegion::Paint(nsDisplayListBuilder* aBuilder,
   2956                                      gfxContext* aCtx) {
   2957  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   2958  DrawTarget* drawTarget = aCtx->GetDrawTarget();
   2959  ColorPattern color(ToDeviceColor(mColor));
   2960  for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
   2961    Rect rect =
   2962        NSRectToSnappedRect(iter.Get(), appUnitsPerDevPixel, *drawTarget);
   2963    drawTarget->FillRect(rect, color);
   2964  }
   2965 }
   2966 
   2967 void nsDisplaySolidColorRegion::WriteDebugInfo(std::stringstream& aStream) {
   2968  aStream << " (rgba " << int(mColor.r * 255) << "," << int(mColor.g * 255)
   2969          << "," << int(mColor.b * 255) << "," << mColor.a << ")";
   2970 }
   2971 
   2972 bool nsDisplaySolidColorRegion::CreateWebRenderCommands(
   2973    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   2974    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   2975    nsDisplayListBuilder* aDisplayListBuilder) {
   2976  for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
   2977    nsRect rect = iter.Get();
   2978    LayoutDeviceRect layerRects = LayoutDeviceRect::FromAppUnits(
   2979        rect, mFrame->PresContext()->AppUnitsPerDevPixel());
   2980    wr::LayoutRect r = wr::ToLayoutRect(layerRects);
   2981    aBuilder.PushRect(r, r, !BackfaceIsHidden(), false, false,
   2982                      wr::ToColorF(ToDeviceColor(mColor)));
   2983  }
   2984 
   2985  return true;
   2986 }
   2987 
   2988 static void RegisterThemeGeometry(nsDisplayListBuilder* aBuilder,
   2989                                  nsDisplayItem* aItem, nsIFrame* aFrame,
   2990                                  nsITheme::ThemeGeometryType aType) {
   2991  if (aBuilder->IsInChromeDocumentOrPopup()) {
   2992    nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
   2993    bool preservesAxisAlignedRectangles = false;
   2994    nsRect borderBox = nsLayoutUtils::TransformFrameRectToAncestor(
   2995        aFrame, aFrame->GetRectRelativeToSelf(), displayRoot,
   2996        &preservesAxisAlignedRectangles);
   2997    if (preservesAxisAlignedRectangles) {
   2998      aBuilder->RegisterThemeGeometry(
   2999          aType, aItem,
   3000          LayoutDeviceIntRect::FromUnknownRect(borderBox.ToNearestPixels(
   3001              aFrame->PresContext()->AppUnitsPerDevPixel())));
   3002    }
   3003  }
   3004 }
   3005 
   3006 // Return the bounds of the viewport relative to |aFrame|'s reference frame.
   3007 // Returns Nothing() if transforming into |aFrame|'s coordinate space fails.
   3008 static Maybe<nsRect> GetViewportRectRelativeToReferenceFrame(
   3009    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
   3010  nsIFrame* rootFrame = aFrame->PresShell()->GetRootFrame();
   3011  nsRect rootRect = rootFrame->GetRectRelativeToSelf();
   3012  if (nsLayoutUtils::TransformRect(rootFrame, aFrame, rootRect) ==
   3013      nsLayoutUtils::TRANSFORM_SUCCEEDED) {
   3014    return Some(rootRect + aBuilder->ToReferenceFrame(aFrame));
   3015  }
   3016  return Nothing();
   3017 }
   3018 
   3019 /* static */ nsDisplayBackgroundImage::InitData
   3020 nsDisplayBackgroundImage::GetInitData(nsDisplayListBuilder* aBuilder,
   3021                                      nsIFrame* aFrame, uint16_t aLayer,
   3022                                      const nsRect& aBackgroundRect,
   3023                                      const ComputedStyle* aBackgroundStyle) {
   3024  nsPresContext* presContext = aFrame->PresContext();
   3025  uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   3026  const nsStyleImageLayers::Layer& layer =
   3027      aBackgroundStyle->StyleBackground()->mImage.mLayers[aLayer];
   3028 
   3029  bool isTransformedFixed;
   3030  nsBackgroundLayerState state = nsCSSRendering::PrepareImageLayer(
   3031      presContext, aFrame, flags, aBackgroundRect, aBackgroundRect, layer,
   3032      &isTransformedFixed);
   3033 
   3034  // background-attachment:fixed is treated as background-attachment:scroll
   3035  // if it's affected by a transform.
   3036  // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=17521.
   3037  bool shouldTreatAsFixed =
   3038      layer.mAttachment == StyleImageLayerAttachment::Fixed &&
   3039      !isTransformedFixed;
   3040 
   3041  bool shouldFixToViewport = shouldTreatAsFixed && !layer.mImage.IsNone();
   3042  bool isRasterImage = state.mImageRenderer.IsRasterImage();
   3043  nsCOMPtr<imgIContainer> image;
   3044  if (isRasterImage) {
   3045    image = state.mImageRenderer.GetImage();
   3046  }
   3047  return InitData{aBuilder,        aBackgroundStyle, image,
   3048                  aBackgroundRect, state.mFillArea,  state.mDestArea,
   3049                  aLayer,          isRasterImage,    shouldFixToViewport};
   3050 }
   3051 
   3052 nsDisplayBackgroundImage::nsDisplayBackgroundImage(
   3053    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const InitData& aInitData,
   3054    nsIFrame* aFrameForBounds)
   3055    : nsPaintedDisplayItem(aBuilder, aFrame),
   3056      mBackgroundStyle(aInitData.backgroundStyle),
   3057      mImage(aInitData.image),
   3058      mDependentFrame(nullptr),
   3059      mBackgroundRect(aInitData.backgroundRect),
   3060      mFillRect(aInitData.fillArea),
   3061      mDestRect(aInitData.destArea),
   3062      mLayer(aInitData.layer),
   3063      mIsRasterImage(aInitData.isRasterImage) {
   3064  MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
   3065 #ifdef DEBUG
   3066  if (mBackgroundStyle && mBackgroundStyle != mFrame->Style()) {
   3067    // If this changes, then you also need to adjust css::ImageLoader to
   3068    // invalidate mFrame as needed.
   3069    MOZ_ASSERT(mFrame->IsCanvasFrame() || mFrame->IsTablePart());
   3070  }
   3071 #endif
   3072 
   3073  mBounds = GetBoundsInternal(aInitData.builder, aFrameForBounds);
   3074  if (aInitData.shouldFixToViewport) {
   3075    // Expand the item's visible rect to cover the entire bounds, limited to the
   3076    // viewport rect. This is necessary because the background's clip can move
   3077    // asynchronously.
   3078    if (Maybe<nsRect> viewportRect = GetViewportRectRelativeToReferenceFrame(
   3079            aInitData.builder, mFrame)) {
   3080      SetBuildingRect(mBounds.Intersect(*viewportRect));
   3081    }
   3082  }
   3083 }
   3084 
   3085 void nsDisplayBackgroundImage::Destroy(nsDisplayListBuilder* aBuilder) {
   3086  RemoveDisplayItemFromFrame(aBuilder, mDependentFrame);
   3087  nsPaintedDisplayItem::Destroy(aBuilder);
   3088 }
   3089 
   3090 static void SetBackgroundClipRegion(
   3091    DisplayListClipState::AutoSaveRestore& aClipState, nsIFrame* aFrame,
   3092    const nsStyleImageLayers::Layer& aLayer, const nsRect& aBackgroundRect,
   3093    bool aWillPaintBorder) {
   3094  nsCSSRendering::ImageLayerClipState clip;
   3095  nsCSSRendering::GetImageLayerClip(
   3096      aLayer, aFrame, *aFrame->StyleBorder(), aBackgroundRect, aBackgroundRect,
   3097      aWillPaintBorder, aFrame->PresContext()->AppUnitsPerDevPixel(), &clip);
   3098 
   3099  if (clip.mHasAdditionalBGClipArea) {
   3100    aClipState.ClipContentDescendants(
   3101        clip.mAdditionalBGClipArea, clip.mBGClipArea,
   3102        clip.mHasRoundedCorners ? &clip.mRadii : nullptr);
   3103  } else {
   3104    aClipState.ClipContentDescendants(
   3105        clip.mBGClipArea, clip.mHasRoundedCorners ? &clip.mRadii : nullptr);
   3106  }
   3107 }
   3108 
   3109 /**
   3110 * This is used for the find bar highlighter overlay. It's only accessible
   3111 * through the AnonymousContent API, so it's not exposed to general web pages.
   3112 */
   3113 static bool SpecialCutoutRegionCase(nsDisplayListBuilder* aBuilder,
   3114                                    nsIFrame* aFrame,
   3115                                    const nsRect& aBackgroundRect,
   3116                                    nsDisplayList* aList, nscolor aColor) {
   3117  nsIContent* content = aFrame->GetContent();
   3118  if (!content) {
   3119    return false;
   3120  }
   3121 
   3122  void* cutoutRegion = content->GetProperty(nsGkAtoms::cutoutregion);
   3123  if (!cutoutRegion) {
   3124    return false;
   3125  }
   3126 
   3127  if (NS_GET_A(aColor) == 0) {
   3128    return true;
   3129  }
   3130 
   3131  nsRegion region;
   3132  region.Sub(aBackgroundRect, *static_cast<nsRegion*>(cutoutRegion));
   3133  region.MoveBy(aBuilder->ToReferenceFrame(aFrame));
   3134  aList->AppendNewToTop<nsDisplaySolidColorRegion>(aBuilder, aFrame, region,
   3135                                                   aColor);
   3136 
   3137  return true;
   3138 }
   3139 
   3140 enum class TableType : uint8_t {
   3141  Table,
   3142  TableCol,
   3143  TableColGroup,
   3144  TableRow,
   3145  TableRowGroup,
   3146  TableCell,
   3147 
   3148  MAX,
   3149 };
   3150 
   3151 enum class TableTypeBits : uint8_t { Count = 3 };
   3152 
   3153 static_assert(static_cast<uint8_t>(TableType::MAX) <
   3154                  (1 << (static_cast<uint8_t>(TableTypeBits::Count) + 1)),
   3155              "TableType cannot fit with TableTypeBits::Count");
   3156 TableType GetTableTypeFromFrame(nsIFrame* aFrame);
   3157 
   3158 static uint16_t CalculateTablePerFrameKey(const uint16_t aIndex,
   3159                                          const TableType aType) {
   3160  const uint32_t key = (aIndex << static_cast<uint8_t>(TableTypeBits::Count)) |
   3161                       static_cast<uint8_t>(aType);
   3162 
   3163  return static_cast<uint16_t>(key);
   3164 }
   3165 
   3166 static nsDisplayBackgroundImage* CreateBackgroundImage(
   3167    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aSecondaryFrame,
   3168    const nsDisplayBackgroundImage::InitData& aBgData) {
   3169  const auto index = aBgData.layer;
   3170 
   3171  if (aSecondaryFrame) {
   3172    const auto tableType = GetTableTypeFromFrame(aFrame);
   3173    const uint16_t tableItemIndex = CalculateTablePerFrameKey(index, tableType);
   3174 
   3175    return MakeDisplayItemWithIndex<nsDisplayTableBackgroundImage>(
   3176        aBuilder, aSecondaryFrame, tableItemIndex, aBgData, aFrame);
   3177  }
   3178 
   3179  return MakeDisplayItemWithIndex<nsDisplayBackgroundImage>(aBuilder, aFrame,
   3180                                                            index, aBgData);
   3181 }
   3182 
   3183 static nsDisplayThemedBackground* CreateThemedBackground(
   3184    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aSecondaryFrame,
   3185    const nsRect& aBgRect) {
   3186  if (aSecondaryFrame) {
   3187    const uint16_t index = static_cast<uint16_t>(GetTableTypeFromFrame(aFrame));
   3188    return MakeDisplayItemWithIndex<nsDisplayTableThemedBackground>(
   3189        aBuilder, aSecondaryFrame, index, aBgRect, aFrame);
   3190  }
   3191 
   3192  return MakeDisplayItem<nsDisplayThemedBackground>(aBuilder, aFrame, aBgRect);
   3193 }
   3194 
   3195 static nsDisplayBackgroundColor* CreateBackgroundColor(
   3196    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aSecondaryFrame,
   3197    nsRect& aBgRect, const ComputedStyle* aBgSC, nscolor aColor) {
   3198  if (aSecondaryFrame) {
   3199    const uint16_t index = static_cast<uint16_t>(GetTableTypeFromFrame(aFrame));
   3200    return MakeDisplayItemWithIndex<nsDisplayTableBackgroundColor>(
   3201        aBuilder, aSecondaryFrame, index, aBgRect, aBgSC, aColor, aFrame);
   3202  }
   3203 
   3204  return MakeDisplayItem<nsDisplayBackgroundColor>(aBuilder, aFrame, aBgRect,
   3205                                                   aBgSC, aColor);
   3206 }
   3207 
   3208 static void DealWithWindowsAppearanceHacks(nsIFrame* aFrame,
   3209                                           nsDisplayListBuilder* aBuilder) {
   3210  if (!XRE_IsParentProcess()) {
   3211    return;
   3212  }
   3213 
   3214  const auto& disp = *aFrame->StyleDisplay();
   3215 
   3216  // We use default appearance rather than effective appearance because we want
   3217  // to handle when titlebar buttons that have appearance: none.
   3218  const auto defaultAppearance = disp.mDefaultAppearance;
   3219  if (MOZ_LIKELY(defaultAppearance == StyleAppearance::None)) {
   3220    return;
   3221  }
   3222 
   3223  if (auto type = disp.GetWindowButtonType()) {
   3224    if (auto* widget = aFrame->GetNearestWidget()) {
   3225      auto rect = LayoutDevicePixel::FromAppUnitsToNearest(
   3226          nsRect(aBuilder->ToReferenceFrame(aFrame), aFrame->GetSize()),
   3227          aFrame->PresContext()->AppUnitsPerDevPixel());
   3228      widget->SetWindowButtonRect(*type, rect);
   3229    }
   3230  }
   3231 }
   3232 
   3233 /*static*/
   3234 AppendedBackgroundType nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
   3235    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   3236    const nsRect& aBackgroundRect, nsDisplayList* aList,
   3237    bool aAllowWillPaintBorderOptimization, const nsRect& aBackgroundOriginRect,
   3238    nsIFrame* aSecondaryReferenceFrame,
   3239    Maybe<nsDisplayListBuilder::AutoBuildingDisplayList>*
   3240        aAutoBuildingDisplayList) {
   3241  MOZ_ASSERT(!aFrame->IsCanvasFrame(),
   3242             "We don't expect propagated canvas backgrounds here");
   3243 #ifdef DEBUG
   3244  {
   3245    nsIFrame* bgFrame = nsCSSRendering::FindBackgroundFrame(aFrame);
   3246    MOZ_ASSERT(
   3247        !bgFrame || bgFrame == aFrame,
   3248        "Should only suppress backgrounds, never propagate to another frame");
   3249  }
   3250 #endif
   3251 
   3252  DealWithWindowsAppearanceHacks(aFrame, aBuilder);
   3253 
   3254  const bool isThemed = aFrame->IsThemed();
   3255 
   3256  const ComputedStyle* bgSC = aFrame->Style();
   3257  const nsStyleBackground* bg = bgSC->StyleBackground();
   3258  const bool needsBackgroundColor =
   3259      aBuilder->IsForEventDelivery() ||
   3260      (EffectCompositor::HasAnimationsForCompositor(
   3261           aFrame, DisplayItemType::TYPE_BACKGROUND_COLOR) &&
   3262       !isThemed);
   3263  if (!needsBackgroundColor && !isThemed && bg->IsTransparent(bgSC)) {
   3264    return AppendedBackgroundType::None;
   3265  }
   3266 
   3267  bool drawBackgroundColor = false;
   3268  bool drawBackgroundImage = false;
   3269  nscolor color = NS_RGBA(0, 0, 0, 0);
   3270  // Don't get background color / images if we propagated our background to the
   3271  // canvas (that is, if FindBackgroundFrame is null). But don't early return
   3272  // yet, since we might still need a background-color item for hit-testing.
   3273  if (!isThemed && nsCSSRendering::FindBackgroundFrame(aFrame)) {
   3274    color = nsCSSRendering::DetermineBackgroundColor(
   3275        aFrame->PresContext(), bgSC, aFrame, drawBackgroundImage,
   3276        drawBackgroundColor);
   3277  }
   3278 
   3279  if (SpecialCutoutRegionCase(aBuilder, aFrame, aBackgroundRect, aList,
   3280                              color)) {
   3281    return AppendedBackgroundType::None;
   3282  }
   3283 
   3284  const nsStyleBorder& border = *aFrame->StyleBorder();
   3285  const bool willPaintBorder =
   3286      aAllowWillPaintBorderOptimization && !isThemed &&
   3287      !aFrame->StyleEffects()->HasBoxShadowWithInset(true) &&
   3288      border.HasBorder();
   3289 
   3290  auto EnsureBuildingDisplayList = [&] {
   3291    if (!aAutoBuildingDisplayList || *aAutoBuildingDisplayList) {
   3292      return;
   3293    }
   3294    nsPoint offset = aBuilder->GetCurrentFrame()->GetOffsetTo(aFrame);
   3295    aAutoBuildingDisplayList->emplace(aBuilder, aFrame,
   3296                                      aBuilder->GetVisibleRect() + offset,
   3297                                      aBuilder->GetDirtyRect() + offset);
   3298  };
   3299 
   3300  // An auxiliary list is necessary in case we have background blending; if that
   3301  // is the case, background items need to be wrapped by a blend container to
   3302  // isolate blending to the background
   3303  nsDisplayList bgItemList(aBuilder);
   3304  // Even if we don't actually have a background color to paint, we may still
   3305  // need to create an item for hit testing and we still need to create an item
   3306  // for background-color animations.
   3307  if ((drawBackgroundColor && color != NS_RGBA(0, 0, 0, 0)) ||
   3308      needsBackgroundColor) {
   3309    EnsureBuildingDisplayList();
   3310    Maybe<DisplayListClipState::AutoSaveRestore> clipState;
   3311    nsRect bgColorRect = aBackgroundRect;
   3312    if (!isThemed && !aBuilder->IsForEventDelivery()) {
   3313      // Disable the will-paint-border optimization for background
   3314      // colors with no border-radius. Enabling it for background colors
   3315      // doesn't help much (there are no tiling issues) and clipping the
   3316      // background breaks detection of the element's border-box being
   3317      // opaque. For nonzero border-radius we still need it because we
   3318      // want to inset the background if possible to avoid antialiasing
   3319      // artifacts along the rounded corners.
   3320      const bool useWillPaintBorderOptimization =
   3321          willPaintBorder &&
   3322          nsLayoutUtils::HasNonZeroCorner(border.mBorderRadius);
   3323 
   3324      nsCSSRendering::ImageLayerClipState clip;
   3325      nsCSSRendering::GetImageLayerClip(
   3326          bg->BottomLayer(), aFrame, border, aBackgroundRect, aBackgroundRect,
   3327          useWillPaintBorderOptimization,
   3328          aFrame->PresContext()->AppUnitsPerDevPixel(), &clip);
   3329 
   3330      bgColorRect = bgColorRect.Intersect(clip.mBGClipArea);
   3331      if (clip.mHasAdditionalBGClipArea) {
   3332        bgColorRect = bgColorRect.Intersect(clip.mAdditionalBGClipArea);
   3333      }
   3334      if (clip.mHasRoundedCorners) {
   3335        clipState.emplace(aBuilder);
   3336        clipState->ClipContentDescendants(clip.mBGClipArea, &clip.mRadii);
   3337      }
   3338    }
   3339 
   3340    nsDisplayBackgroundColor* bgItem = CreateBackgroundColor(
   3341        aBuilder, aFrame, aSecondaryReferenceFrame, bgColorRect, bgSC,
   3342        drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0));
   3343 
   3344    if (bgItem) {
   3345      bgItemList.AppendToTop(bgItem);
   3346    }
   3347  }
   3348 
   3349  if (isThemed) {
   3350    nsDisplayThemedBackground* bgItem = CreateThemedBackground(
   3351        aBuilder, aFrame, aSecondaryReferenceFrame, aBackgroundRect);
   3352 
   3353    if (bgItem) {
   3354      bgItem->Init(aBuilder);
   3355      bgItemList.AppendToTop(bgItem);
   3356    }
   3357 
   3358    if (!bgItemList.IsEmpty()) {
   3359      aList->AppendToTop(&bgItemList);
   3360      return AppendedBackgroundType::ThemedBackground;
   3361    }
   3362 
   3363    return AppendedBackgroundType::None;
   3364  }
   3365 
   3366  if (!drawBackgroundImage) {
   3367    if (!bgItemList.IsEmpty()) {
   3368      aList->AppendToTop(&bgItemList);
   3369      return AppendedBackgroundType::Background;
   3370    }
   3371 
   3372    return AppendedBackgroundType::None;
   3373  }
   3374 
   3375  const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
   3376 
   3377  bool needBlendContainer = false;
   3378  const nsRect& bgOriginRect =
   3379      aBackgroundOriginRect.IsEmpty() ? aBackgroundRect : aBackgroundOriginRect;
   3380 
   3381  // Passing bg == nullptr in this macro will result in one iteration with
   3382  // i = 0.
   3383  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
   3384    if (bg->mImage.mLayers[i].mImage.IsNone()) {
   3385      continue;
   3386    }
   3387 
   3388    EnsureBuildingDisplayList();
   3389 
   3390    if (bg->mImage.mLayers[i].mBlendMode != StyleBlend::Normal) {
   3391      needBlendContainer = true;
   3392    }
   3393 
   3394    DisplayListClipState::AutoSaveRestore clipState(aBuilder);
   3395    if (!aBuilder->IsForEventDelivery()) {
   3396      const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
   3397      SetBackgroundClipRegion(clipState, aFrame, layer, aBackgroundRect,
   3398                              willPaintBorder);
   3399    }
   3400 
   3401    nsDisplayList thisItemList(aBuilder);
   3402    nsDisplayBackgroundImage::InitData bgData =
   3403        nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgOriginRect,
   3404                                              bgSC);
   3405 
   3406    if (bgData.shouldFixToViewport) {
   3407      auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
   3408      nsDisplayListBuilder::AutoBuildingDisplayList buildingDisplayList(
   3409          aBuilder, aFrame, aBuilder->GetVisibleRect(),
   3410          aBuilder->GetDirtyRect());
   3411 
   3412      nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(
   3413          aBuilder);
   3414      if (displayData) {
   3415        asrSetter.SetCurrentActiveScrolledRoot(
   3416            displayData->mContainingBlockActiveScrolledRoot);
   3417        asrSetter.SetCurrentScrollParentId(displayData->mScrollParentId);
   3418        if (nsLayoutUtils::UsesAsyncScrolling(aFrame)) {
   3419          // Override the dirty rect on the builder to be the dirty rect of
   3420          // the viewport.
   3421          // displayData->mDirtyRect is relative to the presshell's viewport
   3422          // frame (the root frame), and we need it to be relative to aFrame.
   3423          nsIFrame* rootFrame =
   3424              aBuilder->CurrentPresShellState()->mPresShell->GetRootFrame();
   3425          // There cannot be any transforms between aFrame and rootFrame
   3426          // because then bgData.shouldFixToViewport would have been false.
   3427          nsRect visibleRect =
   3428              displayData->mVisibleRect + aFrame->GetOffsetTo(rootFrame);
   3429          aBuilder->SetVisibleRect(visibleRect);
   3430          nsRect dirtyRect =
   3431              displayData->mDirtyRect + aFrame->GetOffsetTo(rootFrame);
   3432          aBuilder->SetDirtyRect(dirtyRect);
   3433        }
   3434      }
   3435 
   3436      nsDisplayBackgroundImage* bgItem = nullptr;
   3437      {
   3438        // The clip is captured by the nsDisplayFixedPosition, so clear the
   3439        // clip for the nsDisplayBackgroundImage inside.
   3440        DisplayListClipState::AutoSaveRestore bgImageClip(aBuilder);
   3441        bgImageClip.Clear();
   3442        bgItem = CreateBackgroundImage(aBuilder, aFrame,
   3443                                       aSecondaryReferenceFrame, bgData);
   3444      }
   3445      if (bgItem) {
   3446        const ActiveScrolledRoot* scrollTargetASR =
   3447            asr ? asr->GetNearestScrollASR() : nullptr;
   3448        thisItemList.AppendToTop(
   3449            nsDisplayFixedPosition::CreateForFixedBackground(
   3450                aBuilder, aFrame, aSecondaryReferenceFrame, bgItem, i,
   3451                scrollTargetASR));
   3452      }
   3453    } else {  // bgData.shouldFixToViewport == false
   3454      nsDisplayBackgroundImage* bgItem = CreateBackgroundImage(
   3455          aBuilder, aFrame, aSecondaryReferenceFrame, bgData);
   3456      if (bgItem) {
   3457        thisItemList.AppendToTop(bgItem);
   3458      }
   3459    }
   3460 
   3461    if (bg->mImage.mLayers[i].mBlendMode != StyleBlend::Normal) {
   3462      // asr is scrolled. Even if we wrap a fixed background layer, that's
   3463      // fine, because the item will have a scrolled clip that limits the
   3464      // item with respect to asr.
   3465      if (aSecondaryReferenceFrame) {
   3466        const auto tableType = GetTableTypeFromFrame(aFrame);
   3467        const uint16_t index = CalculateTablePerFrameKey(i + 1, tableType);
   3468 
   3469        thisItemList.AppendNewToTopWithIndex<nsDisplayTableBlendMode>(
   3470            aBuilder, aSecondaryReferenceFrame, index, &thisItemList,
   3471            bg->mImage.mLayers[i].mBlendMode, asr, ContainerASRType::Constant,
   3472            aFrame, true);
   3473      } else {
   3474        thisItemList.AppendNewToTopWithIndex<nsDisplayBlendMode>(
   3475            aBuilder, aFrame, i + 1, &thisItemList,
   3476            bg->mImage.mLayers[i].mBlendMode, asr, ContainerASRType::Constant,
   3477            true);
   3478      }
   3479    }
   3480    bgItemList.AppendToTop(&thisItemList);
   3481  }
   3482 
   3483  if (needBlendContainer) {
   3484    bgItemList.AppendToTop(
   3485        nsDisplayBlendContainer::CreateForBackgroundBlendMode(
   3486            aBuilder, aFrame, aSecondaryReferenceFrame, &bgItemList, asr,
   3487            nsDisplayItem::ContainerASRType::Constant));
   3488  }
   3489 
   3490  if (!bgItemList.IsEmpty()) {
   3491    aList->AppendToTop(&bgItemList);
   3492    return AppendedBackgroundType::Background;
   3493  }
   3494 
   3495  return AppendedBackgroundType::None;
   3496 }
   3497 
   3498 // Check that the rounded border of aFrame, added to aToReferenceFrame,
   3499 // intersects aRect.  Assumes that the unrounded border has already
   3500 // been checked for intersection.
   3501 static bool RoundedBorderIntersectsRect(nsIFrame* aFrame,
   3502                                        const nsPoint& aFrameToReferenceFrame,
   3503                                        const nsRect& aTestRect) {
   3504  if (!nsRect(aFrameToReferenceFrame, aFrame->GetSize())
   3505           .Intersects(aTestRect)) {
   3506    return false;
   3507  }
   3508 
   3509  nsRectCornerRadii radii;
   3510  return !aFrame->GetBorderRadii(radii) ||
   3511         nsLayoutUtils::RoundedRectIntersectsRect(
   3512             nsRect(aFrameToReferenceFrame, aFrame->GetSize()), radii,
   3513             aTestRect);
   3514 }
   3515 
   3516 // Returns TRUE if aContainedRect is guaranteed to be contained in
   3517 // the rounded rect defined by aRoundedRect and aRadii. Complex cases are
   3518 // handled conservatively by returning FALSE in some situations where
   3519 // a more thorough analysis could return TRUE.
   3520 //
   3521 // See also RoundedRectIntersectsRect.
   3522 static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
   3523                                    const nsRectCornerRadii& aRadii,
   3524                                    const nsRect& aContainedRect) {
   3525  nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii,
   3526                                                         aContainedRect);
   3527  return rgn.Contains(aContainedRect);
   3528 }
   3529 
   3530 bool nsDisplayBackgroundImage::CanApplyOpacity(
   3531    WebRenderLayerManager* aManager, nsDisplayListBuilder* aBuilder) const {
   3532  return CanBuildWebRenderDisplayItems(aManager, aBuilder);
   3533 }
   3534 
   3535 bool nsDisplayBackgroundImage::CanBuildWebRenderDisplayItems(
   3536    WebRenderLayerManager* aManager, nsDisplayListBuilder* aBuilder) const {
   3537  return mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mClip !=
   3538             StyleGeometryBox::Text &&
   3539         nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(
   3540             aManager, *StyleFrame()->PresContext(), StyleFrame(),
   3541             mBackgroundStyle->StyleBackground(), mLayer,
   3542             aBuilder->GetBackgroundPaintFlags());
   3543 }
   3544 
   3545 bool nsDisplayBackgroundImage::CreateWebRenderCommands(
   3546    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   3547    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   3548    nsDisplayListBuilder* aDisplayListBuilder) {
   3549  if (!CanBuildWebRenderDisplayItems(aManager->LayerManager(),
   3550                                     aDisplayListBuilder)) {
   3551    return false;
   3552  }
   3553 
   3554  uint32_t paintFlags = aDisplayListBuilder->GetBackgroundPaintFlags();
   3555  bool dummy;
   3556  nsCSSRendering::PaintBGParams params =
   3557      nsCSSRendering::PaintBGParams::ForSingleLayer(
   3558          *StyleFrame()->PresContext(), GetBounds(aDisplayListBuilder, &dummy),
   3559          mBackgroundRect, StyleFrame(), paintFlags, mLayer,
   3560          CompositionOp::OP_OVER, aBuilder.GetInheritedOpacity());
   3561  params.bgClipRect = &mBounds;
   3562  ImgDrawResult result =
   3563      nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(
   3564          params, aBuilder, aResources, aSc, aManager, this);
   3565  if (result == ImgDrawResult::NOT_SUPPORTED) {
   3566    return false;
   3567  }
   3568 
   3569  if (nsIContent* content = StyleFrame()->GetContent()) {
   3570    if (imgRequestProxy* requestProxy = mBackgroundStyle->StyleBackground()
   3571                                            ->mImage.mLayers[mLayer]
   3572                                            .mImage.GetImageRequest()) {
   3573      // LCP don't consider gradient backgrounds.
   3574      LCPHelpers::FinalizeLCPEntryForImage(content->AsElement(), requestProxy,
   3575                                           mBounds - ToReferenceFrame());
   3576    }
   3577  }
   3578 
   3579  return true;
   3580 }
   3581 
   3582 void nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
   3583                                       const nsRect& aRect,
   3584                                       HitTestState* aState,
   3585                                       nsTArray<nsIFrame*>* aOutFrames) {
   3586  if (ShouldIgnoreForBackfaceHidden(aState)) {
   3587    return;
   3588  }
   3589 
   3590  if (RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
   3591    aOutFrames->AppendElement(mFrame);
   3592  }
   3593 }
   3594 
   3595 static nsRect GetInsideClipRect(const nsDisplayItem* aItem,
   3596                                StyleGeometryBox aClip, const nsRect& aRect,
   3597                                const nsRect& aBackgroundRect) {
   3598  if (aRect.IsEmpty()) {
   3599    return {};
   3600  }
   3601 
   3602  nsIFrame* frame = aItem->Frame();
   3603 
   3604  nsRect clipRect = aBackgroundRect;
   3605  if (frame->IsCanvasFrame()) {
   3606    nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame);
   3607    clipRect = canvasFrame->CanvasArea() + aItem->ToReferenceFrame();
   3608  } else if (aClip == StyleGeometryBox::PaddingBox ||
   3609             aClip == StyleGeometryBox::ContentBox) {
   3610    nsMargin border = frame->GetUsedBorder();
   3611    if (aClip == StyleGeometryBox::ContentBox) {
   3612      border += frame->GetUsedPadding();
   3613    }
   3614    border.ApplySkipSides(frame->GetSkipSides());
   3615    clipRect.Deflate(border);
   3616  }
   3617 
   3618  return clipRect.Intersect(aRect);
   3619 }
   3620 
   3621 nsRegion nsDisplayBackgroundImage::GetOpaqueRegion(
   3622    nsDisplayListBuilder* aBuilder, bool* aSnap) const {
   3623  nsRegion result;
   3624  *aSnap = false;
   3625 
   3626  if (!mBackgroundStyle) {
   3627    return result;
   3628  }
   3629 
   3630  *aSnap = true;
   3631 
   3632  // For StyleBoxDecorationBreak::Slice, don't try to optimize here, since
   3633  // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
   3634  // which expects frames to be sent to it in content order, not reverse
   3635  // content order which we'll produce here.
   3636  // Of course, if there's only one frame in the flow, it doesn't matter.
   3637  if (mFrame->StyleBorder()->mBoxDecorationBreak ==
   3638          StyleBoxDecorationBreak::Clone ||
   3639      (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
   3640    const nsStyleImageLayers::Layer& layer =
   3641        mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
   3642    if (layer.mImage.IsOpaque() && layer.mBlendMode == StyleBlend::Normal &&
   3643        layer.mRepeat.mXRepeat != StyleImageLayerRepeat::Space &&
   3644        layer.mRepeat.mYRepeat != StyleImageLayerRepeat::Space &&
   3645        layer.mClip != StyleGeometryBox::Text) {
   3646      result = GetInsideClipRect(this, layer.mClip, mBounds, mBackgroundRect);
   3647    }
   3648  }
   3649 
   3650  return result;
   3651 }
   3652 
   3653 Maybe<nscolor> nsDisplayBackgroundImage::IsUniform(
   3654    nsDisplayListBuilder* aBuilder) const {
   3655  if (!mBackgroundStyle) {
   3656    return Some(NS_RGBA(0, 0, 0, 0));
   3657  }
   3658  return Nothing();
   3659 }
   3660 
   3661 nsRect nsDisplayBackgroundImage::GetPositioningArea() const {
   3662  if (!mBackgroundStyle) {
   3663    return nsRect();
   3664  }
   3665  nsIFrame* attachedToFrame;
   3666  bool transformedFixed;
   3667  return nsCSSRendering::ComputeImageLayerPositioningArea(
   3668             mFrame->PresContext(), mFrame, mBackgroundRect,
   3669             mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer],
   3670             &attachedToFrame, &transformedFixed) +
   3671         ToReferenceFrame();
   3672 }
   3673 
   3674 bool nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
   3675    const {
   3676  if (!mBackgroundStyle) {
   3677    return false;
   3678  }
   3679 
   3680  nsRectCornerRadii radii;
   3681  if (mFrame->GetBorderRadii(radii)) {
   3682    // A change in the size of the positioning area might change the position
   3683    // of the rounded corners.
   3684    return true;
   3685  }
   3686 
   3687  const nsStyleImageLayers::Layer& layer =
   3688      mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
   3689  return layer.RenderingMightDependOnPositioningAreaSizeChange();
   3690 }
   3691 
   3692 void nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
   3693                                     gfxContext* aCtx) {
   3694  PaintInternal(aBuilder, aCtx, GetPaintRect(aBuilder, aCtx), &mBounds);
   3695 }
   3696 
   3697 void nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
   3698                                             gfxContext* aCtx,
   3699                                             const nsRect& aBounds,
   3700                                             nsRect* aClipRect) {
   3701  gfxContext* ctx = aCtx;
   3702  StyleGeometryBox clip =
   3703      mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mClip;
   3704 
   3705  if (clip == StyleGeometryBox::Text) {
   3706    if (!GenerateAndPushTextMask(StyleFrame(), aCtx, mBackgroundRect,
   3707                                 aBuilder)) {
   3708      return;
   3709    }
   3710  }
   3711 
   3712  nsCSSRendering::PaintBGParams params =
   3713      nsCSSRendering::PaintBGParams::ForSingleLayer(
   3714          *StyleFrame()->PresContext(), aBounds, mBackgroundRect, StyleFrame(),
   3715          aBuilder->GetBackgroundPaintFlags(), mLayer, CompositionOp::OP_OVER,
   3716          1.0f);
   3717  params.bgClipRect = aClipRect;
   3718  (void)nsCSSRendering::PaintStyleImageLayer(params, *aCtx);
   3719 
   3720  if (clip == StyleGeometryBox::Text) {
   3721    ctx->PopGroupAndBlend();
   3722  }
   3723 }
   3724 
   3725 void nsDisplayBackgroundImage::ComputeInvalidationRegion(
   3726    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   3727    nsRegion* aInvalidRegion) const {
   3728  if (!mBackgroundStyle) {
   3729    return;
   3730  }
   3731 
   3732  const auto* geometry =
   3733      static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
   3734 
   3735  bool snap;
   3736  nsRect bounds = GetBounds(aBuilder, &snap);
   3737  nsRect positioningArea = GetPositioningArea();
   3738  if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() ||
   3739      (positioningArea.Size() != geometry->mPositioningArea.Size() &&
   3740       RenderingMightDependOnPositioningAreaSizeChange())) {
   3741    // Positioning area changed in a way that could cause everything to change,
   3742    // so invalidate everything (both old and new painting areas).
   3743    aInvalidRegion->Or(bounds, geometry->mBounds);
   3744    return;
   3745  }
   3746  if (!mDestRect.IsEqualInterior(geometry->mDestRect)) {
   3747    // Dest area changed in a way that could cause everything to change,
   3748    // so invalidate everything (both old and new painting areas).
   3749    aInvalidRegion->Or(bounds, geometry->mBounds);
   3750    return;
   3751  }
   3752  if (!bounds.IsEqualInterior(geometry->mBounds)) {
   3753    // Positioning area is unchanged, so invalidate just the change in the
   3754    // painting area.
   3755    aInvalidRegion->Xor(bounds, geometry->mBounds);
   3756  }
   3757 }
   3758 
   3759 nsRect nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder,
   3760                                           bool* aSnap) const {
   3761  *aSnap = true;
   3762  return mBounds;
   3763 }
   3764 
   3765 nsRect nsDisplayBackgroundImage::GetBoundsInternal(
   3766    nsDisplayListBuilder* aBuilder, nsIFrame* aFrameForBounds) {
   3767  // This allows nsDisplayTableBackgroundImage to change the frame used for
   3768  // bounds calculation.
   3769  nsIFrame* frame = aFrameForBounds ? aFrameForBounds : mFrame;
   3770 
   3771  nsPresContext* presContext = frame->PresContext();
   3772 
   3773  if (!mBackgroundStyle) {
   3774    return nsRect();
   3775  }
   3776 
   3777  nsRect clipRect = mBackgroundRect;
   3778  if (frame->IsCanvasFrame()) {
   3779    nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame);
   3780    clipRect = canvasFrame->CanvasArea() + ToReferenceFrame();
   3781  }
   3782  const nsStyleImageLayers::Layer& layer =
   3783      mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
   3784  return nsCSSRendering::GetBackgroundLayerRect(
   3785      presContext, frame, mBackgroundRect, clipRect, layer,
   3786      aBuilder->GetBackgroundPaintFlags());
   3787 }
   3788 
   3789 nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(
   3790    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const InitData& aData,
   3791    nsIFrame* aCellFrame)
   3792    : nsDisplayBackgroundImage(aBuilder, aFrame, aData, aCellFrame),
   3793      mStyleFrame(aCellFrame) {
   3794  if (aBuilder->IsRetainingDisplayList()) {
   3795    mStyleFrame->AddDisplayItem(this);
   3796  }
   3797 }
   3798 
   3799 void nsDisplayTableBackgroundImage::Destroy(nsDisplayListBuilder* aBuilder) {
   3800  RemoveDisplayItemFromFrame(aBuilder, mStyleFrame);
   3801  nsDisplayBackgroundImage::Destroy(aBuilder);
   3802 }
   3803 
   3804 bool nsDisplayTableBackgroundImage::IsInvalid(nsRect& aRect) const {
   3805  bool result = mStyleFrame ? mStyleFrame->IsInvalid(aRect) : false;
   3806  aRect += ToReferenceFrame();
   3807  return result;
   3808 }
   3809 
   3810 nsDisplayThemedBackground::nsDisplayThemedBackground(
   3811    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   3812    const nsRect& aBackgroundRect)
   3813    : nsPaintedDisplayItem(aBuilder, aFrame), mBackgroundRect(aBackgroundRect) {
   3814  MOZ_COUNT_CTOR(nsDisplayThemedBackground);
   3815 }
   3816 
   3817 void nsDisplayThemedBackground::Init(nsDisplayListBuilder* aBuilder) {
   3818  const nsStyleDisplay* disp = StyleFrame()->StyleDisplay();
   3819  mAppearance = disp->EffectiveAppearance();
   3820  StyleFrame()->IsThemed(disp, &mThemeTransparency);
   3821 
   3822  // Perform necessary RegisterThemeGeometry
   3823  nsITheme* theme = StyleFrame()->PresContext()->Theme();
   3824  nsITheme::ThemeGeometryType type =
   3825      theme->ThemeGeometryTypeForWidget(StyleFrame(), mAppearance);
   3826  if (type != nsITheme::eThemeGeometryTypeUnknown) {
   3827    RegisterThemeGeometry(aBuilder, this, StyleFrame(), type);
   3828  }
   3829 
   3830  mBounds = GetBoundsInternal();
   3831 }
   3832 
   3833 void nsDisplayThemedBackground::WriteDebugInfo(std::stringstream& aStream) {
   3834  aStream << " (themed, appearance:" << (int)mAppearance << ")";
   3835 }
   3836 
   3837 void nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder,
   3838                                        const nsRect& aRect,
   3839                                        HitTestState* aState,
   3840                                        nsTArray<nsIFrame*>* aOutFrames) {
   3841  if (ShouldIgnoreForBackfaceHidden(aState)) {
   3842    return;
   3843  }
   3844 
   3845  // Assume that any point in our background rect is a hit.
   3846  if (mBackgroundRect.Intersects(aRect)) {
   3847    aOutFrames->AppendElement(mFrame);
   3848  }
   3849 }
   3850 
   3851 nsRegion nsDisplayThemedBackground::GetOpaqueRegion(
   3852    nsDisplayListBuilder* aBuilder, bool* aSnap) const {
   3853  nsRegion result;
   3854  *aSnap = false;
   3855 
   3856  if (mThemeTransparency == nsITheme::eOpaque) {
   3857    *aSnap = true;
   3858    result = mBackgroundRect;
   3859  }
   3860  return result;
   3861 }
   3862 
   3863 Maybe<nscolor> nsDisplayThemedBackground::IsUniform(
   3864    nsDisplayListBuilder* aBuilder) const {
   3865  return Nothing();
   3866 }
   3867 
   3868 nsRect nsDisplayThemedBackground::GetPositioningArea() const {
   3869  return mBackgroundRect;
   3870 }
   3871 
   3872 void nsDisplayThemedBackground::Paint(nsDisplayListBuilder* aBuilder,
   3873                                      gfxContext* aCtx) {
   3874  PaintInternal(aBuilder, aCtx, GetPaintRect(aBuilder, aCtx), nullptr);
   3875 }
   3876 
   3877 void nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder,
   3878                                              gfxContext* aCtx,
   3879                                              const nsRect& aBounds,
   3880                                              nsRect* aClipRect) {
   3881  // XXXzw this ignores aClipRect.
   3882  nsPresContext* presContext = StyleFrame()->PresContext();
   3883  nsITheme* theme = presContext->Theme();
   3884  nsRect drawing(mBackgroundRect);
   3885  theme->GetWidgetOverflow(presContext->DeviceContext(), StyleFrame(),
   3886                           mAppearance, &drawing);
   3887  drawing.IntersectRect(drawing, aBounds);
   3888  theme->DrawWidgetBackground(aCtx, StyleFrame(), mAppearance, mBackgroundRect,
   3889                              drawing);
   3890 }
   3891 
   3892 bool nsDisplayThemedBackground::CreateWebRenderCommands(
   3893    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   3894    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   3895    nsDisplayListBuilder* aDisplayListBuilder) {
   3896  nsITheme* theme = StyleFrame()->PresContext()->Theme();
   3897  return theme->CreateWebRenderCommandsForWidget(aBuilder, aResources, aSc,
   3898                                                 aManager, StyleFrame(),
   3899                                                 mAppearance, mBackgroundRect);
   3900 }
   3901 
   3902 bool nsDisplayThemedBackground::IsWindowActive() const {
   3903  return !mFrame->PresContext()->Document()->IsTopLevelWindowInactive();
   3904 }
   3905 
   3906 void nsDisplayThemedBackground::ComputeInvalidationRegion(
   3907    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   3908    nsRegion* aInvalidRegion) const {
   3909  const auto* geometry =
   3910      static_cast<const nsDisplayThemedBackgroundGeometry*>(aGeometry);
   3911 
   3912  bool snap;
   3913  nsRect bounds = GetBounds(aBuilder, &snap);
   3914  nsRect positioningArea = GetPositioningArea();
   3915  if (!positioningArea.IsEqualInterior(geometry->mPositioningArea)) {
   3916    // Invalidate everything (both old and new painting areas).
   3917    aInvalidRegion->Or(bounds, geometry->mBounds);
   3918    return;
   3919  }
   3920  if (!bounds.IsEqualInterior(geometry->mBounds)) {
   3921    // Positioning area is unchanged, so invalidate just the change in the
   3922    // painting area.
   3923    aInvalidRegion->Xor(bounds, geometry->mBounds);
   3924  }
   3925  nsITheme* theme = StyleFrame()->PresContext()->Theme();
   3926  if (theme->WidgetAppearanceDependsOnWindowFocus(mAppearance) &&
   3927      IsWindowActive() != geometry->mWindowIsActive) {
   3928    aInvalidRegion->Or(*aInvalidRegion, bounds);
   3929  }
   3930 }
   3931 
   3932 nsRect nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder,
   3933                                            bool* aSnap) const {
   3934  *aSnap = true;
   3935  return mBounds;
   3936 }
   3937 
   3938 nsRect nsDisplayThemedBackground::GetBoundsInternal() {
   3939  nsPresContext* presContext = mFrame->PresContext();
   3940 
   3941  nsRect r = mBackgroundRect - ToReferenceFrame();
   3942  presContext->Theme()->GetWidgetOverflow(
   3943      presContext->DeviceContext(), mFrame,
   3944      mFrame->StyleDisplay()->EffectiveAppearance(), &r);
   3945  return r + ToReferenceFrame();
   3946 }
   3947 
   3948 void nsDisplayTableThemedBackground::Destroy(nsDisplayListBuilder* aBuilder) {
   3949  RemoveDisplayItemFromFrame(aBuilder, mAncestorFrame);
   3950  nsDisplayThemedBackground::Destroy(aBuilder);
   3951 }
   3952 
   3953 #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
   3954 void nsDisplayReflowCount::Paint(nsDisplayListBuilder* aBuilder,
   3955                                 gfxContext* aCtx) {
   3956  mFrame->PresShell()->PaintCount(mFrameName, aCtx, mFrame->PresContext(),
   3957                                  mFrame, ToReferenceFrame(), mColor);
   3958 }
   3959 #endif
   3960 
   3961 void nsDisplayBackgroundColor::Destroy(nsDisplayListBuilder* aBuilder) {
   3962  RemoveDisplayItemFromFrame(aBuilder, mDependentFrame);
   3963  nsPaintedDisplayItem::Destroy(aBuilder);
   3964 }
   3965 
   3966 bool nsDisplayBackgroundColor::CanApplyOpacity(
   3967    WebRenderLayerManager* aManager, nsDisplayListBuilder* aBuilder) const {
   3968  // Don't apply opacity if the background color is animated since the color is
   3969  // going to be changed on the compositor.
   3970  return !EffectCompositor::HasAnimationsForCompositor(
   3971      mFrame, DisplayItemType::TYPE_BACKGROUND_COLOR);
   3972 }
   3973 
   3974 bool nsDisplayBackgroundColor::CreateWebRenderCommands(
   3975    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   3976    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   3977    nsDisplayListBuilder* aDisplayListBuilder) {
   3978  gfx::sRGBColor color = mColor;
   3979  color.a *= aBuilder.GetInheritedOpacity();
   3980 
   3981  if (color == sRGBColor() &&
   3982      !EffectCompositor::HasAnimationsForCompositor(
   3983          mFrame, DisplayItemType::TYPE_BACKGROUND_COLOR)) {
   3984    return true;
   3985  }
   3986 
   3987  if (HasBackgroundClipText()) {
   3988    return false;
   3989  }
   3990 
   3991  uint64_t animationsId = 0;
   3992  // We don't support background-color animations on table elements yet.
   3993  if (GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) {
   3994    animationsId =
   3995        AddAnimationsForWebRender(this, aManager, aDisplayListBuilder);
   3996  }
   3997 
   3998  LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
   3999      mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel());
   4000  wr::LayoutRect r = wr::ToLayoutRect(bounds);
   4001 
   4002  if (animationsId) {
   4003    wr::WrAnimationProperty prop{
   4004        wr::WrAnimationType::BackgroundColor,
   4005        animationsId,
   4006    };
   4007    aBuilder.PushRectWithAnimation(r, r, !BackfaceIsHidden(),
   4008                                   wr::ToColorF(ToDeviceColor(color)), &prop);
   4009  } else {
   4010    aBuilder.StartGroup(this);
   4011    aBuilder.PushRect(r, r, !BackfaceIsHidden(), false, false,
   4012                      wr::ToColorF(ToDeviceColor(color)));
   4013    aBuilder.FinishGroup();
   4014  }
   4015 
   4016  return true;
   4017 }
   4018 
   4019 void nsDisplayBackgroundColor::PaintWithClip(nsDisplayListBuilder* aBuilder,
   4020                                             gfxContext* aCtx,
   4021                                             const DisplayItemClip& aClip) {
   4022  MOZ_ASSERT(!HasBackgroundClipText());
   4023 
   4024  if (mColor == sRGBColor()) {
   4025    return;
   4026  }
   4027 
   4028  nsRect fillRect = mBackgroundRect;
   4029  if (aClip.HasClip()) {
   4030    fillRect.IntersectRect(fillRect, aClip.GetClipRect());
   4031  }
   4032 
   4033  DrawTarget* dt = aCtx->GetDrawTarget();
   4034  int32_t A2D = mFrame->PresContext()->AppUnitsPerDevPixel();
   4035  Rect bounds = ToRect(nsLayoutUtils::RectToGfxRect(fillRect, A2D));
   4036  MaybeSnapToDevicePixels(bounds, *dt);
   4037  ColorPattern fill(ToDeviceColor(mColor));
   4038 
   4039  if (aClip.GetRoundedRectCount()) {
   4040    MOZ_ASSERT(aClip.GetRoundedRectCount() == 1);
   4041 
   4042    AutoTArray<DisplayItemClip::RoundedRect, 1> roundedRect;
   4043    aClip.AppendRoundedRects(&roundedRect);
   4044 
   4045    bool pushedClip = false;
   4046    if (!fillRect.Contains(roundedRect[0].mRect)) {
   4047      dt->PushClipRect(bounds);
   4048      pushedClip = true;
   4049    }
   4050 
   4051    RectCornerRadii pixelRadii;
   4052    nsCSSRendering::ComputePixelRadii(roundedRect[0].mRadii, A2D, &pixelRadii);
   4053    dt->FillRoundedRect(
   4054        RoundedRect(NSRectToSnappedRect(roundedRect[0].mRect, A2D, *dt),
   4055                    pixelRadii),
   4056        fill);
   4057    if (pushedClip) {
   4058      dt->PopClip();
   4059    }
   4060  } else {
   4061    dt->FillRect(bounds, fill);
   4062  }
   4063 }
   4064 
   4065 void nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
   4066                                     gfxContext* aCtx) {
   4067  if (mColor == sRGBColor()) {
   4068    return;
   4069  }
   4070 
   4071 #if 0
   4072  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1148418#c21 for why this
   4073  // results in a precision induced rounding issue that makes the rect one
   4074  // pixel shorter in rare cases. Disabled in favor of the old code for now.
   4075  // Note that the pref layout.css.devPixelsPerPx needs to be set to 1 to
   4076  // reproduce the bug.
   4077  //
   4078  // TODO:
   4079  // This new path does not include support for background-clip:text; need to
   4080  // be fixed if/when we switch to this new code path.
   4081 
   4082  DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
   4083 
   4084  Rect rect = NSRectToSnappedRect(mBackgroundRect,
   4085                                  mFrame->PresContext()->AppUnitsPerDevPixel(),
   4086                                  aDrawTarget);
   4087  ColorPattern color(ToDeviceColor(mColor));
   4088  aDrawTarget.FillRect(rect, color);
   4089 #else
   4090  gfxContext* ctx = aCtx;
   4091  gfxRect bounds = nsLayoutUtils::RectToGfxRect(
   4092      mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel());
   4093 
   4094  if (HasBackgroundClipText()) {
   4095    if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
   4096      return;
   4097    }
   4098 
   4099    ctx->SetColor(mColor);
   4100    ctx->NewPath();
   4101    ctx->SnappedRectangle(bounds);
   4102    ctx->Fill();
   4103    ctx->PopGroupAndBlend();
   4104    return;
   4105  }
   4106 
   4107  ctx->SetColor(mColor);
   4108  ctx->NewPath();
   4109  ctx->SnappedRectangle(bounds);
   4110  ctx->Fill();
   4111 #endif
   4112 }
   4113 
   4114 nsRegion nsDisplayBackgroundColor::GetOpaqueRegion(
   4115    nsDisplayListBuilder* aBuilder, bool* aSnap) const {
   4116  *aSnap = false;
   4117 
   4118  if (mColor.a != 1 ||
   4119      // Even if the current alpha channel is 1, we treat this item as if it's
   4120      // non-opaque if there is a background-color animation since the animation
   4121      // might change the alpha channel.
   4122      EffectCompositor::HasAnimationsForCompositor(
   4123          mFrame, DisplayItemType::TYPE_BACKGROUND_COLOR)) {
   4124    return nsRegion();
   4125  }
   4126 
   4127  if (!mHasStyle || HasBackgroundClipText()) {
   4128    return nsRegion();
   4129  }
   4130 
   4131  *aSnap = true;
   4132  return GetInsideClipRect(this, mBottomLayerClip, mBackgroundRect,
   4133                           mBackgroundRect);
   4134 }
   4135 
   4136 Maybe<nscolor> nsDisplayBackgroundColor::IsUniform(
   4137    nsDisplayListBuilder* aBuilder) const {
   4138  return Some(mColor.ToABGR());
   4139 }
   4140 
   4141 void nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder,
   4142                                       const nsRect& aRect,
   4143                                       HitTestState* aState,
   4144                                       nsTArray<nsIFrame*>* aOutFrames) {
   4145  if (ShouldIgnoreForBackfaceHidden(aState)) {
   4146    return;
   4147  }
   4148 
   4149  if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
   4150    // aRect doesn't intersect our border-radius curve.
   4151    return;
   4152  }
   4153 
   4154  aOutFrames->AppendElement(mFrame);
   4155 }
   4156 
   4157 void nsDisplayBackgroundColor::WriteDebugInfo(std::stringstream& aStream) {
   4158  aStream << " (rgba " << mColor.r << "," << mColor.g << "," << mColor.b << ","
   4159          << mColor.a << ")";
   4160  aStream << " backgroundRect" << mBackgroundRect;
   4161 }
   4162 
   4163 nsRect nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder,
   4164                                   bool* aSnap) const {
   4165  *aSnap = false;
   4166  return mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
   4167 }
   4168 
   4169 nsRect nsDisplayOutline::GetInnerRect() const {
   4170  if (nsRect* savedOutlineInnerRect =
   4171          mFrame->GetProperty(nsIFrame::OutlineInnerRectProperty())) {
   4172    return *savedOutlineInnerRect;
   4173  }
   4174  return mFrame->GetRectRelativeToSelf();
   4175 }
   4176 
   4177 void nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   4178  // TODO join outlines together
   4179  MOZ_ASSERT(mFrame->StyleOutline()->ShouldPaintOutline(),
   4180             "Should have not created a nsDisplayOutline!");
   4181 
   4182  nsRect rect = GetInnerRect() + ToReferenceFrame();
   4183  nsPresContext* pc = mFrame->PresContext();
   4184  if (IsThemedOutline()) {
   4185    pc->Theme()->DrawWidgetBackground(aCtx, mFrame,
   4186                                      StyleAppearance::FocusOutline, rect,
   4187                                      GetPaintRect(aBuilder, aCtx));
   4188    return;
   4189  }
   4190 
   4191  nsCSSRendering::PaintNonThemedOutline(
   4192      pc, *aCtx, mFrame, GetPaintRect(aBuilder, aCtx), rect, mFrame->Style());
   4193 }
   4194 
   4195 bool nsDisplayOutline::IsThemedOutline() const {
   4196 #ifdef DEBUG
   4197  nsPresContext* pc = mFrame->PresContext();
   4198  MOZ_ASSERT(
   4199      pc->Theme()->ThemeSupportsWidget(pc, mFrame,
   4200                                       StyleAppearance::FocusOutline),
   4201      "All of our supported platforms have support for themed focus-outlines");
   4202 #endif
   4203  return mFrame->StyleOutline()->mOutlineStyle.IsAuto();
   4204 }
   4205 
   4206 bool nsDisplayOutline::CreateWebRenderCommands(
   4207    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4208    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4209    nsDisplayListBuilder* aDisplayListBuilder) {
   4210  nsPresContext* pc = mFrame->PresContext();
   4211  nsRect rect = GetInnerRect() + ToReferenceFrame();
   4212  if (IsThemedOutline()) {
   4213    return pc->Theme()->CreateWebRenderCommandsForWidget(
   4214        aBuilder, aResources, aSc, aManager, mFrame,
   4215        StyleAppearance::FocusOutline, rect);
   4216  }
   4217 
   4218  bool dummy;
   4219  Maybe<nsCSSBorderRenderer> borderRenderer =
   4220      nsCSSRendering::CreateBorderRendererForNonThemedOutline(
   4221          pc, /* aDrawTarget = */ nullptr, mFrame,
   4222          GetBounds(aDisplayListBuilder, &dummy), rect, mFrame->Style());
   4223 
   4224  if (!borderRenderer) {
   4225    // No border renderer means "there is no outline".
   4226    // Paint nothing and return success.
   4227    return true;
   4228  }
   4229 
   4230  borderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
   4231  return true;
   4232 }
   4233 
   4234 bool nsDisplayOutline::HasRadius() const {
   4235  const auto& radius = mFrame->StyleBorder()->mBorderRadius;
   4236  return !nsLayoutUtils::HasNonZeroCorner(radius);
   4237 }
   4238 
   4239 bool nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect) const {
   4240  nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
   4241  // aRect is entirely inside the border-rect, and the outline isn't rendered
   4242  // inside the border-rect, so the outline is not visible.
   4243  return borderBox.Contains(aRect) && !HasRadius() &&
   4244         mFrame->StyleOutline()->mOutlineOffset >= 0;
   4245 }
   4246 
   4247 void nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder,
   4248                                     const nsRect& aRect, HitTestState* aState,
   4249                                     nsTArray<nsIFrame*>* aOutFrames) {
   4250  if (ShouldIgnoreForBackfaceHidden(aState)) {
   4251    return;
   4252  }
   4253 
   4254  if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
   4255    // aRect doesn't intersect our border-radius curve.
   4256    return;
   4257  }
   4258 
   4259  aOutFrames->AppendElement(mFrame);
   4260 }
   4261 
   4262 bool nsDisplayCompositorHitTestInfo::CreateWebRenderCommands(
   4263    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4264    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4265    nsDisplayListBuilder* aDisplayListBuilder) {
   4266  return true;
   4267 }
   4268 
   4269 int32_t nsDisplayCompositorHitTestInfo::ZIndex() const {
   4270  return mOverrideZIndex ? *mOverrideZIndex : nsDisplayItem::ZIndex();
   4271 }
   4272 
   4273 void nsDisplayCompositorHitTestInfo::SetOverrideZIndex(int32_t aZIndex) {
   4274  mOverrideZIndex = Some(aZIndex);
   4275 }
   4276 
   4277 nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder,
   4278                               nsIFrame* aCaretFrame)
   4279    : nsPaintedDisplayItem(aBuilder, aCaretFrame),
   4280      mCaret(aBuilder->GetCaret()),
   4281      mBounds(aBuilder->GetCaretRect() + ToReferenceFrame()) {
   4282  MOZ_COUNT_CTOR(nsDisplayCaret);
   4283  // The presence of a caret doesn't change the overflow rect
   4284  // of the owning frame, so the normal building rect might not
   4285  // include the caret at all. We use MarkFrameForDisplay to ensure
   4286  // we build this item, and here we override the building rect
   4287  // to cover the pixels we're going to draw.
   4288  SetBuildingRect(mBounds);
   4289 }
   4290 
   4291 nsRect nsDisplayCaret::GetBounds(nsDisplayListBuilder* aBuilder,
   4292                                 bool* aSnap) const {
   4293  *aSnap = true;
   4294  // The caret returns a rect in the coordinates of mFrame.
   4295  return mBounds;
   4296 }
   4297 
   4298 void nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   4299  // Note: Because we exist, we know that the caret is visible, so we don't
   4300  // need to check for the caret's visibility.
   4301  mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
   4302 }
   4303 
   4304 bool nsDisplayCaret::CreateWebRenderCommands(
   4305    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4306    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4307    nsDisplayListBuilder* aDisplayListBuilder) {
   4308  using namespace layers;
   4309  nsRect caretRect;
   4310  nsRect hookRect;
   4311  nscolor caretColor;
   4312  nsIFrame* frame =
   4313      mCaret->GetPaintGeometry(&caretRect, &hookRect, &caretColor);
   4314  if (NS_WARN_IF(!frame) || NS_WARN_IF(frame != mFrame)) {
   4315    return true;
   4316  }
   4317 
   4318  int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
   4319  gfx::DeviceColor color = ToDeviceColor(caretColor);
   4320  LayoutDeviceRect devCaretRect = LayoutDeviceRect::FromAppUnits(
   4321      caretRect + ToReferenceFrame(), appUnitsPerDevPixel);
   4322  LayoutDeviceRect devHookRect = LayoutDeviceRect::FromAppUnits(
   4323      hookRect + ToReferenceFrame(), appUnitsPerDevPixel);
   4324 
   4325  wr::LayoutRect caret = wr::ToLayoutRect(devCaretRect);
   4326  wr::LayoutRect hook = wr::ToLayoutRect(devHookRect);
   4327 
   4328  // Note, WR will pixel snap anything that is layout aligned.
   4329  aBuilder.PushRect(caret, caret, !BackfaceIsHidden(), false, false,
   4330                    wr::ToColorF(color));
   4331 
   4332  if (!devHookRect.IsEmpty()) {
   4333    aBuilder.PushRect(hook, hook, !BackfaceIsHidden(), false, false,
   4334                      wr::ToColorF(color));
   4335  }
   4336  return true;
   4337 }
   4338 
   4339 nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder,
   4340                                 nsIFrame* aFrame)
   4341    : nsPaintedDisplayItem(aBuilder, aFrame) {
   4342  MOZ_COUNT_CTOR(nsDisplayBorder);
   4343 
   4344  mBounds = CalculateBounds<nsRect>(*mFrame->StyleBorder());
   4345 }
   4346 
   4347 bool nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect) const {
   4348  nsRect paddingRect = GetPaddingRect();
   4349  const nsStyleBorder* styleBorder;
   4350  if (paddingRect.Contains(aRect) &&
   4351      !(styleBorder = mFrame->StyleBorder())->IsBorderImageSizeAvailable() &&
   4352      !nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) {
   4353    // aRect is entirely inside the content rect, and no part
   4354    // of the border is rendered inside the content rect, so we are not
   4355    // visible
   4356    // Skip this if there's a border-image (which draws a background
   4357    // too) or if there is a border-radius (which makes the border draw
   4358    // further in).
   4359    return true;
   4360  }
   4361 
   4362  return false;
   4363 }
   4364 
   4365 nsDisplayItemGeometry* nsDisplayBorder::AllocateGeometry(
   4366    nsDisplayListBuilder* aBuilder) {
   4367  return new nsDisplayBorderGeometry(this, aBuilder);
   4368 }
   4369 
   4370 void nsDisplayBorder::ComputeInvalidationRegion(
   4371    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   4372    nsRegion* aInvalidRegion) const {
   4373  const auto* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
   4374  bool snap;
   4375 
   4376  if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap))) {
   4377    // We can probably get away with only invalidating the difference
   4378    // between the border and padding rects, but the XUL ui at least
   4379    // is apparently painting a background with this?
   4380    aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
   4381  }
   4382 }
   4383 
   4384 bool nsDisplayBorder::CreateWebRenderCommands(
   4385    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4386    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4387    nsDisplayListBuilder* aDisplayListBuilder) {
   4388  nsRect rect = nsRect(ToReferenceFrame(), mFrame->GetSize());
   4389 
   4390  ImgDrawResult drawResult = nsCSSRendering::CreateWebRenderCommandsForBorder(
   4391      this, mFrame, rect, aBuilder, aResources, aSc, aManager,
   4392      aDisplayListBuilder);
   4393 
   4394  if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
   4395    return false;
   4396  }
   4397  return true;
   4398 };
   4399 
   4400 void nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   4401  nsPoint offset = ToReferenceFrame();
   4402 
   4403  PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
   4404                               ? PaintBorderFlags::SyncDecodeImages
   4405                               : PaintBorderFlags();
   4406 
   4407  (void)nsCSSRendering::PaintBorder(
   4408      mFrame->PresContext(), *aCtx, mFrame, GetPaintRect(aBuilder, aCtx),
   4409      nsRect(offset, mFrame->GetSize()), mFrame->Style(), flags,
   4410      mFrame->GetSkipSides());
   4411 }
   4412 
   4413 nsRect nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder,
   4414                                  bool* aSnap) const {
   4415  *aSnap = true;
   4416  return mBounds;
   4417 }
   4418 
   4419 void nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
   4420                                    gfxContext* aCtx) {
   4421  nsPoint offset = ToReferenceFrame();
   4422  nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
   4423  nsPresContext* presContext = mFrame->PresContext();
   4424 
   4425  AUTO_PROFILER_LABEL("nsDisplayBoxShadowOuter::Paint", GRAPHICS);
   4426 
   4427  nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame, borderRect,
   4428                                      GetPaintRect(aBuilder, aCtx), 1.0f);
   4429 }
   4430 
   4431 nsRect nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
   4432                                          bool* aSnap) const {
   4433  *aSnap = false;
   4434  return mBounds;
   4435 }
   4436 
   4437 nsRect nsDisplayBoxShadowOuter::GetBoundsInternal() {
   4438  return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame, mFrame->GetSize()) +
   4439         ToReferenceFrame();
   4440 }
   4441 
   4442 bool nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect) const {
   4443  nsPoint origin = ToReferenceFrame();
   4444  nsRect frameRect(origin, mFrame->GetSize());
   4445  if (!frameRect.Contains(aRect)) {
   4446    return false;
   4447  }
   4448 
   4449  // the visible region is entirely inside the border-rect, and box shadows
   4450  // never render within the border-rect (unless there's a border radius).
   4451  nsRectCornerRadii twipsRadii;
   4452  bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
   4453  if (!hasBorderRadii) {
   4454    return true;
   4455  }
   4456 
   4457  return RoundedRectContainsRect(frameRect, twipsRadii, aRect);
   4458 }
   4459 
   4460 bool nsDisplayBoxShadowOuter::CanBuildWebRenderDisplayItems() const {
   4461  auto shadows = mFrame->StyleEffects()->mBoxShadow.AsSpan();
   4462  if (shadows.IsEmpty()) {
   4463    return false;
   4464  }
   4465 
   4466  bool hasBorderRadius;
   4467  // We don't support native themed things yet like box shadows around
   4468  // input buttons.
   4469  //
   4470  // TODO(emilio): The non-native theme could provide the right rect+radius
   4471  // instead relatively painlessly, if we find this causes performance issues or
   4472  // what not.
   4473  return !nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
   4474 }
   4475 
   4476 bool nsDisplayBoxShadowOuter::CreateWebRenderCommands(
   4477    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4478    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4479    nsDisplayListBuilder* aDisplayListBuilder) {
   4480  if (!CanBuildWebRenderDisplayItems()) {
   4481    return false;
   4482  }
   4483 
   4484  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   4485  nsPoint offset = ToReferenceFrame();
   4486  nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
   4487  bool snap;
   4488  nsRect bounds = GetBounds(aDisplayListBuilder, &snap);
   4489 
   4490  bool hasBorderRadius;
   4491  bool nativeTheme =
   4492      nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
   4493 
   4494  // Don't need the full size of the shadow rect like we do in
   4495  // nsCSSRendering since WR takes care of calculations for blur
   4496  // and spread radius.
   4497  nsRect frameRect =
   4498      nsCSSRendering::GetShadowRect(borderRect, nativeTheme, mFrame);
   4499 
   4500  RectCornerRadii borderRadii;
   4501  if (hasBorderRadius) {
   4502    hasBorderRadius = nsCSSRendering::GetBorderRadii(frameRect, borderRect,
   4503                                                     mFrame, borderRadii);
   4504  }
   4505 
   4506  // Everything here is in app units, change to device units.
   4507  LayoutDeviceRect clipRect =
   4508      LayoutDeviceRect::FromAppUnits(bounds, appUnitsPerDevPixel);
   4509  auto shadows = mFrame->StyleEffects()->mBoxShadow.AsSpan();
   4510  MOZ_ASSERT(!shadows.IsEmpty());
   4511 
   4512  for (const auto& shadow : Reversed(shadows)) {
   4513    if (shadow.inset) {
   4514      continue;
   4515    }
   4516 
   4517    float blurRadius =
   4518        float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
   4519    gfx::sRGBColor shadowColor = nsCSSRendering::GetShadowColor(
   4520        shadow.base, mFrame, aBuilder.GetInheritedOpacity());
   4521 
   4522    // We don't move the shadow rect here since WR does it for us
   4523    // Now translate everything to device pixels.
   4524    const nsRect& shadowRect = frameRect;
   4525    LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
   4526        nsPoint(shadow.base.horizontal.ToAppUnits(),
   4527                shadow.base.vertical.ToAppUnits()),
   4528        appUnitsPerDevPixel);
   4529 
   4530    LayoutDeviceRect deviceBox =
   4531        LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
   4532    wr::LayoutRect deviceBoxRect = wr::ToLayoutRect(deviceBox);
   4533    wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect);
   4534 
   4535    LayoutDeviceSize zeroSize;
   4536    wr::BorderRadius borderRadius =
   4537        wr::ToBorderRadius(zeroSize, zeroSize, zeroSize, zeroSize);
   4538    if (hasBorderRadius) {
   4539      borderRadius = wr::ToBorderRadius(
   4540          LayoutDeviceSize::FromUnknownSize(borderRadii.TopLeft()),
   4541          LayoutDeviceSize::FromUnknownSize(borderRadii.TopRight()),
   4542          LayoutDeviceSize::FromUnknownSize(borderRadii.BottomLeft()),
   4543          LayoutDeviceSize::FromUnknownSize(borderRadii.BottomRight()));
   4544    }
   4545 
   4546    float spreadRadius =
   4547        float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
   4548 
   4549    aBuilder.PushBoxShadow(deviceBoxRect, deviceClipRect, !BackfaceIsHidden(),
   4550                           deviceBoxRect, wr::ToLayoutVector2D(shadowOffset),
   4551                           wr::ToColorF(ToDeviceColor(shadowColor)), blurRadius,
   4552                           spreadRadius, borderRadius,
   4553                           wr::BoxShadowClipMode::Outset);
   4554  }
   4555 
   4556  return true;
   4557 }
   4558 
   4559 void nsDisplayBoxShadowOuter::ComputeInvalidationRegion(
   4560    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   4561    nsRegion* aInvalidRegion) const {
   4562  const auto* geometry =
   4563      static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
   4564  bool snap;
   4565  if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
   4566      !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
   4567    nsRegion oldShadow, newShadow;
   4568    nsRectCornerRadii dontCare;
   4569    bool hasBorderRadius = mFrame->GetBorderRadii(dontCare);
   4570    if (hasBorderRadius) {
   4571      // If we have rounded corners then we need to invalidate the frame area
   4572      // too since we paint into it.
   4573      oldShadow = geometry->mBounds;
   4574      newShadow = GetBounds(aBuilder, &snap);
   4575    } else {
   4576      oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
   4577      newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
   4578    }
   4579    aInvalidRegion->Or(oldShadow, newShadow);
   4580  }
   4581 }
   4582 
   4583 void nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
   4584                                    gfxContext* aCtx) {
   4585  nsPoint offset = ToReferenceFrame();
   4586  nsRect borderRect = nsRect(offset, mFrame->GetSize());
   4587  nsPresContext* presContext = mFrame->PresContext();
   4588 
   4589  AUTO_PROFILER_LABEL("nsDisplayBoxShadowInner::Paint", GRAPHICS);
   4590 
   4591  nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame, borderRect);
   4592 }
   4593 
   4594 bool nsDisplayBoxShadowInner::CanCreateWebRenderCommands(
   4595    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   4596    const nsPoint& aReferenceOffset) {
   4597  auto shadows = aFrame->StyleEffects()->mBoxShadow.AsSpan();
   4598  if (shadows.IsEmpty()) {
   4599    // Means we don't have to paint anything
   4600    return true;
   4601  }
   4602 
   4603  bool hasBorderRadius;
   4604  bool nativeTheme =
   4605      nsCSSRendering::HasBoxShadowNativeTheme(aFrame, hasBorderRadius);
   4606 
   4607  // We don't support native themed things yet like box shadows around
   4608  // input buttons.
   4609  return !nativeTheme;
   4610 }
   4611 
   4612 /* static */
   4613 void nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
   4614    wr::DisplayListBuilder& aBuilder, const StackingContextHelper& aSc,
   4615    nsRect& aVisibleRect, nsIFrame* aFrame, const nsRect& aBorderRect) {
   4616  if (!nsCSSRendering::ShouldPaintBoxShadowInner(aFrame)) {
   4617    return;
   4618  }
   4619 
   4620  int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
   4621 
   4622  auto shadows = aFrame->StyleEffects()->mBoxShadow.AsSpan();
   4623 
   4624  LayoutDeviceRect clipRect =
   4625      LayoutDeviceRect::FromAppUnits(aVisibleRect, appUnitsPerDevPixel);
   4626 
   4627  for (const auto& shadow : Reversed(shadows)) {
   4628    if (!shadow.inset) {
   4629      continue;
   4630    }
   4631 
   4632    nsRect shadowRect =
   4633        nsCSSRendering::GetBoxShadowInnerPaddingRect(aFrame, aBorderRect);
   4634    RectCornerRadii innerRadii;
   4635    nsCSSRendering::GetShadowInnerRadii(aFrame, aBorderRect, innerRadii);
   4636 
   4637    // Now translate everything to device pixels.
   4638    LayoutDeviceRect deviceBoxRect =
   4639        LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
   4640    wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect);
   4641    sRGBColor shadowColor =
   4642        nsCSSRendering::GetShadowColor(shadow.base, aFrame, 1.0);
   4643 
   4644    LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
   4645        nsPoint(shadow.base.horizontal.ToAppUnits(),
   4646                shadow.base.vertical.ToAppUnits()),
   4647        appUnitsPerDevPixel);
   4648 
   4649    float blurRadius =
   4650        float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
   4651 
   4652    wr::BorderRadius borderRadius = wr::ToBorderRadius(
   4653        LayoutDeviceSize::FromUnknownSize(innerRadii.TopLeft()),
   4654        LayoutDeviceSize::FromUnknownSize(innerRadii.TopRight()),
   4655        LayoutDeviceSize::FromUnknownSize(innerRadii.BottomLeft()),
   4656        LayoutDeviceSize::FromUnknownSize(innerRadii.BottomRight()));
   4657    // NOTE: Any spread radius > 0 will render nothing. WR Bug.
   4658    float spreadRadius =
   4659        float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
   4660 
   4661    aBuilder.PushBoxShadow(
   4662        wr::ToLayoutRect(deviceBoxRect), deviceClipRect,
   4663        !aFrame->BackfaceIsHidden(), wr::ToLayoutRect(deviceBoxRect),
   4664        wr::ToLayoutVector2D(shadowOffset),
   4665        wr::ToColorF(ToDeviceColor(shadowColor)), blurRadius, spreadRadius,
   4666        borderRadius, wr::BoxShadowClipMode::Inset);
   4667  }
   4668 }
   4669 
   4670 bool nsDisplayBoxShadowInner::CreateWebRenderCommands(
   4671    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4672    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4673    nsDisplayListBuilder* aDisplayListBuilder) {
   4674  if (!CanCreateWebRenderCommands(aDisplayListBuilder, mFrame,
   4675                                  ToReferenceFrame())) {
   4676    return false;
   4677  }
   4678 
   4679  bool snap;
   4680  nsRect visible = GetBounds(aDisplayListBuilder, &snap);
   4681  nsPoint offset = ToReferenceFrame();
   4682  nsRect borderRect = nsRect(offset, mFrame->GetSize());
   4683  nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
   4684      aBuilder, aSc, visible, mFrame, borderRect);
   4685 
   4686  return true;
   4687 }
   4688 
   4689 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
   4690                                     nsIFrame* aFrame, nsDisplayList* aList,
   4691                                     bool aClearClipChain)
   4692    : nsDisplayWrapList(aBuilder, aFrame, aList,
   4693                        aBuilder->CurrentActiveScrolledRoot(),
   4694                        ContainerASRType::Constant, aClearClipChain) {}
   4695 
   4696 nsDisplayWrapList::nsDisplayWrapList(
   4697    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   4698    const ActiveScrolledRoot* aActiveScrolledRoot,
   4699    ContainerASRType aContainerASRType, bool aClearClipChain)
   4700    : nsPaintedDisplayItem(aBuilder, aFrame, aActiveScrolledRoot),
   4701      mList(aBuilder),
   4702      mFrameASR(aContainerASRType == ContainerASRType::AncestorOfContained
   4703                    ? aBuilder->CurrentActiveScrolledRoot()
   4704                    : nullptr),
   4705      mOverrideZIndex(0),
   4706      mContainerASRType(aContainerASRType),
   4707      mHasZIndexOverride(false),
   4708      mClearingClipChain(aClearClipChain) {
   4709  MOZ_COUNT_CTOR(nsDisplayWrapList);
   4710 
   4711  mBaseBuildingRect = GetBuildingRect();
   4712 
   4713  mListPtr = &mList;
   4714  mListPtr->AppendToTop(aList);
   4715  mOriginalClipChain = mClipChain;
   4716  nsDisplayWrapList::UpdateBounds(aBuilder);
   4717 }
   4718 
   4719 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
   4720                                     nsIFrame* aFrame, nsDisplayItem* aItem)
   4721    : nsPaintedDisplayItem(aBuilder, aFrame),
   4722      mList(aBuilder),
   4723      mOverrideZIndex(0),
   4724      mHasZIndexOverride(false) {
   4725  MOZ_COUNT_CTOR(nsDisplayWrapList);
   4726 
   4727  mBaseBuildingRect = GetBuildingRect();
   4728 
   4729  mListPtr = &mList;
   4730  mListPtr->AppendToTop(aItem);
   4731  mOriginalClipChain = mClipChain;
   4732  nsDisplayWrapList::UpdateBounds(aBuilder);
   4733 
   4734  if (!aFrame || !aFrame->IsTransformed()) {
   4735    return;
   4736  }
   4737 
   4738  // See the previous nsDisplayWrapList constructor
   4739  if (aItem->Frame() == aFrame) {
   4740    mToReferenceFrame = aItem->ToReferenceFrame();
   4741  }
   4742 
   4743  nsRect visible = aBuilder->GetVisibleRect() +
   4744                   aBuilder->GetCurrentFrameOffsetToReferenceFrame();
   4745 
   4746  SetBuildingRect(visible);
   4747 }
   4748 
   4749 void nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder,
   4750                                const nsRect& aRect, HitTestState* aState,
   4751                                nsTArray<nsIFrame*>* aOutFrames) {
   4752  mListPtr->HitTest(aBuilder, aRect, aState, aOutFrames);
   4753 }
   4754 
   4755 nsRect nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder,
   4756                                    bool* aSnap) const {
   4757  *aSnap = false;
   4758  return mBounds;
   4759 }
   4760 
   4761 nsRegion nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   4762                                            bool* aSnap) const {
   4763  *aSnap = false;
   4764  bool snap;
   4765  return ::mozilla::GetOpaqueRegion(aBuilder, GetChildren(),
   4766                                    GetBounds(aBuilder, &snap));
   4767 }
   4768 
   4769 Maybe<nscolor> nsDisplayWrapList::IsUniform(
   4770    nsDisplayListBuilder* aBuilder) const {
   4771  // We could try to do something but let's conservatively just return Nothing.
   4772  return Nothing();
   4773 }
   4774 
   4775 void nsDisplayWrapper::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   4776  NS_ERROR("nsDisplayWrapper should have been flattened away for painting");
   4777 }
   4778 
   4779 nsRect nsDisplayWrapList::GetComponentAlphaBounds(
   4780    nsDisplayListBuilder* aBuilder) const {
   4781  return mListPtr->GetComponentAlphaBounds(aBuilder);
   4782 }
   4783 
   4784 bool nsDisplayWrapList::CreateWebRenderCommandsNewClipListOption(
   4785    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   4786    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   4787    nsDisplayListBuilder* aDisplayListBuilder, bool aNewClipList) {
   4788  aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
   4789      GetChildren(), this, aDisplayListBuilder, aSc, aBuilder, aResources,
   4790      aNewClipList);
   4791  return true;
   4792 }
   4793 
   4794 static nsresult WrapDisplayList(nsDisplayListBuilder* aBuilder,
   4795                                nsIFrame* aFrame, nsDisplayList* aList,
   4796                                nsDisplayItemWrapper* aWrapper) {
   4797  if (!aList->GetTop()) {
   4798    return NS_OK;
   4799  }
   4800  nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
   4801  if (!item) {
   4802    return NS_ERROR_OUT_OF_MEMORY;
   4803  }
   4804  // aList was emptied
   4805  aList->AppendToTop(item);
   4806  return NS_OK;
   4807 }
   4808 
   4809 static nsresult WrapEachDisplayItem(nsDisplayListBuilder* aBuilder,
   4810                                    nsDisplayList* aList,
   4811                                    nsDisplayItemWrapper* aWrapper) {
   4812  for (nsDisplayItem* item : aList->TakeItems()) {
   4813    item = aWrapper->WrapItem(aBuilder, item);
   4814    if (!item) {
   4815      return NS_ERROR_OUT_OF_MEMORY;
   4816    }
   4817    aList->AppendToTop(item);
   4818  }
   4819  // aList was emptied
   4820  return NS_OK;
   4821 }
   4822 
   4823 nsresult nsDisplayItemWrapper::WrapLists(nsDisplayListBuilder* aBuilder,
   4824                                         nsIFrame* aFrame,
   4825                                         const nsDisplayListSet& aIn,
   4826                                         const nsDisplayListSet& aOut) {
   4827  nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn);
   4828  NS_ENSURE_SUCCESS(rv, rv);
   4829 
   4830  if (&aOut == &aIn) {
   4831    return NS_OK;
   4832  }
   4833  aOut.BorderBackground()->AppendToTop(aIn.BorderBackground());
   4834  aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds());
   4835  aOut.Floats()->AppendToTop(aIn.Floats());
   4836  aOut.Content()->AppendToTop(aIn.Content());
   4837  aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants());
   4838  aOut.Outlines()->AppendToTop(aIn.Outlines());
   4839  return NS_OK;
   4840 }
   4841 
   4842 nsresult nsDisplayItemWrapper::WrapListsInPlace(
   4843    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   4844    const nsDisplayListSet& aLists) {
   4845  nsresult rv;
   4846  if (WrapBorderBackground()) {
   4847    // Our border-backgrounds are in-flow
   4848    rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this);
   4849    NS_ENSURE_SUCCESS(rv, rv);
   4850  }
   4851  // Our block border-backgrounds are in-flow
   4852  rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this);
   4853  NS_ENSURE_SUCCESS(rv, rv);
   4854  // The floats are not in flow
   4855  rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this);
   4856  NS_ENSURE_SUCCESS(rv, rv);
   4857  // Our child content is in flow
   4858  rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this);
   4859  NS_ENSURE_SUCCESS(rv, rv);
   4860  // The positioned descendants may not be in-flow
   4861  rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
   4862  NS_ENSURE_SUCCESS(rv, rv);
   4863  // The outlines may not be in-flow
   4864  return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
   4865 }
   4866 
   4867 nsDisplayOpacity::nsDisplayOpacity(
   4868    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   4869    const ActiveScrolledRoot* aActiveScrolledRoot,
   4870    ContainerASRType aContainerASRType, bool aForEventsOnly,
   4871    bool aNeedsActiveLayer, bool aWrapsBackdropFilter, bool aForceIsolation)
   4872    : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
   4873                        aContainerASRType, true),
   4874      mOpacity(aFrame->StyleEffects()->mOpacity),
   4875      mForEventsOnly(aForEventsOnly),
   4876      mNeedsActiveLayer(aNeedsActiveLayer),
   4877      mChildOpacityState(ChildOpacityState::Unknown),
   4878      mWrapsBackdropFilter(aWrapsBackdropFilter),
   4879      mForceIsolation(aForceIsolation) {
   4880  MOZ_COUNT_CTOR(nsDisplayOpacity);
   4881 }
   4882 
   4883 void nsDisplayOpacity::HitTest(nsDisplayListBuilder* aBuilder,
   4884                               const nsRect& aRect,
   4885                               nsDisplayItem::HitTestState* aState,
   4886                               nsTArray<nsIFrame*>* aOutFrames) {
   4887  AutoRestore<float> opacity(aState->mCurrentOpacity);
   4888  aState->mCurrentOpacity *= mOpacity;
   4889 
   4890  // TODO(emilio): special-casing zero is a bit arbitrary... Maybe we should
   4891  // only consider fully opaque items? Or make this configurable somehow?
   4892  if (aBuilder->HitTestIsForVisibility() && mOpacity == 0.0f) {
   4893    return;
   4894  }
   4895  nsDisplayWrapList::HitTest(aBuilder, aRect, aState, aOutFrames);
   4896 }
   4897 
   4898 nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   4899                                           bool* aSnap) const {
   4900  *aSnap = false;
   4901  // The only time where mOpacity == 1.0 should be when we have will-change.
   4902  // We could report this as opaque then but when the will-change value starts
   4903  // animating the element would become non opaque and could cause repaints.
   4904  return nsRegion();
   4905 }
   4906 
   4907 void nsDisplayOpacity::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   4908  if (GetOpacity() == 0.0f) {
   4909    return;
   4910  }
   4911 
   4912  int32_t apd = mFrame->PresContext()->AppUnitsPerDevPixel();
   4913 
   4914  if (GetOpacity() == 1.0f) {
   4915    GetChildren()->Paint(aBuilder, aCtx, apd);
   4916    return;
   4917  }
   4918 
   4919  bool unusedSnap = false;
   4920  auto deviceSpaceBounds = IntRect::FromUnknownRect(
   4921      RoundedOut(ToRect(aCtx->UserToDevice(nsLayoutUtils::RectToGfxRect(
   4922          GetBounds(aBuilder, &unusedSnap), apd)))));
   4923 
   4924  aCtx->GetDrawTarget()->PushLayer(false, GetOpacity(), nullptr, gfx::Matrix(),
   4925                                   deviceSpaceBounds);
   4926  GetChildren()->Paint(aBuilder, aCtx, apd);
   4927  aCtx->GetDrawTarget()->PopLayer();
   4928 }
   4929 
   4930 /* static */
   4931 bool nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder* aBuilder,
   4932                                        nsIFrame* aFrame) {
   4933  return EffectCompositor::HasAnimationsForCompositor(
   4934             aFrame, DisplayItemType::TYPE_OPACITY) ||
   4935         ActiveLayerTracker::IsStyleAnimated(
   4936             aBuilder, aFrame, nsCSSPropertyIDSet::OpacityProperties());
   4937 }
   4938 
   4939 bool nsDisplayOpacity::CanApplyOpacity(WebRenderLayerManager* aManager,
   4940                                       nsDisplayListBuilder* aBuilder) const {
   4941  return !EffectCompositor::HasAnimationsForCompositor(
   4942      mFrame, DisplayItemType::TYPE_OPACITY);
   4943 }
   4944 
   4945 // Only try folding our opacity down if we have at most |kOpacityMaxChildCount|
   4946 // children that don't overlap and can all apply the opacity to themselves.
   4947 static const size_t kOpacityMaxChildCount = 3;
   4948 
   4949 // |kOpacityMaxListSize| defines an early exit condition for opacity items that
   4950 // are likely have more child items than |kOpacityMaxChildCount|.
   4951 static const size_t kOpacityMaxListSize = kOpacityMaxChildCount * 2;
   4952 
   4953 /**
   4954 * Recursively iterates through |aList| and collects at most
   4955 * |kOpacityMaxChildCount| display item pointers to items that return true for
   4956 * CanApplyOpacity(). The item pointers are added to |aArray|.
   4957 *
   4958 * LayerEventRegions and WrapList items are ignored.
   4959 *
   4960 * We need to do this recursively, because the child display items might contain
   4961 * nested nsDisplayWrapLists.
   4962 *
   4963 * Returns false if there are more than |kOpacityMaxChildCount| items, or if an
   4964 * item that returns false for CanApplyOpacity() is encountered.
   4965 * Otherwise returns true.
   4966 */
   4967 static bool CollectItemsWithOpacity(WebRenderLayerManager* aManager,
   4968                                    nsDisplayListBuilder* aBuilder,
   4969                                    nsDisplayList* aList,
   4970                                    nsTArray<nsPaintedDisplayItem*>& aArray) {
   4971  if (aList->Length() > kOpacityMaxListSize) {
   4972    // Exit early, since |aList| will likely contain more than
   4973    // |kOpacityMaxChildCount| items.
   4974    return false;
   4975  }
   4976 
   4977  for (nsDisplayItem* i : *aList) {
   4978    const DisplayItemType type = i->GetType();
   4979 
   4980    if (type == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
   4981      continue;
   4982    }
   4983 
   4984    // Descend only into wraplists.
   4985    if (type == DisplayItemType::TYPE_WRAP_LIST ||
   4986        type == DisplayItemType::TYPE_CONTAINER) {
   4987      // The current display item has children, process them first.
   4988      if (!CollectItemsWithOpacity(aManager, aBuilder, i->GetChildren(),
   4989                                   aArray)) {
   4990        return false;
   4991      }
   4992 
   4993      continue;
   4994    }
   4995 
   4996    if (aArray.Length() == kOpacityMaxChildCount) {
   4997      return false;
   4998    }
   4999 
   5000    auto* item = i->AsPaintedDisplayItem();
   5001    if (!item || !item->CanApplyOpacity(aManager, aBuilder)) {
   5002      return false;
   5003    }
   5004 
   5005    aArray.AppendElement(item);
   5006  }
   5007 
   5008  return true;
   5009 }
   5010 
   5011 bool nsDisplayOpacity::CanApplyToChildren(WebRenderLayerManager* aManager,
   5012                                          nsDisplayListBuilder* aBuilder) {
   5013  if (mChildOpacityState == ChildOpacityState::Deferred) {
   5014    return false;
   5015  }
   5016 
   5017  // Iterate through the child display list and copy at most
   5018  // |kOpacityMaxChildCount| child display item pointers to a temporary list.
   5019  AutoTArray<nsPaintedDisplayItem*, kOpacityMaxChildCount> items;
   5020  if (!CollectItemsWithOpacity(aManager, aBuilder, &mList, items)) {
   5021    mChildOpacityState = ChildOpacityState::Deferred;
   5022    return false;
   5023  }
   5024 
   5025  struct {
   5026    nsPaintedDisplayItem* item{};
   5027    nsRect bounds;
   5028  } children[kOpacityMaxChildCount];
   5029 
   5030  bool snap;
   5031  size_t childCount = 0;
   5032  for (nsPaintedDisplayItem* item : items) {
   5033    children[childCount].item = item;
   5034    children[childCount].bounds = item->GetBounds(aBuilder, &snap);
   5035    childCount++;
   5036  }
   5037 
   5038  for (size_t i = 0; i < childCount; i++) {
   5039    for (size_t j = i + 1; j < childCount; j++) {
   5040      if (children[i].bounds.Intersects(children[j].bounds)) {
   5041        mChildOpacityState = ChildOpacityState::Deferred;
   5042        return false;
   5043      }
   5044    }
   5045  }
   5046 
   5047  mChildOpacityState = ChildOpacityState::Applied;
   5048  return true;
   5049 }
   5050 
   5051 /**
   5052 * Returns true if this nsDisplayOpacity contains only a filter or a mask item
   5053 * that has the same frame as the opacity item, and that supports painting with
   5054 * opacity. In this case the opacity item can be optimized away.
   5055 */
   5056 bool nsDisplayOpacity::ApplyToMask() {
   5057  if (mList.Length() != 1) {
   5058    return false;
   5059  }
   5060 
   5061  nsDisplayItem* item = mList.GetBottom();
   5062  if (item->Frame() != mFrame) {
   5063    // The effect item needs to have the same frame as the opacity item.
   5064    return false;
   5065  }
   5066 
   5067  const DisplayItemType type = item->GetType();
   5068  if (type == DisplayItemType::TYPE_MASK) {
   5069    return true;
   5070  }
   5071 
   5072  return false;
   5073 }
   5074 
   5075 bool nsDisplayOpacity::CanApplyOpacityToChildren(
   5076    WebRenderLayerManager* aManager, nsDisplayListBuilder* aBuilder,
   5077    float aInheritedOpacity) {
   5078  if (mFrame->GetPrevContinuation() || mFrame->GetNextContinuation() ||
   5079      mFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) {
   5080    // If we've been split, then we might need to merge, so
   5081    // don't flatten us away.
   5082    return false;
   5083  }
   5084 
   5085  if (mNeedsActiveLayer || mOpacity == 0.0) {
   5086    // If our opacity is zero then we'll discard all descendant display items
   5087    // except for layer event regions, so there's no point in doing this
   5088    // optimization (and if we do do it, then invalidations of those descendants
   5089    // might trigger repainting).
   5090    return false;
   5091  }
   5092 
   5093  if (mList.IsEmpty()) {
   5094    return false;
   5095  }
   5096 
   5097  // We can only flatten opacity items into a mask if we haven't
   5098  // already flattened an earlier ancestor, since the SVG code pulls the opacity
   5099  // from style directly, and won't know about the outer opacity value.
   5100  if (aInheritedOpacity == 1.0f && ApplyToMask()) {
   5101    MOZ_ASSERT(SVGIntegrationUtils::UsingEffectsForFrame(mFrame));
   5102    mChildOpacityState = ChildOpacityState::Applied;
   5103    return true;
   5104  }
   5105 
   5106  // Return true if we successfully applied opacity to child items.
   5107  return CanApplyToChildren(aManager, aBuilder);
   5108 }
   5109 
   5110 void nsDisplayOpacity::ComputeInvalidationRegion(
   5111    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   5112    nsRegion* aInvalidRegion) const {
   5113  const auto* geometry =
   5114      static_cast<const nsDisplayOpacityGeometry*>(aGeometry);
   5115 
   5116  bool snap;
   5117  if (mOpacity != geometry->mOpacity) {
   5118    aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
   5119  }
   5120 }
   5121 
   5122 void nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream) {
   5123  aStream << " (opacity " << mOpacity << ", mChildOpacityState: ";
   5124  switch (mChildOpacityState) {
   5125    case ChildOpacityState::Unknown:
   5126      aStream << "Unknown";
   5127      break;
   5128    case ChildOpacityState::Applied:
   5129      aStream << "Applied";
   5130      break;
   5131    case ChildOpacityState::Deferred:
   5132      aStream << "Deferred";
   5133      break;
   5134    default:
   5135      break;
   5136  }
   5137 
   5138  aStream << ")";
   5139 }
   5140 
   5141 bool nsDisplayOpacity::CreateWebRenderCommands(
   5142    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5143    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5144    nsDisplayListBuilder* aDisplayListBuilder) {
   5145  MOZ_ASSERT(mChildOpacityState != ChildOpacityState::Applied);
   5146  float oldOpacity = aBuilder.GetInheritedOpacity();
   5147  const DisplayItemClipChain* oldClipChain = aBuilder.GetInheritedClipChain();
   5148  aBuilder.SetInheritedOpacity(1.0f);
   5149  aBuilder.SetInheritedClipChain(nullptr);
   5150  float opacity = mOpacity * oldOpacity;
   5151  float* opacityForSC = &opacity;
   5152 
   5153  uint64_t animationsId =
   5154      AddAnimationsForWebRender(this, aManager, aDisplayListBuilder);
   5155  wr::WrAnimationProperty prop{
   5156      wr::WrAnimationType::Opacity,
   5157      animationsId,
   5158  };
   5159 
   5160  wr::StackingContextParams params;
   5161  params.animation = animationsId ? &prop : nullptr;
   5162  params.opacity = opacityForSC;
   5163  params.clip =
   5164      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   5165  if (mWrapsBackdropFilter) {
   5166    params.flags |= wr::StackingContextFlags::WRAPS_BACKDROP_FILTER;
   5167  }
   5168  if (mForceIsolation) {
   5169    params.flags |= wr::StackingContextFlags::FORCED_ISOLATION;
   5170  }
   5171  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   5172                           params);
   5173 
   5174  aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
   5175      &mList, this, aDisplayListBuilder, sc, aBuilder, aResources);
   5176  aBuilder.SetInheritedOpacity(oldOpacity);
   5177  aBuilder.SetInheritedClipChain(oldClipChain);
   5178  return true;
   5179 }
   5180 
   5181 nsDisplayBlendMode::nsDisplayBlendMode(
   5182    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5183    StyleBlend aBlendMode, const ActiveScrolledRoot* aActiveScrolledRoot,
   5184    ContainerASRType aContainerASRType, const bool aIsForBackground)
   5185    : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
   5186                        aContainerASRType, true),
   5187      mBlendMode(aBlendMode),
   5188      mIsForBackground(aIsForBackground) {
   5189  MOZ_COUNT_CTOR(nsDisplayBlendMode);
   5190 }
   5191 
   5192 nsRegion nsDisplayBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   5193                                             bool* aSnap) const {
   5194  *aSnap = false;
   5195  // We are never considered opaque
   5196  return nsRegion();
   5197 }
   5198 
   5199 bool nsDisplayBlendMode::CreateWebRenderCommands(
   5200    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5201    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5202    nsDisplayListBuilder* aDisplayListBuilder) {
   5203  wr::StackingContextParams params;
   5204  params.mix_blend_mode =
   5205      wr::ToMixBlendMode(nsCSSRendering::GetGFXBlendMode(mBlendMode));
   5206  params.clip =
   5207      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   5208  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   5209                           params);
   5210 
   5211  return nsDisplayWrapList::CreateWebRenderCommands(
   5212      aBuilder, aResources, sc, aManager, aDisplayListBuilder);
   5213 }
   5214 
   5215 void nsDisplayBlendMode::Paint(nsDisplayListBuilder* aBuilder,
   5216                               gfxContext* aCtx) {
   5217  // This should be switched to use PushLayerWithBlend, once it's
   5218  // been implemented for all DrawTarget backends.
   5219  DrawTarget* dt = aCtx->GetDrawTarget();
   5220  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   5221  Rect rect = NSRectToRect(GetPaintRect(aBuilder, aCtx), appUnitsPerDevPixel);
   5222  rect.RoundOut();
   5223 
   5224  // Create a temporary DrawTarget that is clipped to the area that
   5225  // we're going to draw to. This will include the same transform as
   5226  // is currently on |dt|.
   5227  RefPtr<DrawTarget> temp =
   5228      dt->CreateClippedDrawTarget(rect, SurfaceFormat::B8G8R8A8);
   5229  if (!temp) {
   5230    return;
   5231  }
   5232 
   5233  gfxContext ctx(temp, /* aPreserveTransform */ true);
   5234 
   5235  GetChildren()->Paint(aBuilder, &ctx,
   5236                       mFrame->PresContext()->AppUnitsPerDevPixel());
   5237 
   5238  // Draw the temporary DT to the real destination, applying the blend mode, but
   5239  // no transform.
   5240  temp->Flush();
   5241  RefPtr<SourceSurface> surface = temp->Snapshot();
   5242  gfxContextMatrixAutoSaveRestore saveMatrix(aCtx);
   5243  dt->SetTransform(Matrix());
   5244  dt->DrawSurface(
   5245      surface, Rect(surface->GetRect()), Rect(surface->GetRect()),
   5246      DrawSurfaceOptions(),
   5247      DrawOptions(1.0f, nsCSSRendering::GetGFXBlendMode(mBlendMode)));
   5248 }
   5249 
   5250 gfx::CompositionOp nsDisplayBlendMode::BlendMode() {
   5251  return nsCSSRendering::GetGFXBlendMode(mBlendMode);
   5252 }
   5253 
   5254 bool nsDisplayBlendMode::CanMerge(const nsDisplayItem* aItem) const {
   5255  // Items for the same content element should be merged into a single
   5256  // compositing group.
   5257  if (!HasDifferentFrame(aItem) || !HasSameTypeAndClip(aItem) ||
   5258      !HasSameContent(aItem)) {
   5259    return false;
   5260  }
   5261 
   5262  const auto* item = static_cast<const nsDisplayBlendMode*>(aItem);
   5263  if (mIsForBackground || item->mIsForBackground) {
   5264    // Don't merge background-blend-mode items
   5265    return false;
   5266  }
   5267 
   5268  return true;
   5269 }
   5270 
   5271 /* static */
   5272 nsDisplayBlendContainer* nsDisplayBlendContainer::CreateForMixBlendMode(
   5273    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5274    const ActiveScrolledRoot* aActiveScrolledRoot,
   5275    ContainerASRType aContainerASRType) {
   5276  return MakeDisplayItemWithIndex<nsDisplayBlendContainer>(
   5277      aBuilder, aFrame, uint16_t(BlendContainerType::MixBlendMode), aList,
   5278      aActiveScrolledRoot, aContainerASRType, BlendContainerType::MixBlendMode);
   5279 }
   5280 
   5281 /* static */
   5282 nsDisplayBlendContainer* nsDisplayBlendContainer::CreateForBackgroundBlendMode(
   5283    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aSecondaryFrame,
   5284    nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot,
   5285    ContainerASRType aContainerASRType) {
   5286  if (aSecondaryFrame) {
   5287    auto type = GetTableTypeFromFrame(aFrame);
   5288    auto index = static_cast<uint16_t>(type);
   5289 
   5290    return MakeDisplayItemWithIndex<nsDisplayTableBlendContainer>(
   5291        aBuilder, aSecondaryFrame, index, aList, aActiveScrolledRoot,
   5292        aContainerASRType, BlendContainerType::BackgroundBlendMode, aFrame);
   5293  }
   5294 
   5295  return MakeDisplayItemWithIndex<nsDisplayBlendContainer>(
   5296      aBuilder, aFrame, uint16_t(BlendContainerType::BackgroundBlendMode),
   5297      aList, aActiveScrolledRoot, aContainerASRType,
   5298      BlendContainerType::BackgroundBlendMode);
   5299 }
   5300 
   5301 /* static */
   5302 nsDisplayBlendContainer* nsDisplayBlendContainer::CreateForIsolation(
   5303    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5304    const ActiveScrolledRoot* aActiveScrolledRoot,
   5305    ContainerASRType aContainerASRType, bool aNeedsIsolation) {
   5306  auto type = aNeedsIsolation ? BlendContainerType::NeedsIsolationNeedsContainer
   5307                              : BlendContainerType::NeedsIsolationNothing;
   5308  return MakeDisplayItemWithIndex<nsDisplayBlendContainer>(
   5309      aBuilder, aFrame, uint16_t(BlendContainerType::NeedsIsolationNothing),
   5310      aList, aActiveScrolledRoot, aContainerASRType, type);
   5311 }
   5312 
   5313 nsDisplayBlendContainer::nsDisplayBlendContainer(
   5314    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5315    const ActiveScrolledRoot* aActiveScrolledRoot,
   5316    ContainerASRType aContainerASRType, BlendContainerType aBlendContainerType)
   5317    : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
   5318                        aContainerASRType, true),
   5319      mBlendContainerType(aBlendContainerType) {
   5320  MOZ_COUNT_CTOR(nsDisplayBlendContainer);
   5321 }
   5322 
   5323 void nsDisplayBlendContainer::Paint(nsDisplayListBuilder* aBuilder,
   5324                                    gfxContext* aCtx) {
   5325  aCtx->GetDrawTarget()->PushLayer(false, 1.0, nullptr, gfx::Matrix());
   5326  GetChildren()->Paint(aBuilder, aCtx,
   5327                       mFrame->PresContext()->AppUnitsPerDevPixel());
   5328  aCtx->GetDrawTarget()->PopLayer();
   5329 }
   5330 
   5331 bool nsDisplayBlendContainer::CreateWebRenderCommands(
   5332    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5333    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5334    nsDisplayListBuilder* aDisplayListBuilder) {
   5335  Maybe<StackingContextHelper> layer;
   5336  const StackingContextHelper* sc = &aSc;
   5337  if (CreatesStackingContextHelper()) {
   5338    wr::StackingContextParams params;
   5339    params.flags |= wr::StackingContextFlags::IS_BLEND_CONTAINER;
   5340    params.clip =
   5341        wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   5342    layer.emplace(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, params);
   5343    sc = layer.ptr();
   5344  }
   5345 
   5346  return nsDisplayWrapList::CreateWebRenderCommandsNewClipListOption(
   5347      aBuilder, aResources, *sc, aManager, aDisplayListBuilder, layer.isSome());
   5348 }
   5349 
   5350 void nsDisplayTableBlendContainer::Destroy(nsDisplayListBuilder* aBuilder) {
   5351  RemoveDisplayItemFromFrame(aBuilder, mAncestorFrame);
   5352  nsDisplayBlendContainer::Destroy(aBuilder);
   5353 }
   5354 
   5355 void nsDisplayTableBlendMode::Destroy(nsDisplayListBuilder* aBuilder) {
   5356  RemoveDisplayItemFromFrame(aBuilder, mAncestorFrame);
   5357  nsDisplayBlendMode::Destroy(aBuilder);
   5358 }
   5359 
   5360 nsDisplayOwnLayer::nsDisplayOwnLayer(
   5361    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5362    const ActiveScrolledRoot* aActiveScrolledRoot,
   5363    ContainerASRType aContainerASRType, nsDisplayOwnLayerFlags aFlags,
   5364    const ScrollbarData& aScrollbarData, bool aForceActive,
   5365    bool aClearClipChain)
   5366    : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
   5367                        aContainerASRType, aClearClipChain),
   5368      mFlags(aFlags),
   5369      mScrollbarData(aScrollbarData),
   5370      mForceActive(aForceActive),
   5371      mWrAnimationId(0) {
   5372  MOZ_COUNT_CTOR(nsDisplayOwnLayer);
   5373 }
   5374 
   5375 bool nsDisplayOwnLayer::IsScrollThumbLayer() const {
   5376  return mScrollbarData.mScrollbarLayerType == ScrollbarLayerType::Thumb;
   5377 }
   5378 
   5379 bool nsDisplayOwnLayer::IsScrollbarContainer() const {
   5380  return mScrollbarData.mScrollbarLayerType == ScrollbarLayerType::Container;
   5381 }
   5382 
   5383 bool nsDisplayOwnLayer::IsRootScrollbarContainer() const {
   5384  return IsScrollbarContainer() && IsScrollbarLayerForRoot();
   5385 }
   5386 
   5387 bool nsDisplayOwnLayer::IsScrollbarLayerForRoot() const {
   5388  return mFrame->PresContext()->IsRootContentDocumentCrossProcess() &&
   5389         mScrollbarData.mTargetViewId ==
   5390             nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext());
   5391 }
   5392 
   5393 bool nsDisplayOwnLayer::IsZoomingLayer() const {
   5394  return GetType() == DisplayItemType::TYPE_ASYNC_ZOOM;
   5395 }
   5396 
   5397 bool nsDisplayOwnLayer::IsFixedPositionLayer() const {
   5398  return GetType() == DisplayItemType::TYPE_FIXED_POSITION ||
   5399         GetType() == DisplayItemType::TYPE_TABLE_FIXED_POSITION;
   5400 }
   5401 
   5402 bool nsDisplayOwnLayer::IsStickyPositionLayer() const {
   5403  return GetType() == DisplayItemType::TYPE_STICKY_POSITION;
   5404 }
   5405 
   5406 /* static */
   5407 bool nsDisplayOwnLayer::HasDynamicToolbar(nsIFrame* aFrame) {
   5408  if (!aFrame->PresContext()->IsRootContentDocumentCrossProcess()) {
   5409    return false;
   5410  }
   5411  return aFrame->PresContext()->HasDynamicToolbar() ||
   5412         // For tests on Android, this pref is set to simulate the dynamic
   5413         // toolbar
   5414         StaticPrefs::apz_fixed_margin_override_enabled();
   5415 }
   5416 
   5417 bool nsDisplayOwnLayer::HasDynamicToolbar() const {
   5418  return HasDynamicToolbar(mFrame);
   5419 }
   5420 
   5421 bool nsDisplayOwnLayer::CreateWebRenderCommands(
   5422    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5423    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5424    nsDisplayListBuilder* aDisplayListBuilder, bool aForceIsolation) {
   5425  Maybe<wr::WrAnimationProperty> prop;
   5426  const bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
   5427                         (IsScrollThumbLayer() || IsZoomingLayer() ||
   5428                          ShouldGetFixedAnimationId() ||
   5429                          (IsRootScrollbarContainer() && HasDynamicToolbar()));
   5430 
   5431  if (needsProp) {
   5432    // APZ is enabled and this is a scroll thumb or zooming layer, so we need
   5433    // to create and set an animation id. That way APZ can adjust the position/
   5434    // zoom of this content asynchronously as needed.
   5435    RefPtr<WebRenderAPZAnimationData> animationData =
   5436        aManager->CommandBuilder()
   5437            .CreateOrRecycleWebRenderUserData<WebRenderAPZAnimationData>(this);
   5438    mWrAnimationId = animationData->GetAnimationId();
   5439 
   5440    prop.emplace();
   5441    prop->id = mWrAnimationId;
   5442    prop->key = wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
   5443                               wr::SpatialKeyKind::APZ);
   5444    prop->effect_type = wr::WrAnimationType::Transform;
   5445  }
   5446 
   5447  wr::StackingContextParams params;
   5448  params.animation = prop.ptrOr(nullptr);
   5449  params.clip =
   5450      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   5451  const bool rootScrollbarContainer = IsRootScrollbarContainer();
   5452  if (rootScrollbarContainer) {
   5453    params.prim_flags |= wr::PrimitiveFlags::IS_SCROLLBAR_CONTAINER;
   5454  }
   5455  if (aForceIsolation) {
   5456    params.flags |= wr::StackingContextFlags::FORCED_ISOLATION;
   5457  }
   5458  if (IsZoomingLayer() || ShouldGetFixedAnimationId() ||
   5459      (rootScrollbarContainer && HasDynamicToolbar())) {
   5460    params.is_2d_scale_translation = true;
   5461    params.should_snap = true;
   5462  }
   5463 
   5464  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   5465                           params);
   5466 
   5467  nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
   5468                                             aDisplayListBuilder);
   5469  return true;
   5470 }
   5471 
   5472 bool nsDisplayOwnLayer::UpdateScrollData(WebRenderScrollData* aData,
   5473                                         WebRenderLayerScrollData* aLayerData) {
   5474  bool isRelevantToApz = (IsScrollThumbLayer() || IsScrollbarContainer() ||
   5475                          IsZoomingLayer() || ShouldGetFixedAnimationId());
   5476 
   5477  if (!isRelevantToApz) {
   5478    return false;
   5479  }
   5480 
   5481  if (!aLayerData) {
   5482    return true;
   5483  }
   5484 
   5485  if (IsZoomingLayer()) {
   5486    aLayerData->SetZoomAnimationId(mWrAnimationId);
   5487    return true;
   5488  }
   5489 
   5490  if (IsFixedPositionLayer() && ShouldGetFixedAnimationId()) {
   5491    aLayerData->SetFixedPositionAnimationId(mWrAnimationId);
   5492    return true;
   5493  }
   5494 
   5495  MOZ_ASSERT(IsScrollbarContainer() || IsScrollThumbLayer());
   5496 
   5497  aLayerData->SetScrollbarData(mScrollbarData);
   5498 
   5499  if (IsRootScrollbarContainer() && HasDynamicToolbar()) {
   5500    aLayerData->SetScrollbarAnimationId(mWrAnimationId);
   5501    return true;
   5502  }
   5503 
   5504  if (IsScrollThumbLayer()) {
   5505    aLayerData->SetScrollbarAnimationId(mWrAnimationId);
   5506    LayoutDeviceRect bounds = LayoutDeviceIntRect::FromAppUnits(
   5507        mBounds, mFrame->PresContext()->AppUnitsPerDevPixel());
   5508    // Subframe scrollbars are subject to the pinch-zoom scale,
   5509    // but root scrollbars are not because they are outside of the
   5510    // region that is zoomed.
   5511    const float resolution =
   5512        IsScrollbarLayerForRoot()
   5513            ? 1.0f
   5514            : mFrame->PresShell()->GetCumulativeResolution();
   5515    LayerIntRect layerBounds =
   5516        RoundedOut(bounds * LayoutDeviceToLayerScale(resolution));
   5517    aLayerData->SetVisibleRect(layerBounds);
   5518  }
   5519  return true;
   5520 }
   5521 
   5522 void nsDisplayOwnLayer::WriteDebugInfo(std::stringstream& aStream) {
   5523  aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")",
   5524                             (int)mFlags, mScrollbarData.mTargetViewId)
   5525                 .get();
   5526 }
   5527 
   5528 bool nsDisplayViewTransitionCapture::CreateWebRenderCommands(
   5529    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5530    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5531    nsDisplayListBuilder* aDisplayListBuilder) {
   5532  Maybe<wr::SnapshotInfo> si;
   5533  nsPresContext* pc = mFrame->PresContext();
   5534  nsIFrame* capturedFrame =
   5535      mIsRoot ? pc->FrameConstructor()->GetRootElementStyleFrame() : mFrame;
   5536  auto captureRect =
   5537      ViewTransition::CapturedInkOverflowRectForFrame(mFrame, mIsRoot);
   5538  auto* vt = pc->Document()->GetActiveViewTransition();
   5539  auto key = [&]() -> Maybe<wr::SnapshotImageKey> {
   5540    if (NS_WARN_IF(!vt)) {
   5541      return Nothing();
   5542    }
   5543    const auto* key =
   5544        vt->GetImageKeyForCapturedFrame(capturedFrame, aManager, aResources);
   5545    return key ? Some(wr::SnapshotImageKey{*key}) : Nothing();
   5546  }();
   5547  VT_LOG_DEBUG(
   5548      "nsDisplayViewTransitionCapture::CreateWebrenderCommands(%s, key=%s)",
   5549      capturedFrame->ListTag().get(), ToString(key).c_str());
   5550  wr::StackingContextParams params;
   5551  params.clip =
   5552      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   5553 
   5554  // This is for the case if this frame is transformed. In this case, the wr
   5555  // display list looks like:
   5556  //
   5557  // PushStackingContext(...)  // For the root
   5558  //   ...
   5559  //   nsDisplayTransform      // For the captured element if it is transformed
   5560  //     PushReferenceFrame    // If the transform matrix is not identity
   5561  //     PushStackingContext(...)
   5562  //     VTCapture             // For the captured element
   5563  //       PushReferenceFrame
   5564  //       PushStackingContext
   5565  //       ...
   5566  //       Other display items // For the descendants of the captured element
   5567  //       ...
   5568  //       PopStackingContext
   5569  //       PopReferenceFrame
   5570  //     PopStackingContext
   5571  //     PopReferenceFrame
   5572  //   ...
   5573  // PopStackingContext
   5574  //
   5575  // The wrapper, nsDisplayTransform, creates a new coordinate system whose
   5576  // origin is from ToReferenceFrame(mFrame). The VTCapture item is inside this
   5577  // nsDisplayTransform, so it's in this coordinate system. This works well if
   5578  // the transform matrix is not identity. However, if the transform matrix is
   5579  // identity, we don't create a new coordinate system (because we don't push a
   5580  // reference frame in WR), at this moment, the |ref_frame_offset| of the
   5581  // stacking context of this VTCapture becomes the |origin| of the
   5582  // nsDisplayTransform (see wr_dp_push_stacking_context() and
   5583  // push_stacking_context() for more details), so this offset may makes the
   5584  // position of this VTCapture wrong. (Note that the ToReferenceFrame(mFrame)
   5585  // of this VTCapture is the frame itself, but ToReferenceFrame(mFrame) of the
   5586  // nsDisplayTransform is its containing frame, e.g. viewport frame.)
   5587  //
   5588  // Therefore, we push a reference frame for this display item if the frame is
   5589  // transformed. This makes this VTCapture creates a new coordinate system, so
   5590  // its |ref_frame_offset| will be (0, 0), just fit the nsDisplayTransform's
   5591  // position.
   5592  //
   5593  // FIXME: We can avoid pushing a reference frame if the transform matrix is
   5594  // not identity, because we generate a new coordinate system already from the
   5595  // nsDisplayTransform (see nsDisplayTransform::CreateWebRenderCommands() for
   5596  // more details).
   5597  wr::WrTransformInfo info;
   5598  if (mFrame->IsTransformed()) {
   5599    // Use an identity matrix to force to push a reference frame to create a new
   5600    // coordinate system for view transition captured frame.
   5601    params.mTransformPtr = [&]() {
   5602      info.transform = wr::ToLayoutTransform(gfx::Matrix4x4());
   5603      info.key = wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
   5604                                wr::SpatialKeyKind::ViewTransition);
   5605      return &info;
   5606    }();
   5607    params.reference_frame_kind = wr::WrReferenceFrameKind::Transform;
   5608  }
   5609 
   5610  if (key) {
   5611    vt->UpdateActiveRectForCapturedFrame(capturedFrame, aSc.GetInheritedScale(),
   5612                                         captureRect);
   5613 
   5614    si.emplace(wr::SnapshotInfo{
   5615        .key = *key,
   5616        .area = wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(
   5617            captureRect + ToReferenceFrame(), pc->AppUnitsPerDevPixel())),
   5618        .detached = true,
   5619    });
   5620    params.snapshot = si.ptr();
   5621  }
   5622  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   5623                           params);
   5624  nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
   5625                                             aDisplayListBuilder);
   5626  return true;
   5627 }
   5628 
   5629 nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
   5630                                           nsIFrame* aFrame,
   5631                                           nsSubDocumentFrame* aSubDocFrame,
   5632                                           nsDisplayList* aList,
   5633                                           nsDisplayOwnLayerFlags aFlags)
   5634    : nsDisplayOwnLayer(aBuilder, aFrame, aList,
   5635                        aBuilder->CurrentActiveScrolledRoot(),
   5636                        ContainerASRType::Constant, aFlags),
   5637      mShouldFlatten(false),
   5638      mSubDocFrame(aSubDocFrame) {
   5639  MOZ_COUNT_CTOR(nsDisplaySubDocument);
   5640 
   5641  if (aBuilder->IsRetainingDisplayList() && mSubDocFrame &&
   5642      mSubDocFrame != mFrame) {
   5643    mSubDocFrame->AddDisplayItem(this);
   5644  }
   5645 }
   5646 
   5647 void nsDisplaySubDocument::Destroy(nsDisplayListBuilder* aBuilder) {
   5648  RemoveDisplayItemFromFrame(aBuilder, mSubDocFrame);
   5649  nsDisplayOwnLayer::Destroy(aBuilder);
   5650 }
   5651 
   5652 nsIFrame* nsDisplaySubDocument::FrameForInvalidation() const {
   5653  return mSubDocFrame ? mSubDocFrame : mFrame;
   5654 }
   5655 
   5656 void nsDisplaySubDocument::RemoveFrame(nsIFrame* aFrame) {
   5657  if (aFrame == mSubDocFrame) {
   5658    mSubDocFrame = nullptr;
   5659    SetDeletedFrame();
   5660  }
   5661  nsDisplayOwnLayer::RemoveFrame(aFrame);
   5662 }
   5663 
   5664 static bool UseDisplayPortForViewport(nsDisplayListBuilder* aBuilder,
   5665                                      nsIFrame* aFrame) {
   5666  return aBuilder->IsPaintingToWindow() &&
   5667         DisplayPortUtils::ViewportHasDisplayPort(aFrame->PresContext());
   5668 }
   5669 
   5670 nsRect nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder,
   5671                                       bool* aSnap) const {
   5672  bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
   5673 
   5674  if ((mFlags & nsDisplayOwnLayerFlags::GenerateScrollableLayer) &&
   5675      usingDisplayPort) {
   5676    *aSnap = false;
   5677    return mFrame->GetRect() + aBuilder->ToReferenceFrame(mFrame);
   5678  }
   5679 
   5680  return nsDisplayOwnLayer::GetBounds(aBuilder, aSnap);
   5681 }
   5682 
   5683 nsRegion nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   5684                                               bool* aSnap) const {
   5685  bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
   5686 
   5687  if ((mFlags & nsDisplayOwnLayerFlags::GenerateScrollableLayer) &&
   5688      usingDisplayPort) {
   5689    *aSnap = false;
   5690    return nsRegion();
   5691  }
   5692 
   5693  return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder, aSnap);
   5694 }
   5695 
   5696 /* static */
   5697 nsDisplayFixedPosition* nsDisplayFixedPosition::CreateForFixedBackground(
   5698    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aSecondaryFrame,
   5699    nsDisplayBackgroundImage* aImage, const uint16_t aIndex,
   5700    const ActiveScrolledRoot* aScrollTargetASR) {
   5701  nsDisplayList temp(aBuilder);
   5702  temp.AppendToTop(aImage);
   5703 
   5704  if (aSecondaryFrame) {
   5705    auto tableType = GetTableTypeFromFrame(aFrame);
   5706    const uint16_t index = CalculateTablePerFrameKey(aIndex + 1, tableType);
   5707    return MakeDisplayItemWithIndex<nsDisplayTableFixedPosition>(
   5708        aBuilder, aSecondaryFrame, index, &temp, aFrame, aScrollTargetASR);
   5709  }
   5710 
   5711  return MakeDisplayItemWithIndex<nsDisplayFixedPosition>(
   5712      aBuilder, aFrame, aIndex + 1, &temp, aScrollTargetASR);
   5713 }
   5714 
   5715 nsDisplayFixedPosition::nsDisplayFixedPosition(
   5716    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5717    const ActiveScrolledRoot* aActiveScrolledRoot,
   5718    ContainerASRType aContainerASRType,
   5719    const ActiveScrolledRoot* aScrollTargetASR, bool aForceIsolation)
   5720    : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot,
   5721                        aContainerASRType),
   5722      mScrollTargetASR(aScrollTargetASR),
   5723      mIsFixedBackground(false),
   5724      mForceIsolation(aForceIsolation) {
   5725  MOZ_COUNT_CTOR(nsDisplayFixedPosition);
   5726  MOZ_ASSERT_IF(mScrollTargetASR,
   5727                mScrollTargetASR->mKind == ActiveScrolledRoot::ASRKind::Scroll);
   5728 }
   5729 
   5730 nsDisplayFixedPosition::nsDisplayFixedPosition(
   5731    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5732    const ActiveScrolledRoot* aScrollTargetASR)
   5733    : nsDisplayOwnLayer(aBuilder, aFrame, aList,
   5734                        aBuilder->CurrentActiveScrolledRoot(),
   5735                        ContainerASRType::Constant),
   5736      // For fixed backgrounds, this is the ASR for the nearest scroll frame.
   5737      mScrollTargetASR(aScrollTargetASR),
   5738      mIsFixedBackground(true),
   5739      mForceIsolation(false) {
   5740  MOZ_COUNT_CTOR(nsDisplayFixedPosition);
   5741  MOZ_ASSERT_IF(mScrollTargetASR,
   5742                mScrollTargetASR->mKind == ActiveScrolledRoot::ASRKind::Scroll);
   5743 }
   5744 
   5745 ScrollableLayerGuid::ViewID nsDisplayFixedPosition::GetScrollTargetId() const {
   5746  if (mScrollTargetASR &&
   5747      (mIsFixedBackground || !nsLayoutUtils::IsReallyFixedPos(mFrame))) {
   5748    return mScrollTargetASR->GetViewId();
   5749  }
   5750  return nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext());
   5751 }
   5752 
   5753 bool nsDisplayFixedPosition::CreateWebRenderCommands(
   5754    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5755    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5756    nsDisplayListBuilder* aDisplayListBuilder) {
   5757  SideBits sides = SideBits::eNone;
   5758  if (!mIsFixedBackground) {
   5759    sides = nsLayoutUtils::GetSideBitsForFixedPositionContent(mFrame);
   5760  }
   5761 
   5762  // We install this RAII scrolltarget tracker so that any
   5763  // nsDisplayCompositorHitTestInfo items inside this fixed-pos item (and that
   5764  // share the same ASR as this item) use the correct scroll target. That way
   5765  // attempts to scroll on those items will scroll the root scroll frame.
   5766  wr::DisplayListBuilder::FixedPosScrollTargetTracker tracker(
   5767      aBuilder, GetActiveScrolledRoot(), GetScrollTargetId(), sides);
   5768  return nsDisplayOwnLayer::CreateWebRenderCommands(
   5769      aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
   5770 }
   5771 
   5772 bool nsDisplayFixedPosition::UpdateScrollData(
   5773    WebRenderScrollData* aData, WebRenderLayerScrollData* aLayerData) {
   5774  if (aLayerData) {
   5775    if (!mIsFixedBackground) {
   5776      aLayerData->SetFixedPositionSides(
   5777          nsLayoutUtils::GetSideBitsForFixedPositionContent(mFrame));
   5778    }
   5779    aLayerData->SetFixedPositionScrollContainerId(GetScrollTargetId());
   5780  }
   5781  nsDisplayOwnLayer::UpdateScrollData(aData, aLayerData);
   5782  return true;
   5783 }
   5784 
   5785 bool nsDisplayFixedPosition::ShouldGetFixedAnimationId() {
   5786 #if defined(MOZ_WIDGET_ANDROID)
   5787  return mFrame->PresContext()->IsRootContentDocumentCrossProcess() &&
   5788         nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext()) ==
   5789             GetScrollTargetId();
   5790 #else
   5791  return HasDynamicToolbar() &&
   5792         (nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext()) ==
   5793          GetScrollTargetId());
   5794 #endif
   5795 }
   5796 
   5797 void nsDisplayFixedPosition::WriteDebugInfo(std::stringstream& aStream) {
   5798  aStream << nsPrintfCString(
   5799                 " (containerASR %s) (scrolltarget %" PRIu64 ")",
   5800                 ActiveScrolledRoot::ToString(mScrollTargetASR).get(),
   5801                 GetScrollTargetId())
   5802                 .get();
   5803 }
   5804 
   5805 TableType GetTableTypeFromFrame(nsIFrame* aFrame) {
   5806  if (aFrame->IsTableFrame()) {
   5807    return TableType::Table;
   5808  }
   5809 
   5810  if (aFrame->IsTableColFrame()) {
   5811    return TableType::TableCol;
   5812  }
   5813 
   5814  if (aFrame->IsTableColGroupFrame()) {
   5815    return TableType::TableColGroup;
   5816  }
   5817 
   5818  if (aFrame->IsTableRowFrame()) {
   5819    return TableType::TableRow;
   5820  }
   5821 
   5822  if (aFrame->IsTableRowGroupFrame()) {
   5823    return TableType::TableRowGroup;
   5824  }
   5825 
   5826  if (aFrame->IsTableCellFrame()) {
   5827    return TableType::TableCell;
   5828  }
   5829 
   5830  MOZ_ASSERT_UNREACHABLE("Invalid frame.");
   5831  return TableType::Table;
   5832 }
   5833 
   5834 nsDisplayTableFixedPosition::nsDisplayTableFixedPosition(
   5835    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5836    nsIFrame* aAncestorFrame, const ActiveScrolledRoot* aScrollTargetASR)
   5837    : nsDisplayFixedPosition(aBuilder, aFrame, aList, aScrollTargetASR),
   5838      mAncestorFrame(aAncestorFrame) {
   5839  if (aBuilder->IsRetainingDisplayList()) {
   5840    mAncestorFrame->AddDisplayItem(this);
   5841  }
   5842 }
   5843 
   5844 void nsDisplayTableFixedPosition::Destroy(nsDisplayListBuilder* aBuilder) {
   5845  RemoveDisplayItemFromFrame(aBuilder, mAncestorFrame);
   5846  nsDisplayFixedPosition::Destroy(aBuilder);
   5847 }
   5848 
   5849 nsDisplayStickyPosition::nsDisplayStickyPosition(
   5850    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   5851    const ActiveScrolledRoot* aActiveScrolledRoot,
   5852    ContainerASRType aContainerASRType, const ActiveScrolledRoot* aContainerASR)
   5853    : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot,
   5854                        aContainerASRType, nsDisplayOwnLayerFlags::None,
   5855                        layers::ScrollbarData{},
   5856                        /*aForceActive=*/true, /*aClearClipChain=*/true),
   5857      mContainerASR(aContainerASR),
   5858      mShouldFlatten(false) {
   5859  MOZ_COUNT_CTOR(nsDisplayStickyPosition);
   5860 }
   5861 
   5862 StickyScrollContainer* nsDisplayStickyPosition::GetStickyScrollContainer() {
   5863  auto* ssc = StickyScrollContainer::GetOrCreateForFrame(mFrame);
   5864  if (!ssc) {
   5865    return nullptr;
   5866  }
   5867  // If there's no ASR for the scrollframe that this sticky item is attached
   5868  // to, then don't create a WR sticky item for it either. Trying to do so
   5869  // will end in sadness because WR will interpret some coordinates as
   5870  // relative to the nearest enclosing scrollframe, which will correspond
   5871  // to the nearest ancestor ASR on the gecko side. That ASR will not be the
   5872  // same as the scrollframe this sticky item is actually supposed to be
   5873  // attached to, thus the sadness.
   5874  // Not sending WR the sticky item is ok, because the enclosing scrollframe
   5875  // will never be asynchronously scrolled. Instead we will always position
   5876  // the sticky items correctly on the gecko side and WR will never need to
   5877  // adjust their position itself.
   5878  MOZ_ASSERT(ssc->ScrollContainer()->IsMaybeAsynchronouslyScrolled());
   5879  if (!ssc->ScrollContainer()->IsMaybeAsynchronouslyScrolled()) {
   5880    return nullptr;
   5881  }
   5882  return ssc;
   5883 }
   5884 
   5885 bool nsDisplayStickyPosition::CreateWebRenderCommands(
   5886    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   5887    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   5888    nsDisplayListBuilder* aDisplayListBuilder) {
   5889  StickyScrollContainer* stickyScrollContainer = GetStickyScrollContainer();
   5890 
   5891  Maybe<wr::SpaceAndClipChainHelper> saccHelper;
   5892 
   5893  if (stickyScrollContainer && !stickyScrollContainer->ShouldFlattenAway()) {
   5894    const ActiveScrolledRoot* stickyAsr =
   5895        ActiveScrolledRoot::GetStickyASRFromFrame(mFrame);
   5896    MOZ_ASSERT(stickyAsr);
   5897    auto spatialId = aBuilder.GetSpatialIdForDefinedStickyLayer(stickyAsr);
   5898    MOZ_ASSERT(spatialId.isSome());
   5899    saccHelper.emplace(aBuilder, *spatialId);
   5900  }
   5901 
   5902  {
   5903    wr::StackingContextParams params;
   5904    params.clip =
   5905        wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   5906    StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this,
   5907                             aBuilder, params);
   5908    nsDisplayOwnLayer::CreateWebRenderCommands(aBuilder, aResources, sc,
   5909                                               aManager, aDisplayListBuilder);
   5910  }
   5911 
   5912  return true;
   5913 }
   5914 
   5915 void nsDisplayStickyPosition::CalculateLayerScrollRanges(
   5916    StickyScrollContainer* aStickyScrollContainer, float aAppUnitsPerDevPixel,
   5917    float aScaleX, float aScaleY, LayerRectAbsolute& aStickyOuter,
   5918    LayerRectAbsolute& aStickyInner) {
   5919  nsRectAbsolute outer;
   5920  nsRectAbsolute inner;
   5921  aStickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
   5922  aStickyOuter.SetBox(
   5923      NSAppUnitsToFloatPixels(outer.X(), aAppUnitsPerDevPixel) * aScaleX,
   5924      NSAppUnitsToFloatPixels(outer.Y(), aAppUnitsPerDevPixel) * aScaleY,
   5925      NSAppUnitsToFloatPixels(outer.XMost(), aAppUnitsPerDevPixel) * aScaleX,
   5926      NSAppUnitsToFloatPixels(outer.YMost(), aAppUnitsPerDevPixel) * aScaleY);
   5927  aStickyInner.SetBox(
   5928      NSAppUnitsToFloatPixels(inner.X(), aAppUnitsPerDevPixel) * aScaleX,
   5929      NSAppUnitsToFloatPixels(inner.Y(), aAppUnitsPerDevPixel) * aScaleY,
   5930      NSAppUnitsToFloatPixels(inner.XMost(), aAppUnitsPerDevPixel) * aScaleX,
   5931      NSAppUnitsToFloatPixels(inner.YMost(), aAppUnitsPerDevPixel) * aScaleY);
   5932 }
   5933 
   5934 bool nsDisplayStickyPosition::UpdateScrollData(
   5935    WebRenderScrollData* aData, WebRenderLayerScrollData* aLayerData) {
   5936  bool hasDynamicToolbar = HasDynamicToolbar();
   5937  if (aLayerData && hasDynamicToolbar) {
   5938    StickyScrollContainer* stickyScrollContainer = GetStickyScrollContainer();
   5939    if (stickyScrollContainer) {
   5940      float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   5941      float cumulativeResolution =
   5942          mFrame->PresShell()->GetCumulativeResolution();
   5943      LayerRectAbsolute stickyOuter;
   5944      LayerRectAbsolute stickyInner;
   5945      CalculateLayerScrollRanges(stickyScrollContainer, auPerDevPixel,
   5946                                 cumulativeResolution, cumulativeResolution,
   5947                                 stickyOuter, stickyInner);
   5948      aLayerData->SetStickyScrollRangeOuter(stickyOuter);
   5949      aLayerData->SetStickyScrollRangeInner(stickyInner);
   5950 
   5951      SideBits sides =
   5952          nsLayoutUtils::GetSideBitsForFixedPositionContent(mFrame);
   5953      aLayerData->SetFixedPositionSides(sides);
   5954 
   5955      ScrollableLayerGuid::ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
   5956          stickyScrollContainer->ScrollContainer()
   5957              ->GetScrolledFrame()
   5958              ->GetContent());
   5959      aLayerData->SetStickyPositionScrollContainerId(scrollId);
   5960    }
   5961 
   5962    if (ShouldGetStickyAnimationId()) {
   5963      // TODO(follow-up to bug 1730749): Should there be a
   5964      // "GetWebRenderUserData" method we should be calling here, rather than
   5965      // "CreateOrRecycle"?
   5966      RefPtr<WebRenderAPZAnimationData> animationData =
   5967          aData->GetManager()
   5968              ->CommandBuilder()
   5969              .CreateOrRecycleWebRenderUserData<WebRenderAPZAnimationData>(
   5970                  this);
   5971      MOZ_ASSERT(animationData);
   5972      aLayerData->SetStickyPositionAnimationId(animationData->GetAnimationId());
   5973    }
   5974  }
   5975  // Return true if either there is a dynamic toolbar affecting this sticky
   5976  // item or the OwnLayer base implementation returns true for some other
   5977  // reason.
   5978  bool ret = hasDynamicToolbar;
   5979  ret |= nsDisplayOwnLayer::UpdateScrollData(aData, aLayerData);
   5980  return ret;
   5981 }
   5982 
   5983 bool nsDisplayStickyPosition::ShouldGetStickyAnimationId(
   5984    nsIFrame* aStickyFrame) {
   5985  // Also implies being in the cross-process RCD.
   5986  // The animation id is how we translate the layer by the dynamic toolbar
   5987  // offset. It's not needed for regular sticky positioning, that's handled
   5988  // by WebRender without an animation id.
   5989  return nsDisplayOwnLayer::HasDynamicToolbar(aStickyFrame);
   5990 }
   5991 
   5992 bool nsDisplayStickyPosition::ShouldGetStickyAnimationId() const {
   5993  return ShouldGetStickyAnimationId(mFrame);
   5994 }
   5995 
   5996 nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
   5997    nsDisplayListBuilder* aBuilder, nsIFrame* aScrolledFrame,
   5998    nsIFrame* aScrollFrame, const CompositorHitTestInfo& aHitInfo,
   5999    const nsRect& aHitArea)
   6000    : nsDisplayWrapList(aBuilder, aScrollFrame),
   6001      mScrollFrame(aScrollFrame),
   6002      mScrolledFrame(aScrolledFrame),
   6003      mScrollParentId(aBuilder->GetCurrentScrollParentId()),
   6004      mHitInfo(aHitInfo),
   6005      mHitArea(aHitArea) {
   6006 #ifdef NS_BUILD_REFCNT_LOGGING
   6007  MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
   6008 #endif
   6009 }
   6010 
   6011 UniquePtr<ScrollMetadata> nsDisplayScrollInfoLayer::ComputeScrollMetadata(
   6012    nsDisplayListBuilder* aBuilder, WebRenderLayerManager* aLayerManager) {
   6013  ScrollMetadata metadata = nsLayoutUtils::ComputeScrollMetadata(
   6014      mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(), Frame(),
   6015      ToReferenceFrame(), aLayerManager, mScrollParentId,
   6016      mScrollFrame->GetSize(), false);
   6017  metadata.GetMetrics().SetIsScrollInfoLayer(true);
   6018  ScrollContainerFrame* scrollContainerFrame =
   6019      mScrollFrame->GetScrollTargetFrame();
   6020  if (scrollContainerFrame) {
   6021    aBuilder->AddScrollContainerFrameToNotify(scrollContainerFrame);
   6022  }
   6023 
   6024  return UniquePtr<ScrollMetadata>(new ScrollMetadata(metadata));
   6025 }
   6026 
   6027 bool nsDisplayScrollInfoLayer::UpdateScrollData(
   6028    WebRenderScrollData* aData, WebRenderLayerScrollData* aLayerData) {
   6029  if (aLayerData) {
   6030    UniquePtr<ScrollMetadata> metadata =
   6031        ComputeScrollMetadata(aData->GetBuilder(), aData->GetManager());
   6032    MOZ_ASSERT(aData);
   6033    MOZ_ASSERT(metadata);
   6034    aLayerData->AppendScrollMetadata(*aData, *metadata);
   6035  }
   6036  return true;
   6037 }
   6038 
   6039 bool nsDisplayScrollInfoLayer::CreateWebRenderCommands(
   6040    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   6041    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   6042    nsDisplayListBuilder* aDisplayListBuilder) {
   6043  ScrollableLayerGuid::ViewID scrollId =
   6044      nsLayoutUtils::FindOrCreateIDFor(mScrollFrame->GetContent());
   6045 
   6046  const LayoutDeviceRect devRect = LayoutDeviceRect::FromAppUnits(
   6047      mHitArea, mScrollFrame->PresContext()->AppUnitsPerDevPixel());
   6048 
   6049  const wr::LayoutRect rect = wr::ToLayoutRect(devRect);
   6050 
   6051  aBuilder.PushHitTest(rect, rect, !BackfaceIsHidden(), scrollId, mHitInfo,
   6052                       SideBits::eNone);
   6053 
   6054  return true;
   6055 }
   6056 
   6057 void nsDisplayScrollInfoLayer::WriteDebugInfo(std::stringstream& aStream) {
   6058  aStream << " (scrollframe " << mScrollFrame << " scrolledFrame "
   6059          << mScrolledFrame << ")";
   6060 }
   6061 
   6062 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
   6063                             nsSubDocumentFrame* aSubDocFrame,
   6064                             nsDisplayList* aList, int32_t aAPD,
   6065                             int32_t aParentAPD, nsDisplayOwnLayerFlags aFlags)
   6066    : nsDisplaySubDocument(aBuilder, aFrame, aSubDocFrame, aList, aFlags),
   6067      mAPD(aAPD),
   6068      mParentAPD(aParentAPD) {
   6069  MOZ_COUNT_CTOR(nsDisplayZoom);
   6070 }
   6071 
   6072 nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder,
   6073                                bool* aSnap) const {
   6074  nsRect bounds = nsDisplaySubDocument::GetBounds(aBuilder, aSnap);
   6075  *aSnap = false;
   6076  return bounds.ScaleToOtherAppUnitsRoundOut(mAPD, mParentAPD);
   6077 }
   6078 
   6079 void nsDisplayZoom::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   6080                            HitTestState* aState,
   6081                            nsTArray<nsIFrame*>* aOutFrames) {
   6082  nsRect rect;
   6083  // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
   6084  // rect as well instead of possibly rounding the width or height to zero.
   6085  if (aRect.width == 1 && aRect.height == 1) {
   6086    rect.MoveTo(aRect.TopLeft().ScaleToOtherAppUnits(mParentAPD, mAPD));
   6087    rect.width = rect.height = 1;
   6088  } else {
   6089    rect = aRect.ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
   6090  }
   6091  mList.HitTest(aBuilder, rect, aState, aOutFrames);
   6092 }
   6093 
   6094 nsDisplayAsyncZoom::nsDisplayAsyncZoom(
   6095    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   6096    const ActiveScrolledRoot* aActiveScrolledRoot,
   6097    ContainerASRType aContainerASRType, FrameMetrics::ViewID aViewID)
   6098    : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot,
   6099                        aContainerASRType),
   6100      mViewID(aViewID) {
   6101  MOZ_COUNT_CTOR(nsDisplayAsyncZoom);
   6102 }
   6103 
   6104 void nsDisplayAsyncZoom::HitTest(nsDisplayListBuilder* aBuilder,
   6105                                 const nsRect& aRect, HitTestState* aState,
   6106                                 nsTArray<nsIFrame*>* aOutFrames) {
   6107 #ifdef DEBUG
   6108  ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(mFrame);
   6109  MOZ_ASSERT(scrollContainerFrame &&
   6110             ViewportUtils::IsZoomedContentRoot(
   6111                 scrollContainerFrame->GetScrolledFrame()));
   6112 #endif
   6113  nsRect rect = ViewportUtils::VisualToLayout(aRect, mFrame->PresShell());
   6114  mList.HitTest(aBuilder, rect, aState, aOutFrames);
   6115 }
   6116 
   6117 bool nsDisplayAsyncZoom::UpdateScrollData(
   6118    WebRenderScrollData* aData, WebRenderLayerScrollData* aLayerData) {
   6119  bool ret = nsDisplayOwnLayer::UpdateScrollData(aData, aLayerData);
   6120  MOZ_ASSERT(ret);
   6121  if (aLayerData) {
   6122    aLayerData->SetAsyncZoomContainerId(mViewID);
   6123  }
   6124  return ret;
   6125 }
   6126 
   6127 ///////////////////////////////////////////////////
   6128 // nsDisplayTransform Implementation
   6129 //
   6130 
   6131 #ifndef DEBUG
   6132 static_assert(sizeof(nsDisplayTransform) <= 512,
   6133              "nsDisplayTransform has grown");
   6134 #endif
   6135 
   6136 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
   6137                                       nsIFrame* aFrame, nsDisplayList* aList,
   6138                                       const nsRect& aChildrenBuildingRect)
   6139    : nsPaintedDisplayItem(aBuilder, aFrame),
   6140      mChildren(aBuilder),
   6141      mTransform(Some(Matrix4x4())),
   6142      mChildrenBuildingRect(aChildrenBuildingRect),
   6143      mPrerenderDecision(PrerenderDecision::No),
   6144      mIsTransformSeparator(true),
   6145      mHasTransformGetter(false),
   6146      mHasAssociatedPerspective(false),
   6147      mContainsASRs(false),
   6148      mWrapsBackdropFilter(false),
   6149      mForceIsolation(false) {
   6150  MOZ_COUNT_CTOR(nsDisplayTransform);
   6151  MOZ_ASSERT(aFrame, "Must have a frame!");
   6152  Init(aBuilder, aList);
   6153 }
   6154 
   6155 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
   6156                                       nsIFrame* aFrame, nsDisplayList* aList,
   6157                                       const nsRect& aChildrenBuildingRect,
   6158                                       PrerenderDecision aPrerenderDecision,
   6159                                       bool aWrapsBackdropFilter,
   6160                                       bool aForceIsolation)
   6161    : nsPaintedDisplayItem(aBuilder, aFrame),
   6162      mChildren(aBuilder),
   6163      mChildrenBuildingRect(aChildrenBuildingRect),
   6164      mPrerenderDecision(aPrerenderDecision),
   6165      mIsTransformSeparator(false),
   6166      mHasTransformGetter(false),
   6167      mHasAssociatedPerspective(false),
   6168      mContainsASRs(false),
   6169      mWrapsBackdropFilter(aWrapsBackdropFilter),
   6170      mForceIsolation(aForceIsolation) {
   6171  MOZ_COUNT_CTOR(nsDisplayTransform);
   6172  MOZ_ASSERT(aFrame, "Must have a frame!");
   6173  SetReferenceFrameToAncestor(aBuilder);
   6174  Init(aBuilder, aList);
   6175 }
   6176 
   6177 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
   6178                                       nsIFrame* aFrame, nsDisplayList* aList,
   6179                                       const nsRect& aChildrenBuildingRect,
   6180                                       decltype(WithTransformGetter))
   6181    : nsPaintedDisplayItem(aBuilder, aFrame),
   6182      mChildren(aBuilder),
   6183      mChildrenBuildingRect(aChildrenBuildingRect),
   6184      mPrerenderDecision(PrerenderDecision::No),
   6185      mIsTransformSeparator(false),
   6186      mHasTransformGetter(true),
   6187      mHasAssociatedPerspective(false),
   6188      mContainsASRs(false),
   6189      mWrapsBackdropFilter(false),
   6190      mForceIsolation(false) {
   6191  MOZ_COUNT_CTOR(nsDisplayTransform);
   6192  MOZ_ASSERT(aFrame, "Must have a frame!");
   6193  MOZ_ASSERT(aFrame->GetTransformGetter());
   6194  Init(aBuilder, aList);
   6195 }
   6196 
   6197 void nsDisplayTransform::SetReferenceFrameToAncestor(
   6198    nsDisplayListBuilder* aBuilder) {
   6199  if (mFrame == aBuilder->RootReferenceFrame()) {
   6200    return;
   6201  }
   6202  // We manually recompute mToReferenceFrame without going through the
   6203  // builder, since this won't apply the 'additional offset'. Our
   6204  // children will already be painting with that applied, and we don't
   6205  // want to include it a second time in our transform. We don't recompute
   6206  // our visible/building rects, since those should still include the additional
   6207  // offset.
   6208  // TODO: Are there are things computed using our ToReferenceFrame that should
   6209  // have the additional offset applied? Should we instead just manually remove
   6210  // the offset from our transform instead of this more general value?
   6211  // Can we instead apply the additional offset to us and not our children, like
   6212  // we do for all other offsets (and how reference frames are supposed to
   6213  // work)?
   6214  // The reference frame on the builder has already been set to the ancestor
   6215  // reference frame by BuildDisplayListForStackingContext using
   6216  // SetReferenceFrameAndCurrentOffset, so we just compute the offset.
   6217  MOZ_ASSERT(aBuilder->FindReferenceFrameFor(
   6218                 nsLayoutUtils::GetCrossDocParentFrameInProcess(mFrame)) ==
   6219             aBuilder->GetCurrentReferenceFrame());
   6220  mToReferenceFrame =
   6221      mFrame->GetOffsetToCrossDoc(aBuilder->GetCurrentReferenceFrame());
   6222 }
   6223 
   6224 void nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder,
   6225                              nsDisplayList* aChildren) {
   6226  mChildren.AppendToTop(aChildren);
   6227  UpdateBounds(aBuilder);
   6228 }
   6229 
   6230 bool nsDisplayTransform::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
   6231  return false;
   6232 }
   6233 
   6234 /* Returns the delta specified by the transform-origin property.
   6235 * This is a positive delta, meaning that it indicates the direction to move
   6236 * to get from (0, 0) of the frame to the transform origin.  This function is
   6237 * called off the main thread.
   6238 */
   6239 /* static */
   6240 Point3D nsDisplayTransform::GetDeltaToTransformOrigin(
   6241    const nsIFrame* aFrame, TransformReferenceBox& aRefBox,
   6242    float aAppUnitsPerPixel) {
   6243  MOZ_ASSERT(aFrame, "Can't get delta for a null frame!");
   6244  MOZ_ASSERT(aFrame->IsTransformed() || aFrame->BackfaceIsHidden() ||
   6245                 aFrame->Combines3DTransformWithAncestors(),
   6246             "Shouldn't get a delta for an untransformed frame!");
   6247 
   6248  if (!aFrame->IsTransformed()) {
   6249    return Point3D();
   6250  }
   6251 
   6252  /* For both of the coordinates, if the value of transform is a
   6253   * percentage, it's relative to the size of the frame.  Otherwise, if it's
   6254   * a distance, it's already computed for us!
   6255   */
   6256  const nsStyleDisplay* display = aFrame->StyleDisplay();
   6257 
   6258  const StyleTransformOrigin& transformOrigin = display->mTransformOrigin;
   6259  CSSPoint origin = nsStyleTransformMatrix::Convert2DPosition(
   6260      transformOrigin.horizontal, transformOrigin.vertical, aRefBox);
   6261 
   6262  // Note:
   6263  // 1. SVG frames have a reference box that can be (and typically is) offset
   6264  //    from the TopLeft() of the frame. We need to account for that here.
   6265  // 2. If we are using transform-box:content-box in CSS layout, we have the
   6266  //    offset from TopLeft() of the frame as well.
   6267  origin.x += CSSPixel::FromAppUnits(aRefBox.X());
   6268  origin.y += CSSPixel::FromAppUnits(aRefBox.Y());
   6269 
   6270  float scale = AppUnitsPerCSSPixel() / float(aAppUnitsPerPixel);
   6271  float z = transformOrigin.depth._0;
   6272  return Point3D(origin.x * scale, origin.y * scale, z * scale);
   6273 }
   6274 
   6275 /* static */
   6276 bool nsDisplayTransform::ComputePerspectiveMatrix(const nsIFrame* aFrame,
   6277                                                  float aAppUnitsPerPixel,
   6278                                                  Matrix4x4& aOutMatrix) {
   6279  MOZ_ASSERT(aFrame, "Can't get delta for a null frame!");
   6280  MOZ_ASSERT(aFrame->IsTransformed() || aFrame->BackfaceIsHidden() ||
   6281                 aFrame->Combines3DTransformWithAncestors(),
   6282             "Shouldn't get a delta for an untransformed frame!");
   6283  MOZ_ASSERT(aOutMatrix.IsIdentity(), "Must have a blank output matrix");
   6284 
   6285  if (!aFrame->IsTransformed()) {
   6286    return false;
   6287  }
   6288 
   6289  // TODO: Is it possible that the perspectiveFrame's bounds haven't been set
   6290  // correctly yet (similar to the aBoundsOverride case for
   6291  // GetResultingTransformMatrix)?
   6292  nsIFrame* perspectiveFrame =
   6293      aFrame->GetClosestFlattenedTreeAncestorPrimaryFrame();
   6294  if (!perspectiveFrame) {
   6295    return false;
   6296  }
   6297 
   6298  /* Grab the values for perspective and perspective-origin (if present) */
   6299  const nsStyleDisplay* perspectiveDisplay = perspectiveFrame->StyleDisplay();
   6300  if (perspectiveDisplay->mChildPerspective.IsNone()) {
   6301    return false;
   6302  }
   6303 
   6304  MOZ_ASSERT(perspectiveDisplay->mChildPerspective.IsLength());
   6305  float perspective =
   6306      perspectiveDisplay->mChildPerspective.AsLength().ToCSSPixels();
   6307  perspective = std::max(1.0f, perspective);
   6308  if (perspective < std::numeric_limits<Float>::epsilon()) {
   6309    return true;
   6310  }
   6311 
   6312  TransformReferenceBox refBox(perspectiveFrame);
   6313 
   6314  Point perspectiveOrigin = nsStyleTransformMatrix::Convert2DPosition(
   6315      perspectiveDisplay->mPerspectiveOrigin.horizontal,
   6316      perspectiveDisplay->mPerspectiveOrigin.vertical, refBox,
   6317      aAppUnitsPerPixel);
   6318 
   6319  /* GetOffsetTo computes the offset required to move from 0,0 in
   6320   * perspectiveFrame to 0,0 in aFrame. Although we actually want the inverse of
   6321   * this, it's faster to compute this way.
   6322   */
   6323  nsPoint frameToPerspectiveOffset = -aFrame->GetOffsetTo(perspectiveFrame);
   6324  Point frameToPerspectiveGfxOffset(
   6325      NSAppUnitsToFloatPixels(frameToPerspectiveOffset.x, aAppUnitsPerPixel),
   6326      NSAppUnitsToFloatPixels(frameToPerspectiveOffset.y, aAppUnitsPerPixel));
   6327 
   6328  /* Move the perspective origin to be relative to aFrame, instead of relative
   6329   * to the containing block which is how it was specified in the style system.
   6330   */
   6331  perspectiveOrigin += frameToPerspectiveGfxOffset;
   6332 
   6333  aOutMatrix._34 =
   6334      -1.0 / NSAppUnitsToFloatPixels(CSSPixel::ToAppUnits(perspective),
   6335                                     aAppUnitsPerPixel);
   6336 
   6337  aOutMatrix.ChangeBasis(Point3D(perspectiveOrigin.x, perspectiveOrigin.y, 0));
   6338  return true;
   6339 }
   6340 
   6341 nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(
   6342    const nsIFrame* aFrame, TransformReferenceBox& aRefBox,
   6343    float aAppUnitsPerPixel)
   6344    : mFrame(aFrame),
   6345      mTranslate(aFrame->StyleDisplay()->mTranslate),
   6346      mRotate(aFrame->StyleDisplay()->mRotate),
   6347      mScale(aFrame->StyleDisplay()->mScale),
   6348      mTransform(aFrame->StyleDisplay()->mTransform),
   6349      mMotion(aFrame->StyleDisplay()->mOffsetPath.IsNone()
   6350                  ? Nothing()
   6351                  : MotionPathUtils::ResolveMotionPath(aFrame, aRefBox)),
   6352      mToTransformOrigin(
   6353          GetDeltaToTransformOrigin(aFrame, aRefBox, aAppUnitsPerPixel)) {}
   6354 
   6355 /* Wraps up the transform matrix in a change-of-basis matrix pair that
   6356 * translates from local coordinate space to transform coordinate space, then
   6357 * hands it back.
   6358 */
   6359 Matrix4x4 nsDisplayTransform::GetResultingTransformMatrix(
   6360    const FrameTransformProperties& aProperties, TransformReferenceBox& aRefBox,
   6361    float aAppUnitsPerPixel) {
   6362  return GetResultingTransformMatrixInternal(aProperties, aRefBox, nsPoint(),
   6363                                             aAppUnitsPerPixel, 0);
   6364 }
   6365 
   6366 Matrix4x4 nsDisplayTransform::GetResultingTransformMatrix(
   6367    const nsIFrame* aFrame, const nsPoint& aOrigin, float aAppUnitsPerPixel,
   6368    uint32_t aFlags) {
   6369  TransformReferenceBox refBox(aFrame);
   6370  FrameTransformProperties props(aFrame, refBox, aAppUnitsPerPixel);
   6371  return GetResultingTransformMatrixInternal(props, refBox, aOrigin,
   6372                                             aAppUnitsPerPixel, aFlags);
   6373 }
   6374 
   6375 Matrix4x4 nsDisplayTransform::GetResultingTransformMatrixInternal(
   6376    const FrameTransformProperties& aProperties, TransformReferenceBox& aRefBox,
   6377    const nsPoint& aOrigin, float aAppUnitsPerPixel, uint32_t aFlags) {
   6378  const nsIFrame* frame = aProperties.mFrame;
   6379  NS_ASSERTION(frame || !(aFlags & INCLUDE_PERSPECTIVE),
   6380               "Must have a frame to compute perspective!");
   6381 
   6382  // IncrementScaleRestyleCountIfNeeded in ActiveLayerTracker.cpp is a
   6383  // simplified copy of this function.
   6384 
   6385  // Get the underlying transform matrix:
   6386 
   6387  /* Get the matrix, then change its basis to factor in the origin. */
   6388  Matrix4x4 result;
   6389 
   6390  // See the comment for SVGContainerFrame::HasChildrenOnlyTransform for
   6391  // an explanation of what children-only transforms are.
   6392  Matrix parentsChildrenOnlyTransform;
   6393  const bool parentHasChildrenOnlyTransform =
   6394      frame && frame->HasAnyStateBits(NS_FRAME_MAY_BE_TRANSFORMED) &&
   6395      frame->GetParentSVGTransforms(&parentsChildrenOnlyTransform) &&
   6396      !parentsChildrenOnlyTransform.IsIdentity();
   6397  bool shouldRound = nsLayoutUtils::ShouldSnapToGrid(frame);
   6398 
   6399  /* Transformed frames always have a transform, or are preserving 3d (and might
   6400   * still have perspective!) */
   6401  if (aProperties.HasTransform()) {
   6402    result = nsStyleTransformMatrix::ReadTransforms(
   6403        aProperties.mTranslate, aProperties.mRotate, aProperties.mScale,
   6404        aProperties.mMotion.ptrOr(nullptr), aProperties.mTransform, aRefBox,
   6405        aAppUnitsPerPixel);
   6406  }
   6407 
   6408  // Apply any translation due to 'transform-origin' and/or 'transform-box':
   6409  if (aProperties.mToTransformOrigin != gfx::Point3D()) {
   6410    result.ChangeBasis(aProperties.mToTransformOrigin);
   6411  }
   6412 
   6413  if (parentHasChildrenOnlyTransform) {
   6414    float pixelsPerCSSPx = AppUnitsPerCSSPixel() / aAppUnitsPerPixel;
   6415    parentsChildrenOnlyTransform._31 *= pixelsPerCSSPx;
   6416    parentsChildrenOnlyTransform._32 *= pixelsPerCSSPx;
   6417    auto parentsChildrenOnlyTransform3D =
   6418        Matrix4x4::From2D(parentsChildrenOnlyTransform);
   6419    // <svg> outer anon child frame doesn't need the extra basis change because
   6420    // it is the root of the svg rendering (and thus its offset with respect to
   6421    // its parent, like border / padding shouldn't be accounted for).
   6422    if (frame->GetPosition() != nsPoint() &&
   6423        !frame->IsSVGOuterSVGAnonChildFrame()) {
   6424      const Point3D frameOffset(
   6425          NSAppUnitsToFloatPixels(-frame->GetPosition().x, aAppUnitsPerPixel),
   6426          NSAppUnitsToFloatPixels(-frame->GetPosition().y, aAppUnitsPerPixel),
   6427          0);
   6428      parentsChildrenOnlyTransform3D.ChangeBasis(frameOffset);
   6429    }
   6430 
   6431    result *= parentsChildrenOnlyTransform3D;
   6432  }
   6433 
   6434  Matrix4x4 perspectiveMatrix;
   6435  bool hasPerspective = aFlags & INCLUDE_PERSPECTIVE;
   6436  if (hasPerspective) {
   6437    if (ComputePerspectiveMatrix(frame, aAppUnitsPerPixel, perspectiveMatrix)) {
   6438      result *= perspectiveMatrix;
   6439    }
   6440  }
   6441 
   6442  if ((aFlags & INCLUDE_PRESERVE3D_ANCESTORS) && frame &&
   6443      frame->Combines3DTransformWithAncestors()) {
   6444    // Include the transform set on our parent
   6445    nsIFrame* parentFrame =
   6446        frame->GetClosestFlattenedTreeAncestorPrimaryFrame();
   6447    NS_ASSERTION(parentFrame && parentFrame->IsTransformed() &&
   6448                     parentFrame->Extend3DContext(),
   6449                 "Preserve3D mismatch!");
   6450    TransformReferenceBox refBox(parentFrame);
   6451    FrameTransformProperties props(parentFrame, refBox, aAppUnitsPerPixel);
   6452 
   6453    // Whenever we are including preserve3d we want to also include perspective
   6454    // (if it exists).
   6455    uint32_t flags = (INCLUDE_PRESERVE3D_ANCESTORS | INCLUDE_PERSPECTIVE);
   6456 
   6457    // If this frame isn't transformed (but we exist for backface-visibility),
   6458    // then we're not a reference frame so no offset to origin will be added.
   6459    // Otherwise we need to manually translate into our parent's coordinate
   6460    // space.
   6461    if (frame->IsTransformed()) {
   6462      nsLayoutUtils::PostTranslate(result, frame->GetPosition(),
   6463                                   aAppUnitsPerPixel, shouldRound);
   6464    }
   6465    Matrix4x4 parent = GetResultingTransformMatrixInternal(
   6466        props, refBox, nsPoint(0, 0), aAppUnitsPerPixel, flags);
   6467    result = result * parent;
   6468  }
   6469 
   6470  MOZ_ASSERT((aOrigin == nsPoint()) || (aFlags & OFFSET_BY_ORIGIN));
   6471  if ((aFlags & OFFSET_BY_ORIGIN) && (aOrigin != nsPoint())) {
   6472    nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel,
   6473                                 shouldRound);
   6474  }
   6475 
   6476  return result;
   6477 }
   6478 
   6479 bool nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
   6480  static constexpr nsCSSPropertyIDSet opacitySet =
   6481      nsCSSPropertyIDSet::OpacityProperties();
   6482  if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, opacitySet)) {
   6483    return true;
   6484  }
   6485 
   6486  EffectCompositor::SetPerformanceWarning(
   6487      mFrame, opacitySet,
   6488      AnimationPerformanceWarning(
   6489          AnimationPerformanceWarning::Type::OpacityFrameInactive));
   6490 
   6491  return false;
   6492 }
   6493 
   6494 bool nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
   6495  return mPrerenderDecision != PrerenderDecision::No;
   6496 }
   6497 
   6498 bool nsDisplayBackgroundColor::CanUseAsyncAnimations(
   6499    nsDisplayListBuilder* aBuilder) {
   6500  return StaticPrefs::gfx_omta_background_color();
   6501 }
   6502 
   6503 void nsDisplayTableBackgroundColor::Destroy(nsDisplayListBuilder* aBuilder) {
   6504  RemoveDisplayItemFromFrame(aBuilder, mAncestorFrame);
   6505  nsDisplayBackgroundColor::Destroy(aBuilder);
   6506 }
   6507 
   6508 static bool IsInStickyPositionedSubtree(const nsIFrame* aFrame) {
   6509  for (const nsIFrame* frame = aFrame; frame;
   6510       frame = nsLayoutUtils::GetCrossDocParentFrameInProcess(frame)) {
   6511    if (frame->IsStickyPositioned()) {
   6512      return true;
   6513    }
   6514  }
   6515  return false;
   6516 }
   6517 
   6518 static bool ShouldUsePartialPrerender(const nsIFrame* aFrame) {
   6519  return StaticPrefs::layout_animation_prerender_partial() &&
   6520         // Bug 1642547: Support partial prerender for position:sticky elements.
   6521         !IsInStickyPositionedSubtree(aFrame);
   6522 }
   6523 
   6524 /* static */
   6525 auto nsDisplayTransform::ShouldPrerenderTransformedContent(
   6526    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsRect* aDirtyRect)
   6527    -> PrerenderInfo {
   6528  PrerenderInfo result;
   6529 
   6530  // Prerendering only makes sense if we are painting to the window so that the
   6531  // extra prerendered content can be animated into view by the compositor.
   6532  // GenerateGlyphMask (for background-clip: text) uses a nested builder, so it
   6533  // can be inside a builder that is painting to window, and it's buggy, so just
   6534  // allow it to minimize bugs.
   6535  if (!aBuilder->IsPaintingToWindow() && !aBuilder->IsForGenerateGlyphMask()) {
   6536    return result;
   6537  }
   6538 
   6539  // If we are in a preserve-3d tree, and we've disallowed async animations, we
   6540  // return No prerender decision directly.
   6541  if ((aFrame->Extend3DContext() ||
   6542       aFrame->Combines3DTransformWithAncestors()) &&
   6543      !aBuilder->GetPreserves3DAllowAsyncAnimation()) {
   6544    return result;
   6545  }
   6546 
   6547  // Elements whose transform has been modified recently, or which
   6548  // have a compositor-animated transform, can be prerendered. An element
   6549  // might have only just had its transform animated in which case
   6550  // the ActiveLayerManager may not have been notified yet.
   6551  static constexpr nsCSSPropertyIDSet transformSet =
   6552      nsCSSPropertyIDSet::TransformLikeProperties();
   6553  if (!ActiveLayerTracker::IsTransformMaybeAnimated(aFrame) &&
   6554      !EffectCompositor::HasAnimationsForCompositor(
   6555          aFrame, DisplayItemType::TYPE_TRANSFORM)) {
   6556    EffectCompositor::SetPerformanceWarning(
   6557        aFrame, transformSet,
   6558        AnimationPerformanceWarning(
   6559            AnimationPerformanceWarning::Type::TransformFrameInactive));
   6560 
   6561    // This case happens when we're sure that the frame is not animated and its
   6562    // preserve-3d ancestors are not, either. So we don't need to pre-render.
   6563    // However, this decision shouldn't affect the decisions for other frames in
   6564    // the preserve-3d context. We need this flag to determine whether we should
   6565    // block async animations on other frames in the current preserve-3d tree.
   6566    result.mHasAnimations = false;
   6567    return result;
   6568  }
   6569 
   6570  // We should not allow prerender if any ancestor container element has
   6571  // mask/clip-path effects.
   6572  //
   6573  // With prerender and async transform animation, we do not need to restyle an
   6574  // animated element to respect position changes, since that transform is done
   6575  // by layer animation. As a result, the container element is not aware of
   6576  // position change of that containing element and loses the chance to update
   6577  // the content of mask/clip-path.
   6578  //
   6579  // Why do we need to update a mask? This is relative to how we generate a
   6580  // mask layer in ContainerState::SetupMaskLayerForCSSMask. While creating a
   6581  // mask layer, to reduce memory usage, we did not choose the size of the
   6582  // masked element as mask size. Instead, we read the union of bounds of all
   6583  // children display items by nsDisplayWrapList::GetBounds, which is smaller
   6584  // than or equal to the masked element's boundary, and use it as the position
   6585  // size of the mask layer. That union bounds is actually affected by the
   6586  // geometry of the animated element. To keep the content of mask up to date,
   6587  // forbidding of prerender is required.
   6588  for (nsIFrame* container =
   6589           nsLayoutUtils::GetCrossDocParentFrameInProcess(aFrame);
   6590       container;
   6591       container = nsLayoutUtils::GetCrossDocParentFrameInProcess(container)) {
   6592    const nsStyleSVGReset* svgReset = container->StyleSVGReset();
   6593    if (svgReset->HasMask() || svgReset->HasClipPath()) {
   6594      return result;
   6595    }
   6596  }
   6597 
   6598  // If the incoming dirty rect already contains the entire overflow area,
   6599  // we are already rendering the entire content.
   6600  nsRect overflow = aFrame->InkOverflowRectRelativeToSelf();
   6601  // UntransformRect will not touch the output rect (`&untranformedDirtyRect`)
   6602  // in cases of non-invertible transforms, so we set `untransformedRect` to
   6603  // `aDirtyRect` as an initial value for such cases.
   6604  nsRect untransformedDirtyRect = *aDirtyRect;
   6605  UntransformRect(*aDirtyRect, overflow, aFrame, &untransformedDirtyRect);
   6606  if (untransformedDirtyRect.Contains(overflow)) {
   6607    *aDirtyRect = untransformedDirtyRect;
   6608    result.mDecision = PrerenderDecision::Full;
   6609    return result;
   6610  }
   6611 
   6612  float viewportRatio =
   6613      StaticPrefs::layout_animation_prerender_viewport_ratio_limit();
   6614  uint32_t absoluteLimitX =
   6615      StaticPrefs::layout_animation_prerender_absolute_limit_x();
   6616  uint32_t absoluteLimitY =
   6617      StaticPrefs::layout_animation_prerender_absolute_limit_y();
   6618  nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
   6619 
   6620  float resolution = aFrame->PresShell()->GetCumulativeResolution();
   6621  if (resolution < 1.0f) {
   6622    refSize.SizeTo(
   6623        NSCoordSaturatingNonnegativeMultiply(refSize.width, 1.0f / resolution),
   6624        NSCoordSaturatingNonnegativeMultiply(refSize.height,
   6625                                             1.0f / resolution));
   6626  }
   6627 
   6628  // Only prerender if the transformed frame's size is <= a multiple of the
   6629  // reference frame size (~viewport), and less than an absolute limit.
   6630  // Both the ratio and the absolute limit are configurable.
   6631  nscoord maxLength = std::max(nscoord(refSize.width * viewportRatio),
   6632                               nscoord(refSize.height * viewportRatio));
   6633  nsSize relativeLimit(maxLength, maxLength);
   6634  nsSize absoluteLimit(
   6635      aFrame->PresContext()->DevPixelsToAppUnits(absoluteLimitX),
   6636      aFrame->PresContext()->DevPixelsToAppUnits(absoluteLimitY));
   6637  nsSize maxSize = Min(relativeLimit, absoluteLimit);
   6638 
   6639  const auto transform = nsLayoutUtils::GetTransformToAncestor(
   6640      RelativeTo{aFrame},
   6641      RelativeTo{nsLayoutUtils::GetDisplayRootFrame(aFrame)});
   6642  const gfxRect transformedBounds = transform.TransformAndClipBounds(
   6643      gfxRect(overflow.x, overflow.y, overflow.width, overflow.height),
   6644      gfxRect::MaxIntRect());
   6645  const nsSize frameSize =
   6646      nsSize(transformedBounds.width, transformedBounds.height);
   6647 
   6648  uint64_t maxLimitArea = uint64_t(maxSize.width) * maxSize.height;
   6649  uint64_t frameArea = uint64_t(frameSize.width) * frameSize.height;
   6650  if (frameArea <= maxLimitArea && frameSize <= absoluteLimit) {
   6651    *aDirtyRect = overflow;
   6652    result.mDecision = PrerenderDecision::Full;
   6653    return result;
   6654  }
   6655 
   6656  if (ShouldUsePartialPrerender(aFrame)) {
   6657    *aDirtyRect = nsLayoutUtils::ComputePartialPrerenderArea(
   6658        aFrame, untransformedDirtyRect, overflow, maxSize);
   6659    result.mDecision = PrerenderDecision::Partial;
   6660    return result;
   6661  }
   6662 
   6663  if (frameArea > maxLimitArea) {
   6664    uint64_t appUnitsPerPixel = AppUnitsPerCSSPixel();
   6665    EffectCompositor::SetPerformanceWarning(
   6666        aFrame, transformSet,
   6667        AnimationPerformanceWarning(
   6668            AnimationPerformanceWarning::Type::ContentTooLargeArea,
   6669            {
   6670                int(frameArea / (appUnitsPerPixel * appUnitsPerPixel)),
   6671                int(maxLimitArea / (appUnitsPerPixel * appUnitsPerPixel)),
   6672            }));
   6673  } else {
   6674    EffectCompositor::SetPerformanceWarning(
   6675        aFrame, transformSet,
   6676        AnimationPerformanceWarning(
   6677            AnimationPerformanceWarning::Type::ContentTooLarge,
   6678            {
   6679                nsPresContext::AppUnitsToIntCSSPixels(frameSize.width),
   6680                nsPresContext::AppUnitsToIntCSSPixels(frameSize.height),
   6681                nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.width),
   6682                nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.height),
   6683                nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.width),
   6684                nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.height),
   6685            }));
   6686  }
   6687 
   6688  return result;
   6689 }
   6690 
   6691 /* If the matrix is singular, or a hidden backface is shown, the frame won't be
   6692 * visible or hit. */
   6693 static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix) {
   6694  if (aMatrix.IsSingular()) {
   6695    return false;
   6696  }
   6697  if (aFrame->BackfaceIsHidden() && aMatrix.IsBackfaceVisible()) {
   6698    return false;
   6699  }
   6700  return true;
   6701 }
   6702 
   6703 const Matrix4x4Flagged& nsDisplayTransform::GetTransform() const {
   6704  if (mTransform) {
   6705    return *mTransform;
   6706  }
   6707 
   6708  float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
   6709 
   6710  if (mHasTransformGetter) {
   6711    mTransform.emplace((mFrame->GetTransformGetter())(mFrame, scale));
   6712    Point3D newOrigin =
   6713        Point3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale),
   6714                NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale), 0.0f);
   6715    mTransform->ChangeBasis(newOrigin.x, newOrigin.y, newOrigin.z);
   6716  } else if (!mIsTransformSeparator) {
   6717    DebugOnly<bool> isReference = mFrame->IsTransformed() ||
   6718                                  mFrame->Combines3DTransformWithAncestors() ||
   6719                                  mFrame->Extend3DContext();
   6720    MOZ_ASSERT(isReference);
   6721    mTransform.emplace(
   6722        GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale,
   6723                                    INCLUDE_PERSPECTIVE | OFFSET_BY_ORIGIN));
   6724  } else {
   6725    // Use identity matrix
   6726    mTransform.emplace();
   6727  }
   6728 
   6729  return *mTransform;
   6730 }
   6731 
   6732 const Matrix4x4Flagged& nsDisplayTransform::GetInverseTransform() const {
   6733  if (mInverseTransform) {
   6734    return *mInverseTransform;
   6735  }
   6736 
   6737  MOZ_ASSERT(!GetTransform().IsSingular());
   6738 
   6739  mInverseTransform.emplace(GetTransform().Inverse());
   6740 
   6741  return *mInverseTransform;
   6742 }
   6743 
   6744 Matrix4x4 nsDisplayTransform::GetTransformForRendering(
   6745    LayoutDevicePoint* aOutOrigin) const {
   6746  if (!mFrame->HasPerspective() || mHasTransformGetter ||
   6747      mIsTransformSeparator) {
   6748    if (!mHasTransformGetter && !mIsTransformSeparator && aOutOrigin) {
   6749      // If aOutOrigin is provided, put the offset to origin into it, because
   6750      // we need to keep it separate for webrender. The combination of
   6751      // *aOutOrigin and the returned matrix here should always be equivalent
   6752      // to what GetTransform() would have returned.
   6753      float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
   6754      *aOutOrigin = LayoutDevicePoint::FromAppUnits(ToReferenceFrame(), scale);
   6755 
   6756      // The rounding behavior should also be the same as GetTransform().
   6757      if (nsLayoutUtils::ShouldSnapToGrid(mFrame)) {
   6758        aOutOrigin->Round();
   6759      }
   6760      return GetResultingTransformMatrix(mFrame, nsPoint(0, 0), scale,
   6761                                         INCLUDE_PERSPECTIVE);
   6762    }
   6763    return GetTransform().GetMatrix();
   6764  }
   6765  MOZ_ASSERT(!mHasTransformGetter);
   6766 
   6767  float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
   6768  // Don't include perspective transform, or the offset to origin, since
   6769  // nsDisplayPerspective will handle both of those.
   6770  return GetResultingTransformMatrix(mFrame, nsPoint(), scale, 0);
   6771 }
   6772 
   6773 const Matrix4x4& nsDisplayTransform::GetAccumulatedPreserved3DTransform(
   6774    nsDisplayListBuilder* aBuilder) {
   6775  MOZ_ASSERT(!mFrame->Extend3DContext() || IsLeafOf3DContext());
   6776 
   6777  if (!IsLeafOf3DContext()) {
   6778    return GetTransform().GetMatrix();
   6779  }
   6780 
   6781  if (!mTransformPreserves3D) {
   6782    const nsIFrame* establisher;  // Establisher of the 3D rendering context.
   6783    for (establisher = mFrame;
   6784         establisher && establisher->Combines3DTransformWithAncestors();
   6785         establisher =
   6786             establisher->GetClosestFlattenedTreeAncestorPrimaryFrame()) {
   6787    }
   6788    const nsIFrame* establisherReference = aBuilder->FindReferenceFrameFor(
   6789        nsLayoutUtils::GetCrossDocParentFrameInProcess(establisher));
   6790 
   6791    nsPoint offset = establisher->GetOffsetToCrossDoc(establisherReference);
   6792    float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
   6793    uint32_t flags =
   6794        INCLUDE_PRESERVE3D_ANCESTORS | INCLUDE_PERSPECTIVE | OFFSET_BY_ORIGIN;
   6795    mTransformPreserves3D = MakeUnique<Matrix4x4>(
   6796        GetResultingTransformMatrix(mFrame, offset, scale, flags));
   6797  }
   6798 
   6799  return *mTransformPreserves3D;
   6800 }
   6801 
   6802 bool nsDisplayTransform::CreateWebRenderCommands(
   6803    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   6804    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   6805    nsDisplayListBuilder* aDisplayListBuilder) {
   6806  // We want to make sure we don't pollute the transform property in the WR
   6807  // stacking context by including the position of this frame (relative to the
   6808  // parent reference frame). We need to keep those separate; the position of
   6809  // this frame goes into the stacking context bounds while the transform goes
   6810  // into the transform.
   6811  LayoutDevicePoint position;
   6812  Matrix4x4 newTransformMatrix = GetTransformForRendering(&position);
   6813 
   6814  gfx::Matrix4x4* transformForSC = &newTransformMatrix;
   6815  if (newTransformMatrix.IsIdentity()) {
   6816    // If the transform is an identity transform, strip it out so that WR
   6817    // doesn't turn this stacking context into a reference frame, as it
   6818    // affects positioning.
   6819    transformForSC = nullptr;
   6820 
   6821    // In ChooseScaleAndSetTransform, we round the offset from the reference
   6822    // frame used to adjust the transform, if there is no transform, or it
   6823    // is just a translation. We need to do the same here.
   6824    if (nsLayoutUtils::ShouldSnapToGrid(mFrame)) {
   6825      position.Round();
   6826    }
   6827  }
   6828 
   6829  auto key = wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
   6830                            wr::SpatialKeyKind::Transform);
   6831 
   6832  // We don't send animations for transform separator display items.
   6833  uint64_t animationsId =
   6834      mIsTransformSeparator
   6835          ? 0
   6836          : AddAnimationsForWebRender(
   6837                this, aManager, aDisplayListBuilder,
   6838                IsPartialPrerender() ? Some(position) : Nothing());
   6839  wr::WrAnimationProperty prop{wr::WrAnimationType::Transform, animationsId,
   6840                               key};
   6841 
   6842  nsDisplayTransform* deferredTransformItem = nullptr;
   6843  if (ShouldDeferTransform()) {
   6844    // If it has perspective, we create a new scroll data via the
   6845    // UpdateScrollData call because that scenario is more complex. Otherwise,
   6846    // if we don't contain any ASRs then just stash the transform on the
   6847    // StackingContextHelper and apply it to any scroll data that are created
   6848    // inside this nsDisplayTransform.
   6849    deferredTransformItem = this;
   6850  }
   6851 
   6852  // Determine if we're possibly animated (= would need an active layer in FLB).
   6853  bool animated = !mIsTransformSeparator &&
   6854                  ActiveLayerTracker::IsTransformMaybeAnimated(Frame());
   6855 
   6856  wr::StackingContextParams params;
   6857  params.mBoundTransform = &newTransformMatrix;
   6858  params.animation = animationsId ? &prop : nullptr;
   6859 
   6860  if (mWrapsBackdropFilter) {
   6861    params.flags |= wr::StackingContextFlags::WRAPS_BACKDROP_FILTER;
   6862  }
   6863  if (mForceIsolation) {
   6864    params.flags |= wr::StackingContextFlags::FORCED_ISOLATION;
   6865  }
   6866 
   6867  wr::WrTransformInfo transform_info;
   6868  if (transformForSC) {
   6869    transform_info.transform = wr::ToLayoutTransform(newTransformMatrix);
   6870    transform_info.key = key;
   6871    params.mTransformPtr = &transform_info;
   6872  } else {
   6873    params.mTransformPtr = nullptr;
   6874  }
   6875 
   6876  params.prim_flags = !BackfaceIsHidden()
   6877                          ? wr::PrimitiveFlags::IS_BACKFACE_VISIBLE
   6878                          : wr::PrimitiveFlags{0};
   6879  params.paired_with_perspective = mHasAssociatedPerspective;
   6880  params.mDeferredTransformItem = deferredTransformItem;
   6881  params.mAnimated = animated;
   6882  // Determine if we would have to rasterize any items in local raster space
   6883  // (i.e. disable subpixel AA). We don't always need to rasterize locally even
   6884  // if the stacking context is possibly animated (at the cost of potentially
   6885  // some false negatives with respect to will-change handling), so we pass in
   6886  // this determination separately to accurately match with when FLB would
   6887  // normally disable subpixel AA.
   6888  params.mRasterizeLocally = animated && Frame()->HasAnimationOfTransform();
   6889  params.SetPreserve3D(mFrame->Extend3DContext() && !mIsTransformSeparator);
   6890  params.clip =
   6891      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   6892 
   6893  LayoutDeviceSize boundsSize = LayoutDeviceSize::FromAppUnits(
   6894      mChildBounds.Size(), mFrame->PresContext()->AppUnitsPerDevPixel());
   6895 
   6896  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   6897                           params, LayoutDeviceRect(position, boundsSize));
   6898 
   6899  aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
   6900      GetChildren(), this, aDisplayListBuilder, sc, aBuilder, aResources);
   6901  return true;
   6902 }
   6903 
   6904 bool nsDisplayTransform::UpdateScrollData(
   6905    WebRenderScrollData* aData, WebRenderLayerScrollData* aLayerData) {
   6906  if (ShouldDeferTransform()) {
   6907    // This case is handled in CreateWebRenderCommands by stashing the transform
   6908    // on the stacking context.
   6909    return false;
   6910  }
   6911  if (aLayerData) {
   6912    aLayerData->SetTransform(GetTransform().GetMatrix());
   6913    aLayerData->SetTransformIsPerspective(mFrame->ChildrenHavePerspective());
   6914  }
   6915  return true;
   6916 }
   6917 
   6918 bool nsDisplayTransform::ShouldSkipTransform(
   6919    nsDisplayListBuilder* aBuilder) const {
   6920  return (aBuilder->RootReferenceFrame() == mFrame) &&
   6921         aBuilder->IsForGenerateGlyphMask();
   6922 }
   6923 
   6924 void nsDisplayTransform::Collect3DTransformLeaves(
   6925    nsDisplayListBuilder* aBuilder, nsTArray<nsDisplayTransform*>& aLeaves) {
   6926  if (!IsParticipating3DContext() || IsLeafOf3DContext()) {
   6927    aLeaves.AppendElement(this);
   6928    return;
   6929  }
   6930 
   6931  FlattenedDisplayListIterator iter(aBuilder, &mChildren);
   6932  while (iter.HasNext()) {
   6933    nsDisplayItem* item = iter.GetNextItem();
   6934    if (item->GetType() == DisplayItemType::TYPE_PERSPECTIVE) {
   6935      auto* perspective = static_cast<nsDisplayPerspective*>(item);
   6936      if (!perspective->GetChildren()->GetTop()) {
   6937        continue;
   6938      }
   6939      item = perspective->GetChildren()->GetTop();
   6940    }
   6941    if (item->GetType() != DisplayItemType::TYPE_TRANSFORM) {
   6942      gfxCriticalError() << "Invalid child item within 3D transform of type: "
   6943                         << item->Name();
   6944      continue;
   6945    }
   6946    static_cast<nsDisplayTransform*>(item)->Collect3DTransformLeaves(aBuilder,
   6947                                                                     aLeaves);
   6948  }
   6949 }
   6950 
   6951 static RefPtr<gfx::Path> BuildPathFromPolygon(const RefPtr<DrawTarget>& aDT,
   6952                                              const gfx::Polygon& aPolygon) {
   6953  MOZ_ASSERT(!aPolygon.IsEmpty());
   6954 
   6955  RefPtr<PathBuilder> pathBuilder = aDT->CreatePathBuilder();
   6956  const nsTArray<Point4D>& points = aPolygon.GetPoints();
   6957 
   6958  pathBuilder->MoveTo(points[0].As2DPoint());
   6959 
   6960  for (size_t i = 1; i < points.Length(); ++i) {
   6961    pathBuilder->LineTo(points[i].As2DPoint());
   6962  }
   6963 
   6964  pathBuilder->Close();
   6965  return pathBuilder->Finish();
   6966 }
   6967 
   6968 void nsDisplayTransform::CollectSorted3DTransformLeaves(
   6969    nsDisplayListBuilder* aBuilder, nsTArray<TransformPolygon>& aLeaves) {
   6970  std::list<TransformPolygon> inputLayers;
   6971 
   6972  nsTArray<nsDisplayTransform*> leaves;
   6973  Collect3DTransformLeaves(aBuilder, leaves);
   6974  for (nsDisplayTransform* item : leaves) {
   6975    auto bounds = LayoutDeviceRect::FromAppUnits(
   6976        item->mChildBounds, item->mFrame->PresContext()->AppUnitsPerDevPixel());
   6977    Matrix4x4 transform = item->GetAccumulatedPreserved3DTransform(aBuilder);
   6978 
   6979    if (!IsFrameVisible(item->mFrame, transform)) {
   6980      continue;
   6981    }
   6982    gfx::Polygon polygon =
   6983        gfx::Polygon::FromRect(gfx::Rect(bounds.ToUnknownRect()));
   6984 
   6985    polygon.TransformToScreenSpace(transform);
   6986 
   6987    if (polygon.GetPoints().Length() >= 3) {
   6988      inputLayers.push_back(TransformPolygon(item, std::move(polygon)));
   6989    }
   6990  }
   6991 
   6992  if (inputLayers.empty()) {
   6993    return;
   6994  }
   6995 
   6996  BSPTree<nsDisplayTransform> tree(inputLayers);
   6997  nsTArray<TransformPolygon> orderedLayers(tree.GetDrawOrder());
   6998 
   6999  for (TransformPolygon& polygon : orderedLayers) {
   7000    Matrix4x4 inverse =
   7001        polygon.data->GetAccumulatedPreserved3DTransform(aBuilder).Inverse();
   7002 
   7003    MOZ_ASSERT(polygon.geometry);
   7004    polygon.geometry->TransformToLayerSpace(inverse);
   7005  }
   7006 
   7007  aLeaves = std::move(orderedLayers);
   7008 }
   7009 
   7010 void nsDisplayTransform::Paint(nsDisplayListBuilder* aBuilder,
   7011                               gfxContext* aCtx) {
   7012  Paint(aBuilder, aCtx, Nothing());
   7013 }
   7014 
   7015 void nsDisplayTransform::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
   7016                               const Maybe<gfx::Polygon>& aPolygon) {
   7017  if (IsParticipating3DContext() && !IsLeafOf3DContext()) {
   7018    MOZ_ASSERT(!aPolygon);
   7019    nsTArray<TransformPolygon> leaves;
   7020    CollectSorted3DTransformLeaves(aBuilder, leaves);
   7021    for (TransformPolygon& item : leaves) {
   7022      item.data->Paint(aBuilder, aCtx, item.geometry);
   7023    }
   7024    return;
   7025  }
   7026 
   7027  gfxContextMatrixAutoSaveRestore saveMatrix(aCtx);
   7028  Matrix4x4 trans = ShouldSkipTransform(aBuilder)
   7029                        ? Matrix4x4()
   7030                        : GetAccumulatedPreserved3DTransform(aBuilder);
   7031  if (!IsFrameVisible(mFrame, trans)) {
   7032    return;
   7033  }
   7034 
   7035  Matrix trans2d;
   7036  if (trans.CanDraw2D(&trans2d)) {
   7037    aCtx->Multiply(ThebesMatrix(trans2d));
   7038 
   7039    if (aPolygon) {
   7040      RefPtr<gfx::Path> path =
   7041          BuildPathFromPolygon(aCtx->GetDrawTarget(), *aPolygon);
   7042      aCtx->GetDrawTarget()->PushClip(path);
   7043    }
   7044 
   7045    GetChildren()->Paint(aBuilder, aCtx,
   7046                         mFrame->PresContext()->AppUnitsPerDevPixel());
   7047 
   7048    if (aPolygon) {
   7049      aCtx->GetDrawTarget()->PopClip();
   7050    }
   7051    return;
   7052  }
   7053 
   7054  // TODO: Implement 3d transform handling, including plane splitting and
   7055  // sorting. See BasicCompositor.
   7056  auto pixelBounds = LayoutDeviceRect::FromAppUnitsToOutside(
   7057      mChildBounds, mFrame->PresContext()->AppUnitsPerDevPixel());
   7058  RefPtr<DrawTarget> untransformedDT =
   7059      gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
   7060          IntSize(pixelBounds.Width(), pixelBounds.Height()),
   7061          SurfaceFormat::B8G8R8A8, true);
   7062  if (!untransformedDT || !untransformedDT->IsValid()) {
   7063    return;
   7064  }
   7065  untransformedDT->SetTransform(
   7066      Matrix::Translation(-Point(pixelBounds.X(), pixelBounds.Y())));
   7067 
   7068  gfxContext groupTarget(untransformedDT, /* aPreserveTransform */ true);
   7069 
   7070  if (aPolygon) {
   7071    RefPtr<gfx::Path> path =
   7072        BuildPathFromPolygon(aCtx->GetDrawTarget(), *aPolygon);
   7073    aCtx->GetDrawTarget()->PushClip(path);
   7074  }
   7075 
   7076  GetChildren()->Paint(aBuilder, &groupTarget,
   7077                       mFrame->PresContext()->AppUnitsPerDevPixel());
   7078 
   7079  if (aPolygon) {
   7080    aCtx->GetDrawTarget()->PopClip();
   7081  }
   7082 
   7083  RefPtr<SourceSurface> untransformedSurf = untransformedDT->Snapshot();
   7084 
   7085  trans.PreTranslate(pixelBounds.X(), pixelBounds.Y(), 0);
   7086  aCtx->GetDrawTarget()->Draw3DTransformedSurface(untransformedSurf, trans);
   7087 }
   7088 
   7089 bool nsDisplayTransform::MayBeAnimated(nsDisplayListBuilder* aBuilder) const {
   7090  // If EffectCompositor::HasAnimationsForCompositor() is true then we can
   7091  // completely bypass the main thread for this animation, so it is always
   7092  // worthwhile.
   7093  // For ActiveLayerTracker::IsTransformAnimated() cases the main thread is
   7094  // already involved so there is less to be gained.
   7095  // Therefore we check that the *post-transform* bounds of this item are
   7096  // big enough to justify an active layer.
   7097  return EffectCompositor::HasAnimationsForCompositor(
   7098             mFrame, DisplayItemType::TYPE_TRANSFORM) ||
   7099         (ActiveLayerTracker::IsTransformAnimated(aBuilder, mFrame));
   7100 }
   7101 
   7102 nsRect nsDisplayTransform::TransformUntransformedBounds(
   7103    nsDisplayListBuilder* aBuilder, const Matrix4x4Flagged& aMatrix) const {
   7104  const nsRect untransformedBounds = GetUntransformedBounds(aBuilder);
   7105  // GetTransform always operates in dev pixels.
   7106  const float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   7107  return nsLayoutUtils::MatrixTransformRect(untransformedBounds, aMatrix,
   7108                                            factor);
   7109 }
   7110 
   7111 /**
   7112 * Returns the bounds for this transform. The bounds are calculated during
   7113 * display list building and merging, see |nsDisplayTransform::UpdateBounds()|.
   7114 */
   7115 nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
   7116                                     bool* aSnap) const {
   7117  *aSnap = false;
   7118  return mBounds;
   7119 }
   7120 
   7121 void nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder) {
   7122  MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
   7123 
   7124  /* Some transforms can get empty bounds in 2D, but might get transformed again
   7125   * and get non-empty bounds. A simple example of this would be a 180 degree
   7126   * rotation getting applied twice.
   7127   * We should not depend on transforming bounds level by level.
   7128   *
   7129   * This function collects the bounds of this transform and stores it in
   7130   * nsDisplayListBuilder. If this is not a leaf of a 3D context, we recurse
   7131   * down and include the bounds of the child transforms.
   7132   * The bounds are transformed with the accumulated transformation matrix up to
   7133   * the 3D context root coordinate space.
   7134   */
   7135  nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
   7136  accTransform.Accumulate(GetTransform().GetMatrix());
   7137 
   7138  // Do not dive into another 3D context.
   7139  if (!IsLeafOf3DContext()) {
   7140    for (nsDisplayItem* i : *GetChildren()) {
   7141      i->DoUpdateBoundsPreserves3D(aBuilder);
   7142    }
   7143  }
   7144 
   7145  /* The child transforms that extend 3D context further will have empty bounds,
   7146   * so the untransformed bounds here is the bounds of all the non-preserve-3d
   7147   * content under this transform.
   7148   */
   7149  const nsRect rect = TransformUntransformedBounds(
   7150      aBuilder, accTransform.GetCurrentTransform());
   7151  aBuilder->AccumulateRect(rect);
   7152 }
   7153 
   7154 void nsDisplayTransform::DoUpdateBoundsPreserves3D(
   7155    nsDisplayListBuilder* aBuilder) {
   7156  MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
   7157             IsTransformSeparator());
   7158  // Updating is not going through to child 3D context.
   7159  ComputeBounds(aBuilder);
   7160 }
   7161 
   7162 void nsDisplayTransform::UpdateBounds(nsDisplayListBuilder* aBuilder) {
   7163  UpdateUntransformedBounds(aBuilder);
   7164 
   7165  if (IsTransformSeparator()) {
   7166    MOZ_ASSERT(GetTransform().IsIdentity());
   7167    mBounds = mChildBounds;
   7168    return;
   7169  }
   7170 
   7171  if (mFrame->Extend3DContext()) {
   7172    if (!Combines3DTransformWithAncestors()) {
   7173      // The transform establishes a 3D context. |UpdateBoundsFor3D()| will
   7174      // collect the bounds from the child transforms.
   7175      UpdateBoundsFor3D(aBuilder);
   7176    } else {
   7177      // With nested 3D transforms, the 2D bounds might not be useful.
   7178      mBounds = nsRect();
   7179    }
   7180 
   7181    return;
   7182  }
   7183 
   7184  MOZ_ASSERT(!mFrame->Extend3DContext());
   7185 
   7186  // We would like to avoid calculating 2D bounds here for nested 3D transforms,
   7187  // but mix-blend-mode relies on having bounds set. See bug 1556956.
   7188 
   7189  // A stand-alone transform.
   7190  mBounds = TransformUntransformedBounds(aBuilder, GetTransform());
   7191 }
   7192 
   7193 void nsDisplayTransform::UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder) {
   7194  MOZ_ASSERT(mFrame->Extend3DContext() &&
   7195             !mFrame->Combines3DTransformWithAncestors() &&
   7196             !IsTransformSeparator());
   7197 
   7198  // Always start updating from an establisher of a 3D rendering context.
   7199  nsDisplayListBuilder::AutoAccumulateRect accRect(aBuilder);
   7200  nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
   7201  accTransform.StartRoot();
   7202  ComputeBounds(aBuilder);
   7203  mBounds = aBuilder->GetAccumulatedRect();
   7204 }
   7205 
   7206 void nsDisplayTransform::UpdateUntransformedBounds(
   7207    nsDisplayListBuilder* aBuilder) {
   7208  mChildBounds = GetChildren()->GetClippedBoundsWithRespectToASR(
   7209      aBuilder, mActiveScrolledRoot);
   7210 }
   7211 
   7212 #ifdef DEBUG_HIT
   7213 #  include <time.h>
   7214 #endif
   7215 
   7216 /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
   7217 void nsDisplayTransform::HitTest(nsDisplayListBuilder* aBuilder,
   7218                                 const nsRect& aRect, HitTestState* aState,
   7219                                 nsTArray<nsIFrame*>* aOutFrames) {
   7220  if (aState->mGatheringPreserves3DLeaves) {
   7221    GetChildren()->HitTest(aBuilder, aRect, aState, aOutFrames);
   7222    return;
   7223  }
   7224 
   7225  /* Here's how this works:
   7226   * 1. Get the matrix.  If it's singular, abort (clearly we didn't hit
   7227   *    anything).
   7228   * 2. Invert the matrix.
   7229   * 3. Use it to transform the rect into the correct space.
   7230   * 4. Pass that rect down through to the list's version of HitTest.
   7231   */
   7232  // GetTransform always operates in dev pixels.
   7233  float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   7234  Matrix4x4 matrix = GetAccumulatedPreserved3DTransform(aBuilder);
   7235 
   7236  if (!IsFrameVisible(mFrame, matrix)) {
   7237    return;
   7238  }
   7239 
   7240  const bool oldHitOccludingItem = aState->mHitOccludingItem;
   7241 
   7242  /* We want to go from transformed-space to regular space.
   7243   * Thus we have to invert the matrix, which normally does
   7244   * the reverse operation (e.g. regular->transformed)
   7245   */
   7246 
   7247  /* Now, apply the transform and pass it down the channel. */
   7248  matrix.Invert();
   7249  nsRect resultingRect;
   7250  // Magic width/height indicating we're hit testing a point, not a rect
   7251  const bool testingPoint = aRect.width == 1 && aRect.height == 1;
   7252  if (testingPoint) {
   7253    Point4D point =
   7254        matrix.ProjectPoint(Point(NSAppUnitsToFloatPixels(aRect.x, factor),
   7255                                  NSAppUnitsToFloatPixels(aRect.y, factor)));
   7256    if (!point.HasPositiveWCoord()) {
   7257      return;
   7258    }
   7259 
   7260    Point point2d = point.As2DPoint();
   7261 
   7262    resultingRect =
   7263        nsRect(NSFloatPixelsToAppUnits(float(point2d.x), factor),
   7264               NSFloatPixelsToAppUnits(float(point2d.y), factor), 1, 1);
   7265 
   7266  } else {
   7267    Rect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
   7268                      NSAppUnitsToFloatPixels(aRect.y, factor),
   7269                      NSAppUnitsToFloatPixels(aRect.width, factor),
   7270                      NSAppUnitsToFloatPixels(aRect.height, factor));
   7271 
   7272    Rect childGfxBounds(NSAppUnitsToFloatPixels(mChildBounds.x, factor),
   7273                        NSAppUnitsToFloatPixels(mChildBounds.y, factor),
   7274                        NSAppUnitsToFloatPixels(mChildBounds.width, factor),
   7275                        NSAppUnitsToFloatPixels(mChildBounds.height, factor));
   7276 
   7277    Rect rect = matrix.ProjectRectBounds(originalRect, childGfxBounds);
   7278 
   7279    resultingRect =
   7280        nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
   7281               NSFloatPixelsToAppUnits(float(rect.Y()), factor),
   7282               NSFloatPixelsToAppUnits(float(rect.Width()), factor),
   7283               NSFloatPixelsToAppUnits(float(rect.Height()), factor));
   7284  }
   7285 
   7286  if (resultingRect.IsEmpty()) {
   7287    return;
   7288  }
   7289 
   7290 #ifdef DEBUG_HIT
   7291  printf("Frame: %p\n", dynamic_cast<void*>(mFrame));
   7292  printf("  Untransformed point: (%f, %f)\n", resultingRect.X(),
   7293         resultingRect.Y());
   7294  uint32_t originalFrameCount = aOutFrames.Length();
   7295 #endif
   7296 
   7297  const bool savedTransformHasBackfaceVisible =
   7298      aState->mTransformHasBackfaceVisible;
   7299  if (IsLeafOf3DContext()) {
   7300    aState->mTransformHasBackfaceVisible = matrix.IsBackfaceVisible();
   7301  }
   7302  GetChildren()->HitTest(aBuilder, resultingRect, aState, aOutFrames);
   7303  if (IsLeafOf3DContext()) {
   7304    aState->mTransformHasBackfaceVisible = savedTransformHasBackfaceVisible;
   7305  }
   7306 
   7307  if (aState->mHitOccludingItem && !testingPoint && !mBounds.Contains(aRect)) {
   7308    MOZ_ASSERT(aBuilder->HitTestIsForVisibility());
   7309    // We're hit-testing a rect that's bigger than our child bounds, but
   7310    // resultingRect is clipped by our bounds (in ProjectRectBounds above), so
   7311    // we can't stop hit-testing altogether.
   7312    //
   7313    // FIXME(emilio): I think this means that theoretically we might include
   7314    // some frames fully behind other transformed-but-opaque frames? Then again
   7315    // that's our pre-existing behavior for other untransformed content that
   7316    // doesn't fill the whole rect. To be fully correct I think we'd need proper
   7317    // "known occluded region" tracking, but that might be overkill for our
   7318    // purposes here.
   7319    aState->mHitOccludingItem = oldHitOccludingItem;
   7320  }
   7321 
   7322 #ifdef DEBUG_HIT
   7323  if (originalFrameCount != aOutFrames.Length())
   7324    printf("  Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
   7325           dynamic_cast<void*>(aOutFrames.ElementAt(0)));
   7326  printf("=== end of hit test ===\n");
   7327 #endif
   7328 }
   7329 
   7330 float nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder,
   7331                                             const nsPoint& aPoint) {
   7332  // GetTransform always operates in dev pixels.
   7333  float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   7334  Matrix4x4 matrix = GetAccumulatedPreserved3DTransform(aBuilder);
   7335 
   7336  NS_ASSERTION(IsFrameVisible(mFrame, matrix),
   7337               "We can't have hit a frame that isn't visible!");
   7338 
   7339  Matrix4x4 inverse = matrix;
   7340  inverse.Invert();
   7341 
   7342  // Compute the value z so that (aPoint.x, aPoint.y, z, 1) gets transformed by
   7343  // inverse to the z=0 plane. This is the same thing that
   7344  // Matrix4x4Typed::ProjectPoint does, but we are only interested in the z
   7345  // value, not the projected point, thus we extract the formula here, look
   7346  // there for how this equation is determined.
   7347  // https://searchfox.org/mozilla-central/rev/bd4d1cd1ca3037e6dc8d4081a4303824880b1b45/gfx/2d/Matrix.h#724
   7348  return -(NSAppUnitsToFloatPixels(aPoint.x, factor) * inverse._13 +
   7349           NSAppUnitsToFloatPixels(aPoint.y, factor) * inverse._23 +
   7350           inverse._43) /
   7351         inverse._33;
   7352 }
   7353 
   7354 /* The transform is opaque iff the transform consists solely of scales and
   7355 * translations and if the underlying content is opaque.  Thus if the transform
   7356 * is of the form
   7357 *
   7358 * |a c e|
   7359 * |b d f|
   7360 * |0 0 1|
   7361 *
   7362 * We need b and c to be zero.
   7363 *
   7364 * We also need to check whether the underlying opaque content completely fills
   7365 * our visible rect. We use UntransformRect which expands to the axis-aligned
   7366 * bounding rect, but that's OK since if
   7367 * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
   7368 * certainly contains the actual (non-axis-aligned) untransformed rect.
   7369 */
   7370 nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   7371                                             bool* aSnap) const {
   7372  *aSnap = false;
   7373 
   7374  nsRect untransformedVisible;
   7375  if (!UntransformBuildingRect(aBuilder, &untransformedVisible)) {
   7376    return nsRegion();
   7377  }
   7378 
   7379  const Matrix4x4Flagged& matrix = GetTransform();
   7380  Matrix matrix2d;
   7381  if (!matrix.Is2D(&matrix2d) || !matrix2d.PreservesAxisAlignedRectangles()) {
   7382    return nsRegion();
   7383  }
   7384 
   7385  nsRegion result;
   7386 
   7387  const nsRect bounds = GetUntransformedBounds(aBuilder);
   7388  const nsRegion opaque =
   7389      ::mozilla::GetOpaqueRegion(aBuilder, GetChildren(), bounds);
   7390 
   7391  if (opaque.Contains(untransformedVisible)) {
   7392    bool tmpSnap;
   7393    result = GetBuildingRect().Intersect(GetBounds(aBuilder, &tmpSnap));
   7394  }
   7395  return result;
   7396 }
   7397 
   7398 nsRect nsDisplayTransform::GetComponentAlphaBounds(
   7399    nsDisplayListBuilder* aBuilder) const {
   7400  if (GetChildren()->GetComponentAlphaBounds(aBuilder).IsEmpty()) {
   7401    return nsRect();
   7402  }
   7403 
   7404  bool snap;
   7405  return GetBounds(aBuilder, &snap);
   7406 }
   7407 
   7408 /* TransformRect takes in as parameters a rectangle (in app space) and returns
   7409 * the smallest rectangle (in app space) containing the transformed image of
   7410 * that rectangle.  That is, it takes the four corners of the rectangle,
   7411 * transforms them according to the matrix associated with the specified frame,
   7412 * then returns the smallest rectangle containing the four transformed points.
   7413 *
   7414 * @param aUntransformedBounds The rectangle (in app units) to transform.
   7415 * @param aFrame The frame whose transformation should be applied.
   7416 * @param aOrigin The delta from the frame origin to the coordinate space origin
   7417 * @return The smallest rectangle containing the image of the transformed
   7418 *         rectangle.
   7419 */
   7420 nsRect nsDisplayTransform::TransformRect(const nsRect& aUntransformedBounds,
   7421                                         const nsIFrame* aFrame,
   7422                                         TransformReferenceBox& aRefBox) {
   7423  MOZ_ASSERT(aFrame, "Can't take the transform based on a null frame!");
   7424 
   7425  float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
   7426 
   7427  FrameTransformProperties props(aFrame, aRefBox, factor);
   7428  return nsLayoutUtils::MatrixTransformRect(
   7429      aUntransformedBounds,
   7430      GetResultingTransformMatrixInternal(
   7431          props, aRefBox, nsPoint(), factor,
   7432          kTransformRectFlags & ~OFFSET_BY_ORIGIN),
   7433      factor);
   7434 }
   7435 
   7436 bool nsDisplayTransform::UntransformRect(const nsRect& aTransformedBounds,
   7437                                         const nsRect& aChildBounds,
   7438                                         const nsIFrame* aFrame,
   7439                                         nsRect* aOutRect) {
   7440  MOZ_ASSERT(aFrame, "Can't take the transform based on a null frame!");
   7441 
   7442  float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
   7443  Matrix4x4 transform = GetResultingTransformMatrix(
   7444      aFrame, nsPoint(), factor, kTransformRectFlags & ~OFFSET_BY_ORIGIN);
   7445  return UntransformRect(aTransformedBounds, aChildBounds, transform, factor,
   7446                         aOutRect);
   7447 }
   7448 
   7449 bool nsDisplayTransform::UntransformRect(const nsRect& aTransformedBounds,
   7450                                         const nsRect& aChildBounds,
   7451                                         const Matrix4x4& aMatrix,
   7452                                         float aAppUnitsPerPixel,
   7453                                         nsRect* aOutRect) {
   7454  Maybe<Matrix4x4> inverse = aMatrix.MaybeInverse();
   7455  if (inverse.isNothing()) {
   7456    return false;
   7457  }
   7458 
   7459  RectDouble result(
   7460      NSAppUnitsToFloatPixels(aTransformedBounds.x, aAppUnitsPerPixel),
   7461      NSAppUnitsToFloatPixels(aTransformedBounds.y, aAppUnitsPerPixel),
   7462      NSAppUnitsToFloatPixels(aTransformedBounds.width, aAppUnitsPerPixel),
   7463      NSAppUnitsToFloatPixels(aTransformedBounds.height, aAppUnitsPerPixel));
   7464 
   7465  RectDouble childGfxBounds(
   7466      NSAppUnitsToFloatPixels(aChildBounds.x, aAppUnitsPerPixel),
   7467      NSAppUnitsToFloatPixels(aChildBounds.y, aAppUnitsPerPixel),
   7468      NSAppUnitsToFloatPixels(aChildBounds.width, aAppUnitsPerPixel),
   7469      NSAppUnitsToFloatPixels(aChildBounds.height, aAppUnitsPerPixel));
   7470 
   7471  result = inverse->ProjectRectBounds(result, childGfxBounds);
   7472  *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, aAppUnitsPerPixel);
   7473  return true;
   7474 }
   7475 
   7476 bool nsDisplayTransform::UntransformRect(nsDisplayListBuilder* aBuilder,
   7477                                         const nsRect& aRect,
   7478                                         nsRect* aOutRect) const {
   7479  if (GetTransform().IsSingular()) {
   7480    return false;
   7481  }
   7482 
   7483  // GetTransform always operates in dev pixels.
   7484  float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   7485  RectDouble result(NSAppUnitsToFloatPixels(aRect.x, factor),
   7486                    NSAppUnitsToFloatPixels(aRect.y, factor),
   7487                    NSAppUnitsToFloatPixels(aRect.width, factor),
   7488                    NSAppUnitsToFloatPixels(aRect.height, factor));
   7489 
   7490  nsRect childBounds = GetUntransformedBounds(aBuilder);
   7491  RectDouble childGfxBounds(
   7492      NSAppUnitsToFloatPixels(childBounds.x, factor),
   7493      NSAppUnitsToFloatPixels(childBounds.y, factor),
   7494      NSAppUnitsToFloatPixels(childBounds.width, factor),
   7495      NSAppUnitsToFloatPixels(childBounds.height, factor));
   7496 
   7497  /* We want to untransform the matrix, so invert the transformation first! */
   7498  result = GetInverseTransform().ProjectRectBounds(result, childGfxBounds);
   7499 
   7500  *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor);
   7501 
   7502  return true;
   7503 }
   7504 
   7505 void nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream) {
   7506  aStream << GetTransform().GetMatrix();
   7507  if (IsTransformSeparator()) {
   7508    aStream << " transform-separator";
   7509  }
   7510  if (IsLeafOf3DContext()) {
   7511    aStream << " 3d-context-leaf";
   7512  }
   7513  if (mFrame->Extend3DContext()) {
   7514    aStream << " extends-3d-context";
   7515  }
   7516  if (mFrame->Combines3DTransformWithAncestors()) {
   7517    aStream << " combines-3d-with-ancestors";
   7518  }
   7519 
   7520  aStream << " prerender(";
   7521  switch (mPrerenderDecision) {
   7522    case PrerenderDecision::No:
   7523      aStream << "no";
   7524      break;
   7525    case PrerenderDecision::Partial:
   7526      aStream << "partial";
   7527      break;
   7528    case PrerenderDecision::Full:
   7529      aStream << "full";
   7530      break;
   7531  }
   7532  aStream << ")";
   7533  aStream << " childrenBuildingRect" << mChildrenBuildingRect;
   7534 }
   7535 
   7536 nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder,
   7537                                           nsIFrame* aFrame,
   7538                                           nsDisplayList* aList)
   7539    : nsPaintedDisplayItem(aBuilder, aFrame), mList(aBuilder) {
   7540  mList.AppendToTop(aList);
   7541  MOZ_ASSERT(mList.Length() == 1);
   7542  MOZ_ASSERT(mList.GetTop()->GetType() == DisplayItemType::TYPE_TRANSFORM);
   7543 }
   7544 
   7545 void nsDisplayPerspective::Paint(nsDisplayListBuilder* aBuilder,
   7546                                 gfxContext* aCtx) {
   7547  // Just directly recurse into children, since we'll include the persepctive
   7548  // value in any nsDisplayTransform children.
   7549  GetChildren()->Paint(aBuilder, aCtx,
   7550                       mFrame->PresContext()->AppUnitsPerDevPixel());
   7551 }
   7552 
   7553 nsRegion nsDisplayPerspective::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   7554                                               bool* aSnap) const {
   7555  if (!GetChildren()->GetTop()) {
   7556    *aSnap = false;
   7557    return nsRegion();
   7558  }
   7559 
   7560  return GetChildren()->GetTop()->GetOpaqueRegion(aBuilder, aSnap);
   7561 }
   7562 
   7563 bool nsDisplayPerspective::CreateWebRenderCommands(
   7564    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   7565    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   7566    nsDisplayListBuilder* aDisplayListBuilder) {
   7567  float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   7568  Matrix4x4 perspectiveMatrix;
   7569  DebugOnly<bool> hasPerspective = nsDisplayTransform::ComputePerspectiveMatrix(
   7570      mFrame, appUnitsPerPixel, perspectiveMatrix);
   7571  MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?");
   7572 
   7573  /*
   7574   * ClipListToRange can remove our child after we were created.
   7575   */
   7576  if (!GetChildren()->GetTop()) {
   7577    return false;
   7578  }
   7579 
   7580  /*
   7581   * The resulting matrix is still in the coordinate space of the transformed
   7582   * frame. Append a translation to the reference frame coordinates.
   7583   */
   7584  nsDisplayTransform* transform =
   7585      static_cast<nsDisplayTransform*>(GetChildren()->GetTop());
   7586 
   7587  Point3D newOrigin =
   7588      Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x,
   7589                                      appUnitsPerPixel),
   7590              NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y,
   7591                                      appUnitsPerPixel),
   7592              0.0f);
   7593  Point3D roundedOrigin(NS_round(newOrigin.x), NS_round(newOrigin.y), 0);
   7594 
   7595  perspectiveMatrix.PostTranslate(roundedOrigin);
   7596 
   7597  nsIFrame* perspectiveFrame =
   7598      mFrame->GetClosestFlattenedTreeAncestorPrimaryFrame();
   7599 
   7600  // Passing true here is always correct, since perspective always combines
   7601  // transforms with the descendants. However that'd make WR do a lot of work
   7602  // that it doesn't really need to do if there aren't other transforms forming
   7603  // part of the 3D context.
   7604  //
   7605  // WR knows how to treat perspective in that case, so the only thing we need
   7606  // to do is to ensure we pass true when we're involved in a 3d context in any
   7607  // other way via the transform-style property on either the transformed frame
   7608  // or the perspective frame in order to not confuse WR's preserve-3d code in
   7609  // very awful ways.
   7610  bool preserve3D =
   7611      mFrame->Extend3DContext() || perspectiveFrame->Extend3DContext();
   7612 
   7613  wr::StackingContextParams params;
   7614 
   7615  wr::WrTransformInfo transform_info;
   7616  transform_info.transform = wr::ToLayoutTransform(perspectiveMatrix);
   7617  transform_info.key = wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
   7618                                      wr::SpatialKeyKind::Perspective);
   7619  params.mTransformPtr = &transform_info;
   7620 
   7621  params.reference_frame_kind = wr::WrReferenceFrameKind::Perspective;
   7622  params.prim_flags = !BackfaceIsHidden()
   7623                          ? wr::PrimitiveFlags::IS_BACKFACE_VISIBLE
   7624                          : wr::PrimitiveFlags{0};
   7625  params.SetPreserve3D(preserve3D);
   7626  params.clip =
   7627      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   7628 
   7629  Maybe<uint64_t> scrollingRelativeTo;
   7630  for (const auto* asr = GetActiveScrolledRoot(); asr; asr = asr->mParent) {
   7631    // In OOP documents, the root scrollable frame of the in-process root
   7632    // document is always active, so using IsAncestorFrameCrossDocInProcess
   7633    // should be fine here.
   7634    if (ScrollContainerFrame* scrollFrame = asr->ScrollFrameOrNull()) {
   7635      if (nsLayoutUtils::IsAncestorFrameCrossDocInProcess(
   7636              scrollFrame->GetScrolledFrame(), perspectiveFrame)) {
   7637        scrollingRelativeTo.emplace(asr->GetViewId());
   7638        break;
   7639      }
   7640    }
   7641  }
   7642 
   7643  // We put the perspective reference frame wrapping the transformed frame,
   7644  // even though there may be arbitrarily nested scroll frames in between.
   7645  //
   7646  // We need to know how many ancestor scroll-frames are we nested in, in order
   7647  // for the async scrolling code in WebRender to calculate the right
   7648  // transformation for the perspective contents.
   7649  params.scrolling_relative_to = scrollingRelativeTo.ptrOr(nullptr);
   7650 
   7651  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   7652                           params);
   7653 
   7654  aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
   7655      GetChildren(), this, aDisplayListBuilder, sc, aBuilder, aResources);
   7656 
   7657  return true;
   7658 }
   7659 
   7660 nsDisplayText::nsDisplayText(nsDisplayListBuilder* aBuilder,
   7661                             nsTextFrame* aFrame)
   7662    : nsPaintedDisplayItem(aBuilder, aFrame),
   7663      mVisIStartEdge(0),
   7664      mVisIEndEdge(0) {
   7665  MOZ_COUNT_CTOR(nsDisplayText);
   7666  mBounds = mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
   7667  // Bug 748228
   7668  mBounds.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
   7669  mVisibleRect = aBuilder->GetVisibleRect() +
   7670                 aBuilder->GetCurrentFrameOffsetToReferenceFrame();
   7671 }
   7672 
   7673 bool nsDisplayText::CanApplyOpacity(WebRenderLayerManager* aManager,
   7674                                    nsDisplayListBuilder* aBuilder) const {
   7675  auto* f = static_cast<nsTextFrame*>(mFrame);
   7676 
   7677  if (f->IsSelected()) {
   7678    return false;
   7679  }
   7680 
   7681  const nsStyleText* textStyle = f->StyleText();
   7682  if (textStyle->HasTextShadow()) {
   7683    return false;
   7684  }
   7685 
   7686  nsTextFrame::TextDecorations decorations;
   7687  f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors,
   7688                        decorations);
   7689  return !decorations.HasDecorationLines();
   7690 }
   7691 
   7692 void nsDisplayText::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   7693  AUTO_PROFILER_LABEL("nsDisplayText::Paint", GRAPHICS);
   7694  // We don't pass mVisibleRect here, since this can be called from within
   7695  // the WebRender fallback painting path, and we don't want to issue
   7696  // recorded commands that are dependent on the visible/building rect.
   7697  RenderToContext(aCtx, aBuilder, GetPaintRect(aBuilder, aCtx));
   7698 
   7699  auto* textFrame = static_cast<nsTextFrame*>(mFrame);
   7700  LCPTextFrameHelper::MaybeUnionTextFrame(textFrame,
   7701                                          mBounds - ToReferenceFrame());
   7702 }
   7703 
   7704 bool nsDisplayText::CreateWebRenderCommands(
   7705    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   7706    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   7707    nsDisplayListBuilder* aDisplayListBuilder) {
   7708  auto* f = static_cast<nsTextFrame*>(mFrame);
   7709  auto appUnitsPerDevPixel = f->PresContext()->AppUnitsPerDevPixel();
   7710 
   7711  nsRect bounds = f->WebRenderBounds() + ToReferenceFrame();
   7712  // Bug 748228
   7713  bounds.Inflate(appUnitsPerDevPixel);
   7714 
   7715  if (bounds.IsEmpty()) {
   7716    return true;
   7717  }
   7718 
   7719  // For large font sizes, punt to a blob image, to avoid the blurry rendering
   7720  // that results from WR clamping the glyph size used for rasterization.
   7721  //
   7722  // (See FONT_SIZE_LIMIT in webrender/src/glyph_rasterizer/mod.rs.)
   7723  //
   7724  // This is not strictly accurate, as final used font sizes might not be the
   7725  // same as claimed by the fontGroup's style.size (eg: due to font-size-adjust
   7726  // altering the used size of the font actually used).
   7727  // It also fails to consider how transforms might affect the device-font-size
   7728  // that webrender uses (and clamps).
   7729  // But it should be near enough for practical purposes; the limitations just
   7730  // mean we might sometimes end up with webrender still applying some bitmap
   7731  // scaling, or bail out when we didn't really need to.
   7732  constexpr float kWebRenderFontSizeLimit = 320.0;
   7733  f->EnsureTextRun(nsTextFrame::eInflated);
   7734  gfxTextRun* textRun = f->GetTextRun(nsTextFrame::eInflated);
   7735  if (textRun &&
   7736      textRun->GetFontGroup()->GetStyle()->size > kWebRenderFontSizeLimit) {
   7737    return false;
   7738  }
   7739 
   7740  gfx::Point deviceOffset =
   7741      LayoutDevicePoint::FromAppUnits(bounds.TopLeft(), appUnitsPerDevPixel)
   7742          .ToUnknownPoint();
   7743 
   7744  // Clipping the bounds to the PaintRect (factoring in what's covered by parent
   7745  // frames) lets us early reject a bunch of things.
   7746  nsRect visible = mVisibleRect;
   7747 
   7748  // Add the "source rect" area from which the given shadows could intersect
   7749  // with mVisibleRect, and which therefore needs to included in the paint
   7750  // operation, to the `visible` rect that we will use to limit the bounds of
   7751  // what we send to the renderer.
   7752  auto addShadowSourceToVisible = [&](Span<const StyleSimpleShadow> aShadows) {
   7753    for (const auto& shadow : aShadows) {
   7754      nsRect sourceRect = mVisibleRect;
   7755      // Negate the offsets, because we're looking for the "source" rect that
   7756      // could cast a shadow into the visible rect, rather than a "target" area
   7757      // onto which the visible rect would cast a shadow.
   7758      sourceRect.MoveBy(-shadow.horizontal.ToAppUnits(),
   7759                        -shadow.vertical.ToAppUnits());
   7760      // Inflate to account for the shadow blur.
   7761      sourceRect.Inflate(nsContextBoxBlur::GetBlurRadiusMargin(
   7762          shadow.blur.ToAppUnits(), appUnitsPerDevPixel));
   7763      visible.OrWith(sourceRect);
   7764    }
   7765  };
   7766 
   7767  // Shadows can translate things back into view, so we enlarge the notional
   7768  // "visible" rect to ensure we don't skip painting relevant parts that might
   7769  // cast a shadow within the visible area.
   7770  addShadowSourceToVisible(f->StyleText()->mTextShadow.AsSpan());
   7771 
   7772  // Similarly for shadows that may be cast by ::selection.
   7773  if (f->IsSelected()) {
   7774    nsTextPaintStyle textPaint(f);
   7775    Span<const StyleSimpleShadow> shadows;
   7776    f->GetSelectionTextShadow(SelectionType::eNormal, textPaint, &shadows);
   7777    addShadowSourceToVisible(shadows);
   7778  }
   7779 
   7780  // Inflate a little extra to allow for potential antialiasing "blur".
   7781  visible.Inflate(3 * appUnitsPerDevPixel);
   7782  bounds = bounds.Intersect(visible);
   7783 
   7784  gfxContext* textDrawer = aBuilder.GetTextContext(aResources, aSc, aManager,
   7785                                                   this, bounds, deviceOffset);
   7786 
   7787  LCPTextFrameHelper::MaybeUnionTextFrame(f, bounds - ToReferenceFrame());
   7788 
   7789  aBuilder.StartGroup(this);
   7790 
   7791  RenderToContext(textDrawer, aDisplayListBuilder, mVisibleRect,
   7792                  aBuilder.GetInheritedOpacity(), true);
   7793  const bool result = textDrawer->GetTextDrawer()->Finish();
   7794 
   7795  if (result) {
   7796    aBuilder.FinishGroup();
   7797  } else {
   7798    aBuilder.CancelGroup(true);
   7799  }
   7800 
   7801  return result;
   7802 }
   7803 
   7804 void nsDisplayText::RenderToContext(gfxContext* aCtx,
   7805                                    nsDisplayListBuilder* aBuilder,
   7806                                    const nsRect& aVisibleRect, float aOpacity,
   7807                                    bool aIsRecording) {
   7808  nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
   7809 
   7810  // Add 1 pixel of dirty area around mVisibleRect to allow us to paint
   7811  // antialiased pixels beyond the measured text extents.
   7812  // This is temporary until we do this in the actual calculation of text
   7813  // extents.
   7814  auto A2D = mFrame->PresContext()->AppUnitsPerDevPixel();
   7815  LayoutDeviceRect extraVisible =
   7816      LayoutDeviceRect::FromAppUnits(aVisibleRect, A2D);
   7817  extraVisible.Inflate(1);
   7818 
   7819  gfxRect pixelVisible(extraVisible.x, extraVisible.y, extraVisible.width,
   7820                       extraVisible.height);
   7821  pixelVisible.Inflate(2);
   7822  pixelVisible.RoundOut();
   7823 
   7824  gfxClipAutoSaveRestore autoSaveClip(aCtx);
   7825  if (!aBuilder->IsForGenerateGlyphMask() && !aIsRecording) {
   7826    autoSaveClip.Clip(pixelVisible);
   7827  }
   7828 
   7829  NS_ASSERTION(mVisIStartEdge >= 0, "illegal start edge");
   7830  NS_ASSERTION(mVisIEndEdge >= 0, "illegal end edge");
   7831 
   7832  gfxContextMatrixAutoSaveRestore matrixSR;
   7833 
   7834  nsPoint framePt = ToReferenceFrame();
   7835  if (f->Style()->IsTextCombined()) {
   7836    auto [offset, scale] = f->GetTextCombineOffsetAndScale();
   7837    gfxTextRun* textRun = f->GetTextRun(nsTextFrame::eInflated);
   7838    bool rtl = textRun && textRun->IsRightToLeft();
   7839    if (rtl) {
   7840      framePt.x -= offset;
   7841    } else {
   7842      framePt.x += offset;
   7843    }
   7844    if (scale != 1.0f) {
   7845      if (auto* textDrawer = aCtx->GetTextDrawer()) {
   7846        // WebRender doesn't support scaling text like this yet
   7847        textDrawer->FoundUnsupportedFeature();
   7848        return;
   7849      }
   7850      matrixSR.SetContext(aCtx);
   7851      // Setup matrix to compress text for text-combine-upright if
   7852      // necessary. This is done here because we want selection be
   7853      // compressed at the same time as text.
   7854      gfxPoint pt = nsLayoutUtils::PointToGfxPoint(framePt, A2D);
   7855      if (rtl) {
   7856        pt.x += gfxFloat(f->GetSize().width) / A2D;
   7857      }
   7858      gfxMatrix mat = aCtx->CurrentMatrixDouble()
   7859                          .PreTranslate(pt)
   7860                          .PreScale(scale, 1.0)
   7861                          .PreTranslate(-pt);
   7862      aCtx->SetMatrixDouble(mat);
   7863    }
   7864  }
   7865  nsTextFrame::PaintTextParams params(aCtx);
   7866  params.framePt = gfx::Point(framePt.x, framePt.y);
   7867  params.dirtyRect = extraVisible;
   7868 
   7869  if (aBuilder->IsForGenerateGlyphMask()) {
   7870    params.state = nsTextFrame::PaintTextParams::GenerateTextMask;
   7871  } else {
   7872    params.state = nsTextFrame::PaintTextParams::PaintText;
   7873  }
   7874 
   7875  f->PaintText(params, mVisIStartEdge, mVisIEndEdge, ToReferenceFrame(),
   7876               f->IsSelected(), aOpacity);
   7877 }
   7878 
   7879 // This could go to nsDisplayListInvalidation.h, but
   7880 // |nsTextFrame::TextDecorations| requires including of nsTextFrame.h which
   7881 // would produce circular dependencies.
   7882 class nsDisplayTextGeometry : public nsDisplayItemGenericGeometry {
   7883 public:
   7884  nsDisplayTextGeometry(nsDisplayText* aItem, nsDisplayListBuilder* aBuilder)
   7885      : nsDisplayItemGenericGeometry(aItem, aBuilder),
   7886        mVisIStartEdge(aItem->VisIStartEdge()),
   7887        mVisIEndEdge(aItem->VisIEndEdge()) {
   7888    nsTextFrame* f = static_cast<nsTextFrame*>(aItem->Frame());
   7889    f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors,
   7890                          mDecorations);
   7891  }
   7892 
   7893  /**
   7894   * We store the computed text decorations here since they are
   7895   * computed using style data from parent frames. Any changes to these
   7896   * styles will only invalidate the parent frame and not this frame.
   7897   */
   7898  nsTextFrame::TextDecorations mDecorations;
   7899  nscoord mVisIStartEdge;
   7900  nscoord mVisIEndEdge;
   7901 };
   7902 
   7903 nsDisplayItemGeometry* nsDisplayText::AllocateGeometry(
   7904    nsDisplayListBuilder* aBuilder) {
   7905  return new nsDisplayTextGeometry(this, aBuilder);
   7906 }
   7907 
   7908 void nsDisplayText::ComputeInvalidationRegion(
   7909    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   7910    nsRegion* aInvalidRegion) const {
   7911  const nsDisplayTextGeometry* geometry =
   7912      static_cast<const nsDisplayTextGeometry*>(aGeometry);
   7913  nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
   7914 
   7915  nsTextFrame::TextDecorations decorations;
   7916  f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors,
   7917                        decorations);
   7918 
   7919  bool snap;
   7920  const nsRect& newRect = geometry->mBounds;
   7921  nsRect oldRect = GetBounds(aBuilder, &snap);
   7922  if (decorations != geometry->mDecorations ||
   7923      mVisIStartEdge != geometry->mVisIStartEdge ||
   7924      mVisIEndEdge != geometry->mVisIEndEdge ||
   7925      !oldRect.IsEqualInterior(newRect) ||
   7926      !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
   7927    aInvalidRegion->Or(oldRect, newRect);
   7928  }
   7929 }
   7930 
   7931 void nsDisplayText::WriteDebugInfo(std::stringstream& aStream) {
   7932 #ifdef DEBUG
   7933  aStream << " (\"";
   7934 
   7935  nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
   7936  nsCString buf;
   7937  f->ToCString(buf);
   7938 
   7939  aStream << buf.get() << "\")";
   7940 #endif
   7941 }
   7942 
   7943 nsDisplayEffectsBase::nsDisplayEffectsBase(
   7944    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   7945    const ActiveScrolledRoot* aActiveScrolledRoot,
   7946    ContainerASRType aContainerASRType, bool aClearClipChain)
   7947    : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
   7948                        aContainerASRType, aClearClipChain) {
   7949  MOZ_COUNT_CTOR(nsDisplayEffectsBase);
   7950 }
   7951 
   7952 nsDisplayEffectsBase::nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
   7953                                           nsIFrame* aFrame,
   7954                                           nsDisplayList* aList)
   7955    : nsDisplayWrapList(aBuilder, aFrame, aList) {
   7956  MOZ_COUNT_CTOR(nsDisplayEffectsBase);
   7957 }
   7958 
   7959 nsRegion nsDisplayEffectsBase::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
   7960                                               bool* aSnap) const {
   7961  *aSnap = false;
   7962  return nsRegion();
   7963 }
   7964 
   7965 void nsDisplayEffectsBase::HitTest(nsDisplayListBuilder* aBuilder,
   7966                                   const nsRect& aRect, HitTestState* aState,
   7967                                   nsTArray<nsIFrame*>* aOutFrames) {
   7968  nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
   7969  if (SVGIntegrationUtils::HitTestFrameForEffects(
   7970          mFrame, rectCenter - ToReferenceFrame())) {
   7971    mList.HitTest(aBuilder, aRect, aState, aOutFrames);
   7972  }
   7973 }
   7974 
   7975 gfxRect nsDisplayEffectsBase::BBoxInUserSpace() const {
   7976  return SVGUtils::GetBBox(mFrame);
   7977 }
   7978 
   7979 gfxPoint nsDisplayEffectsBase::UserSpaceOffset() const {
   7980  return SVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame);
   7981 }
   7982 
   7983 void nsDisplayEffectsBase::ComputeInvalidationRegion(
   7984    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   7985    nsRegion* aInvalidRegion) const {
   7986  const auto* geometry =
   7987      static_cast<const nsDisplaySVGEffectGeometry*>(aGeometry);
   7988  bool snap;
   7989  nsRect bounds = GetBounds(aBuilder, &snap);
   7990  if (geometry->mFrameOffsetToReferenceFrame != ToReferenceFrame() ||
   7991      geometry->mUserSpaceOffset != UserSpaceOffset() ||
   7992      !geometry->mBBox.IsEqualInterior(BBoxInUserSpace())) {
   7993    // Filter and mask output can depend on the location of the frame's user
   7994    // space and on the frame's BBox. We need to invalidate if either of these
   7995    // change relative to the reference frame.
   7996    // Invalidations from our inactive layer manager are not enough to catch
   7997    // some of these cases because filters can produce output even if there's
   7998    // nothing in the filter input.
   7999    aInvalidRegion->Or(bounds, geometry->mBounds);
   8000  }
   8001 }
   8002 
   8003 bool nsDisplayEffectsBase::ValidateSVGFrame() {
   8004  if (mFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
   8005    ISVGDisplayableFrame* svgFrame = do_QueryFrame(mFrame);
   8006    if (!svgFrame) {
   8007      return false;
   8008    }
   8009    if (auto* svgElement = SVGElement::FromNode(mFrame->GetContent())) {
   8010      // The SVG spec says only to draw filters if the element
   8011      // has valid dimensions.
   8012      return svgElement->HasValidDimensions();
   8013    }
   8014    return false;
   8015  }
   8016 
   8017  return true;
   8018 }
   8019 
   8020 using PaintFramesParams = SVGIntegrationUtils::PaintFramesParams;
   8021 
   8022 static void ComputeMaskGeometry(PaintFramesParams& aParams) {
   8023  // Properties are added lazily and may have been removed by a restyle, so
   8024  // make sure all applicable ones are set again.
   8025  nsIFrame* firstFrame =
   8026      nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParams.frame);
   8027 
   8028  const nsStyleSVGReset* svgReset = firstFrame->StyleSVGReset();
   8029 
   8030  nsTArray<SVGMaskFrame*> maskFrames;
   8031  // XXX check return value?
   8032  SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
   8033 
   8034  if (maskFrames.Length() == 0) {
   8035    return;
   8036  }
   8037 
   8038  gfxContext& ctx = aParams.ctx;
   8039  nsIFrame* frame = aParams.frame;
   8040 
   8041  nsPoint offsetToUserSpace =
   8042      nsLayoutUtils::ComputeOffsetToUserSpace(aParams.builder, aParams.frame);
   8043 
   8044  auto cssToDevScale = frame->PresContext()->CSSToDevPixelScale();
   8045  int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
   8046 
   8047  gfxPoint devPixelOffsetToUserSpace =
   8048      nsLayoutUtils::PointToGfxPoint(offsetToUserSpace, appUnitsPerDevPixel);
   8049 
   8050  gfxContextMatrixAutoSaveRestore matSR(&ctx);
   8051  ctx.SetMatrixDouble(
   8052      ctx.CurrentMatrixDouble().PreTranslate(devPixelOffsetToUserSpace));
   8053 
   8054  // Convert boaderArea and dirtyRect to user space.
   8055  nsRect userSpaceBorderArea = aParams.borderArea - offsetToUserSpace;
   8056  nsRect userSpaceDirtyRect = aParams.dirtyRect - offsetToUserSpace;
   8057 
   8058  // Union all mask layer rectangles in user space.
   8059  LayoutDeviceRect maskInUserSpace;
   8060  for (size_t i = 0; i < maskFrames.Length(); i++) {
   8061    SVGMaskFrame* maskFrame = maskFrames[i];
   8062    LayoutDeviceRect currentMaskSurfaceRect;
   8063 
   8064    if (maskFrame) {
   8065      auto rect = maskFrame->GetMaskArea(aParams.frame);
   8066      currentMaskSurfaceRect =
   8067          CSSRect::FromUnknownRect(ToRect(rect)) * cssToDevScale;
   8068    } else {
   8069      nsCSSRendering::ImageLayerClipState clipState;
   8070      nsCSSRendering::GetImageLayerClip(
   8071          svgReset->mMask.mLayers[i], frame, *frame->StyleBorder(),
   8072          userSpaceBorderArea, userSpaceDirtyRect,
   8073          /* aWillPaintBorder = */ false, appUnitsPerDevPixel, &clipState);
   8074      currentMaskSurfaceRect = LayoutDeviceRect::FromUnknownRect(
   8075          ToRect(clipState.mDirtyRectInDevPx));
   8076    }
   8077 
   8078    maskInUserSpace = maskInUserSpace.Union(currentMaskSurfaceRect);
   8079  }
   8080 
   8081  if (!maskInUserSpace.IsEmpty()) {
   8082    aParams.maskRect = Some(maskInUserSpace);
   8083  } else {
   8084    aParams.maskRect = Nothing();
   8085  }
   8086 }
   8087 
   8088 nsDisplayMasksAndClipPaths::nsDisplayMasksAndClipPaths(
   8089    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
   8090    const ActiveScrolledRoot* aActiveScrolledRoot,
   8091    ContainerASRType aContainerASRType, bool aWrapsBackdropFilter,
   8092    bool aForceIsolation)
   8093    : nsDisplayEffectsBase(aBuilder, aFrame, aList, aActiveScrolledRoot,
   8094                           aContainerASRType, /* aClearClipChain = */ true),
   8095      mWrapsBackdropFilter(aWrapsBackdropFilter),
   8096      mForceIsolation(aForceIsolation) {
   8097  MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
   8098 
   8099  nsPresContext* presContext = mFrame->PresContext();
   8100  uint32_t flags =
   8101      aBuilder->GetBackgroundPaintFlags() | nsCSSRendering::PAINTBG_MASK_IMAGE;
   8102  const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
   8103  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
   8104    const auto& layer = svgReset->mMask.mLayers[i];
   8105    if (!layer.mImage.IsResolved()) {
   8106      continue;
   8107    }
   8108    const nsRect& borderArea = mFrame->GetRectRelativeToSelf();
   8109    // NOTE(emilio): We only care about the dest rect so we don't bother
   8110    // computing a clip.
   8111    bool isTransformedFixed = false;
   8112    nsBackgroundLayerState state = nsCSSRendering::PrepareImageLayer(
   8113        presContext, aFrame, flags, borderArea, borderArea, layer,
   8114        &isTransformedFixed);
   8115    mDestRects.AppendElement(state.mDestArea);
   8116  }
   8117 }
   8118 
   8119 static bool CanMergeDisplayMaskFrame(nsIFrame* aFrame) {
   8120  // Do not merge items for box-decoration-break:clone elements,
   8121  // since each box should have its own mask in that case.
   8122  if (aFrame->StyleBorder()->mBoxDecorationBreak ==
   8123      StyleBoxDecorationBreak::Clone) {
   8124    return false;
   8125  }
   8126 
   8127  // Do not merge if either frame has a mask. Continuation frames should apply
   8128  // the mask independently (just like nsDisplayBackgroundImage).
   8129  if (aFrame->StyleSVGReset()->HasMask()) {
   8130    return false;
   8131  }
   8132 
   8133  return true;
   8134 }
   8135 
   8136 bool nsDisplayMasksAndClipPaths::CanMerge(const nsDisplayItem* aItem) const {
   8137  // Items for the same content element should be merged into a single
   8138  // compositing group.
   8139  if (!HasDifferentFrame(aItem) || !HasSameTypeAndClip(aItem) ||
   8140      !HasSameContent(aItem)) {
   8141    return false;
   8142  }
   8143 
   8144  return CanMergeDisplayMaskFrame(mFrame) &&
   8145         CanMergeDisplayMaskFrame(aItem->Frame());
   8146 }
   8147 
   8148 bool nsDisplayMasksAndClipPaths::IsValidMask() {
   8149  if (!ValidateSVGFrame()) {
   8150    return false;
   8151  }
   8152 
   8153  return SVGUtils::DetermineMaskUsage(mFrame, false).UsingMaskOrClipPath();
   8154 }
   8155 
   8156 bool nsDisplayMasksAndClipPaths::PaintMask(nsDisplayListBuilder* aBuilder,
   8157                                           gfxContext* aMaskContext,
   8158                                           bool aHandleOpacity,
   8159                                           bool* aMaskPainted) {
   8160  MOZ_ASSERT(aMaskContext->GetDrawTarget()->GetFormat() == SurfaceFormat::A8);
   8161 
   8162  imgDrawingParams imgParams(aBuilder->GetImageDecodeFlags());
   8163  nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   8164  PaintFramesParams params(*aMaskContext, mFrame, mBounds, borderArea, aBuilder,
   8165                           aHandleOpacity, imgParams);
   8166  ComputeMaskGeometry(params);
   8167  bool maskIsComplete = false;
   8168  bool painted = SVGIntegrationUtils::PaintMask(params, maskIsComplete);
   8169  if (aMaskPainted) {
   8170    *aMaskPainted = painted;
   8171  }
   8172 
   8173  return maskIsComplete &&
   8174         (imgParams.result == ImgDrawResult::SUCCESS ||
   8175          imgParams.result == ImgDrawResult::SUCCESS_NOT_COMPLETE ||
   8176          imgParams.result == ImgDrawResult::WRONG_SIZE);
   8177 }
   8178 
   8179 void nsDisplayMasksAndClipPaths::ComputeInvalidationRegion(
   8180    nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
   8181    nsRegion* aInvalidRegion) const {
   8182  nsDisplayEffectsBase::ComputeInvalidationRegion(aBuilder, aGeometry,
   8183                                                  aInvalidRegion);
   8184 
   8185  const auto* geometry =
   8186      static_cast<const nsDisplayMasksAndClipPathsGeometry*>(aGeometry);
   8187  bool snap;
   8188  nsRect bounds = GetBounds(aBuilder, &snap);
   8189 
   8190  if (mDestRects.Length() != geometry->mDestRects.Length()) {
   8191    aInvalidRegion->Or(bounds, geometry->mBounds);
   8192  } else {
   8193    for (size_t i = 0; i < mDestRects.Length(); i++) {
   8194      if (!mDestRects[i].IsEqualInterior(geometry->mDestRects[i])) {
   8195        aInvalidRegion->Or(bounds, geometry->mBounds);
   8196        break;
   8197      }
   8198    }
   8199  }
   8200 }
   8201 
   8202 void nsDisplayMasksAndClipPaths::PaintWithContentsPaintCallback(
   8203    nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
   8204    const std::function<void()>& aPaintChildren) {
   8205  // Clip the drawing target by mVisibleRect, which contains the visible
   8206  // region of the target frame and its out-of-flow and inflow descendants.
   8207  Rect bounds = NSRectToRect(GetPaintRect(aBuilder, aCtx),
   8208                             mFrame->PresContext()->AppUnitsPerDevPixel());
   8209  bounds.RoundOut();
   8210  gfxClipAutoSaveRestore autoSaveClip(aCtx);
   8211  autoSaveClip.Clip(bounds);
   8212 
   8213  imgDrawingParams imgParams(aBuilder->GetImageDecodeFlags());
   8214  nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   8215  PaintFramesParams params(*aCtx, mFrame, GetPaintRect(aBuilder, aCtx),
   8216                           borderArea, aBuilder, false, imgParams);
   8217 
   8218  ComputeMaskGeometry(params);
   8219 
   8220  SVGIntegrationUtils::PaintMaskAndClipPath(params, aPaintChildren);
   8221 }
   8222 
   8223 void nsDisplayMasksAndClipPaths::Paint(nsDisplayListBuilder* aBuilder,
   8224                                       gfxContext* aCtx) {
   8225  if (!IsValidMask()) {
   8226    return;
   8227  }
   8228  PaintWithContentsPaintCallback(aBuilder, aCtx, [&] {
   8229    GetChildren()->Paint(aBuilder, aCtx,
   8230                         mFrame->PresContext()->AppUnitsPerDevPixel());
   8231  });
   8232 }
   8233 
   8234 static Maybe<wr::WrClipChainId> CreateSimpleClipRegion(
   8235    const nsDisplayMasksAndClipPaths& aDisplayItem,
   8236    wr::DisplayListBuilder& aBuilder) {
   8237  nsIFrame* frame = aDisplayItem.Frame();
   8238  const auto* style = frame->StyleSVGReset();
   8239  MOZ_ASSERT(style->HasClipPath() || style->HasMask());
   8240  if (!SVGUtils::DetermineMaskUsage(frame, false).IsSimpleClipShape()) {
   8241    return Nothing();
   8242  }
   8243 
   8244  const auto& clipPath = style->mClipPath;
   8245  const auto& shape = *clipPath.AsShape()._0;
   8246 
   8247  auto appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
   8248  const nsRect refBox =
   8249      nsLayoutUtils::ComputeClipPathGeometryBox(frame, clipPath.AsShape()._1);
   8250 
   8251  wr::WrClipId clipId{};
   8252 
   8253  switch (shape.tag) {
   8254    case StyleBasicShape::Tag::Rect: {
   8255      const nsRect rect =
   8256          ShapeUtils::ComputeInsetRect(shape.AsRect().rect, refBox) +
   8257          aDisplayItem.ToReferenceFrame();
   8258 
   8259      nsRectCornerRadii radii;
   8260      if (ShapeUtils::ComputeRectRadii(shape.AsRect().round, refBox, rect,
   8261                                       radii)) {
   8262        clipId = aBuilder.DefineRoundedRectClip(
   8263            Nothing(),
   8264            wr::ToComplexClipRegion(rect, radii, appUnitsPerDevPixel));
   8265      } else {
   8266        clipId = aBuilder.DefineRectClip(
   8267            Nothing(), wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(
   8268                           rect, appUnitsPerDevPixel)));
   8269      }
   8270 
   8271      break;
   8272    }
   8273    case StyleBasicShape::Tag::Ellipse:
   8274    case StyleBasicShape::Tag::Circle: {
   8275      nsPoint center = ShapeUtils::ComputeCircleOrEllipseCenter(shape, refBox);
   8276 
   8277      nsSize radii;
   8278      if (shape.IsEllipse()) {
   8279        radii = ShapeUtils::ComputeEllipseRadii(shape, center, refBox);
   8280      } else {
   8281        nscoord radius = ShapeUtils::ComputeCircleRadius(shape, center, refBox);
   8282        radii = {radius, radius};
   8283      }
   8284 
   8285      nsRect ellipseRect(aDisplayItem.ToReferenceFrame() + center -
   8286                             nsPoint(radii.width, radii.height),
   8287                         radii * 2);
   8288 
   8289      nsRectCornerRadii ellipseRadii;
   8290      for (const auto corner : AllPhysicalHalfCorners()) {
   8291        ellipseRadii[corner] =
   8292            HalfCornerIsX(corner) ? radii.width : radii.height;
   8293      }
   8294 
   8295      clipId = aBuilder.DefineRoundedRectClip(
   8296          Nothing(), wr::ToComplexClipRegion(ellipseRect, ellipseRadii,
   8297                                             appUnitsPerDevPixel));
   8298 
   8299      break;
   8300    }
   8301    default:
   8302      // Please don't add more exceptions, try to find a way to define the clip
   8303      // without using a mask image.
   8304      //
   8305      // And if you _really really_ need to add an exception, add it to
   8306      // SVGUtils::DetermineMaskUsage
   8307      MOZ_ASSERT_UNREACHABLE("Unhandled shape id?");
   8308      return Nothing();
   8309  }
   8310 
   8311  wr::WrClipChainId clipChainId = aBuilder.DefineClipChain(
   8312      {&clipId, 1}, aBuilder.CurrentClipChainIdIfNotRoot());
   8313 
   8314  return Some(clipChainId);
   8315 }
   8316 
   8317 static void FillPolygonDataForDisplayItem(
   8318    const nsDisplayMasksAndClipPaths& aDisplayItem,
   8319    nsTArray<wr::LayoutPoint>& aPoints, wr::FillRule& aFillRule) {
   8320  nsIFrame* frame = aDisplayItem.Frame();
   8321  const auto* style = frame->StyleSVGReset();
   8322  bool isPolygon = style->HasClipPath() && style->mClipPath.IsShape() &&
   8323                   style->mClipPath.AsShape()._0->IsPolygon();
   8324  if (!isPolygon) {
   8325    return;
   8326  }
   8327 
   8328  const auto& clipPath = style->mClipPath;
   8329  const auto& shape = *clipPath.AsShape()._0;
   8330  const nsRect refBox =
   8331      nsLayoutUtils::ComputeClipPathGeometryBox(frame, clipPath.AsShape()._1);
   8332 
   8333  // We only fill polygon data for polygons that are below a complexity
   8334  // limit.
   8335  nsTArray<nsPoint> vertices =
   8336      ShapeUtils::ComputePolygonVertices(shape, refBox);
   8337  if (vertices.Length() > wr::POLYGON_CLIP_VERTEX_MAX) {
   8338    return;
   8339  }
   8340 
   8341  auto appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
   8342 
   8343  for (size_t i = 0; i < vertices.Length(); ++i) {
   8344    wr::LayoutPoint point = wr::ToLayoutPoint(
   8345        LayoutDevicePoint::FromAppUnits(vertices[i], appUnitsPerDevPixel));
   8346    aPoints.AppendElement(point);
   8347  }
   8348 
   8349  aFillRule = (shape.AsPolygon().fill == StyleFillRule::Nonzero)
   8350                  ? wr::FillRule::Nonzero
   8351                  : wr::FillRule::Evenodd;
   8352 }
   8353 
   8354 static Maybe<wr::WrClipChainId> CreateWRClipPathAndMasks(
   8355    nsDisplayMasksAndClipPaths* aDisplayItem, const LayoutDeviceRect& aBounds,
   8356    wr::IpcResourceUpdateQueue& aResources, wr::DisplayListBuilder& aBuilder,
   8357    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   8358    nsDisplayListBuilder* aDisplayListBuilder) {
   8359  if (auto clip = CreateSimpleClipRegion(*aDisplayItem, aBuilder)) {
   8360    return clip;
   8361  }
   8362 
   8363  Maybe<wr::ImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(
   8364      aDisplayItem, aBuilder, aResources, aSc, aDisplayListBuilder, aBounds);
   8365  if (!mask) {
   8366    return Nothing();
   8367  }
   8368 
   8369  // We couldn't create a simple clip region, but before we create an image
   8370  // mask clip, see if we can get a polygon clip to add to it.
   8371  nsTArray<wr::LayoutPoint> points;
   8372  wr::FillRule fillRule = wr::FillRule::Nonzero;
   8373  FillPolygonDataForDisplayItem(*aDisplayItem, points, fillRule);
   8374 
   8375  wr::WrClipId clipId =
   8376      aBuilder.DefineImageMaskClip(mask.ref(), points, fillRule);
   8377 
   8378  wr::WrClipChainId clipChainId = aBuilder.DefineClipChain(
   8379      {&clipId, 1}, aBuilder.CurrentClipChainIdIfNotRoot());
   8380 
   8381  return Some(clipChainId);
   8382 }
   8383 
   8384 bool nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
   8385    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   8386    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   8387    nsDisplayListBuilder* aDisplayListBuilder) {
   8388  bool snap;
   8389  auto appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   8390  nsRect displayBounds = GetBounds(aDisplayListBuilder, &snap);
   8391  LayoutDeviceRect bounds =
   8392      LayoutDeviceRect::FromAppUnits(displayBounds, appUnitsPerDevPixel);
   8393 
   8394  Maybe<wr::WrClipChainId> clip = CreateWRClipPathAndMasks(
   8395      this, bounds, aResources, aBuilder, aSc, aManager, aDisplayListBuilder);
   8396 
   8397  float oldOpacity = aBuilder.GetInheritedOpacity();
   8398 
   8399  Maybe<StackingContextHelper> layer;
   8400  const StackingContextHelper* sc = &aSc;
   8401  if (clip) {
   8402    // Create a new stacking context to attach the mask to, ensuring the mask is
   8403    // applied to the aggregate, and not the individual elements.
   8404 
   8405    // The stacking context shouldn't have any offset.
   8406    bounds.MoveTo(0, 0);
   8407 
   8408    Maybe<float> opacity =
   8409        (SVGUtils::DetermineMaskUsage(mFrame, false).IsSimpleClipShape() &&
   8410         aBuilder.GetInheritedOpacity() != 1.0f)
   8411            ? Some(aBuilder.GetInheritedOpacity())
   8412            : Nothing();
   8413 
   8414    wr::StackingContextParams params;
   8415    params.clip = wr::WrStackingContextClip::ClipChain(clip->id);
   8416    params.opacity = opacity.ptrOr(nullptr);
   8417    if (mForceIsolation) {
   8418      params.flags |= wr::StackingContextFlags::FORCED_ISOLATION;
   8419    }
   8420    if (mWrapsBackdropFilter) {
   8421      params.flags |= wr::StackingContextFlags::WRAPS_BACKDROP_FILTER;
   8422    }
   8423    layer.emplace(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, params,
   8424                  bounds);
   8425    sc = layer.ptr();
   8426  }
   8427 
   8428  aBuilder.SetInheritedOpacity(1.0f);
   8429  const DisplayItemClipChain* oldClipChain = aBuilder.GetInheritedClipChain();
   8430  aBuilder.SetInheritedClipChain(nullptr);
   8431  CreateWebRenderCommandsNewClipListOption(aBuilder, aResources, *sc, aManager,
   8432                                           aDisplayListBuilder, layer.isSome());
   8433  aBuilder.SetInheritedOpacity(oldOpacity);
   8434  aBuilder.SetInheritedClipChain(oldClipChain);
   8435 
   8436  return true;
   8437 }
   8438 
   8439 Maybe<nsRect> nsDisplayMasksAndClipPaths::GetClipWithRespectToASR(
   8440    nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR) const {
   8441  if (const DisplayItemClip* clip =
   8442          DisplayItemClipChain::ClipForASR(GetClipChain(), aASR)) {
   8443    return Some(clip->GetClipRect());
   8444  }
   8445  // This item does not have a clip with respect to |aASR|. However, we
   8446  // might still have finite bounds with respect to |aASR|. Check our
   8447  // children.
   8448  nsDisplayList* childList = GetSameCoordinateSystemChildren();
   8449  if (childList) {
   8450    return Some(childList->GetClippedBoundsWithRespectToASR(aBuilder, aASR));
   8451  }
   8452 #ifdef DEBUG
   8453  NS_ASSERTION(false, "item should have finite clip with respect to aASR");
   8454 #endif
   8455  return Nothing();
   8456 }
   8457 
   8458 #ifdef MOZ_DUMP_PAINTING
   8459 void nsDisplayMasksAndClipPaths::PrintEffects(nsACString& aTo) {
   8460  nsIFrame* firstFrame =
   8461      nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   8462  bool first = true;
   8463  aTo += " effects=(";
   8464  SVGClipPathFrame* clipPathFrame;
   8465  // XXX Check return value?
   8466  SVGObserverUtils::GetAndObserveClipPath(firstFrame, &clipPathFrame);
   8467  if (clipPathFrame) {
   8468    if (!first) {
   8469      aTo += ", ";
   8470    }
   8471    aTo += nsPrintfCString(
   8472        "clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
   8473    first = false;
   8474  } else if (mFrame->StyleSVGReset()->HasClipPath()) {
   8475    if (!first) {
   8476      aTo += ", ";
   8477    }
   8478    aTo += "clip(basic-shape)";
   8479    first = false;
   8480  }
   8481 
   8482  nsTArray<SVGMaskFrame*> masks;
   8483  // XXX check return value?
   8484  SVGObserverUtils::GetAndObserveMasks(firstFrame, &masks);
   8485  if (!masks.IsEmpty() && masks[0]) {
   8486    if (!first) {
   8487      aTo += ", ";
   8488    }
   8489    aTo += "mask";
   8490  }
   8491  aTo += ")";
   8492 }
   8493 #endif
   8494 
   8495 bool nsDisplayBackdropFilters::CreateWebRenderCommands(
   8496    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   8497    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   8498    nsDisplayListBuilder* aDisplayListBuilder) {
   8499  WrFiltersHolder wrFilters;
   8500  const ComputedStyle& style = mStyle ? *mStyle : *mFrame->Style();
   8501  auto filterChain = style.StyleEffects()->mBackdropFilters.AsSpan();
   8502  // Try building a CSS filter chain
   8503  WrFiltersStatus status = SVGIntegrationUtils::CreateWebRenderCSSFilters(
   8504      filterChain, mFrame, wrFilters);
   8505  if (status == WrFiltersStatus::BLOB_FALLBACK) {
   8506    // If the filters are too complex for CSS filters, try SVG filters
   8507    auto offsetForSVGFilters =
   8508        nsLayoutUtils::ComputeOffsetToUserSpace(aDisplayListBuilder, mFrame);
   8509    status = SVGIntegrationUtils::BuildWebRenderFilters(
   8510        mFrame, filterChain, StyleFilterType::BackdropFilter, wrFilters,
   8511        offsetForSVGFilters);
   8512  }
   8513 
   8514  if (status == WrFiltersStatus::BLOB_FALLBACK) {
   8515    // TODO: If painting backdrop-filters on the content side is implemented,
   8516    // consider returning false to fall back to that.
   8517    wrFilters = {};
   8518  }
   8519 
   8520  if (status == WrFiltersStatus::UNSUPPORTED) {
   8521    wrFilters = {};
   8522  }
   8523 
   8524  nsCSSRendering::ImageLayerClipState clip;
   8525  nsCSSRendering::GetImageLayerClip(
   8526      style.StyleBackground()->BottomLayer(), mFrame, *style.StyleBorder(),
   8527      mBackdropRect, mBackdropRect, false,
   8528      mFrame->PresContext()->AppUnitsPerDevPixel(), &clip);
   8529 
   8530  LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
   8531      mBackdropRect, mFrame->PresContext()->AppUnitsPerDevPixel());
   8532 
   8533  wr::ComplexClipRegion region =
   8534      wr::ToComplexClipRegion(clip.mBGClipArea, clip.mRadii,
   8535                              mFrame->PresContext()->AppUnitsPerDevPixel());
   8536 
   8537  aBuilder.PushBackdropFilter(wr::ToLayoutRect(bounds), region,
   8538                              wrFilters.filters, wrFilters.filter_datas,
   8539                              !BackfaceIsHidden());
   8540 
   8541  wr::StackingContextParams params;
   8542  params.clip =
   8543      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   8544  params.flags = wr::StackingContextFlags::FORCED_ISOLATION;
   8545  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   8546                           params);
   8547 
   8548  nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
   8549                                             aDisplayListBuilder);
   8550  return true;
   8551 }
   8552 
   8553 void nsDisplayBackdropFilters::Paint(nsDisplayListBuilder* aBuilder,
   8554                                     gfxContext* aCtx) {
   8555  // TODO: Implement backdrop filters
   8556  GetChildren()->Paint(aBuilder, aCtx,
   8557                       mFrame->PresContext()->AppUnitsPerDevPixel());
   8558 }
   8559 
   8560 nsRect nsDisplayBackdropFilters::GetBounds(nsDisplayListBuilder* aBuilder,
   8561                                           bool* aSnap) const {
   8562  nsRect childBounds = nsDisplayWrapList::GetBounds(aBuilder, aSnap);
   8563 
   8564  *aSnap = false;
   8565 
   8566  return mBackdropRect.Union(childBounds);
   8567 }
   8568 
   8569 /* static */
   8570 nsDisplayFilters::nsDisplayFilters(nsDisplayListBuilder* aBuilder,
   8571                                   nsIFrame* aFrame, nsDisplayList* aList,
   8572                                   nsIFrame* aStyleFrame,
   8573                                   bool aWrapsBackdropFilter)
   8574    : nsDisplayEffectsBase(aBuilder, aFrame, aList),
   8575      mStyle(aFrame == aStyleFrame ? nullptr : aStyleFrame->Style()),
   8576      mEffectsBounds(aFrame->InkOverflowRectRelativeToSelf()),
   8577      mWrapsBackdropFilter(aWrapsBackdropFilter) {
   8578  MOZ_COUNT_CTOR(nsDisplayFilters);
   8579  mVisibleRect = aBuilder->GetVisibleRect() +
   8580                 aBuilder->GetCurrentFrameOffsetToReferenceFrame();
   8581 }
   8582 
   8583 void nsDisplayFilters::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   8584  PaintWithContentsPaintCallback(aBuilder, aCtx, [&](gfxContext* aContext) {
   8585    GetChildren()->Paint(aBuilder, aContext,
   8586                         mFrame->PresContext()->AppUnitsPerDevPixel());
   8587  });
   8588 }
   8589 
   8590 void nsDisplayFilters::PaintWithContentsPaintCallback(
   8591    nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
   8592    const std::function<void(gfxContext* aContext)>& aPaintChildren) {
   8593  imgDrawingParams imgParams(aBuilder->GetImageDecodeFlags());
   8594  nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   8595  PaintFramesParams params(*aCtx, mFrame, mVisibleRect, borderArea, aBuilder,
   8596                           false, imgParams);
   8597 
   8598  gfxPoint userSpaceToFrameSpaceOffset =
   8599      SVGIntegrationUtils::GetOffsetToUserSpaceInDevPx(mFrame, params);
   8600 
   8601  auto filterChain = mStyle ? mStyle->StyleEffects()->mFilters.AsSpan()
   8602                            : mFrame->StyleEffects()->mFilters.AsSpan();
   8603  SVGIntegrationUtils::PaintFilter(
   8604      params, filterChain,
   8605      [&](gfxContext& aContext, imgDrawingParams&, const gfxMatrix*,
   8606          const nsIntRect*) {
   8607        gfxContextMatrixAutoSaveRestore autoSR(&aContext);
   8608        aContext.SetMatrixDouble(aContext.CurrentMatrixDouble().PreTranslate(
   8609            -userSpaceToFrameSpaceOffset));
   8610        aPaintChildren(&aContext);
   8611      });
   8612 }
   8613 
   8614 bool nsDisplayFilters::CanCreateWebRenderCommands() const {
   8615  return SVGIntegrationUtils::CanCreateWebRenderFiltersForFrame(mFrame);
   8616 }
   8617 
   8618 bool nsDisplayFilters::CreateWebRenderCommands(
   8619    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   8620    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   8621    nsDisplayListBuilder* aDisplayListBuilder) {
   8622  WrFiltersHolder wrFilters;
   8623  const ComputedStyle& style = mStyle ? *mStyle : *mFrame->Style();
   8624  auto filterChain = style.StyleEffects()->mFilters.AsSpan();
   8625  // Try building a CSS filter chain
   8626  WrFiltersStatus status = SVGIntegrationUtils::CreateWebRenderCSSFilters(
   8627      filterChain, mFrame, wrFilters);
   8628  if (status == WrFiltersStatus::BLOB_FALLBACK) {
   8629    // Try building an SVG filter graph
   8630    auto offsetForSVGFilters =
   8631        nsLayoutUtils::ComputeOffsetToUserSpace(aDisplayListBuilder, mFrame);
   8632    status = SVGIntegrationUtils::BuildWebRenderFilters(
   8633        mFrame, filterChain, StyleFilterType::Filter, wrFilters,
   8634        offsetForSVGFilters);
   8635    if (status == WrFiltersStatus::BLOB_FALLBACK && mStyle) {
   8636      // TODO(bug 1769223): Support fallback filters in the root code-path,
   8637      // perhaps. For now treat it the same way as invalid filters.
   8638      status = WrFiltersStatus::UNSUPPORTED;
   8639    }
   8640  }
   8641 
   8642  switch (status) {
   8643    case WrFiltersStatus::BLOB_FALLBACK:
   8644      // Draw using fallback.
   8645      return false;
   8646    case WrFiltersStatus::UNSUPPORTED:
   8647      // https://drafts.fxtf.org/filter-effects/#typedef-filter-url:
   8648      //
   8649      //   If the filter references a non-existent object or the referenced
   8650      //   object is not a filter element, then the whole filter chain is
   8651      //   ignored. No filter is applied to the object.
   8652      //
   8653      // Note that other engines have a weird discrepancy between SVG and HTML
   8654      // content here, but the spec is clear.
   8655      wrFilters = {};
   8656      break;
   8657    case WrFiltersStatus::DISABLED_FOR_PERFORMANCE:
   8658      // SVG spec allows us to drop the entire filter graph if it contains too
   8659      // many filters to render or other performance considerations.
   8660      wrFilters = {};
   8661      break;
   8662    case WrFiltersStatus::CHAIN:
   8663    case WrFiltersStatus::SVGFE:
   8664      // Filter the image using the wrFilters produced above.
   8665      break;
   8666  }
   8667 
   8668  uint64_t clipChainId;
   8669  if (wrFilters.post_filters_clip) {
   8670    auto devPxRect = LayoutDeviceRect::FromAppUnits(
   8671        wrFilters.post_filters_clip.value() + ToReferenceFrame(),
   8672        mFrame->PresContext()->AppUnitsPerDevPixel());
   8673    auto clipId =
   8674        aBuilder.DefineRectClip(Nothing(), wr::ToLayoutRect(devPxRect));
   8675    clipChainId = aBuilder
   8676                      .DefineClipChain({&clipId, 1},
   8677                                       aBuilder.CurrentClipChainIdIfNotRoot())
   8678                      .id;
   8679  } else {
   8680    clipChainId = aBuilder.CurrentClipChainId();
   8681  }
   8682  wr::WrStackingContextClip clip =
   8683      wr::WrStackingContextClip::ClipChain(clipChainId);
   8684 
   8685  float opacity = aBuilder.GetInheritedOpacity();
   8686  aBuilder.SetInheritedOpacity(1.0f);
   8687  const DisplayItemClipChain* oldClipChain = aBuilder.GetInheritedClipChain();
   8688  aBuilder.SetInheritedClipChain(nullptr);
   8689  wr::StackingContextParams params;
   8690  params.mFilters = std::move(wrFilters.filters);
   8691  params.mFilterDatas = std::move(wrFilters.filter_datas);
   8692  params.opacity = opacity != 1.0f ? &opacity : nullptr;
   8693  params.clip = clip;
   8694  if (mWrapsBackdropFilter) {
   8695    params.flags |= wr::StackingContextFlags::WRAPS_BACKDROP_FILTER;
   8696  }
   8697  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
   8698                           params);
   8699 
   8700  nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc,
   8701                                                aManager, aDisplayListBuilder);
   8702  aBuilder.SetInheritedOpacity(opacity);
   8703  aBuilder.SetInheritedClipChain(oldClipChain);
   8704 
   8705  return true;
   8706 }
   8707 
   8708 #ifdef MOZ_DUMP_PAINTING
   8709 void nsDisplayFilters::PrintEffects(nsACString& aTo) {
   8710  nsIFrame* firstFrame =
   8711      nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   8712  bool first = true;
   8713  aTo += " effects=(";
   8714  // We may exist for a mix of CSS filter functions and/or references to SVG
   8715  // filters.  If we have invalid references to SVG filters then we paint
   8716  // nothing, but otherwise we will apply one or more filters.
   8717  if (SVGObserverUtils::GetAndObserveFilters(firstFrame, nullptr) !=
   8718      SVGObserverUtils::eHasRefsSomeInvalid) {
   8719    if (!first) {
   8720      aTo += ", ";
   8721    }
   8722    aTo += "filter";
   8723  }
   8724  aTo += ")";
   8725 }
   8726 #endif
   8727 
   8728 nsDisplaySVGWrapper::nsDisplaySVGWrapper(nsDisplayListBuilder* aBuilder,
   8729                                         nsIFrame* aFrame, nsDisplayList* aList)
   8730    : nsDisplayWrapList(aBuilder, aFrame, aList) {
   8731  MOZ_COUNT_CTOR(nsDisplaySVGWrapper);
   8732 }
   8733 
   8734 bool nsDisplaySVGWrapper::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
   8735  return !aBuilder->GetWidgetLayerManager();
   8736 }
   8737 
   8738 bool nsDisplaySVGWrapper::CreateWebRenderCommands(
   8739    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   8740    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   8741    nsDisplayListBuilder* aDisplayListBuilder) {
   8742  return CreateWebRenderCommandsNewClipListOption(
   8743      aBuilder, aResources, aSc, aManager, aDisplayListBuilder, false);
   8744 }
   8745 
   8746 nsDisplayForeignObject::nsDisplayForeignObject(nsDisplayListBuilder* aBuilder,
   8747                                               nsIFrame* aFrame,
   8748                                               nsDisplayList* aList)
   8749    : nsDisplayWrapList(aBuilder, aFrame, aList) {
   8750  MOZ_COUNT_CTOR(nsDisplayForeignObject);
   8751 }
   8752 
   8753 bool nsDisplayForeignObject::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
   8754  return !aBuilder->GetWidgetLayerManager();
   8755 }
   8756 
   8757 bool nsDisplayForeignObject::CreateWebRenderCommands(
   8758    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
   8759    const StackingContextHelper& aSc, RenderRootStateManager* aManager,
   8760    nsDisplayListBuilder* aDisplayListBuilder) {
   8761  AutoRestore<bool> restoreDoGrouping(aManager->CommandBuilder().mDoGrouping);
   8762  aManager->CommandBuilder().mDoGrouping = false;
   8763  return CreateWebRenderCommandsNewClipListOption(
   8764      aBuilder, aResources, aSc, aManager, aDisplayListBuilder, false);
   8765 }
   8766 
   8767 void nsDisplayLink::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   8768  auto appPerDev = mFrame->PresContext()->AppUnitsPerDevPixel();
   8769  aCtx->GetDrawTarget()->Link(
   8770      mLinkURI.get(), mLinkDest.get(),
   8771      NSRectToRect(GetPaintRect(aBuilder, aCtx), appPerDev));
   8772 }
   8773 
   8774 void nsDisplayDestination::Paint(nsDisplayListBuilder* aBuilder,
   8775                                 gfxContext* aCtx) {
   8776  auto appPerDev = mFrame->PresContext()->AppUnitsPerDevPixel();
   8777  aCtx->GetDrawTarget()->Destination(
   8778      mDestinationName.get(),
   8779      NSPointToPoint(GetPaintRect(aBuilder, aCtx).TopLeft(), appPerDev));
   8780 }
   8781 
   8782 void nsDisplayListCollection::SerializeWithCorrectZOrder(
   8783    nsDisplayList* aOutResultList, nsIContent* aContent) {
   8784  // Sort PositionedDescendants() in CSS 'z-order' order.  The list is already
   8785  // in content document order and SortByZOrder is a stable sort which
   8786  // guarantees that boxes produced by the same element are placed together
   8787  // in the sort. Consider a position:relative inline element that breaks
   8788  // across lines and has absolutely positioned children; all the abs-pos
   8789  // children should be z-ordered after all the boxes for the position:relative
   8790  // element itself.
   8791  PositionedDescendants()->SortByZOrder();
   8792 
   8793  // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
   8794  // 1,2: backgrounds and borders
   8795  aOutResultList->AppendToTop(BorderBackground());
   8796  // 3: negative z-index children.
   8797  for (auto* item : PositionedDescendants()->TakeItems()) {
   8798    if (item->ZIndex() < 0) {
   8799      aOutResultList->AppendToTop(item);
   8800    } else {
   8801      PositionedDescendants()->AppendToTop(item);
   8802    }
   8803  }
   8804 
   8805  // 4: block backgrounds
   8806  aOutResultList->AppendToTop(BlockBorderBackgrounds());
   8807  // 5: floats
   8808  aOutResultList->AppendToTop(Floats());
   8809  // 7: general content
   8810  aOutResultList->AppendToTop(Content());
   8811  // 7.5: outlines, in content tree order. We need to sort by content order
   8812  // because an element with outline that breaks and has children with outline
   8813  // might have placed child outline items between its own outline items.
   8814  // The element's outline items need to all come before any child outline
   8815  // items.
   8816  if (aContent) {
   8817    Outlines()->SortByContentOrder(aContent);
   8818  }
   8819  aOutResultList->AppendToTop(Outlines());
   8820  // 8, 9: non-negative z-index children
   8821  aOutResultList->AppendToTop(PositionedDescendants());
   8822 }
   8823 
   8824 uint32_t PaintTelemetry::sPaintLevel = 0;
   8825 
   8826 PaintTelemetry::AutoRecordPaint::AutoRecordPaint() {
   8827  // Don't record nested paints.
   8828  if (sPaintLevel++ > 0) {
   8829    return;
   8830  }
   8831 
   8832  mStart = TimeStamp::Now();
   8833 }
   8834 
   8835 PaintTelemetry::AutoRecordPaint::~AutoRecordPaint() {
   8836  MOZ_ASSERT(sPaintLevel != 0);
   8837  if (--sPaintLevel > 0) {
   8838    return;
   8839  }
   8840 
   8841  // If we're in multi-process mode, don't include paint times for the parent
   8842  // process.
   8843  if (gfxVars::BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) {
   8844    return;
   8845  }
   8846 
   8847  // Record the total time.
   8848  mozilla::glean::gfx_content::paint_time.AccumulateRawDuration(
   8849      TimeStamp::Now() - mStart);
   8850 }
   8851 
   8852 static nsIFrame* GetSelfOrPlaceholderFor(nsIFrame* aFrame) {
   8853  if (aFrame->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
   8854    return aFrame;
   8855  }
   8856 
   8857  if (aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
   8858      !aFrame->GetPrevInFlow()) {
   8859    return aFrame->GetPlaceholderFrame();
   8860  }
   8861 
   8862  return aFrame;
   8863 }
   8864 
   8865 static nsIFrame* GetAncestorFor(nsIFrame* aFrame) {
   8866  nsIFrame* f = GetSelfOrPlaceholderFor(aFrame);
   8867  MOZ_ASSERT(f);
   8868  return nsLayoutUtils::GetCrossDocParentFrameInProcess(f);
   8869 }
   8870 
   8871 nsDisplayListBuilder::AutoBuildingDisplayList::AutoBuildingDisplayList(
   8872    nsDisplayListBuilder* aBuilder, nsIFrame* aForChild,
   8873    const nsRect& aVisibleRect, const nsRect& aDirtyRect,
   8874    const bool aIsTransformed)
   8875    : mBuilder(aBuilder),
   8876      mPrevFrame(aBuilder->mCurrentFrame),
   8877      mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
   8878      mPrevVisibleRect(aBuilder->mVisibleRect),
   8879      mPrevDirtyRect(aBuilder->mDirtyRect),
   8880      mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
   8881      mPrevAdditionalOffset(aBuilder->mAdditionalOffset),
   8882      mPrevCompositorHitTestInfo(aBuilder->mCompositorHitTestInfo),
   8883      mPrevAncestorHasApzAwareEventHandler(
   8884          aBuilder->mAncestorHasApzAwareEventHandler),
   8885      mPrevBuildingInvisibleItems(aBuilder->mBuildingInvisibleItems),
   8886      mPrevInInvalidSubtree(aBuilder->mInInvalidSubtree) {
   8887  // If the last AutoBuildingDisplayList on the stack that we created was for
   8888  // this same frame then we are already up to date and can skip this work (this
   8889  // happens eg when BuildDisplayListForChild calls
   8890  // BuildDisplayListForStackingContext).
   8891  if (aForChild != mPrevFrame) {
   8892    if (aIsTransformed) {
   8893      aBuilder->mCurrentOffsetToReferenceFrame =
   8894          aBuilder->AdditionalOffset().refOr(nsPoint());
   8895      aBuilder->mCurrentReferenceFrame = aForChild;
   8896    } else if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
   8897      aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition();
   8898    } else {
   8899      aBuilder->mCurrentReferenceFrame = aBuilder->FindReferenceFrameFor(
   8900          aForChild, &aBuilder->mCurrentOffsetToReferenceFrame);
   8901    }
   8902  }
   8903 
   8904  // If aForChild is being visited from a frame other than it's ancestor frame,
   8905  // mInInvalidSubtree will need to be recalculated the slow way.
   8906  if (aForChild == mPrevFrame || GetAncestorFor(aForChild) == mPrevFrame) {
   8907    aBuilder->mInInvalidSubtree =
   8908        aBuilder->mInInvalidSubtree || aForChild->IsFrameModified();
   8909  } else {
   8910    aBuilder->mInInvalidSubtree = AnyContentAncestorModified(aForChild);
   8911  }
   8912 
   8913  aBuilder->mCurrentFrame = aForChild;
   8914  aBuilder->mVisibleRect = aVisibleRect;
   8915  aBuilder->mDirtyRect =
   8916      aBuilder->mInInvalidSubtree ? aVisibleRect : aDirtyRect;
   8917 }
   8918 
   8919 }  // namespace mozilla