tor-browser

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

ViewportFrame.cpp (21978B)


      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 that is the root of the frame tree, which contains
      9 * the document's scrollbars and contains fixed-positioned elements
     10 */
     11 
     12 #include "mozilla/ViewportFrame.h"
     13 
     14 #include "MobileViewportManager.h"
     15 #include "mozilla/AbsoluteContainingBlock.h"
     16 #include "mozilla/ComputedStyleInlines.h"
     17 #include "mozilla/PresShell.h"
     18 #include "mozilla/ProfilerLabels.h"
     19 #include "mozilla/RestyleManager.h"
     20 #include "mozilla/ScrollContainerFrame.h"
     21 #include "mozilla/dom/ViewTransition.h"
     22 #include "nsCanvasFrame.h"
     23 #include "nsGkAtoms.h"
     24 #include "nsLayoutUtils.h"
     25 #include "nsPlaceholderFrame.h"
     26 #include "nsSubDocumentFrame.h"
     27 
     28 using namespace mozilla;
     29 
     30 // ScrollContainerFrame can create two other wrap lists for scrollbars and such.
     31 static constexpr uint16_t kFirstTopLayerIndex = 2;
     32 enum class TopLayerIndex : uint16_t {
     33  // The content-accessible top layer (fullscreen, <dialog>, popover).
     34  Content = kFirstTopLayerIndex,
     35  // The view transitions and anonymous content top layer. View transitions need
     36  // to be separate from the content top layer, because the former needs to be
     37  // potentially captured by a view transition, but the later can't be
     38  // (otherwise it'd be cyclic).
     39  // The native anonymous content are for things like the one for DevTools
     40  // highlighters and other non-web-visible UI.
     41  ViewTransitionsAndAnonymousContent,
     42 };
     43 
     44 ViewportFrame* NS_NewViewportFrame(PresShell* aPresShell,
     45                                   ComputedStyle* aStyle) {
     46  return new (aPresShell) ViewportFrame(aStyle, aPresShell->GetPresContext());
     47 }
     48 
     49 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame)
     50 NS_QUERYFRAME_HEAD(ViewportFrame)
     51  NS_QUERYFRAME_ENTRY(ViewportFrame)
     52 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
     53 
     54 void ViewportFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
     55                         nsIFrame* aPrevInFlow) {
     56  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
     57  // No need to call CreateView() here - the frame ctor will call SetView()
     58  // with the ViewManager's root view, so we'll assign it in SetViewInternal().
     59 
     60  nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(this);
     61  if (parent) {
     62    nsFrameState state = parent->GetStateBits();
     63 
     64    AddStateBits(state & (NS_FRAME_IN_POPUP));
     65  }
     66 }
     67 
     68 void ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
     69                                     const nsDisplayListSet& aLists) {
     70  AUTO_PROFILER_LABEL("ViewportFrame::BuildDisplayList",
     71                      GRAPHICS_DisplayListBuilding);
     72 
     73  nsIFrame* kid = mFrames.FirstChild();
     74  if (!kid) {
     75    return;
     76  }
     77 
     78  nsDisplayListCollection set(aBuilder);
     79  BuildDisplayListForChild(aBuilder, kid, set);
     80 
     81  // If we have a scrollframe then it takes care of creating the display list
     82  // for the top layer, but otherwise we need to do it here.
     83  if (!kid->IsScrollContainerFrame()) {
     84    bool isOpaque = false;
     85    if (auto* list = BuildDisplayListForContentTopLayer(aBuilder, &isOpaque)) {
     86      if (isOpaque) {
     87        set.DeleteAll(aBuilder);
     88      }
     89      set.PositionedDescendants()->AppendToTop(list);
     90    }
     91    if (auto* list =
     92            BuildDisplayListForViewTransitionsAndNACTopLayer(aBuilder)) {
     93      set.PositionedDescendants()->AppendToTop(list);
     94    }
     95  }
     96 
     97  set.MoveTo(aLists);
     98 }
     99 
    100 #ifdef DEBUG
    101 // Returns whether we are going to put an element in the top layer for
    102 // fullscreen. This function should matches the CSS rules in ua.css and xul.css.
    103 static bool ShouldInTopLayerForFullscreen(dom::Element* aElement) {
    104  return !aElement->IsRootElement() &&
    105         !aElement->IsXULElement(nsGkAtoms::browser);
    106 }
    107 #endif  // DEBUG
    108 
    109 static void BuildDisplayListForTopLayerFrame(nsDisplayListBuilder* aBuilder,
    110                                             nsIFrame* aFrame,
    111                                             nsDisplayList* aList) {
    112  nsRect visible;
    113  nsRect dirty;
    114  DisplayListClipState::AutoSaveRestore clipState(aBuilder);
    115  nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
    116  if (auto* savedOutOfFlowData =
    117          nsDisplayListBuilder::GetOutOfFlowData(aFrame)) {
    118    visible =
    119        savedOutOfFlowData->GetVisibleRectForFrame(aBuilder, aFrame, &dirty);
    120    // If we are in the top layer, our containing block is the viewport, which
    121    // can't be captured by a view transition on the same document itself.
    122    // Also, the top layer is painted from the root scrollframe, so that
    123    // already takes care of clearing the ASR / clip when captured.
    124    // TODO(emilio): We might need to clear the ASR / clip when coming from the
    125    // viewport (for chrome / XUL docs).
    126    if (!aBuilder->IsInViewTransitionCapture()) {
    127      // This function is called after we've finished building display items for
    128      // the root scroll frame. That means that the content clip from the root
    129      // scroll frame is no longer on aBuilder. However, we need to make sure
    130      // that the display items we build in this function have finite clipped
    131      // bounds with respect to the root ASR, so we restore the *combined clip*
    132      // that we saved earlier. The combined clip will include the clip from the
    133      // root scroll frame.
    134      clipState.SetClipChainForContainingBlockDescendants(
    135          savedOutOfFlowData->mCombinedClipChain);
    136      asrSetter.SetCurrentActiveScrolledRoot(
    137          savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
    138      asrSetter.SetCurrentScrollParentId(savedOutOfFlowData->mScrollParentId);
    139    }
    140  }
    141 
    142  nsDisplayListBuilder::AutoBuildingDisplayList buildingForChild(
    143      aBuilder, aFrame, visible, dirty);
    144 
    145  nsDisplayList list(aBuilder);
    146  aFrame->BuildDisplayListForStackingContext(aBuilder, &list);
    147  aList->AppendToTop(&list);
    148 }
    149 
    150 static bool BackdropListIsOpaque(ViewportFrame* aFrame,
    151                                 nsDisplayListBuilder* aBuilder,
    152                                 nsDisplayList* aList) {
    153  // The common case for ::backdrop elements on the top layer is a single
    154  // fixed position container, holding an opaque background color covering
    155  // the whole viewport.
    156  if (aList->Length() != 1 ||
    157      aList->GetTop()->GetType() != DisplayItemType::TYPE_FIXED_POSITION) {
    158    return false;
    159  }
    160 
    161  // Make sure the fixed position container isn't clipped or scrollable.
    162  nsDisplayFixedPosition* fixed =
    163      static_cast<nsDisplayFixedPosition*>(aList->GetTop());
    164  if (fixed->GetActiveScrolledRoot() || fixed->GetClipChain()) {
    165    return false;
    166  }
    167 
    168  nsDisplayList* children = fixed->GetChildren();
    169  if (!children->GetTop() ||
    170      children->GetTop()->GetType() != DisplayItemType::TYPE_BACKGROUND_COLOR) {
    171    return false;
    172  }
    173 
    174  nsDisplayBackgroundColor* child =
    175      static_cast<nsDisplayBackgroundColor*>(children->GetTop());
    176  if (child->GetActiveScrolledRoot() || child->GetClipChain()) {
    177    return false;
    178  }
    179 
    180  // Check that the background color is both opaque, and covering the
    181  // whole viewport.
    182  bool dummy;
    183  nsRegion opaque = child->GetOpaqueRegion(aBuilder, &dummy);
    184  return opaque.Contains(aFrame->GetRect());
    185 }
    186 
    187 nsDisplayWrapList* ViewportFrame::MaybeWrapTopLayerList(
    188    nsDisplayListBuilder* aBuilder, uint16_t aIndex,
    189    nsDisplayList& aTopLayerList) {
    190  if (aTopLayerList.IsEmpty()) {
    191    return nullptr;
    192  }
    193  nsPoint offset = aBuilder->GetCurrentFrame()->GetOffsetTo(this);
    194  nsDisplayListBuilder::AutoBuildingDisplayList buildingDisplayList(
    195      aBuilder, this, aBuilder->GetVisibleRect() + offset,
    196      aBuilder->GetDirtyRect() + offset);
    197  // Wrap the whole top layer in a single item with maximum z-index,
    198  // and append it at the very end, so that it stays at the topmost.
    199  nsDisplayWrapList* wrapList = MakeDisplayItemWithIndex<nsDisplayWrapper>(
    200      aBuilder, this, aIndex, &aTopLayerList, false);
    201  if (!wrapList) {
    202    return nullptr;
    203  }
    204  wrapList->SetOverrideZIndex(
    205      std::numeric_limits<decltype(wrapList->ZIndex())>::max());
    206  return wrapList;
    207 }
    208 
    209 nsDisplayWrapList* ViewportFrame::BuildDisplayListForContentTopLayer(
    210    nsDisplayListBuilder* aBuilder, bool* aIsOpaque) {
    211  if (aBuilder->AvoidBuildingDuplicateOofs()) {
    212    return nullptr;
    213  }
    214 
    215  nsDisplayList topLayerList(aBuilder);
    216  auto* doc = PresContext()->Document();
    217 
    218  nsTArray<dom::Element*> topLayer = doc->GetTopLayer();
    219  for (dom::Element* elem : topLayer) {
    220    nsIFrame* frame = elem->GetPrimaryFrame();
    221    if (!frame) {
    222      continue;
    223    }
    224    if (frame->GetContent() != elem->AsContent()) {
    225      // area elements in image maps point to the image frame as their primary
    226      // frame but we should treat them like they don't have their own frame
    227      // here. See also bug 135040.
    228      continue;
    229    }
    230 
    231    if (frame->IsHiddenByContentVisibilityOnAnyAncestor(
    232            nsIFrame::IncludeContentVisibility::Hidden)) {
    233      continue;
    234    }
    235 
    236    // There are two cases where an element in fullscreen is not in
    237    // the top layer:
    238    // 1. When building display list for purpose other than painting,
    239    //    it is possible that there is inconsistency between the style
    240    //    info and the content tree.
    241    // 2. This is an element which we are not going to put in the top
    242    //    layer for fullscreen. See ShouldInTopLayerForFullscreen().
    243    // In both cases, we want to skip the frame here and paint it in
    244    // the normal path.
    245    if (frame->StyleDisplay()->mTopLayer == StyleTopLayer::None) {
    246      MOZ_ASSERT(!aBuilder->IsForPainting() ||
    247                 !elem->State().HasState(dom::ElementState::FULLSCREEN) ||
    248                 !ShouldInTopLayerForFullscreen(elem));
    249      continue;
    250    }
    251    MOZ_ASSERT_IF(elem->State().HasState(dom::ElementState::FULLSCREEN),
    252                  ShouldInTopLayerForFullscreen(elem));
    253    // Inner SVG, MathML elements, as well as children of some XUL
    254    // elements are not allowed to be out-of-flow. They should not
    255    // be handled as top layer element here.
    256    if (!frame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
    257      MOZ_ASSERT(!elem->GetParent()->IsHTMLElement(),
    258                 "HTML element should always be out-of-flow if in the top "
    259                 "layer");
    260      continue;
    261    }
    262    if (auto* backdropFrame = nsLayoutUtils::GetBackdropFrame(elem)) {
    263      BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, &topLayerList);
    264      if (aIsOpaque) {
    265        *aIsOpaque = BackdropListIsOpaque(this, aBuilder, &topLayerList);
    266      }
    267    }
    268    BuildDisplayListForTopLayerFrame(aBuilder, frame, &topLayerList);
    269  }
    270 
    271  return MaybeWrapTopLayerList(aBuilder, uint16_t(TopLayerIndex::Content),
    272                               topLayerList);
    273 }
    274 
    275 nsDisplayWrapList*
    276 ViewportFrame::BuildDisplayListForViewTransitionsAndNACTopLayer(
    277    nsDisplayListBuilder* aBuilder) {
    278  if (aBuilder->AvoidBuildingDuplicateOofs()) {
    279    return nullptr;
    280  }
    281 
    282  nsDisplayList topLayerList(aBuilder);
    283  auto* doc = PresContext()->Document();
    284  if (dom::ViewTransition* vt = doc->GetActiveViewTransition()) {
    285    if (dom::Element* root = vt->GetSnapshotContainingBlock()) {
    286      if (nsIFrame* frame = root->GetPrimaryFrame()) {
    287        MOZ_ASSERT(frame->StyleDisplay()->mTopLayer != StyleTopLayer::None,
    288                   "the snapshot containing block should ensure this");
    289        MOZ_ASSERT(frame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
    290        BuildDisplayListForTopLayerFrame(aBuilder, frame, &topLayerList);
    291      }
    292    }
    293  }
    294 
    295  if (dom::Element* container = doc->GetCustomContentContainer()) {
    296    if (nsIFrame* frame = container->GetPrimaryFrame()) {
    297      MOZ_ASSERT(frame->StyleDisplay()->mTopLayer != StyleTopLayer::None,
    298                 "ua.css should ensure this");
    299      MOZ_ASSERT(frame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
    300      BuildDisplayListForTopLayerFrame(aBuilder, frame, &topLayerList);
    301    }
    302  }
    303 
    304  return MaybeWrapTopLayerList(
    305      aBuilder, uint16_t(TopLayerIndex::ViewTransitionsAndAnonymousContent),
    306      topLayerList);
    307 }
    308 
    309 #ifdef DEBUG
    310 void ViewportFrame::AppendFrames(ChildListID aListID,
    311                                 nsFrameList&& aFrameList) {
    312  NS_ASSERTION(aListID == FrameChildListID::Principal, "unexpected child list");
    313  NS_ASSERTION(GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
    314  nsContainerFrame::AppendFrames(aListID, std::move(aFrameList));
    315 }
    316 
    317 void ViewportFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
    318                                 const nsLineList::iterator* aPrevFrameLine,
    319                                 nsFrameList&& aFrameList) {
    320  NS_ASSERTION(aListID == FrameChildListID::Principal, "unexpected child list");
    321  NS_ASSERTION(GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
    322  nsContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine,
    323                                 std::move(aFrameList));
    324 }
    325 
    326 void ViewportFrame::RemoveFrame(DestroyContext& aContext, ChildListID aListID,
    327                                nsIFrame* aOldFrame) {
    328  NS_ASSERTION(aListID == FrameChildListID::Principal, "unexpected child list");
    329  nsContainerFrame::RemoveFrame(aContext, aListID, aOldFrame);
    330 }
    331 #endif
    332 
    333 void ViewportFrame::Destroy(DestroyContext& aContext) {
    334  if (PresShell()->IsDestroying()) {
    335    PresShell::ClearMouseCapture(this);
    336  }
    337  nsContainerFrame::Destroy(aContext);
    338 }
    339 
    340 nscoord ViewportFrame::IntrinsicISize(const IntrinsicSizeInput& aInput,
    341                                      IntrinsicISizeType aType) {
    342  return mFrames.IsEmpty()
    343             ? 0
    344             : mFrames.FirstChild()->IntrinsicISize(aInput, aType);
    345 }
    346 
    347 nsRect ViewportFrame::GetContainingBlockAdjustedForScrollbars(
    348    const ReflowInput& aReflowInput) const {
    349  const WritingMode wm = aReflowInput.GetWritingMode();
    350 
    351  LogicalSize computedSize = aReflowInput.ComputedSize();
    352  const nsPoint& origin = [&]() {
    353    // Get our prinicpal child frame and see if we're scrollable
    354    nsIFrame* kidFrame = mFrames.FirstChild();
    355    if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(kidFrame)) {
    356      // Note: In ReflowInput::CalculateHypotheticalPosition(), we exclude the
    357      // scrollbar or scrollbar-gutter area when computing the offset to
    358      // ViewportFrame. Ensure the code there remains in sync with the logic
    359      // here.
    360      LogicalMargin scrollbars(wm,
    361                               scrollContainerFrame->GetActualScrollbarSizes());
    362      computedSize.ISize(wm) =
    363          std::max(0, aReflowInput.ComputedISize() - scrollbars.IStartEnd(wm));
    364      computedSize.BSize(wm) =
    365          std::max(0, aReflowInput.ComputedBSize() - scrollbars.BStartEnd(wm));
    366      return nsPoint(scrollbars.Left(wm), scrollbars.Top(wm));
    367    }
    368    return nsPoint(0, 0);
    369  }();
    370 
    371  nsRect rect(origin, computedSize.GetPhysicalSize(wm));
    372  rect.SizeTo(AdjustViewportSizeForFixedPosition(rect));
    373 
    374  return rect;
    375 }
    376 
    377 void ViewportFrame::Reflow(nsPresContext* aPresContext,
    378                           ReflowOutput& aDesiredSize,
    379                           const ReflowInput& aReflowInput,
    380                           nsReflowStatus& aStatus) {
    381  MarkInReflow();
    382  DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
    383  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
    384  NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow");
    385 
    386  // Because |Reflow| sets ComputedBSize() on the child to our
    387  // ComputedBSize().
    388  AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
    389 
    390  // Set our size up front, since some parts of reflow depend on it
    391  // being already set.  Note that the computed height may be
    392  // unconstrained; that's ok.  Consumers should watch out for that.
    393  SetSize(aReflowInput.ComputedPhysicalSize());
    394 
    395  // Reflow the main content first so that the placeholders of the
    396  // fixed-position frames will be in the right places on an initial
    397  // reflow.
    398  nscoord kidBSize = 0;
    399  WritingMode wm = aReflowInput.GetWritingMode();
    400 
    401  if (mFrames.NotEmpty()) {
    402    // Deal with a non-incremental reflow or an incremental reflow
    403    // targeted at our one-and-only principal child frame.
    404    if (aReflowInput.ShouldReflowAllKids() ||
    405        mFrames.FirstChild()->IsSubtreeDirty()) {
    406      // Reflow our one-and-only principal child frame
    407      nsIFrame* kidFrame = mFrames.FirstChild();
    408      ReflowOutput kidDesiredSize(aReflowInput);
    409      const WritingMode kidWM = kidFrame->GetWritingMode();
    410      LogicalSize availableSpace = aReflowInput.AvailableSize(kidWM);
    411      ReflowInput kidReflowInput(aPresContext, aReflowInput, kidFrame,
    412                                 availableSpace);
    413 
    414      // Reflow the frame
    415      kidReflowInput.SetComputedBSize(aReflowInput.ComputedBSize());
    416      if (aReflowInput.IsBResizeForWM(kidWM)) {
    417        kidReflowInput.SetBResize(true);
    418      }
    419      if (aReflowInput.IsBResizeForPercentagesForWM(kidWM)) {
    420        kidReflowInput.SetBResizeForPercentages(true);
    421      }
    422      ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowInput, 0, 0,
    423                  ReflowChildFlags::Default, aStatus);
    424      kidBSize = kidDesiredSize.BSize(wm);
    425 
    426      FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, &kidReflowInput,
    427                        0, 0, ReflowChildFlags::Default);
    428    } else {
    429      kidBSize = LogicalSize(wm, mFrames.FirstChild()->GetSize()).BSize(wm);
    430    }
    431  }
    432 
    433  NS_ASSERTION(aReflowInput.AvailableISize() != NS_UNCONSTRAINEDSIZE,
    434               "shouldn't happen anymore");
    435 
    436  // Return the max size as our desired size
    437  LogicalSize maxSize(wm, aReflowInput.AvailableISize(),
    438                      // Being flowed initially at an unconstrained block size
    439                      // means we should return our child's intrinsic size.
    440                      aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE
    441                          ? aReflowInput.ComputedBSize()
    442                          : kidBSize);
    443  aDesiredSize.SetSize(wm, maxSize);
    444  aDesiredSize.SetOverflowAreasToDesiredBounds();
    445 
    446  if (HasAbsolutelyPositionedChildren()) {
    447    // Make a copy of the reflow input and change the computed block size to
    448    // reflect the available space for the fixed items
    449    ReflowInput reflowInput(aReflowInput);
    450 
    451    if (reflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
    452      // We have an intrinsic-block-size document with abs-pos/fixed-pos
    453      // children. Set the available block-size and computed block-size to our
    454      // chosen block-size.
    455      reflowInput.SetAvailableBSize(maxSize.BSize(wm));
    456      // Not having border/padding simplifies things
    457      NS_ASSERTION(reflowInput.ComputedPhysicalBorderPadding() == nsMargin(),
    458                   "Viewports can't have border/padding");
    459      reflowInput.SetComputedBSize(maxSize.BSize(wm));
    460    }
    461 
    462    // The containing block for children. We intentionally not take scrollbar
    463    // size and dynamic toolbar into account because
    464    // ::-moz-snapshot-containing-block should include those areas.
    465    //
    466    // We will take them into account in AbsoluteContainingBlock::Reflow(),
    467    // for kid frames other than ::-moz-snapshot-containing-block.
    468    const nsRect cb(nsPoint(), reflowInput.ComputedPhysicalSize());
    469    // XXX: To optimize the performance, set the flags only when the CB width or
    470    // height actually changes.
    471    AbsPosReflowFlags flags{AbsPosReflowFlag::CBWidthChanged,
    472                            AbsPosReflowFlag::CBHeightChanged};
    473    GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowInput,
    474                                         aStatus, cb, flags,
    475                                         /* aOverflowAreas = */ nullptr);
    476  }
    477 
    478  if (mFrames.NotEmpty()) {
    479    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild());
    480  }
    481 
    482  // If we were dirty then do a repaint
    483  if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) {
    484    InvalidateFrame();
    485  }
    486 
    487  // Clipping is handled by the document container (e.g., nsSubDocumentFrame),
    488  // so we don't need to change our overflow areas.
    489  FinishAndStoreOverflow(&aDesiredSize);
    490 
    491  NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus);
    492 }
    493 
    494 void ViewportFrame::UpdateStyle(ServoRestyleState& aRestyleState) {
    495  RefPtr<ComputedStyle> newStyle =
    496      aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
    497          Style()->GetPseudoType(), nullptr);
    498 
    499  MOZ_ASSERT(!GetNextContinuation(), "Viewport has continuations?");
    500  SetComputedStyle(newStyle);
    501 
    502  UpdateStyleOfOwnedAnonBoxes(aRestyleState);
    503 }
    504 
    505 void ViewportFrame::AppendDirectlyOwnedAnonBoxes(
    506    nsTArray<OwnedAnonBox>& aResult) {
    507  if (mFrames.NotEmpty()) {
    508    aResult.AppendElement(mFrames.FirstChild());
    509  }
    510 }
    511 
    512 nsSize ViewportFrame::AdjustViewportSizeForFixedPosition(
    513    const nsRect& aViewportRect) const {
    514  nsSize result = aViewportRect.Size();
    515 
    516  mozilla::PresShell* presShell = PresShell();
    517  // Layout fixed position elements to the visual viewport size if and only if
    518  // it has been set and it is larger than the computed size, otherwise use the
    519  // computed size.
    520  if (presShell->IsVisualViewportSizeSet()) {
    521    if (presShell->GetDynamicToolbarState() == DynamicToolbarState::Collapsed &&
    522        result < presShell->GetVisualViewportSizeUpdatedByDynamicToolbar()) {
    523      // We need to use the viewport size updated by the dynamic toolbar in the
    524      // case where the dynamic toolbar is completely hidden.
    525      result = presShell->GetVisualViewportSizeUpdatedByDynamicToolbar();
    526    } else if (result < presShell->GetVisualViewportSize()) {
    527      result = presShell->GetVisualViewportSize();
    528    }
    529  }
    530  // Expand the size to the layout viewport size if necessary.
    531  const nsSize layoutViewportSize = presShell->GetLayoutViewportSize();
    532  if (result < layoutViewportSize) {
    533    result = layoutViewportSize;
    534  }
    535 
    536  return result;
    537 }
    538 
    539 #ifdef DEBUG_FRAME_DUMP
    540 nsresult ViewportFrame::GetFrameName(nsAString& aResult) const {
    541  return MakeFrameName(u"Viewport"_ns, aResult);
    542 }
    543 #endif