tor-browser

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

nsSubDocumentFrame.cpp (46228B)


      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 * rendering object for replaced elements that contain a document, such
      9 * as <frame>, <iframe>, and some <object>s
     10 */
     11 
     12 #include "nsSubDocumentFrame.h"
     13 
     14 #include "RetainedDisplayListBuilder.h"
     15 #include "mozilla/ComputedStyleInlines.h"
     16 #include "mozilla/Preferences.h"
     17 #include "mozilla/PresShell.h"
     18 #include "mozilla/ProfilerLabels.h"
     19 #include "mozilla/ScrollContainerFrame.h"
     20 #include "mozilla/StaticPrefs_layout.h"
     21 #include "mozilla/dom/BrowserParent.h"
     22 #include "mozilla/dom/Document.h"
     23 #include "mozilla/dom/HTMLFrameElement.h"
     24 #include "mozilla/dom/ImageDocument.h"
     25 #include "mozilla/dom/RemoteBrowser.h"
     26 #include "mozilla/layers/RenderRootStateManager.h"
     27 #include "mozilla/layers/StackingContextHelper.h"  // for StackingContextHelper
     28 #include "mozilla/layers/WebRenderScrollData.h"
     29 #include "mozilla/layers/WebRenderUserData.h"
     30 #include "nsAttrValueInlines.h"
     31 #include "nsCOMPtr.h"
     32 #include "nsContentUtils.h"
     33 #include "nsDeviceContext.h"
     34 #include "nsDisplayList.h"
     35 #include "nsFrameSetFrame.h"
     36 #include "nsGenericHTMLElement.h"
     37 #include "nsGenericHTMLFrameElement.h"
     38 #include "nsGkAtoms.h"
     39 #include "nsIContentInlines.h"
     40 #include "nsIDocShell.h"
     41 #include "nsIDocumentViewer.h"
     42 #include "nsIObjectLoadingContent.h"
     43 #include "nsIWeakReferenceUtils.h"
     44 #include "nsLayoutUtils.h"
     45 #include "nsNameSpaceManager.h"
     46 #include "nsObjectLoadingContent.h"
     47 #include "nsPresContext.h"
     48 #include "nsQueryObject.h"
     49 #include "nsServiceManagerUtils.h"
     50 #include "nsStyleConsts.h"
     51 #include "nsStyleStruct.h"
     52 #include "nsStyleStructInlines.h"
     53 
     54 using namespace mozilla;
     55 using namespace mozilla::dom;
     56 using namespace mozilla::gfx;
     57 using namespace mozilla::layers;
     58 
     59 static void PropagateIsUnderHiddenEmbedderElement(nsFrameLoader* aFrameLoader,
     60                                                  bool aValue) {
     61  if (!aFrameLoader) {
     62    return;
     63  }
     64 
     65  if (BrowsingContext* bc = aFrameLoader->GetExtantBrowsingContext()) {
     66    if (bc->IsUnderHiddenEmbedderElement() != aValue) {
     67      (void)bc->SetIsUnderHiddenEmbedderElement(aValue);
     68    }
     69  }
     70 }
     71 
     72 nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle,
     73                                       nsPresContext* aPresContext)
     74    : nsAtomicContainerFrame(aStyle, aPresContext, kClassID),
     75      mIsInline(false),
     76      mPostedReflowCallback(false),
     77      mDidCreateDoc(false),
     78      mCallingShow(false),
     79      mIsInObjectOrEmbed(false) {}
     80 
     81 #ifdef ACCESSIBILITY
     82 a11y::AccType nsSubDocumentFrame::AccessibleType() {
     83  return a11y::eOuterDocType;
     84 }
     85 #endif
     86 
     87 NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
     88  NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
     89 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
     90 
     91 class AsyncFrameInit : public Runnable {
     92 public:
     93  explicit AsyncFrameInit(nsIFrame* aFrame)
     94      : mozilla::Runnable("AsyncFrameInit"), mFrame(aFrame) {}
     95  NS_IMETHOD Run() override {
     96    AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER);
     97    if (mFrame.IsAlive()) {
     98      static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
     99    }
    100    return NS_OK;
    101  }
    102 
    103 private:
    104  WeakFrame mFrame;
    105 };
    106 
    107 void nsSubDocumentFrame::EnsureEmbeddingPresShell(class PresShell* aPs) {
    108  MOZ_ASSERT(aPs);
    109  nsWeakPtr weakRef = do_GetWeakReference(aPs);
    110  if (!mInProcessPresShells.Contains(weakRef)) {
    111    aPs->SetInProcessEmbedderFrame(this);
    112    mInProcessPresShells.AppendElement(std::move(weakRef));
    113  }
    114 }
    115 
    116 void nsSubDocumentFrame::AddEmbeddingPresShell(class PresShell* aPs) {
    117  MOZ_ASSERT(aPs);
    118  nsWeakPtr weakRef = do_GetWeakReference(aPs);
    119  MOZ_ASSERT(!mInProcessPresShells.Contains(weakRef));
    120  aPs->SetInProcessEmbedderFrame(this);
    121  mInProcessPresShells.AppendElement(std::move(weakRef));
    122 }
    123 
    124 void nsSubDocumentFrame::RemoveEmbeddingPresShell(class PresShell* aPs) {
    125  MOZ_ASSERT(aPs);
    126  nsWeakPtr weakRef = do_GetWeakReference(aPs);
    127  MOZ_ASSERT(mInProcessPresShells.Contains(weakRef));
    128  aPs->SetInProcessEmbedderFrame(nullptr);
    129  if (mLastPaintedPresShell == weakRef) {
    130    mLastPaintedPresShell = nullptr;
    131  }
    132  mInProcessPresShells.RemoveElement(weakRef);
    133 }
    134 
    135 void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
    136                              nsIFrame* aPrevInFlow) {
    137  MOZ_ASSERT(aContent);
    138  // determine if we are a <frame> or <iframe>
    139  mIsInline = !aContent->IsHTMLElement(nsGkAtoms::frame);
    140 
    141  nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
    142 
    143  aContent->SetPrimaryFrame(this);
    144 
    145  // If we have a detached subdoc's root view on our frame loader, re-insert it
    146  // into the view tree. This happens when we've been reframed, and ensures the
    147  // presentation persists across reframes.
    148  if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
    149    mInProcessPresShells = frameloader->TakeDetachedSubdocs();
    150    const bool anyLiveShell = FixUpInProcessPresShellsAfterAttach();
    151    if (!mInProcessPresShells.IsEmpty() && !anyLiveShell) {
    152      mInProcessPresShells.Clear();
    153      // Presentation is for a different document, don't restore it.
    154      frameloader->Hide();
    155    }
    156  }
    157 
    158  // NOTE: The frame loader might not yet be initialized yet. If it's not, the
    159  // call in ShowViewer() should pick things up.
    160  UpdateEmbeddedBrowsingContextDependentData();
    161  nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
    162 }
    163 
    164 void nsSubDocumentFrame::UpdateEmbeddedBrowsingContextDependentData() {
    165  if (!mFrameLoader) {
    166    return;
    167  }
    168  BrowsingContext* bc = mFrameLoader->GetExtantBrowsingContext();
    169  if (!bc) {
    170    return;
    171  }
    172  mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed();
    173  MaybeUpdateRemoteStyle();
    174  MaybeUpdateEmbedderColorScheme();
    175  MaybeUpdateEmbedderZoom();
    176  PropagateIsUnderHiddenEmbedderElement(
    177      PresShell()->IsUnderHiddenEmbedderElement() ||
    178      !StyleVisibility()->IsVisible());
    179 }
    180 
    181 void nsSubDocumentFrame::PropagateIsUnderHiddenEmbedderElement(bool aValue) {
    182  ::PropagateIsUnderHiddenEmbedderElement(mFrameLoader, aValue);
    183 }
    184 
    185 void nsSubDocumentFrame::ShowViewer() {
    186  if (mCallingShow) {
    187    return;
    188  }
    189 
    190  RefPtr<nsFrameLoader> frameloader = FrameLoader();
    191  if (!frameloader || frameloader->IsDead()) {
    192    return;
    193  }
    194 
    195  if (!frameloader->IsRemoteFrame() && !PresContext()->IsDynamic()) {
    196    // We let the printing code take care of loading the document and
    197    // initializing the shell.
    198  } else {
    199    AutoWeakFrame weakThis(this);
    200    mCallingShow = true;
    201    bool didCreateDoc = frameloader->Show(this);
    202    if (!weakThis.IsAlive()) {
    203      return;
    204    }
    205    mCallingShow = false;
    206    mDidCreateDoc = didCreateDoc;
    207    if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
    208      frameloader->UpdatePositionAndSize(this);
    209    }
    210    if (!weakThis.IsAlive()) {
    211      return;
    212    }
    213    UpdateEmbeddedBrowsingContextDependentData();
    214    InvalidateFrame();
    215  }
    216 }
    217 
    218 Document* nsSubDocumentFrame::GetExtantSubdocument() {
    219  nsIDocShell* ds = GetExtantDocShell();
    220  return ds ? ds->GetExtantDocument() : nullptr;
    221 }
    222 
    223 mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShell() {
    224  Document* doc = GetExtantSubdocument();
    225  return doc ? doc->GetPresShell() : nullptr;
    226 }
    227 
    228 nsIFrame* nsSubDocumentFrame::GetSubdocumentRootFrame() {
    229  mozilla::PresShell* ps = GetSubdocumentPresShell();
    230  return ps ? ps->GetRootFrame() : nullptr;
    231 }
    232 
    233 mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShellForPainting(
    234    uint32_t aFlags) {
    235  mozilla::PresShell* presShell = GetSubdocumentPresShell();
    236  if (presShell && (!presShell->IsPaintingSuppressed() ||
    237                    (aFlags & IGNORE_PAINT_SUPPRESSION))) {
    238    return presShell;
    239  }
    240  // If painting is suppressed in the presshell or there's no presShell, we try
    241  // to look for a better presshell to use.
    242  if (StaticPrefs::layout_show_previous_page()) {
    243    RefPtr<mozilla::PresShell> old = do_QueryReferent(mLastPaintedPresShell);
    244    if (old && old->GetInProcessEmbedderFrame() == this) {
    245      return old;
    246    }
    247  }
    248  return presShell;
    249 }
    250 
    251 nsRect nsSubDocumentFrame::GetDestRect() const {
    252  const nsRect rect = GetContent()->IsHTMLElement(nsGkAtoms::frame)
    253                          ? GetRectRelativeToSelf()
    254                          : GetContentRectRelativeToSelf();
    255  return GetDestRect(rect);
    256 }
    257 
    258 nsRect nsSubDocumentFrame::GetDestRect(const nsRect& aConstraintRect) const {
    259  // Adjust subdocument size, according to 'object-fit' and the subdocument's
    260  // intrinsic size and ratio.
    261  return nsLayoutUtils::ComputeObjectDestRect(
    262      aConstraintRect, ComputeIntrinsicSize(/* aIgnoreContainment = */ true),
    263      GetIntrinsicRatio(), StylePosition());
    264 }
    265 
    266 LayoutDeviceIntSize nsSubDocumentFrame::GetInitialSubdocumentSize() const {
    267  if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
    268    for (const auto& detachedShell : frameloader->GetDetachedSubdocs()) {
    269      if (RefPtr<mozilla::PresShell> ps = do_QueryReferent(detachedShell)) {
    270        if (nsPresContext* pc = ps->GetPresContext()) {
    271          return LayoutDeviceIntSize(
    272              pc->AppUnitsToDevPixels(pc->GetVisibleArea().width),
    273              pc->AppUnitsToDevPixels(pc->GetVisibleArea().height));
    274        }
    275      }
    276    }
    277  }
    278  // Pick some default size for now.  Using 10x10 because that's what the
    279  // code used to do.
    280  return LayoutDeviceIntSize(10, 10);
    281 }
    282 
    283 LayoutDeviceIntSize nsSubDocumentFrame::GetSubdocumentSize() const {
    284  if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
    285    return GetInitialSubdocumentSize();
    286  }
    287 
    288  nsSize docSizeAppUnits = GetDestRect().Size();
    289  nsPresContext* pc = PresContext();
    290  return LayoutDeviceIntSize(pc->AppUnitsToDevPixels(docSizeAppUnits.width),
    291                             pc->AppUnitsToDevPixels(docSizeAppUnits.height));
    292 }
    293 
    294 static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
    295                                          nsIFrame* aFrame,
    296                                          nsDisplayList* aList) {
    297  for (nsDisplayItem* item : aList->TakeItems()) {
    298    if (item->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) {
    299      nsDisplayList tmpList(aBuilder);
    300      tmpList.AppendToTop(item);
    301      item = MakeDisplayItemWithIndex<nsDisplayOwnLayer>(
    302          aBuilder, aFrame, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc,
    303          &tmpList, aBuilder->CurrentActiveScrolledRoot(),
    304          nsDisplayItem::ContainerASRType::Constant,
    305          nsDisplayOwnLayerFlags::None, ScrollbarData{}, true, false);
    306    }
    307    aList->AppendToTop(item);
    308  }
    309 }
    310 
    311 void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
    312                                          const nsDisplayListSet& aLists) {
    313  if (!IsVisibleForPainting()) {
    314    return;
    315  }
    316 
    317  const bool forEvents = aBuilder->IsForEventDelivery();
    318  if (forEvents && Style()->PointerEvents() == StylePointerEvents::None) {
    319    // If we are pointer-events:none then we don't need to HitTest background or
    320    // anything else.
    321    return;
    322  }
    323 
    324  nsFrameLoader* frameLoader = FrameLoader();
    325  const bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame();
    326 
    327  nsDisplayListCollection decorations(aBuilder);
    328  DisplayBorderBackgroundOutline(aBuilder, decorations);
    329  if (isRemoteFrame) {
    330    // Wrap background colors of <iframe>s with remote subdocuments in their
    331    // own layer so we generate a ColorLayer. This is helpful for optimizing
    332    // compositing; we can skip compositing the ColorLayer when the
    333    // remote content is opaque.
    334    WrapBackgroundColorInOwnLayer(aBuilder, this,
    335                                  decorations.BorderBackground());
    336  }
    337  decorations.MoveTo(aLists);
    338 
    339  if (forEvents && !ContentReactsToPointerEvents()) {
    340    return;
    341  }
    342 
    343  if (HidesContent()) {
    344    return;
    345  }
    346 
    347  // If we're passing pointer events to children then we have to descend into
    348  // subdocuments no matter what, to determine which parts are transparent for
    349  // hit-testing or event regions.
    350  if (!aBuilder->GetDescendIntoSubdocuments()) {
    351    return;
    352  }
    353 
    354  if (isRemoteFrame) {
    355    // We're the subdoc for <browser remote="true"> and it has
    356    // painted content.  Display its shadow layer tree.
    357    DisplayListClipState::AutoSaveRestore clipState(aBuilder);
    358    clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
    359 
    360    aLists.Content()->AppendNewToTop<nsDisplayRemote>(aBuilder, this);
    361    return;
    362  }
    363 
    364  RefPtr<mozilla::PresShell> presShell = GetSubdocumentPresShellForPainting(
    365      aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0);
    366 
    367  if (!presShell) {
    368    return;
    369  }
    370 
    371  if (aBuilder->IsForPainting() && !aBuilder->IsIgnoringPaintSuppression()) {
    372    mLastPaintedPresShell = do_GetWeakReference(presShell);
    373  }
    374 
    375  if (aBuilder->IsInFilter()) {
    376    Document* outerDoc = PresShell()->GetDocument();
    377    Document* innerDoc = presShell->GetDocument();
    378    if (outerDoc && innerDoc) {
    379      if (!outerDoc->NodePrincipal()->Equals(innerDoc->NodePrincipal())) {
    380        outerDoc->SetUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame);
    381      }
    382    }
    383  }
    384 
    385  nsIFrame* subdocRootFrame = presShell->GetRootFrame();
    386 
    387  nsPresContext* presContext = presShell->GetPresContext();
    388 
    389  int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
    390  int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
    391 
    392  nsRect visible;
    393  nsRect dirty;
    394  bool ignoreViewportScrolling = false;
    395  if (subdocRootFrame) {
    396    // get the dirty rect relative to the root frame of the subdoc
    397    visible = aBuilder->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame);
    398    dirty = aBuilder->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame);
    399    // and convert into the appunits of the subdoc
    400    visible = visible.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
    401    dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
    402 
    403    if (ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame()) {
    404      // Use a copy, so the rects don't get modified.
    405      nsRect copyOfDirty = dirty;
    406      nsRect copyOfVisible = visible;
    407      // TODO(botond): Can we just axe this DecideScrollableLayer call?
    408      sf->DecideScrollableLayer(aBuilder, &copyOfVisible, &copyOfDirty,
    409                                /* aSetBase = */ true);
    410 
    411      ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
    412    }
    413 
    414    aBuilder->EnterPresShell(subdocRootFrame, !ContentReactsToPointerEvents());
    415    aBuilder->IncrementPresShellPaintCount(presShell);
    416  } else {
    417    visible = aBuilder->GetVisibleRect();
    418    dirty = aBuilder->GetDirtyRect();
    419  }
    420 
    421  DisplayListClipState::AutoSaveRestore clipState(aBuilder);
    422  clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
    423 
    424  ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame();
    425  bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
    426  bool needsOwnLayer = constructZoomItem ||
    427                       presContext->IsRootContentDocumentCrossProcess() ||
    428                       (sf && sf->IsScrollingActive());
    429 
    430  nsDisplayList childItems(aBuilder);
    431 
    432  if (subdocRootFrame) {
    433    DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
    434    if (needsOwnLayer) {
    435      // Clear current clip. There's no point in propagating it down, since
    436      // the layer we will construct will be clipped by the current clip.
    437      // In fact for nsDisplayZoom propagating it down would be incorrect since
    438      // nsDisplayZoom changes the meaning of appunits.
    439      nestedClipState.Clear();
    440    }
    441 
    442    nsDisplayListBuilder::AutoBuildingDisplayList building(
    443        aBuilder, subdocRootFrame, visible, dirty);
    444    if (aBuilder->BuildCompositorHitTestInfo()) {
    445      bool hasDocumentLevelListenersForApzAwareEvents =
    446          gfxPlatform::AsyncPanZoomEnabled() &&
    447          nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell);
    448 
    449      aBuilder->SetAncestorHasApzAwareEventHandler(
    450          hasDocumentLevelListenersForApzAwareEvents);
    451    }
    452    subdocRootFrame->BuildDisplayListForStackingContext(aBuilder, &childItems);
    453    if (!aBuilder->IsForEventDelivery()) {
    454      // If we are going to use a displayzoom below then any items we put
    455      // under it need to have underlying frames from the subdocument. So we
    456      // need to calculate the bounds based on which frame will be the
    457      // underlying frame for the canvas background color item.
    458      nsRect bounds =
    459          GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
    460      bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
    461 
    462      // Add the canvas background color to the bottom of the list. This
    463      // happens after we've built the list so that
    464      // AddCanvasBackgroundColorItem can monkey with the contents if
    465      // necessary.
    466      presShell->AddCanvasBackgroundColorItem(
    467          aBuilder, &childItems, subdocRootFrame, bounds, NS_RGBA(0, 0, 0, 0));
    468    }
    469  }
    470 
    471  if (subdocRootFrame) {
    472    aBuilder->LeavePresShell(subdocRootFrame, &childItems);
    473  }
    474 
    475  // Generate a resolution and/or zoom item if needed. If one or both of those
    476  // is created, we don't need to create a separate nsDisplaySubDocument.
    477 
    478  nsDisplayOwnLayerFlags flags =
    479      nsDisplayOwnLayerFlags::GenerateSubdocInvalidations;
    480  // If ignoreViewportScrolling is true then the top most layer we create here
    481  // is going to become the scrollable layer for the root scroll frame, so we
    482  // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
    483  // becomes the topmost. We do this below.
    484  if (constructZoomItem) {
    485    nsDisplayOwnLayerFlags zoomFlags = flags;
    486    if (ignoreViewportScrolling) {
    487      zoomFlags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer;
    488    }
    489    childItems.AppendNewToTop<nsDisplayZoom>(aBuilder, subdocRootFrame, this,
    490                                             &childItems, subdocAPD, parentAPD,
    491                                             zoomFlags);
    492 
    493    needsOwnLayer = false;
    494  }
    495  // Wrap the zoom item in the resolution item if we have both because we want
    496  // the resolution scale applied on top of the app units per dev pixel
    497  // conversion.
    498  if (ignoreViewportScrolling) {
    499    flags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer;
    500  }
    501 
    502  // We always want top level content documents to be in their own layer.
    503  nsDisplaySubDocument* layerItem = MakeDisplayItem<nsDisplaySubDocument>(
    504      aBuilder, subdocRootFrame ? subdocRootFrame : this, this, &childItems,
    505      flags);
    506  if (layerItem) {
    507    childItems.AppendToTop(layerItem);
    508    layerItem->SetShouldFlattenAway(!needsOwnLayer);
    509  }
    510 
    511  if (aBuilder->IsForFrameVisibility()) {
    512    // We don't add the childItems to the return list as we're dealing with them
    513    // here.
    514    presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
    515    childItems.DeleteAll(aBuilder);
    516  } else {
    517    aLists.Content()->AppendToTop(&childItems);
    518  }
    519 }
    520 
    521 #ifdef DEBUG_FRAME_DUMP
    522 void nsSubDocumentFrame::List(FILE* out, const char* aPrefix,
    523                              ListFlags aFlags) const {
    524  nsCString str;
    525  ListGeneric(str, aPrefix, aFlags);
    526  fprintf_stderr(out, "%s\n", str.get());
    527 
    528  if (aFlags.contains(ListFlag::TraverseSubdocumentFrames)) {
    529    nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
    530    nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
    531    if (subdocRootFrame) {
    532      nsCString pfx(aPrefix);
    533      pfx += "  ";
    534      subdocRootFrame->List(out, pfx.get(), aFlags);
    535    }
    536  }
    537 }
    538 
    539 nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const {
    540  return MakeFrameName(u"FrameOuter"_ns, aResult);
    541 }
    542 #endif
    543 
    544 nscoord nsSubDocumentFrame::IntrinsicISize(const IntrinsicSizeInput& aInput,
    545                                           IntrinsicISizeType aType) {
    546  // Note: when computing max-content inline size (i.e. when aType is
    547  // IntrinsicISizeType::PrefISize), if the subdocument is an SVG document, then
    548  // in theory we want to return the same value that SVGOuterSVGFrame does. That
    549  // method has some special handling of percentage values to avoid unhelpful
    550  // zero sizing in the presence of orthogonal writing modes. We don't bother
    551  // with that for SVG documents in <embed> and <object>, since that special
    552  // handling doesn't look up across document boundaries anyway.
    553  return GetIntrinsicSize().ISize(GetWritingMode()).valueOr(0);
    554 }
    555 
    556 /* virtual */
    557 IntrinsicSize nsSubDocumentFrame::GetIntrinsicSize() {
    558  return ComputeIntrinsicSize();
    559 }
    560 
    561 IntrinsicSize nsSubDocumentFrame::ComputeIntrinsicSize(
    562    bool aIgnoreContainment) const {
    563  const auto containAxes =
    564      aIgnoreContainment ? ContainSizeAxes(false, false) : GetContainSizeAxes();
    565  if (containAxes.IsBoth()) {
    566    // Intrinsic size of 'contain:size' replaced elements is determined by
    567    // contain-intrinsic-size.
    568    return FinishIntrinsicSize(containAxes, IntrinsicSize(0, 0));
    569  }
    570 
    571  if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
    572    const auto* olc = static_cast<nsObjectLoadingContent*>(iolc.get());
    573    if (auto size = olc->GetSubdocumentIntrinsicSize()) {
    574      // Use the intrinsic size from the child SVG document, if available.
    575      return FinishIntrinsicSize(containAxes, *size);
    576    }
    577  }
    578 
    579  if (!IsInline()) {
    580    return {};  // <frame> elements have no useful intrinsic size.
    581  }
    582 
    583  if (mContent->IsXULElement()) {
    584    return {};  // XUL <iframe> and <browser> have no useful intrinsic size
    585  }
    586 
    587  // We must be an HTML <iframe>. Return fallback size.
    588  return FinishIntrinsicSize(containAxes,
    589                             IntrinsicSize(kFallbackIntrinsicSize));
    590 }
    591 
    592 /* virtual */
    593 AspectRatio nsSubDocumentFrame::GetIntrinsicRatio() const {
    594  // FIXME(emilio): This should probably respect contain: size and return no
    595  // ratio in the case subDocRoot is non-null. Otherwise we do it by virtue of
    596  // using a zero-size below and reusing GetIntrinsicSize().
    597  if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
    598    auto olc = static_cast<nsObjectLoadingContent*>(iolc.get());
    599 
    600    auto ratio = olc->GetSubdocumentIntrinsicRatio();
    601    if (ratio && *ratio) {
    602      // Use the intrinsic aspect ratio from the child SVG document, if
    603      // available.
    604      return *ratio;
    605    }
    606  }
    607 
    608  // NOTE(emilio): Even though we have an intrinsic size, we may not have an
    609  // intrinsic ratio. For example `<iframe style="width: 100px">` should not
    610  // shrink in the vertical axis to preserve the 300x150 ratio.
    611  return nsAtomicContainerFrame::GetIntrinsicRatio();
    612 }
    613 
    614 /* virtual */
    615 nsIFrame::SizeComputationResult nsSubDocumentFrame::ComputeSize(
    616    const SizeComputationInput& aSizingInput, WritingMode aWM,
    617    const LogicalSize& aCBSize, nscoord aAvailableISize,
    618    const LogicalSize& aMargin, const LogicalSize& aBorderPadding,
    619    const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) {
    620  return {ComputeSizeWithIntrinsicDimensions(
    621              aSizingInput.mRenderingContext, aWM, GetIntrinsicSize(),
    622              GetAspectRatio(), aCBSize, aMargin, aBorderPadding,
    623              aSizeOverrides, aFlags),
    624          AspectRatioUsage::None};
    625 }
    626 
    627 void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
    628                                ReflowOutput& aDesiredSize,
    629                                const ReflowInput& aReflowInput,
    630                                nsReflowStatus& aStatus) {
    631  MarkInReflow();
    632  DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
    633  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
    634  NS_FRAME_TRACE(
    635      NS_FRAME_TRACE_CALLS,
    636      ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
    637       aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
    638 
    639  NS_ASSERTION(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE,
    640               "Shouldn't have unconstrained inline-size here "
    641               "thanks to the rules of reflow");
    642  NS_ASSERTION(aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE,
    643               "Shouldn't have unconstrained block-size here "
    644               "thanks to ComputeAutoSize");
    645 
    646  NS_ASSERTION(mContent->GetPrimaryFrame() == this, "Shouldn't happen");
    647 
    648  // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
    649  const auto wm = aReflowInput.GetWritingMode();
    650  aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
    651 
    652  // "offset" is the offset of our content area from our frame's
    653  // top-left corner.
    654  nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left,
    655                           aReflowInput.ComputedPhysicalBorderPadding().top);
    656 
    657  if (nsCOMPtr<nsIDocShell> ds = GetExtantDocShell()) {
    658    const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding();
    659    nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
    660                     aDesiredSize.Height() - bp.TopBottom());
    661 
    662    // Size & position the view according to 'object-fit' & 'object-position'.
    663    const nsRect destRect = GetDestRect(nsRect(offset, innerSize));
    664    auto rect = LayoutDeviceIntRect::FromAppUnitsToInside(
    665        destRect, PresContext()->AppUnitsPerDevPixel());
    666    mExtraOffset = destRect.TopLeft();
    667    nsDocShell::Cast(ds)->SetPositionAndSize(0, 0, rect.width, rect.height,
    668                                             nsIBaseWindow::eDelayResize);
    669  }
    670 
    671  aDesiredSize.SetOverflowAreasToDesiredBounds();
    672 
    673  FinishAndStoreOverflow(&aDesiredSize);
    674 
    675  if (!aPresContext->IsRootPaginatedDocument() && !mPostedReflowCallback) {
    676    PresShell()->PostReflowCallback(this);
    677    mPostedReflowCallback = true;
    678  }
    679 
    680  NS_FRAME_TRACE(
    681      NS_FRAME_TRACE_CALLS,
    682      ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",
    683       aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus).c_str()));
    684 }
    685 
    686 bool nsSubDocumentFrame::ReflowFinished() {
    687  mPostedReflowCallback = false;
    688  nsFrameLoader* fl = FrameLoader();
    689  if (!fl) {
    690    return false;
    691  }
    692  if (fl->IsRemoteFrame() && fl->HasRemoteBrowserBeenSized()) {
    693    // For remote frames we don't need to update the size and position instantly
    694    // (but we should try to do so if we haven't shown it yet).
    695    return false;
    696  }
    697  RefPtr{fl}->UpdatePositionAndSize(this);
    698  return false;
    699 }
    700 
    701 void nsSubDocumentFrame::ReflowCallbackCanceled() {
    702  mPostedReflowCallback = false;
    703 }
    704 
    705 nsresult nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
    706                                              nsAtom* aAttribute, AttrModType) {
    707  if (aNameSpaceID != kNameSpaceID_None) {
    708    return NS_OK;
    709  }
    710 
    711  // If the noResize attribute changes, dis/allow frame to be resized
    712  if (aAttribute == nsGkAtoms::noresize) {
    713    // Note that we're not doing content type checks, but that's ok -- if
    714    // they'd fail we will just end up with a null framesetFrame.
    715    if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) {
    716      nsIFrame* parentFrame = GetParent();
    717 
    718      if (parentFrame) {
    719        // There is no interface for nsHTMLFramesetFrame so QI'ing to
    720        // concrete class, yay!
    721        nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
    722        if (framesetFrame) {
    723          framesetFrame->RecalculateBorderResize();
    724        }
    725      }
    726    }
    727  } else if (aAttribute == nsGkAtoms::marginwidth ||
    728             aAttribute == nsGkAtoms::marginheight) {
    729    // Notify the frameloader
    730    if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
    731      frameloader->MarginsChanged();
    732    }
    733  }
    734 
    735  return NS_OK;
    736 }
    737 
    738 void nsSubDocumentFrame::MaybeUpdateEmbedderColorScheme() {
    739  nsFrameLoader* fl = mFrameLoader.get();
    740  if (!fl) {
    741    return;
    742  }
    743 
    744  BrowsingContext* bc = fl->GetExtantBrowsingContext();
    745  if (!bc) {
    746    return;
    747  }
    748 
    749  auto ToOverride = [](ColorScheme aScheme) -> PrefersColorSchemeOverride {
    750    return aScheme == ColorScheme::Dark ? PrefersColorSchemeOverride::Dark
    751                                        : PrefersColorSchemeOverride::Light;
    752  };
    753 
    754  EmbedderColorSchemes schemes{
    755      ToOverride(LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Used)),
    756      ToOverride(
    757          LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Preferred))};
    758  if (bc->GetEmbedderColorSchemes() == schemes) {
    759    return;
    760  }
    761 
    762  (void)bc->SetEmbedderColorSchemes(schemes);
    763 }
    764 
    765 void nsSubDocumentFrame::MaybeUpdateEmbedderZoom() {
    766  nsFrameLoader* fl = mFrameLoader.get();
    767  if (!fl) {
    768    return;
    769  }
    770 
    771  BrowsingContext* bc = fl->GetExtantBrowsingContext();
    772  if (!bc) {
    773    return;
    774  }
    775 
    776  BrowsingContext* parent = bc->GetParent();
    777  if (!parent) {
    778    // Don't propagate zoom from the top browsing context, i.e. the browser
    779    // frontend. (If we did propagate at that level, we wouldn't be able to
    780    // reliably handle per-tab zoom levels, because the top level context's
    781    // propagated zoom level would replace the per-tab zoom levels.)
    782    return;
    783  }
    784 
    785  // The zoom that we propagate to our child document is parent's full-page-zoom
    786  // level, *combined with* the EffectiveZoom (i.e. the css 'zoom') of this
    787  // embedding frame.
    788  auto newZoom = Style()->EffectiveZoom().Zoom(parent->GetFullZoom());
    789  if (bc->GetFullZoom() == newZoom) {
    790    return;
    791  }
    792  (void)bc->SetFullZoom(newZoom);
    793 }
    794 
    795 void nsSubDocumentFrame::MaybeUpdateRemoteStyle(
    796    ComputedStyle* aOldComputedStyle) {
    797  if (!mIsInObjectOrEmbed) {
    798    return;
    799  }
    800 
    801  if (aOldComputedStyle &&
    802      aOldComputedStyle->StyleVisibility()->mImageRendering ==
    803          Style()->StyleVisibility()->mImageRendering) {
    804    return;
    805  }
    806 
    807  if (!mFrameLoader) {
    808    return;
    809  }
    810 
    811  if (mFrameLoader->IsRemoteFrame()) {
    812    mFrameLoader->UpdateRemoteStyle(
    813        Style()->StyleVisibility()->mImageRendering);
    814    return;
    815  }
    816 
    817  BrowsingContext* context = mFrameLoader->GetExtantBrowsingContext();
    818  if (!context) {
    819    return;
    820  }
    821 
    822  Document* document = context->GetDocument();
    823  if (!document) {
    824    return;
    825  }
    826 
    827  if (document->IsImageDocument()) {
    828    document->AsImageDocument()->UpdateRemoteStyle(
    829        Style()->StyleVisibility()->mImageRendering);
    830  }
    831 }
    832 
    833 void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
    834  nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle);
    835 
    836  if (aOldComputedStyle) {
    837    // If there's no old style, the call in Init() or ShowViewer() should have
    838    // us covered.
    839    MaybeUpdateEmbedderColorScheme();
    840    MaybeUpdateRemoteStyle(aOldComputedStyle);
    841    if (aOldComputedStyle->EffectiveZoom() != Style()->EffectiveZoom()) {
    842      MaybeUpdateEmbedderZoom();
    843    }
    844  }
    845 
    846  // If this presshell has invisible ancestors, we don't need to propagate the
    847  // visibility style change to the subdocument since the subdocument should
    848  // have already set the IsUnderHiddenEmbedderElement flag in
    849  // nsSubDocumentFrame::Init.
    850  if (PresShell()->IsUnderHiddenEmbedderElement()) {
    851    return;
    852  }
    853 
    854  const bool isVisible = StyleVisibility()->IsVisible();
    855  if (!aOldComputedStyle ||
    856      isVisible != aOldComputedStyle->StyleVisibility()->IsVisible()) {
    857    PropagateIsUnderHiddenEmbedderElement(!isVisible);
    858  }
    859 }
    860 
    861 nsIFrame* NS_NewSubDocumentFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
    862  return new (aPresShell)
    863      nsSubDocumentFrame(aStyle, aPresShell->GetPresContext());
    864 }
    865 
    866 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
    867 
    868 class nsHideViewer final : public Runnable {
    869 public:
    870  nsHideViewer(nsIContent* aFrameElement, nsFrameLoader* aFrameLoader,
    871               PresShell* aPresShell, bool aHideViewerIfFrameless)
    872      : mozilla::Runnable("nsHideViewer"),
    873        mFrameElement(aFrameElement),
    874        mFrameLoader(aFrameLoader),
    875        mPresShell(aPresShell),
    876        mHideViewerIfFrameless(aHideViewerIfFrameless) {
    877    NS_ASSERTION(mFrameElement, "Must have a frame element");
    878    NS_ASSERTION(mFrameLoader, "Must have a frame loader");
    879    NS_ASSERTION(mPresShell, "Must have a presshell");
    880  }
    881 
    882  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
    883    // Flush frames, to ensure any pending display:none changes are made.
    884    // Note it can be unsafe to flush if we've destroyed the presentation
    885    // for some other reason, like if we're shutting down.
    886    //
    887    // But avoid the flush if we know for sure we're away, like when we're out
    888    // of the document already.
    889    //
    890    // FIXME(emilio): This could still be a perf footgun when removing lots of
    891    // siblings where each of them cause the reframe of an ancestor which happen
    892    // to contain a subdocument.
    893    //
    894    // We should find some way to avoid that!
    895    if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) {
    896      mPresShell->FlushPendingNotifications(FlushType::Frames);
    897    }
    898 
    899    // Either the frame has been constructed by now, or it never will be,
    900    // either way we want to clear the stashed views.
    901    mFrameLoader->SetDetachedSubdocs({});
    902 
    903    nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
    904    if (!frame || frame->FrameLoader() != mFrameLoader) {
    905      PropagateIsUnderHiddenEmbedderElement(mFrameLoader, true);
    906      if (mHideViewerIfFrameless) {
    907        // The frame element has no nsIFrame for the same frame loader.
    908        // Hide the nsFrameLoader, which destroys the presentation.
    909        mFrameLoader->Hide();
    910      }
    911    }
    912    return NS_OK;
    913  }
    914 
    915 private:
    916  const nsCOMPtr<nsIContent> mFrameElement;
    917  const RefPtr<nsFrameLoader> mFrameLoader;
    918  const RefPtr<PresShell> mPresShell;
    919  const bool mHideViewerIfFrameless;
    920 };
    921 
    922 void nsSubDocumentFrame::Destroy(DestroyContext& aContext) {
    923  if (mPostedReflowCallback) {
    924    PresShell()->CancelReflowCallback(this);
    925    mPostedReflowCallback = false;
    926  }
    927 
    928  // Detach the subdocument's views and stash them in the frame loader.
    929  // We can then reattach them if we're being reframed (for example if
    930  // the frame has been made position:fixed).
    931  if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
    932    ClearDisplayItems();
    933 
    934    PrepareInProcessPresShellsForDetach();
    935    frameloader->SetDetachedSubdocs(std::move(mInProcessPresShells));
    936 
    937    // We call nsFrameLoader::HideViewer() in a script runner so that we can
    938    // safely determine whether the frame is being reframed or destroyed.
    939    nsContentUtils::AddScriptRunner(new nsHideViewer(
    940        mContent, frameloader, PresShell(), (mDidCreateDoc || mCallingShow)));
    941  }
    942 
    943  nsAtomicContainerFrame::Destroy(aContext);
    944 }
    945 
    946 nsFrameLoader* nsSubDocumentFrame::FrameLoader() const {
    947  if (mFrameLoader) {
    948    return mFrameLoader;
    949  }
    950 
    951  if (RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(GetContent())) {
    952    mFrameLoader = loaderOwner->GetFrameLoader();
    953  }
    954 
    955  return mFrameLoader;
    956 }
    957 
    958 auto nsSubDocumentFrame::GetRemotePaintData() const -> RemoteFramePaintData {
    959  if (mRetainedRemoteFrame) {
    960    return *mRetainedRemoteFrame;
    961  }
    962 
    963  RemoteFramePaintData data;
    964  nsFrameLoader* fl = FrameLoader();
    965  if (!fl) {
    966    return data;
    967  }
    968 
    969  auto* rb = fl->GetRemoteBrowser();
    970  if (!rb) {
    971    return data;
    972  }
    973  data.mLayersId = rb->GetLayersId();
    974  data.mTabId = rb->GetTabId();
    975  return data;
    976 }
    977 
    978 void nsSubDocumentFrame::ResetFrameLoader(RetainPaintData aRetain) {
    979  if (aRetain == RetainPaintData::Yes && mFrameLoader) {
    980    mRetainedRemoteFrame = Some(GetRemotePaintData());
    981  } else {
    982    mRetainedRemoteFrame.reset();
    983  }
    984  mFrameLoader = nullptr;
    985  ClearDisplayItems();
    986  nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
    987 }
    988 
    989 void nsSubDocumentFrame::ClearRetainedPaintData() {
    990  mRetainedRemoteFrame.reset();
    991  ClearDisplayItems();
    992  InvalidateFrameSubtree();
    993 }
    994 
    995 // XXX this should be called ObtainDocShell or something like that,
    996 // to indicate that it could have side effects
    997 nsIDocShell* nsSubDocumentFrame::GetDocShell() const {
    998  // How can FrameLoader() return null???
    999  if (NS_WARN_IF(!FrameLoader())) {
   1000    return nullptr;
   1001  }
   1002  return mFrameLoader->GetDocShell(IgnoreErrors());
   1003 }
   1004 
   1005 nsIDocShell* nsSubDocumentFrame::GetExtantDocShell() const {
   1006  return mFrameLoader ? mFrameLoader->GetExistingDocShell() : nullptr;
   1007 }
   1008 
   1009 static void DestroyDisplayItemDataForFrames(nsIFrame* aFrame) {
   1010  // Destroying a WebRenderUserDataTable can cause destruction of other objects
   1011  // which can remove frame properties in their destructor. If we delete a frame
   1012  // property it runs the destructor of the stored object in the middle of
   1013  // updating the frame property table, so if the destruction of that object
   1014  // causes another update to the frame property table it would leave the frame
   1015  // property table in an inconsistent state. So we remove it from the table and
   1016  // then destroy it. (bug 1530657)
   1017  WebRenderUserDataTable* userDataTable =
   1018      aFrame->TakeProperty(WebRenderUserDataProperty::Key());
   1019  if (userDataTable) {
   1020    for (const auto& data : userDataTable->Values()) {
   1021      data->RemoveFromTable();
   1022    }
   1023    delete userDataTable;
   1024  }
   1025 
   1026  for (const auto& childList : aFrame->ChildLists()) {
   1027    for (nsIFrame* child : childList.mList) {
   1028      DestroyDisplayItemDataForFrames(child);
   1029    }
   1030  }
   1031 }
   1032 
   1033 nsresult nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther) {
   1034  if (!aOther || !aOther->IsSubDocumentFrame()) {
   1035    return NS_ERROR_NOT_IMPLEMENTED;
   1036  }
   1037 
   1038  nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
   1039  if (!mFrameLoader || !mDidCreateDoc || mCallingShow || !other->mFrameLoader ||
   1040      !other->mDidCreateDoc) {
   1041    return NS_ERROR_NOT_IMPLEMENTED;
   1042  }
   1043 
   1044  ClearDisplayItems();
   1045  other->ClearDisplayItems();
   1046 
   1047  PrepareInProcessPresShellsForDetach();
   1048  other->PrepareInProcessPresShellsForDetach();
   1049 
   1050  mFrameLoader.swap(other->mFrameLoader);
   1051  return NS_OK;
   1052 }
   1053 
   1054 static CallState EndSwapDocShellsForDocument(Document& aDocument) {
   1055  // Our docshell trees have been updated for the new hierarchy. Now also update
   1056  // all nsDeviceContext::mWidget to that of the container view in the new
   1057  // hierarchy.
   1058  if (nsCOMPtr<nsIDocShell> ds = aDocument.GetDocShell()) {
   1059    nsCOMPtr<nsIDocumentViewer> viewer;
   1060    ds->GetDocViewer(getter_AddRefs(viewer));
   1061    while (viewer) {
   1062      RefPtr<nsPresContext> pc = viewer->GetPresContext();
   1063      if (pc && pc->GetPresShell()) {
   1064        pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
   1065      }
   1066      nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
   1067      if (dc) {
   1068        nsSubDocumentFrame* f = viewer->FindContainerFrame();
   1069        nsIWidget* widget = f ? f->GetNearestWidget() : nullptr;
   1070        if (widget) {
   1071          widget = widget->GetTopLevelWidget();
   1072        }
   1073        dc->Init(widget);
   1074      }
   1075      viewer = viewer->GetPreviousViewer();
   1076    }
   1077  }
   1078 
   1079  aDocument.EnumerateSubDocuments(EndSwapDocShellsForDocument);
   1080  return CallState::Continue;
   1081 }
   1082 
   1083 static CallState BeginSwapDocShellsForDocument(Document& aDocument) {
   1084  if (PresShell* presShell = aDocument.GetPresShell()) {
   1085    // Disable painting while the presentation shell is detached.
   1086    presShell->SetNeverPainting(true);
   1087 
   1088    if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
   1089      ::DestroyDisplayItemDataForFrames(rootFrame);
   1090    }
   1091  }
   1092  aDocument.EnumerateSubDocuments(BeginSwapDocShellsForDocument);
   1093  return CallState::Continue;
   1094 }
   1095 
   1096 void nsSubDocumentFrame::PrepareInProcessPresShellsForDetach() {
   1097  for (const auto& shell : mInProcessPresShells) {
   1098    if (RefPtr<class PresShell> ps = do_QueryReferent(shell)) {
   1099      BeginSwapDocShellsForDocument(*ps->GetDocument());
   1100    }
   1101  }
   1102 }
   1103 
   1104 bool nsSubDocumentFrame::FixUpInProcessPresShellsAfterAttach() {
   1105  bool anyLiveShell = false;
   1106  for (auto& shell : mInProcessPresShells) {
   1107    if (RefPtr<mozilla::PresShell> ps = do_QueryReferent(shell)) {
   1108      if (ps && !ps->IsDestroying()) {
   1109        anyLiveShell = true;
   1110        ps->SetInProcessEmbedderFrame(this);
   1111        EndSwapDocShellsForDocument(*ps->GetDocument());
   1112      }
   1113    }
   1114  }
   1115  return anyLiveShell;
   1116 }
   1117 
   1118 void nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther) {
   1119  auto* other = static_cast<nsSubDocumentFrame*>(aOther);
   1120 
   1121  mInProcessPresShells.SwapElements(other->mInProcessPresShells);
   1122  FixUpInProcessPresShellsAfterAttach();
   1123  other->FixUpInProcessPresShellsAfterAttach();
   1124 
   1125  // Now make sure we reflow both frames, in case their contents
   1126  // determine their size.
   1127  // And repaint them, for good measure, in case there's nothing
   1128  // interesting that happens during reflow.
   1129  PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors,
   1130                                NS_FRAME_IS_DIRTY);
   1131  InvalidateFrameSubtree();
   1132  PropagateIsUnderHiddenEmbedderElement(
   1133      PresShell()->IsUnderHiddenEmbedderElement() ||
   1134      !StyleVisibility()->IsVisible());
   1135 
   1136  other->PresShell()->FrameNeedsReflow(other, IntrinsicDirty::FrameAndAncestors,
   1137                                       NS_FRAME_IS_DIRTY);
   1138  other->InvalidateFrameSubtree();
   1139  other->PropagateIsUnderHiddenEmbedderElement(
   1140      other->PresShell()->IsUnderHiddenEmbedderElement() ||
   1141      !other->StyleVisibility()->IsVisible());
   1142 }
   1143 
   1144 void nsSubDocumentFrame::ClearDisplayItems() {
   1145  if (auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(this)) {
   1146    DL_LOGD("nsSubDocumentFrame::ClearDisplayItems() %p", this);
   1147    builder->ClearRetainedData();
   1148  }
   1149 }
   1150 
   1151 void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
   1152  const nsStylePosition* pos = StylePosition();
   1153  const auto anchorResolutionParams = AnchorPosResolutionParams::From(this);
   1154  bool dependsOnIntrinsics =
   1155      !pos->GetWidth(anchorResolutionParams)->ConvertsToLength() ||
   1156      !pos->GetHeight(anchorResolutionParams)->ConvertsToLength();
   1157 
   1158  if (dependsOnIntrinsics || pos->mObjectFit != StyleObjectFit::Fill) {
   1159    auto dirtyHint = dependsOnIntrinsics
   1160                         ? IntrinsicDirty::FrameAncestorsAndDescendants
   1161                         : IntrinsicDirty::None;
   1162    PresShell()->FrameNeedsReflow(this, dirtyHint, NS_FRAME_IS_DIRTY);
   1163    InvalidateFrame();
   1164  }
   1165 }
   1166 
   1167 bool nsSubDocumentFrame::ContentReactsToPointerEvents() const {
   1168  if (Style()->PointerEvents() == StylePointerEvents::None) {
   1169    return false;
   1170  }
   1171  if (mIsInObjectOrEmbed) {
   1172    if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
   1173      const auto* olc = static_cast<nsObjectLoadingContent*>(iolc.get());
   1174      if (olc->IsSyntheticImageDocument()) {
   1175        return false;
   1176      }
   1177    }
   1178  }
   1179  return true;
   1180 }
   1181 
   1182 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
   1183                                 nsSubDocumentFrame* aFrame)
   1184    : nsPaintedDisplayItem(aBuilder, aFrame),
   1185      mEventRegionsOverride(EventRegionsOverride::NoOverride) {
   1186  if (aBuilder->BuildCompositorHitTestInfo()) {
   1187    if (aBuilder->IsInsidePointerEventsNoneDoc() ||
   1188        !aFrame->ContentReactsToPointerEvents()) {
   1189      mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion;
   1190    }
   1191    if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(
   1192            aFrame->PresShell())) {
   1193      mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
   1194    }
   1195  }
   1196 
   1197  mPaintData = aFrame->GetRemotePaintData();
   1198 }
   1199 
   1200 namespace mozilla {
   1201 
   1202 void nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   1203  DrawTarget* target = aCtx->GetDrawTarget();
   1204  if (!target->IsRecording() || mPaintData.mTabId == 0) {
   1205    NS_WARNING("Remote iframe not rendered");
   1206    return;
   1207  }
   1208 
   1209  // Rendering the inner document will apply a scale to account for its app
   1210  // units per dev pixel ratio. We want to apply the inverse scaling using our
   1211  // app units per dev pixel ratio, so that no actual scaling will be applied if
   1212  // they match. For in-process rendering, nsSubDocumentFrame creates an
   1213  // nsDisplayZoom item if the app units per dev pixel ratio changes.
   1214  //
   1215  // Similarly, rendering the inner document will scale up by the cross process
   1216  // paint scale again, so we also need to account for that.
   1217  const int32_t appUnitsPerDevPixel =
   1218      mFrame->PresContext()->AppUnitsPerDevPixel();
   1219 
   1220  gfxContextMatrixAutoSaveRestore saveMatrix(aCtx);
   1221  gfxFloat targetAuPerDev =
   1222      gfxFloat(AppUnitsPerCSSPixel()) / aCtx->GetCrossProcessPaintScale();
   1223 
   1224  gfxFloat scale = targetAuPerDev / appUnitsPerDevPixel;
   1225  aCtx->Multiply(gfxMatrix::Scaling(scale, scale));
   1226 
   1227  Rect destRect =
   1228      NSRectToSnappedRect(GetContentRect(), targetAuPerDev, *target);
   1229  target->DrawDependentSurface(mPaintData.mTabId, destRect);
   1230 }
   1231 
   1232 bool nsDisplayRemote::CreateWebRenderCommands(
   1233    mozilla::wr::DisplayListBuilder& aBuilder,
   1234    mozilla::wr::IpcResourceUpdateQueue& aResources,
   1235    const StackingContextHelper& aSc,
   1236    mozilla::layers::RenderRootStateManager* aManager,
   1237    nsDisplayListBuilder* aDisplayListBuilder) {
   1238  if (!mPaintData.mLayersId.IsValid()) {
   1239    return true;
   1240  }
   1241 
   1242  auto* subDocFrame = static_cast<nsSubDocumentFrame*>(mFrame);
   1243  nsRect destRect = subDocFrame->GetDestRect();
   1244  if (aDisplayListBuilder->IsForPainting()) {
   1245    subDocFrame->SetRasterScale(aSc.GetInheritedScale());
   1246    const nsRect buildingRect = GetBuildingRect() - ToReferenceFrame();
   1247    Maybe<nsRect> visibleRect =
   1248        buildingRect.EdgeInclusiveIntersection(destRect);
   1249    if (visibleRect) {
   1250      *visibleRect -= destRect.TopLeft();
   1251    }
   1252    subDocFrame->SetVisibleRect(visibleRect);
   1253  }
   1254  nscoord auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   1255  nsPoint layerOffset =
   1256      aDisplayListBuilder->ToReferenceFrame(mFrame) + destRect.TopLeft();
   1257  mOffset = LayoutDevicePoint::FromAppUnits(layerOffset, auPerDevPixel);
   1258 
   1259  destRect.MoveTo(0, 0);
   1260  auto rect = LayoutDeviceRect::FromAppUnits(destRect, auPerDevPixel);
   1261  rect += mOffset;
   1262 
   1263  aBuilder.PushIFrame(rect, !BackfaceIsHidden(),
   1264                      mozilla::wr::AsPipelineId(mPaintData.mLayersId),
   1265                      /*ignoreMissingPipelines*/ true);
   1266 
   1267  return true;
   1268 }
   1269 
   1270 bool nsDisplayRemote::UpdateScrollData(
   1271    mozilla::layers::WebRenderScrollData* aData,
   1272    mozilla::layers::WebRenderLayerScrollData* aLayerData) {
   1273  if (!mPaintData.mLayersId.IsValid()) {
   1274    return true;
   1275  }
   1276 
   1277  if (aLayerData) {
   1278    aLayerData->SetReferentId(mPaintData.mLayersId);
   1279 
   1280    auto size = static_cast<nsSubDocumentFrame*>(mFrame)->GetSubdocumentSize();
   1281    Matrix4x4 m = Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0);
   1282    aLayerData->SetTransform(m);
   1283    aLayerData->SetEventRegionsOverride(mEventRegionsOverride);
   1284    aLayerData->SetRemoteDocumentSize(LayerIntSize(size.width, size.height));
   1285  }
   1286  return true;
   1287 }
   1288 
   1289 nsFrameLoader* nsDisplayRemote::GetFrameLoader() const {
   1290  return static_cast<nsSubDocumentFrame*>(mFrame)->FrameLoader();
   1291 }
   1292 
   1293 }  // namespace mozilla