tor-browser

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

nsCSSFrameConstructor.cpp (468395B)


      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 * construction of a frame tree that is nearly isomorphic to the content
      9 * tree and updating of that tree in response to dynamic changes
     10 */
     11 
     12 #include "nsCSSFrameConstructor.h"
     13 
     14 #include "ActiveLayerTracker.h"
     15 #include "ChildIterator.h"
     16 #include "RetainedDisplayListBuilder.h"
     17 #include "RubyUtils.h"
     18 #include "StickyScrollContainer.h"
     19 #include "mozilla/AbsoluteContainingBlock.h"
     20 #include "mozilla/Assertions.h"
     21 #include "mozilla/AutoRestore.h"
     22 #include "mozilla/ComputedStyleInlines.h"
     23 #include "mozilla/DebugOnly.h"
     24 #include "mozilla/ErrorResult.h"
     25 #include "mozilla/Likely.h"
     26 #include "mozilla/ManualNAC.h"
     27 #include "mozilla/PresShell.h"
     28 #include "mozilla/PresShellInlines.h"
     29 #include "mozilla/PrintedSheetFrame.h"
     30 #include "mozilla/ProfilerLabels.h"
     31 #include "mozilla/ProfilerMarkers.h"
     32 #include "mozilla/RestyleManager.h"
     33 #include "mozilla/SVGGradientFrame.h"
     34 #include "mozilla/ScopeExit.h"
     35 #include "mozilla/ScrollContainerFrame.h"
     36 #include "mozilla/ServoBindings.h"
     37 #include "mozilla/ServoStyleSetInlines.h"
     38 #include "mozilla/StaticPrefs_browser.h"
     39 #include "mozilla/StaticPrefs_layout.h"
     40 #include "mozilla/StaticPrefs_mathml.h"
     41 #include "mozilla/dom/BindContext.h"
     42 #include "mozilla/dom/BrowsingContext.h"
     43 #include "mozilla/dom/CharacterData.h"
     44 #include "mozilla/dom/CharacterDataBuffer.h"
     45 #include "mozilla/dom/Document.h"
     46 #include "mozilla/dom/DocumentInlines.h"
     47 #include "mozilla/dom/Element.h"
     48 #include "mozilla/dom/ElementInlines.h"
     49 #include "mozilla/dom/GeneratedImageContent.h"
     50 #include "mozilla/dom/HTMLInputElement.h"
     51 #include "mozilla/dom/HTMLSelectElement.h"
     52 #include "mozilla/dom/HTMLSharedListElement.h"
     53 #include "mozilla/dom/HTMLSummaryElement.h"
     54 #include "mozilla/intl/LocaleService.h"
     55 #include "nsAtom.h"
     56 #include "nsAutoLayoutPhase.h"
     57 #include "nsBlockFrame.h"
     58 #include "nsCRT.h"
     59 #include "nsCSSAnonBoxes.h"
     60 #include "nsCSSPseudoElements.h"
     61 #include "nsCanvasFrame.h"
     62 #include "nsCheckboxRadioFrame.h"
     63 #include "nsComboboxControlFrame.h"
     64 #include "nsContainerFrame.h"
     65 #include "nsContentUtils.h"
     66 #include "nsError.h"
     67 #include "nsFieldSetFrame.h"
     68 #include "nsFirstLetterFrame.h"
     69 #include "nsFlexContainerFrame.h"
     70 #include "nsGkAtoms.h"
     71 #include "nsGridContainerFrame.h"
     72 #include "nsHTMLParts.h"
     73 #include "nsIAnonymousContentCreator.h"
     74 #include "nsIFormControl.h"
     75 #include "nsIFrameInlines.h"
     76 #include "nsIObjectLoadingContent.h"
     77 #include "nsIPopupContainer.h"
     78 #include "nsIScriptError.h"
     79 #include "nsImageFrame.h"
     80 #include "nsInlineFrame.h"
     81 #include "nsLayoutUtils.h"
     82 #include "nsListControlFrame.h"
     83 #include "nsMathMLParts.h"
     84 #include "nsNameSpaceManager.h"
     85 #include "nsPageContentFrame.h"
     86 #include "nsPageFrame.h"
     87 #include "nsPageSequenceFrame.h"
     88 #include "nsPlaceholderFrame.h"
     89 #include "nsPresContext.h"
     90 #include "nsRefreshDriver.h"
     91 #include "nsRubyBaseContainerFrame.h"
     92 #include "nsRubyBaseFrame.h"
     93 #include "nsRubyFrame.h"
     94 #include "nsRubyTextContainerFrame.h"
     95 #include "nsRubyTextFrame.h"
     96 #include "nsStyleConsts.h"
     97 #include "nsStyleStructInlines.h"
     98 #include "nsTArray.h"
     99 #include "nsTableCellFrame.h"
    100 #include "nsTableColFrame.h"
    101 #include "nsTableFrame.h"
    102 #include "nsTableRowFrame.h"
    103 #include "nsTableRowGroupFrame.h"
    104 #include "nsTableWrapperFrame.h"
    105 #include "nsTextNode.h"
    106 #include "nsTransitionManager.h"
    107 #include "nsUnicharUtils.h"
    108 #include "nsXULElement.h"
    109 
    110 #ifdef XP_MACOSX
    111 #  include "nsIDocShell.h"
    112 #endif
    113 
    114 #ifdef ACCESSIBILITY
    115 #  include "nsAccessibilityService.h"
    116 #endif
    117 
    118 #undef NOISY_FIRST_LETTER
    119 
    120 using namespace mozilla;
    121 using namespace mozilla::dom;
    122 
    123 nsIFrame* NS_NewHTMLCanvasFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    124 
    125 nsIFrame* NS_NewHTMLVideoFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    126 nsIFrame* NS_NewHTMLAudioFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    127 
    128 nsContainerFrame* NS_NewSVGOuterSVGFrame(PresShell* aPresShell,
    129                                         ComputedStyle* aStyle);
    130 nsContainerFrame* NS_NewSVGOuterSVGAnonChildFrame(PresShell* aPresShell,
    131                                                  ComputedStyle* aStyle);
    132 nsIFrame* NS_NewSVGInnerSVGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    133 nsIFrame* NS_NewSVGGeometryFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    134 nsIFrame* NS_NewSVGGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    135 nsContainerFrame* NS_NewSVGForeignObjectFrame(PresShell* aPresShell,
    136                                              ComputedStyle* aStyle);
    137 nsIFrame* NS_NewSVGAFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    138 nsIFrame* NS_NewSVGSwitchFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    139 nsIFrame* NS_NewSVGSymbolFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    140 nsIFrame* NS_NewSVGTextFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    141 nsIFrame* NS_NewSVGContainerFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    142 nsIFrame* NS_NewSVGUseFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    143 nsIFrame* NS_NewSVGViewFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    144 extern nsIFrame* NS_NewSVGLinearGradientFrame(PresShell* aPresShell,
    145                                              ComputedStyle* aStyle);
    146 extern nsIFrame* NS_NewSVGRadialGradientFrame(PresShell* aPresShell,
    147                                              ComputedStyle* aStyle);
    148 extern nsIFrame* NS_NewSVGStopFrame(PresShell* aPresShell,
    149                                    ComputedStyle* aStyle);
    150 nsContainerFrame* NS_NewSVGMarkerFrame(PresShell* aPresShell,
    151                                       ComputedStyle* aStyle);
    152 nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(PresShell* aPresShell,
    153                                                ComputedStyle* aStyle);
    154 extern nsIFrame* NS_NewSVGImageFrame(PresShell* aPresShell,
    155                                     ComputedStyle* aStyle);
    156 nsIFrame* NS_NewSVGClipPathFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    157 nsIFrame* NS_NewSVGFilterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    158 nsIFrame* NS_NewSVGPatternFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    159 nsIFrame* NS_NewSVGMaskFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    160 nsIFrame* NS_NewSVGFEContainerFrame(PresShell* aPresShell,
    161                                    ComputedStyle* aStyle);
    162 nsIFrame* NS_NewSVGFELeafFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    163 nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    164 nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
    165                                       ComputedStyle* aStyle);
    166 nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
    167 nsIFrame* NS_NewComboboxLabelFrame(PresShell*, ComputedStyle*);
    168 nsIFrame* NS_NewMiddleCroppingLabelFrame(PresShell*, ComputedStyle*);
    169 nsIFrame* NS_NewInputButtonControlFrame(PresShell*, ComputedStyle*);
    170 
    171 #include "mozilla/dom/NodeInfo.h"
    172 #include "nsContentCreatorFunctions.h"
    173 #include "nsNodeInfoManager.h"
    174 #include "prenv.h"
    175 
    176 #ifdef DEBUG
    177 // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
    178 // more of the following flags (comma separated) for handy debug
    179 // output.
    180 static bool gNoisyContentUpdates = false;
    181 static bool gReallyNoisyContentUpdates = false;
    182 static bool gNoisyInlineConstruction = false;
    183 
    184 struct FrameCtorDebugFlags {
    185  const char* name;
    186  bool* on;
    187 };
    188 
    189 static FrameCtorDebugFlags gFrameCtorDebugFlags[] = {
    190    {"content-updates", &gNoisyContentUpdates},
    191    {"really-noisy-content-updates", &gReallyNoisyContentUpdates},
    192    {"noisy-inline", &gNoisyInlineConstruction}};
    193 
    194 #  define NUM_DEBUG_FLAGS (std::size(gFrameCtorDebugFlags))
    195 #endif
    196 
    197 //------------------------------------------------------------------
    198 
    199 nsIFrame* NS_NewLeafBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    200 
    201 nsIFrame* NS_NewRangeFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    202 
    203 nsIFrame* NS_NewTextBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    204 
    205 nsIFrame* NS_NewSplitterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    206 
    207 nsIFrame* NS_NewMenuPopupFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    208 
    209 nsIFrame* NS_NewTreeBodyFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    210 
    211 nsIFrame* NS_NewSliderFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    212 
    213 nsIFrame* NS_NewScrollbarFrame(PresShell* aPresShell, ComputedStyle* aStyle);
    214 
    215 nsIFrame* NS_NewScrollbarButtonFrame(PresShell*, ComputedStyle*);
    216 nsIFrame* NS_NewSimpleXULLeafFrame(PresShell*, ComputedStyle*);
    217 
    218 nsIFrame* NS_NewXULImageFrame(PresShell*, ComputedStyle*);
    219 nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
    220 nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*);
    221 nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*);
    222 nsIFrame* NS_NewImageFrameForViewTransition(PresShell*, ComputedStyle*);
    223 
    224 // Returns true if aFrame is an anonymous flex/grid item.
    225 static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
    226  return aFrame->Style()->GetPseudoType() == PseudoStyleType::anonymousItem;
    227 }
    228 
    229 // Returns true IFF the given nsIFrame is a nsFlexContainerFrame and represents
    230 // a -webkit-{inline-}box container.
    231 static inline bool IsFlexContainerForLegacyWebKitBox(const nsIFrame* aFrame) {
    232  return aFrame->IsFlexContainerFrame() && aFrame->IsLegacyWebkitBox();
    233 }
    234 
    235 #if DEBUG
    236 static void AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
    237                                                const nsIFrame* aParent) {
    238  MOZ_ASSERT(IsAnonymousItem(aChild), "expected an anonymous item child frame");
    239  MOZ_ASSERT(aParent, "expected a parent frame");
    240  MOZ_ASSERT(aParent->IsFlexOrGridContainer(),
    241             "anonymous items should only exist as children of flex/grid "
    242             "container frames");
    243 }
    244 #else
    245 #  define AssertAnonymousFlexOrGridItemParent(x, y) PR_BEGIN_MACRO PR_END_MACRO
    246 #endif
    247 
    248 #define ToCreationFunc(_func)                              \
    249  [](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { \
    250    return _func(aPs, aStyle);                             \
    251  }
    252 
    253 /**
    254 * True if aFrame is an actual inline frame in the sense of non-replaced
    255 * display:inline CSS boxes.  In other words, it can be affected by {ib}
    256 * splitting and can contain first-letter frames.  Basically, this is either an
    257 * inline frame (positioned or otherwise) or an line frame (this last because
    258 * it can contain first-letter and because inserting blocks in the middle of it
    259 * needs to terminate it).
    260 */
    261 static bool IsInlineFrame(const nsIFrame* aFrame) {
    262  return aFrame->IsLineParticipant();
    263 }
    264 
    265 /**
    266 * True for display: contents elements.
    267 */
    268 static inline bool IsDisplayContents(const Element* aElement) {
    269  return aElement->IsDisplayContents();
    270 }
    271 
    272 static inline bool IsDisplayContents(const nsIContent* aContent) {
    273  return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
    274 }
    275 
    276 /**
    277 * True if aFrame is an instance of an SVG frame class or is an inline/block
    278 * frame being used for SVG text.
    279 */
    280 static bool IsFrameForSVG(const nsIFrame* aFrame) {
    281  return aFrame->IsSVGFrame() || aFrame->IsInSVGTextSubtree();
    282 }
    283 
    284 static bool IsLastContinuationForColumnContent(const nsIFrame* aFrame) {
    285  MOZ_ASSERT(aFrame);
    286  return aFrame->Style()->GetPseudoType() == PseudoStyleType::columnContent &&
    287         !aFrame->GetNextContinuation();
    288 }
    289 
    290 /**
    291 * Returns true iff aFrame explicitly prevents its descendants from floating
    292 * (at least, down to the level of descendants which themselves are
    293 * float-containing blocks -- those will manage the floating status of any
    294 * lower-level descendents inside them, of course).
    295 */
    296 static bool ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame) {
    297  return aFrame->IsFlexOrGridContainer() || aFrame->IsMathMLFrame();
    298 }
    299 
    300 // Return true if column-span descendants should be suppressed under aFrame's
    301 // subtree (until a multi-column container re-establishing a block formatting
    302 // context). Basically, this is testing whether aFrame establishes a new block
    303 // formatting context or not.
    304 static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) {
    305  if (aFrame->Style()->GetPseudoType() == PseudoStyleType::columnContent) {
    306    // Never suppress column-span under ::-moz-column-content frames.
    307    return false;
    308  }
    309 
    310  if (aFrame->IsInlineFrame()) {
    311    // Allow inline frames to have column-span block children.
    312    return false;
    313  }
    314 
    315  if (!aFrame->IsBlockFrameOrSubclass() ||
    316      aFrame->HasAnyStateBits(NS_BLOCK_BFC | NS_FRAME_OUT_OF_FLOW) ||
    317      aFrame->IsFixedPosContainingBlock()) {
    318    // Need to suppress column-span if we:
    319    // - Are a different block formatting context,
    320    // - Are an out-of-flow frame, OR
    321    // - Establish a containing block for fixed-position descendants
    322    //
    323    // For example, the children of a column-span never need to be further
    324    // processed even if there is a nested column-span child. Because a
    325    // column-span always creates its own block formatting context, a nested
    326    // column-span child won't be in the same block formatting context with the
    327    // nearest multi-column ancestor. This is the same case as if the
    328    // column-span is outside of a multi-column hierarchy.
    329    return true;
    330  }
    331 
    332  return false;
    333 }
    334 
    335 // Reparent a frame into a wrapper frame that is a child of its old parent.
    336 static void ReparentFrame(RestyleManager* aRestyleManager,
    337                          nsContainerFrame* aNewParentFrame, nsIFrame* aFrame,
    338                          bool aForceStyleReparent) {
    339  aFrame->SetParent(aNewParentFrame);
    340  // We reparent frames for two reasons: to put them inside ::first-line, and to
    341  // put them inside some wrapper anonymous boxes.
    342  if (aForceStyleReparent) {
    343    aRestyleManager->ReparentComputedStyleForFirstLine(aFrame);
    344  }
    345 }
    346 
    347 static void ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
    348                           nsContainerFrame* aNewParentFrame,
    349                           const nsFrameList& aFrameList,
    350                           bool aForceStyleReparent) {
    351  RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
    352  for (nsIFrame* f : aFrameList) {
    353    ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
    354  }
    355 }
    356 
    357 //----------------------------------------------------------------------
    358 //
    359 // When inline frames get weird and have block frames in them, we
    360 // annotate them to help us respond to incremental content changes
    361 // more easily.
    362 
    363 static inline bool IsFramePartOfIBSplit(nsIFrame* aFrame) {
    364  bool result = aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT);
    365  MOZ_ASSERT(!result || static_cast<nsBlockFrame*>(do_QueryFrame(aFrame)) ||
    366                 static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)),
    367             "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT");
    368  return result;
    369 }
    370 
    371 static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) {
    372  MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
    373 
    374  // We only store the "ib-split sibling" annotation with the first
    375  // frame in the continuation chain. Walk back to find that frame now.
    376  return aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
    377 }
    378 
    379 static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) {
    380  MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
    381 
    382  // We only store the ib-split sibling annotation with the first
    383  // frame in the continuation chain. Walk back to find that frame now.
    384  return aFrame->FirstContinuation()->GetProperty(
    385      nsIFrame::IBSplitPrevSibling());
    386 }
    387 
    388 static nsContainerFrame* GetLastIBSplitSibling(nsIFrame* aFrame) {
    389  for (nsIFrame *frame = aFrame, *next;; frame = next) {
    390    next = GetIBSplitSibling(frame);
    391    if (!next) {
    392      return static_cast<nsContainerFrame*>(frame);
    393    }
    394  }
    395  MOZ_ASSERT_UNREACHABLE("unreachable code");
    396  return nullptr;
    397 }
    398 
    399 static void SetFrameIsIBSplit(nsContainerFrame* aFrame,
    400                              nsContainerFrame* aIBSplitSibling) {
    401  MOZ_ASSERT(aFrame, "bad args!");
    402 
    403  // We should be the only continuation
    404  NS_ASSERTION(!aFrame->GetPrevContinuation(),
    405               "assigning ib-split sibling to other than first continuation!");
    406  NS_ASSERTION(!aFrame->GetNextContinuation() ||
    407                   IsFramePartOfIBSplit(aFrame->GetNextContinuation()),
    408               "should have no non-ib-split continuations here");
    409 
    410  // Mark the frame as ib-split.
    411  aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
    412 
    413  if (aIBSplitSibling) {
    414    NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),
    415                 "assigning something other than the first continuation as the "
    416                 "ib-split sibling");
    417 
    418    // Store the ib-split sibling (if we were given one) with the
    419    // first frame in the flow.
    420    aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
    421    aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
    422  }
    423 }
    424 
    425 static nsIFrame* GetIBContainingBlockFor(nsIFrame* aFrame) {
    426  MOZ_ASSERT(
    427      IsFramePartOfIBSplit(aFrame),
    428      "GetIBContainingBlockFor() should only be called on known IB frames");
    429 
    430  // Get the first "normal" ancestor of the target frame.
    431  nsIFrame* parentFrame;
    432  do {
    433    parentFrame = aFrame->GetParent();
    434 
    435    if (!parentFrame) {
    436      NS_ERROR("no unsplit block frame in IB hierarchy");
    437      return aFrame;
    438    }
    439 
    440    // Note that we ignore non-ib-split frames which have a pseudo on their
    441    // ComputedStyle -- they're not the frames we're looking for!  In
    442    // particular, they may be hiding a real parent that _is_ in an ib-split.
    443    if (!IsFramePartOfIBSplit(parentFrame) &&
    444        !parentFrame->Style()->IsPseudoOrAnonBox()) {
    445      break;
    446    }
    447 
    448    aFrame = parentFrame;
    449  } while (true);
    450 
    451  // post-conditions
    452  NS_ASSERTION(parentFrame,
    453               "no normal ancestor found for ib-split frame "
    454               "in GetIBContainingBlockFor");
    455  NS_ASSERTION(parentFrame != aFrame,
    456               "parentFrame is actually the child frame - bogus reslt");
    457 
    458  return parentFrame;
    459 }
    460 
    461 // Find the multicol containing block suitable for reframing.
    462 //
    463 // Note: this function may not return a ColumnSetWrapperFrame. For example, if
    464 // the multicol containing block has "overflow:scroll" style,
    465 // ScrollContainerFrame is returned because ColumnSetWrapperFrame is the
    466 // scrolled frame which has the -moz-scrolled-content pseudo style. We may walk
    467 // up "too far", but in terms of correctness of reframing, it's OK.
    468 static nsContainerFrame* GetMultiColumnContainingBlockFor(nsIFrame* aFrame) {
    469  MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),
    470             "Should only be called if the frame has a multi-column ancestor!");
    471 
    472  nsContainerFrame* current = aFrame->GetParent();
    473  while (current &&
    474         (current->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||
    475          current->Style()->IsPseudoOrAnonBox())) {
    476    current = current->GetParent();
    477  }
    478 
    479  MOZ_ASSERT(current,
    480             "No multicol containing block in a valid column hierarchy?");
    481 
    482  return current;
    483 }
    484 
    485 static bool InsertSeparatorBeforeAccessKey() {
    486  static bool sInitialized = false;
    487  static bool sValue = false;
    488  if (!sInitialized) {
    489    sInitialized = true;
    490    sValue =
    491        intl::LocaleService::GetInstance()->InsertSeparatorBeforeAccesskeys();
    492  }
    493  return sValue;
    494 }
    495 
    496 static bool AlwaysAppendAccessKey() {
    497  static bool sInitialized = false;
    498  static bool sValue = false;
    499  if (!sInitialized) {
    500    sInitialized = true;
    501    sValue = intl::LocaleService::GetInstance()->AlwaysAppendAccesskeys();
    502  }
    503  return sValue;
    504 }
    505 
    506 //----------------------------------------------------------------------
    507 
    508 // Block/inline frame construction logic. We maintain a few invariants here:
    509 //
    510 // 1. Block frames contain block and inline frames.
    511 //
    512 // 2. Inline frames only contain inline frames. If an inline parent has a block
    513 // child then the block child is migrated upward until it lands in a block
    514 // parent (the inline frames containing block is where it will end up).
    515 
    516 inline void SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame) {
    517  MOZ_ASSERT(!aFrame->GetNextSibling(), "Should be using a frame list");
    518  aParent->SetInitialChildList(FrameChildListID::Principal,
    519                               nsFrameList(aFrame, aFrame));
    520 }
    521 
    522 // -----------------------------------------------------------
    523 
    524 // Structure used when constructing formatting object trees. Contains
    525 // state information needed for absolutely positioned elements
    526 namespace mozilla {
    527 struct AbsoluteFrameList final : public nsFrameList {
    528  // Containing block for absolutely positioned elements.
    529  nsContainerFrame* mContainingBlock;
    530 
    531  explicit AbsoluteFrameList(nsContainerFrame* aContainingBlock = nullptr)
    532      : mContainingBlock(aContainingBlock) {}
    533 
    534  // Transfer frames in aOther to this list. aOther becomes empty after this
    535  // operation.
    536  AbsoluteFrameList(AbsoluteFrameList&& aOther) = default;
    537  AbsoluteFrameList& operator=(AbsoluteFrameList&& aOther) = default;
    538 
    539 #ifdef DEBUG
    540  // XXXbz Does this need a debug-only assignment operator that nulls out the
    541  // childList in the AbsoluteFrameList we're copying?  Introducing a difference
    542  // between debug and non-debug behavior seems bad, so I guess not...
    543  ~AbsoluteFrameList() {
    544    NS_ASSERTION(!FirstChild(),
    545                 "Dangling child list.  Someone forgot to insert it?");
    546  }
    547 #endif
    548 };
    549 }  // namespace mozilla
    550 
    551 // -----------------------------------------------------------
    552 
    553 // Structure for saving the existing state when pushing/poping containing
    554 // blocks. The destructor restores the state to its previous state
    555 class MOZ_STACK_CLASS nsFrameConstructorSaveState {
    556 public:
    557  ~nsFrameConstructorSaveState();
    558 
    559 private:
    560  // Pointer to struct whose data we save/restore.
    561  AbsoluteFrameList* mList = nullptr;
    562 
    563  // The saved pointer to the fixed list.
    564  AbsoluteFrameList* mSavedFixedList = nullptr;
    565 
    566  // Copy of original frame list. This can be the original absolute list or a
    567  // float list.
    568  AbsoluteFrameList mSavedList;
    569 
    570  // The name of the child list in which our frames would belong.
    571  mozilla::FrameChildListID mChildListID = FrameChildListID::Principal;
    572  nsFrameConstructorState* mState = nullptr;
    573 
    574  friend class nsFrameConstructorState;
    575 };
    576 
    577 // Structure used for maintaining state information during the
    578 // frame construction process
    579 class MOZ_STACK_CLASS nsFrameConstructorState {
    580 public:
    581  nsPresContext* mPresContext;
    582  PresShell* mPresShell;
    583  nsCSSFrameConstructor* mFrameConstructor;
    584 
    585  // Containing block information for out-of-flow frames.
    586  //
    587  // Floats are easy. Whatever is our float CB.
    588  //
    589  // Regular abspos elements are easy too. Its containing block can be the
    590  // nearest abspos element, or the ICB (the canvas frame).
    591  //
    592  // Top layer abspos elements are always children of the ICB, but we can get
    593  // away with having two different lists (mAbsoluteList and
    594  // mTopLayerAbsoluteList), because because top layer frames cause
    595  // non-top-layer frames to be contained inside (so any descendants of a top
    596  // layer abspos can never share containing block with it, unless they're also
    597  // in the top layer).
    598  //
    599  // Regular fixed elements however are trickier. Fixed elements can be
    600  // contained in one of three lists:
    601  //
    602  //  * mAbsoluteList, if our abspos cb is also a fixpos cb (e.g., is
    603  //                   transformed or has a filter).
    604  //
    605  //  * mAncestorFixedList, if the fixpos cb is an ancestor element other than
    606  //                        the viewport frame, (so, a transformed / filtered
    607  //                        ancestor).
    608  //
    609  //  * mRealFixedList, which is also the fixed list used for the top layer
    610  //                    fixed items, which is the fixed list of the viewport
    611  //                    frame.
    612  //
    613  // It is important that mRealFixedList is shared between regular and top layer
    614  // fixpos elements, since no-top-layer descendants of top layer fixed elements
    615  // could share ICB and vice versa, so without that there would be no guarantee
    616  // of layout ordering between them.
    617  AbsoluteFrameList mFloatedList;
    618  AbsoluteFrameList mAbsoluteList;
    619  AbsoluteFrameList mTopLayerAbsoluteList;
    620  AbsoluteFrameList mAncestorFixedList;
    621  AbsoluteFrameList mRealFixedList;
    622 
    623  // Never null, always pointing to one of the lists documented above.
    624  AbsoluteFrameList* mFixedList;
    625 
    626  // What `page: auto` resolves to. This is the used page-name of the parent
    627  // frame. Updated by AutoFrameConstructionPageName.
    628  const nsAtom* mAutoPageNameValue = nullptr;
    629 
    630  nsCOMPtr<nsILayoutHistoryState> mFrameState;
    631  // These bits will be added to the state bits of any frame we construct
    632  // using this state.
    633  nsFrameState mAdditionalStateBits{0};
    634 
    635  // If false (which is the default) then call SetPrimaryFrame() as needed
    636  // during frame construction.  If true, don't make any SetPrimaryFrame()
    637  // calls, except for generated content which doesn't have a primary frame
    638  // yet.  The mCreatingExtraFrames == true mode is meant to be used for
    639  // construction of random "extra" frames for elements via normal frame
    640  // construction APIs (e.g. replication of things across pages in paginated
    641  // mode).
    642  bool mCreatingExtraFrames;
    643 
    644  // This keeps track of whether we have found a "rendered legend" for
    645  // the current FieldSetFrame.
    646  bool mHasRenderedLegend;
    647 
    648  nsTArray<RefPtr<nsIContent>> mGeneratedContentWithInitializer;
    649 
    650 #ifdef DEBUG
    651  // Record the float containing block candidate passed into
    652  // MaybePushFloatContainingBlock() to keep track that we've call the method to
    653  // handle the float CB scope before processing the CB's children. It is reset
    654  // in ConstructFramesFromItemList().
    655  nsContainerFrame* mFloatCBCandidate = nullptr;
    656 #endif
    657 
    658  // Constructor
    659  // Use the passed-in history state.
    660  nsFrameConstructorState(
    661      PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
    662      nsContainerFrame* aAbsoluteContainingBlock,
    663      nsContainerFrame* aFloatContainingBlock,
    664      already_AddRefed<nsILayoutHistoryState> aHistoryState);
    665  // Get the history state from the pres context's pres shell.
    666  nsFrameConstructorState(PresShell* aPresShell,
    667                          nsContainerFrame* aFixedContainingBlock,
    668                          nsContainerFrame* aAbsoluteContainingBlock,
    669                          nsContainerFrame* aFloatContainingBlock);
    670 
    671  ~nsFrameConstructorState();
    672 
    673  // Process the frame insertions for all the out-of-flow nsAbsoluteItems.
    674  void ProcessFrameInsertionsForAllLists();
    675 
    676  // Function to push the existing absolute containing block state and
    677  // create a new scope. Code that uses this function should get matching
    678  // logic in GetAbsoluteContainingBlock.
    679  // Also makes aNewAbsoluteContainingBlock the containing block for
    680  // fixed-pos elements if necessary.
    681  // aPositionedFrame is the frame whose style actually makes
    682  // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable
    683  // element aPositionedFrame is the element's primary frame and
    684  // aNewAbsoluteContainingBlock is the scrolled frame.
    685  void PushAbsoluteContainingBlock(
    686      nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
    687      nsFrameConstructorSaveState& aSaveState);
    688 
    689  // Function to forbid floats descendants under aFloatCBCandidate, or open a
    690  // new float containing block scope for aFloatCBCandidate. The current
    691  // state is saved in aSaveState if a new scope is pushed.
    692  void MaybePushFloatContainingBlock(nsContainerFrame* aFloatCBCandidate,
    693                                     nsFrameConstructorSaveState& aSaveState);
    694 
    695  // Helper function for MaybePushFloatContainingBlock().
    696  void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
    697                                nsFrameConstructorSaveState& aSaveState);
    698 
    699  // Function to return the proper geometric parent for a frame with display
    700  // struct given by aStyleDisplay and parent's frame given by
    701  // aContentParentFrame.
    702  nsContainerFrame* GetGeometricParent(
    703      const nsStyleDisplay& aStyleDisplay,
    704      nsContainerFrame* aContentParentFrame) const;
    705 
    706  // Collect absolute frames in mAbsoluteList which are proper descendants
    707  // of aNewParent, and reparent them to aNewParent.
    708  //
    709  // Note: This function does something unusual that moves absolute items
    710  // after their frames are constructed under a column hierarchy which has
    711  // column-span elements. Do not use this if you're not dealing with
    712  // columns.
    713  void ReparentAbsoluteItems(nsContainerFrame* aNewParent);
    714 
    715  // Collect floats in mFloatedList which are proper descendants of aNewParent,
    716  // and reparent them to aNewParent.
    717  //
    718  // Note: This function does something unusual that moves floats after their
    719  // frames are constructed under a column hierarchy which has column-span
    720  // elements. Do not use this if you're not dealing with columns.
    721  void ReparentFloats(nsContainerFrame* aNewParent);
    722 
    723  /**
    724   * Function to add a new frame to the right frame list.  This MUST be called
    725   * on frames before their children have been processed if the frames might
    726   * conceivably be out-of-flow; otherwise cleanup in error cases won't work
    727   * right.  Also, this MUST be called on frames after they have been
    728   * initialized.
    729   * @param aNewFrame the frame to add
    730   * @param aFrameList the list to add in-flow frames to
    731   * @param aContent the content pointer for aNewFrame
    732   * @param aParentFrame the parent frame for the content if it were in-flow
    733   * @param aCanBePositioned pass false if the frame isn't allowed to be
    734   *        positioned
    735   * @param aCanBeFloated pass false if the frame isn't allowed to be
    736   *        floated
    737   */
    738  void AddChild(nsIFrame* aNewFrame, nsFrameList& aFrameList,
    739                nsIContent* aContent, nsContainerFrame* aParentFrame,
    740                bool aCanBePositioned = true, bool aCanBeFloated = true,
    741                bool aInsertAfter = false,
    742                nsIFrame* aInsertAfterFrame = nullptr);
    743 
    744  /**
    745   * Function to return the fixed-pos element list.  Normally this will just
    746   * hand back the fixed-pos element list, but in case we're dealing with a
    747   * transformed element that's acting as an abs-pos and fixed-pos container,
    748   * we'll hand back the abs-pos list.  Callers should use this function if they
    749   * want to get the list acting as the fixed-pos item parent.
    750   */
    751  AbsoluteFrameList& GetFixedList() { return *mFixedList; }
    752  const AbsoluteFrameList& GetFixedList() const { return *mFixedList; }
    753 
    754 protected:
    755  friend class nsFrameConstructorSaveState;
    756 
    757  /**
    758   * ProcessFrameInsertions takes the frames in aFrameList and adds them as
    759   * kids to the aChildListID child list of |aFrameList.containingBlock|.
    760   */
    761  void ProcessFrameInsertions(AbsoluteFrameList& aFrameList,
    762                              mozilla::FrameChildListID aChildListID);
    763 
    764  /**
    765   * GetOutOfFlowFrameList selects the out-of-flow frame list the new
    766   * frame should be added to. If the frame shouldn't be added to any
    767   * out-of-flow list, it returns nullptr. The corresponding type of
    768   * placeholder is also returned via the aPlaceholderType parameter
    769   * if this method doesn't return nullptr. The caller should check
    770   * whether the returned list really has a containing block.
    771   */
    772  AbsoluteFrameList* GetOutOfFlowFrameList(nsIFrame* aNewFrame,
    773                                           bool aCanBePositioned,
    774                                           bool aCanBeFloated,
    775                                           nsFrameState* aPlaceholderType);
    776 };
    777 
    778 nsFrameConstructorState::nsFrameConstructorState(
    779    PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
    780    nsContainerFrame* aAbsoluteContainingBlock,
    781    nsContainerFrame* aFloatContainingBlock,
    782    already_AddRefed<nsILayoutHistoryState> aHistoryState)
    783    : mPresContext(aPresShell->GetPresContext()),
    784      mPresShell(aPresShell),
    785      mFrameConstructor(aPresShell->FrameConstructor()),
    786      mFloatedList(aFloatContainingBlock),
    787      mAbsoluteList(aAbsoluteContainingBlock),
    788      mTopLayerAbsoluteList(mFrameConstructor->GetCanvasFrame()),
    789      mAncestorFixedList(aFixedContainingBlock),
    790      mRealFixedList(
    791          static_cast<nsContainerFrame*>(mFrameConstructor->GetRootFrame())),
    792      // See PushAbsoluteContaningBlock below
    793      mFrameState(aHistoryState),
    794      mCreatingExtraFrames(false),
    795      mHasRenderedLegend(false) {
    796  MOZ_COUNT_CTOR(nsFrameConstructorState);
    797  mFixedList = [&] {
    798    if (aFixedContainingBlock == aAbsoluteContainingBlock) {
    799      return &mAbsoluteList;
    800    }
    801    if (aAbsoluteContainingBlock == mRealFixedList.mContainingBlock) {
    802      return &mRealFixedList;
    803    }
    804    return &mAncestorFixedList;
    805  }();
    806 }
    807 
    808 nsFrameConstructorState::nsFrameConstructorState(
    809    PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
    810    nsContainerFrame* aAbsoluteContainingBlock,
    811    nsContainerFrame* aFloatContainingBlock)
    812    : nsFrameConstructorState(
    813          aPresShell, aFixedContainingBlock, aAbsoluteContainingBlock,
    814          aFloatContainingBlock,
    815          aPresShell->GetDocument()->GetLayoutHistoryState()) {}
    816 
    817 nsFrameConstructorState::~nsFrameConstructorState() {
    818  MOZ_COUNT_DTOR(nsFrameConstructorState);
    819  ProcessFrameInsertionsForAllLists();
    820  for (auto& content : Reversed(mGeneratedContentWithInitializer)) {
    821    content->RemoveProperty(nsGkAtoms::genConInitializerProperty);
    822  }
    823 }
    824 
    825 void nsFrameConstructorState::ProcessFrameInsertionsForAllLists() {
    826  ProcessFrameInsertions(mFloatedList, FrameChildListID::Float);
    827  ProcessFrameInsertions(mAbsoluteList, FrameChildListID::Absolute);
    828  ProcessFrameInsertions(mTopLayerAbsoluteList, FrameChildListID::Absolute);
    829  ProcessFrameInsertions(*mFixedList, FrameChildListID::Fixed);
    830  ProcessFrameInsertions(mRealFixedList, FrameChildListID::Fixed);
    831 }
    832 
    833 void nsFrameConstructorState::PushAbsoluteContainingBlock(
    834    nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
    835    nsFrameConstructorSaveState& aSaveState) {
    836  MOZ_ASSERT(!!aNewAbsoluteContainingBlock == !!aPositionedFrame,
    837             "We should have both or none");
    838  aSaveState.mList = &mAbsoluteList;
    839  aSaveState.mChildListID = FrameChildListID::Absolute;
    840  aSaveState.mState = this;
    841  aSaveState.mSavedList = std::move(mAbsoluteList);
    842  aSaveState.mSavedFixedList = mFixedList;
    843  mAbsoluteList = AbsoluteFrameList(aNewAbsoluteContainingBlock);
    844  mFixedList = [&] {
    845    if (!aPositionedFrame || aPositionedFrame->IsFixedPosContainingBlock()) {
    846      // See if we need to treat abspos and fixedpos the same. This happens if
    847      // we're a transformed/filtered/etc element, or if we force a null abspos
    848      // containing block (for mathml for example).
    849      return &mAbsoluteList;
    850    }
    851    if (aPositionedFrame->StyleDisplay()->mTopLayer == StyleTopLayer::Auto) {
    852      // If our new CB is in the top layer, and isn't a fixed CB itself, we also
    853      // escape the usual containment.
    854      return &mRealFixedList;
    855    }
    856    if (mFixedList == &mAbsoluteList) {
    857      // If we were pointing to our old absolute list, keep pointing to it.
    858      return &aSaveState.mSavedList;
    859    }
    860    // Otherwise keep pointing to the current thing (another ancestor's
    861    // absolute list, or the real fixed list, doesn't matter).
    862    return mFixedList;
    863  }();
    864 
    865  if (aNewAbsoluteContainingBlock &&
    866      !aNewAbsoluteContainingBlock->IsAbsoluteContainer()) {
    867    aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
    868  }
    869 }
    870 
    871 void nsFrameConstructorState::MaybePushFloatContainingBlock(
    872    nsContainerFrame* aFloatCBCandidate,
    873    nsFrameConstructorSaveState& aSaveState) {
    874  // The logic here needs to match the logic in GetFloatContainingBlock().
    875  if (ShouldSuppressFloatingOfDescendants(aFloatCBCandidate)) {
    876    // Pushing a null float containing block forbids any frames from being
    877    // floated until a new float containing block is pushed. See implementation
    878    // of nsFrameConstructorState::AddChild().
    879    //
    880    // XXX we should get rid of null float containing blocks and teach the
    881    // various frame classes to deal with floats instead.
    882    PushFloatContainingBlock(nullptr, aSaveState);
    883  } else if (aFloatCBCandidate->IsFloatContainingBlock()) {
    884    PushFloatContainingBlock(aFloatCBCandidate, aSaveState);
    885  }
    886 
    887 #ifdef DEBUG
    888  mFloatCBCandidate = aFloatCBCandidate;
    889 #endif
    890 }
    891 
    892 void nsFrameConstructorState::PushFloatContainingBlock(
    893    nsContainerFrame* aNewFloatContainingBlock,
    894    nsFrameConstructorSaveState& aSaveState) {
    895  MOZ_ASSERT(!aNewFloatContainingBlock ||
    896                 aNewFloatContainingBlock->IsFloatContainingBlock(),
    897             "Please push a real float containing block!");
    898  NS_ASSERTION(
    899      !aNewFloatContainingBlock ||
    900          !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),
    901      "We should not push a frame that is supposed to _suppress_ "
    902      "floats as a float containing block!");
    903  aSaveState.mList = &mFloatedList;
    904  aSaveState.mSavedList = std::move(mFloatedList);
    905  aSaveState.mChildListID = FrameChildListID::Float;
    906  aSaveState.mState = this;
    907  mFloatedList = AbsoluteFrameList(aNewFloatContainingBlock);
    908 }
    909 
    910 nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
    911    const nsStyleDisplay& aStyleDisplay,
    912    nsContainerFrame* aContentParentFrame) const {
    913  // If there is no container for a fixed, absolute, or floating root
    914  // frame, we will ignore the positioning.  This hack is originally
    915  // brought to you by the letter T: tables, since other roots don't
    916  // even call into this code.  See bug 178855.
    917  //
    918  // XXX Disabling positioning in this case is a hack.  If one was so inclined,
    919  // one could support this either by (1) inserting a dummy block between the
    920  // table and the canvas or (2) teaching the canvas how to reflow positioned
    921  // elements. (1) has the usual problems when multiple frames share the same
    922  // content (notice all the special cases in this file dealing with inner
    923  // tables and table wrappers which share the same content). (2) requires some
    924  // work and possible factoring.
    925  //
    926  // XXXbz couldn't we just force position to "static" on roots and
    927  // float to "none"?  That's OK per CSS 2.1, as far as I can tell.
    928 
    929  if (aContentParentFrame && aContentParentFrame->IsInSVGTextSubtree()) {
    930    return aContentParentFrame;
    931  }
    932 
    933  if (aStyleDisplay.IsFloatingStyle() && mFloatedList.mContainingBlock) {
    934    NS_ASSERTION(!aStyleDisplay.IsAbsolutelyPositionedStyle(),
    935                 "Absolutely positioned _and_ floating?");
    936    return mFloatedList.mContainingBlock;
    937  }
    938 
    939  if (aStyleDisplay.mTopLayer != StyleTopLayer::None) {
    940    MOZ_ASSERT(aStyleDisplay.mTopLayer == StyleTopLayer::Auto,
    941               "-moz-top-layer should be either none or auto");
    942    MOZ_ASSERT(aStyleDisplay.IsAbsolutelyPositionedStyle(),
    943               "Top layer items should always be absolutely positioned");
    944    if (aStyleDisplay.mPosition == StylePositionProperty::Fixed) {
    945      MOZ_ASSERT(mRealFixedList.mContainingBlock, "No root frame?");
    946      return mRealFixedList.mContainingBlock;
    947    }
    948    MOZ_ASSERT(aStyleDisplay.mPosition == StylePositionProperty::Absolute);
    949    MOZ_ASSERT(mTopLayerAbsoluteList.mContainingBlock);
    950    return mTopLayerAbsoluteList.mContainingBlock;
    951  }
    952 
    953  if (aStyleDisplay.mPosition == StylePositionProperty::Absolute &&
    954      mAbsoluteList.mContainingBlock) {
    955    return mAbsoluteList.mContainingBlock;
    956  }
    957 
    958  if (aStyleDisplay.mPosition == StylePositionProperty::Fixed &&
    959      mFixedList->mContainingBlock) {
    960    return mFixedList->mContainingBlock;
    961  }
    962 
    963  return aContentParentFrame;
    964 }
    965 
    966 void nsFrameConstructorState::ReparentAbsoluteItems(
    967    nsContainerFrame* aNewParent) {
    968  // Bug 1491727: This function might not conform to the spec. See
    969  // https://github.com/w3c/csswg-drafts/issues/1894.
    970 
    971  MOZ_ASSERT(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),
    972             "Restrict the usage under column hierarchy.");
    973 
    974  AbsoluteFrameList newAbsoluteItems(aNewParent);
    975 
    976  nsIFrame* current = mAbsoluteList.FirstChild();
    977  while (current) {
    978    nsIFrame* placeholder = current->GetPlaceholderFrame();
    979 
    980    if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
    981      nsIFrame* next = current->GetNextSibling();
    982      mAbsoluteList.RemoveFrame(current);
    983      newAbsoluteItems.AppendFrame(aNewParent, current);
    984      current = next;
    985    } else {
    986      current = current->GetNextSibling();
    987    }
    988  }
    989 
    990  if (newAbsoluteItems.NotEmpty()) {
    991    // ~nsFrameConstructorSaveState() will move newAbsoluteItems to
    992    // aNewParent's absolute child list.
    993    nsFrameConstructorSaveState absoluteSaveState;
    994 
    995    // It doesn't matter whether aNewParent has position style or not. Caller
    996    // won't call us if we can't have absolute children.
    997    PushAbsoluteContainingBlock(aNewParent, aNewParent, absoluteSaveState);
    998    mAbsoluteList = std::move(newAbsoluteItems);
    999  }
   1000 }
   1001 
   1002 void nsFrameConstructorState::ReparentFloats(nsContainerFrame* aNewParent) {
   1003  MOZ_ASSERT(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),
   1004             "Restrict the usage under column hierarchy.");
   1005  MOZ_ASSERT(
   1006      aNewParent->IsFloatContainingBlock(),
   1007      "Why calling this method if aNewParent is not a float containing block?");
   1008 
   1009  // Gather floats that should reparent under aNewParent.
   1010  AbsoluteFrameList floats(aNewParent);
   1011  nsIFrame* current = mFloatedList.FirstChild();
   1012  while (current) {
   1013    nsIFrame* placeholder = current->GetPlaceholderFrame();
   1014    nsIFrame* next = current->GetNextSibling();
   1015    if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
   1016      mFloatedList.RemoveFrame(current);
   1017      floats.AppendFrame(aNewParent, current);
   1018    }
   1019    current = next;
   1020  }
   1021 
   1022  if (floats.NotEmpty()) {
   1023    // Make floats move into aNewParent's float child list in
   1024    // ~nsFrameConstructorSaveState() when destructing floatSaveState.
   1025    nsFrameConstructorSaveState floatSaveState;
   1026    PushFloatContainingBlock(aNewParent, floatSaveState);
   1027    mFloatedList = std::move(floats);
   1028  }
   1029 }
   1030 
   1031 AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList(
   1032    nsIFrame* aNewFrame, bool aCanBePositioned, bool aCanBeFloated,
   1033    nsFrameState* aPlaceholderType) {
   1034  const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
   1035  if (aCanBeFloated && disp->IsFloatingStyle()) {
   1036    *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
   1037    return &mFloatedList;
   1038  }
   1039 
   1040  if (aCanBePositioned) {
   1041    if (disp->mTopLayer != StyleTopLayer::None) {
   1042      *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
   1043      if (disp->mPosition == StylePositionProperty::Fixed) {
   1044        *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
   1045        return &mRealFixedList;
   1046      }
   1047      *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
   1048      return &mTopLayerAbsoluteList;
   1049    }
   1050    if (disp->mPosition == StylePositionProperty::Absolute) {
   1051      *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
   1052      return &mAbsoluteList;
   1053    }
   1054    if (disp->mPosition == StylePositionProperty::Fixed) {
   1055      *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
   1056      return mFixedList;
   1057    }
   1058  }
   1059  return nullptr;
   1060 }
   1061 
   1062 void nsFrameConstructorState::AddChild(
   1063    nsIFrame* aNewFrame, nsFrameList& aFrameList, nsIContent* aContent,
   1064    nsContainerFrame* aParentFrame, bool aCanBePositioned, bool aCanBeFloated,
   1065    bool aInsertAfter, nsIFrame* aInsertAfterFrame) {
   1066  MOZ_ASSERT(!aNewFrame->GetNextSibling(), "Shouldn't happen");
   1067 
   1068  nsFrameState placeholderType;
   1069  AbsoluteFrameList* outOfFlowFrameList = GetOutOfFlowFrameList(
   1070      aNewFrame, aCanBePositioned, aCanBeFloated, &placeholderType);
   1071 
   1072  // The comments in GetGeometricParent regarding root table frames
   1073  // all apply here, unfortunately. Thus, we need to check whether
   1074  // the returned frame items really has containing block.
   1075  nsFrameList* frameList;
   1076  if (outOfFlowFrameList && outOfFlowFrameList->mContainingBlock) {
   1077    MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock,
   1078               "Parent of the frame is not the containing block?");
   1079    frameList = outOfFlowFrameList;
   1080  } else {
   1081    frameList = &aFrameList;
   1082    placeholderType = nsFrameState(0);
   1083  }
   1084 
   1085  if (placeholderType) {
   1086    NS_ASSERTION(frameList != &aFrameList,
   1087                 "Putting frame in-flow _and_ want a placeholder?");
   1088    nsIFrame* placeholderFrame =
   1089        nsCSSFrameConstructor::CreatePlaceholderFrameFor(
   1090            mPresShell, aContent, aNewFrame, aParentFrame, nullptr,
   1091            placeholderType);
   1092 
   1093    placeholderFrame->AddStateBits(mAdditionalStateBits);
   1094    // Add the placeholder frame to the flow
   1095    aFrameList.AppendFrame(nullptr, placeholderFrame);
   1096  }
   1097 #ifdef DEBUG
   1098  else {
   1099    NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
   1100                 "In-flow frame has wrong parent");
   1101  }
   1102 #endif
   1103 
   1104  if (aInsertAfter) {
   1105    frameList->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
   1106  } else {
   1107    frameList->AppendFrame(nullptr, aNewFrame);
   1108  }
   1109 }
   1110 
   1111 // Some of this function's callers recurse 1000 levels deep in crashtests. On
   1112 // platforms where stack limits are low, we can't afford to incorporate this
   1113 // function's `AutoTArray`s into its callers' stack frames, so disable inlining.
   1114 MOZ_NEVER_INLINE void nsFrameConstructorState::ProcessFrameInsertions(
   1115    AbsoluteFrameList& aFrameList, FrameChildListID aChildListID) {
   1116  MOZ_ASSERT(&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList ||
   1117             &aFrameList == &mTopLayerAbsoluteList ||
   1118             &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList ||
   1119             &aFrameList == &mRealFixedList);
   1120  MOZ_ASSERT_IF(&aFrameList == &mFloatedList,
   1121                aChildListID == FrameChildListID::Float);
   1122  MOZ_ASSERT_IF(&aFrameList == &mAbsoluteList || &aFrameList == mFixedList,
   1123                aChildListID == FrameChildListID::Absolute ||
   1124                    aChildListID == FrameChildListID::Fixed);
   1125  MOZ_ASSERT_IF(&aFrameList == &mTopLayerAbsoluteList,
   1126                aChildListID == FrameChildListID::Absolute);
   1127  MOZ_ASSERT_IF(&aFrameList == mFixedList && &aFrameList != &mAbsoluteList,
   1128                aChildListID == FrameChildListID::Fixed);
   1129  MOZ_ASSERT_IF(&aFrameList == &mAncestorFixedList,
   1130                aChildListID == FrameChildListID::Fixed);
   1131  MOZ_ASSERT_IF(&aFrameList == &mRealFixedList,
   1132                aChildListID == FrameChildListID::Fixed);
   1133 
   1134  if (aFrameList.IsEmpty()) {
   1135    return;
   1136  }
   1137 
   1138  nsContainerFrame* containingBlock = aFrameList.mContainingBlock;
   1139 
   1140  NS_ASSERTION(containingBlock, "Child list without containing block?");
   1141 
   1142  if (aChildListID == FrameChildListID::Fixed) {
   1143    // Put this frame on the transformed-frame's abs-pos list instead, if
   1144    // it has abs-pos children instead of fixed-pos children.
   1145    aChildListID = containingBlock->GetAbsoluteListID();
   1146  }
   1147 
   1148  // Insert the frames hanging out in aItems.  We can use SetInitialChildList()
   1149  // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
   1150  // is set) and doesn't have any frames in the aChildListID child list yet.
   1151  const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
   1152  if (childList.IsEmpty() &&
   1153      containingBlock->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
   1154    // If we're injecting absolutely positioned frames, inject them on the
   1155    // absolute containing block
   1156    if (aChildListID == containingBlock->GetAbsoluteListID()) {
   1157      containingBlock->GetAbsoluteContainingBlock()->SetInitialChildList(
   1158          containingBlock, aChildListID, std::move(aFrameList));
   1159    } else {
   1160      containingBlock->SetInitialChildList(aChildListID, std::move(aFrameList));
   1161    }
   1162  } else if (childList.IsEmpty() || aChildListID == FrameChildListID::Fixed ||
   1163             aChildListID == FrameChildListID::Absolute) {
   1164    // The order is not important for abs-pos/fixed-pos frame list, just
   1165    // append the frame items to the list directly.
   1166    mFrameConstructor->AppendFrames(containingBlock, aChildListID,
   1167                                    std::move(aFrameList));
   1168  } else {
   1169    MOZ_ASSERT(aChildListID == FrameChildListID::Float);
   1170    // Note that whether the frame construction context is doing an append or
   1171    // not is not helpful here, since it could be appending to some frame in
   1172    // the middle of the document, which means we're not necessarily
   1173    // appending to the children of the containing block.
   1174    //
   1175    // We need to make sure the 'append to the end of document' case is fast.
   1176    // So first test the last child of the containing block
   1177    nsIFrame* lastChild = childList.LastChild();
   1178    lastChild = lastChild->FirstContinuation()->GetPlaceholderFrame();
   1179 
   1180    // CompareTreePosition uses placeholder hierarchy for out of flow frames,
   1181    // so this will make out-of-flows respect the ordering of placeholders,
   1182    // which is great because it takes care of anonymous content.
   1183    nsIFrame* firstNewFrame = aFrameList.FirstChild();
   1184    firstNewFrame = firstNewFrame->GetPlaceholderFrame();
   1185 
   1186    // Cache the ancestor chain so that we can reuse it if needed.
   1187    AutoTArray<const nsIFrame*, 20> firstNewFrameAncestors;
   1188    const nsIFrame* notCommonAncestor = nsLayoutUtils::FillAncestors(
   1189        firstNewFrame, containingBlock, &firstNewFrameAncestors);
   1190 
   1191    if (nsLayoutUtils::CompareTreePosition(
   1192            lastChild, firstNewFrame, firstNewFrameAncestors,
   1193            notCommonAncestor ? containingBlock : nullptr) < 0) {
   1194      // lastChild comes before the new children, so just append
   1195      mFrameConstructor->AppendFrames(containingBlock, aChildListID,
   1196                                      std::move(aFrameList));
   1197    } else {
   1198      // Try the other children. First collect them to an array so that a
   1199      // reasonable fast binary search can be used to find the insertion point.
   1200      AutoTArray<std::pair<nsIFrame*, nsPlaceholderFrame*>, 128> children;
   1201      for (nsIFrame* f : childList) {
   1202        children.AppendElement(
   1203            std::make_pair(f, f->FirstContinuation()->GetPlaceholderFrame()));
   1204      }
   1205 
   1206      nsIFrame* insertionPoint = nullptr;
   1207      int32_t imin = 0;
   1208      int32_t max = children.Length();
   1209      while (max > imin) {
   1210        int32_t imid = imin + ((max - imin) / 2);
   1211        const auto& pair = children[imid];
   1212        int32_t compare = nsLayoutUtils::CompareTreePosition(
   1213            pair.second, firstNewFrame, firstNewFrameAncestors,
   1214            notCommonAncestor ? containingBlock : nullptr);
   1215        if (compare > 0) {
   1216          // f is after the new frame.
   1217          max = imid;
   1218          insertionPoint = imid > 0 ? children[imid - 1].first : nullptr;
   1219        } else if (compare < 0) {
   1220          // f is before the new frame.
   1221          imin = imid + 1;
   1222          insertionPoint = pair.first;
   1223        } else {
   1224          // This is for the old behavior. Should be removed once it is
   1225          // guaranteed that CompareTreePosition can't return 0!
   1226          // See bug 928645.
   1227          NS_WARNING("Something odd happening???");
   1228          insertionPoint = nullptr;
   1229          for (auto [frame, placeholder] : children) {
   1230            if (nsLayoutUtils::CompareTreePosition(
   1231                    placeholder, firstNewFrame, firstNewFrameAncestors,
   1232                    notCommonAncestor ? containingBlock : nullptr) > 0) {
   1233              break;
   1234            }
   1235            insertionPoint = frame;
   1236          }
   1237          break;
   1238        }
   1239      }
   1240      mFrameConstructor->InsertFrames(containingBlock, aChildListID,
   1241                                      insertionPoint, std::move(aFrameList));
   1242    }
   1243  }
   1244 
   1245  MOZ_ASSERT(aFrameList.IsEmpty(), "How did that happen?");
   1246 }
   1247 
   1248 nsFrameConstructorSaveState::~nsFrameConstructorSaveState() {
   1249  // Restore the state
   1250  if (mList) {
   1251    MOZ_ASSERT(mState, "Can't have mList set without having a state!");
   1252    mState->ProcessFrameInsertions(*mList, mChildListID);
   1253 
   1254    if (mList == &mState->mAbsoluteList) {
   1255      mState->mAbsoluteList = std::move(mSavedList);
   1256      mState->mFixedList = mSavedFixedList;
   1257    } else {
   1258      mState->mFloatedList = std::move(mSavedList);
   1259    }
   1260 
   1261    MOZ_ASSERT(mSavedList.IsEmpty(),
   1262               "Frames in mSavedList should've moved back into mState!");
   1263    MOZ_ASSERT(!mList->LastChild() || !mList->LastChild()->GetNextSibling(),
   1264               "Something corrupted our list!");
   1265  }
   1266 }
   1267 
   1268 /**
   1269 * Moves aFrameList from aOldParent to aNewParent.  This updates the parent
   1270 * pointer of the frames in the list, and reparents their views as needed.
   1271 * nsIFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
   1272 * ancestors as needed. Then it sets the list as the initial child list
   1273 * on aNewParent, unless aNewParent either already has kids or has been
   1274 * reflowed; in that case it appends the new frames.  Note that this
   1275 * method differs from ReparentFrames in that it doesn't change the kids'
   1276 * style.
   1277 */
   1278 // XXXbz Since this is only used for {ib} splits, could we just copy the view
   1279 // bits from aOldParent to aNewParent and then use the
   1280 // nsFrameList::ApplySetParent?  That would still leave us doing two passes
   1281 // over the list, of course; if we really wanted to we could factor out the
   1282 // relevant part of ReparentFrameViewList, I suppose...  Or just get rid of
   1283 // views, which would make most of this function go away.
   1284 static void MoveChildrenTo(nsIFrame* aOldParent, nsContainerFrame* aNewParent,
   1285                           nsFrameList& aFrameList) {
   1286  aFrameList.ApplySetParent(aNewParent);
   1287 
   1288  if (aNewParent->PrincipalChildList().IsEmpty() &&
   1289      aNewParent->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
   1290    aNewParent->SetInitialChildList(FrameChildListID::Principal,
   1291                                    std::move(aFrameList));
   1292  } else {
   1293    aNewParent->AppendFrames(FrameChildListID::Principal,
   1294                             std::move(aFrameList));
   1295  }
   1296 }
   1297 
   1298 static void EnsureAutoPageName(nsFrameConstructorState& aState,
   1299                               const nsContainerFrame* const aFrame) {
   1300  // Check if we need to figure out our used page name.
   1301  // When building the entire document, this should only happen for the
   1302  // root, which will mean the loop will immediately end. Either way, this will
   1303  // only happen once for each time the frame constructor is run.
   1304  if (aState.mAutoPageNameValue) {
   1305    return;
   1306  }
   1307 
   1308  for (const nsContainerFrame* frame = aFrame; frame;
   1309       frame = frame->GetParent()) {
   1310    if (const nsAtom* maybePageName = frame->GetStylePageName()) {
   1311      aState.mAutoPageNameValue = maybePageName;
   1312      return;
   1313    }
   1314  }
   1315  // Ensure that a root with `page: auto` gets an empty page name
   1316  // https://drafts.csswg.org/css-page-3/#using-named-pages
   1317  aState.mAutoPageNameValue = nsGkAtoms::_empty;
   1318 }
   1319 
   1320 nsCSSFrameConstructor::AutoFrameConstructionPageName::
   1321    AutoFrameConstructionPageName(nsFrameConstructorState& aState,
   1322                                  nsIFrame* const aFrame)
   1323    : mState(aState), mNameToRestore(nullptr) {
   1324  if (!aState.mPresContext->IsPaginated()) {
   1325    MOZ_ASSERT(!aState.mAutoPageNameValue,
   1326               "Page name should not have been set");
   1327    return;
   1328  }
   1329 #ifdef DEBUG
   1330  MOZ_ASSERT(!aFrame->mWasVisitedByAutoFrameConstructionPageName,
   1331             "Frame should only have been visited once");
   1332  aFrame->mWasVisitedByAutoFrameConstructionPageName = true;
   1333 #endif
   1334 
   1335  EnsureAutoPageName(aState, aFrame->GetParent());
   1336  mNameToRestore = aState.mAutoPageNameValue;
   1337 
   1338  MOZ_ASSERT(mNameToRestore,
   1339             "Page name should have been found by EnsureAutoPageName");
   1340  if (const nsAtom* maybePageName = aFrame->GetStylePageName()) {
   1341    aState.mAutoPageNameValue = maybePageName;
   1342  }
   1343  aFrame->SetAutoPageValue(aState.mAutoPageNameValue);
   1344 }
   1345 
   1346 nsCSSFrameConstructor::AutoFrameConstructionPageName::
   1347    ~AutoFrameConstructionPageName() {
   1348  // This isn't actually useful when not in paginated layout, but it's very
   1349  // likely cheaper to unconditionally write this pointer than to test for
   1350  // paginated layout and then branch on the result.
   1351  mState.mAutoPageNameValue = mNameToRestore;
   1352 }
   1353 
   1354 //----------------------------------------------------------------------
   1355 
   1356 nsCSSFrameConstructor::nsCSSFrameConstructor(Document* aDocument,
   1357                                             PresShell* aPresShell)
   1358    : nsFrameManager(aPresShell),
   1359      mDocument(aDocument),
   1360      mFirstFreeFCItem(nullptr),
   1361      mFCItemsInUse(0),
   1362      mCurrentDepth(0),
   1363      mQuotesDirty(false),
   1364      mCountersDirty(false),
   1365      mAlwaysCreateFramesForIgnorableWhitespace(false),
   1366      mRemovingContent(false) {
   1367 #ifdef DEBUG
   1368  static bool gFirstTime = true;
   1369  if (gFirstTime) {
   1370    gFirstTime = false;
   1371    char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
   1372    if (flags) {
   1373      bool error = false;
   1374      for (;;) {
   1375        char* comma = strchr(flags, ',');
   1376        if (comma) *comma = '\0';
   1377 
   1378        bool found = false;
   1379        FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
   1380        FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS;
   1381        while (flag < limit) {
   1382          if (nsCRT::strcasecmp(flag->name, flags) == 0) {
   1383            *(flag->on) = true;
   1384            printf("nsCSSFrameConstructor: setting %s debug flag on\n",
   1385                   flag->name);
   1386            found = true;
   1387            break;
   1388          }
   1389          ++flag;
   1390        }
   1391 
   1392        if (!found) error = true;
   1393 
   1394        if (!comma) break;
   1395 
   1396        *comma = ',';
   1397        flags = comma + 1;
   1398      }
   1399 
   1400      if (error) {
   1401        printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
   1402        FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
   1403        FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS;
   1404        while (flag < limit) {
   1405          printf("  %s\n", flag->name);
   1406          ++flag;
   1407        }
   1408        printf(
   1409            "Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of "
   1410            "flag\n");
   1411        printf("names (no whitespace)\n");
   1412      }
   1413    }
   1414  }
   1415 #endif
   1416 }
   1417 
   1418 void nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) {
   1419  if (aFrame->StyleDisplay()->IsContainStyle()) {
   1420    mContainStyleScopeManager.DestroyScopesFor(aFrame);
   1421  }
   1422 
   1423  if (aFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT) &&
   1424      mContainStyleScopeManager.DestroyQuoteNodesFor(aFrame)) {
   1425    QuotesDirty();
   1426  }
   1427 
   1428  if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
   1429      mContainStyleScopeManager.DestroyCounterNodesFor(aFrame)) {
   1430    // Technically we don't need to update anything if we destroyed only
   1431    // USE nodes.  However, this is unlikely to happen in the real world
   1432    // since USE nodes generally go along with INCREMENT nodes.
   1433    CountersDirty();
   1434  }
   1435 
   1436  RestyleManager()->NotifyDestroyingFrame(aFrame);
   1437 }
   1438 
   1439 struct nsGenConInitializer {
   1440  UniquePtr<nsGenConNode> mNode;
   1441  nsGenConList* mList;
   1442  void (nsCSSFrameConstructor::*mDirtyAll)();
   1443 
   1444  nsGenConInitializer(UniquePtr<nsGenConNode> aNode, nsGenConList* aList,
   1445                      void (nsCSSFrameConstructor::*aDirtyAll)())
   1446      : mNode(std::move(aNode)), mList(aList), mDirtyAll(aDirtyAll) {}
   1447 };
   1448 
   1449 already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
   1450    nsFrameConstructorState& aState, const nsAString& aString,
   1451    UniquePtr<nsGenConInitializer> aInitializer) {
   1452  RefPtr<nsTextNode> content = new (mDocument->NodeInfoManager())
   1453      nsTextNode(mDocument->NodeInfoManager());
   1454  content->SetText(aString, false);
   1455  if (aInitializer) {
   1456    aInitializer->mNode->mText = content;
   1457    content->SetProperty(nsGkAtoms::genConInitializerProperty,
   1458                         aInitializer.release(),
   1459                         nsINode::DeleteProperty<nsGenConInitializer>);
   1460    aState.mGeneratedContentWithInitializer.AppendElement(content);
   1461  }
   1462  return content.forget();
   1463 }
   1464 
   1465 void nsCSSFrameConstructor::CreateGeneratedContent(
   1466    nsFrameConstructorState& aState, Element& aOriginatingElement,
   1467    ComputedStyle& aPseudoStyle, const StyleContentItem& aItem,
   1468    size_t aContentIndex, const FunctionRef<void(nsIContent*)> aAddChild) {
   1469  using Type = StyleContentItem::Tag;
   1470  // Get the content value
   1471  const Type type = aItem.tag;
   1472 
   1473  switch (type) {
   1474    case Type::Image: {
   1475      RefPtr c = GeneratedImageContent::Create(*mDocument, aContentIndex);
   1476      aAddChild(c);
   1477      return;
   1478    }
   1479 
   1480    case Type::String: {
   1481      const auto string = aItem.AsString().AsString();
   1482      if (string.IsEmpty()) {
   1483        return;
   1484      }
   1485      RefPtr text =
   1486          CreateGenConTextNode(aState, NS_ConvertUTF8toUTF16(string), nullptr);
   1487      aAddChild(text);
   1488      return;
   1489    }
   1490 
   1491    case Type::Attr: {
   1492      const auto& attr = aItem.AsAttr();
   1493      RefPtr<nsAtom> attrName = attr.attribute.AsAtom();
   1494      int32_t attrNameSpace = kNameSpaceID_None;
   1495      RefPtr<nsAtom> ns = attr.namespace_url.AsAtom();
   1496      if (!ns->IsEmpty()) {
   1497        nsresult rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
   1498            ns.forget(), attrNameSpace);
   1499        NS_ENSURE_SUCCESS_VOID(rv);
   1500      }
   1501 
   1502      if (mDocument->IsHTMLDocument() && aOriginatingElement.IsHTMLElement()) {
   1503        ToLowerCaseASCII(attrName);
   1504      }
   1505 
   1506      RefPtr<nsAtom> fallback = attr.fallback.AsAtom();
   1507 
   1508      nsCOMPtr<nsIContent> content;
   1509      NS_NewAttributeContent(mDocument->NodeInfoManager(), attrNameSpace,
   1510                             attrName, fallback, getter_AddRefs(content));
   1511      aAddChild(content);
   1512      return;
   1513    }
   1514 
   1515    case Type::Counter:
   1516    case Type::Counters: {
   1517      RefPtr<nsAtom> name;
   1518      const StyleCounterStyle* style;
   1519      nsString separator;
   1520      if (type == Type::Counter) {
   1521        const auto& counter = aItem.AsCounter();
   1522        name = counter._0.AsAtom();
   1523        style = &counter._1;
   1524      } else {
   1525        const auto& counters = aItem.AsCounters();
   1526        name = counters._0.AsAtom();
   1527        CopyUTF8toUTF16(counters._1.AsString(), separator);
   1528        style = &counters._2;
   1529      }
   1530 
   1531      auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
   1532          aOriginatingElement, name);
   1533      auto node = MakeUnique<nsCounterUseNode>(
   1534          *style, std::move(separator), aContentIndex,
   1535          /* aAllCounters = */ type == Type::Counters);
   1536 
   1537      auto initializer = MakeUnique<nsGenConInitializer>(
   1538          std::move(node), counterList, &nsCSSFrameConstructor::CountersDirty);
   1539      RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
   1540      aAddChild(c);
   1541      return;
   1542    }
   1543    case Type::OpenQuote:
   1544    case Type::CloseQuote:
   1545    case Type::NoOpenQuote:
   1546    case Type::NoCloseQuote: {
   1547      auto node = MakeUnique<nsQuoteNode>(type, aContentIndex);
   1548      auto* quoteList =
   1549          mContainStyleScopeManager.QuoteListFor(aOriginatingElement);
   1550      auto initializer = MakeUnique<nsGenConInitializer>(
   1551          std::move(node), quoteList, &nsCSSFrameConstructor::QuotesDirty);
   1552      RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
   1553      aAddChild(c);
   1554      return;
   1555    }
   1556 
   1557    case Type::MozLabelContent: {
   1558      nsAutoString accesskey;
   1559      if (!aOriginatingElement.GetAttr(nsGkAtoms::accesskey, accesskey) ||
   1560          accesskey.IsEmpty() || !LookAndFeel::GetMenuAccessKey()) {
   1561        // Easy path: just return a regular value attribute content.
   1562        nsCOMPtr<nsIContent> content;
   1563        NS_NewAttributeContent(mDocument->NodeInfoManager(), kNameSpaceID_None,
   1564                               nsGkAtoms::value, nsGkAtoms::_empty,
   1565                               getter_AddRefs(content));
   1566        aAddChild(content);
   1567        return;
   1568      }
   1569 
   1570      nsAutoString value;
   1571      aOriginatingElement.GetAttr(nsGkAtoms::value, value);
   1572 
   1573      auto AppendAccessKeyLabel = [&] {
   1574        // Always append accesskey text in uppercase, see bug 1806167.
   1575        ToUpperCase(accesskey);
   1576        nsAutoString accessKeyLabel = u"("_ns + accesskey + u")"_ns;
   1577        if (!StringEndsWith(value, accessKeyLabel)) {
   1578          if (InsertSeparatorBeforeAccessKey() && !value.IsEmpty() &&
   1579              !NS_IS_SPACE(value.Last())) {
   1580            value.Append(' ');
   1581          }
   1582          value.Append(accessKeyLabel);
   1583        }
   1584      };
   1585      if (AlwaysAppendAccessKey()) {
   1586        AppendAccessKeyLabel();
   1587        RefPtr c = CreateGenConTextNode(aState, value, nullptr);
   1588        aAddChild(c);
   1589        return;
   1590      }
   1591 
   1592      const auto accessKeyStart = [&]() -> Maybe<size_t> {
   1593        nsAString::const_iterator start, end;
   1594        value.BeginReading(start);
   1595        value.EndReading(end);
   1596 
   1597        const auto originalStart = start;
   1598        // not appending access key - do case-sensitive search
   1599        // first
   1600        bool found = true;
   1601        if (!FindInReadable(accesskey, start, end)) {
   1602          start = originalStart;
   1603          // didn't find it - perform a case-insensitive search
   1604          found = FindInReadable(accesskey, start, end,
   1605                                 nsCaseInsensitiveStringComparator);
   1606        }
   1607        if (!found) {
   1608          return Nothing();
   1609        }
   1610        return Some(Distance(originalStart, start));
   1611      }();
   1612 
   1613      if (accessKeyStart.isNothing()) {
   1614        AppendAccessKeyLabel();
   1615        RefPtr c = CreateGenConTextNode(aState, value, nullptr);
   1616        aAddChild(c);
   1617        return;
   1618      }
   1619 
   1620      if (*accessKeyStart != 0) {
   1621        RefPtr beginning = CreateGenConTextNode(
   1622            aState, Substring(value, 0, *accessKeyStart), nullptr);
   1623        aAddChild(beginning);
   1624      }
   1625 
   1626      {
   1627        RefPtr accessKeyText = CreateGenConTextNode(
   1628            aState, Substring(value, *accessKeyStart, accesskey.Length()),
   1629            nullptr);
   1630        RefPtr<nsIContent> underline =
   1631            mDocument->CreateHTMLElement(nsGkAtoms::u);
   1632        underline->AppendChildTo(accessKeyText, /* aNotify = */ false,
   1633                                 IgnoreErrors());
   1634        aAddChild(underline);
   1635      }
   1636 
   1637      size_t accessKeyEnd = *accessKeyStart + accesskey.Length();
   1638      if (accessKeyEnd != value.Length()) {
   1639        RefPtr valueEnd = CreateGenConTextNode(
   1640            aState, Substring(value, *accessKeyStart + accesskey.Length()),
   1641            nullptr);
   1642        aAddChild(valueEnd);
   1643      }
   1644      break;
   1645    }
   1646    case Type::MozAltContent: {
   1647      // Use the "alt" attribute; if that fails and the node is an HTML
   1648      // <input>, try the value attribute and then fall back to some default
   1649      // localized text we have.
   1650      // XXX what if the 'alt' attribute is added later, how will we
   1651      // detect that and do the right thing here?
   1652      if (aOriginatingElement.HasAttr(nsGkAtoms::alt)) {
   1653        nsCOMPtr<nsIContent> content;
   1654        NS_NewAttributeContent(mDocument->NodeInfoManager(), kNameSpaceID_None,
   1655                               nsGkAtoms::alt, nsGkAtoms::_empty,
   1656                               getter_AddRefs(content));
   1657        aAddChild(content);
   1658        return;
   1659      }
   1660 
   1661      if (aOriginatingElement.IsHTMLElement(nsGkAtoms::input)) {
   1662        if (aOriginatingElement.HasAttr(nsGkAtoms::value)) {
   1663          nsCOMPtr<nsIContent> content;
   1664          NS_NewAttributeContent(mDocument->NodeInfoManager(),
   1665                                 kNameSpaceID_None, nsGkAtoms::value,
   1666                                 nsGkAtoms::_empty, getter_AddRefs(content));
   1667          aAddChild(content);
   1668          return;
   1669        }
   1670 
   1671        nsAutoString temp;
   1672        nsContentUtils::GetMaybeLocalizedString(
   1673            nsContentUtils::eFORMS_PROPERTIES, "Submit", mDocument, temp);
   1674        RefPtr c = CreateGenConTextNode(aState, temp, nullptr);
   1675        aAddChild(c);
   1676        return;
   1677      }
   1678      break;
   1679    }
   1680  }
   1681 }
   1682 
   1683 void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
   1684    nsFrameConstructorState& aState, Element& aOriginatingElement,
   1685    const ComputedStyle& aPseudoStyle,
   1686    const FunctionRef<void(nsIContent*)> aAddChild) {
   1687  const nsStyleList* styleList = aPseudoStyle.StyleList();
   1688  if (!styleList->mListStyleImage.IsNone()) {
   1689    RefPtr<nsIContent> child =
   1690        GeneratedImageContent::CreateForListStyleImage(*mDocument);
   1691    aAddChild(child);
   1692    child = CreateGenConTextNode(aState, u" "_ns, nullptr);
   1693    aAddChild(child);
   1694    return;
   1695  }
   1696  CreateGeneratedContentFromListStyleType(aState, aOriginatingElement,
   1697                                          aPseudoStyle, aAddChild);
   1698 }
   1699 
   1700 void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType(
   1701    nsFrameConstructorState& aState, Element& aOriginatingElement,
   1702    const ComputedStyle& aPseudoStyle,
   1703    const FunctionRef<void(nsIContent*)> aAddChild) {
   1704  using Tag = StyleCounterStyle::Tag;
   1705  const auto& styleType = aPseudoStyle.StyleList()->mListStyleType;
   1706  switch (styleType.tag) {
   1707    case Tag::None:
   1708      return;
   1709    case Tag::String: {
   1710      nsDependentAtomString string(styleType.AsString().AsAtom());
   1711      RefPtr<nsIContent> child = CreateGenConTextNode(aState, string, nullptr);
   1712      aAddChild(child);
   1713      return;
   1714    }
   1715    case Tag::Name:
   1716    case Tag::Symbols:
   1717      break;
   1718  }
   1719 
   1720  auto node = MakeUnique<nsCounterUseNode>(nsCounterUseNode::ForLegacyBullet,
   1721                                           styleType);
   1722  if (styleType.IsName()) {
   1723    nsAtom* name = styleType.AsName().AsAtom();
   1724    if (name == nsGkAtoms::disc || name == nsGkAtoms::circle ||
   1725        name == nsGkAtoms::square || name == nsGkAtoms::disclosure_closed ||
   1726        name == nsGkAtoms::disclosure_open) {
   1727      // We don't need a use node inserted for these.
   1728      CounterStyle* counterStyle = mPresShell->GetPresContext()
   1729                                       ->CounterStyleManager()
   1730                                       ->ResolveCounterStyle(name);
   1731      nsAutoString text;
   1732      node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
   1733      // Note that we're done with 'node' in this case.  It's not inserted into
   1734      // any list so it's deleted when we return.
   1735      RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
   1736      aAddChild(child);
   1737      return;
   1738    }
   1739  }
   1740 
   1741  auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
   1742      aOriginatingElement, nsGkAtoms::list_item);
   1743  auto initializer = MakeUnique<nsGenConInitializer>(
   1744      std::move(node), counterList, &nsCSSFrameConstructor::CountersDirty);
   1745  RefPtr<nsIContent> child =
   1746      CreateGenConTextNode(aState, EmptyString(), std::move(initializer));
   1747  aAddChild(child);
   1748 }
   1749 
   1750 // Frames for these may not be leaves in the proper sense, but we still don't
   1751 // want to expose generated content on them. For the purposes of the page they
   1752 // should be leaves.
   1753 static bool HasUAWidget(const Element& aOriginatingElement) {
   1754  const ShadowRoot* sr = aOriginatingElement.GetShadowRoot();
   1755  return sr && sr->IsUAWidget();
   1756 }
   1757 
   1758 /*
   1759 * aParentFrame - the frame that should be the parent of the generated
   1760 *   content.  This is the frame for the corresponding content node,
   1761 *   which must not be a leaf frame.
   1762 *
   1763 * Any items created are added to aItems.
   1764 *
   1765 * We create an XML element (tag _moz_generated_content_before/after/marker)
   1766 * representing the pseudoelement. We create a DOM node for each 'content'
   1767 * item and make those nodes the children of the XML element. Then we create
   1768 * a frame subtree for the XML element as if it were a regular child of
   1769 * aParentFrame/aParentContent, giving the XML element the ::before, ::after
   1770 * or ::marker style.
   1771 */
   1772 void nsCSSFrameConstructor::CreateGeneratedContentItem(
   1773    nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
   1774    Element& aOriginatingElement, ComputedStyle& aStyle,
   1775    PseudoStyleType aPseudoElement, FrameConstructionItemList& aItems,
   1776    ItemFlags aExtraFlags) {
   1777  MOZ_ASSERT(aPseudoElement == PseudoStyleType::before ||
   1778                 aPseudoElement == PseudoStyleType::after ||
   1779                 aPseudoElement == PseudoStyleType::marker ||
   1780                 aPseudoElement == PseudoStyleType::backdrop,
   1781             "unexpected aPseudoElement");
   1782 
   1783  if (aPseudoElement != PseudoStyleType::backdrop &&
   1784      HasUAWidget(aOriginatingElement) &&
   1785      !aOriginatingElement.IsHTMLElement(nsGkAtoms::details)) {
   1786    // ::before / ::after / ::marker shouldn't work on <video> / <input>.
   1787    return;
   1788  }
   1789 
   1790  ServoStyleSet* styleSet = mPresShell->StyleSet();
   1791 
   1792  // Probe for the existence of the pseudo-element.
   1793  // |ProbePseudoElementStyle| checks the relevant properties for the pseudo.
   1794  // It only returns a non-null value if the pseudo should exist.
   1795  RefPtr<ComputedStyle> pseudoStyle = styleSet->ProbePseudoElementStyle(
   1796      aOriginatingElement, aPseudoElement, nullptr, &aStyle);
   1797  if (!pseudoStyle) {
   1798    return;
   1799  }
   1800 
   1801  nsAtom* elemName = nullptr;
   1802  nsAtom* property = nullptr;
   1803  switch (aPseudoElement) {
   1804    case PseudoStyleType::before:
   1805      elemName = nsGkAtoms::mozgeneratedcontentbefore;
   1806      property = nsGkAtoms::beforePseudoProperty;
   1807      break;
   1808    case PseudoStyleType::after:
   1809      elemName = nsGkAtoms::mozgeneratedcontentafter;
   1810      property = nsGkAtoms::afterPseudoProperty;
   1811      break;
   1812    case PseudoStyleType::marker:
   1813      // We want to get a marker style even if we match no rules, but we still
   1814      // want to check the result of GeneratedContentPseudoExists.
   1815      elemName = nsGkAtoms::mozgeneratedcontentmarker;
   1816      property = nsGkAtoms::markerPseudoProperty;
   1817      break;
   1818    case PseudoStyleType::backdrop:
   1819      elemName = nsGkAtoms::mozgeneratedcontentbackdrop;
   1820      property = nsGkAtoms::backdropPseudoProperty;
   1821      break;
   1822    default:
   1823      MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement");
   1824  }
   1825 
   1826  RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
   1827      elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
   1828  RefPtr<Element> container;
   1829  nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
   1830  if (NS_FAILED(rv)) {
   1831    return;
   1832  }
   1833 
   1834  // Cleared when the pseudo is unbound from the tree, so no need to store a
   1835  // strong reference, nor a destructor.
   1836  aOriginatingElement.SetProperty(property, container.get());
   1837 
   1838  container->SetIsNativeAnonymousRoot();
   1839  container->SetPseudoElementType(aPseudoElement);
   1840 
   1841  BindContext context(aOriginatingElement, BindContext::ForNativeAnonymous);
   1842  rv = container->BindToTree(context, aOriginatingElement);
   1843  if (NS_FAILED(rv)) {
   1844    container->UnbindFromTree();
   1845    return;
   1846  }
   1847 
   1848  if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
   1849    container->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
   1850  }
   1851 
   1852  // Servo has already eagerly computed the style for the container, so we can
   1853  // just stick the style on the element and avoid an additional traversal.
   1854  //
   1855  // We don't do this for pseudos that may trigger animations or transitions,
   1856  // since those need to be kicked off by the traversal machinery.
   1857  //
   1858  // Note that when a pseudo-element animates, we flag the originating element,
   1859  // so we check that flag, but we could also a more expensive (but exhaustive)
   1860  // check using EffectSet::GetEffectSet, for example.
   1861  if (!Servo_ComputedValues_SpecifiesAnimationsOrTransitions(pseudoStyle) &&
   1862      !aOriginatingElement.MayHaveAnimations()) {
   1863    Servo_SetExplicitStyle(container, pseudoStyle);
   1864  } else {
   1865    // If animations are involved, we avoid the SetExplicitStyle optimization
   1866    // above. We need to grab style with animations from the pseudo element and
   1867    // replace old one.
   1868    mPresShell->StyleSet()->StyleNewSubtree(container);
   1869    pseudoStyle = ServoStyleSet::ResolveServoStyle(*container);
   1870  }
   1871  if (aPseudoElement != PseudoStyleType::backdrop) {
   1872    auto AppendChild = [&container, this](nsIContent* aChild) {
   1873      // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
   1874      // here; it would get set under AppendChildTo.  But AppendChildTo might
   1875      // think that we're going from not being anonymous to being anonymous and
   1876      // do some extra work; setting the flag here avoids that.
   1877      aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
   1878      container->AppendChildTo(aChild, false, IgnoreErrors());
   1879      if (auto* childElement = Element::FromNode(aChild)) {
   1880        // If we created any children elements, Servo needs to traverse them,
   1881        // but the root is already set up.
   1882        mPresShell->StyleSet()->StyleNewSubtree(childElement);
   1883      }
   1884    };
   1885    auto items = pseudoStyle->StyleContent()->NonAltContentItems();
   1886    size_t index = 0;
   1887    for (const auto& item : items) {
   1888      CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item,
   1889                             index++, AppendChild);
   1890    }
   1891    // If a ::marker has no 'content' then generate it from its 'list-style-*'.
   1892    if (index == 0 && aPseudoElement == PseudoStyleType::marker) {
   1893      CreateGeneratedContentFromListStyle(aState, aOriginatingElement,
   1894                                          *pseudoStyle, AppendChild);
   1895    }
   1896  }
   1897  auto flags = ItemFlags{ItemFlag::IsGeneratedContent} + aExtraFlags;
   1898  AddFrameConstructionItemsInternal(aState, container, aParentFrame, true,
   1899                                    pseudoStyle, flags, aItems);
   1900 }
   1901 
   1902 /****************************************************
   1903 **  BEGIN TABLE SECTION
   1904 ****************************************************/
   1905 
   1906 // The term pseudo frame is being used instead of anonymous frame, since
   1907 // anonymous frame has been used elsewhere to refer to frames that have
   1908 // generated content
   1909 
   1910 // Return whether the given frame is a table pseudo-frame. Note that
   1911 // cell-content and table-outer frames have pseudo-types, but are always
   1912 // created, even for non-anonymous cells and tables respectively.  So for those
   1913 // we have to examine the cell or table frame to see whether it's a pseudo
   1914 // frame. In particular, a lone table caption will have a table wrapper as its
   1915 // parent, but will also trigger construction of an empty inner table, which
   1916 // will be the one we can examine to see whether the wrapper was a pseudo-frame.
   1917 static bool IsTablePseudo(nsIFrame* aFrame) {
   1918  auto pseudoType = aFrame->Style()->GetPseudoType();
   1919  if (pseudoType == PseudoStyleType::NotPseudo) {
   1920    return false;
   1921  }
   1922  return pseudoType == PseudoStyleType::table ||
   1923         pseudoType == PseudoStyleType::inlineTable ||
   1924         pseudoType == PseudoStyleType::tableColGroup ||
   1925         pseudoType == PseudoStyleType::tableRowGroup ||
   1926         pseudoType == PseudoStyleType::tableRow ||
   1927         pseudoType == PseudoStyleType::tableCell ||
   1928         (pseudoType == PseudoStyleType::cellContent &&
   1929          aFrame->GetParent()->Style()->GetPseudoType() ==
   1930              PseudoStyleType::tableCell) ||
   1931         (pseudoType == PseudoStyleType::tableWrapper &&
   1932          static_cast<nsTableWrapperFrame*>(aFrame)
   1933              ->InnerTableFrame()
   1934              ->Style()
   1935              ->IsPseudoOrAnonBox());
   1936 }
   1937 
   1938 static bool IsRubyPseudo(nsIFrame* aFrame) {
   1939  return RubyUtils::IsRubyPseudo(aFrame->Style()->GetPseudoType());
   1940 }
   1941 
   1942 // Note that this is (subtly) different to ParentIsWrapperAnonBox, since
   1943 // ParentIsWrapperAnonBox is really just about restyles, but there are wrapper
   1944 // anon boxes that don't need to return true for that...
   1945 // FIXME(emilio): This should be less complicated, ParentIsWrapperAnonBox should
   1946 // probably be renamed to something else, and this should just use
   1947 // IsWrapperAnonBox or similar...
   1948 static bool IsWrapperPseudo(nsIFrame* aFrame) {
   1949  auto pseudoType = aFrame->Style()->GetPseudoType();
   1950  if (!PseudoStyle::IsAnonBox(pseudoType)) {
   1951    return false;
   1952  }
   1953  return PseudoStyle::IsWrapperAnonBox(pseudoType) || IsTablePseudo(aFrame);
   1954 }
   1955 
   1956 static bool IsInAnonymousTable(nsIFrame* aFrame) {
   1957  for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
   1958    if (!IsWrapperPseudo(f)) {
   1959      return false;
   1960    }
   1961    if (f->IsTableWrapperFrame()) {
   1962      return true;
   1963    }
   1964  }
   1965  MOZ_ASSERT_UNREACHABLE("Expected to be called inside tables");
   1966  return false;
   1967 }
   1968 
   1969 /* static */
   1970 nsCSSFrameConstructor::ParentType nsCSSFrameConstructor::GetParentType(
   1971    LayoutFrameType aFrameType) {
   1972  if (aFrameType == LayoutFrameType::Table) {
   1973    return eTypeTable;
   1974  }
   1975  if (aFrameType == LayoutFrameType::TableRowGroup) {
   1976    return eTypeRowGroup;
   1977  }
   1978  if (aFrameType == LayoutFrameType::TableRow) {
   1979    return eTypeRow;
   1980  }
   1981  if (aFrameType == LayoutFrameType::TableColGroup) {
   1982    return eTypeColGroup;
   1983  }
   1984  if (aFrameType == LayoutFrameType::RubyBaseContainer) {
   1985    return eTypeRubyBaseContainer;
   1986  }
   1987  if (aFrameType == LayoutFrameType::RubyTextContainer) {
   1988    return eTypeRubyTextContainer;
   1989  }
   1990  if (aFrameType == LayoutFrameType::Ruby) {
   1991    return eTypeRuby;
   1992  }
   1993 
   1994  return eTypeBlock;
   1995 }
   1996 
   1997 // Pull all the captions present in aItems out into aCaptions.
   1998 static void PullOutCaptionFrames(nsFrameList& aList, nsFrameList& aCaptions) {
   1999  nsIFrame* child = aList.FirstChild();
   2000  while (child) {
   2001    nsIFrame* nextSibling = child->GetNextSibling();
   2002    if (child->StyleDisplay()->mDisplay == StyleDisplay::TableCaption) {
   2003      aList.RemoveFrame(child);
   2004      aCaptions.AppendFrame(nullptr, child);
   2005    }
   2006    child = nextSibling;
   2007  }
   2008 }
   2009 
   2010 // Construct the outer, inner table frames and the children frames for the
   2011 // table.
   2012 // XXX Page break frames for pseudo table frames are not constructed to avoid
   2013 // the risk associated with revising the pseudo frame mechanism. The long term
   2014 // solution of having frames handle page-break-before/after will solve the
   2015 // problem.
   2016 nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
   2017                                                FrameConstructionItem& aItem,
   2018                                                nsContainerFrame* aParentFrame,
   2019                                                const nsStyleDisplay* aDisplay,
   2020                                                nsFrameList& aFrameList) {
   2021  MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::Table ||
   2022                 aDisplay->mDisplay == StyleDisplay::InlineTable,
   2023             "Unexpected call");
   2024 
   2025  nsIContent* const content = aItem.mContent;
   2026  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   2027  const bool isMathMLContent = content->IsMathMLElement();
   2028 
   2029  // create the pseudo SC for the table wrapper as a child of the inner SC
   2030  RefPtr<ComputedStyle> outerComputedStyle =
   2031      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   2032          PseudoStyleType::tableWrapper, computedStyle);
   2033 
   2034  // Create the table wrapper frame which holds the caption and inner table
   2035  // frame
   2036  nsContainerFrame* newFrame;
   2037  if (isMathMLContent) {
   2038    newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerComputedStyle);
   2039  } else {
   2040    newFrame = NS_NewTableWrapperFrame(mPresShell, outerComputedStyle);
   2041  }
   2042 
   2043  nsContainerFrame* geometricParent = aState.GetGeometricParent(
   2044      *outerComputedStyle->StyleDisplay(), aParentFrame);
   2045 
   2046  // Init the table wrapper frame
   2047  InitAndRestoreFrame(aState, content, geometricParent, newFrame);
   2048 
   2049  // Create the inner table frame
   2050  nsContainerFrame* innerFrame;
   2051  if (isMathMLContent) {
   2052    innerFrame = NS_NewMathMLmtableFrame(mPresShell, computedStyle);
   2053  } else {
   2054    innerFrame = NS_NewTableFrame(mPresShell, computedStyle);
   2055  }
   2056 
   2057  InitAndRestoreFrame(aState, content, newFrame, innerFrame);
   2058  innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   2059 
   2060  // Put the newly created frames into the right child list
   2061  SetInitialSingleChild(newFrame, innerFrame);
   2062 
   2063  aState.AddChild(newFrame, aFrameList, content, aParentFrame);
   2064 
   2065  if (!mRootElementFrame) {
   2066    mRootElementFrame = newFrame;
   2067  }
   2068 
   2069  nsFrameList childList;
   2070 
   2071  // Process children
   2072  nsFrameConstructorSaveState absoluteSaveState;
   2073 
   2074  // Mark the table frame as an absolute container if needed
   2075  newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2076  if (newFrame->IsAbsPosContainingBlock()) {
   2077    aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
   2078  }
   2079 
   2080  nsFrameConstructorSaveState floatSaveState;
   2081  aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
   2082 
   2083  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
   2084    ConstructFramesFromItemList(
   2085        aState, aItem.mChildItems, innerFrame,
   2086        aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childList);
   2087  } else {
   2088    ProcessChildren(aState, content, computedStyle, innerFrame, true, childList,
   2089                    false);
   2090  }
   2091 
   2092  nsFrameList captionList;
   2093  PullOutCaptionFrames(childList, captionList);
   2094 
   2095  // Set the inner table frame's principal child list.
   2096  innerFrame->SetInitialChildList(FrameChildListID::Principal,
   2097                                  std::move(childList));
   2098 
   2099  // Append caption frames to the table wrapper frame's principal child list.
   2100  if (captionList.NotEmpty()) {
   2101    captionList.ApplySetParent(newFrame);
   2102    newFrame->AppendFrames(FrameChildListID::Principal, std::move(captionList));
   2103  }
   2104 
   2105  return newFrame;
   2106 }
   2107 
   2108 static void MakeTablePartAbsoluteContainingBlock(
   2109    nsFrameConstructorState& aState, nsFrameConstructorSaveState& aAbsSaveState,
   2110    nsContainerFrame* aFrame) {
   2111  // If we're positioned, then we need to become an absolute containing block
   2112  // for any absolutely positioned children.
   2113  aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2114  if (aFrame->IsAbsPosContainingBlock()) {
   2115    aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
   2116  }
   2117 }
   2118 
   2119 nsIFrame* nsCSSFrameConstructor::ConstructTableRowOrRowGroup(
   2120    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   2121    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
   2122    nsFrameList& aFrameList) {
   2123  MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableRow ||
   2124                 aDisplay->mDisplay == StyleDisplay::TableRowGroup ||
   2125                 aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
   2126                 aDisplay->mDisplay == StyleDisplay::TableHeaderGroup,
   2127             "Not a row or row group");
   2128  MOZ_ASSERT(aItem.mComputedStyle->StyleDisplay() == aDisplay,
   2129             "Display style doesn't match style");
   2130  nsIContent* const content = aItem.mContent;
   2131  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   2132 
   2133  nsContainerFrame* newFrame;
   2134  if (aDisplay->mDisplay == StyleDisplay::TableRow) {
   2135    if (content->IsMathMLElement()) {
   2136      newFrame = NS_NewMathMLmtrFrame(mPresShell, computedStyle);
   2137    } else {
   2138      newFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
   2139    }
   2140  } else {
   2141    newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
   2142  }
   2143 
   2144  InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
   2145 
   2146  nsFrameConstructorSaveState absoluteSaveState;
   2147  MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, newFrame);
   2148 
   2149  nsFrameConstructorSaveState floatSaveState;
   2150  aState.MaybePushFloatContainingBlock(newFrame, floatSaveState);
   2151 
   2152  nsFrameList childList;
   2153  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
   2154    ConstructFramesFromItemList(
   2155        aState, aItem.mChildItems, newFrame,
   2156        aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childList);
   2157  } else {
   2158    ProcessChildren(aState, content, computedStyle, newFrame, true, childList,
   2159                    false);
   2160  }
   2161 
   2162  newFrame->SetInitialChildList(FrameChildListID::Principal,
   2163                                std::move(childList));
   2164  aFrameList.AppendFrame(nullptr, newFrame);
   2165  return newFrame;
   2166 }
   2167 
   2168 nsIFrame* nsCSSFrameConstructor::ConstructTableCol(
   2169    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   2170    nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
   2171    nsFrameList& aFrameList) {
   2172  nsIContent* const content = aItem.mContent;
   2173  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   2174 
   2175  nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, computedStyle);
   2176  InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
   2177 
   2178  NS_ASSERTION(colFrame->Style() == computedStyle, "Unexpected style");
   2179 
   2180  aFrameList.AppendFrame(nullptr, colFrame);
   2181 
   2182  // construct additional col frames if the col frame has a span > 1
   2183  int32_t span = colFrame->GetSpan();
   2184  for (int32_t spanX = 1; spanX < span; spanX++) {
   2185    nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, computedStyle);
   2186    InitAndRestoreFrame(aState, content, aParentFrame, newCol, false);
   2187    aFrameList.LastChild()->SetNextContinuation(newCol);
   2188    newCol->SetPrevContinuation(aFrameList.LastChild());
   2189    aFrameList.AppendFrame(nullptr, newCol);
   2190    newCol->SetColType(eColAnonymousCol);
   2191  }
   2192 
   2193  return colFrame;
   2194 }
   2195 
   2196 nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
   2197    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   2198    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
   2199    nsFrameList& aFrameList) {
   2200  MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableCell, "Unexpected call");
   2201 
   2202  nsIContent* const content = aItem.mContent;
   2203  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   2204  const bool isMathMLContent = content->IsMathMLElement();
   2205 
   2206  nsTableFrame* tableFrame =
   2207      static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
   2208  nsContainerFrame* cellFrame;
   2209  // <mtable> is border separate in mathml.css and the MathML code doesn't
   2210  // implement border collapse. For those users who style <mtable> with border
   2211  // collapse, give them the default non-MathML table frames that understand
   2212  // border collapse. This won't break us because MathML table frames are all
   2213  // subclasses of the default table code, and so we can freely mix <mtable>
   2214  // with <mtr> or <tr>, <mtd> or <td>. What will happen is just that non-MathML
   2215  // frames won't understand MathML attributes and will therefore miss the
   2216  // special handling that the MathML code does.
   2217  if (isMathMLContent && !tableFrame->IsBorderCollapse()) {
   2218    cellFrame = NS_NewMathMLmtdFrame(mPresShell, computedStyle, tableFrame);
   2219  } else {
   2220    // Warning: If you change this and add a wrapper frame around table cell
   2221    // frames, make sure Bug 368554 doesn't regress!
   2222    // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
   2223    cellFrame = NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
   2224  }
   2225 
   2226  // Initialize the table cell frame
   2227  InitAndRestoreFrame(aState, content, aParentFrame, cellFrame);
   2228  cellFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   2229 
   2230  // Resolve pseudo style and initialize the body cell frame
   2231  RefPtr<ComputedStyle> innerPseudoStyle =
   2232      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   2233          PseudoStyleType::cellContent, computedStyle);
   2234 
   2235  nsContainerFrame* cellInnerFrame;
   2236  nsContainerFrame* scrollFrame = nullptr;
   2237  bool isScrollable = false;
   2238  // Create a block frame that will format the cell's content
   2239  if (isMathMLContent) {
   2240    cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
   2241  } else {
   2242    isScrollable = innerPseudoStyle->StyleDisplay()->IsScrollableOverflow() &&
   2243                   !aState.mPresContext->IsPaginated() &&
   2244                   StaticPrefs::layout_tables_scrollable_cells();
   2245    if (isScrollable) {
   2246      innerPseudoStyle = BeginBuildingScrollContainerFrame(
   2247          aState, content, innerPseudoStyle, cellFrame,
   2248          PseudoStyleType::scrolledContent, false, scrollFrame);
   2249    }
   2250    cellInnerFrame = NS_NewBlockFrame(mPresShell, innerPseudoStyle);
   2251  }
   2252  auto* parent = scrollFrame ? scrollFrame : cellFrame;
   2253  InitAndRestoreFrame(aState, content, parent, cellInnerFrame);
   2254 
   2255  nsFrameConstructorSaveState absoluteSaveState;
   2256  MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, cellFrame);
   2257 
   2258  nsFrameConstructorSaveState floatSaveState;
   2259  aState.MaybePushFloatContainingBlock(cellInnerFrame, floatSaveState);
   2260 
   2261  nsFrameList childList;
   2262  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
   2263    AutoFrameConstructionPageName pageNameTracker(aState, cellInnerFrame);
   2264    ConstructFramesFromItemList(
   2265        aState, aItem.mChildItems, cellInnerFrame,
   2266        aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childList);
   2267  } else {
   2268    // Process the child content
   2269    ProcessChildren(aState, content, computedStyle, cellInnerFrame, true,
   2270                    childList, !isMathMLContent);
   2271  }
   2272 
   2273  cellInnerFrame->SetInitialChildList(FrameChildListID::Principal,
   2274                                      std::move(childList));
   2275 
   2276  if (isScrollable) {
   2277    FinishBuildingScrollContainerFrame(scrollFrame, cellInnerFrame);
   2278  }
   2279  SetInitialSingleChild(cellFrame, scrollFrame ? scrollFrame : cellInnerFrame);
   2280  aFrameList.AppendFrame(nullptr, cellFrame);
   2281  return cellFrame;
   2282 }
   2283 
   2284 static inline bool NeedFrameFor(const nsFrameConstructorState& aState,
   2285                                nsContainerFrame* aParentFrame,
   2286                                nsIContent* aChildContent) {
   2287  // XXX the GetContent() != aChildContent check is needed due to bug 135040.
   2288  // Remove it once that's fixed.
   2289  MOZ_ASSERT(
   2290      !aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
   2291          aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
   2292      "Why did we get called?");
   2293 
   2294  // don't create a whitespace frame if aParentFrame doesn't want it.
   2295  // always create frames for children in generated content. counter(),
   2296  // quotes, and attr() content can easily change dynamically and we don't
   2297  // want to be reconstructing frames. It's not even clear that these
   2298  // should be considered ignorable just because they evaluate to
   2299  // whitespace.
   2300 
   2301  // We could handle all this in CreateNeededPseudoContainers or some other
   2302  // place after we build our frame construction items, but that would involve
   2303  // creating frame construction items for whitespace kids that ignores
   2304  // white-space, where we know we'll be dropping them all anyway, and involve
   2305  // an extra walk down the frame construction item list.
   2306  auto excludesIgnorableWhitespace = [](nsIFrame* aParentFrame) {
   2307    return aParentFrame->IsMathMLFrame();
   2308  };
   2309  if (!aParentFrame || !excludesIgnorableWhitespace(aParentFrame) ||
   2310      aParentFrame->IsGeneratedContentFrame() || !aChildContent->IsText()) {
   2311    return true;
   2312  }
   2313 
   2314  aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
   2315                          NS_REFRAME_IF_WHITESPACE);
   2316  return !aChildContent->TextIsOnlyWhitespace();
   2317 }
   2318 
   2319 /***********************************************
   2320 * END TABLE SECTION
   2321 ***********************************************/
   2322 
   2323 nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
   2324    Element* aDocElement) {
   2325  MOZ_ASSERT(GetRootFrame(),
   2326             "No viewport?  Someone forgot to call ConstructRootFrame!");
   2327  MOZ_ASSERT(!mDocElementContainingBlock,
   2328             "Shouldn't have a doc element containing block here");
   2329 
   2330  // Resolve a new style for the viewport since it may be affected by a new root
   2331  // element style (e.g. a propagated 'direction').
   2332  //
   2333  // @see ComputedStyle::ApplyStyleFixups
   2334  {
   2335    RefPtr<ComputedStyle> sc =
   2336        mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   2337            PseudoStyleType::viewport, nullptr);
   2338    GetRootFrame()->SetComputedStyleWithoutNotification(sc);
   2339  }
   2340 
   2341  // Ensure the document element is styled at this point.
   2342  // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
   2343  // construction from PresShell::Initialize.
   2344  if (!aDocElement->HasServoData()) {
   2345    mPresShell->StyleSet()->StyleNewSubtree(aDocElement);
   2346  }
   2347  aDocElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
   2348 
   2349  // Make sure to call UpdateViewportScrollStylesOverride before
   2350  // SetUpDocElementContainingBlock, since it sets up our scrollbar state
   2351  // properly.
   2352  DebugOnly<nsIContent*> propagatedScrollFrom;
   2353  if (nsPresContext* presContext = mPresShell->GetPresContext()) {
   2354    propagatedScrollFrom = presContext->UpdateViewportScrollStylesOverride();
   2355  }
   2356 
   2357  SetUpDocElementContainingBlock(aDocElement);
   2358 
   2359  // This has the side-effect of getting `mFrameTreeState` from our docshell.
   2360  //
   2361  // FIXME(emilio): There may be a more sensible time to do this.
   2362  if (!mFrameTreeState) {
   2363    mPresShell->CaptureHistoryState(getter_AddRefs(mFrameTreeState));
   2364  }
   2365 
   2366  NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
   2367  nsFrameConstructorState state(
   2368      mPresShell,
   2369      GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
   2370      nullptr, nullptr, do_AddRef(mFrameTreeState));
   2371 
   2372  RefPtr<ComputedStyle> computedStyle =
   2373      ServoStyleSet::ResolveServoStyle(*aDocElement);
   2374 
   2375  const nsStyleDisplay* display = computedStyle->StyleDisplay();
   2376 
   2377  // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
   2378 
   2379  NS_ASSERTION(!display->IsScrollableOverflow() ||
   2380                   state.mPresContext->IsPaginated() ||
   2381                   propagatedScrollFrom == aDocElement,
   2382               "Scrollbars should have been propagated to the viewport");
   2383 
   2384  if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
   2385    return nullptr;
   2386  }
   2387 
   2388  // This implements "The Principal Writing Mode".
   2389  // https://drafts.csswg.org/css-writing-modes-3/#principal-flow
   2390  //
   2391  // If there's a <body> element in an HTML document, its writing-mode,
   2392  // direction, and text-orientation override the root element's used value.
   2393  //
   2394  // We need to copy <body>'s WritingMode to mDocElementContainingBlock before
   2395  // construct mRootElementFrame so that anonymous internal frames such as
   2396  // <html> with table style can copy their parent frame's mWritingMode in
   2397  // nsIFrame::Init().
   2398  MOZ_ASSERT(!mRootElementFrame,
   2399             "We need to copy <body>'s principal writing-mode before "
   2400             "constructing mRootElementFrame.");
   2401 
   2402  const WritingMode propagatedWM = [&] {
   2403    const WritingMode rootWM(computedStyle);
   2404    if (computedStyle->StyleDisplay()->IsContainAny()) {
   2405      return rootWM;
   2406    }
   2407    Element* body = mDocument->GetBodyElement();
   2408    if (!body) {
   2409      return rootWM;
   2410    }
   2411    RefPtr<ComputedStyle> bodyStyle = ResolveComputedStyle(body);
   2412    if (bodyStyle->StyleDisplay()->IsContainAny()) {
   2413      return rootWM;
   2414    }
   2415    const WritingMode bodyWM(bodyStyle);
   2416    if (bodyWM != rootWM) {
   2417      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Layout"_ns,
   2418                                      mDocument,
   2419                                      nsContentUtils::eLAYOUT_PROPERTIES,
   2420                                      "PrincipalWritingModePropagationWarning");
   2421    }
   2422    return bodyWM;
   2423  }();
   2424 
   2425  mDocElementContainingBlock->PropagateWritingModeToSelfAndAncestors(
   2426      propagatedWM);
   2427 
   2428  // Push the absolute containing block now so we can absolutely position the
   2429  // root element
   2430  nsFrameConstructorSaveState canvasCbSaveState;
   2431  mCanvasFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2432 
   2433  state.PushAbsoluteContainingBlock(mCanvasFrame, mCanvasFrame,
   2434                                    canvasCbSaveState);
   2435 
   2436  nsFrameConstructorSaveState docElementCbSaveState;
   2437  if (mCanvasFrame != mDocElementContainingBlock) {
   2438    mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2439    state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
   2440                                      mDocElementContainingBlock,
   2441                                      docElementCbSaveState);
   2442  }
   2443 
   2444  // The rules from CSS 2.1, section 9.2.4, have already been applied
   2445  // by the style system, so we can assume that display->mDisplay is
   2446  // either NONE, BLOCK, or TABLE.
   2447 
   2448  // contentFrame is the primary frame for the root element. frameList contains
   2449  // the children of the initial containing block.
   2450  //
   2451  // The first of those frames is usually `contentFrame`, but it can be
   2452  // different, in particular if the root frame is positioned, in which case
   2453  // contentFrame is the out-of-flow frame and frameList.FirstChild() is the
   2454  // placeholder.
   2455  //
   2456  // The rest of the frames in frameList are the anonymous content of the canvas
   2457  // frame.
   2458  nsContainerFrame* contentFrame;
   2459  nsFrameList frameList;
   2460  bool processChildren = false;
   2461 
   2462  nsFrameConstructorSaveState absoluteSaveState;
   2463 
   2464  if (aDocElement->IsSVGElement()) {
   2465    if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
   2466      return nullptr;
   2467    }
   2468    // We're going to call the right function ourselves, so no need to give a
   2469    // function to this FrameConstructionData.
   2470 
   2471    // XXXbz on the other hand, if we converted this whole function to
   2472    // FrameConstructionData/Item, then we'd need the right function
   2473    // here... but would probably be able to get away with less code in this
   2474    // function in general.
   2475    static constexpr FrameConstructionData rootSVGData;
   2476    AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
   2477                                   do_AddRef(computedStyle), true);
   2478 
   2479    contentFrame = static_cast<nsContainerFrame*>(ConstructOuterSVG(
   2480        state, item, mDocElementContainingBlock, display, frameList));
   2481  } else if (display->mDisplay == StyleDisplay::Flex ||
   2482             display->mDisplay == StyleDisplay::WebkitBox ||
   2483             display->mDisplay == StyleDisplay::Grid) {
   2484    auto func = [&] {
   2485      if (display->mDisplay == StyleDisplay::Grid) {
   2486        return NS_NewGridContainerFrame;
   2487      }
   2488      return NS_NewFlexContainerFrame;
   2489    }();
   2490    contentFrame = func(mPresShell, computedStyle);
   2491    InitAndRestoreFrame(
   2492        state, aDocElement,
   2493        state.GetGeometricParent(*display, mDocElementContainingBlock),
   2494        contentFrame);
   2495    state.AddChild(contentFrame, frameList, aDocElement,
   2496                   mDocElementContainingBlock);
   2497    processChildren = true;
   2498 
   2499    contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2500    if (contentFrame->IsAbsPosContainingBlock()) {
   2501      state.PushAbsoluteContainingBlock(contentFrame, contentFrame,
   2502                                        absoluteSaveState);
   2503    }
   2504  } else if (display->mDisplay == StyleDisplay::Table) {
   2505    // We're going to call the right function ourselves, so no need to give a
   2506    // function to this FrameConstructionData.
   2507 
   2508    // XXXbz on the other hand, if we converted this whole function to
   2509    // FrameConstructionData/Item, then we'd need the right function
   2510    // here... but would probably be able to get away with less code in this
   2511    // function in general.
   2512    static constexpr FrameConstructionData rootTableData;
   2513    AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
   2514                                   do_AddRef(computedStyle), true);
   2515 
   2516    // if the document is a table then just populate it.
   2517    contentFrame = static_cast<nsContainerFrame*>(ConstructTable(
   2518        state, item, mDocElementContainingBlock, display, frameList));
   2519  } else if (display->DisplayInside() == StyleDisplayInside::Ruby) {
   2520    static constexpr FrameConstructionData data(
   2521        &nsCSSFrameConstructor::ConstructBlockRubyFrame);
   2522    AutoFrameConstructionItem item(this, &data, aDocElement,
   2523                                   do_AddRef(computedStyle), true);
   2524    contentFrame = static_cast<nsContainerFrame*>(ConstructBlockRubyFrame(
   2525        state, item,
   2526        state.GetGeometricParent(*display, mDocElementContainingBlock), display,
   2527        frameList));
   2528  } else {
   2529    MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||
   2530                   display->mDisplay == StyleDisplay::FlowRoot,
   2531               "Unhandled display type for root element");
   2532    contentFrame = NS_NewBlockFrame(mPresShell, computedStyle);
   2533    ConstructBlock(
   2534        state, aDocElement,
   2535        state.GetGeometricParent(*display, mDocElementContainingBlock),
   2536        mDocElementContainingBlock, computedStyle, &contentFrame, frameList,
   2537        contentFrame->IsAbsPosContainingBlock() ? contentFrame : nullptr);
   2538  }
   2539 
   2540  MOZ_ASSERT(frameList.FirstChild());
   2541  MOZ_ASSERT(frameList.FirstChild()->GetContent() == aDocElement);
   2542  MOZ_ASSERT(contentFrame);
   2543 
   2544  MOZ_ASSERT(
   2545      processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame,
   2546      "unexpected mRootElementFrame");
   2547  if (processChildren) {
   2548    mRootElementFrame = contentFrame;
   2549  }
   2550 
   2551  // Figure out which frame has the main style for the document element,
   2552  // assigning it to mRootElementStyleFrame.
   2553  // Backgrounds should be propagated from that frame to the viewport.
   2554  contentFrame->GetParentComputedStyle(&mRootElementStyleFrame);
   2555  bool isChild = mRootElementStyleFrame &&
   2556                 mRootElementStyleFrame->GetParent() == contentFrame;
   2557  if (!isChild) {
   2558    mRootElementStyleFrame = mRootElementFrame;
   2559  }
   2560 
   2561  if (processChildren) {
   2562    // Still need to process the child content
   2563    nsFrameList childList;
   2564 
   2565    NS_ASSERTION(
   2566        !contentFrame->IsBlockFrameOrSubclass() && !contentFrame->IsSVGFrame(),
   2567        "Only XUL frames should reach here");
   2568 
   2569    nsFrameConstructorSaveState floatSaveState;
   2570    state.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
   2571 
   2572    ProcessChildren(state, aDocElement, computedStyle, contentFrame, true,
   2573                    childList, false);
   2574 
   2575    // Set the initial child lists
   2576    contentFrame->SetInitialChildList(FrameChildListID::Principal,
   2577                                      std::move(childList));
   2578  }
   2579 
   2580  nsIFrame* newFrame = frameList.FirstChild();
   2581  // set the primary frame
   2582  aDocElement->SetPrimaryFrame(contentFrame);
   2583  mDocElementContainingBlock->AppendFrames(FrameChildListID::Principal,
   2584                                           std::move(frameList));
   2585 
   2586  // NOTE(emilio): This is in the reverse order compared to normal anonymous
   2587  // children. We usually generate anonymous kids first, then non-anonymous,
   2588  // but we generate the doc element frame the other way around. This is fine
   2589  // either way, but generating anonymous children in a different order requires
   2590  // changing nsCanvasFrame (and a whole lot of other potentially unknown code)
   2591  // to look at the last child to find the root frame rather than the first
   2592  // child.
   2593  ConstructAnonymousContentForRoot(state, mCanvasFrame,
   2594                                   mRootElementFrame->GetContent(), frameList);
   2595  mCanvasFrame->AppendFrames(FrameChildListID::Principal, std::move(frameList));
   2596 
   2597  return newFrame;
   2598 }
   2599 
   2600 RestyleManager* nsCSSFrameConstructor::RestyleManager() const {
   2601  return mPresShell->GetPresContext()->RestyleManager();
   2602 }
   2603 
   2604 ViewportFrame* nsCSSFrameConstructor::ConstructRootFrame() {
   2605  AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ConstructRootFrame",
   2606                          LAYOUT_FrameConstruction);
   2607  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   2608 
   2609  ServoStyleSet* styleSet = mPresShell->StyleSet();
   2610 
   2611  // --------- BUILD VIEWPORT -----------
   2612  RefPtr<ComputedStyle> viewportPseudoStyle =
   2613      styleSet->ResolveInheritingAnonymousBoxStyle(PseudoStyleType::viewport,
   2614                                                   nullptr);
   2615  ViewportFrame* viewportFrame =
   2616      NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
   2617 
   2618  // XXXbz do we _have_ to pass a null content pointer to that frame?
   2619  // Would it really kill us to pass in the root element or something?
   2620  // What would that break?
   2621  viewportFrame->Init(nullptr, nullptr, nullptr);
   2622 
   2623  viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   2624 
   2625  mPresShell->SetNeedsWindowPropertiesSync();
   2626 
   2627  // Make it an absolute container for fixed-pos elements
   2628  viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2629  viewportFrame->MarkAsAbsoluteContainingBlock();
   2630 
   2631  return viewportFrame;
   2632 }
   2633 
   2634 void nsCSSFrameConstructor::SetUpDocElementContainingBlock(
   2635    nsIContent* aDocElement) {
   2636  MOZ_ASSERT(aDocElement, "No element?");
   2637  MOZ_ASSERT(!aDocElement->GetParent(), "Not root content?");
   2638  MOZ_ASSERT(aDocElement->GetUncomposedDoc(), "Not in a document?");
   2639  MOZ_ASSERT(aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement,
   2640             "Not the root of the document?");
   2641 
   2642  /*
   2643    how the root frame hierarchy should look
   2644 
   2645  Galley presentation, with scrolling:
   2646 
   2647      ViewportFrame [fixed-cb]
   2648        ScrollContainerFrame (if needed)
   2649          nsCanvasFrame [abs-cb]
   2650            root element frame (nsBlockFrame, SVGOuterSVGFrame,
   2651                                nsTableWrapperFrame, nsPlaceholderFrame,
   2652                                nsFlexContainerFrame, nsGridContainerFrame)
   2653 
   2654  Print presentation, non-XUL
   2655 
   2656      ViewportFrame
   2657        nsCanvasFrame
   2658          nsPageSequenceFrame
   2659            PrintedSheetFrame
   2660              nsPageFrame
   2661                nsPageContentFrame [fixed-cb]
   2662                  nsCanvasFrame [abs-cb]
   2663                    root element frame (nsBlockFrame, SVGOuterSVGFrame,
   2664                                        nsTableWrapperFrame, nsPlaceholderFrame,
   2665                                        nsFlexContainerFrame,
   2666                                        nsGridContainerFrame)
   2667 
   2668  Print-preview presentation, non-XUL
   2669 
   2670      ViewportFrame
   2671        ScrollContainerFrame
   2672          nsCanvasFrame
   2673            nsPageSequenceFrame
   2674              PrintedSheetFrame
   2675                nsPageFrame
   2676                  nsPageContentFrame [fixed-cb]
   2677                    nsCanvasFrame [abs-cb]
   2678                      root element frame (nsBlockFrame, SVGOuterSVGFrame,
   2679                                          nsTableWrapperFrame,
   2680                                          nsPlaceholderFrame,
   2681                                          nsFlexContainerFrame,
   2682                                          nsGridContainerFrame)
   2683 
   2684  Print/print preview of XUL is not supported.
   2685  [fixed-cb]: the default containing block for fixed-pos content
   2686  [abs-cb]: the default containing block for abs-pos content
   2687 
   2688  Meaning of nsCSSFrameConstructor fields:
   2689    mRootElementFrame is "root element frame".  This is the primary frame for
   2690      the root element.
   2691    mDocElementContainingBlock is the parent of mRootElementFrame
   2692      (i.e. nsCanvasFrame)
   2693    mPageSequenceFrame is the nsPageSequenceFrame, or null if there isn't
   2694      one
   2695  */
   2696 
   2697  // --------- CREATE ROOT FRAME -------
   2698 
   2699  // Create the root frame. The document element's frame is a child of the
   2700  // root frame.
   2701  //
   2702  // The root frame serves two purposes:
   2703  // - reserves space for any margins needed for the document element's frame
   2704  // - renders the document element's background. This ensures the background
   2705  //   covers the entire canvas as specified by the CSS2 spec
   2706 
   2707  nsPresContext* presContext = mPresShell->GetPresContext();
   2708  const bool isPaginated = presContext->IsRootPaginatedDocument();
   2709 
   2710  const bool isHTML = aDocElement->IsHTMLElement();
   2711  const bool isXUL = !isHTML && aDocElement->IsXULElement();
   2712 
   2713  const bool isScrollable = [&] {
   2714    if (isPaginated) {
   2715      return presContext->HasPaginatedScrolling();
   2716    }
   2717    // Never create scrollbars for XUL documents or top level XHTML documents
   2718    // that disable scrolling.
   2719    if (isXUL) {
   2720      return false;
   2721    }
   2722    if (aDocElement->OwnerDoc()->ChromeRulesEnabled() &&
   2723        aDocElement->AsElement()->AttrValueIs(
   2724            kNameSpaceID_None, nsGkAtoms::scrolling, nsGkAtoms::_false,
   2725            eCaseMatters)) {
   2726      return false;
   2727    }
   2728    return true;
   2729  }();
   2730 
   2731  nsContainerFrame* viewportFrame =
   2732      static_cast<nsContainerFrame*>(GetRootFrame());
   2733  ComputedStyle* viewportPseudoStyle = viewportFrame->Style();
   2734 
   2735  nsCanvasFrame* rootCanvasFrame =
   2736      NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
   2737  PseudoStyleType rootPseudo = PseudoStyleType::canvas;
   2738  mCanvasFrame = rootCanvasFrame;
   2739  mDocElementContainingBlock = rootCanvasFrame;
   2740 
   2741  // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
   2742 
   2743  // If the device supports scrolling (e.g., in galley mode on the screen and
   2744  // for print-preview, but not when printing), then create a scroll frame that
   2745  // will act as the scrolling mechanism for the viewport.
   2746  // XXX Do we even need a viewport when printing to a printer?
   2747 
   2748  // We no longer need to do overflow propagation here. It's taken care of
   2749  // when we construct frames for the element whose overflow might be
   2750  // propagated
   2751  NS_ASSERTION(!isScrollable || !isXUL,
   2752               "XUL documents should never be scrollable - see above");
   2753 
   2754  nsContainerFrame* newFrame = rootCanvasFrame;
   2755  RefPtr<ComputedStyle> rootPseudoStyle;
   2756  // we must create a state because if the scrollbars are GFX it needs the
   2757  // state to build the scrollbar frames.
   2758  nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
   2759 
   2760  // Start off with the viewport as parent; we'll adjust it as needed.
   2761  nsContainerFrame* parentFrame = viewportFrame;
   2762 
   2763  ServoStyleSet* styleSet = mPresShell->StyleSet();
   2764  // If paginated, make sure we don't put scrollbars in
   2765  if (!isScrollable) {
   2766    rootPseudoStyle = styleSet->ResolveInheritingAnonymousBoxStyle(
   2767        rootPseudo, viewportPseudoStyle);
   2768  } else {
   2769    rootPseudo = PseudoStyleType::scrolledCanvas;
   2770 
   2771    // Build the frame. We give it the content we are wrapping which is the
   2772    // document element, the root frame, the parent view port frame, and we
   2773    // should get back the new frame and the scrollable view if one was
   2774    // created.
   2775 
   2776    // resolve a context for the scrollframe
   2777    RefPtr<ComputedStyle> computedStyle =
   2778        styleSet->ResolveInheritingAnonymousBoxStyle(
   2779            PseudoStyleType::viewportScroll, viewportPseudoStyle);
   2780 
   2781    // Note that the viewport scrollframe is always built with
   2782    // overflow:auto style. This forces the scroll frame to create
   2783    // anonymous content for both scrollbars. This is necessary even
   2784    // if the HTML or BODY elements are overriding the viewport
   2785    // scroll style to 'hidden' --- dynamic style changes might put
   2786    // scrollbars back on the viewport and we don't want to have to
   2787    // reframe the viewport to create the scrollbar content.
   2788    newFrame = nullptr;
   2789    rootPseudoStyle = BeginBuildingScrollContainerFrame(
   2790        state, aDocElement, computedStyle, viewportFrame, rootPseudo, true,
   2791        newFrame);
   2792    parentFrame = newFrame;
   2793  }
   2794 
   2795  rootCanvasFrame->SetComputedStyleWithoutNotification(rootPseudoStyle);
   2796  rootCanvasFrame->Init(aDocElement, parentFrame, nullptr);
   2797 
   2798  if (isScrollable) {
   2799    FinishBuildingScrollContainerFrame(parentFrame, rootCanvasFrame);
   2800  }
   2801 
   2802  if (isPaginated) {
   2803    // Create a page sequence frame
   2804    {
   2805      RefPtr<ComputedStyle> pageSequenceStyle =
   2806          styleSet->ResolveInheritingAnonymousBoxStyle(
   2807              PseudoStyleType::pageSequence, viewportPseudoStyle);
   2808      mPageSequenceFrame =
   2809          NS_NewPageSequenceFrame(mPresShell, pageSequenceStyle);
   2810      mPageSequenceFrame->Init(aDocElement, rootCanvasFrame, nullptr);
   2811      SetInitialSingleChild(rootCanvasFrame, mPageSequenceFrame);
   2812    }
   2813 
   2814    // Create the first printed sheet frame, as the sole child (for now) of our
   2815    // page sequence frame (mPageSequenceFrame).
   2816    auto* printedSheetFrame =
   2817        ConstructPrintedSheetFrame(mPresShell, mPageSequenceFrame, nullptr);
   2818    SetInitialSingleChild(mPageSequenceFrame, printedSheetFrame);
   2819 
   2820    MOZ_ASSERT(!mNextPageContentFramePageName,
   2821               "Next page name should not have been set.");
   2822 
   2823    // Create the first page, as the sole child (for now) of the printed sheet
   2824    // frame that we just created.
   2825    nsCanvasFrame* canvasFrame;
   2826    nsContainerFrame* pageFrame =
   2827        ConstructPageFrame(mPresShell, printedSheetFrame, nullptr, canvasFrame);
   2828    pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   2829    SetInitialSingleChild(printedSheetFrame, pageFrame);
   2830 
   2831    // The eventual parent of the document element frame.
   2832    // XXX should this be set for every new page (in ConstructPageFrame)?
   2833    mDocElementContainingBlock = canvasFrame;
   2834  }
   2835 
   2836  if (viewportFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
   2837    SetInitialSingleChild(viewportFrame, newFrame);
   2838  } else {
   2839    viewportFrame->AppendFrames(FrameChildListID::Principal,
   2840                                nsFrameList(newFrame, newFrame));
   2841  }
   2842 }
   2843 
   2844 void nsCSSFrameConstructor::ConstructAnonymousContentForRoot(
   2845    nsFrameConstructorState& aState, nsContainerFrame* aCanvasFrame,
   2846    nsIContent* aDocElement, nsFrameList& aFrameList) {
   2847  NS_ASSERTION(aCanvasFrame->IsCanvasFrame(), "aFrame should be canvas frame!");
   2848  MOZ_ASSERT(mRootElementFrame->GetContent() == aDocElement);
   2849 
   2850  AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
   2851  GetAnonymousContent(aDocElement, aCanvasFrame, anonymousItems);
   2852 
   2853  // If we get here, we are rebuilding the anonymous content of the root
   2854  // element. In this case, we also need to deal with the custom content
   2855  // container.
   2856  if (auto* container =
   2857          aState.mPresContext->Document()->GetCustomContentContainer()) {
   2858    // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
   2859    // construction from PresShell::Initialize. See the similar code-path in
   2860    // ConstructDocElementFrame.
   2861    if (!container->HasServoData()) {
   2862      mPresShell->StyleSet()->StyleNewSubtree(container);
   2863    }
   2864    anonymousItems.AppendElement(container);
   2865  }
   2866 
   2867  if (anonymousItems.IsEmpty()) {
   2868    return;
   2869  }
   2870 
   2871  AutoFrameConstructionItemList itemsToConstruct(this);
   2872  AutoFrameConstructionPageName pageNameTracker(aState, aCanvasFrame);
   2873  AddFCItemsForAnonymousContent(aState, aCanvasFrame, anonymousItems,
   2874                                itemsToConstruct, pageNameTracker);
   2875  ConstructFramesFromItemList(aState, itemsToConstruct, aCanvasFrame,
   2876                              /* aParentIsWrapperAnonBox = */ false,
   2877                              aFrameList);
   2878 }
   2879 
   2880 PrintedSheetFrame* nsCSSFrameConstructor::ConstructPrintedSheetFrame(
   2881    PresShell* aPresShell, nsContainerFrame* aParentFrame,
   2882    nsIFrame* aPrevSheetFrame) {
   2883  RefPtr<ComputedStyle> printedSheetPseudoStyle =
   2884      aPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
   2885          PseudoStyleType::printedSheet);
   2886 
   2887  auto* printedSheetFrame =
   2888      NS_NewPrintedSheetFrame(aPresShell, printedSheetPseudoStyle);
   2889 
   2890  printedSheetFrame->Init(nullptr, aParentFrame, aPrevSheetFrame);
   2891 
   2892  return printedSheetFrame;
   2893 }
   2894 
   2895 nsContainerFrame* nsCSSFrameConstructor::ConstructPageFrame(
   2896    PresShell* aPresShell, nsContainerFrame* aParentFrame,
   2897    nsIFrame* aPrevPageFrame, nsCanvasFrame*& aCanvasFrame) {
   2898  ServoStyleSet* styleSet = aPresShell->StyleSet();
   2899 
   2900  RefPtr<ComputedStyle> pagePseudoStyle =
   2901      styleSet->ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType::page);
   2902 
   2903  nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
   2904 
   2905  // Initialize the page frame and force it to have a view. This makes printing
   2906  // of the pages easier and faster.
   2907  pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
   2908 
   2909  RefPtr<const nsAtom> pageName;
   2910  if (mNextPageContentFramePageName) {
   2911    pageName = mNextPageContentFramePageName.forget();
   2912  } else if (aPrevPageFrame) {
   2913    pageName = aPrevPageFrame->ComputePageValue();
   2914    MOZ_ASSERT(pageName,
   2915               "Page name from prev-in-flow should not have been null");
   2916  }
   2917  RefPtr<ComputedStyle> pageContentPseudoStyle =
   2918      styleSet->ResolvePageContentStyle(pageName,
   2919                                        StylePagePseudoClassFlags::NONE);
   2920 
   2921  nsContainerFrame* pageContentFrame = NS_NewPageContentFrame(
   2922      aPresShell, pageContentPseudoStyle, pageName.forget());
   2923 
   2924  nsPageContentFrame* prevPageContentFrame = nullptr;
   2925  if (aPrevPageFrame) {
   2926    MOZ_ASSERT(aPrevPageFrame->IsPageFrame());
   2927    prevPageContentFrame =
   2928        static_cast<nsPageFrame*>(aPrevPageFrame)->PageContentFrame();
   2929  }
   2930  pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
   2931  if (!prevPageContentFrame) {
   2932    // The canvas is an inheriting anon box, so needs to be "owned" by the page
   2933    // content.
   2934    pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES |
   2935                                   NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   2936    // Make it an absolute container for fixed-pos elements
   2937    pageContentFrame->MarkAsAbsoluteContainingBlock();
   2938  } else {
   2939    MOZ_ASSERT(
   2940        pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN),
   2941        "This bit should've been carried over from the previous continuation "
   2942        "in nsIFrame::Init().");
   2943    MOZ_ASSERT(pageContentFrame->GetAbsoluteContainingBlock(),
   2944               "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
   2945               "for continuations!");
   2946  }
   2947  SetInitialSingleChild(pageFrame, pageContentFrame);
   2948 
   2949  RefPtr<ComputedStyle> canvasPseudoStyle =
   2950      styleSet->ResolveInheritingAnonymousBoxStyle(PseudoStyleType::canvas,
   2951                                                   pageContentPseudoStyle);
   2952 
   2953  aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
   2954 
   2955  nsIFrame* prevCanvasFrame = nullptr;
   2956  if (prevPageContentFrame) {
   2957    prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
   2958    NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
   2959  }
   2960  aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
   2961  SetInitialSingleChild(pageContentFrame, aCanvasFrame);
   2962  return pageFrame;
   2963 }
   2964 
   2965 /* static */
   2966 nsIFrame* nsCSSFrameConstructor::CreatePlaceholderFrameFor(
   2967    PresShell* aPresShell, nsIContent* aContent, nsIFrame* aFrame,
   2968    nsContainerFrame* aParentFrame, nsIFrame* aPrevInFlow,
   2969    nsFrameState aTypeBit) {
   2970  RefPtr<ComputedStyle> placeholderStyle =
   2971      aPresShell->StyleSet()->ResolveStyleForPlaceholder();
   2972 
   2973  // The placeholder frame gets a pseudo style.
   2974  nsPlaceholderFrame* placeholderFrame =
   2975      NS_NewPlaceholderFrame(aPresShell, placeholderStyle, aTypeBit);
   2976 
   2977  placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
   2978 
   2979  // Associate the placeholder/out-of-flow with each other.
   2980  placeholderFrame->SetOutOfFlowFrame(aFrame);
   2981  aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
   2982 
   2983  aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
   2984 
   2985  return placeholderFrame;
   2986 }
   2987 
   2988 // Clears any lazy bits set in the range [aStartContent, aEndContent).  If
   2989 // aEndContent is null, that means to clear bits in all siblings starting with
   2990 // aStartContent.  aStartContent must not be null unless aEndContent is also
   2991 // null.  We do this so that when new children are inserted under elements whose
   2992 // frame is a leaf the new children don't cause us to try to construct frames
   2993 // for the existing children again.
   2994 static inline void ClearLazyBits(nsIContent* aStartContent,
   2995                                 nsIContent* aEndContent) {
   2996  MOZ_ASSERT(aStartContent || !aEndContent,
   2997             "Must have start child if we have an end child");
   2998 
   2999  for (nsIContent* cur = aStartContent; cur != aEndContent;
   3000       cur = cur->GetNextSibling()) {
   3001    cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
   3002  }
   3003 }
   3004 
   3005 /* static */
   3006 const nsCSSFrameConstructor::FrameConstructionData*
   3007 nsCSSFrameConstructor::FindSelectData(const Element& aElement,
   3008                                      ComputedStyle& aStyle) {
   3009  // Construct a frame-based listbox or combobox
   3010  const auto* sel = dom::HTMLSelectElement::FromNode(aElement);
   3011  MOZ_ASSERT(sel);
   3012  if (sel->IsCombobox()) {
   3013    static constexpr FrameConstructionData sComboboxData{
   3014        ToCreationFunc(NS_NewComboboxControlFrame)};
   3015    return &sComboboxData;
   3016  }
   3017  // FIXME: Can we simplify this to avoid needing ConstructListboxSelectFrame,
   3018  // and reuse ConstructScrollableBlock or so?
   3019  static constexpr FrameConstructionData sListBoxData{
   3020      &nsCSSFrameConstructor::ConstructListBoxSelectFrame};
   3021  return &sListBoxData;
   3022 }
   3023 
   3024 nsIFrame* nsCSSFrameConstructor::ConstructListBoxSelectFrame(
   3025    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   3026    nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
   3027    nsFrameList& aFrameList) {
   3028  nsIContent* const content = aItem.mContent;
   3029  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   3030 
   3031  // Listbox, not combobox
   3032  nsContainerFrame* listFrame =
   3033      NS_NewListControlFrame(mPresShell, computedStyle);
   3034 
   3035  nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle);
   3036 
   3037  // ******* this code stolen from Initialze ScrollFrame ********
   3038  // please adjust this code to use BuildScrollFrame.
   3039 
   3040  InitializeListboxSelect(aState, listFrame, scrolledFrame, content,
   3041                          aParentFrame, computedStyle, aFrameList);
   3042 
   3043  return listFrame;
   3044 }
   3045 
   3046 void nsCSSFrameConstructor::InitializeListboxSelect(
   3047    nsFrameConstructorState& aState, nsContainerFrame* scrollFrame,
   3048    nsContainerFrame* scrolledFrame, nsIContent* aContent,
   3049    nsContainerFrame* aParentFrame, ComputedStyle* aComputedStyle,
   3050    nsFrameList& aFrameList) {
   3051  // Initialize it
   3052  nsContainerFrame* geometricParent =
   3053      aState.GetGeometricParent(*aComputedStyle->StyleDisplay(), aParentFrame);
   3054 
   3055  // We don't call InitAndRestoreFrame for scrollFrame because we can only
   3056  // restore the frame state after its parts have been created (in particular,
   3057  // the scrollable view). So we have to split Init and Restore.
   3058 
   3059  scrollFrame->Init(aContent, geometricParent, nullptr);
   3060  aState.AddChild(scrollFrame, aFrameList, aContent, aParentFrame);
   3061  BuildScrollContainerFrame(aState, aContent, aComputedStyle, scrolledFrame,
   3062                            geometricParent, scrollFrame);
   3063  if (aState.mFrameState) {
   3064    // Restore frame state for the scroll frame
   3065    RestoreFrameStateFor(scrollFrame, aState.mFrameState);
   3066  }
   3067 
   3068  nsFrameConstructorSaveState floatSaveState;
   3069  aState.MaybePushFloatContainingBlock(scrolledFrame, floatSaveState);
   3070 
   3071  // Process children
   3072  nsFrameList childList;
   3073 
   3074  ProcessChildren(aState, aContent, aComputedStyle, scrolledFrame, false,
   3075                  childList, false);
   3076 
   3077  // Set the scrolled frame's initial child lists
   3078  scrolledFrame->SetInitialChildList(FrameChildListID::Principal,
   3079                                     std::move(childList));
   3080 }
   3081 
   3082 nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
   3083    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   3084    nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
   3085    nsFrameList& aFrameList) {
   3086  AutoRestore<bool> savedHasRenderedLegend(aState.mHasRenderedLegend);
   3087  aState.mHasRenderedLegend = false;
   3088  nsIContent* const content = aItem.mContent;
   3089  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   3090 
   3091  nsContainerFrame* fieldsetFrame =
   3092      NS_NewFieldSetFrame(mPresShell, computedStyle);
   3093 
   3094  // Initialize it
   3095  InitAndRestoreFrame(aState, content,
   3096                      aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
   3097                      fieldsetFrame);
   3098 
   3099  fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   3100 
   3101  // Resolve style and initialize the frame
   3102  RefPtr<ComputedStyle> fieldsetContentStyle =
   3103      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   3104          PseudoStyleType::fieldsetContent, computedStyle);
   3105 
   3106  const nsStyleDisplay* fieldsetContentDisplay =
   3107      fieldsetContentStyle->StyleDisplay();
   3108  const bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
   3109  nsContainerFrame* scrollFrame = nullptr;
   3110  if (isScrollable) {
   3111    fieldsetContentStyle = BeginBuildingScrollContainerFrame(
   3112        aState, content, fieldsetContentStyle, fieldsetFrame,
   3113        PseudoStyleType::scrolledContent, false, scrollFrame);
   3114  }
   3115 
   3116  // Create the inner ::-moz-fieldset-content frame.
   3117  nsContainerFrame* contentFrameTop;
   3118  nsContainerFrame* contentFrame;
   3119  auto* parent = scrollFrame ? scrollFrame : fieldsetFrame;
   3120  MOZ_ASSERT(fieldsetContentDisplay->DisplayOutside() ==
   3121             StyleDisplayOutside::Block);
   3122  switch (fieldsetContentDisplay->DisplayInside()) {
   3123    case StyleDisplayInside::Flex:
   3124      contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
   3125      InitAndRestoreFrame(aState, content, parent, contentFrame);
   3126      contentFrameTop = contentFrame;
   3127      break;
   3128    case StyleDisplayInside::Grid:
   3129      contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
   3130      InitAndRestoreFrame(aState, content, parent, contentFrame);
   3131      contentFrameTop = contentFrame;
   3132      break;
   3133    default: {
   3134      MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
   3135                 "bug in StyleAdjuster::adjust_for_fieldset_content?");
   3136 
   3137      contentFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle);
   3138      if (fieldsetContentStyle->StyleColumn()->IsColumnContainerStyle()) {
   3139        contentFrameTop = BeginBuildingColumns(
   3140            aState, content, parent, contentFrame, fieldsetContentStyle);
   3141      } else {
   3142        // No need to create column container. Initialize content frame.
   3143        InitAndRestoreFrame(aState, content, parent, contentFrame);
   3144        contentFrameTop = contentFrame;
   3145      }
   3146 
   3147      break;
   3148    }
   3149  }
   3150 
   3151  aState.AddChild(fieldsetFrame, aFrameList, content, aParentFrame);
   3152 
   3153  // Process children
   3154  nsFrameConstructorSaveState absoluteSaveState;
   3155  nsFrameList childList;
   3156 
   3157  contentFrameTop->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   3158  if (fieldsetFrame->IsAbsPosContainingBlock()) {
   3159    aState.PushAbsoluteContainingBlock(contentFrameTop, fieldsetFrame,
   3160                                       absoluteSaveState);
   3161  }
   3162 
   3163  nsFrameConstructorSaveState floatSaveState;
   3164  aState.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
   3165 
   3166  ProcessChildren(aState, content, computedStyle, contentFrame, true, childList,
   3167                  true);
   3168  nsFrameList fieldsetKids;
   3169  fieldsetKids.AppendFrame(nullptr,
   3170                           scrollFrame ? scrollFrame : contentFrameTop);
   3171 
   3172  if (!MayNeedToCreateColumnSpanSiblings(contentFrame, childList)) {
   3173    // Set the inner frame's initial child lists.
   3174    contentFrame->SetInitialChildList(FrameChildListID::Principal,
   3175                                      std::move(childList));
   3176  } else {
   3177    // Extract any initial non-column-span kids, and put them in inner frame's
   3178    // child list.
   3179    nsFrameList initialNonColumnSpanKids =
   3180        childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
   3181    contentFrame->SetInitialChildList(FrameChildListID::Principal,
   3182                                      std::move(initialNonColumnSpanKids));
   3183 
   3184    if (childList.NotEmpty()) {
   3185      nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
   3186          aState, contentFrame, childList,
   3187          // Column content should never be a absolute/fixed positioned
   3188          // containing block. Pass nullptr as aPositionedFrame.
   3189          nullptr);
   3190      FinishBuildingColumns(aState, contentFrameTop, contentFrame,
   3191                            columnSpanSiblings);
   3192    }
   3193  }
   3194 
   3195  if (isScrollable) {
   3196    FinishBuildingScrollContainerFrame(scrollFrame, contentFrameTop);
   3197  }
   3198 
   3199  // We use AppendFrames here because the rendered legend will already
   3200  // be present in the principal child list if it exists.
   3201  fieldsetFrame->AppendFrames(FrameChildListID::NoReflowPrincipal,
   3202                              std::move(fieldsetKids));
   3203 
   3204  return fieldsetFrame;
   3205 }
   3206 
   3207 const nsCSSFrameConstructor::FrameConstructionData*
   3208 nsCSSFrameConstructor::FindDetailsData(const Element& aElement,
   3209                                       ComputedStyle& aStyle) {
   3210  if (!StaticPrefs::layout_details_force_block_layout()) {
   3211    return nullptr;
   3212  }
   3213  static constexpr FrameConstructionData sBlockData[2] = {
   3214      {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
   3215      {&nsCSSFrameConstructor::ConstructScrollableBlock},
   3216  };
   3217  return &sBlockData[aStyle.StyleDisplay()->IsScrollableOverflow()];
   3218 }
   3219 
   3220 nsIFrame* nsCSSFrameConstructor::ConstructBlockRubyFrame(
   3221    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   3222    nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
   3223    nsFrameList& aFrameList) {
   3224  nsIContent* const content = aItem.mContent;
   3225  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   3226 
   3227  nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, computedStyle);
   3228  nsContainerFrame* newFrame = blockFrame;
   3229  nsContainerFrame* geometricParent =
   3230      aState.GetGeometricParent(*aStyleDisplay, aParentFrame);
   3231  AutoFrameConstructionPageName pageNameTracker(aState, blockFrame);
   3232  if ((aItem.mFCData->mBits & FCDATA_MAY_NEED_SCROLLFRAME) &&
   3233      aStyleDisplay->IsScrollableOverflow()) {
   3234    nsContainerFrame* scrollframe = nullptr;
   3235    BuildScrollContainerFrame(aState, content, computedStyle, blockFrame,
   3236                              geometricParent, scrollframe);
   3237    newFrame = scrollframe;
   3238  } else {
   3239    InitAndRestoreFrame(aState, content, geometricParent, blockFrame);
   3240  }
   3241 
   3242  RefPtr<ComputedStyle> rubyStyle =
   3243      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   3244          PseudoStyleType::blockRubyContent, computedStyle);
   3245  nsContainerFrame* rubyFrame = NS_NewRubyFrame(mPresShell, rubyStyle);
   3246  InitAndRestoreFrame(aState, content, blockFrame, rubyFrame);
   3247  SetInitialSingleChild(blockFrame, rubyFrame);
   3248  blockFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   3249 
   3250  aState.AddChild(newFrame, aFrameList, content, aParentFrame);
   3251 
   3252  if (!mRootElementFrame) {
   3253    mRootElementFrame = newFrame;
   3254  }
   3255 
   3256  nsFrameConstructorSaveState absoluteSaveState;
   3257  blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   3258  if (newFrame->IsAbsPosContainingBlock()) {
   3259    aState.PushAbsoluteContainingBlock(blockFrame, blockFrame,
   3260                                       absoluteSaveState);
   3261  }
   3262  nsFrameConstructorSaveState floatSaveState;
   3263  aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
   3264 
   3265  nsFrameList childList;
   3266  ProcessChildren(aState, content, rubyStyle, rubyFrame, true, childList, false,
   3267                  nullptr);
   3268  rubyFrame->SetInitialChildList(FrameChildListID::Principal,
   3269                                 std::move(childList));
   3270 
   3271  return newFrame;
   3272 }
   3273 
   3274 static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) {
   3275  for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
   3276    NS_ASSERTION(f->IsGeneratedContentFrame(),
   3277                 "should not have exited generated content");
   3278    auto pseudo = f->Style()->GetPseudoType();
   3279    if (pseudo == PseudoStyleType::before || pseudo == PseudoStyleType::after ||
   3280        pseudo == PseudoStyleType::marker ||
   3281        pseudo == PseudoStyleType::backdrop) {
   3282      return f;
   3283    }
   3284  }
   3285  return nullptr;
   3286 }
   3287 
   3288 /* static */
   3289 const nsCSSFrameConstructor::FrameConstructionData*
   3290 nsCSSFrameConstructor::FindTextData(const Text& aTextContent,
   3291                                    nsIFrame* aParentFrame) {
   3292  if (aParentFrame && IsFrameForSVG(aParentFrame)) {
   3293    if (!aParentFrame->IsInSVGTextSubtree()) {
   3294      return nullptr;
   3295    }
   3296 
   3297    // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
   3298    // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
   3299    // really know how to deal with it. This kinda sucks. :(
   3300    if (aParentFrame->GetContent() != aTextContent.GetParent()) {
   3301      return nullptr;
   3302    }
   3303 
   3304    static constexpr FrameConstructionData sSVGTextData(
   3305        NS_NewTextFrame, FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT);
   3306    return &sSVGTextData;
   3307  }
   3308 
   3309  static constexpr FrameConstructionData sTextData(NS_NewTextFrame,
   3310                                                   FCDATA_IS_LINE_PARTICIPANT);
   3311  return &sTextData;
   3312 }
   3313 
   3314 void nsCSSFrameConstructor::ConstructTextFrame(
   3315    const FrameConstructionData* aData, nsFrameConstructorState& aState,
   3316    nsIContent* aContent, nsContainerFrame* aParentFrame,
   3317    ComputedStyle* aComputedStyle, nsFrameList& aFrameList) {
   3318  MOZ_ASSERT(aData, "Must have frame construction data");
   3319 
   3320  nsIFrame* newFrame =
   3321      (*aData->mFunc.mCreationFunc)(mPresShell, aComputedStyle);
   3322 
   3323  InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
   3324 
   3325  // We never need to create a view for a text frame.
   3326 
   3327  if (newFrame->IsGeneratedContentFrame()) {
   3328    UniquePtr<nsGenConInitializer> initializer(
   3329        static_cast<nsGenConInitializer*>(
   3330            aContent->TakeProperty(nsGkAtoms::genConInitializerProperty)));
   3331    if (initializer) {
   3332      if (initializer->mNode.release()->InitTextFrame(
   3333              initializer->mList,
   3334              FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
   3335        (this->*(initializer->mDirtyAll))();
   3336      }
   3337    }
   3338  }
   3339 
   3340  // Add the newly constructed frame to the flow
   3341  aFrameList.AppendFrame(nullptr, newFrame);
   3342 
   3343  if (!aState.mCreatingExtraFrames || (aContent->IsInNativeAnonymousSubtree() &&
   3344                                       !aContent->GetPrimaryFrame())) {
   3345    aContent->SetPrimaryFrame(newFrame);
   3346  }
   3347 }
   3348 
   3349 /* static */
   3350 const nsCSSFrameConstructor::FrameConstructionData*
   3351 nsCSSFrameConstructor::FindDataByInt(int32_t aInt, const Element& aElement,
   3352                                     ComputedStyle& aComputedStyle,
   3353                                     const FrameConstructionDataByInt* aDataPtr,
   3354                                     uint32_t aDataLength) {
   3355  for (const FrameConstructionDataByInt *curData = aDataPtr,
   3356                                        *endData = aDataPtr + aDataLength;
   3357       curData != endData; ++curData) {
   3358    if (curData->mInt == aInt) {
   3359      const FrameConstructionData* data = &curData->mData;
   3360      if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
   3361        return data->mFunc.mDataGetter(aElement, aComputedStyle);
   3362      }
   3363 
   3364      return data;
   3365    }
   3366  }
   3367 
   3368  return nullptr;
   3369 }
   3370 
   3371 /* static */
   3372 const nsCSSFrameConstructor::FrameConstructionData*
   3373 nsCSSFrameConstructor::FindDataByTag(const Element& aElement,
   3374                                     ComputedStyle& aStyle,
   3375                                     const FrameConstructionDataByTag* aDataPtr,
   3376                                     uint32_t aDataLength) {
   3377  const nsAtom* tag = aElement.NodeInfo()->NameAtom();
   3378  for (const FrameConstructionDataByTag *curData = aDataPtr,
   3379                                        *endData = aDataPtr + aDataLength;
   3380       curData != endData; ++curData) {
   3381    if (curData->mTag == tag) {
   3382      const FrameConstructionData* data = &curData->mData;
   3383      if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
   3384        return data->mFunc.mDataGetter(aElement, aStyle);
   3385      }
   3386 
   3387      return data;
   3388    }
   3389  }
   3390 
   3391  return nullptr;
   3392 }
   3393 
   3394 #define SUPPRESS_FCDATA() FrameConstructionData(nullptr, FCDATA_SUPPRESS_FRAME)
   3395 #define SIMPLE_INT_CREATE(_int, _func) \
   3396  {int32_t(_int), FrameConstructionData(_func)}
   3397 #define SIMPLE_INT_CHAIN(_int, _func) \
   3398  {int32_t(_int), FrameConstructionData(_func)}
   3399 #define COMPLEX_INT_CREATE(_int, _func) \
   3400  {int32_t(_int), FrameConstructionData(_func)}
   3401 
   3402 #define SIMPLE_TAG_CREATE(_tag, _func) \
   3403  {nsGkAtoms::_tag, FrameConstructionData(_func)}
   3404 #define SIMPLE_TAG_CHAIN(_tag, _func) \
   3405  {nsGkAtoms::_tag, FrameConstructionData(_func)}
   3406 #define COMPLEX_TAG_CREATE(_tag, _func) \
   3407  {nsGkAtoms::_tag, FrameConstructionData(_func)}
   3408 
   3409 static nsFieldSetFrame* GetFieldSetFrameFor(nsIFrame* aFrame) {
   3410  auto pseudo = aFrame->Style()->GetPseudoType();
   3411  if (pseudo == PseudoStyleType::fieldsetContent ||
   3412      pseudo == PseudoStyleType::scrolledContent ||
   3413      pseudo == PseudoStyleType::columnSet ||
   3414      pseudo == PseudoStyleType::columnContent) {
   3415    return GetFieldSetFrameFor(aFrame->GetParent());
   3416  }
   3417  return do_QueryFrame(aFrame);
   3418 }
   3419 
   3420 /* static */
   3421 const nsCSSFrameConstructor::FrameConstructionData*
   3422 nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
   3423                                    nsIFrame* aParentFrame,
   3424                                    ComputedStyle& aStyle) {
   3425  MOZ_ASSERT(aElement.IsHTMLElement());
   3426  NS_ASSERTION(!aParentFrame ||
   3427                   aParentFrame->Style()->GetPseudoType() !=
   3428                       PseudoStyleType::fieldsetContent ||
   3429                   aParentFrame->GetParent()->IsFieldSetFrame(),
   3430               "Unexpected parent for fieldset content anon box");
   3431 
   3432  if (aElement.IsInNativeAnonymousSubtree()) {
   3433    if (aElement.NodeInfo()->NameAtom() == nsGkAtoms::label && aParentFrame) {
   3434      if (aParentFrame->IsFileControlFrame()) {
   3435        static constexpr FrameConstructionData sFileLabelData(
   3436            NS_NewFileControlLabelFrame);
   3437        return &sFileLabelData;
   3438      }
   3439      if (aParentFrame->IsComboboxControlFrame()) {
   3440        static constexpr FrameConstructionData sComboboxLabelData(
   3441            NS_NewComboboxLabelFrame);
   3442        return &sComboboxLabelData;
   3443      }
   3444    }
   3445    if (aStyle.GetPseudoType() == PseudoStyleType::viewTransitionOld ||
   3446        aStyle.GetPseudoType() == PseudoStyleType::viewTransitionNew) {
   3447      static constexpr FrameConstructionData sViewTransitionData(
   3448          NS_NewImageFrameForViewTransition);
   3449      return &sViewTransitionData;
   3450    }
   3451  }
   3452 
   3453  static constexpr FrameConstructionDataByTag sHTMLData[] = {
   3454      SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
   3455      SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
   3456                       nsCSSFrameConstructor::FindGeneratedImageData),
   3457      {nsGkAtoms::br,
   3458       {NS_NewBRFrame, FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK}},
   3459      SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
   3460      SIMPLE_TAG_CHAIN(button, nsCSSFrameConstructor::FindHTMLButtonData),
   3461      SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
   3462      SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
   3463      SIMPLE_TAG_CHAIN(select, nsCSSFrameConstructor::FindSelectData),
   3464      SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
   3465      SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
   3466      COMPLEX_TAG_CREATE(fieldset,
   3467                         &nsCSSFrameConstructor::ConstructFieldSetFrame),
   3468      SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
   3469      SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
   3470      SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
   3471      SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
   3472      SIMPLE_TAG_CREATE(audio, NS_NewHTMLAudioFrame),
   3473      SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
   3474      SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
   3475      SIMPLE_TAG_CHAIN(details, nsCSSFrameConstructor::FindDetailsData),
   3476  };
   3477 
   3478  return FindDataByTag(aElement, aStyle, sHTMLData, std::size(sHTMLData));
   3479 }
   3480 
   3481 /* static */
   3482 const nsCSSFrameConstructor::FrameConstructionData*
   3483 nsCSSFrameConstructor::FindGeneratedImageData(const Element& aElement,
   3484                                              ComputedStyle&) {
   3485  if (!aElement.IsInNativeAnonymousSubtree()) {
   3486    return nullptr;
   3487  }
   3488 
   3489  auto& generatedContent = static_cast<const GeneratedImageContent&>(aElement);
   3490  if (generatedContent.IsForListStyleImageMarker()) {
   3491    static constexpr FrameConstructionData sImgData(
   3492        NS_NewImageFrameForListStyleImage);
   3493    return &sImgData;
   3494  }
   3495 
   3496  static constexpr FrameConstructionData sImgData(
   3497      NS_NewImageFrameForGeneratedContentIndex);
   3498  return &sImgData;
   3499 }
   3500 
   3501 const nsCSSFrameConstructor::FrameConstructionData*
   3502 nsCSSFrameConstructor::FindHTMLButtonData(const Element&,
   3503                                          ComputedStyle& aStyle) {
   3504  // Buttons force a (maybe inline) block unless their display is flex or grid.
   3505  // TODO(emilio): It'd be good to remove this restriction more broadly.
   3506  // There are some tests that expect block baselines on e.g. a `display: table`
   3507  // button, but seems like it would be doable.
   3508  const auto* disp = aStyle.StyleDisplay();
   3509  const bool respectDisplay = [&] {
   3510    if (disp->IsInlineFlow()) {
   3511      // For compat, `display: inline` and co need to create an inline-block.
   3512      return false;
   3513    }
   3514    switch (disp->DisplayInside()) {
   3515      case StyleDisplayInside::Flex:
   3516      case StyleDisplayInside::Grid:
   3517      case StyleDisplayInside::FlowRoot:
   3518        return true;
   3519      default:
   3520        return false;
   3521    }
   3522  }();
   3523  if (respectDisplay) {
   3524    return nullptr;
   3525  }
   3526  static constexpr FrameConstructionData sBlockData[2] = {
   3527      {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
   3528      {&nsCSSFrameConstructor::ConstructScrollableBlock},
   3529  };
   3530  return &sBlockData[disp->IsScrollableOverflow()];
   3531 }
   3532 
   3533 /* static */
   3534 const nsCSSFrameConstructor::FrameConstructionData*
   3535 nsCSSFrameConstructor::FindImgData(const Element& aElement,
   3536                                   ComputedStyle& aStyle) {
   3537  if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
   3538      nsImageFrame::ImageFrameType::ForElementRequest) {
   3539    // content: url gets handled by the generic code-path.
   3540    return nullptr;
   3541  }
   3542 
   3543  static constexpr FrameConstructionData sImgData(NS_NewImageFrame);
   3544  return &sImgData;
   3545 }
   3546 
   3547 /* static */
   3548 const nsCSSFrameConstructor::FrameConstructionData*
   3549 nsCSSFrameConstructor::FindImgControlData(const Element& aElement,
   3550                                          ComputedStyle& aStyle) {
   3551  if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
   3552      nsImageFrame::ImageFrameType::ForElementRequest) {
   3553    return nullptr;
   3554  }
   3555 
   3556  static constexpr FrameConstructionData sImgControlData(
   3557      NS_NewImageControlFrame);
   3558  return &sImgControlData;
   3559 }
   3560 
   3561 /* static */
   3562 const nsCSSFrameConstructor::FrameConstructionData*
   3563 nsCSSFrameConstructor::FindSearchControlData(const Element& aElement,
   3564                                             ComputedStyle& aStyle) {
   3565  // Bug 1936648: Until we're absolutely sure we've solved the
   3566  // accessibility issues around the clear search button, we're only
   3567  // enabling the clear button in chrome contexts. See also Bug 1655503
   3568  if (StaticPrefs::layout_forms_input_type_search_enabled() ||
   3569      aElement.OwnerDoc()->ChromeRulesEnabled()) {
   3570    static constexpr FrameConstructionData sSearchControlData(
   3571        NS_NewSearchControlFrame);
   3572    return &sSearchControlData;
   3573  }
   3574 
   3575  static constexpr FrameConstructionData sTextControlData(
   3576      NS_NewTextControlFrame);
   3577  return &sTextControlData;
   3578 }
   3579 
   3580 /* static */
   3581 const nsCSSFrameConstructor::FrameConstructionData*
   3582 nsCSSFrameConstructor::FindInputData(const Element& aElement,
   3583                                     ComputedStyle& aStyle) {
   3584  static constexpr FrameConstructionDataByInt sInputData[] = {
   3585      SIMPLE_INT_CREATE(FormControlType::InputCheckbox,
   3586                        ToCreationFunc(NS_NewCheckboxRadioFrame)),
   3587      SIMPLE_INT_CREATE(FormControlType::InputRadio,
   3588                        ToCreationFunc(NS_NewCheckboxRadioFrame)),
   3589      SIMPLE_INT_CREATE(FormControlType::InputFile, NS_NewFileControlFrame),
   3590      SIMPLE_INT_CHAIN(FormControlType::InputImage,
   3591                       nsCSSFrameConstructor::FindImgControlData),
   3592      SIMPLE_INT_CREATE(FormControlType::InputEmail, NS_NewTextControlFrame),
   3593      SIMPLE_INT_CREATE(FormControlType::InputText, NS_NewTextControlFrame),
   3594      SIMPLE_INT_CREATE(FormControlType::InputTel, NS_NewTextControlFrame),
   3595      SIMPLE_INT_CREATE(FormControlType::InputUrl, NS_NewTextControlFrame),
   3596      SIMPLE_INT_CREATE(FormControlType::InputRange, NS_NewRangeFrame),
   3597      SIMPLE_INT_CREATE(FormControlType::InputPassword, NS_NewTextControlFrame),
   3598      SIMPLE_INT_CREATE(FormControlType::InputColor, NS_NewColorControlFrame),
   3599      SIMPLE_INT_CHAIN(FormControlType::InputSearch,
   3600                       nsCSSFrameConstructor::FindSearchControlData),
   3601      SIMPLE_INT_CREATE(FormControlType::InputNumber, NS_NewNumberControlFrame),
   3602      SIMPLE_INT_CREATE(FormControlType::InputTime, NS_NewDateTimeControlFrame),
   3603      SIMPLE_INT_CREATE(FormControlType::InputDate, NS_NewDateTimeControlFrame),
   3604      SIMPLE_INT_CREATE(FormControlType::InputDatetimeLocal,
   3605                        NS_NewDateTimeControlFrame),
   3606      // TODO: this is temporary until a frame is written: bug 888320
   3607      SIMPLE_INT_CREATE(FormControlType::InputMonth, NS_NewTextControlFrame),
   3608      // TODO: this is temporary until a frame is written: bug 888320
   3609      SIMPLE_INT_CREATE(FormControlType::InputWeek, NS_NewTextControlFrame),
   3610      SIMPLE_INT_CREATE(FormControlType::InputSubmit,
   3611                        NS_NewInputButtonControlFrame),
   3612      SIMPLE_INT_CREATE(FormControlType::InputReset,
   3613                        NS_NewInputButtonControlFrame),
   3614      SIMPLE_INT_CREATE(FormControlType::InputButton,
   3615                        NS_NewInputButtonControlFrame),
   3616      // Keeping hidden inputs out of here on purpose for so they get frames by
   3617      // display (in practice, none).
   3618  };
   3619 
   3620  auto controlType = HTMLInputElement::FromNode(aElement)->ControlType();
   3621 
   3622  // radio and checkbox inputs with appearance:none should be constructed
   3623  // by display type.  (Note that we're not checking that appearance is
   3624  // not (respectively) StyleAppearance::Radio and StyleAppearance::Checkbox.)
   3625  if ((controlType == FormControlType::InputCheckbox ||
   3626       controlType == FormControlType::InputRadio) &&
   3627      !aStyle.StyleDisplay()->HasAppearance()) {
   3628    return nullptr;
   3629  }
   3630 
   3631  return FindDataByInt(int32_t(controlType), aElement, aStyle, sInputData,
   3632                       std::size(sInputData));
   3633 }
   3634 
   3635 /* static */
   3636 const nsCSSFrameConstructor::FrameConstructionData*
   3637 nsCSSFrameConstructor::FindObjectData(const Element& aElement,
   3638                                      ComputedStyle& aStyle) {
   3639  uint32_t type;
   3640  nsCOMPtr<nsIObjectLoadingContent> objContent =
   3641      do_QueryInterface(const_cast<Element*>(&aElement));
   3642  NS_ASSERTION(objContent,
   3643               "embed and object must implement "
   3644               "nsIObjectLoadingContent!");
   3645  objContent->GetDisplayedType(&type);
   3646 
   3647  static constexpr FrameConstructionDataByInt sObjectData[] = {
   3648      // TODO(emilio): Can we remove the NS_NewEmptyFrame case and just use a
   3649      // subdocument frame here?
   3650      SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
   3651                        NS_NewEmptyFrame),
   3652      SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
   3653                        NS_NewSubDocumentFrame),
   3654      // Nothing for TYPE_FALLBACK so we'll construct frames by display there
   3655  };
   3656 
   3657  return FindDataByInt((int32_t)type, aElement, aStyle, sObjectData,
   3658                       std::size(sObjectData));
   3659 }
   3660 
   3661 /* static */
   3662 const nsCSSFrameConstructor::FrameConstructionData*
   3663 nsCSSFrameConstructor::FindCanvasData(const Element& aElement,
   3664                                      ComputedStyle& aStyle) {
   3665  // We want to check whether script is enabled on the document that
   3666  // could be painting to the canvas.  That's the owner document of
   3667  // the canvas, except when the owner document is a static document,
   3668  // in which case it's the original document it was cloned from.
   3669  Document* doc = aElement.OwnerDoc();
   3670  if (doc->IsStaticDocument()) {
   3671    doc = doc->GetOriginalDocument();
   3672  }
   3673  if (!doc->IsScriptEnabled()) {
   3674    return nullptr;
   3675  }
   3676 
   3677  static constexpr FrameConstructionData sCanvasData(
   3678      NS_NewHTMLCanvasFrame, 0, PseudoStyleType::htmlCanvasContent);
   3679  return &sCanvasData;
   3680 }
   3681 
   3682 static MOZ_NEVER_INLINE void DestroyFramesInList(PresShell* aPs,
   3683                                                 nsFrameList& aList) {
   3684  nsIFrame::DestroyContext context(aPs);
   3685  aList.DestroyFrames(context);
   3686 }
   3687 
   3688 void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
   3689    FrameConstructionItem& aItem, nsFrameConstructorState& aState,
   3690    nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
   3691  const FrameConstructionData* data = aItem.mFCData;
   3692  NS_ASSERTION(data, "Must have frame construction data");
   3693 
   3694  uint32_t bits = data->mBits;
   3695 
   3696  NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
   3697               "Should have dealt with this inside the data finder");
   3698 
   3699  // Some sets of bits are not compatible with each other
   3700 #define CHECK_ONLY_ONE_BIT(_bit1, _bit2)           \
   3701  NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
   3702               "Only one of these bits should be set")
   3703  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
   3704                     FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
   3705  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
   3706  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
   3707  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
   3708  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
   3709                     FCDATA_DISALLOW_GENERATED_CONTENT);
   3710  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
   3711  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
   3712                     FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
   3713  CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
   3714                     FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
   3715 #undef CHECK_ONLY_ONE_BIT
   3716  MOZ_ASSERT(
   3717      !(bits & FCDATA_IS_WRAPPER_ANON_BOX) || (bits & FCDATA_USE_CHILD_ITEMS),
   3718      "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS");
   3719 
   3720  // Don't create a subdocument frame for iframes if we're creating extra frames
   3721  if (aState.mCreatingExtraFrames &&
   3722      aItem.mContent->IsHTMLElement(nsGkAtoms::iframe)) {
   3723    return;
   3724  }
   3725 
   3726  nsIContent* const content = aItem.mContent;
   3727  nsIFrame* newFrame;
   3728  nsIFrame* primaryFrame;
   3729  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   3730  const nsStyleDisplay* display = computedStyle->StyleDisplay();
   3731  if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
   3732    newFrame = (this->*(data->mFunc.mFullConstructor))(
   3733        aState, aItem, aParentFrame, display, aFrameList);
   3734    MOZ_ASSERT(newFrame, "Full constructor failed");
   3735    primaryFrame = newFrame;
   3736  } else {
   3737    newFrame = (*data->mFunc.mCreationFunc)(mPresShell, computedStyle);
   3738 
   3739    const bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
   3740    const bool isPopup = aItem.mIsPopup;
   3741 
   3742    nsContainerFrame* geometricParent =
   3743        (isPopup || allowOutOfFlow)
   3744            ? aState.GetGeometricParent(*display, aParentFrame)
   3745            : aParentFrame;
   3746 
   3747    // In the non-scrollframe case, primaryFrame and newFrame are equal; in the
   3748    // scrollframe case, newFrame is the scrolled frame while primaryFrame is
   3749    // the scrollframe.
   3750    if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
   3751        display->IsScrollableOverflow()) {
   3752      nsContainerFrame* scrollframe = nullptr;
   3753      BuildScrollContainerFrame(aState, content, computedStyle, newFrame,
   3754                                geometricParent, scrollframe);
   3755      primaryFrame = scrollframe;
   3756    } else {
   3757      InitAndRestoreFrame(aState, content, geometricParent, newFrame);
   3758      primaryFrame = newFrame;
   3759    }
   3760 
   3761    // If we need to create a block formatting context to wrap our
   3762    // kids, do it now.
   3763    nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
   3764    nsIFrame* maybeAbsoluteContainingBlock = newFrame;
   3765    nsIFrame* possiblyLeafFrame = newFrame;
   3766    nsContainerFrame* outerFrame = nullptr;
   3767    if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
   3768      RefPtr<ComputedStyle> outerStyle =
   3769          mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   3770              data->mAnonBoxPseudo, computedStyle);
   3771 #ifdef DEBUG
   3772      nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
   3773      MOZ_ASSERT(containerFrame);
   3774 #endif
   3775      nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
   3776      nsContainerFrame* innerFrame = NS_NewBlockFrame(mPresShell, outerStyle);
   3777      InitAndRestoreFrame(aState, content, container, innerFrame);
   3778      outerFrame = innerFrame;
   3779 
   3780      SetInitialSingleChild(container, outerFrame);
   3781 
   3782      container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   3783 
   3784      // Now figure out whether newFrame or outerFrame should be the
   3785      // absolute container.
   3786      if (outerFrame->IsAbsPosContainingBlock()) {
   3787        maybeAbsoluteContainingBlock = outerFrame;
   3788        maybeAbsoluteContainingBlockStyleFrame = outerFrame;
   3789        innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   3790      }
   3791 
   3792      // Our kids should go into the innerFrame.
   3793      newFrame = innerFrame;
   3794    }
   3795 
   3796    aState.AddChild(primaryFrame, aFrameList, content, aParentFrame,
   3797                    allowOutOfFlow, allowOutOfFlow);
   3798 
   3799    nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
   3800    if (newFrameAsContainer) {
   3801      // Process the child content if requested
   3802      nsFrameList childList;
   3803      nsFrameConstructorSaveState absoluteSaveState;
   3804 
   3805      if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
   3806        aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
   3807      } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
   3808        maybeAbsoluteContainingBlock->AddStateBits(
   3809            NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   3810        if (maybeAbsoluteContainingBlockStyleFrame->IsAbsPosContainingBlock()) {
   3811          auto* cf =
   3812              static_cast<nsContainerFrame*>(maybeAbsoluteContainingBlock);
   3813          aState.PushAbsoluteContainingBlock(
   3814              cf, maybeAbsoluteContainingBlockStyleFrame, absoluteSaveState);
   3815        }
   3816      }
   3817 
   3818      nsFrameConstructorSaveState floatSaveState;
   3819      aState.MaybePushFloatContainingBlock(newFrameAsContainer, floatSaveState);
   3820 
   3821      if (bits & FCDATA_USE_CHILD_ITEMS) {
   3822        // At this point, we have not set up the auto value for this frame, and
   3823        // no caller will have set it so it is not redundant and therefor will
   3824        // not assert.
   3825        AutoFrameConstructionPageName pageNameTracker(aState,
   3826                                                      newFrameAsContainer);
   3827        ConstructFramesFromItemList(
   3828            aState, aItem.mChildItems, newFrameAsContainer,
   3829            bits & FCDATA_IS_WRAPPER_ANON_BOX, childList);
   3830      } else {
   3831        // Process the child frames.
   3832        ProcessChildren(aState, content, computedStyle, newFrameAsContainer,
   3833                        !(bits & FCDATA_DISALLOW_GENERATED_CONTENT), childList,
   3834                        (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
   3835                        possiblyLeafFrame);
   3836      }
   3837 
   3838      if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) {
   3839        nsFrameList newList;
   3840        nsFrameList currentBlockList;
   3841        nsIFrame* f;
   3842        while ((f = childList.FirstChild()) != nullptr) {
   3843          bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
   3844          if (!wrapFrame) {
   3845            FlushAccumulatedBlock(aState, content, newFrameAsContainer,
   3846                                  currentBlockList, newList);
   3847          }
   3848 
   3849          childList.RemoveFrame(f);
   3850          if (wrapFrame) {
   3851            currentBlockList.AppendFrame(nullptr, f);
   3852          } else {
   3853            newList.AppendFrame(nullptr, f);
   3854          }
   3855        }
   3856        FlushAccumulatedBlock(aState, content, newFrameAsContainer,
   3857                              currentBlockList, newList);
   3858 
   3859        if (childList.NotEmpty()) {
   3860          // an error must have occurred, delete unprocessed frames
   3861          DestroyFramesInList(mPresShell, childList);
   3862        }
   3863 
   3864        childList = std::move(newList);
   3865      }
   3866 
   3867      // Set the frame's initial child list. Note that MathML depends on this
   3868      // being called even if childList is empty!
   3869      newFrameAsContainer->SetInitialChildList(FrameChildListID::Principal,
   3870                                               std::move(childList));
   3871    }
   3872  }
   3873 
   3874  NS_ASSERTION(newFrame->IsLineParticipant() ==
   3875                   ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
   3876               "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
   3877 
   3878  // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
   3879  // generated content that doesn't have one yet.  Note that we have to examine
   3880  // the frame bit, because by this point mIsGeneratedContent has been cleared
   3881  // on aItem.
   3882  if ((!aState.mCreatingExtraFrames ||
   3883       (aItem.mContent->IsRootOfNativeAnonymousSubtree() &&
   3884        !aItem.mContent->GetPrimaryFrame())) &&
   3885      !(bits & FCDATA_SKIP_FRAMESET)) {
   3886    aItem.mContent->SetPrimaryFrame(primaryFrame);
   3887    ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
   3888  }
   3889 }
   3890 
   3891 static void GatherSubtreeElements(Element* aElement,
   3892                                  nsTArray<Element*>& aElements) {
   3893  aElements.AppendElement(aElement);
   3894  StyleChildrenIterator iter(aElement);
   3895  for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
   3896    if (!c->IsElement()) {
   3897      continue;
   3898    }
   3899    GatherSubtreeElements(c->AsElement(), aElements);
   3900  }
   3901 }
   3902 
   3903 nsresult nsCSSFrameConstructor::GetAnonymousContent(
   3904    nsIContent* aParent, nsIFrame* aParentFrame,
   3905    nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) {
   3906  nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
   3907  if (!creator) {
   3908    return NS_OK;
   3909  }
   3910 
   3911  nsresult rv = creator->CreateAnonymousContent(aContent);
   3912  if (NS_FAILED(rv)) {
   3913    // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
   3914    return rv;
   3915  }
   3916 
   3917  if (aContent.IsEmpty()) {
   3918    return NS_OK;
   3919  }
   3920 
   3921  const bool devtoolsEventsEnabled =
   3922      mDocument->DevToolsAnonymousAndShadowEventsEnabled();
   3923 
   3924  MOZ_ASSERT(aParent->IsElement());
   3925  for (const auto& info : aContent) {
   3926    // get our child's content and set its parent to our content
   3927    nsIContent* content = info.mContent;
   3928    content->SetIsNativeAnonymousRoot();
   3929 
   3930    BindContext context(*aParent->AsElement(), BindContext::ForNativeAnonymous);
   3931    rv = content->BindToTree(context, *aParent);
   3932 
   3933    if (NS_FAILED(rv)) {
   3934      content->UnbindFromTree();
   3935      return rv;
   3936    }
   3937 
   3938    if (devtoolsEventsEnabled) {
   3939      content->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
   3940    }
   3941  }
   3942 
   3943  // Some situations where we don't cache anonymous content styles:
   3944  //
   3945  // * when visibility or pointer-events is anything other than the initial
   3946  //   value; we rely on visibility and pointer-events inheriting into anonymous
   3947  //   content, but don't bother adding this state to the AnonymousContentKey,
   3948  //   since it's not so common. Note that with overlay scrollbars, scrollbars
   3949  //   always start off with pointer-events: none so we don't need to check for
   3950  //   that in that case.
   3951  //
   3952  // * when the medium is anything other than screen; some UA style sheet rules
   3953  //   apply in e.g. print medium, and will give different results from the
   3954  //   cached styles
   3955  Maybe<bool> computedAllowStyleCaching;
   3956  auto ComputeAllowStyleCaching = [&] {
   3957    if (!StaticPrefs::layout_css_cached_scrollbar_styles_enabled()) {
   3958      return false;
   3959    }
   3960    if (aParentFrame->StyleVisibility()->mVisible != StyleVisibility::Visible) {
   3961      return false;
   3962    }
   3963    nsPresContext* pc = mPresShell->GetPresContext();
   3964    if (!pc->UseOverlayScrollbars() &&
   3965        aParentFrame->StyleUI()->ComputedPointerEvents() !=
   3966            StylePointerEvents::Auto) {
   3967      return false;
   3968    }
   3969    if (pc->Medium() != nsGkAtoms::screen) {
   3970      return false;
   3971    }
   3972    return true;
   3973  };
   3974 
   3975  auto AllowStyleCaching = [&] {
   3976    if (computedAllowStyleCaching.isNothing()) {
   3977      computedAllowStyleCaching.emplace(ComputeAllowStyleCaching());
   3978    }
   3979    return computedAllowStyleCaching.value();
   3980  };
   3981 
   3982  // Compute styles for the anonymous content tree.
   3983  ServoStyleSet* styleSet = mPresShell->StyleSet();
   3984  for (auto& info : aContent) {
   3985    Element* e = Element::FromNode(info.mContent);
   3986    if (!e) {
   3987      continue;
   3988    }
   3989 
   3990    if (info.mKey == AnonymousContentKey::None || !AllowStyleCaching()) {
   3991      // Most NAC subtrees do not use caching of computed styles.  Just go
   3992      // ahead and eagerly style the subtree.
   3993      styleSet->StyleNewSubtree(e);
   3994      continue;
   3995    }
   3996 
   3997    // We have a NAC subtree for which we can use cached styles.
   3998    AutoTArray<RefPtr<ComputedStyle>, 2> cachedStyles;
   3999    AutoTArray<Element*, 2> elements;
   4000 
   4001    GatherSubtreeElements(e, elements);
   4002    styleSet->GetCachedAnonymousContentStyles(info.mKey, cachedStyles);
   4003 
   4004    if (cachedStyles.IsEmpty()) {
   4005      // We haven't stored cached styles for this kind of NAC subtree yet.
   4006      // Eagerly compute those styles, then cache them for later.
   4007      styleSet->StyleNewSubtree(e);
   4008      for (Element* e : elements) {
   4009        if (e->HasServoData()) {
   4010          cachedStyles.AppendElement(ServoStyleSet::ResolveServoStyle(*e));
   4011        } else {
   4012          cachedStyles.AppendElement(nullptr);
   4013        }
   4014      }
   4015      styleSet->PutCachedAnonymousContentStyles(info.mKey,
   4016                                                std::move(cachedStyles));
   4017      continue;
   4018    }
   4019 
   4020    // We previously stored cached styles for this kind of NAC subtree.
   4021    // Iterate over them and set them on the subtree's elements.
   4022    MOZ_ASSERT(cachedStyles.Length() == elements.Length(),
   4023               "should always produce the same size NAC subtree");
   4024    for (size_t i = 0, len = cachedStyles.Length(); i != len; ++i) {
   4025      if (cachedStyles[i]) {
   4026 #ifdef DEBUG
   4027        // Assert that our cached style is the same as one we could compute.
   4028        RefPtr<ComputedStyle> cs = styleSet->ResolveStyleLazily(*elements[i]);
   4029        MOZ_ASSERT(
   4030            cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs),
   4031            "cached anonymous content styles should be identical to those we "
   4032            "would compute normally");
   4033        // All overlay scrollbars start off as inactive, so we can rely on their
   4034        // pointer-events value being always none.
   4035        MOZ_ASSERT(!mPresShell->GetPresContext()->UseOverlayScrollbars() ||
   4036                   cs->StyleUI()->ComputedPointerEvents() ==
   4037                       StylePointerEvents::None);
   4038 #endif
   4039        Servo_SetExplicitStyle(elements[i], cachedStyles[i]);
   4040      }
   4041    }
   4042  }
   4043 
   4044  return NS_OK;
   4045 }
   4046 
   4047 /* static */
   4048 const nsCSSFrameConstructor::FrameConstructionData*
   4049 nsCSSFrameConstructor::FindXULTagData(const Element& aElement,
   4050                                      ComputedStyle& aStyle) {
   4051  MOZ_ASSERT(aElement.IsXULElement());
   4052  static constexpr FrameConstructionData kPopupData(NS_NewMenuPopupFrame,
   4053                                                    FCDATA_IS_POPUP);
   4054 
   4055  static constexpr FrameConstructionDataByTag sXULTagData[] = {
   4056      SIMPLE_TAG_CREATE(image, NS_NewXULImageFrame),
   4057      SIMPLE_TAG_CREATE(treechildren, NS_NewTreeBodyFrame),
   4058      SIMPLE_TAG_CHAIN(label,
   4059                       nsCSSFrameConstructor::FindXULLabelOrDescriptionData),
   4060      SIMPLE_TAG_CHAIN(description,
   4061                       nsCSSFrameConstructor::FindXULLabelOrDescriptionData),
   4062      SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
   4063      SIMPLE_TAG_CREATE(editor, NS_NewSubDocumentFrame),
   4064      SIMPLE_TAG_CREATE(browser, NS_NewSubDocumentFrame),
   4065      SIMPLE_TAG_CREATE(splitter, NS_NewSplitterFrame),
   4066      SIMPLE_TAG_CREATE(scrollbar, NS_NewScrollbarFrame),
   4067      SIMPLE_TAG_CREATE(slider, NS_NewSliderFrame),
   4068      SIMPLE_TAG_CREATE(thumb, NS_NewSimpleXULLeafFrame),
   4069      SIMPLE_TAG_CREATE(scrollcorner, NS_NewSimpleXULLeafFrame),
   4070      SIMPLE_TAG_CREATE(resizer, NS_NewSimpleXULLeafFrame),
   4071      SIMPLE_TAG_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame),
   4072      {nsGkAtoms::panel, kPopupData},
   4073      {nsGkAtoms::menupopup, kPopupData},
   4074      {nsGkAtoms::tooltip, kPopupData},
   4075  };
   4076 
   4077  return FindDataByTag(aElement, aStyle, sXULTagData, std::size(sXULTagData));
   4078 }
   4079 
   4080 /* static */
   4081 const nsCSSFrameConstructor::FrameConstructionData*
   4082 nsCSSFrameConstructor::FindXULLabelOrDescriptionData(const Element& aElement,
   4083                                                     ComputedStyle&) {
   4084  // Follow CSS display value if no value attribute
   4085  if (!aElement.HasAttr(nsGkAtoms::value)) {
   4086    return nullptr;
   4087  }
   4088 
   4089  // Follow CSS display if there's no crop="center".
   4090  if (!aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::crop,
   4091                            nsGkAtoms::center, eCaseMatters)) {
   4092    return nullptr;
   4093  }
   4094 
   4095  static constexpr FrameConstructionData sMiddleCroppingData(
   4096      NS_NewMiddleCroppingLabelFrame);
   4097  return &sMiddleCroppingData;
   4098 }
   4099 
   4100 already_AddRefed<ComputedStyle>
   4101 nsCSSFrameConstructor::BeginBuildingScrollContainerFrame(
   4102    nsFrameConstructorState& aState, nsIContent* aContent,
   4103    ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame,
   4104    PseudoStyleType aScrolledPseudo, bool aIsRoot,
   4105    nsContainerFrame*& aNewFrame) {
   4106  nsContainerFrame* scrollContainerFrame = aNewFrame;
   4107 
   4108  if (!scrollContainerFrame) {
   4109    scrollContainerFrame =
   4110        NS_NewScrollContainerFrame(mPresShell, aContentStyle, aIsRoot);
   4111    InitAndRestoreFrame(aState, aContent, aParentFrame, scrollContainerFrame);
   4112  }
   4113 
   4114  MOZ_ASSERT(scrollContainerFrame);
   4115 
   4116  // if there are any anonymous children for the scroll frame, create
   4117  // frames for them.
   4118  //
   4119  // We can't take the normal ProcessChildren path, because the NAC needs to
   4120  // be parented to the scrollframe, and everything else needs to be parented
   4121  // to the scrolledframe.
   4122  AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
   4123  DebugOnly<nsresult> rv =
   4124      GetAnonymousContent(aContent, scrollContainerFrame, scrollNAC);
   4125  MOZ_ASSERT(NS_SUCCEEDED(rv));
   4126  nsFrameList anonymousList;
   4127  if (!scrollNAC.IsEmpty()) {
   4128    nsFrameConstructorSaveState floatSaveState;
   4129    aState.MaybePushFloatContainingBlock(scrollContainerFrame, floatSaveState);
   4130 
   4131    AutoFrameConstructionItemList items(this);
   4132    AutoFrameConstructionPageName pageNameTracker(aState, scrollContainerFrame);
   4133    AddFCItemsForAnonymousContent(aState, scrollContainerFrame, scrollNAC,
   4134                                  items, pageNameTracker);
   4135    ConstructFramesFromItemList(aState, items, scrollContainerFrame,
   4136                                /* aParentIsWrapperAnonBox = */ false,
   4137                                anonymousList);
   4138  }
   4139 
   4140  aNewFrame = scrollContainerFrame;
   4141  scrollContainerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   4142 
   4143  // we used the style that was passed in. So resolve another one.
   4144  ServoStyleSet* styleSet = mPresShell->StyleSet();
   4145  RefPtr<ComputedStyle> scrolledChildStyle =
   4146      styleSet->ResolveInheritingAnonymousBoxStyle(aScrolledPseudo,
   4147                                                   aContentStyle);
   4148 
   4149  scrollContainerFrame->SetInitialChildList(FrameChildListID::Principal,
   4150                                            std::move(anonymousList));
   4151 
   4152  return scrolledChildStyle.forget();
   4153 }
   4154 
   4155 void nsCSSFrameConstructor::FinishBuildingScrollContainerFrame(
   4156    nsContainerFrame* aScrollContainerFrame, nsIFrame* aScrolledFrame) {
   4157  aScrollContainerFrame->AppendFrames(
   4158      FrameChildListID::Principal, nsFrameList(aScrolledFrame, aScrolledFrame));
   4159 }
   4160 
   4161 void nsCSSFrameConstructor::BuildScrollContainerFrame(
   4162    nsFrameConstructorState& aState, nsIContent* aContent,
   4163    ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
   4164    nsContainerFrame* aParentFrame, nsContainerFrame*& aNewFrame) {
   4165  RefPtr<ComputedStyle> scrolledContentStyle =
   4166      BeginBuildingScrollContainerFrame(
   4167          aState, aContent, aContentStyle, aParentFrame,
   4168          PseudoStyleType::scrolledContent, false, aNewFrame);
   4169 
   4170  aScrolledFrame->SetComputedStyleWithoutNotification(scrolledContentStyle);
   4171  InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
   4172 
   4173  FinishBuildingScrollContainerFrame(aNewFrame, aScrolledFrame);
   4174 }
   4175 
   4176 const nsCSSFrameConstructor::FrameConstructionData*
   4177 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
   4178                                       const Element& aElement) {
   4179  static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)),
   4180                "Check eParentTypeCount should not overflow");
   4181 
   4182  // The style system ensures that floated and positioned frames are
   4183  // block-level.
   4184  NS_ASSERTION(
   4185      !(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle()) ||
   4186          aDisplay.IsBlockOutsideStyle(),
   4187      "Style system did not apply CSS2.1 section 9.7 fixups");
   4188 
   4189  // If this is "body", try propagating its scroll style to the viewport
   4190  // Note that we need to do this even if the body is NOT scrollable;
   4191  // it might have dynamically changed from scrollable to not scrollable,
   4192  // and that might need to be propagated.
   4193  // XXXbz is this the right place to do this?  If this code moves,
   4194  // make this function static.
   4195  bool propagatedScrollToViewport = false;
   4196  if (aElement.IsHTMLElement(nsGkAtoms::body)) {
   4197    if (nsPresContext* presContext = mPresShell->GetPresContext()) {
   4198      propagatedScrollToViewport =
   4199          presContext->UpdateViewportScrollStylesOverride() == &aElement;
   4200      MOZ_ASSERT(!propagatedScrollToViewport ||
   4201                     !mPresShell->GetPresContext()->IsPaginated(),
   4202                 "Shouldn't propagate scroll in paginated contexts");
   4203    }
   4204  }
   4205 
   4206  switch (aDisplay.DisplayInside()) {
   4207    case StyleDisplayInside::Flow:
   4208    case StyleDisplayInside::FlowRoot: {
   4209      if (aDisplay.IsInlineFlow()) {
   4210        static constexpr FrameConstructionData data(
   4211            &nsCSSFrameConstructor::ConstructInline,
   4212            FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT);
   4213        return &data;
   4214      }
   4215 
   4216      // If the frame is a block-level frame and is scrollable, then wrap it in
   4217      // a scroll frame.  Except we don't want to do that for paginated contexts
   4218      // for frames that are block-outside and aren't frames for native
   4219      // anonymous stuff.
   4220      // XXX Ignore tables for the time being (except caption)
   4221      const uint32_t kCaptionCtorFlags =
   4222          FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable);
   4223      const bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
   4224      const bool needScrollFrame =
   4225          aDisplay.IsScrollableOverflow() && !propagatedScrollToViewport;
   4226      if (needScrollFrame) {
   4227        const bool suppressScrollFrame =
   4228            mPresShell->GetPresContext()->IsPaginated() &&
   4229            aDisplay.IsBlockOutsideStyle() &&
   4230            !aElement.IsInNativeAnonymousSubtree();
   4231        if (!suppressScrollFrame) {
   4232          static constexpr FrameConstructionData sScrollableBlockData[2] = {
   4233              {&nsCSSFrameConstructor::ConstructScrollableBlock},
   4234              {&nsCSSFrameConstructor::ConstructScrollableBlock,
   4235               kCaptionCtorFlags}};
   4236          return &sScrollableBlockData[caption];
   4237        }
   4238      }
   4239 
   4240      // Handle various non-scrollable blocks.
   4241      static constexpr FrameConstructionData sNonScrollableBlockData[2] = {
   4242          {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
   4243          {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
   4244           kCaptionCtorFlags}};
   4245      return &sNonScrollableBlockData[caption];
   4246    }
   4247    case StyleDisplayInside::Table: {
   4248      static constexpr FrameConstructionData data(
   4249          &nsCSSFrameConstructor::ConstructTable);
   4250      return &data;
   4251    }
   4252    // NOTE: In the unlikely event that we add another table-part here that
   4253    // has a desired-parent-type (& hence triggers table fixup), we'll need to
   4254    // also update the flexbox chunk in ComputedStyle::ApplyStyleFixups().
   4255    case StyleDisplayInside::TableRowGroup: {
   4256      static constexpr FrameConstructionData data(
   4257          &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
   4258          FCDATA_IS_TABLE_PART |
   4259              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable));
   4260      return &data;
   4261    }
   4262    case StyleDisplayInside::TableColumn: {
   4263      static constexpr FrameConstructionData data(
   4264          &nsCSSFrameConstructor::ConstructTableCol,
   4265          FCDATA_IS_TABLE_PART |
   4266              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup));
   4267      return &data;
   4268    }
   4269    case StyleDisplayInside::TableColumnGroup: {
   4270      static constexpr FrameConstructionData data(
   4271          ToCreationFunc(NS_NewTableColGroupFrame),
   4272          FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
   4273              FCDATA_SKIP_ABSPOS_PUSH |
   4274              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable));
   4275      return &data;
   4276    }
   4277    case StyleDisplayInside::TableHeaderGroup: {
   4278      static constexpr FrameConstructionData data(
   4279          &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
   4280          FCDATA_IS_TABLE_PART |
   4281              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable));
   4282      return &data;
   4283    }
   4284    case StyleDisplayInside::TableFooterGroup: {
   4285      static constexpr FrameConstructionData data(
   4286          &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
   4287          FCDATA_IS_TABLE_PART |
   4288              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable));
   4289      return &data;
   4290    }
   4291    case StyleDisplayInside::TableRow: {
   4292      static constexpr FrameConstructionData data(
   4293          &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
   4294          FCDATA_IS_TABLE_PART |
   4295              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup));
   4296      return &data;
   4297    }
   4298    case StyleDisplayInside::TableCell: {
   4299      static constexpr FrameConstructionData data(
   4300          &nsCSSFrameConstructor::ConstructTableCell,
   4301          FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow));
   4302      return &data;
   4303    }
   4304    case StyleDisplayInside::Flex:
   4305    case StyleDisplayInside::WebkitBox: {
   4306      static constexpr FrameConstructionData nonScrollableData(
   4307          ToCreationFunc(NS_NewFlexContainerFrame));
   4308      static constexpr FrameConstructionData data(
   4309          ToCreationFunc(NS_NewFlexContainerFrame),
   4310          FCDATA_MAY_NEED_SCROLLFRAME);
   4311      return MOZ_UNLIKELY(propagatedScrollToViewport) ? &nonScrollableData
   4312                                                      : &data;
   4313    }
   4314    case StyleDisplayInside::Grid: {
   4315      static constexpr FrameConstructionData nonScrollableData(
   4316          ToCreationFunc(NS_NewGridContainerFrame));
   4317      static constexpr FrameConstructionData data(
   4318          ToCreationFunc(NS_NewGridContainerFrame),
   4319          FCDATA_MAY_NEED_SCROLLFRAME);
   4320      return MOZ_UNLIKELY(propagatedScrollToViewport) ? &nonScrollableData
   4321                                                      : &data;
   4322    }
   4323    case StyleDisplayInside::Ruby: {
   4324      static constexpr FrameConstructionData data[] = {
   4325          {&nsCSSFrameConstructor::ConstructBlockRubyFrame,
   4326           FCDATA_MAY_NEED_SCROLLFRAME},
   4327          {ToCreationFunc(NS_NewRubyFrame), FCDATA_IS_LINE_PARTICIPANT}};
   4328      bool isInline = aDisplay.DisplayOutside() == StyleDisplayOutside::Inline;
   4329      return &data[isInline];
   4330    }
   4331    case StyleDisplayInside::RubyBase: {
   4332      static constexpr FrameConstructionData data(
   4333          ToCreationFunc(NS_NewRubyBaseFrame),
   4334          FCDATA_IS_LINE_PARTICIPANT |
   4335              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer));
   4336      return &data;
   4337    }
   4338    case StyleDisplayInside::RubyBaseContainer: {
   4339      static constexpr FrameConstructionData data(
   4340          ToCreationFunc(NS_NewRubyBaseContainerFrame),
   4341          FCDATA_IS_LINE_PARTICIPANT |
   4342              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby));
   4343      return &data;
   4344    }
   4345    case StyleDisplayInside::RubyText: {
   4346      static constexpr FrameConstructionData data(
   4347          ToCreationFunc(NS_NewRubyTextFrame),
   4348          FCDATA_IS_LINE_PARTICIPANT |
   4349              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer));
   4350      return &data;
   4351    }
   4352    case StyleDisplayInside::RubyTextContainer: {
   4353      static constexpr FrameConstructionData data(
   4354          ToCreationFunc(NS_NewRubyTextContainerFrame),
   4355          FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby));
   4356      return &data;
   4357    }
   4358    default:
   4359      MOZ_ASSERT_UNREACHABLE("unknown 'display' value");
   4360      return nullptr;
   4361  }
   4362 }
   4363 
   4364 nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
   4365    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   4366    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
   4367    nsFrameList& aFrameList) {
   4368  nsIContent* const content = aItem.mContent;
   4369  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   4370 
   4371  nsContainerFrame* newFrame = nullptr;
   4372  RefPtr<ComputedStyle> scrolledContentStyle =
   4373      BeginBuildingScrollContainerFrame(
   4374          aState, content, computedStyle,
   4375          aState.GetGeometricParent(*aDisplay, aParentFrame),
   4376          PseudoStyleType::scrolledContent, false, newFrame);
   4377 
   4378  // Create our block frame
   4379  // pass a temporary stylecontext, the correct one will be set later
   4380  nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle);
   4381 
   4382  // Make sure to AddChild before we call ConstructBlock so that we
   4383  // end up before our descendants in fixed-pos lists as needed.
   4384  aState.AddChild(newFrame, aFrameList, content, aParentFrame);
   4385 
   4386  nsFrameList blockList;
   4387  ConstructBlock(aState, content, newFrame, newFrame, scrolledContentStyle,
   4388                 &scrolledFrame, blockList,
   4389                 newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
   4390 
   4391  MOZ_ASSERT(blockList.OnlyChild() == scrolledFrame,
   4392             "Scrollframe's frameList should be exactly the scrolled frame!");
   4393  FinishBuildingScrollContainerFrame(newFrame, scrolledFrame);
   4394 
   4395  return newFrame;
   4396 }
   4397 
   4398 nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
   4399    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   4400    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
   4401    nsFrameList& aFrameList) {
   4402  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   4403  nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
   4404  ConstructBlock(aState, aItem.mContent,
   4405                 aState.GetGeometricParent(*aDisplay, aParentFrame),
   4406                 aParentFrame, computedStyle, &newFrame, aFrameList,
   4407                 newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
   4408  return newFrame;
   4409 }
   4410 
   4411 void nsCSSFrameConstructor::InitAndRestoreFrame(
   4412    const nsFrameConstructorState& aState, nsIContent* aContent,
   4413    nsContainerFrame* aParentFrame, nsIFrame* aNewFrame, bool aAllowCounters) {
   4414  MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized");
   4415 
   4416  // Initialize the frame
   4417  aNewFrame->Init(aContent, aParentFrame, nullptr);
   4418  aNewFrame->AddStateBits(aState.mAdditionalStateBits);
   4419 
   4420  if (aState.mFrameState) {
   4421    // Restore frame state for just the newly created frame.
   4422    RestoreFrameStateFor(aNewFrame, aState.mFrameState);
   4423  }
   4424 
   4425  if (aAllowCounters &&
   4426      mContainStyleScopeManager.AddCounterChanges(aNewFrame)) {
   4427    CountersDirty();
   4428  }
   4429 }
   4430 
   4431 already_AddRefed<ComputedStyle> nsCSSFrameConstructor::ResolveComputedStyle(
   4432    nsIContent* aContent) {
   4433  if (auto* element = Element::FromNode(aContent)) {
   4434    return ServoStyleSet::ResolveServoStyle(*element);
   4435  }
   4436 
   4437  MOZ_ASSERT(aContent->IsText(),
   4438             "shouldn't waste time creating ComputedStyles for "
   4439             "comments and processing instructions");
   4440 
   4441  Element* parent = aContent->GetFlattenedTreeParentElement();
   4442  MOZ_ASSERT(parent, "Text out of the flattened tree?");
   4443 
   4444  // FIXME(emilio): The const_cast is unfortunate, but it's not worse than what
   4445  // we did before.
   4446  //
   4447  // We could use ResolveServoStyle, but that would involve extra unnecessary
   4448  // refcount traffic...
   4449  auto* parentStyle =
   4450      const_cast<ComputedStyle*>(Servo_Element_GetMaybeOutOfDateStyle(parent));
   4451  MOZ_ASSERT(parentStyle,
   4452             "How are we inserting text frames in an unstyled element?");
   4453  return mPresShell->StyleSet()->ResolveStyleForText(aContent, parentStyle);
   4454 }
   4455 
   4456 // MathML Mod - RBS
   4457 void nsCSSFrameConstructor::FlushAccumulatedBlock(
   4458    nsFrameConstructorState& aState, nsIContent* aContent,
   4459    nsContainerFrame* aParentFrame, nsFrameList& aBlockList,
   4460    nsFrameList& aNewList) {
   4461  if (aBlockList.IsEmpty()) {
   4462    // Nothing to do
   4463    return;
   4464  }
   4465 
   4466  auto anonPseudo = PseudoStyleType::mozMathMLAnonymousBlock;
   4467 
   4468  ComputedStyle* parentContext =
   4469      nsIFrame::CorrectStyleParentFrame(aParentFrame, anonPseudo)->Style();
   4470  ServoStyleSet* styleSet = mPresShell->StyleSet();
   4471  RefPtr<ComputedStyle> blockContext =
   4472      styleSet->ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
   4473 
   4474  // then, create a block frame that will wrap the child frames. Make it a
   4475  // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
   4476  // is not a suitable block.
   4477  nsContainerFrame* blockFrame =
   4478      NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
   4479 
   4480  InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
   4481  ReparentFrames(this, blockFrame, aBlockList, false);
   4482  // We have to walk over aBlockList before we hand it over to blockFrame.
   4483  for (nsIFrame* f : aBlockList) {
   4484    f->SetParentIsWrapperAnonBox();
   4485  }
   4486  // abs-pos and floats are disabled in MathML children so we don't have to
   4487  // worry about messing up those.
   4488  blockFrame->SetInitialChildList(FrameChildListID::Principal,
   4489                                  std::move(aBlockList));
   4490  aNewList.AppendFrame(nullptr, blockFrame);
   4491 }
   4492 
   4493 // Only <math> elements can be floated or positioned.  All other MathML
   4494 // should be in-flow.
   4495 #define MATHML_DATA(_func)                                                    \
   4496  FrameConstructionData {                                                     \
   4497    _func, FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
   4498               FCDATA_WRAP_KIDS_IN_BLOCKS                                     \
   4499  }
   4500 
   4501 #define SIMPLE_MATHML_CREATE(_tag, _func) {nsGkAtoms::_tag, MATHML_DATA(_func)}
   4502 
   4503 /* static */
   4504 const nsCSSFrameConstructor::FrameConstructionData*
   4505 nsCSSFrameConstructor::FindMathMLData(const Element& aElement,
   4506                                      ComputedStyle& aStyle) {
   4507  MOZ_ASSERT(aElement.IsMathMLElement());
   4508 
   4509  nsAtom* tag = aElement.NodeInfo()->NameAtom();
   4510 
   4511  // Handle <math> specially, because it sometimes produces inlines
   4512  if (tag == nsGkAtoms::math) {
   4513    // The IsBlockOutsideStyle() check must match what
   4514    // specified::Display::equivalent_block_display is checking for
   4515    // already-block-outside things. Though the behavior here for the
   4516    // display:table case is pretty weird...
   4517    if (aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
   4518      static constexpr FrameConstructionData sBlockMathData(
   4519          ToCreationFunc(NS_NewMathMLmathBlockFrame),
   4520          FCDATA_FORCE_NULL_ABSPOS_CONTAINER | FCDATA_WRAP_KIDS_IN_BLOCKS);
   4521      return &sBlockMathData;
   4522    }
   4523 
   4524    static constexpr FrameConstructionData sInlineMathData(
   4525        ToCreationFunc(NS_NewMathMLmathInlineFrame),
   4526        FCDATA_FORCE_NULL_ABSPOS_CONTAINER | FCDATA_IS_LINE_PARTICIPANT |
   4527            FCDATA_WRAP_KIDS_IN_BLOCKS);
   4528    return &sInlineMathData;
   4529  }
   4530 
   4531  // Special case for elements with a display value other than none
   4532  // specified in mathml.css that are not handled by this function.
   4533  // These shouldn't be rendered as an mrow.
   4534  if (tag == nsGkAtoms::mtable || tag == nsGkAtoms::mtr ||
   4535      tag == nsGkAtoms::mlabeledtr || tag == nsGkAtoms::mtd) {
   4536    return nullptr;
   4537  }
   4538 
   4539  static constexpr FrameConstructionDataByTag sMathMLData[] = {
   4540      SIMPLE_MATHML_CREATE(annotation, NS_NewMathMLTokenFrame),
   4541      SIMPLE_MATHML_CREATE(annotation_xml, NS_NewMathMLmrowFrame),
   4542      SIMPLE_MATHML_CREATE(mi, NS_NewMathMLTokenFrame),
   4543      SIMPLE_MATHML_CREATE(mn, NS_NewMathMLTokenFrame),
   4544      SIMPLE_MATHML_CREATE(ms, NS_NewMathMLTokenFrame),
   4545      SIMPLE_MATHML_CREATE(mtext, NS_NewMathMLTokenFrame),
   4546      SIMPLE_MATHML_CREATE(mo, NS_NewMathMLmoFrame),
   4547      SIMPLE_MATHML_CREATE(mfrac, NS_NewMathMLmfracFrame),
   4548      SIMPLE_MATHML_CREATE(msup, NS_NewMathMLmmultiscriptsFrame),
   4549      SIMPLE_MATHML_CREATE(msub, NS_NewMathMLmmultiscriptsFrame),
   4550      SIMPLE_MATHML_CREATE(msubsup, NS_NewMathMLmmultiscriptsFrame),
   4551      SIMPLE_MATHML_CREATE(munder, NS_NewMathMLmunderoverFrame),
   4552      SIMPLE_MATHML_CREATE(mover, NS_NewMathMLmunderoverFrame),
   4553      SIMPLE_MATHML_CREATE(munderover, NS_NewMathMLmunderoverFrame),
   4554      SIMPLE_MATHML_CREATE(mphantom, NS_NewMathMLmrowFrame),
   4555      SIMPLE_MATHML_CREATE(mpadded, NS_NewMathMLmpaddedFrame),
   4556      SIMPLE_MATHML_CREATE(mspace, NS_NewMathMLmspaceFrame),
   4557      SIMPLE_MATHML_CREATE(none, NS_NewMathMLmrowFrame),
   4558      SIMPLE_MATHML_CREATE(mprescripts, NS_NewMathMLmrowFrame),
   4559      SIMPLE_MATHML_CREATE(mfenced, NS_NewMathMLmrowFrame),
   4560      SIMPLE_MATHML_CREATE(mmultiscripts, NS_NewMathMLmmultiscriptsFrame),
   4561      SIMPLE_MATHML_CREATE(mstyle, NS_NewMathMLmrowFrame),
   4562      SIMPLE_MATHML_CREATE(msqrt, NS_NewMathMLmrootFrame),
   4563      SIMPLE_MATHML_CREATE(mroot, NS_NewMathMLmrootFrame),
   4564      SIMPLE_MATHML_CREATE(maction, NS_NewMathMLmrowFrame),
   4565      SIMPLE_MATHML_CREATE(mrow, NS_NewMathMLmrowFrame),
   4566      SIMPLE_MATHML_CREATE(merror, NS_NewMathMLmrowFrame),
   4567      SIMPLE_MATHML_CREATE(menclose, NS_NewMathMLmencloseFrame),
   4568      SIMPLE_MATHML_CREATE(semantics, NS_NewMathMLmrowFrame)};
   4569 
   4570  if (const auto* data = FindDataByTag(aElement, aStyle, sMathMLData,
   4571                                       std::size(sMathMLData))) {
   4572    return data;
   4573  }
   4574  // Unknown MathML elements render as an mrow, see:
   4575  // https://w3c.github.io/mathml-core/#ref-for-dfn-unknown-mathml-element-2
   4576  static constexpr FrameConstructionData sMrowData =
   4577      MATHML_DATA(NS_NewMathMLmrowFrame);
   4578  return &sMrowData;
   4579 }
   4580 
   4581 nsContainerFrame* nsCSSFrameConstructor::ConstructFrameWithAnonymousChild(
   4582    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   4583    nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
   4584    ContainerFrameCreationFunc aConstructor,
   4585    ContainerFrameCreationFunc aInnerConstructor, PseudoStyleType aInnerPseudo,
   4586    bool aCandidateRootFrame) {
   4587  nsIContent* const content = aItem.mContent;
   4588  ComputedStyle* const computedStyle = aItem.mComputedStyle;
   4589 
   4590  // Create the outer frame:
   4591  nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
   4592 
   4593  InitAndRestoreFrame(aState, content,
   4594                      aCandidateRootFrame
   4595                          ? aState.GetGeometricParent(
   4596                                *computedStyle->StyleDisplay(), aParentFrame)
   4597                          : aParentFrame,
   4598                      newFrame);
   4599  newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
   4600 
   4601  // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
   4602  RefPtr<ComputedStyle> scForAnon =
   4603      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(aInnerPseudo,
   4604                                                                 computedStyle);
   4605 
   4606  // Create the anonymous inner wrapper frame
   4607  nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
   4608 
   4609  InitAndRestoreFrame(aState, content, newFrame, innerFrame);
   4610 
   4611  // Put the newly created frames into the right child list
   4612  SetInitialSingleChild(newFrame, innerFrame);
   4613 
   4614  aState.AddChild(newFrame, aFrameList, content, aParentFrame,
   4615                  aCandidateRootFrame, aCandidateRootFrame);
   4616 
   4617  if (!mRootElementFrame && aCandidateRootFrame) {
   4618    mRootElementFrame = newFrame;
   4619  }
   4620 
   4621  nsFrameConstructorSaveState floatSaveState;
   4622  aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
   4623 
   4624  nsFrameList childList;
   4625 
   4626  // Process children
   4627  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
   4628    ConstructFramesFromItemList(
   4629        aState, aItem.mChildItems, innerFrame,
   4630        aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childList);
   4631  } else {
   4632    ProcessChildren(aState, content, computedStyle, innerFrame, true, childList,
   4633                    false);
   4634  }
   4635 
   4636  // Set the inner wrapper frame's initial primary list
   4637  innerFrame->SetInitialChildList(FrameChildListID::Principal,
   4638                                  std::move(childList));
   4639 
   4640  return newFrame;
   4641 }
   4642 
   4643 nsIFrame* nsCSSFrameConstructor::ConstructOuterSVG(
   4644    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   4645    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
   4646    nsFrameList& aFrameList) {
   4647  return ConstructFrameWithAnonymousChild(
   4648      aState, aItem, aParentFrame, aFrameList, NS_NewSVGOuterSVGFrame,
   4649      NS_NewSVGOuterSVGAnonChildFrame, PseudoStyleType::mozSVGOuterSVGAnonChild,
   4650      true);
   4651 }
   4652 
   4653 nsIFrame* nsCSSFrameConstructor::ConstructMarker(
   4654    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
   4655    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
   4656    nsFrameList& aFrameList) {
   4657  return ConstructFrameWithAnonymousChild(
   4658      aState, aItem, aParentFrame, aFrameList, NS_NewSVGMarkerFrame,
   4659      NS_NewSVGMarkerAnonChildFrame, PseudoStyleType::mozSVGMarkerAnonChild,
   4660      false);
   4661 }
   4662 
   4663 // Only outer <svg> elements can be floated or positioned.  All other SVG
   4664 // should be in-flow.
   4665 #define SIMPLE_SVG_FCDATA(_func)                      \
   4666  FrameConstructionData(ToCreationFunc(_func),        \
   4667                        FCDATA_DISALLOW_OUT_OF_FLOW | \
   4668                            FCDATA_SKIP_ABSPOS_PUSH | \
   4669                            FCDATA_DISALLOW_GENERATED_CONTENT)
   4670 #define SIMPLE_SVG_CREATE(_tag, _func) \
   4671  {nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func)}
   4672 
   4673 /* static */
   4674 const nsCSSFrameConstructor::FrameConstructionData*
   4675 nsCSSFrameConstructor::FindSVGData(const Element& aElement,
   4676                                   nsIFrame* aParentFrame,
   4677                                   bool aIsWithinSVGText,
   4678                                   bool aAllowsTextPathChild,
   4679                                   ComputedStyle& aStyle) {
   4680  MOZ_ASSERT(aElement.IsSVGElement());
   4681 
   4682  static constexpr FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
   4683  static constexpr FrameConstructionData sContainerData =
   4684      SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
   4685 
   4686  bool parentIsSVG = aIsWithinSVGText;
   4687  nsIContent* parentContent =
   4688      aParentFrame ? aParentFrame->GetContent() : nullptr;
   4689 
   4690  nsAtom* tag = aElement.NodeInfo()->NameAtom();
   4691 
   4692  // XXXbz should this really be based on the tag of the parent frame's content?
   4693  // Should it not be based on the type of the parent frame (e.g. whether it's
   4694  // an SVG frame)?
   4695  if (parentContent) {
   4696    // It's not clear whether the SVG spec intends to allow any SVG
   4697    // content within svg:foreignObject at all (SVG 1.1, section
   4698    // 23.2), but if it does, it better be svg:svg.  So given that
   4699    // we're allowing it, treat it as a non-SVG parent.
   4700    parentIsSVG =
   4701        parentContent->IsSVGElement() &&
   4702        parentContent->NodeInfo()->NameAtom() != nsGkAtoms::foreignObject;
   4703  }
   4704 
   4705  if ((tag != nsGkAtoms::svg && !parentIsSVG) ||
   4706      (tag == nsGkAtoms::desc || tag == nsGkAtoms::title ||
   4707       tag == nsGkAtoms::metadata)) {
   4708    // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
   4709    // svg:svg not contained within svg:svg are incorrect, although they
   4710    // don't seem to specify error handling.  Ignore them, since many of
   4711    // our frame classes can't deal.  It *may* be that the document
   4712    // should at that point be considered in error according to F.2, but
   4713    // it's hard to tell.
   4714    //
   4715    // Style mutation can't change this situation, so don't bother
   4716    // adding to the undisplayed content map.
   4717    //
   4718    // We don't currently handle any UI for desc/title/metadata
   4719    return &sSuppressData;
   4720  }
   4721 
   4722  // We don't need frames for animation elements
   4723  if (aElement.IsSVGAnimationElement()) {
   4724    return &sSuppressData;
   4725  }
   4726 
   4727  if (tag == nsGkAtoms::svg && !parentIsSVG) {
   4728    // We need outer <svg> elements to have an SVGOuterSVGFrame regardless
   4729    // of whether they fail conditional processing attributes, since various
   4730    // SVG frames assume that one exists.  We handle the non-rendering
   4731    // of failing outer <svg> element contents like <switch> statements,
   4732    // and do the PassesConditionalProcessingTests call in
   4733    // SVGOuterSVGFrame::Init.
   4734    static constexpr FrameConstructionData sOuterSVGData(
   4735        &nsCSSFrameConstructor::ConstructOuterSVG);
   4736    return &sOuterSVGData;
   4737  }
   4738 
   4739  if (tag == nsGkAtoms::marker) {
   4740    static constexpr FrameConstructionData sMarkerSVGData(
   4741        &nsCSSFrameConstructor::ConstructMarker);
   4742    return &sMarkerSVGData;
   4743  }
   4744 
   4745  if (!aElement.PassesConditionalProcessingTests()) {
   4746    // Elements with failing conditional processing attributes never get
   4747    // rendered.  Note that this is not where we select which frame in a
   4748    // <switch> to render!  That happens in SVGSwitchFrame::PaintSVG.
   4749    if (aIsWithinSVGText) {
   4750      // SVGTextFrame doesn't handle conditional processing attributes,
   4751      // so don't create frames for descendants of <text> with failing
   4752      // attributes.  We need frames not to be created so that text layout
   4753      // is correct.
   4754      return &sSuppressData;
   4755    }
   4756    // If we're not inside <text>, create an SVGContainerFrame (which is a
   4757    // frame that doesn't render) so that paint servers can still be referenced,
   4758    // even if they live inside an element with failing conditional processing
   4759    // attributes.
   4760    return &sContainerData;
   4761  }
   4762 
   4763  // Ensure that a stop frame is a child of a gradient and that gradients
   4764  // can only have stop children.
   4765  bool parentIsGradient = aParentFrame && static_cast<SVGGradientFrame*>(
   4766                                              do_QueryFrame(aParentFrame));
   4767  bool stop = (tag == nsGkAtoms::stop);
   4768  if ((parentIsGradient && !stop) || (!parentIsGradient && stop)) {
   4769    return &sSuppressData;
   4770  }
   4771 
   4772  // Prevent bad frame types being children of filters or parents of filter
   4773  // primitives.  If aParentFrame is null, we know that the frame that will
   4774  // be created will be an nsInlineFrame, so it can never be a filter.
   4775  bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
   4776  if ((parentIsFilter && !aElement.IsSVGFilterPrimitiveElement()) ||
   4777      (!parentIsFilter && aElement.IsSVGFilterPrimitiveElement())) {
   4778    return &sSuppressData;
   4779  }
   4780 
   4781  // Prevent bad frame types being children of filter primitives or parents of
   4782  // filter primitive children.  If aParentFrame is null, we know that the frame
   4783  // that will be created will be an nsInlineFrame, so it can never be a filter
   4784  // primitive.
   4785  bool parentIsFEContainerFrame =
   4786      aParentFrame && aParentFrame->IsSVGFEContainerFrame();
   4787  if ((parentIsFEContainerFrame &&
   4788       !aElement.IsSVGFilterPrimitiveChildElement()) ||
   4789      (!parentIsFEContainerFrame &&
   4790       aElement.IsSVGFilterPrimitiveChildElement())) {
   4791    return &sSuppressData;
   4792  }
   4793 
   4794  // Special cases for text/tspan/textPath, because the kind of frame
   4795  // they get depends on the parent frame.  We ignore 'a' elements when
   4796  // determining the parent, however.
   4797  if (aIsWithinSVGText) {
   4798    // If aIsWithinSVGText is true, then we know that the "SVG text uses
   4799    // CSS frames" pref was true when this SVG fragment was first constructed.
   4800    //
   4801    // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
   4802    // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
   4803    // really know how to deal with it. This kinda sucks. :(
   4804    if (aParentFrame && aParentFrame->GetContent() != aElement.GetParent()) {
   4805      return &sSuppressData;
   4806    }
   4807 
   4808    // We don't use ConstructInline because we want different behavior
   4809    // for generated content.
   4810    static constexpr FrameConstructionData sTSpanData(
   4811        ToCreationFunc(NS_NewInlineFrame),
   4812        FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
   4813            FCDATA_DISALLOW_GENERATED_CONTENT | FCDATA_IS_LINE_PARTICIPANT |
   4814            FCDATA_IS_INLINE | FCDATA_USE_CHILD_ITEMS);
   4815    if (tag == nsGkAtoms::textPath) {
   4816      if (aAllowsTextPathChild) {
   4817        return &sTSpanData;
   4818      }
   4819    } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::a) {
   4820      return &sTSpanData;
   4821    }
   4822    return &sSuppressData;
   4823  } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::textPath) {
   4824    return &sSuppressData;
   4825  }
   4826 
   4827  static constexpr FrameConstructionDataByTag sSVGData[] = {
   4828      SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
   4829      SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
   4830      SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
   4831      SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame),
   4832      SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame),
   4833      SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame),
   4834      SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame),
   4835      SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame),
   4836      SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame),
   4837      SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame),
   4838      SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame),
   4839      SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
   4840      {nsGkAtoms::text,
   4841       {NS_NewSVGTextFrame,
   4842        FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_ALLOW_BLOCK_STYLES,
   4843        PseudoStyleType::mozSVGText}},
   4844      {nsGkAtoms::foreignObject,
   4845       {ToCreationFunc(NS_NewSVGForeignObjectFrame),
   4846        FCDATA_DISALLOW_OUT_OF_FLOW, PseudoStyleType::mozSVGForeignContent}},
   4847      SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
   4848      SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
   4849      SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
   4850      SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
   4851      SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
   4852      SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame),
   4853      SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
   4854      SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
   4855      SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
   4856      SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
   4857      SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
   4858      SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
   4859      SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
   4860      SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
   4861      SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
   4862      SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
   4863      SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
   4864      SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
   4865      SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
   4866      SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
   4867      SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
   4868      SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
   4869      SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
   4870      SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
   4871      SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
   4872      SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
   4873      SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
   4874      SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
   4875      SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
   4876      SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
   4877      SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
   4878      SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
   4879      SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
   4880      SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
   4881      SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
   4882      SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)};
   4883 
   4884  const FrameConstructionData* data =
   4885      FindDataByTag(aElement, aStyle, sSVGData, std::size(sSVGData));
   4886 
   4887  if (!data) {
   4888    data = &sContainerData;
   4889  }
   4890 
   4891  return data;
   4892 }
   4893 
   4894 void nsCSSFrameConstructor::AppendPageBreakItem(
   4895    nsIContent* aContent, FrameConstructionItemList& aItems) {
   4896  RefPtr<ComputedStyle> pseudoStyle =
   4897      mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
   4898          PseudoStyleType::pageBreak);
   4899 
   4900  MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,
   4901             "Unexpected display");
   4902 
   4903  static constexpr FrameConstructionData sPageBreakData(NS_NewPageBreakFrame,
   4904                                                        FCDATA_SKIP_FRAMESET);
   4905  aItems.AppendItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
   4906                    true);
   4907 }
   4908 
   4909 bool nsCSSFrameConstructor::ShouldCreateItemsForChild(
   4910    nsFrameConstructorState& aState, nsIContent* aContent,
   4911    nsContainerFrame* aParentFrame) {
   4912  aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
   4913  // XXX the GetContent() != aContent check is needed due to bug 135040.
   4914  // Remove it once that's fixed.
   4915  if (aContent->GetPrimaryFrame() &&
   4916      aContent->GetPrimaryFrame()->GetContent() == aContent &&
   4917      !aState.mCreatingExtraFrames) {
   4918    MOZ_ASSERT(false,
   4919               "asked to create frame construction item for a node that "
   4920               "already has a frame");
   4921    return false;
   4922  }
   4923 
   4924  // don't create a whitespace frame if aParent doesn't want it
   4925  if (!NeedFrameFor(aState, aParentFrame, aContent)) {
   4926    return false;
   4927  }
   4928 
   4929  // never create frames for comments or PIs
   4930  if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
   4931    return false;
   4932  }
   4933 
   4934  return true;
   4935 }
   4936 
   4937 void nsCSSFrameConstructor::AddFrameConstructionItems(
   4938    nsFrameConstructorState& aState, nsIContent* aContent,
   4939    bool aSuppressWhiteSpaceOptimizations, const ComputedStyle& aParentStyle,
   4940    const InsertionPoint& aInsertion, FrameConstructionItemList& aItems,
   4941    ItemFlags aFlags) {
   4942  nsContainerFrame* parentFrame = aInsertion.mParentFrame;
   4943  if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
   4944    return;
   4945  }
   4946 
   4947  RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
   4948  auto flags = aFlags + ItemFlag::AllowPageBreak;
   4949  if (parentFrame) {
   4950    if (parentFrame->IsInSVGTextSubtree()) {
   4951      flags += ItemFlag::IsWithinSVGText;
   4952    }
   4953    if (parentFrame->IsBlockFrame() && parentFrame->GetParent() &&
   4954        parentFrame->GetParent()->IsSVGTextFrame()) {
   4955      flags += ItemFlag::AllowTextPathChild;
   4956    }
   4957  }
   4958  AddFrameConstructionItemsInternal(aState, aContent, parentFrame,
   4959                                    aSuppressWhiteSpaceOptimizations,
   4960                                    computedStyle, flags, aItems);
   4961 }
   4962 
   4963 // Whether we should suppress frames for a child under a <select> frame.
   4964 //
   4965 // Never create frames for non-option/optgroup kids of <select> and non-option
   4966 // kids of <optgroup> inside a <select>.
   4967 static bool ShouldSuppressFrameInSelect(const nsIContent* aParent,
   4968                                        const nsIContent& aChild) {
   4969  if (!aParent ||
   4970      !aParent->IsAnyOfHTMLElements(nsGkAtoms::select, nsGkAtoms::optgroup,
   4971                                    nsGkAtoms::option)) {
   4972    return false;
   4973  }
   4974 
   4975  // Allow native anonymous content no matter what.
   4976  if (aChild.IsRootOfNativeAnonymousSubtree()) {
   4977    return false;
   4978  }
   4979 
   4980  // Options with labels have their label text added in ::before by forms.css.
   4981  // Suppress frames for their child text.
   4982  if (aParent->IsHTMLElement(nsGkAtoms::option)) {
   4983    return aParent->AsElement()->HasNonEmptyAttr(nsGkAtoms::label);
   4984  }
   4985 
   4986  // If we're in any display: contents subtree, just suppress the frame.
   4987  //
   4988  // We can't be regular NAC, since display: contents has no frame to generate
   4989  // them off.
   4990  if (aChild.GetParent() != aParent) {
   4991    return true;
   4992  }
   4993 
   4994  // <option> and <hr> are always fine.
   4995  if (aChild.IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::hr)) {
   4996    return false;
   4997  }
   4998 
   4999  // <optgroup> is OK in <select> but not in <optgroup>.
   5000  if (aChild.IsHTMLElement(nsGkAtoms::optgroup) &&
   5001      aParent->IsHTMLElement(nsGkAtoms::select)) {
   5002    return false;
   5003  }
   5004 
   5005  // Anything else is not ok.
   5006  return true;
   5007 }
   5008 
   5009 const nsCSSFrameConstructor::FrameConstructionData*
   5010 nsCSSFrameConstructor::FindDataForContent(nsIContent& aContent,
   5011                                          ComputedStyle& aStyle,
   5012                                          nsIFrame* aParentFrame,
   5013                                          ItemFlags aFlags) {
   5014  MOZ_ASSERT(aStyle.StyleDisplay()->mDisplay != StyleDisplay::None &&
   5015                 aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents,
   5016             "These two special display values should be handled earlier");
   5017 
   5018  if (auto* text = Text::FromNode(aContent)) {
   5019    return FindTextData(*text, aParentFrame);
   5020  }
   5021 
   5022  return FindElementData(*aContent.AsElement(), aStyle, aParentFrame, aFlags);
   5023 }
   5024 
   5025 const nsCSSFrameConstructor::FrameConstructionData*
   5026 nsCSSFrameConstructor::FindElementData(const Element& aElement,
   5027                                       ComputedStyle& aStyle,
   5028                                       nsIFrame* aParentFrame,
   5029                                       ItemFlags aFlags) {
   5030  // Don't create frames for non-SVG element children of SVG elements.
   5031  if (!aElement.IsSVGElement()) {
   5032    if (aParentFrame && IsFrameForSVG(aParentFrame) &&
   5033        !aParentFrame->IsSVGForeignObjectFrame()) {
   5034      return nullptr;
   5035    }
   5036    if (aFlags.contains(ItemFlag::IsWithinSVGText)) {
   5037      return nullptr;
   5038    }
   5039  }
   5040 
   5041  if (auto* data = FindElementTagData(aElement, aStyle, aParentFrame, aFlags)) {
   5042    return data;
   5043  }
   5044 
   5045  // Check for 'content: <image-url>' on the element (which makes us ignore
   5046  // 'display' values other than 'none' or 'contents').
   5047  if (nsImageFrame::ShouldCreateImageFrameForContentProperty(aElement,
   5048                                                             aStyle)) {
   5049    static constexpr FrameConstructionData sImgData(
   5050        NS_NewImageFrameForContentProperty);
   5051    return &sImgData;
   5052  }
   5053 
   5054  const bool shouldBlockify = aFlags.contains(ItemFlag::IsForRenderedLegend) ||
   5055                              aFlags.contains(ItemFlag::IsForOutsideMarker);
   5056  if (shouldBlockify && !aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
   5057    // Make a temp copy of StyleDisplay and blockify its mDisplay value.
   5058    auto display = *aStyle.StyleDisplay();
   5059    bool isRootElement = false;
   5060    uint16_t rawDisplayValue =
   5061        Servo_ComputedValues_BlockifiedDisplay(&aStyle, isRootElement);
   5062    display.mDisplay = StyleDisplay{rawDisplayValue};
   5063    return FindDisplayData(display, aElement);
   5064  }
   5065 
   5066  const auto& display = *aStyle.StyleDisplay();
   5067  return FindDisplayData(display, aElement);
   5068 }
   5069 
   5070 const nsCSSFrameConstructor::FrameConstructionData*
   5071 nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
   5072                                          ComputedStyle& aStyle,
   5073                                          nsIFrame* aParentFrame,
   5074                                          ItemFlags aFlags) {
   5075  switch (aElement.GetNameSpaceID()) {
   5076    case kNameSpaceID_XHTML:
   5077      return FindHTMLData(aElement, aParentFrame, aStyle);
   5078    case kNameSpaceID_MathML:
   5079      return FindMathMLData(aElement, aStyle);
   5080    case kNameSpaceID_SVG:
   5081      return FindSVGData(aElement, aParentFrame,
   5082                         aFlags.contains(ItemFlag::IsWithinSVGText),
   5083                         aFlags.contains(ItemFlag::AllowTextPathChild), aStyle);
   5084    case kNameSpaceID_XUL:
   5085      return FindXULTagData(aElement, aStyle);
   5086    default:
   5087      return nullptr;
   5088  }
   5089 }
   5090 
   5091 void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
   5092    nsFrameConstructorState& aState, nsIContent* aContent,
   5093    nsContainerFrame* aParentFrame, bool aSuppressWhiteSpaceOptimizations,
   5094    ComputedStyle* aComputedStyle, ItemFlags aFlags,
   5095    FrameConstructionItemList& aItems) {
   5096  MOZ_ASSERT(aContent->IsText() || aContent->IsElement(),
   5097             "Shouldn't get anything else here!");
   5098  MOZ_ASSERT(aContent->IsInComposedDoc());
   5099  MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
   5100             aContent->NodeInfo()->NameAtom() == nsGkAtoms::area);
   5101 
   5102  const bool withinSVGText = aFlags.contains(ItemFlag::IsWithinSVGText);
   5103  const bool isGeneratedContent = aFlags.contains(ItemFlag::IsGeneratedContent);
   5104  MOZ_ASSERT(!isGeneratedContent || aComputedStyle->IsPseudoElement(),
   5105             "Generated content should be a pseudo-element");
   5106 
   5107  FrameConstructionItem* item = nullptr;
   5108  auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
   5109    if (isGeneratedContent && !item) {
   5110      MOZ_ASSERT(!IsDisplayContents(aContent),
   5111                 "This would need to change if we support display: contents "
   5112                 "in generated content");
   5113      aContent->UnbindFromTree();
   5114    }
   5115  });
   5116 
   5117  // 'display:none' elements never creates any frames at all.
   5118  const nsStyleDisplay& display = *aComputedStyle->StyleDisplay();
   5119  if (display.mDisplay == StyleDisplay::None) {
   5120    return;
   5121  }
   5122 
   5123  if (display.mDisplay == StyleDisplay::Contents) {
   5124    // See the mDisplay fixup code in StyleAdjuster::adjust.
   5125    MOZ_ASSERT(!aContent->AsElement()->IsRootOfNativeAnonymousSubtree(),
   5126               "display:contents on anonymous content is unsupported");
   5127 
   5128    // FIXME(bug 1588477): <svg:text>'s TextNodeCorrespondenceRecorder has
   5129    // trouble with everything that looks like display: contents.
   5130    if (withinSVGText) {
   5131      return;
   5132    }
   5133 
   5134    CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
   5135                               *aComputedStyle, PseudoStyleType::before,
   5136                               aItems);
   5137 
   5138    FlattenedChildIterator iter(aContent);
   5139    InsertionPoint insertion(aParentFrame, aContent);
   5140    for (nsIContent* child = iter.GetNextChild(); child;
   5141         child = iter.GetNextChild()) {
   5142      AddFrameConstructionItems(aState, child, aSuppressWhiteSpaceOptimizations,
   5143                                *aComputedStyle, insertion, aItems, aFlags);
   5144    }
   5145    aItems.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
   5146 
   5147    CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
   5148                               *aComputedStyle, PseudoStyleType::after, aItems);
   5149    return;
   5150  }
   5151 
   5152  nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
   5153  if (ShouldSuppressFrameInSelect(parent, *aContent)) {
   5154    return;
   5155  }
   5156 
   5157  if (aContent->IsHTMLElement(nsGkAtoms::legend) && aParentFrame) {
   5158    const nsFieldSetFrame* const fs = GetFieldSetFrameFor(aParentFrame);
   5159    if (fs && !fs->GetLegend() && !aState.mHasRenderedLegend &&
   5160        !aComputedStyle->StyleDisplay()->IsFloatingStyle() &&
   5161        !aComputedStyle->StyleDisplay()->IsAbsolutelyPositionedStyle()) {
   5162      aState.mHasRenderedLegend = true;
   5163      aFlags += ItemFlag::IsForRenderedLegend;
   5164    }
   5165  }
   5166 
   5167  const FrameConstructionData* const data =
   5168      FindDataForContent(*aContent, *aComputedStyle, aParentFrame, aFlags);
   5169  if (!data || data->mBits & FCDATA_SUPPRESS_FRAME) {
   5170    return;
   5171  }
   5172 
   5173  const bool isPopup = data->mBits & FCDATA_IS_POPUP;
   5174 
   5175  const uint32_t bits = data->mBits;
   5176 
   5177  // Inside colgroups, suppress everything except columns.
   5178  if (aParentFrame && aParentFrame->IsTableColGroupFrame() &&
   5179      (!(bits & FCDATA_IS_TABLE_PART) ||
   5180       display.mDisplay != StyleDisplay::TableColumn)) {
   5181    return;
   5182  }
   5183 
   5184  const bool canHavePageBreak =
   5185      aFlags.contains(ItemFlag::AllowPageBreak) &&
   5186      aState.mPresContext->IsPaginated() &&
   5187      !display.IsAbsolutelyPositionedStyle() &&
   5188      !(aParentFrame && aParentFrame->IsFlexOrGridContainer()) &&
   5189      !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
   5190  if (canHavePageBreak && display.BreakBefore()) {
   5191    AppendPageBreakItem(aContent, aItems);
   5192  }
   5193 
   5194  if (!item) {
   5195    item = aItems.AppendItem(this, data, aContent, do_AddRef(aComputedStyle),
   5196                             aSuppressWhiteSpaceOptimizations);
   5197    if (aFlags.contains(ItemFlag::IsForRenderedLegend)) {
   5198      item->mIsRenderedLegend = true;
   5199    }
   5200  }
   5201  item->mIsText = !aContent->IsElement();
   5202  item->mIsGeneratedContent = isGeneratedContent;
   5203  if (isGeneratedContent) {
   5204    // We need to keep this alive until the frame takes ownership.
   5205    // This corresponds to the Release in ConstructFramesFromItem.
   5206    item->mContent->AddRef();
   5207  }
   5208  item->mIsPopup = isPopup;
   5209 
   5210  if (canHavePageBreak && display.BreakAfter()) {
   5211    AppendPageBreakItem(aContent, aItems);
   5212  }
   5213 
   5214  if (bits & FCDATA_IS_INLINE) {
   5215    // To correctly set item->mIsAllInline we need to build up our child items
   5216    // right now.
   5217    BuildInlineChildItems(aState, *item,
   5218                          aFlags.contains(ItemFlag::IsWithinSVGText),
   5219                          aFlags.contains(ItemFlag::AllowTextPathChild));
   5220    item->mIsBlock = false;
   5221  } else {
   5222    // Compute a boolean isInline which is guaranteed to be false for blocks
   5223    // (but may also be false for some inlines).
   5224    const bool isInline =
   5225        // Table-internal things are inline-outside if and only if they're kids
   5226        // of inlines, since they'll trigger construction of inline-table
   5227        // pseudos.
   5228        ((bits & FCDATA_IS_TABLE_PART) &&
   5229         (!aParentFrame ||  // No aParentFrame means inline
   5230          aParentFrame->StyleDisplay()->IsInlineFlow())) ||
   5231        // Things that are inline-outside but aren't inline frames are inline
   5232        display.IsInlineOutsideStyle() ||
   5233        // Popups that are certainly out of flow.
   5234        isPopup;
   5235 
   5236    // Set mIsAllInline conservatively.  It just might be that even an inline
   5237    // that has mIsAllInline false doesn't need an {ib} split.  So this is just
   5238    // an optimization to keep from doing too much work in cases when we can
   5239    // show that mIsAllInline is true..
   5240    item->mIsAllInline =
   5241        isInline ||
   5242        // Figure out whether we're guaranteed this item will be out of flow.
   5243        // This is not a precise test, since one of our ancestor inlines might
   5244        // add an absolute containing block (if it's relatively positioned) when
   5245        // there wasn't such a containing block before.  But it's conservative
   5246        // in the sense that anything that will really end up as an in-flow
   5247        // non-inline will test false here.  In other words, if this test is
   5248        // true we're guaranteed to be inline; if it's false we don't know what
   5249        // we'll end up as.
   5250        //
   5251        // If we make this test precise, we can remove some of the code dealing
   5252        // with the imprecision in ConstructInline and adjust the comments on
   5253        // mIsAllInline and mIsBlock in the header.
   5254        (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
   5255         aState.GetGeometricParent(display, nullptr));
   5256 
   5257    // Set mIsBlock conservatively.  It's OK to set it false for some real
   5258    // blocks, but not OK to set it true for things that aren't blocks.  Since
   5259    // isOutOfFlow might be false even in cases when the frame will end up
   5260    // out-of-flow, we can't use it here.  But we _can_ say that the frame will
   5261    // for sure end up in-flow if it's not floated or absolutely positioned.
   5262    item->mIsBlock = !isInline && !display.IsAbsolutelyPositionedStyle() &&
   5263                     !display.IsFloatingStyle() && !(bits & FCDATA_IS_SVG_TEXT);
   5264  }
   5265 
   5266  if (item->mIsAllInline) {
   5267    aItems.InlineItemAdded();
   5268  } else if (item->mIsBlock) {
   5269    aItems.BlockItemAdded();
   5270  }
   5271 }
   5272 
   5273 /**
   5274 * Return true if the frame construction item pointed to by aIter will
   5275 * create a frame adjacent to a line boundary in the frame tree, and that
   5276 * line boundary is induced by a content node adjacent to the frame's
   5277 * content node in the content tree. The latter condition is necessary so
   5278 * that ContentAppended/ContentInserted/ContentWillBeRemoved can easily find any
   5279 * text nodes that were suppressed here.
   5280 */
   5281 bool nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter) {
   5282  if (aIter.item().mSuppressWhiteSpaceOptimizations) {
   5283    return false;
   5284  }
   5285 
   5286  if (aIter.AtStart()) {
   5287    if (aIter.List()->HasLineBoundaryAtStart() &&
   5288        !aIter.item().mContent->GetPreviousSibling()) {
   5289      return true;
   5290    }
   5291  } else {
   5292    FCItemIterator prev = aIter;
   5293    prev.Prev();
   5294    if (prev.item().IsLineBoundary() &&
   5295        !prev.item().mSuppressWhiteSpaceOptimizations &&
   5296        aIter.item().mContent->GetPreviousSibling() == prev.item().mContent) {
   5297      return true;
   5298    }
   5299  }
   5300 
   5301  FCItemIterator next = aIter;
   5302  next.Next();
   5303  if (next.IsDone()) {
   5304    if (aIter.List()->HasLineBoundaryAtEnd() &&
   5305        !aIter.item().mContent->GetNextSibling()) {
   5306      return true;
   5307    }
   5308  } else {
   5309    if (next.item().IsLineBoundary() &&
   5310        !next.item().mSuppressWhiteSpaceOptimizations &&
   5311        aIter.item().mContent->GetNextSibling() == next.item().mContent) {
   5312      return true;
   5313    }
   5314  }
   5315 
   5316  return false;
   5317 }
   5318 
   5319 void nsCSSFrameConstructor::ConstructFramesFromItem(
   5320    nsFrameConstructorState& aState, FCItemIterator& aIter,
   5321    nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
   5322  FrameConstructionItem& item = aIter.item();
   5323  ComputedStyle* computedStyle = item.mComputedStyle;
   5324  if (item.mIsText) {
   5325    // If this is collapsible whitespace next to a line boundary,
   5326    // don't create a frame. item.IsWhitespace() also sets the
   5327    // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
   5328    // end up creating a frame, nsTextFrame::Init will clear the flag.)
   5329    // We don't do this for generated content, because some generated
   5330    // text content is empty text nodes that are about to be initialized.
   5331    // (We check mAdditionalStateBits because only the generated content
   5332    // container's frame construction item is marked with
   5333    // mIsGeneratedContent, and we might not have an aParentFrame.)
   5334    // We don't do it for content that may have Shadow DOM siblings / insertion
   5335    // points, because they make it difficult to correctly create the frame due
   5336    // to dynamic changes.
   5337    // We don't do it for SVG text, since we might need to position and
   5338    // measure the white space glyphs due to x/y/dx/dy attributes.
   5339    if (AtLineBoundary(aIter) &&
   5340        !computedStyle->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
   5341        aIter.List()->ParentHasNoShadowDOM() &&
   5342        !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
   5343        (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
   5344        !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
   5345        !mAlwaysCreateFramesForIgnorableWhitespace &&
   5346        item.IsWhitespace(aState)) {
   5347      return;
   5348    }
   5349 
   5350    ConstructTextFrame(item.mFCData, aState, item.mContent, aParentFrame,
   5351                       computedStyle, aFrameList);
   5352    return;
   5353  }
   5354 
   5355  AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
   5356  if (item.mIsGeneratedContent) {
   5357    // Ensure that frames created here are all tagged with
   5358    // NS_FRAME_GENERATED_CONTENT.
   5359    aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
   5360  }
   5361 
   5362  // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
   5363  ConstructFrameFromItemInternal(item, aState, aParentFrame, aFrameList);
   5364 
   5365  if (item.mIsGeneratedContent) {
   5366    // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
   5367    // The frame owns the generated content now.
   5368    item.mContent->Release();
   5369 
   5370    // Now that we've passed ownership of item.mContent to the frame, unset
   5371    // our generated content flag so we don't release or unbind it ourselves.
   5372    item.mIsGeneratedContent = false;
   5373  }
   5374 }
   5375 
   5376 nsContainerFrame* nsCSSFrameConstructor::GetAbsoluteContainingBlock(
   5377    nsIFrame* aFrame, ContainingBlockType aType) {
   5378  // Starting with aFrame, look for a frame that is absolutely positioned or
   5379  // relatively positioned (and transformed, if aType is FIXED)
   5380  for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
   5381    if (frame->IsMathMLFrame()) {
   5382      // If it's mathml, bail out -- no absolute positioning out from inside
   5383      // mathml frames.  Note that we don't make this part of the loop
   5384      // condition because of the stuff at the end of this method...
   5385      return nullptr;
   5386    }
   5387 
   5388    // Look for the ICB.
   5389    if (aType == FIXED_POS) {
   5390      LayoutFrameType t = frame->Type();
   5391      if (t == LayoutFrameType::Viewport || t == LayoutFrameType::PageContent) {
   5392        return static_cast<nsContainerFrame*>(frame);
   5393      }
   5394    }
   5395 
   5396    // If the frame is positioned, we will probably return it as the containing
   5397    // block (see the exceptions below).  Otherwise, we'll start looking at the
   5398    // parent frame, unless we're dealing with a scrollframe.
   5399    // Scrollframes are special since they're not positioned, but their
   5400    // scrolledframe might be.  So, we need to check this special case to return
   5401    // the correct containing block (the scrolledframe) in that case.
   5402    // If we're looking for a fixed-pos containing block and the frame is
   5403    // not transformed, skip it.
   5404    if (!frame->IsAbsPosContainingBlock()) {
   5405      continue;
   5406    }
   5407    if (aType == FIXED_POS && !frame->IsFixedPosContainingBlock()) {
   5408      continue;
   5409    }
   5410    nsIFrame* absPosCBCandidate = frame;
   5411    LayoutFrameType type = absPosCBCandidate->Type();
   5412    if (type == LayoutFrameType::FieldSet) {
   5413      absPosCBCandidate =
   5414          static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
   5415      if (!absPosCBCandidate) {
   5416        continue;
   5417      }
   5418      type = absPosCBCandidate->Type();
   5419    }
   5420    if (type == LayoutFrameType::ScrollContainer) {
   5421      ScrollContainerFrame* scrollContainerFrame =
   5422          do_QueryFrame(absPosCBCandidate);
   5423      absPosCBCandidate = scrollContainerFrame->GetScrolledFrame();
   5424      if (!absPosCBCandidate) {
   5425        continue;
   5426      }
   5427      type = absPosCBCandidate->Type();
   5428    }
   5429    // Only first continuations can be containing blocks.
   5430    absPosCBCandidate = absPosCBCandidate->FirstContinuation();
   5431    // Is the frame really an absolute container?
   5432    if (!absPosCBCandidate->IsAbsoluteContainer()) {
   5433      continue;
   5434    }
   5435 
   5436    // For tables, skip the inner frame and consider the table wrapper frame.
   5437    if (type == LayoutFrameType::Table) {
   5438      continue;
   5439    }
   5440    // For table wrapper frames, we can just return absPosCBCandidate.
   5441    MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(absPosCBCandidate),
   5442               "abs.pos. containing block must be nsContainerFrame sub-class");
   5443    return static_cast<nsContainerFrame*>(absPosCBCandidate);
   5444  }
   5445 
   5446  MOZ_ASSERT(aType != FIXED_POS, "no ICB in this frame tree?");
   5447 
   5448  // It is possible for the search for the containing block to fail, because
   5449  // no absolute container can be found in the parent chain.  In those cases,
   5450  // we fall back to the document element's containing block.
   5451  return mDocElementContainingBlock;
   5452 }
   5453 
   5454 nsContainerFrame* nsCSSFrameConstructor::GetFloatContainingBlock(
   5455    nsIFrame* aFrame) {
   5456  // Starting with aFrame, look for a frame that is a float containing block.
   5457  // If we hit a frame which prevents its descendants from floating, bail out.
   5458  // The logic here needs to match the logic in MaybePushFloatContainingBlock().
   5459  for (nsIFrame* containingBlock = aFrame;
   5460       containingBlock && !ShouldSuppressFloatingOfDescendants(containingBlock);
   5461       containingBlock = containingBlock->GetParent()) {
   5462    if (containingBlock->IsFloatContainingBlock()) {
   5463      MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(containingBlock),
   5464                 "float containing block must be nsContainerFrame sub-class");
   5465      return static_cast<nsContainerFrame*>(containingBlock);
   5466    }
   5467  }
   5468 
   5469  // If we didn't find a containing block, then there just isn't
   5470  // one.... return null
   5471  return nullptr;
   5472 }
   5473 
   5474 /**
   5475 * This function will get the previous sibling to use for an append operation.
   5476 *
   5477 * It takes a parent frame (must not be null) and the next insertion sibling, if
   5478 * the parent content is display: contents or has ::after content (may be null).
   5479 */
   5480 static nsIFrame* FindAppendPrevSibling(nsIFrame* aParentFrame,
   5481                                       nsIFrame* aNextSibling) {
   5482  aParentFrame->DrainSelfOverflowList();
   5483 
   5484  if (aNextSibling) {
   5485    MOZ_ASSERT(
   5486        aNextSibling->GetParent()->GetContentInsertionFrame() == aParentFrame,
   5487        "Wrong parent");
   5488    return aNextSibling->GetPrevSibling();
   5489  }
   5490 
   5491  return aParentFrame->PrincipalChildList().LastChild();
   5492 }
   5493 
   5494 /**
   5495 * Finds the right parent frame to append content to aParentFrame.
   5496 *
   5497 * Cannot return or receive null.
   5498 */
   5499 static nsContainerFrame* ContinuationToAppendTo(
   5500    nsContainerFrame* aParentFrame) {
   5501  MOZ_ASSERT(aParentFrame);
   5502 
   5503  if (IsFramePartOfIBSplit(aParentFrame)) {
   5504    // If the frame we are manipulating is a ib-split frame (that is, one that's
   5505    // been created as a result of a block-in-inline situation) then we need to
   5506    // append to the last ib-split sibling, not to the frame itself.
   5507    //
   5508    // Always make sure to look at the last continuation of the frame for the
   5509    // {ib} case, even if that continuation is empty.
   5510    //
   5511    // We don't do this for the non-ib-split-frame case, since in the other
   5512    // cases appending to the last nonempty continuation is fine and in fact not
   5513    // doing that can confuse code that doesn't know to pull kids from
   5514    // continuations other than its next one.
   5515    return static_cast<nsContainerFrame*>(
   5516        GetLastIBSplitSibling(aParentFrame)->LastContinuation());
   5517  }
   5518 
   5519  return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
   5520 }
   5521 
   5522 /**
   5523 * This function will get the next sibling for a frame insert operation given
   5524 * the parent and previous sibling.  aPrevSibling may be null.
   5525 */
   5526 static nsIFrame* GetInsertNextSibling(nsIFrame* aParentFrame,
   5527                                      nsIFrame* aPrevSibling) {
   5528  if (aPrevSibling) {
   5529    return aPrevSibling->GetNextSibling();
   5530  }
   5531 
   5532  return aParentFrame->PrincipalChildList().FirstChild();
   5533 }
   5534 
   5535 void nsCSSFrameConstructor::AppendFramesToParent(
   5536    nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
   5537    nsFrameList& aFrameList, nsIFrame* aPrevSibling, bool aIsRecursiveCall) {
   5538  MOZ_ASSERT(
   5539      !IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) ||
   5540          !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild(),
   5541      "aParentFrame has a ib-split sibling with kids?");
   5542  MOZ_ASSERT(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
   5543             "Parent and prevsibling don't match");
   5544  MOZ_ASSERT(
   5545      !aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||
   5546          !IsFramePartOfIBSplit(aParentFrame),
   5547      "We should have wiped aParentFrame in WipeContainingBlock() "
   5548      "if it's part of an IB split!");
   5549 
   5550  nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
   5551 
   5552  NS_ASSERTION(nextSibling || !aParentFrame->GetNextContinuation() ||
   5553                   !aParentFrame->GetNextContinuation()
   5554                        ->PrincipalChildList()
   5555                        .FirstChild() ||
   5556                   aIsRecursiveCall,
   5557               "aParentFrame has later continuations with kids?");
   5558  NS_ASSERTION(
   5559      nextSibling || !IsFramePartOfIBSplit(aParentFrame) ||
   5560          (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) &&
   5561           !aParentFrame->GetNextContinuation()) ||
   5562          aIsRecursiveCall,
   5563      "aParentFrame is not last?");
   5564 
   5565  // If we're inserting a list of frames at the end of the trailing inline
   5566  // of an {ib} split, we may need to create additional {ib} siblings to parent
   5567  // them.
   5568  if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
   5569    // When we get here, our frame list might start with a block.  If it does
   5570    // so, and aParentFrame is an inline, and it and all its previous
   5571    // continuations have no siblings, then put the initial blocks from the
   5572    // frame list into the previous block of the {ib} split.  Note that we
   5573    // didn't want to stop at the block part of the split when figuring out
   5574    // initial parent, because that could screw up float parenting; it's easier
   5575    // to do this little fixup here instead.
   5576    if (aFrameList.NotEmpty() && aFrameList.FirstChild()->IsBlockOutside()) {
   5577      // See whether our trailing inline is empty
   5578      nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
   5579      if (firstContinuation->PrincipalChildList().IsEmpty()) {
   5580        // Our trailing inline is empty.  Collect our starting blocks from
   5581        // aFrameList, get the right parent frame for them, and put them in.
   5582        nsFrameList blockKids =
   5583            aFrameList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
   5584        NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
   5585 
   5586        nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
   5587        prevBlock =
   5588            static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
   5589        NS_ASSERTION(prevBlock, "Should have previous block here");
   5590 
   5591        MoveChildrenTo(aParentFrame, prevBlock, blockKids);
   5592      }
   5593    }
   5594 
   5595    // We want to put some of the frames into this inline frame.
   5596    nsFrameList inlineKids =
   5597        aFrameList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
   5598 
   5599    if (!inlineKids.IsEmpty()) {
   5600      AppendFrames(aParentFrame, FrameChildListID::Principal,
   5601                   std::move(inlineKids));
   5602    }
   5603 
   5604    if (!aFrameList.IsEmpty()) {
   5605      nsFrameList ibSiblings;
   5606      CreateIBSiblings(aState, aParentFrame,
   5607                       aParentFrame->IsAbsPosContainingBlock(), aFrameList,
   5608                       ibSiblings);
   5609 
   5610      // Make sure to trigger reflow of the inline that used to be our
   5611      // last one and now isn't anymore, since its GetSkipSides() has
   5612      // changed.
   5613      mPresShell->FrameNeedsReflow(aParentFrame,
   5614                                   IntrinsicDirty::FrameAndAncestors,
   5615                                   NS_FRAME_HAS_DIRTY_CHILDREN);
   5616 
   5617      // Recurse so we create new ib siblings as needed for aParentFrame's
   5618      // parent
   5619      return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
   5620                                  aParentFrame, true);
   5621    }
   5622    return;
   5623  }
   5624 
   5625  // If we're appending a list of frames to the last continuations of a
   5626  // ::-moz-column-content, we may need to create column-span siblings for them.
   5627  if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
   5628    // Extract any initial non-column-span kids, and append them to
   5629    // ::-moz-column-content's child list.
   5630    nsFrameList initialNonColumnSpanKids =
   5631        aFrameList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
   5632    AppendFrames(aParentFrame, FrameChildListID::Principal,
   5633                 std::move(initialNonColumnSpanKids));
   5634 
   5635    if (aFrameList.IsEmpty()) {
   5636      // No more kids to process (there weren't any column-span kids).
   5637      return;
   5638    }
   5639 
   5640    nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
   5641        aState, aParentFrame, aFrameList,
   5642        // Column content should never be a absolute/fixed positioned containing
   5643        // block. Pass nullptr as aPositionedFrame.
   5644        nullptr);
   5645 
   5646    nsContainerFrame* columnSetWrapper = aParentFrame->GetParent();
   5647    while (!columnSetWrapper->IsColumnSetWrapperFrame()) {
   5648      columnSetWrapper = columnSetWrapper->GetParent();
   5649    }
   5650    MOZ_ASSERT(columnSetWrapper,
   5651               "No ColumnSetWrapperFrame ancestor for -moz-column-content?");
   5652 
   5653    FinishBuildingColumns(aState, columnSetWrapper, aParentFrame,
   5654                          columnSpanSiblings);
   5655 
   5656    MOZ_ASSERT(columnSpanSiblings.IsEmpty(),
   5657               "The column-span siblings should be moved to the proper place!");
   5658    return;
   5659  }
   5660 
   5661  // Insert the frames after our aPrevSibling
   5662  InsertFrames(aParentFrame, FrameChildListID::Principal, aPrevSibling,
   5663               std::move(aFrameList));
   5664 }
   5665 
   5666 template <nsCSSFrameConstructor::SiblingDirection aDirection>
   5667 nsIFrame* nsCSSFrameConstructor::FindSiblingInternal(
   5668    FlattenedChildIterator& aIter) {
   5669  auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
   5670    return aDirection == SiblingDirection::Forward ? aIter.GetNextChild()
   5671                                                   : aIter.GetPreviousChild();
   5672  };
   5673 
   5674  auto getInsideMarkerFrame = [](const nsIContent* aContent) -> nsIFrame* {
   5675    auto* marker = nsLayoutUtils::GetMarkerFrame(aContent);
   5676    const bool isInsideMarker =
   5677        marker && marker->GetInFlowParent()->StyleList()->mListStylePosition ==
   5678                      StyleListStylePosition::Inside;
   5679    return isInsideMarker ? marker : nullptr;
   5680  };
   5681 
   5682  auto getNearPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
   5683    if (aDirection == SiblingDirection::Forward) {
   5684      if (auto* backdrop = nsLayoutUtils::GetBackdropFrame(aContent)) {
   5685        return backdrop;
   5686      }
   5687      if (auto* marker = getInsideMarkerFrame(aContent)) {
   5688        return marker;
   5689      }
   5690      return nsLayoutUtils::GetBeforeFrame(aContent);
   5691    }
   5692    return nsLayoutUtils::GetAfterFrame(aContent);
   5693  };
   5694 
   5695  auto getFarPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
   5696    if (aDirection == SiblingDirection::Forward) {
   5697      return nsLayoutUtils::GetAfterFrame(aContent);
   5698    }
   5699    if (auto* before = nsLayoutUtils::GetBeforeFrame(aContent)) {
   5700      return before;
   5701    }
   5702    if (auto* marker = getInsideMarkerFrame(aContent)) {
   5703      return marker;
   5704    }
   5705    return nsLayoutUtils::GetBackdropFrame(aContent);
   5706  };
   5707 
   5708  while (nsIContent* sibling = nextDomSibling(aIter)) {
   5709    // NOTE(emilio): It's important to check GetPrimaryFrame() before
   5710    // IsDisplayContents to get the correct insertion point when multiple
   5711    // siblings go from display: non-none to display: contents.
   5712    if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
   5713      // XXX the GetContent() == sibling check is needed due to bug 135040.
   5714      // Remove it once that's fixed.
   5715      // The rendered legend check is needed because it is conceptually out of
   5716      // flow. There can only be one rendered legend at a time, and we reframe
   5717      // when that changes, so this is ok. Table captions are a similar case,
   5718      // but there can be multiple of them and they instead get pulled out (and
   5719      // the sibling fixed up) after building the frame list.
   5720      if (primaryFrame->GetContent() == sibling &&
   5721          !primaryFrame->IsRenderedLegend()) [[likely]] {
   5722        return primaryFrame;
   5723      }
   5724    }
   5725 
   5726    if (IsDisplayContents(sibling)) {
   5727      if (nsIFrame* frame = getNearPseudo(sibling)) {
   5728        return frame;
   5729      }
   5730 
   5731      const bool startFromBeginning = aDirection == SiblingDirection::Forward;
   5732      FlattenedChildIterator iter(sibling, startFromBeginning);
   5733      nsIFrame* sibling = FindSiblingInternal<aDirection>(iter);
   5734      if (sibling) {
   5735        return sibling;
   5736      }
   5737    }
   5738  }
   5739 
   5740  return getFarPseudo(aIter.Parent());
   5741 }
   5742 
   5743 nsIFrame* nsCSSFrameConstructor::AdjustSiblingFrame(
   5744    nsIFrame* aSibling, SiblingDirection aDirection) {
   5745  if (!aSibling) {
   5746    return nullptr;
   5747  }
   5748 
   5749  if (aSibling->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
   5750    aSibling = aSibling->GetPlaceholderFrame();
   5751    MOZ_ASSERT(aSibling);
   5752  }
   5753 
   5754  MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
   5755  if (aDirection == SiblingDirection::Backward) {
   5756    // The frame may be a ib-split frame (a split inline frame that contains a
   5757    // block).  Get the last part of that split.
   5758    if (IsFramePartOfIBSplit(aSibling)) {
   5759      aSibling = GetLastIBSplitSibling(aSibling);
   5760    }
   5761 
   5762    // The frame may have a continuation. If so, we want the last
   5763    // non-overflow-container continuation as our previous sibling.
   5764    aSibling = aSibling->GetTailContinuation();
   5765  }
   5766 
   5767  return aSibling;
   5768 }
   5769 
   5770 nsIFrame* nsCSSFrameConstructor::FindPreviousSibling(
   5771    const FlattenedChildIterator& aIter) {
   5772  return AdjustSiblingFrame(FindSibling<SiblingDirection::Backward>(aIter),
   5773                            SiblingDirection::Backward);
   5774 }
   5775 
   5776 nsIFrame* nsCSSFrameConstructor::FindNextSibling(
   5777    const FlattenedChildIterator& aIter) {
   5778  return AdjustSiblingFrame(FindSibling<SiblingDirection::Forward>(aIter),
   5779                            SiblingDirection::Forward);
   5780 }
   5781 
   5782 template <nsCSSFrameConstructor::SiblingDirection aDirection>
   5783 nsIFrame* nsCSSFrameConstructor::FindSibling(
   5784    const FlattenedChildIterator& aIter) {
   5785  FlattenedChildIterator siblingIter = aIter;
   5786  nsIFrame* sibling = FindSiblingInternal<aDirection>(siblingIter);
   5787  if (sibling) {
   5788    return sibling;
   5789  }
   5790 
   5791  // Our siblings (if any) do not have a frame to guide us. The frame for the
   5792  // target content should be inserted whereever a frame for the container would
   5793  // be inserted. This is needed when inserting into display: contents nodes.
   5794  const nsIContent* current = aIter.Parent();
   5795  while (IsDisplayContents(current)) {
   5796    const nsIContent* parent = current->GetFlattenedTreeParent();
   5797    MOZ_ASSERT(parent, "No display: contents on the root");
   5798 
   5799    FlattenedChildIterator iter(parent);
   5800    iter.Seek(current);
   5801    sibling = FindSiblingInternal<aDirection>(iter);
   5802    if (sibling) {
   5803      return sibling;
   5804    }
   5805 
   5806    current = parent;
   5807  }
   5808 
   5809  return nullptr;
   5810 }
   5811 
   5812 nsIFrame* nsCSSFrameConstructor::GetInsertionPrevSibling(
   5813    InsertionPoint* aInsertion, nsIContent* aChild, bool* aIsAppend) {
   5814  MOZ_ASSERT(aInsertion->mParentFrame, "Must have parent frame to start with");
   5815 
   5816  *aIsAppend = false;
   5817 
   5818  // Find the frame that precedes the insertion point.
   5819  FlattenedChildIterator iter(aInsertion->mContainer);
   5820  if (!aChild->IsRootOfNativeAnonymousSubtree()) {
   5821    // The check for IsRootOfNativeAnonymousSubtree() is because editor is
   5822    // severely broken and calls us directly for native anonymous
   5823    // nodes that it creates.
   5824    iter.Seek(aChild);
   5825  } else {
   5826    // Prime the iterator for the call to FindPreviousSibling.
   5827    iter.GetNextChild();
   5828    MOZ_ASSERT(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
   5829               "Someone passed native anonymous content directly into frame "
   5830               "construction.  Stop doing that!");
   5831  }
   5832 
   5833  // Note that FindPreviousSibling is passed the iterator by value, so that
   5834  // the later usage of the iterator starts from the same place.
   5835  nsIFrame* prevSibling = FindPreviousSibling(iter);
   5836 
   5837  // Now, find the geometric parent so that we can handle
   5838  // continuations properly. Use the prev sibling if we have it;
   5839  // otherwise use the next sibling.
   5840  if (prevSibling) {
   5841    aInsertion->mParentFrame =
   5842        prevSibling->GetParent()->GetContentInsertionFrame();
   5843    *aIsAppend =
   5844        !::GetInsertNextSibling(aInsertion->mParentFrame, prevSibling) &&
   5845        !nsLayoutUtils::GetNextContinuationOrIBSplitSibling(
   5846            aInsertion->mParentFrame) &&
   5847        !IsWrapperPseudo(aInsertion->mParentFrame);
   5848  } else if (nsIFrame* nextSibling = FindNextSibling(iter)) {
   5849    // If there is no previous sibling, then find the frame that follows
   5850    aInsertion->mParentFrame =
   5851        nextSibling->GetParent()->GetContentInsertionFrame();
   5852  } else {
   5853    // No previous or next sibling, so treat this like an appended frame.
   5854    *aIsAppend = true;
   5855 
   5856    aInsertion->mParentFrame =
   5857        ::ContinuationToAppendTo(aInsertion->mParentFrame);
   5858 
   5859    prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr);
   5860  }
   5861 
   5862  return prevSibling;
   5863 }
   5864 
   5865 nsContainerFrame* nsCSSFrameConstructor::GetContentInsertionFrameFor(
   5866    nsIContent* aContent) {
   5867  nsIFrame* frame;
   5868  while (!(frame = aContent->GetPrimaryFrame())) {
   5869    if (!IsDisplayContents(aContent)) {
   5870      return nullptr;
   5871    }
   5872 
   5873    aContent = aContent->GetFlattenedTreeParent();
   5874    if (!aContent) {
   5875      return nullptr;
   5876    }
   5877  }
   5878 
   5879  // If the content of the frame is not the desired content then this is not
   5880  // really a frame for the desired content.
   5881  // XXX This check is needed due to bug 135040. Remove it once that's fixed.
   5882  if (frame->GetContent() != aContent) {
   5883    return nullptr;
   5884  }
   5885 
   5886  nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
   5887 
   5888  NS_ASSERTION(!insertionFrame || insertionFrame == frame || !frame->IsLeaf(),
   5889               "The insertion frame is the primary frame or the primary frame "
   5890               "isn't a leaf");
   5891 
   5892  return insertionFrame;
   5893 }
   5894 
   5895 static bool IsSpecialFramesetChild(nsIContent* aContent) {
   5896  // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
   5897  return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
   5898 }
   5899 
   5900 static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode);
   5901 
   5902 void nsCSSFrameConstructor::AddTextItemIfNeeded(
   5903    nsFrameConstructorState& aState, const ComputedStyle& aParentStyle,
   5904    const InsertionPoint& aInsertion, nsIContent* aPossibleTextContent,
   5905    FrameConstructionItemList& aItems) {
   5906  MOZ_ASSERT(aPossibleTextContent, "Must have node");
   5907  if (!aPossibleTextContent->IsText() ||
   5908      !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
   5909      aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
   5910    // Not text, or not suppressed due to being all-whitespace (if it were being
   5911    // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
   5912    // going to be reframed anyway.
   5913    return;
   5914  }
   5915  MOZ_ASSERT(!aPossibleTextContent->GetPrimaryFrame(),
   5916             "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
   5917  AddFrameConstructionItems(aState, aPossibleTextContent, false, aParentStyle,
   5918                            aInsertion, aItems);
   5919 }
   5920 
   5921 void nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aContent) {
   5922  if (!aContent->IsText() ||
   5923      !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
   5924      aContent->HasFlag(NODE_NEEDS_FRAME)) {
   5925    // Not text, or not suppressed due to being all-whitespace (if it were being
   5926    // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
   5927    // going to be reframed anyway.
   5928    return;
   5929  }
   5930  MOZ_ASSERT(!aContent->GetPrimaryFrame(),
   5931             "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
   5932  ContentInserted(aContent, InsertionKind::Async);
   5933 }
   5934 
   5935 #ifdef DEBUG
   5936 void nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(
   5937    nsIContent* aParent) {
   5938  // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
   5939  // we want to assert, but leaf frames that process their own children and may
   5940  // ignore anonymous children (eg framesets) make this complicated. So we set
   5941  // these two booleans if we encounter these situations and unset them if we
   5942  // hit a node with a leaf frame.
   5943  //
   5944  // It's fine if one of node without primary frame is in a display:none
   5945  // subtree.
   5946  //
   5947  // Also, it's fine if one of the nodes without primary frame is a display:
   5948  // contents node.
   5949  bool noPrimaryFrame = false;
   5950  bool needsFrameBitSet = false;
   5951  nsIContent* content = aParent;
   5952  while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
   5953    if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
   5954      noPrimaryFrame = needsFrameBitSet = false;
   5955    }
   5956    if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
   5957      noPrimaryFrame = !IsDisplayContents(content);
   5958    }
   5959    if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
   5960      needsFrameBitSet = true;
   5961    }
   5962 
   5963    content = content->GetFlattenedTreeParent();
   5964  }
   5965  if (content && content->GetPrimaryFrame() &&
   5966      content->GetPrimaryFrame()->IsLeaf()) {
   5967    noPrimaryFrame = needsFrameBitSet = false;
   5968  }
   5969  MOZ_ASSERT(!noPrimaryFrame,
   5970             "Ancestors of nodes with frames to be "
   5971             "constructed lazily should have frames");
   5972  MOZ_ASSERT(!needsFrameBitSet,
   5973             "Ancestors of nodes with frames to be "
   5974             "constructed lazily should not have NEEDS_FRAME bit set");
   5975 }
   5976 #endif
   5977 
   5978 // Returns true if this operation can be lazy, false if not.
   5979 //
   5980 // NOTE(emilio): This function assumes that the flattened tree
   5981 // parent of all the appended children is the same, which holds because this
   5982 // gets called after GetRangeInsertionPoint which notifies individually.
   5983 void nsCSSFrameConstructor::ConstructLazily(nsIContent* aStartChild,
   5984                                            nsIContent* aEndChild) {
   5985  MOZ_ASSERT(aStartChild->GetParent());
   5986 
   5987  // We can construct lazily; just need to set suitable bits in the content
   5988  // tree.
   5989  Element* parent = aStartChild->GetFlattenedTreeParentElement();
   5990  if (!parent) {
   5991    // Not part of the flat tree, nothing to do.
   5992    return;
   5993  }
   5994 
   5995  if (Servo_Element_IsDisplayNone(parent)) {
   5996    // Nothing to do either.
   5997    //
   5998    // FIXME(emilio): This should be an assert, except for weird <frameset>
   5999    // stuff that does its own frame construction. Such an assert would fire in
   6000    // layout/style/crashtests/1411478.html, for example.
   6001    return;
   6002  }
   6003 
   6004  // Set NODE_NEEDS_FRAME on the new nodes.
   6005  for (nsIContent* child = aStartChild; child != aEndChild;
   6006       child = child->GetNextSibling()) {
   6007    NS_ASSERTION(!child->GetPrimaryFrame() ||
   6008                     child->GetPrimaryFrame()->GetContent() != child,
   6009                 // XXX the child->GetPrimaryFrame()->GetContent() != child
   6010                 // check is needed due to bug 135040. Remove it once that's
   6011                 // fixed.
   6012                 "setting NEEDS_FRAME on a node that already has a frame?");
   6013    child->SetFlags(NODE_NEEDS_FRAME);
   6014  }
   6015 
   6016  CheckBitsForLazyFrameConstruction(parent);
   6017  parent->NoteDescendantsNeedFramesForServo();
   6018 }
   6019 
   6020 void nsCSSFrameConstructor::IssueSingleInsertNofications(
   6021    nsIContent* aStartChild, nsIContent* aEndChild,
   6022    InsertionKind aInsertionKind) {
   6023  for (nsIContent* child = aStartChild; child != aEndChild;
   6024       child = child->GetNextSibling()) {
   6025    // XXX the GetContent() != child check is needed due to bug 135040.
   6026    // Remove it once that's fixed.
   6027    MOZ_ASSERT(!child->GetPrimaryFrame() ||
   6028               child->GetPrimaryFrame()->GetContent() != child);
   6029 
   6030    // Call ContentRangeInserted with this node.
   6031    ContentRangeInserted(child, child->GetNextSibling(), aInsertionKind);
   6032  }
   6033 }
   6034 
   6035 nsCSSFrameConstructor::InsertionPoint
   6036 nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
   6037                                              nsIContent* aEndChild,
   6038                                              InsertionKind aInsertionKind) {
   6039  MOZ_ASSERT(aStartChild);
   6040  MOZ_ASSERT(aStartChild->GetParentNode());
   6041 
   6042  // If the children of the container may be distributed to different insertion
   6043  // points, insert them separately and bail out, letting ContentInserted handle
   6044  // the mess.
   6045  if (aStartChild->GetParentNode()->GetShadowRoot()) {
   6046    IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
   6047    return {};
   6048  }
   6049 
   6050 #ifdef DEBUG
   6051  {
   6052    nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
   6053    for (nsIContent* child = aStartChild->GetNextSibling(); child;
   6054         child = child->GetNextSibling()) {
   6055      MOZ_ASSERT(child->GetFlattenedTreeParent() == expectedParent);
   6056    }
   6057  }
   6058 #endif
   6059 
   6060  // Now the flattened tree parent of all the siblings is the same, just use the
   6061  // same insertion point.
   6062  return GetInsertionPoint(aStartChild);
   6063 }
   6064 
   6065 bool nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
   6066                                                     nsIContent* aStartChild,
   6067                                                     nsIContent* aEndChild) {
   6068  if (aParentFrame->IsFrameSetFrame()) {
   6069    // Check whether we have any kids we care about.
   6070    for (nsIContent* cur = aStartChild; cur != aEndChild;
   6071         cur = cur->GetNextSibling()) {
   6072      if (IsSpecialFramesetChild(cur)) {
   6073        // Just reframe the parent, since framesets are weird like that.
   6074        RecreateFramesForContent(aParentFrame->GetContent(),
   6075                                 InsertionKind::Async);
   6076        return true;
   6077      }
   6078    }
   6079  }
   6080  return false;
   6081 }
   6082 
   6083 void nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
   6084                                                     nsIContent* aEndChild) {
   6085  for (nsIContent* child = aStartChild; child != aEndChild;
   6086       child = child->GetNextSibling()) {
   6087    if (child->IsElement()) {
   6088      child->AsElement()->NoteDirtyForServo();
   6089    }
   6090  }
   6091 }
   6092 
   6093 #ifdef DEBUG
   6094 static bool IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild) {
   6095  FlattenedChildIterator iter(aParent);
   6096  for (nsIContent* node = iter.GetNextChild(); node;
   6097       node = iter.GetNextChild()) {
   6098    if (node == aChild) {
   6099      return true;
   6100    }
   6101  }
   6102  return false;
   6103 }
   6104 #endif
   6105 
   6106 void nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
   6107                                               nsIContent* aEndChild) {
   6108  ServoStyleSet* styleSet = mPresShell->StyleSet();
   6109 
   6110  for (nsIContent* child = aStartChild; child != aEndChild;
   6111       child = child->GetNextSibling()) {
   6112    if (!child->IsElement()) {
   6113      continue;
   6114    }
   6115 
   6116    Element* childElement = child->AsElement();
   6117 
   6118    // We only come in here from non-lazy frame construction, so the children
   6119    // should be unstyled.
   6120    MOZ_ASSERT(!childElement->HasServoData());
   6121 
   6122 #ifdef DEBUG
   6123    {
   6124      // Furthermore, all of them should have the same flattened tree parent
   6125      // (GetRangeInsertionPoint ensures it). And that parent should be styled,
   6126      // otherwise we would've never found an insertion point at all.
   6127      Element* parent = childElement->GetFlattenedTreeParentElement();
   6128      MOZ_ASSERT(parent);
   6129      MOZ_ASSERT(parent->HasServoData());
   6130      MOZ_ASSERT(
   6131          IsFlattenedTreeChild(parent, child),
   6132          "GetFlattenedTreeParent and ChildIterator don't agree, fix this!");
   6133    }
   6134 #endif
   6135 
   6136    styleSet->StyleNewSubtree(childElement);
   6137  }
   6138 }
   6139 
   6140 // This is a bit slow, but sometimes we need it.
   6141 static bool ParentIsWrapperAnonBox(nsIFrame* aParent) {
   6142  nsIFrame* maybeAnonBox = aParent;
   6143  if (maybeAnonBox->Style()->GetPseudoType() == PseudoStyleType::cellContent) {
   6144    // The thing that would maybe be a wrapper anon box is the cell.
   6145    maybeAnonBox = maybeAnonBox->GetParent();
   6146  }
   6147  return maybeAnonBox->Style()->IsWrapperAnonBox();
   6148 }
   6149 
   6150 void nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
   6151                                            InsertionKind aInsertionKind) {
   6152  return ContentRangeInserted(aFirstNewContent, nullptr, aInsertionKind);
   6153 }
   6154 
   6155 void nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
   6156                                            InsertionKind aInsertionKind) {
   6157  ContentRangeInserted(aChild, aChild->GetNextSibling(), aInsertionKind);
   6158 }
   6159 
   6160 // It's very likely that we don't have any existing captions (because we only
   6161 // render one of them, see bug 144517). We also don't fragment table captions.
   6162 // So, prefer just walking the existing captions and searching it, rather than
   6163 // adding a special GetInsertionPrevSibling() version that skips everything but
   6164 // table captions.
   6165 static nsIFrame* FindCaptionPrevSibling(nsTableWrapperFrame* aTable,
   6166                                        nsIContent* aCaptionContent) {
   6167  nsIFrame* prevSibling = aTable->InnerTableFrame();
   6168  if (nsIFrame* firstCaption = prevSibling->GetNextSibling()) {
   6169    nsContentUtils::NodeIndexCache cache;
   6170    for (auto* caption = firstCaption; caption;
   6171         caption = caption->GetNextSibling()) {
   6172      if (nsContentUtils::CompareTreePosition<TreeKind::Flat>(
   6173              caption->GetContent(), aCaptionContent, nullptr, &cache) >= 0) {
   6174        break;
   6175      }
   6176      prevSibling = caption;
   6177    }
   6178  }
   6179  return prevSibling;
   6180 }
   6181 
   6182 // ContentRangeInserted handles creating frames for a range of nodes that
   6183 // might not be at the end of their childlist. ContentRangeInserted isn't a real
   6184 // content notification, but rather it handles regular ContentInserted calls
   6185 // for a single node as well as the lazy construction of frames for a range of
   6186 // nodes when called from CreateNeededFrames. For a range of nodes to be
   6187 // suitable to have its frames constructed all at once they must meet the same
   6188 // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
   6189 // these), plus more.
   6190 void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
   6191                                                 nsIContent* aEndChild,
   6192                                                 InsertionKind aInsertionKind) {
   6193  AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentRangeInserted",
   6194                          LAYOUT_FrameConstruction);
   6195  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   6196 
   6197  MOZ_ASSERT(aStartChild, "must always pass a child");
   6198 
   6199 #ifdef DEBUG
   6200  if (gNoisyContentUpdates) {
   6201    printf(
   6202        "nsCSSFrameConstructor::ContentRangeInserted container=%p "
   6203        "start-child=%p end-child=%p lazy=%d\n",
   6204        aStartChild->GetParent(), aStartChild, aEndChild,
   6205        aInsertionKind == InsertionKind::Async);
   6206    if (gReallyNoisyContentUpdates) {
   6207      if (aStartChild->GetParent()) {
   6208        aStartChild->GetParent()->List(stdout, 0);
   6209      } else {
   6210        aStartChild->List(stdout, 0);
   6211      }
   6212    }
   6213  }
   6214 
   6215  for (nsIContent* child = aStartChild; child != aEndChild;
   6216       child = child->GetNextSibling()) {
   6217    // XXX the GetContent() != child check is needed due to bug 135040.
   6218    // Remove it once that's fixed.
   6219    MOZ_ASSERT(
   6220        !child->GetPrimaryFrame() ||
   6221            child->GetPrimaryFrame()->GetContent() != child,
   6222        "asked to construct a frame for a node that already has a frame");
   6223  }
   6224 #endif
   6225 
   6226  // If we have a null parent, then this must be the document element being
   6227  // inserted, or some other child of the document in the DOM (might be a
   6228  // processing instruction or comment).
   6229  if (!aStartChild->GetParent()) {
   6230    Element* docElement = mDocument->GetRootElement();
   6231    const bool foundRoot = [&] {
   6232      for (nsIContent* cur = aStartChild; cur != aEndChild;
   6233           cur = cur->GetNextSibling()) {
   6234        if (cur == docElement) {
   6235          return true;
   6236        }
   6237      }
   6238      return false;
   6239    }();
   6240 
   6241    if (!foundRoot) {
   6242      // Not the root element (could be e.g. a comment), just bail out
   6243      return;
   6244    }
   6245 
   6246    MOZ_ASSERT(!mRootElementFrame, "root element frame already created");
   6247    if (aInsertionKind == InsertionKind::Async) {
   6248      docElement->SetFlags(NODE_NEEDS_FRAME);
   6249      LazilyStyleNewChildRange(docElement, nullptr);
   6250      return;
   6251    }
   6252 
   6253    // Create frames for the document element and its child elements
   6254    if (ConstructDocElementFrame(docElement)) {
   6255      InvalidateCanvasIfNeeded(mPresShell, docElement);
   6256 #ifdef DEBUG
   6257      if (gReallyNoisyContentUpdates) {
   6258        printf(
   6259            "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
   6260            "model:\n");
   6261        mRootElementFrame->List(stdout);
   6262      }
   6263 #endif
   6264    }
   6265 
   6266 #ifdef ACCESSIBILITY
   6267    if (nsAccessibilityService* accService = GetAccService()) {
   6268      accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
   6269    }
   6270 #endif
   6271    return;
   6272  }
   6273 
   6274  const bool isSingleInsert = aStartChild->GetNextSibling() == aEndChild;
   6275  InsertionPoint insertion;
   6276  if (isSingleInsert) {
   6277    // See if we have a Shadow DOM insertion point. If so, then that's our real
   6278    // parent frame; if not, then the frame hasn't been built yet and we just
   6279    // bail.
   6280    insertion = GetInsertionPoint(aStartChild);
   6281  } else {
   6282    // Get our insertion point. If we need to issue single ContentInserteds
   6283    // GetRangeInsertionPoint will take care of that for us.
   6284    LAYOUT_PHASE_TEMP_EXIT();
   6285    insertion = GetRangeInsertionPoint(aStartChild, aEndChild, aInsertionKind);
   6286    LAYOUT_PHASE_TEMP_REENTER();
   6287  }
   6288 
   6289  if (!insertion.mParentFrame) {
   6290    // We're punting on frame construction because there's no container frame.
   6291    // The Servo-backed style system handles this case like the lazy frame
   6292    // construction case, except when we're already constructing frames, in
   6293    // which case we shouldn't need to do anything else.
   6294    if (aInsertionKind == InsertionKind::Async) {
   6295      LazilyStyleNewChildRange(aStartChild, aEndChild);
   6296    }
   6297    return;
   6298  }
   6299 
   6300  if (aInsertionKind == InsertionKind::Async) {
   6301    ConstructLazily(aStartChild, aEndChild);
   6302    LazilyStyleNewChildRange(aStartChild, aEndChild);
   6303    return;
   6304  }
   6305 
   6306  bool isAppend;
   6307  nsIFrame* prevSibling =
   6308      GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
   6309 
   6310  LayoutFrameType frameType = insertion.mParentFrame->Type();
   6311  LAYOUT_PHASE_TEMP_EXIT();
   6312  if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild,
   6313                               aEndChild)) {
   6314    LAYOUT_PHASE_TEMP_REENTER();
   6315    return;
   6316  }
   6317  LAYOUT_PHASE_TEMP_REENTER();
   6318 
   6319  // Don't construct kids of leaves
   6320  if (insertion.mParentFrame->IsLeaf()) {
   6321    // Clear lazy bits so we don't try to construct again.
   6322    ClearLazyBits(aStartChild, aEndChild);
   6323    return;
   6324  }
   6325 
   6326  LAYOUT_PHASE_TEMP_EXIT();
   6327  if (WipeInsertionParent(insertion.mParentFrame)) {
   6328    LAYOUT_PHASE_TEMP_REENTER();
   6329    return;
   6330  }
   6331  LAYOUT_PHASE_TEMP_REENTER();
   6332 
   6333  nsFrameConstructorState state(
   6334      mPresShell, GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
   6335      GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
   6336      GetFloatContainingBlock(insertion.mParentFrame),
   6337      do_AddRef(mFrameTreeState));
   6338 
   6339  // Recover state for the containing block - we need to know if
   6340  // it has :first-letter or :first-line style applied to it. The
   6341  // reason we care is that the internal structure in these cases
   6342  // is not the normal structure and requires custom updating
   6343  // logic.
   6344  nsContainerFrame* containingBlock = state.mFloatedList.mContainingBlock;
   6345  bool haveFirstLetterStyle = false;
   6346  bool haveFirstLineStyle = false;
   6347 
   6348  // In order to shave off some cycles, we only dig up the
   6349  // containing block haveFirst* flags if the parent frame where
   6350  // the insertion/append is occurring is an inline or block
   6351  // container. For other types of containers this isn't relevant.
   6352  StyleDisplayInside parentDisplayInside =
   6353      insertion.mParentFrame->StyleDisplay()->DisplayInside();
   6354 
   6355  // Examine the insertion.mParentFrame where the insertion is taking
   6356  // place. If it's a certain kind of container then some special
   6357  // processing is done.
   6358  if (StyleDisplayInside::Flow == parentDisplayInside) {
   6359    // Recover the special style flags for the containing block
   6360    if (containingBlock) {
   6361      haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
   6362      haveFirstLineStyle = ShouldHaveFirstLineStyle(
   6363          containingBlock->GetContent(), containingBlock->Style());
   6364    }
   6365 
   6366    if (haveFirstLetterStyle) {
   6367      // If our current insertion.mParentFrame is a Letter frame, use its parent
   6368      // as our new parent hint
   6369      if (insertion.mParentFrame->IsLetterFrame()) {
   6370        // If insertion.mParentFrame is out of flow, then we actually want the
   6371        // parent of the placeholder frame.
   6372        if (insertion.mParentFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
   6373          nsPlaceholderFrame* placeholderFrame =
   6374              insertion.mParentFrame->GetPlaceholderFrame();
   6375          NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
   6376          insertion.mParentFrame = placeholderFrame->GetParent();
   6377        } else {
   6378          insertion.mParentFrame = insertion.mParentFrame->GetParent();
   6379        }
   6380      }
   6381 
   6382      // Remove the old letter frames before doing the insertion
   6383      RemoveLetterFrames(mPresShell, state.mFloatedList.mContainingBlock);
   6384 
   6385      // Removing the letterframes messes around with the frame tree, removing
   6386      // and creating frames.  We need to reget our prevsibling, parent frame,
   6387      // etc.
   6388      prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
   6389      frameType = insertion.mParentFrame->Type();
   6390    }
   6391  }
   6392 
   6393  // This handles fallback to 'list-style-type' when a 'list-style-image' fails
   6394  // to load.
   6395  if (aStartChild->IsInNativeAnonymousSubtree() &&
   6396      aStartChild->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
   6397    MOZ_ASSERT(isSingleInsert);
   6398    MOZ_ASSERT(insertion.mParentFrame->Style()->GetPseudoType() ==
   6399                   PseudoStyleType::marker,
   6400               "we can only handle ::marker fallback for now");
   6401    nsIContent* const nextSibling = aStartChild->GetNextSibling();
   6402    MOZ_ASSERT(nextSibling && nextSibling->IsText(),
   6403               "expected a text node after the list-style-image image");
   6404    DestroyContext context(mPresShell);
   6405    RemoveFrame(context, FrameChildListID::Principal,
   6406                nextSibling->GetPrimaryFrame());
   6407    auto* const container = aStartChild->GetParent()->AsElement();
   6408    nsIContent* firstNewChild = nullptr;
   6409    auto InsertChild = [this, container, nextSibling,
   6410                        &firstNewChild](RefPtr<nsIContent>&& aChild) {
   6411      // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
   6412      // here; it would get set under AppendChildTo.  But AppendChildTo might
   6413      // think that we're going from not being anonymous to being anonymous and
   6414      // do some extra work; setting the flag here avoids that.
   6415      aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
   6416      container->InsertChildBefore(aChild, nextSibling, false, IgnoreErrors());
   6417      if (auto* childElement = Element::FromNode(aChild)) {
   6418        // If we created any children elements, Servo needs to traverse them,
   6419        // but the root is already set up.
   6420        mPresShell->StyleSet()->StyleNewSubtree(childElement);
   6421      }
   6422      if (!firstNewChild) {
   6423        firstNewChild = aChild;
   6424      }
   6425    };
   6426    CreateGeneratedContentFromListStyleType(
   6427        state, *insertion.mContainer->AsElement(),
   6428        *insertion.mParentFrame->Style(), InsertChild);
   6429    if (!firstNewChild) {
   6430      // No fallback content - we're done.
   6431      return;
   6432    }
   6433    aStartChild = firstNewChild;
   6434    MOZ_ASSERT(firstNewChild->GetNextSibling() == nextSibling,
   6435               "list-style-type should only create one child");
   6436  }
   6437 
   6438  AutoFrameConstructionItemList items(this);
   6439  RefPtr<ComputedStyle> parentStyle =
   6440      ResolveComputedStyle(insertion.mContainer);
   6441  ParentType parentType = GetParentType(frameType);
   6442  FlattenedChildIterator iter(insertion.mContainer);
   6443  const bool haveNoShadowDOM =
   6444      !iter.ShadowDOMInvolved() || !iter.GetNextChild();
   6445  if (aStartChild->GetPreviousSibling() && parentType == eTypeBlock &&
   6446      haveNoShadowDOM) {
   6447    // If there's a text node in the normal content list just before the
   6448    // new nodes, and it has no frame, make a frame construction item for
   6449    // it, because it might need a frame now.  No need to do this if our
   6450    // parent type is not block, though, since WipeContainingBlock
   6451    // already handles that situation.
   6452    AddTextItemIfNeeded(state, *parentStyle, insertion,
   6453                        aStartChild->GetPreviousSibling(), items);
   6454  }
   6455 
   6456  const bool suppressWhiteSpaceOptimizations =
   6457      isSingleInsert && aStartChild->IsRootOfNativeAnonymousSubtree();
   6458  for (nsIContent* child = aStartChild; child != aEndChild;
   6459       child = child->GetNextSibling()) {
   6460    AddFrameConstructionItems(state, child, suppressWhiteSpaceOptimizations,
   6461                              *parentStyle, insertion, items);
   6462  }
   6463 
   6464  if (aEndChild && parentType == eTypeBlock && haveNoShadowDOM) {
   6465    // If there's a text node in the normal content list just after the
   6466    // new nodes, and it has no frame, make a frame construction item for
   6467    // it, because it might need a frame now.  No need to do this if our
   6468    // parent type is not block, though, since WipeContainingBlock
   6469    // already handles that situation.
   6470    AddTextItemIfNeeded(state, *parentStyle, insertion, aEndChild, items);
   6471  }
   6472 
   6473  // Perform special check for diddling around with the frames in a special
   6474  // inline frame. If we're appending before :after content, then we're not
   6475  // really appending, so let WipeContainingBlock know that.
   6476  LAYOUT_PHASE_TEMP_EXIT();
   6477  if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
   6478                          isAppend, prevSibling)) {
   6479    LAYOUT_PHASE_TEMP_REENTER();
   6480    return;
   6481  }
   6482  LAYOUT_PHASE_TEMP_REENTER();
   6483 
   6484  // If the parent is a block frame, and we're not in a special case
   6485  // where frames can be moved around, determine if the list is for the
   6486  // start or end of the block.
   6487  if (insertion.mParentFrame->IsBlockFrameOrSubclass() &&
   6488      !haveFirstLetterStyle && !haveFirstLineStyle &&
   6489      !IsFramePartOfIBSplit(insertion.mParentFrame)) {
   6490    items.SetLineBoundaryAtStart(!prevSibling ||
   6491                                 !prevSibling->IsInlineOutside() ||
   6492                                 prevSibling->IsBrFrame());
   6493    auto* nextSibling =
   6494        ::GetInsertNextSibling(insertion.mParentFrame, prevSibling);
   6495    items.SetLineBoundaryAtEnd(!nextSibling ||
   6496                               !nextSibling->IsInlineOutside() ||
   6497                               nextSibling->IsBrFrame());
   6498  }
   6499  // To suppress whitespace-only text frames, we have to verify that
   6500  // our container's DOM child list matches its flattened tree child list.
   6501  items.SetParentHasNoShadowDOM(haveNoShadowDOM);
   6502 
   6503  nsFrameConstructorSaveState floatSaveState;
   6504  state.MaybePushFloatContainingBlock(insertion.mParentFrame, floatSaveState);
   6505 
   6506  if (state.mPresContext->IsPaginated()) {
   6507    // Because this function can be called outside frame construction, we need
   6508    // to set state.mAutoPageNameValue based on what the parent frame's auto
   6509    // value is.
   6510    // Calling this from outside the frame constructor can violate many of the
   6511    // expectations in AutoFrameConstructionPageName, and unlike during frame
   6512    // construction we already have an auto value from parentFrame, so we do
   6513    // not use AutoFrameConstructionPageName here.
   6514    state.mAutoPageNameValue = insertion.mParentFrame->GetAutoPageValue();
   6515 #ifdef DEBUG
   6516    insertion.mParentFrame->mWasVisitedByAutoFrameConstructionPageName = true;
   6517 #endif
   6518  }
   6519 
   6520  // If the container is a table and a caption will be appended, it needs to be
   6521  // put in the table wrapper frame's additional child list.
   6522  // We make no attempt here to set flags to indicate whether the list
   6523  // will be at the start or end of a block. It doesn't seem worthwhile.
   6524  nsFrameList frameList, captionList;
   6525  ConstructFramesFromItemList(state, items, insertion.mParentFrame,
   6526                              ParentIsWrapperAnonBox(insertion.mParentFrame),
   6527                              frameList);
   6528 
   6529  if (frameList.NotEmpty()) {
   6530    for (nsIContent* child = aStartChild; child != aEndChild;
   6531         child = child->GetNextSibling()) {
   6532      InvalidateCanvasIfNeeded(mPresShell, child);
   6533    }
   6534 
   6535    if (LayoutFrameType::Table == frameType ||
   6536        LayoutFrameType::TableWrapper == frameType) {
   6537      PullOutCaptionFrames(frameList, captionList);
   6538      if (prevSibling && prevSibling->IsTableCaption()) {
   6539        // This can happen, but only if the table is empty (otherwise
   6540        // SafeToInsertPseudoNeedingChildren bails).
   6541        prevSibling = nullptr;
   6542      }
   6543    }
   6544  }
   6545 
   6546  if (haveFirstLineStyle && insertion.mParentFrame == containingBlock &&
   6547      isAppend) {
   6548    // It's possible that the new frame goes into a first-line
   6549    // frame. Look at it and see...
   6550    AppendFirstLineFrames(state, containingBlock->GetContent(), containingBlock,
   6551                          frameList);
   6552  } else if (insertion.mParentFrame->Style()->IsInFirstLineSubtree()) {
   6553    CheckForFirstLineInsertion(insertion.mParentFrame, frameList);
   6554    CheckForFirstLineInsertion(insertion.mParentFrame, captionList);
   6555  }
   6556 
   6557  // We might have captions; put them into the principal child list of the table
   6558  // wrapper frame.
   6559  if (captionList.NotEmpty()) {
   6560    NS_ASSERTION(LayoutFrameType::Table == frameType ||
   6561                     LayoutFrameType::TableWrapper == frameType,
   6562                 "parent for caption is not table?");
   6563    // We need to determine where to put the caption items; start with the
   6564    // the parent frame that has already been determined and get the insertion
   6565    // prevsibling of the first caption item.
   6566    nsContainerFrame* outerTable = insertion.mParentFrame->IsTableFrame()
   6567                                       ? insertion.mParentFrame->GetParent()
   6568                                       : insertion.mParentFrame;
   6569 
   6570    // If the parent is not a table wrapper frame we will try to add frames
   6571    // to a named child list that the parent does not honor and the frames
   6572    // will get lost.
   6573    MOZ_ASSERT(outerTable->IsTableWrapperFrame(),
   6574               "Pseudo frame construction failure; "
   6575               "a caption can be only a child of a table wrapper frame");
   6576 
   6577    nsIFrame* captionPrevSibling =
   6578        FindCaptionPrevSibling(static_cast<nsTableWrapperFrame*>(outerTable),
   6579                               captionList.FirstChild()->GetContent());
   6580    captionList.ApplySetParent(outerTable);
   6581    if (!captionPrevSibling->GetNextSibling()) {
   6582      AppendFrames(outerTable, FrameChildListID::Principal,
   6583                   std::move(captionList));
   6584    } else {
   6585      InsertFrames(outerTable, FrameChildListID::Principal, captionPrevSibling,
   6586                   std::move(captionList));
   6587    }
   6588  }
   6589 
   6590  LAYOUT_PHASE_TEMP_EXIT();
   6591  if (MaybeRecreateForColumnSpan(state, insertion.mParentFrame, frameList,
   6592                                 prevSibling)) {
   6593    LAYOUT_PHASE_TEMP_REENTER();
   6594    return;
   6595  }
   6596  LAYOUT_PHASE_TEMP_REENTER();
   6597 
   6598  if (frameList.NotEmpty()) {
   6599    // Notify the parent frame
   6600    if (isAppend) {
   6601      AppendFramesToParent(state, insertion.mParentFrame, frameList,
   6602                           prevSibling);
   6603    } else {
   6604      InsertFrames(insertion.mParentFrame, FrameChildListID::Principal,
   6605                   prevSibling, std::move(frameList));
   6606    }
   6607  }
   6608 
   6609  if (haveFirstLetterStyle) {
   6610    // Recover the letter frames for the containing block when
   6611    // it has first-letter style.
   6612    RecoverLetterFrames(state.mFloatedList.mContainingBlock);
   6613  }
   6614 
   6615 #ifdef DEBUG
   6616  if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
   6617    printf(
   6618        "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
   6619        "model:\n");
   6620    insertion.mParentFrame->List(stdout);
   6621  }
   6622 #endif
   6623 
   6624 #ifdef ACCESSIBILITY
   6625  if (nsAccessibilityService* accService = GetAccService()) {
   6626    accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
   6627  }
   6628 #endif
   6629 }
   6630 
   6631 static bool IsWhitespaceFrame(const nsIFrame* aFrame) {
   6632  MOZ_ASSERT(aFrame, "invalid argument");
   6633  return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
   6634 }
   6635 
   6636 static bool IsSyntheticColGroup(const nsIFrame* aFrame) {
   6637  return aFrame->IsTableColGroupFrame() &&
   6638         static_cast<const nsTableColGroupFrame*>(aFrame)->IsSynthetic();
   6639 }
   6640 
   6641 static bool IsOnlyNonWhitespaceFrameInList(
   6642    const nsFrameList& aFrameList, const nsIFrame* aFrame,
   6643    const nsIFrame* aIgnoreFrame = nullptr) {
   6644  for (const nsIFrame* f : aFrameList) {
   6645    if (f == aIgnoreFrame) {
   6646      continue;
   6647    }
   6648    if (f == aFrame) {
   6649      // If we have continuations, ignore them too.
   6650      aFrame = aFrame->GetNextContinuation();
   6651    } else if (!IsWhitespaceFrame(f) && !IsSyntheticColGroup(f)) {
   6652      // Synthetic colgroups get created unconditionally, so let's not consider
   6653      // them as giving us a non-whitespace frame.
   6654      return false;
   6655    }
   6656  }
   6657  return true;
   6658 }
   6659 
   6660 static bool AllChildListsAreEffectivelyEmpty(nsIFrame* aFrame) {
   6661  for (auto& [list, listID] : aFrame->ChildLists()) {
   6662    if (list.IsEmpty()) {
   6663      continue;
   6664    }
   6665    // We have some existing frame, usually that would be considered as making
   6666    // this list nonempty. But let's make an exception for the synthetic
   6667    // colgroup that tables have, since that gets created unconditionally.
   6668    if (listID == FrameChildListID::ColGroup) {
   6669      if (nsIFrame* f = list.OnlyChild(); f && IsSyntheticColGroup(f)) {
   6670        continue;
   6671      }
   6672    }
   6673    return false;
   6674  }
   6675  return true;
   6676 }
   6677 
   6678 static bool SafeToInsertPseudoNeedingChildren(nsIFrame* aFrame) {
   6679  return AllChildListsAreEffectivelyEmpty(aFrame);
   6680 }
   6681 
   6682 // Returns true if aFrame is the only meaningful child of aParent (which is
   6683 // known to be a wrapper-pseudo). This lets us determine whether aParent can be
   6684 // removed, as a result of aFrame being removed.
   6685 static bool IsOnlyMeaningfulChildOfWrapperPseudo(nsIFrame* aFrame,
   6686                                                 nsIFrame* aParent) {
   6687  MOZ_ASSERT(IsWrapperPseudo(aParent));
   6688  // Handle a few special cases with tables and colgroups / captions.
   6689  if (aParent->IsTableFrame()) {
   6690    auto* wrapper = aParent->GetParent();
   6691    MOZ_ASSERT(wrapper);
   6692    MOZ_ASSERT(wrapper->IsTableWrapperFrame());
   6693    MOZ_ASSERT(!aFrame->IsTableCaption(),
   6694               "Caption parent should be the wrapper");
   6695    // We can't remove the table if there are any captions present (captions are
   6696    // never anonymous themselves), because table wrapper always relies on
   6697    // having a table frame.
   6698    if (!wrapper->PrincipalChildList().OnlyChild()) {
   6699      return false;
   6700    }
   6701    // Similarly we can't remove the table if there's still a non-anonymous col
   6702    // group (unless aFrame _is_ the non-anonymous colgroup).
   6703    if (aFrame->IsTableColGroupFrame()) {
   6704      return aParent->PrincipalChildList().IsEmpty() &&
   6705             IsOnlyNonWhitespaceFrameInList(
   6706                 aParent->GetChildList(FrameChildListID::ColGroup), aFrame);
   6707    }
   6708    const auto& colGroupList =
   6709        aParent->GetChildList(FrameChildListID::ColGroup);
   6710    if (!colGroupList.IsEmpty()) {
   6711      nsIFrame* f = colGroupList.OnlyChild();
   6712      if (!f || !IsSyntheticColGroup(f)) {
   6713        return false;
   6714      }
   6715    }
   6716  }
   6717  if (aFrame->IsTableCaption()) {
   6718    MOZ_ASSERT(aParent->IsTableWrapperFrame());
   6719    auto* table = static_cast<nsTableWrapperFrame*>(aParent)->InnerTableFrame();
   6720    MOZ_ASSERT(table);
   6721    return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame,
   6722                                          /* aIgnoreFrame = */ table) &&
   6723           // This checks for both colgroups and the principal list of the table
   6724           // frame.
   6725           AllChildListsAreEffectivelyEmpty(table);
   6726  }
   6727  MOZ_ASSERT(!aFrame->IsTableColGroupFrame());
   6728  return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame);
   6729 }
   6730 
   6731 static bool CanRemoveWrapperPseudoForChildRemoval(nsIFrame* aFrame,
   6732                                                  nsIFrame* aParent) {
   6733  if (!IsOnlyMeaningfulChildOfWrapperPseudo(aFrame, aParent)) {
   6734    return false;
   6735  }
   6736  if (aParent->IsRubyBaseContainerFrame()) {
   6737    // We can't remove the first ruby base container of a ruby frame unless
   6738    // it has no siblings. See CreateNeededPseudoSiblings.
   6739    return aParent->GetPrevSibling() || !aParent->GetNextSibling();
   6740  }
   6741  return true;
   6742 }
   6743 
   6744 bool nsCSSFrameConstructor::ContentWillBeRemoved(nsIContent* aChild,
   6745                                                 RemovalKind aKind) {
   6746  MOZ_ASSERT(aChild);
   6747  MOZ_ASSERT(
   6748      !aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling(),
   6749      "Anonymous roots don't have siblings");
   6750  AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentWillBeRemoved",
   6751                          LAYOUT_FrameConstruction);
   6752  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   6753  nsPresContext* presContext = mPresShell->GetPresContext();
   6754  MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
   6755 
   6756  const bool wasRemovingContent = mRemovingContent;
   6757  auto _ = MakeScopeExit([&] { mRemovingContent = wasRemovingContent; });
   6758  mRemovingContent = true;
   6759 
   6760  // We want to detect when the viewport override element stored in the
   6761  // prescontext is in the subtree being removed.  Except in fullscreen cases
   6762  // (which are handled in Element::UnbindFromTree and do not get stored on the
   6763  // prescontext), the override element is always either the root element or a
   6764  // <body> child of the root element.  So we can only be removing the stored
   6765  // override element if the thing being removed is either the override element
   6766  // itself or the root element (which can be a parent of the override element).
   6767  //
   6768  // The !wasRemovingContent check makes sure that we don't re-enter here from
   6769  // other ContentWillBeRemoved calls, as that'd be useless work, and we don't
   6770  // want to incorrectly pick aChild again as our viewport scroll style element
   6771  // if it's getting removed from the DOM.
   6772  if ((aChild == presContext->GetViewportScrollStylesOverrideElement() ||
   6773       aChild->IsRootElement()) &&
   6774      !wasRemovingContent) {
   6775    // We might be removing the element that we propagated viewport scrollbar
   6776    // styles from.  Recompute those. (This clause covers two of the three
   6777    // possible scrollbar-propagation sources: the <body> [as aChild or a
   6778    // descendant] and the root node. The other possible scrollbar-propagation
   6779    // source is a fullscreen element, and we have code elsewhere to update
   6780    // scrollbars after fullscreen elements are removed -- specifically, it's
   6781    // part of the fullscreen cleanup code called by Element::UnbindFromTree.
   6782    // We don't handle the fullscreen case here, because it doesn't change the
   6783    // scrollbar styles override element stored on the prescontext.)
   6784    const Element* removingElement =
   6785        aKind == RemovalKind::Dom ? aChild->AsElement() : nullptr;
   6786    Element* newOverrideElement =
   6787        presContext->UpdateViewportScrollStylesOverride(removingElement);
   6788 
   6789    // If aChild is the root, then we don't need to do any reframing of
   6790    // newOverrideElement, because we're about to tear down the whole frame tree
   6791    // anyway.  And we need to make sure we don't do any such reframing, because
   6792    // reframing the <body> can trigger a reframe of the <html> and then reenter
   6793    // here.
   6794    //
   6795    // But if aChild is not the root, and if newOverrideElement is not the root
   6796    // and isn't aChild (which it could be if all we're doing here is reframing
   6797    // the current override element), it needs reframing.  In particular, it
   6798    // used to have a scrollframe (because its overflow was not "visible"), but
   6799    // now it will propagate its overflow to the viewport, so it should not need
   6800    // a scrollframe anymore.
   6801    if (aChild->GetParent() && newOverrideElement &&
   6802        newOverrideElement->GetParent() && newOverrideElement != aChild) {
   6803      LAYOUT_PHASE_TEMP_EXIT();
   6804      RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
   6805      LAYOUT_PHASE_TEMP_REENTER();
   6806    }
   6807  }
   6808 
   6809 #ifdef DEBUG
   6810  if (gNoisyContentUpdates) {
   6811    printf(
   6812        "nsCSSFrameConstructor::ContentWillBeRemoved container=%p child=%p\n",
   6813        aChild->GetParent(), aChild);
   6814    if (gReallyNoisyContentUpdates) {
   6815      aChild->GetParent()->List(stdout, 0);
   6816    }
   6817  }
   6818 #endif
   6819 
   6820  nsIFrame* childFrame = aChild->GetPrimaryFrame();
   6821  if (!childFrame || childFrame->GetContent() != aChild) {
   6822    // XXXbz the GetContent() != aChild check is needed due to bug 135040.
   6823    // Remove it once that's fixed.
   6824    childFrame = nullptr;
   6825  }
   6826 
   6827  // If we're removing the root, then make sure to remove things starting at
   6828  // the viewport's child instead of the primary frame (which might even be
   6829  // null if the root was display:none, even though the frames above it got
   6830  // created).  Detecting removal of a root is a little exciting; in particular,
   6831  // having no parent is necessary but NOT sufficient.
   6832  //
   6833  // Due to how we process reframes, the content node might not even be in our
   6834  // document by now.  So explicitly check whether the viewport's first kid's
   6835  // content node is aChild.
   6836  //
   6837  // FIXME(emilio): I think the "might not be in our document" bit is impossible
   6838  // now.
   6839  bool isRoot = false;
   6840  if (!aChild->GetParent()) {
   6841    if (nsIFrame* viewport = GetRootFrame()) {
   6842      nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
   6843      if (firstChild && firstChild->GetContent() == aChild) {
   6844        isRoot = true;
   6845        childFrame = firstChild;
   6846        NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
   6847      }
   6848    }
   6849  }
   6850 
   6851  // We need to be conservative about when to determine whether something has
   6852  // display: contents or not because at this point our actual display may be
   6853  // different.
   6854  //
   6855  // Consider the case of:
   6856  //
   6857  //   <div id="A" style="display: contents"><div id="B"></div></div>
   6858  //
   6859  // If we reconstruct A because its display changed to "none", we still need to
   6860  // cleanup the frame on B, but A's display is now "none", so we can't poke at
   6861  // the style of it.
   6862  //
   6863  // FIXME(emilio, bug 1450366): We can make this faster without adding much
   6864  // complexity for the display: none -> other case, which right now
   6865  // unnecessarily walks the content tree down.
   6866  auto CouldHaveBeenDisplayContents = [aKind](nsIContent* aContent) -> bool {
   6867    return aContent->IsElement() && (aKind != RemovalKind::Dom ||
   6868                                     IsDisplayContents(aContent->AsElement()));
   6869  };
   6870 
   6871  if (!childFrame) {
   6872    if (CouldHaveBeenDisplayContents(aChild)) {
   6873      // NOTE(emilio): We may iterate through ::before and ::after here and they
   6874      // may be gone after the respective ContentWillBeRemoved call. Right now
   6875      // StyleChildrenIterator handles that properly, so it's not an issue.
   6876      StyleChildrenIterator iter(aChild);
   6877      for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
   6878        if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(c)) {
   6879          LAYOUT_PHASE_TEMP_EXIT();
   6880          bool didReconstruct = ContentWillBeRemoved(c, aKind);
   6881          LAYOUT_PHASE_TEMP_REENTER();
   6882          if (didReconstruct) {
   6883            return true;
   6884          }
   6885        }
   6886      }
   6887    }
   6888    return false;
   6889  }
   6890 
   6891  if (aKind != RemovalKind::Dom) {
   6892    // Before removing the frames associated with the content object,
   6893    // ask them to save their state onto our state object.
   6894    CaptureStateForFramesOf(aChild, mFrameTreeState);
   6895  }
   6896 
   6897  InvalidateCanvasIfNeeded(mPresShell, aChild);
   6898 
   6899  // See whether we need to remove more than just childFrame
   6900  LAYOUT_PHASE_TEMP_EXIT();
   6901  if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
   6902    LAYOUT_PHASE_TEMP_REENTER();
   6903    return true;
   6904  }
   6905  LAYOUT_PHASE_TEMP_REENTER();
   6906 
   6907  // Get the childFrame's parent frame
   6908  nsIFrame* parentFrame = childFrame->GetParent();
   6909  LayoutFrameType parentType = parentFrame->Type();
   6910 
   6911  if (parentType == LayoutFrameType::FrameSet &&
   6912      IsSpecialFramesetChild(aChild)) {
   6913    // Just reframe the parent, since framesets are weird like that.
   6914    LAYOUT_PHASE_TEMP_EXIT();
   6915    RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
   6916    LAYOUT_PHASE_TEMP_REENTER();
   6917    return true;
   6918  }
   6919 
   6920  // If we're a child of MathML, then we should reframe the MathML content.
   6921  // If we're non-MathML, then we would be wrapped in a block so we need to
   6922  // check our grandparent in that case.
   6923  nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
   6924                                         ? parentFrame->GetParent()
   6925                                         : parentFrame;
   6926  if (possibleMathMLAncestor->IsMathMLFrame()) {
   6927    LAYOUT_PHASE_TEMP_EXIT();
   6928    RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
   6929    LAYOUT_PHASE_TEMP_REENTER();
   6930    return true;
   6931  }
   6932 
   6933 #ifdef ACCESSIBILITY
   6934  if (aKind != RemovalKind::ForReconstruction) {
   6935    if (nsAccessibilityService* accService = GetAccService()) {
   6936      accService->ContentRemoved(mPresShell, aChild);
   6937    }
   6938  }
   6939 #endif
   6940 
   6941  // Examine the containing-block for the removed content and see if
   6942  // :first-letter style applies.
   6943  nsIFrame* inflowChild = childFrame;
   6944  if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
   6945    inflowChild = childFrame->GetPlaceholderFrame();
   6946    NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
   6947  }
   6948  nsContainerFrame* containingBlock =
   6949      GetFloatContainingBlock(inflowChild->GetParent());
   6950  bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
   6951  if (haveFLS) {
   6952    // Trap out to special routine that handles adjusting a blocks
   6953    // frame tree when first-letter style is present.
   6954 #ifdef NOISY_FIRST_LETTER
   6955    printf("ContentWillBeRemoved: containingBlock=");
   6956    containingBlock->ListTag(stdout);
   6957    printf(" parentFrame=");
   6958    parentFrame->ListTag(stdout);
   6959    printf(" childFrame=");
   6960    childFrame->ListTag(stdout);
   6961    printf("\n");
   6962 #endif
   6963 
   6964    // First update the containing blocks structure by removing the
   6965    // existing letter frames. This makes the subsequent logic
   6966    // simpler.
   6967    RemoveLetterFrames(mPresShell, containingBlock);
   6968 
   6969    // Recover childFrame and parentFrame
   6970    childFrame = aChild->GetPrimaryFrame();
   6971    if (!childFrame || childFrame->GetContent() != aChild) {
   6972      // XXXbz the GetContent() != aChild check is needed due to bug 135040.
   6973      // Remove it once that's fixed.
   6974      return false;
   6975    }
   6976    parentFrame = childFrame->GetParent();
   6977    parentType = parentFrame->Type();
   6978 
   6979 #ifdef NOISY_FIRST_LETTER
   6980    printf("  ==> revised parentFrame=");
   6981    parentFrame->ListTag(stdout);
   6982    printf(" childFrame=");
   6983    childFrame->ListTag(stdout);
   6984    printf("\n");
   6985 #endif
   6986  }
   6987 
   6988 #ifdef DEBUG
   6989  if (gReallyNoisyContentUpdates) {
   6990    printf("nsCSSFrameConstructor::ContentWillBeRemoved: childFrame=");
   6991    childFrame->ListTag(stdout);
   6992    putchar('\n');
   6993    parentFrame->List(stdout);
   6994  }
   6995 #endif
   6996 
   6997  // Notify the parent frame that it should delete the frame
   6998  if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
   6999    childFrame = childFrame->GetPlaceholderFrame();
   7000    NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
   7001    parentFrame = childFrame->GetParent();
   7002  }
   7003 
   7004  // Take care of wrapper anonymous boxes that we might need to remove while
   7005  // at it. Note that MaybeRecreateContainerForFrameRemoval takes care of
   7006  // harder cases (merging sibling anonymous boxes etc).
   7007  while (IsWrapperPseudo(parentFrame) &&
   7008         CanRemoveWrapperPseudoForChildRemoval(childFrame, parentFrame)) {
   7009    childFrame = parentFrame;
   7010    parentFrame = childFrame->GetParent();
   7011  }
   7012 
   7013  const bool canSkipWhitespaceFixup = [&] {
   7014    if (aKind == RemovalKind::ForReconstruction) {
   7015      // If we're just reconstructing frames for the element, then the
   7016      // following ContentInserted notification on the element will
   7017      // take care of fixing up any adjacent white-space text nodes.
   7018      return true;
   7019    }
   7020    switch (parentFrame->Type()) {
   7021      case LayoutFrameType::Table:
   7022      case LayoutFrameType::TableRow:
   7023      case LayoutFrameType::TableRowGroup:
   7024      case LayoutFrameType::TableCol:
   7025      case LayoutFrameType::TableColGroup:
   7026      case LayoutFrameType::TableWrapper: {
   7027        // Tables ignore all whitespace within their wrappers, so we can avoid
   7028        // reconstructing adjacent whitespace if the table is not anonymous.
   7029        if (!IsInAnonymousTable(parentFrame)) {
   7030          return true;
   7031        }
   7032        // If the table is anonymous and the child is at the edges, we might
   7033        // need to create whitespace at the edges of the table that wasn't
   7034        // there before, so we can only skip the check if childFrame has frames
   7035        // around. Captions are extra-special here, because they're siblings
   7036        // with the main table frame, so we can't count that as a relevant
   7037        // sibling for our purposes.
   7038        auto* prevSibling = childFrame->GetPrevSibling();
   7039        return prevSibling && !prevSibling->IsTableFrame() &&
   7040               childFrame->GetNextSibling();
   7041      }
   7042      case LayoutFrameType::GridContainer:
   7043      case LayoutFrameType::FlexContainer:
   7044        // Flex and grid containers similarly skip whitespace and wrap
   7045        // non-whitespace in anonymous flex items, so any change to
   7046        // white-space that could matter would have triggered the
   7047        // reconstruction of the container itself due to merging anonymous
   7048        // grid / flex items.
   7049        return true;
   7050      default:
   7051        break;
   7052    }
   7053    return false;
   7054  }();
   7055  DestroyContext context(mPresShell);
   7056  RemoveFrame(context, nsLayoutUtils::GetChildListNameFor(childFrame),
   7057              childFrame);
   7058 
   7059  // NOTE(emilio): aChild could be dead here already if it is a ::before or
   7060  // ::after pseudo-element (since in that case it was owned by childFrame,
   7061  // which we just destroyed).
   7062 
   7063  if (isRoot) {
   7064    mRootElementFrame = nullptr;
   7065    mRootElementStyleFrame = nullptr;
   7066    mDocElementContainingBlock = nullptr;
   7067    mCanvasFrame = nullptr;
   7068    mPageSequenceFrame = nullptr;
   7069  }
   7070 
   7071  if (haveFLS && mRootElementFrame) {
   7072    RecoverLetterFrames(containingBlock);
   7073  }
   7074 
   7075  if (!canSkipWhitespaceFixup) {
   7076    MOZ_ASSERT(aChild->GetParentNode(),
   7077               "How did we have a sibling without a parent?");
   7078    // Adjacent whitespace-only text nodes might have been suppressed if
   7079    // this node does not have inline ends. Create frames for them now
   7080    // if necessary.
   7081    // Reframe any text node just before the node being removed, if there is
   7082    // one, and if it's not the last child or the first child. If a whitespace
   7083    // textframe was being suppressed and it's now the last child or first
   7084    // child then it can stay suppressed since the parent must be a block
   7085    // and hence it's adjacent to a block end.
   7086    // If aOldNextSibling is null, then the text node before the node being
   7087    // removed is the last node, and we don't need to worry about it.
   7088    nsIContent* prevSibling = aChild->GetPreviousSibling();
   7089    if (prevSibling && prevSibling->GetPreviousSibling()) {
   7090      LAYOUT_PHASE_TEMP_EXIT();
   7091      ReframeTextIfNeeded(prevSibling);
   7092      LAYOUT_PHASE_TEMP_REENTER();
   7093    }
   7094    // Reframe any text node just after the node being removed, if there is
   7095    // one, and if it's not the last child or the first child.
   7096    nsIContent* nextSibling = aChild->GetNextSibling();
   7097    if (nextSibling && prevSibling && nextSibling->GetNextSibling()) {
   7098      LAYOUT_PHASE_TEMP_EXIT();
   7099      ReframeTextIfNeeded(nextSibling);
   7100      LAYOUT_PHASE_TEMP_REENTER();
   7101    }
   7102  }
   7103 
   7104 #ifdef DEBUG
   7105  if (gReallyNoisyContentUpdates && parentFrame) {
   7106    printf(
   7107        "nsCSSFrameConstructor::ContentWillBeRemoved: resulting frame "
   7108        "model:\n");
   7109    parentFrame->List(stdout);
   7110  }
   7111 #endif
   7112 
   7113  return false;
   7114 }
   7115 
   7116 /**
   7117 * This method invalidates the canvas when frames are removed or added for a
   7118 * node that might have its background propagated to the canvas, i.e., a
   7119 * document root node or an HTML BODY which is a child of the root node.
   7120 *
   7121 * @param aFrame a frame for a content node about to be removed or a frame that
   7122 *               was just created for a content node that was inserted.
   7123 */
   7124 static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode) {
   7125  MOZ_ASSERT(aPresShell->GetRootFrame(), "What happened here?");
   7126  MOZ_ASSERT(aPresShell->GetPresContext(), "Say what?");
   7127 
   7128  //  Note that both in ContentWillBeRemoved and ContentInserted the content
   7129  //  node will still have the right parent pointer, so looking at that is ok.
   7130 
   7131  nsIContent* parent = aNode->GetParent();
   7132  if (parent) {
   7133    // Has a parent; might not be what we want
   7134    nsIContent* grandParent = parent->GetParent();
   7135    if (grandParent) {
   7136      // Has a grandparent, so not what we want
   7137      return;
   7138    }
   7139 
   7140    // Check whether it's an HTML body
   7141    if (!aNode->IsHTMLElement(nsGkAtoms::body)) {
   7142      return;
   7143    }
   7144  }
   7145 
   7146  // At this point the node has no parent or it's an HTML <body> child of the
   7147  // root.  We might not need to invalidate in this case (eg we might be in
   7148  // XHTML or something), but chances are we want to.  Play it safe.
   7149  // Invalidate the viewport.
   7150 
   7151  nsIFrame* rootFrame = aPresShell->GetRootFrame();
   7152  rootFrame->InvalidateFrameSubtree();
   7153 }
   7154 
   7155 bool nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
   7156    CharacterData* aContent) {
   7157  if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
   7158    return false;
   7159  }
   7160 
   7161  if (mAlwaysCreateFramesForIgnorableWhitespace) {
   7162    return false;
   7163  }
   7164 
   7165  // Text frame may have been suppressed. Disable suppression and signal that a
   7166  // flush should be performed. We do this on a document-wide basis so that
   7167  // pages that repeatedly query metrics for collapsed-whitespace text nodes
   7168  // don't trigger pathological behavior.
   7169  mAlwaysCreateFramesForIgnorableWhitespace = true;
   7170  Element* root = mDocument->GetRootElement();
   7171  if (!root) {
   7172    return false;
   7173  }
   7174 
   7175  RestyleManager()->PostRestyleEvent(root, RestyleHint{0},
   7176                                     nsChangeHint_ReconstructFrame);
   7177  return true;
   7178 }
   7179 
   7180 void nsCSSFrameConstructor::CharacterDataChanged(
   7181    nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
   7182  AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::CharacterDataChanged",
   7183                          LAYOUT_FrameConstruction);
   7184  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   7185 
   7186  if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
   7187       !aContent->TextIsOnlyWhitespace()) ||
   7188      (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
   7189       aContent->TextIsOnlyWhitespace())) {
   7190 #ifdef DEBUG
   7191    nsIFrame* frame = aContent->GetPrimaryFrame();
   7192    NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
   7193                 "Bit should never be set on generated content");
   7194 #endif
   7195    LAYOUT_PHASE_TEMP_EXIT();
   7196    RecreateFramesForContent(aContent, InsertionKind::Async);
   7197    LAYOUT_PHASE_TEMP_REENTER();
   7198    return;
   7199  }
   7200 
   7201  // It's possible the frame whose content changed isn't inserted into the
   7202  // frame hierarchy yet, or that there is no frame that maps the content
   7203  if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
   7204 #if 0
   7205    NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
   7206       ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
   7207        aContent, ContentTag(aContent, 0),
   7208        aSubContent, frame));
   7209 #endif
   7210 
   7211    if (frame->HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI)) {
   7212      LAYOUT_PHASE_TEMP_EXIT();
   7213      RecreateFramesForContent(aContent, InsertionKind::Async);
   7214      LAYOUT_PHASE_TEMP_REENTER();
   7215      return;
   7216    }
   7217 
   7218    // Special check for text content that is a child of a letter frame.  If
   7219    // this happens, we should remove the letter frame, do whatever we're
   7220    // planning to do with this notification, then put the letter frame back.
   7221    // Note that this is basically what RecreateFramesForContent ends up doing;
   7222    // the reason we dont' want to call that here is that our text content
   7223    // could be native anonymous, in which case RecreateFramesForContent would
   7224    // completely barf on it.  And recreating the non-anonymous ancestor would
   7225    // just lead us to come back into this notification (e.g. if quotes or
   7226    // counters are involved), leading to a loop.
   7227    nsContainerFrame* block = GetFloatContainingBlock(frame);
   7228    bool haveFirstLetterStyle = false;
   7229    if (block) {
   7230      // See if the block has first-letter style applied to it.
   7231      haveFirstLetterStyle = HasFirstLetterStyle(block);
   7232      if (haveFirstLetterStyle) {
   7233        RemoveLetterFrames(mPresShell, block);
   7234        // Reget |frame|, since we might have killed it.
   7235        // Do we really need to call CharacterDataChanged in this case, though?
   7236        frame = aContent->GetPrimaryFrame();
   7237        NS_ASSERTION(frame, "Should have frame here!");
   7238      }
   7239    }
   7240 
   7241    // Notify the first frame that maps the content. It will generate a reflow
   7242    // command
   7243    frame->CharacterDataChanged(aInfo);
   7244 
   7245    if (haveFirstLetterStyle) {
   7246      RecoverLetterFrames(block);
   7247    }
   7248  }
   7249 }
   7250 
   7251 void nsCSSFrameConstructor::RecalcQuotesAndCounters() {
   7252  nsAutoScriptBlocker scriptBlocker;
   7253 
   7254  if (mQuotesDirty) {
   7255    mQuotesDirty = false;
   7256    mContainStyleScopeManager.RecalcAllQuotes();
   7257  }
   7258 
   7259  if (mCountersDirty) {
   7260    mCountersDirty = false;
   7261    mContainStyleScopeManager.RecalcAllCounters();
   7262  }
   7263 
   7264  NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
   7265  NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
   7266 }
   7267 
   7268 void nsCSSFrameConstructor::NotifyCounterStylesAreDirty() {
   7269  mContainStyleScopeManager.SetAllCountersDirty();
   7270  CountersDirty();
   7271 }
   7272 
   7273 void nsCSSFrameConstructor::WillDestroyFrameTree() {
   7274 #if defined(DEBUG_dbaron_off)
   7275  mContainStyleScopeManager.DumpCounters();
   7276 #endif
   7277 
   7278  // Prevent frame tree destruction from being O(N^2)
   7279  mContainStyleScopeManager.Clear();
   7280  nsFrameManager::Destroy();
   7281 }
   7282 
   7283 // STATIC
   7284 
   7285 // XXXbz I'd really like this method to go away. Once we have inline-block and
   7286 // I can just use that for sized broken images, that can happen, maybe.
   7287 //
   7288 // NOTE(emilio): This needs to match MozAltContent handling.
   7289 void nsCSSFrameConstructor::GetAlternateTextFor(const Element& aElement,
   7290                                                nsAString& aAltText) {
   7291  // The "alt" attribute specifies alternate text that is rendered
   7292  // when the image can not be displayed.
   7293  if (aElement.GetAttr(nsGkAtoms::alt, aAltText)) {
   7294    return;
   7295  }
   7296 
   7297  if (aElement.IsHTMLElement(nsGkAtoms::input)) {
   7298    // If there's no "alt" attribute, and aElement is an input element, then use
   7299    // the value of the "value" attribute.
   7300    if (aElement.GetAttr(nsGkAtoms::value, aAltText)) {
   7301      return;
   7302    }
   7303 
   7304    // If there's no "value" attribute either, then use the localized string for
   7305    // "Submit" as the alternate text.
   7306    nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
   7307                                            "Submit", aElement.OwnerDoc(),
   7308                                            aAltText);
   7309  }
   7310 }
   7311 
   7312 nsIFrame* nsCSSFrameConstructor::CreateContinuingOuterTableFrame(
   7313    nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
   7314    ComputedStyle* aComputedStyle) {
   7315  nsTableWrapperFrame* newFrame =
   7316      NS_NewTableWrapperFrame(mPresShell, aComputedStyle);
   7317 
   7318  newFrame->Init(aContent, aParentFrame, aFrame);
   7319 
   7320  // Create a continuing inner table frame. Note we don't replicate the
   7321  // captions: a comment used to hint at that, but the code dealing with that
   7322  // never worked and was removed in bug 309322.
   7323  nsFrameList newChildFrames;
   7324 
   7325  MOZ_ASSERT(aFrame->IsTableWrapperFrame());
   7326  if (nsTableFrame* childFrame =
   7327          static_cast<nsTableWrapperFrame*>(aFrame)->InnerTableFrame()) {
   7328    nsIFrame* continuingTableFrame =
   7329        CreateContinuingFrame(childFrame, newFrame);
   7330    newChildFrames.AppendFrame(nullptr, continuingTableFrame);
   7331  }
   7332 
   7333  // Set the table wrapper's initial child list
   7334  newFrame->SetInitialChildList(FrameChildListID::Principal,
   7335                                std::move(newChildFrames));
   7336 
   7337  return newFrame;
   7338 }
   7339 
   7340 nsIFrame* nsCSSFrameConstructor::CreateContinuingTableFrame(
   7341    nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
   7342    ComputedStyle* aComputedStyle) {
   7343  nsTableFrame* newFrame = NS_NewTableFrame(mPresShell, aComputedStyle);
   7344 
   7345  newFrame->Init(aContent, aParentFrame, aFrame);
   7346 
   7347  // Replicate any header/footer frames
   7348  nsFrameList childFrames;
   7349  for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
   7350    // See if it's a header/footer, possibly wrapped in a scroll frame.
   7351    nsTableRowGroupFrame* rowGroupFrame =
   7352        static_cast<nsTableRowGroupFrame*>(childFrame);
   7353    // If the row group was continued, then don't replicate it.
   7354    nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
   7355    if (rgNextInFlow) {
   7356      rowGroupFrame->SetRepeatable(false);
   7357    } else if (rowGroupFrame->IsRepeatable()) {
   7358      // Replicate the header/footer frame.
   7359      nsTableRowGroupFrame* headerFooterFrame;
   7360      nsFrameList childList;
   7361 
   7362      nsFrameConstructorState state(
   7363          mPresShell, GetAbsoluteContainingBlock(newFrame, FIXED_POS),
   7364          GetAbsoluteContainingBlock(newFrame, ABS_POS), nullptr);
   7365      state.mCreatingExtraFrames = true;
   7366 
   7367      ComputedStyle* const headerFooterComputedStyle = rowGroupFrame->Style();
   7368      headerFooterFrame = static_cast<nsTableRowGroupFrame*>(
   7369          NS_NewTableRowGroupFrame(mPresShell, headerFooterComputedStyle));
   7370 
   7371      nsIContent* headerFooter = rowGroupFrame->GetContent();
   7372      headerFooterFrame->Init(headerFooter, newFrame, nullptr);
   7373 
   7374      nsFrameConstructorSaveState absoluteSaveState;
   7375      MakeTablePartAbsoluteContainingBlock(state, absoluteSaveState,
   7376                                           headerFooterFrame);
   7377 
   7378      nsFrameConstructorSaveState floatSaveState;
   7379      state.MaybePushFloatContainingBlock(headerFooterFrame, floatSaveState);
   7380 
   7381      ProcessChildren(state, headerFooter, rowGroupFrame->Style(),
   7382                      headerFooterFrame, true, childList, false, nullptr);
   7383      NS_ASSERTION(state.mFloatedList.IsEmpty(), "unexpected floated element");
   7384      headerFooterFrame->SetInitialChildList(FrameChildListID::Principal,
   7385                                             std::move(childList));
   7386      headerFooterFrame->SetRepeatable(true);
   7387 
   7388      // Table specific initialization
   7389      headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
   7390 
   7391      // XXX Deal with absolute and fixed frames...
   7392      childFrames.AppendFrame(nullptr, headerFooterFrame);
   7393    }
   7394  }
   7395 
   7396  // Set the table frame's initial child list
   7397  newFrame->SetInitialChildList(FrameChildListID::Principal,
   7398                                std::move(childFrames));
   7399 
   7400  return newFrame;
   7401 }
   7402 
   7403 nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
   7404    nsIFrame* aFrame, nsContainerFrame* aParentFrame, bool aIsFluid) {
   7405  ComputedStyle* computedStyle = aFrame->Style();
   7406  nsIFrame* newFrame = nullptr;
   7407  nsIFrame* nextContinuation = aFrame->GetNextContinuation();
   7408  nsIFrame* nextInFlow = aFrame->GetNextInFlow();
   7409 
   7410  // Use the frame type to determine what type of frame to create
   7411  LayoutFrameType frameType = aFrame->Type();
   7412  nsIContent* content = aFrame->GetContent();
   7413 
   7414  if (LayoutFrameType::Text == frameType) {
   7415    newFrame = NS_NewContinuingTextFrame(mPresShell, computedStyle);
   7416    newFrame->Init(content, aParentFrame, aFrame);
   7417  } else if (LayoutFrameType::Inline == frameType) {
   7418    newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
   7419    newFrame->Init(content, aParentFrame, aFrame);
   7420  } else if (LayoutFrameType::Block == frameType) {
   7421    MOZ_ASSERT(!aFrame->IsTableCaption(),
   7422               "no support for fragmenting table captions yet");
   7423    newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
   7424    newFrame->Init(content, aParentFrame, aFrame);
   7425  } else if (LayoutFrameType::ColumnSetWrapper == frameType) {
   7426    newFrame =
   7427        NS_NewColumnSetWrapperFrame(mPresShell, computedStyle, nsFrameState(0));
   7428    newFrame->Init(content, aParentFrame, aFrame);
   7429  } else if (LayoutFrameType::ColumnSet == frameType) {
   7430    MOZ_ASSERT(!aFrame->IsTableCaption(),
   7431               "no support for fragmenting table captions yet");
   7432    newFrame = NS_NewColumnSetFrame(mPresShell, computedStyle, nsFrameState(0));
   7433    newFrame->Init(content, aParentFrame, aFrame);
   7434  } else if (LayoutFrameType::PrintedSheet == frameType) {
   7435    newFrame = ConstructPrintedSheetFrame(mPresShell, aParentFrame, aFrame);
   7436  } else if (LayoutFrameType::Page == frameType) {
   7437    nsCanvasFrame* canvasFrame;  // (unused outparam for ConstructPageFrame)
   7438    newFrame =
   7439        ConstructPageFrame(mPresShell, aParentFrame, aFrame, canvasFrame);
   7440  } else if (LayoutFrameType::TableWrapper == frameType) {
   7441    newFrame = CreateContinuingOuterTableFrame(aFrame, aParentFrame, content,
   7442                                               computedStyle);
   7443  } else if (LayoutFrameType::Table == frameType) {
   7444    newFrame = CreateContinuingTableFrame(aFrame, aParentFrame, content,
   7445                                          computedStyle);
   7446  } else if (LayoutFrameType::TableRowGroup == frameType) {
   7447    newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
   7448    newFrame->Init(content, aParentFrame, aFrame);
   7449  } else if (LayoutFrameType::TableRow == frameType) {
   7450    nsTableRowFrame* rowFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
   7451 
   7452    rowFrame->Init(content, aParentFrame, aFrame);
   7453 
   7454    // Create a continuing frame for each table cell frame
   7455    nsFrameList newChildList;
   7456    nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
   7457    while (cellFrame) {
   7458      // See if it's a table cell frame
   7459      if (cellFrame->IsTableCellFrame()) {
   7460        nsIFrame* continuingCellFrame =
   7461            CreateContinuingFrame(cellFrame, rowFrame);
   7462        newChildList.AppendFrame(nullptr, continuingCellFrame);
   7463      }
   7464      cellFrame = cellFrame->GetNextSibling();
   7465    }
   7466 
   7467    rowFrame->SetInitialChildList(FrameChildListID::Principal,
   7468                                  std::move(newChildList));
   7469    newFrame = rowFrame;
   7470 
   7471  } else if (LayoutFrameType::TableCell == frameType) {
   7472    // Warning: If you change this and add a wrapper frame around table cell
   7473    // frames, make sure Bug 368554 doesn't regress!
   7474    // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
   7475    nsTableFrame* tableFrame =
   7476        static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
   7477    nsTableCellFrame* cellFrame =
   7478        NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
   7479 
   7480    cellFrame->Init(content, aParentFrame, aFrame);
   7481 
   7482    // Create a continuing area frame
   7483    nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
   7484    nsIFrame* continuingBlockFrame =
   7485        CreateContinuingFrame(blockFrame, cellFrame);
   7486 
   7487    SetInitialSingleChild(cellFrame, continuingBlockFrame);
   7488    newFrame = cellFrame;
   7489  } else if (LayoutFrameType::Line == frameType) {
   7490    newFrame = NS_NewFirstLineFrame(mPresShell, computedStyle);
   7491    newFrame->Init(content, aParentFrame, aFrame);
   7492  } else if (LayoutFrameType::Letter == frameType) {
   7493    newFrame = NS_NewFirstLetterFrame(mPresShell, computedStyle);
   7494    newFrame->Init(content, aParentFrame, aFrame);
   7495  } else if (LayoutFrameType::Image == frameType) {
   7496    auto* imageFrame = static_cast<nsImageFrame*>(aFrame);
   7497    newFrame = imageFrame->CreateContinuingFrame(mPresShell, computedStyle);
   7498    newFrame->Init(content, aParentFrame, aFrame);
   7499  } else if (LayoutFrameType::ImageControl == frameType) {
   7500    newFrame = NS_NewImageControlFrame(mPresShell, computedStyle);
   7501    newFrame->Init(content, aParentFrame, aFrame);
   7502  } else if (LayoutFrameType::FieldSet == frameType) {
   7503    newFrame = NS_NewFieldSetFrame(mPresShell, computedStyle);
   7504    newFrame->Init(content, aParentFrame, aFrame);
   7505  } else if (LayoutFrameType::FlexContainer == frameType) {
   7506    newFrame = NS_NewFlexContainerFrame(mPresShell, computedStyle);
   7507    newFrame->Init(content, aParentFrame, aFrame);
   7508  } else if (LayoutFrameType::GridContainer == frameType) {
   7509    newFrame = NS_NewGridContainerFrame(mPresShell, computedStyle);
   7510    newFrame->Init(content, aParentFrame, aFrame);
   7511  } else if (LayoutFrameType::Ruby == frameType) {
   7512    newFrame = NS_NewRubyFrame(mPresShell, computedStyle);
   7513    newFrame->Init(content, aParentFrame, aFrame);
   7514  } else if (LayoutFrameType::RubyBaseContainer == frameType) {
   7515    newFrame = NS_NewRubyBaseContainerFrame(mPresShell, computedStyle);
   7516    newFrame->Init(content, aParentFrame, aFrame);
   7517  } else if (LayoutFrameType::RubyTextContainer == frameType) {
   7518    newFrame = NS_NewRubyTextContainerFrame(mPresShell, computedStyle);
   7519    newFrame->Init(content, aParentFrame, aFrame);
   7520  } else {
   7521    MOZ_CRASH("unexpected frame type");
   7522  }
   7523 
   7524  // Init() set newFrame to be a fluid continuation of aFrame.
   7525  // If we want a non-fluid continuation, we need to call SetPrevContinuation()
   7526  // to reset NS_FRAME_IS_FLUID_CONTINUATION.
   7527  if (!aIsFluid) {
   7528    newFrame->SetPrevContinuation(aFrame);
   7529  }
   7530 
   7531  // If a continuing frame needs to carry frame state bits from its previous
   7532  // continuation or parent, set them in nsIFrame::Init(), or in any derived
   7533  // frame class's Init() if the bits are belong to specific group.
   7534 
   7535  if (nextInFlow) {
   7536    nextInFlow->SetPrevInFlow(newFrame);
   7537    newFrame->SetNextInFlow(nextInFlow);
   7538  } else if (nextContinuation) {
   7539    nextContinuation->SetPrevContinuation(newFrame);
   7540    newFrame->SetNextContinuation(nextContinuation);
   7541  }
   7542 
   7543  // aFrame cannot be a dynamic reflow root because it has a continuation now.
   7544  aFrame->RemoveStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
   7545 
   7546  MOZ_ASSERT(!newFrame->GetNextSibling(), "unexpected sibling");
   7547  return newFrame;
   7548 }
   7549 
   7550 void nsCSSFrameConstructor::MaybeSetNextPageContentFramePageName(
   7551    const nsIFrame* aFrame) {
   7552  MOZ_ASSERT(aFrame, "Frame should not be null");
   7553  // No parent means the root frame, which isn't what this funciton is for.
   7554  MOZ_ASSERT(aFrame->GetParent(),
   7555             "Frame should be the first child placed on a new page, not the "
   7556             "root frame.");
   7557  if (mNextPageContentFramePageName) {
   7558    return;
   7559  }
   7560  const nsAtom* const autoValue = aFrame->GetParent()->GetAutoPageValue();
   7561  mNextPageContentFramePageName = aFrame->ComputePageValue(autoValue);
   7562 }
   7563 
   7564 nsresult nsCSSFrameConstructor::ReplicateFixedFrames(
   7565    nsPageContentFrame* aParentFrame) {
   7566  // Now deal with fixed-pos things....  They should appear on all pages,
   7567  // so we want to move over the placeholders when processing the child
   7568  // of the pageContentFrame.
   7569 
   7570  nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
   7571  if (!prevPageContentFrame) {
   7572    return NS_OK;
   7573  }
   7574  nsContainerFrame* canvasFrame =
   7575      do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
   7576  nsIFrame* prevCanvasFrame =
   7577      prevPageContentFrame->PrincipalChildList().FirstChild();
   7578  if (!canvasFrame || !prevCanvasFrame) {
   7579    // document's root element frame missing
   7580    return NS_ERROR_UNEXPECTED;
   7581  }
   7582 
   7583  nsFrameList fixedPlaceholders;
   7584  nsIFrame* firstFixed =
   7585      prevPageContentFrame->GetChildList(FrameChildListID::Fixed).FirstChild();
   7586  if (!firstFixed) {
   7587    return NS_OK;
   7588  }
   7589 
   7590  // Don't allow abs-pos descendants of the fixed content to escape the content.
   7591  // This should not normally be possible (because fixed-pos elements should
   7592  // be absolute containers) but fixed-pos tables currently aren't abs-pos
   7593  // containers.
   7594  nsFrameConstructorState state(mPresShell, aParentFrame, nullptr,
   7595                                mRootElementFrame);
   7596  state.mCreatingExtraFrames = true;
   7597 
   7598  // We can't use an ancestor filter here, because we're not going to
   7599  // be usefully recurring down the tree.  This means that other
   7600  // places in frame construction can't assume a filter is
   7601  // initialized!
   7602 
   7603  // Iterate across fixed frames and replicate each whose placeholder is a
   7604  // descendant of aFrame. (We don't want to explicitly copy placeholders that
   7605  // are within fixed frames, because that would cause duplicates on the new
   7606  // page - bug 389619)
   7607  for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
   7608    nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
   7609    if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(
   7610                               prevCanvasFrame, prevPlaceholder)) {
   7611      // We want to use the same style as the primary style frame for
   7612      // our content
   7613      nsIContent* content = fixed->GetContent();
   7614      ComputedStyle* computedStyle =
   7615          nsLayoutUtils::GetStyleFrame(content)->Style();
   7616      AutoFrameConstructionItemList items(this);
   7617      AddFrameConstructionItemsInternal(state, content, canvasFrame, true,
   7618                                        computedStyle,
   7619                                        {ItemFlag::AllowPageBreak}, items);
   7620      ConstructFramesFromItemList(state, items, canvasFrame,
   7621                                  /* aParentIsWrapperAnonBox = */ false,
   7622                                  fixedPlaceholders);
   7623    }
   7624  }
   7625 
   7626  // Add the placeholders to our primary child list.
   7627  // XXXbz this is a little screwed up, since the fixed frames will have
   7628  // broken auto-positioning. Oh, well.
   7629  NS_ASSERTION(!canvasFrame->PrincipalChildList().FirstChild(),
   7630               "leaking frames; doc root continuation must be empty");
   7631  canvasFrame->SetInitialChildList(FrameChildListID::Principal,
   7632                                   std::move(fixedPlaceholders));
   7633  return NS_OK;
   7634 }
   7635 
   7636 nsCSSFrameConstructor::InsertionPoint nsCSSFrameConstructor::GetInsertionPoint(
   7637    nsIContent* aChild) {
   7638  MOZ_ASSERT(aChild);
   7639  nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
   7640  if (!insertionElement) {
   7641    // The element doesn't belong in the flattened tree, and thus we don't want
   7642    // to render it.
   7643    return {};
   7644  }
   7645 
   7646  return {GetContentInsertionFrameFor(insertionElement), insertionElement};
   7647 }
   7648 
   7649 // Capture state for the frame tree rooted at the frame associated with the
   7650 // content object, aContent
   7651 void nsCSSFrameConstructor::CaptureStateForFramesOf(
   7652    nsIContent* aContent, nsILayoutHistoryState* aHistoryState) {
   7653  if (!aHistoryState) {
   7654    return;
   7655  }
   7656  nsIFrame* frame = aContent->GetPrimaryFrame();
   7657  if (frame == mRootElementFrame) {
   7658    frame = mRootElementFrame
   7659                ? GetAbsoluteContainingBlock(mRootElementFrame, FIXED_POS)
   7660                : GetRootFrame();
   7661  }
   7662  for (; frame;
   7663       frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
   7664    CaptureFrameState(frame, aHistoryState);
   7665  }
   7666 }
   7667 
   7668 static bool IsWhitespaceFrame(nsIFrame* aFrame) {
   7669  MOZ_ASSERT(aFrame, "invalid argument");
   7670  return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
   7671 }
   7672 
   7673 static nsIFrame* FindNextNonWhitespaceSibling(nsIFrame* aFrame) {
   7674  nsIFrame* f = aFrame;
   7675  do {
   7676    f = f->GetNextSibling();
   7677  } while (f && IsWhitespaceFrame(f));
   7678  return f;
   7679 }
   7680 
   7681 static nsIFrame* FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) {
   7682  nsIFrame* f = aFrame;
   7683  do {
   7684    f = f->GetPrevSibling();
   7685  } while (f && IsWhitespaceFrame(f));
   7686  return f;
   7687 }
   7688 
   7689 bool nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
   7690    nsIFrame* aFrame) {
   7691 #define TRACE(reason)                                                       \
   7692  PROFILER_MARKER("MaybeRecreateContainerForFrameRemoval: " reason, LAYOUT, \
   7693                  {}, Tracing, "Layout")
   7694  MOZ_ASSERT(aFrame, "Must have a frame");
   7695  MOZ_ASSERT(aFrame->GetParent(), "Frame shouldn't be root");
   7696  MOZ_ASSERT(aFrame == aFrame->FirstContinuation(),
   7697             "aFrame not the result of GetPrimaryFrame()?");
   7698 
   7699  nsIFrame* inFlowFrame = aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
   7700                              ? aFrame->GetPlaceholderFrame()
   7701                              : aFrame;
   7702  MOZ_ASSERT(inFlowFrame, "How did that happen?");
   7703  MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
   7704             "placeholder for primary frame has previous continuations?");
   7705  nsIFrame* parent = inFlowFrame->GetParent();
   7706 
   7707  if (inFlowFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
   7708    nsIFrame* grandparent = parent->GetParent();
   7709    MOZ_ASSERT(grandparent);
   7710 
   7711    bool needsReframe =
   7712        // 1. Removing a column-span may lead to an empty
   7713        // ::-moz-column-span-wrapper.
   7714        inFlowFrame->IsColumnSpan() ||
   7715        // 2. Removing a frame which has any column-span siblings may also
   7716        // lead to an empty ::-moz-column-span-wrapper subtree. The
   7717        // column-span siblings were the frame's children, but later become
   7718        // the frame's siblings after CreateColumnSpanSiblings().
   7719        inFlowFrame->HasColumnSpanSiblings() ||
   7720        // 3. Removing the only child of a ::-moz-column-content, whose
   7721        // ColumnSet grandparent has a previous column-span sibling, requires
   7722        // reframing since we might connect the ColumnSet's next column-span
   7723        // sibling (if there's one). Note that this isn't actually needed if
   7724        // the ColumnSet is at the end of ColumnSetWrapper since we create
   7725        // empty ones at the end anyway, but we're not worried about
   7726        // optimizing that case.
   7727        (parent->Style()->GetPseudoType() == PseudoStyleType::columnContent &&
   7728         // The only child in ::-moz-column-content (might be tall enough to
   7729         // split across columns)
   7730         !inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
   7731         // That ::-moz-column-content is the first column.
   7732         !parent->GetPrevInFlow() &&
   7733         // The ColumnSet grandparent has a previous sibling that is a
   7734         // column-span.
   7735         grandparent->GetPrevSibling());
   7736 
   7737    if (needsReframe) {
   7738      nsContainerFrame* containingBlock =
   7739          GetMultiColumnContainingBlockFor(inFlowFrame);
   7740 
   7741 #ifdef DEBUG
   7742      if (IsFramePartOfIBSplit(inFlowFrame)) {
   7743        nsIFrame* ibContainingBlock = GetIBContainingBlockFor(inFlowFrame);
   7744        MOZ_ASSERT(containingBlock == ibContainingBlock ||
   7745                       nsLayoutUtils::IsProperAncestorFrame(containingBlock,
   7746                                                            ibContainingBlock),
   7747                   "Multi-column containing block should be equal to or be the "
   7748                   "ancestor of the IB containing block!");
   7749      }
   7750 #endif
   7751 
   7752      TRACE("Multi-column");
   7753      RecreateFramesForContent(containingBlock->GetContent(),
   7754                               InsertionKind::Async);
   7755      return true;
   7756    }
   7757  }
   7758 
   7759  if (IsFramePartOfIBSplit(aFrame)) {
   7760    // The removal functions can't handle removal of an {ib} split directly; we
   7761    // need to rebuild the containing block.
   7762    TRACE("IB split removal");
   7763    ReframeContainingBlock(aFrame);
   7764    return true;
   7765  }
   7766 
   7767  if (inFlowFrame->IsRenderedLegend()) {
   7768    TRACE("Fieldset / Legend");
   7769    RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
   7770    return true;
   7771  }
   7772 
   7773  // Might need to reconstruct things if this frame's nextSibling is a table
   7774  // or ruby pseudo, since removal of this frame might mean that this pseudo
   7775  // needs to get merged with the frame's prevSibling if that's also a table
   7776  // or ruby pseudo.
   7777  nsIFrame* nextSibling =
   7778      FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
   7779  NS_ASSERTION(!IsWrapperPseudo(inFlowFrame),
   7780               "Shouldn't happen here (we start removals from primary frames)");
   7781  // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
   7782  // need to be checked here, since all other types of such frames will have
   7783  // a ruby container parent, and be catched by "Check ruby containers" below.
   7784  if (nextSibling && IsWrapperPseudo(nextSibling)) {
   7785    nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
   7786    if (prevSibling && IsWrapperPseudo(prevSibling)) {
   7787      TRACE("Pseudo sibling");
   7788      // Good enough to recreate frames for aFrame's parent's content; even if
   7789      // aFrame's parent is a pseudo, that'll be the right content node.
   7790      // FIXME(emilio): Consider doing a more subtle check here like, only if
   7791      // prevSibling and nextSibling share frame type. Or even consider just
   7792      // moving the frames around and destroying nextSibling?
   7793      RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
   7794      return true;
   7795    }
   7796  }
   7797 
   7798  // Check ruby containers
   7799  LayoutFrameType parentType = parent->Type();
   7800  if (parentType == LayoutFrameType::Ruby ||
   7801      RubyUtils::IsRubyContainerBox(parentType)) {
   7802    // In ruby containers, pseudo frames may be created from
   7803    // whitespaces or even nothing. There are two cases we actually
   7804    // need to handle here, but hard to check exactly:
   7805    // 1. Status of spaces beside the frame may vary, and related
   7806    //    frames may be constructed or destroyed accordingly.
   7807    // 2. The type of the first child of a ruby frame determines
   7808    //    whether a pseudo ruby base container should exist.
   7809    TRACE("Ruby container");
   7810    RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
   7811    return true;
   7812  }
   7813 
   7814  // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
   7815  // a non-fluid continuation, i.e. it was split by bidi resolution
   7816  if (!inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
   7817      ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
   7818       (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
   7819    TRACE("Removing last child of non-fluid split parent");
   7820    RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
   7821    return true;
   7822  }
   7823 
   7824  // We might still need to reconstruct things if the parent of inFlowFrame is
   7825  // ib-split, since in that case the removal of aFrame might affect the
   7826  // splitting of its parent.
   7827  if (!IsFramePartOfIBSplit(parent)) {
   7828    return false;
   7829  }
   7830 
   7831  // If inFlowFrame is not the only in-flow child of |parent|, then removing
   7832  // it will change nothing about the {ib} split.
   7833  if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
   7834      inFlowFrame->LastContinuation()->GetNextSibling()) {
   7835    return false;
   7836  }
   7837 
   7838  // If the parent is the first or last part of the {ib} split, then
   7839  // removing one of its kids will have no effect on the splitting.
   7840  // Get the first continuation up front so we don't have to do it twice.
   7841  nsIFrame* parentFirstContinuation = parent->FirstContinuation();
   7842  if (!GetIBSplitSibling(parentFirstContinuation) ||
   7843      !GetIBSplitPrevSibling(parentFirstContinuation)) {
   7844    return false;
   7845  }
   7846 
   7847  TRACE("IB split parent");
   7848  ReframeContainingBlock(parent);
   7849  return true;
   7850 #undef TRACE
   7851 }
   7852 
   7853 void nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent) {
   7854  nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
   7855 
   7856  // It's possible that this warning could fire if some other style change
   7857  // simultaneously changes the 'display' of the element and makes it no
   7858  // longer be a table cell.
   7859  NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!");
   7860 
   7861  if (cellFrame) {
   7862    cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
   7863  }
   7864 }
   7865 
   7866 static nsIContent* GetTopmostMathMLElement(nsIContent* aMathMLContent) {
   7867  MOZ_ASSERT(aMathMLContent->IsMathMLElement());
   7868  MOZ_ASSERT(aMathMLContent->GetPrimaryFrame());
   7869  MOZ_ASSERT(aMathMLContent->GetPrimaryFrame()->IsMathMLFrame());
   7870  nsIContent* root = aMathMLContent;
   7871 
   7872  for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent(); parent;
   7873       parent = parent->GetFlattenedTreeParent()) {
   7874    nsIFrame* frame = parent->GetPrimaryFrame();
   7875    if (!frame || !frame->IsMathMLFrame()) {
   7876      break;
   7877    }
   7878    root = parent;
   7879  }
   7880 
   7881  return root;
   7882 }
   7883 
   7884 // We don't know how to re-insert an anonymous subtree root, so recreate the
   7885 // closest non-generated ancestor instead, except for a few special cases...
   7886 static bool ShouldRecreateContainerForNativeAnonymousContentRoot(
   7887    nsIContent* aContent) {
   7888  if (!aContent->IsRootOfNativeAnonymousSubtree()) {
   7889    return false;
   7890  }
   7891  if (ManualNACPtr::IsManualNAC(aContent)) {
   7892    // Editor NAC, would enter an infinite loop, and we sorta get away with it
   7893    // because it's all abspos.
   7894    return false;
   7895  }
   7896  if (auto* el = Element::FromNode(aContent)) {
   7897    if (el->GetPseudoElementType() ==
   7898        PseudoStyleType::mozSnapshotContainingBlock) {
   7899      // Much like above, all abspos and on its own top layer so insertion order
   7900      // wouldn't really matter anyways.
   7901      return false;
   7902    }
   7903    if (auto* classes = el->GetClasses()) {
   7904      if (classes->Contains(nsGkAtoms::mozCustomContentContainer,
   7905                            eCaseMatters)) {
   7906        // Canvas anonymous content (like the custom content container) is also
   7907        // fine, because its only sibling is a tooltip which is also abspos, so
   7908        // relative insertion order doesn't really matter.
   7909        //
   7910        // This is important because the inspector uses it, and we don't want
   7911        // inspecting the page to change behavior heavily (and reframing
   7912        // unfortunately has side-effects sometimes, even though they're bugs).
   7913        return false;
   7914      }
   7915    }
   7916  }
   7917 
   7918  return true;
   7919 }
   7920 
   7921 void nsCSSFrameConstructor::RecreateFramesForContent(
   7922    nsIContent* aContent, InsertionKind aInsertionKind) {
   7923  MOZ_ASSERT(aContent);
   7924 
   7925  // If there is no document, we don't want to recreate frames for it.  (You
   7926  // shouldn't generally be giving this method content without a document
   7927  // anyway).
   7928  // Rebuilding the frame tree can have bad effects, especially if it's the
   7929  // frame tree for chrome (see bug 157322).
   7930  if (NS_WARN_IF(!aContent->GetComposedDoc())) {
   7931    return;
   7932  }
   7933 
   7934  // TODO(emilio): We technically can find the right insertion point nowadays
   7935  // using StyleChildrenIterator rather than FlattenedChildIterator. But we'd
   7936  // need to tweak the setup to insert into replaced elements to filter which
   7937  // anonymous roots can be allowed, and which can't.
   7938  //
   7939  // TODO(emilio, 2022): Is this true? If we have a replaced element we wouldn't
   7940  // have generated e.g., a ::before/::after pseudo-element to begin with (which
   7941  // is what this code is about, so maybe we can just remove this piece of code
   7942  // altogether).
   7943  if (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent)) {
   7944    do {
   7945      aContent = aContent->GetParent();
   7946    } while (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent));
   7947    return RecreateFramesForContent(aContent, InsertionKind::Async);
   7948  }
   7949 
   7950  nsIFrame* frame = aContent->GetPrimaryFrame();
   7951  if (frame && frame->IsMathMLFrame()) {
   7952    // Reframe the topmost MathML element to prevent exponential blowup
   7953    // (see bug 397518).
   7954    aContent = GetTopmostMathMLElement(aContent);
   7955    frame = aContent->GetPrimaryFrame();
   7956  }
   7957 
   7958  if (frame) {
   7959    nsIFrame* parent = frame->GetParent();
   7960    nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
   7961    // If the parent frame is a leaf then the subsequent insert will fail to
   7962    // create a frame, so we need to recreate the parent content. This happens
   7963    // with native anonymous content from the editor.
   7964    if (parent && parent->IsLeaf() && parentContent &&
   7965        parentContent != aContent) {
   7966      return RecreateFramesForContent(parentContent, InsertionKind::Async);
   7967    }
   7968  }
   7969 
   7970  if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
   7971    return;
   7972  }
   7973 
   7974  MOZ_ASSERT(aContent->GetParentNode());
   7975  const auto removalKind = [&] {
   7976    if (aInsertionKind == InsertionKind::Sync && aContent->IsElement() &&
   7977        Servo_Element_IsDisplayNone(aContent->AsElement())) {
   7978      // If we know we're not going to have frames after reconstructing, it's
   7979      // more efficient to do some of that work (a11y notifications, fixing-up
   7980      // text nodes) earlier.
   7981      return RemovalKind::ForDisplayNoneChange;
   7982    }
   7983    return RemovalKind::ForReconstruction;
   7984  }();
   7985  const bool didReconstruct = ContentWillBeRemoved(aContent, removalKind);
   7986  if (didReconstruct || removalKind == RemovalKind::ForDisplayNoneChange) {
   7987    // If ContentWillBeRemoved triggered reconstruction, then we don't need to
   7988    // do anything else because the frames will already have been built.
   7989    return;
   7990  }
   7991  if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
   7992    // FIXME(emilio, bug 1397239): There's nothing removing the frame state
   7993    // for elements that go away before we come back to the frame constructor.
   7994    //
   7995    // Also, it'd be nice to just use the `ContentRangeInserted` path for
   7996    // both elements and non-elements, but we need to make lazy frame
   7997    // construction to apply to all elements first.
   7998    //
   7999    // TODO(emilio): I think lazy frame construction works everywhere now, so
   8000    // maybe we can remove this altogether?
   8001    RestyleManager()->PostRestyleEvent(aContent->AsElement(), RestyleHint{0},
   8002                                       nsChangeHint_ReconstructFrame);
   8003    return;
   8004  }
   8005  // Now, recreate the frames associated with this content object.
   8006  ContentRangeInserted(aContent, aContent->GetNextSibling(), aInsertionKind);
   8007 }
   8008 
   8009 bool nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent) {
   8010  MOZ_ASSERT(aContent && aContent->GetParentNode());
   8011  return ContentWillBeRemoved(aContent, RemovalKind::ForReconstruction);
   8012 }
   8013 
   8014 //////////////////////////////////////////////////////////////////////
   8015 
   8016 // Block frame construction code
   8017 
   8018 already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLetterStyle(
   8019    nsIContent* aContent, ComputedStyle* aComputedStyle) {
   8020  if (aContent) {
   8021    return mPresShell->StyleSet()->ResolvePseudoElementStyle(
   8022        *aContent->AsElement(), PseudoStyleType::firstLetter, nullptr,
   8023        aComputedStyle);
   8024  }
   8025  return nullptr;
   8026 }
   8027 
   8028 already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLineStyle(
   8029    nsIContent* aContent, ComputedStyle* aComputedStyle) {
   8030  if (aContent) {
   8031    return mPresShell->StyleSet()->ResolvePseudoElementStyle(
   8032        *aContent->AsElement(), PseudoStyleType::firstLine, nullptr,
   8033        aComputedStyle);
   8034  }
   8035  return nullptr;
   8036 }
   8037 
   8038 // Predicate to see if a given content (block element) has
   8039 // first-letter style applied to it.
   8040 bool nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(
   8041    nsIContent* aContent, ComputedStyle* aComputedStyle) {
   8042  return nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
   8043                                       PseudoStyleType::firstLetter,
   8044                                       mPresShell->GetPresContext());
   8045 }
   8046 
   8047 bool nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame) {
   8048  MOZ_ASSERT(aBlockFrame, "Need a frame");
   8049  NS_ASSERTION(aBlockFrame->IsBlockFrameOrSubclass(), "Not a block frame?");
   8050 
   8051  return aBlockFrame->HasAnyStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
   8052 }
   8053 
   8054 bool nsCSSFrameConstructor::ShouldHaveFirstLineStyle(
   8055    nsIContent* aContent, ComputedStyle* aComputedStyle) {
   8056  bool hasFirstLine = nsLayoutUtils::HasPseudoStyle(
   8057      aContent, aComputedStyle, PseudoStyleType::firstLine,
   8058      mPresShell->GetPresContext());
   8059  return hasFirstLine && !aContent->IsHTMLElement(nsGkAtoms::fieldset);
   8060 }
   8061 
   8062 void nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(
   8063    nsIContent* aContent, ComputedStyle* aComputedStyle,
   8064    bool* aHaveFirstLetterStyle, bool* aHaveFirstLineStyle) {
   8065  *aHaveFirstLetterStyle = ShouldHaveFirstLetterStyle(aContent, aComputedStyle);
   8066  *aHaveFirstLineStyle = ShouldHaveFirstLineStyle(aContent, aComputedStyle);
   8067 }
   8068 
   8069 /* static */
   8070 const nsCSSFrameConstructor::PseudoParentData
   8071    nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
   8072        // Cell
   8073        {{&nsCSSFrameConstructor::ConstructTableCell,
   8074          FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
   8075              FCDATA_IS_WRAPPER_ANON_BOX |
   8076              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)},
   8077         PseudoStyleType::tableCell},
   8078        // Row
   8079        {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
   8080          FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
   8081              FCDATA_IS_WRAPPER_ANON_BOX |
   8082              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)},
   8083         PseudoStyleType::tableRow},
   8084        // Row group
   8085        {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
   8086          FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
   8087              FCDATA_IS_WRAPPER_ANON_BOX |
   8088              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)},
   8089         PseudoStyleType::tableRowGroup},
   8090        // Column group
   8091        {{ToCreationFunc(NS_NewTableColGroupFrame),
   8092          FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
   8093              FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
   8094              FCDATA_SKIP_ABSPOS_PUSH |
   8095              // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
   8096              // restyle these: they have non-inheriting styles.
   8097              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)},
   8098         PseudoStyleType::tableColGroup},
   8099        // Table
   8100        {{&nsCSSFrameConstructor::ConstructTable,
   8101          FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
   8102              FCDATA_IS_WRAPPER_ANON_BOX},
   8103         PseudoStyleType::table},
   8104        // Ruby
   8105        {{ToCreationFunc(NS_NewRubyFrame),
   8106          FCDATA_IS_LINE_PARTICIPANT | FCDATA_USE_CHILD_ITEMS |
   8107              FCDATA_IS_WRAPPER_ANON_BOX | FCDATA_SKIP_FRAMESET},
   8108         PseudoStyleType::ruby},
   8109        // Ruby Base
   8110        {{ToCreationFunc(NS_NewRubyBaseFrame),
   8111          FCDATA_USE_CHILD_ITEMS | FCDATA_IS_LINE_PARTICIPANT |
   8112              FCDATA_IS_WRAPPER_ANON_BOX |
   8113              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
   8114              FCDATA_SKIP_FRAMESET},
   8115         PseudoStyleType::rubyBase},
   8116        // Ruby Base Container
   8117        {{ToCreationFunc(NS_NewRubyBaseContainerFrame),
   8118          FCDATA_USE_CHILD_ITEMS | FCDATA_IS_LINE_PARTICIPANT |
   8119              FCDATA_IS_WRAPPER_ANON_BOX |
   8120              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
   8121              FCDATA_SKIP_FRAMESET},
   8122         PseudoStyleType::rubyBaseContainer},
   8123        // Ruby Text
   8124        {{ToCreationFunc(NS_NewRubyTextFrame),
   8125          FCDATA_USE_CHILD_ITEMS | FCDATA_IS_LINE_PARTICIPANT |
   8126              FCDATA_IS_WRAPPER_ANON_BOX |
   8127              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
   8128              FCDATA_SKIP_FRAMESET},
   8129         PseudoStyleType::rubyText},
   8130        // Ruby Text Container
   8131        {{ToCreationFunc(NS_NewRubyTextContainerFrame),
   8132          FCDATA_USE_CHILD_ITEMS | FCDATA_IS_WRAPPER_ANON_BOX |
   8133              FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
   8134              FCDATA_SKIP_FRAMESET},
   8135         PseudoStyleType::rubyTextContainer}};
   8136 
   8137 void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
   8138    nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
   8139    nsIFrame* aParentFrame) {
   8140  if (aItems.IsEmpty()) {
   8141    return;
   8142  }
   8143 
   8144  if (!aParentFrame->IsFlexOrGridContainer()) {
   8145    return;
   8146  }
   8147 
   8148  const bool isLegacyWebKitBox =
   8149      IsFlexContainerForLegacyWebKitBox(aParentFrame);
   8150  FCItemIterator iter(aItems);
   8151  do {
   8152    // Advance iter past children that don't want to be wrapped
   8153    if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState,
   8154                                                     isLegacyWebKitBox)) {
   8155      // Hit the end of the items without finding any remaining children that
   8156      // need to be wrapped. We're finished!
   8157      return;
   8158    }
   8159 
   8160    // If our next potentially-wrappable child is whitespace, then see if
   8161    // there's anything wrappable immediately after it. If not, we just drop
   8162    // the whitespace and move on. (We're not supposed to create any anonymous
   8163    // flex/grid items that _only_ contain whitespace).
   8164    // (BUT if this is generated content, then we don't give whitespace nodes
   8165    // any special treatment, because they're probably not really whitespace --
   8166    // they're just temporarily empty, waiting for their generated text.)
   8167    // XXXdholbert If this node's generated text will *actually end up being
   8168    // entirely whitespace*, then we technically should still skip over it, per
   8169    // the CSS grid & flexbox specs. I'm not bothering with that at this point,
   8170    // since it's a pretty extreme edge case.
   8171    if (!aParentFrame->IsGeneratedContentFrame() &&
   8172        iter.item().IsWhitespace(aState)) {
   8173      FCItemIterator afterWhitespaceIter(iter);
   8174      bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
   8175      bool nextChildNeedsAnonItem =
   8176          !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(
   8177                         aState, isLegacyWebKitBox);
   8178 
   8179      if (!nextChildNeedsAnonItem) {
   8180        // There's nothing after the whitespace that we need to wrap, so we
   8181        // just drop this run of whitespace.
   8182        iter.DeleteItemsTo(this, afterWhitespaceIter);
   8183        if (hitEnd) {
   8184          // Nothing left to do -- we're finished!
   8185          return;
   8186        }
   8187        // else, we have a next child and it does not want to be wrapped.  So,
   8188        // we jump back to the beginning of the loop to skip over that child
   8189        // (and anything else non-wrappable after it)
   8190        MOZ_ASSERT(!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem(
   8191                                         aState, isLegacyWebKitBox),
   8192                   "hitEnd and/or nextChildNeedsAnonItem lied");
   8193        continue;
   8194      }
   8195    }
   8196 
   8197    // Now |iter| points to the first child that needs to be wrapped in an
   8198    // anonymous flex/grid item. Now we see how many children after it also want
   8199    // to be wrapped in an anonymous flex/grid item.
   8200    FCItemIterator endIter(iter);  // iterator to find the end of the group
   8201    endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox);
   8202 
   8203    NS_ASSERTION(iter != endIter,
   8204                 "Should've had at least one wrappable child to seek past");
   8205 
   8206    // Now, we create the anonymous flex or grid item to contain the children
   8207    // between |iter| and |endIter|.
   8208    nsIContent* parentContent = aParentFrame->GetContent();
   8209    RefPtr<ComputedStyle> wrapperStyle =
   8210        mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   8211            PseudoStyleType::anonymousItem, aParentFrame->Style());
   8212 
   8213    static constexpr FrameConstructionData sBlockFCData(
   8214        ToCreationFunc(NS_NewBlockFrame), FCDATA_SKIP_FRAMESET |
   8215                                              FCDATA_USE_CHILD_ITEMS |
   8216                                              FCDATA_IS_WRAPPER_ANON_BOX);
   8217 
   8218    // Use the content of our parent frame
   8219    auto* newItem = new (this) FrameConstructionItem(
   8220        &sBlockFCData, parentContent, wrapperStyle.forget(), true);
   8221 
   8222    newItem->mIsAllInline =
   8223        newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
   8224    newItem->mIsBlock = !newItem->mIsAllInline;
   8225 
   8226    MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,
   8227               "expecting anonymous flex/grid items to be block-level "
   8228               "(this will make a difference when we encounter "
   8229               "'align-items: baseline')");
   8230 
   8231    // Anonymous flex and grid items induce line boundaries around their
   8232    // contents.
   8233    newItem->mChildItems.SetLineBoundaryAtStart(true);
   8234    newItem->mChildItems.SetLineBoundaryAtEnd(true);
   8235    // The parent of the items in aItems is also the parent of the items
   8236    // in mChildItems
   8237    newItem->mChildItems.SetParentHasNoShadowDOM(aItems.ParentHasNoShadowDOM());
   8238 
   8239    // Eat up all items between |iter| and |endIter| and put them in our
   8240    // wrapper. This advances |iter| to point to |endIter|.
   8241    iter.AppendItemsToList(this, endIter, newItem->mChildItems);
   8242 
   8243    iter.InsertItem(newItem);
   8244  } while (!iter.IsDone());
   8245 }
   8246 
   8247 /* static */ nsCSSFrameConstructor::RubyWhitespaceType
   8248 nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
   8249                                                 StyleDisplay aNextDisplay) {
   8250  MOZ_ASSERT(aPrevDisplay.IsRuby() && aNextDisplay.IsRuby());
   8251  if (aPrevDisplay == aNextDisplay &&
   8252      (aPrevDisplay == StyleDisplay::RubyBase ||
   8253       aPrevDisplay == StyleDisplay::RubyText)) {
   8254    return eRubyInterLeafWhitespace;
   8255  }
   8256  if (aNextDisplay == StyleDisplay::RubyText ||
   8257      aNextDisplay == StyleDisplay::RubyTextContainer) {
   8258    return eRubyInterLevelWhitespace;
   8259  }
   8260  return eRubyInterSegmentWhitespace;
   8261 }
   8262 
   8263 /**
   8264 * This function checks the content from |aStartIter| to |aEndIter|,
   8265 * determines whether it contains only whitespace, and if yes,
   8266 * interprets the type of whitespace. This method does not change
   8267 * any of the iters.
   8268 */
   8269 /* static */ nsCSSFrameConstructor::RubyWhitespaceType
   8270 nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
   8271                                               const FCItemIterator& aStartIter,
   8272                                               const FCItemIterator& aEndIter) {
   8273  if (!aStartIter.item().IsWhitespace(aState)) {
   8274    return eRubyNotWhitespace;
   8275  }
   8276 
   8277  FCItemIterator spaceEndIter(aStartIter);
   8278  spaceEndIter.SkipWhitespace(aState);
   8279  if (spaceEndIter != aEndIter) {
   8280    return eRubyNotWhitespace;
   8281  }
   8282 
   8283  // Any leading or trailing whitespace in non-pseudo ruby box
   8284  // should have been trimmed, hence there should not be any
   8285  // whitespace at the start or the end.
   8286  MOZ_ASSERT(!aStartIter.AtStart() && !aEndIter.IsDone());
   8287  FCItemIterator prevIter(aStartIter);
   8288  prevIter.Prev();
   8289  return ComputeRubyWhitespaceType(
   8290      prevIter.item().mComputedStyle->StyleDisplay()->mDisplay,
   8291      aEndIter.item().mComputedStyle->StyleDisplay()->mDisplay);
   8292 }
   8293 
   8294 /**
   8295 * This function eats up consecutive items which do not want the current
   8296 * parent into either a ruby base box or a ruby text box.  When it
   8297 * returns, |aIter| points to the first item it doesn't wrap.
   8298 */
   8299 void nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
   8300    FCItemIterator& aIter, ComputedStyle* aParentStyle,
   8301    nsIContent* aParentContent) {
   8302  StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
   8303  ParentType parentType, wrapperType;
   8304  if (parentDisplay == StyleDisplay::RubyTextContainer) {
   8305    parentType = eTypeRubyTextContainer;
   8306    wrapperType = eTypeRubyText;
   8307  } else {
   8308    MOZ_ASSERT(parentDisplay == StyleDisplay::RubyBaseContainer);
   8309    parentType = eTypeRubyBaseContainer;
   8310    wrapperType = eTypeRubyBase;
   8311  }
   8312 
   8313  MOZ_ASSERT(aIter.item().DesiredParentType() != parentType,
   8314             "Should point to something needs to be wrapped.");
   8315 
   8316  FCItemIterator endIter(aIter);
   8317  endIter.SkipItemsNotWantingParentType(parentType);
   8318 
   8319  WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
   8320                          endIter);
   8321 }
   8322 
   8323 /**
   8324 * This function eats up consecutive items into a ruby level container.
   8325 * It may create zero or one level container. When it returns, |aIter|
   8326 * points to the first item it doesn't wrap.
   8327 */
   8328 void nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
   8329    nsFrameConstructorState& aState, FCItemIterator& aIter,
   8330    ComputedStyle* aParentStyle, nsIContent* aParentContent) {
   8331  MOZ_ASSERT(aIter.item().DesiredParentType() != eTypeRuby,
   8332             "Pointing to a level container?");
   8333 
   8334  FrameConstructionItem& firstItem = aIter.item();
   8335  ParentType wrapperType = firstItem.DesiredParentType();
   8336  if (wrapperType != eTypeRubyTextContainer) {
   8337    // If the first item is not ruby text,
   8338    // it should be in a base container.
   8339    wrapperType = eTypeRubyBaseContainer;
   8340  }
   8341 
   8342  FCItemIterator endIter(aIter);
   8343  do {
   8344    if (endIter.SkipItemsWantingParentType(wrapperType) ||
   8345        // If the skipping above stops at some item which wants a
   8346        // different ruby parent, then we have finished.
   8347        IsRubyParentType(endIter.item().DesiredParentType())) {
   8348      // No more items need to be wrapped in this level container.
   8349      break;
   8350    }
   8351 
   8352    FCItemIterator contentEndIter(endIter);
   8353    contentEndIter.SkipItemsNotWantingRubyParent();
   8354    // endIter must be on something doesn't want a ruby parent.
   8355    MOZ_ASSERT(contentEndIter != endIter);
   8356 
   8357    // InterpretRubyWhitespace depends on the fact that any leading or
   8358    // trailing whitespace described in the spec have been trimmed at
   8359    // this point. With this precondition, it is safe not to check
   8360    // whether contentEndIter has been done.
   8361    RubyWhitespaceType whitespaceType =
   8362        InterpretRubyWhitespace(aState, endIter, contentEndIter);
   8363    if (whitespaceType == eRubyInterLevelWhitespace) {
   8364      // Remove inter-level whitespace.
   8365      bool atStart = (aIter == endIter);
   8366      endIter.DeleteItemsTo(this, contentEndIter);
   8367      if (atStart) {
   8368        aIter = endIter;
   8369      }
   8370    } else if (whitespaceType == eRubyInterSegmentWhitespace) {
   8371      // If this level container starts with inter-segment whitespaces,
   8372      // wrap them. Break at contentEndIter. Otherwise, leave it here.
   8373      // Break at endIter. They will be wrapped when we are here again.
   8374      if (aIter == endIter) {
   8375        MOZ_ASSERT(wrapperType == eTypeRubyBaseContainer,
   8376                   "Inter-segment whitespace should be wrapped in rbc");
   8377        endIter = contentEndIter;
   8378      }
   8379      break;
   8380    } else if (wrapperType == eTypeRubyTextContainer &&
   8381               whitespaceType != eRubyInterLeafWhitespace) {
   8382      // Misparented inline content that's not inter-annotation
   8383      // whitespace doesn't belong in a pseudo ruby text container.
   8384      // Break at endIter.
   8385      break;
   8386    } else {
   8387      endIter = contentEndIter;
   8388    }
   8389  } while (!endIter.IsDone());
   8390 
   8391  // It is possible that everything our parent wants us to wrap is
   8392  // simply an inter-level whitespace, which has been trimmed, or
   8393  // an inter-segment whitespace, which will be wrapped later.
   8394  // In those cases, don't create anything.
   8395  if (aIter != endIter) {
   8396    WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
   8397                            endIter);
   8398  }
   8399 }
   8400 
   8401 /**
   8402 * This function trims leading and trailing whitespaces
   8403 * in the given item list.
   8404 */
   8405 void nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
   8406    nsFrameConstructorState& aState, FrameConstructionItemList& aItems) {
   8407  FCItemIterator iter(aItems);
   8408  if (!iter.IsDone() && iter.item().IsWhitespace(aState)) {
   8409    FCItemIterator spaceEndIter(iter);
   8410    spaceEndIter.SkipWhitespace(aState);
   8411    iter.DeleteItemsTo(this, spaceEndIter);
   8412  }
   8413 
   8414  iter.SetToEnd();
   8415  if (!iter.AtStart()) {
   8416    FCItemIterator spaceEndIter(iter);
   8417    do {
   8418      iter.Prev();
   8419      if (iter.AtStart()) {
   8420        // It's fine to not check the first item, because we
   8421        // should have trimmed leading whitespaces above.
   8422        break;
   8423      }
   8424    } while (iter.item().IsWhitespace(aState));
   8425    iter.Next();
   8426    if (iter != spaceEndIter) {
   8427      iter.DeleteItemsTo(this, spaceEndIter);
   8428    }
   8429  }
   8430 }
   8431 
   8432 /**
   8433 * This function walks through the child list (aItems) and creates
   8434 * needed pseudo ruby boxes to wrap misparented children.
   8435 */
   8436 void nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
   8437    nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
   8438    nsIFrame* aParentFrame) {
   8439  const ParentType ourParentType = GetParentType(aParentFrame);
   8440  if (!IsRubyParentType(ourParentType) ||
   8441      aItems.AllWantParentType(ourParentType)) {
   8442    return;
   8443  }
   8444 
   8445  if (!IsRubyPseudo(aParentFrame) ||
   8446      ourParentType == eTypeRuby /* for 'display:block ruby' */) {
   8447    // Normally, ruby pseudo frames start from and end at some elements,
   8448    // which means they don't have leading and trailing whitespaces at
   8449    // all.  But there are two cases where they do actually have leading
   8450    // or trailing whitespaces:
   8451    // 1. It is an inter-segment whitespace which in an individual ruby
   8452    //    base container.
   8453    // 2. The pseudo frame starts from or ends at consecutive inline
   8454    //    content, which is not pure whitespace, but includes some.
   8455    // In either case, the whitespaces are not the leading or trailing
   8456    // whitespaces defined in the spec, and thus should not be trimmed.
   8457    TrimLeadingAndTrailingWhitespaces(aState, aItems);
   8458  }
   8459 
   8460  FCItemIterator iter(aItems);
   8461  nsIContent* parentContent = aParentFrame->GetContent();
   8462  ComputedStyle* parentStyle = aParentFrame->Style();
   8463  while (!iter.IsDone()) {
   8464    if (!iter.SkipItemsWantingParentType(ourParentType)) {
   8465      if (ourParentType == eTypeRuby) {
   8466        WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
   8467                                            parentContent);
   8468      } else {
   8469        WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
   8470      }
   8471    }
   8472  }
   8473 }
   8474 
   8475 /*
   8476 * This function works as follows: we walk through the child list (aItems) and
   8477 * find items that cannot have aParentFrame as their parent.  We wrap
   8478 * continuous runs of such items into a FrameConstructionItem for a frame that
   8479 * gets them closer to their desired parents.  For example, a run of non-row
   8480 * children of a row-group will get wrapped in a row.  When we later construct
   8481 * the frame for this wrapper (in this case for the row), it'll be the correct
   8482 * parent for the cells in the set of items we wrapped or we'll wrap cells
   8483 * around everything else.  At the end of this method, aItems is guaranteed to
   8484 * contain only items for frames that can be direct kids of aParentFrame.
   8485 */
   8486 void nsCSSFrameConstructor::CreateNeededPseudoContainers(
   8487    nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
   8488    nsIFrame* aParentFrame) {
   8489  ParentType ourParentType = GetParentType(aParentFrame);
   8490  if (IsRubyParentType(ourParentType) ||
   8491      aItems.AllWantParentType(ourParentType)) {
   8492    // Nothing to do here
   8493    return;
   8494  }
   8495 
   8496  FCItemIterator iter(aItems);
   8497  do {
   8498    if (iter.SkipItemsWantingParentType(ourParentType)) {
   8499      // Nothing else to do here; we're finished
   8500      return;
   8501    }
   8502 
   8503    // Now we're pointing to the first child that wants a different parent
   8504    // type.
   8505 
   8506    // Now try to figure out what kids we can group together.  We can generally
   8507    // group everything that has a different desired parent type from us.  Two
   8508    // exceptions to this:
   8509    // 1) If our parent type is table, we can't group columns with anything
   8510    //    else other than whitespace.
   8511    // 2) Whitespace that lies between two things we can group which both want
   8512    //    a non-block parent should be dropped, even if we can't group them
   8513    //    with each other and even if the whitespace wants a parent of
   8514    //    ourParentType.  Ends of the list count as things that don't want a
   8515    //    block parent (so that for example we'll drop a whitespace-only list).
   8516 
   8517    FCItemIterator endIter(iter); /* iterator to find the end of the group */
   8518    ParentType groupingParentType = endIter.item().DesiredParentType();
   8519    if (aItems.AllWantParentType(groupingParentType) &&
   8520        groupingParentType != eTypeBlock) {
   8521      // Just group them all and be done with it.  We need the check for
   8522      // eTypeBlock here to catch the "all the items are whitespace" case
   8523      // described above.
   8524      endIter.SetToEnd();
   8525    } else {
   8526      // Locate the end of the group.
   8527 
   8528      // Keep track of the type the previous item wanted, in case we have to
   8529      // deal with whitespace.  Start it off with ourParentType, since that's
   8530      // the last thing |iter| would have skipped over.
   8531      ParentType prevParentType = ourParentType;
   8532      do {
   8533        // Walk an iterator past any whitespace that we might be able to drop
   8534        // from the list
   8535        FCItemIterator spaceEndIter(endIter);
   8536        if (prevParentType != eTypeBlock &&
   8537            !aParentFrame->IsGeneratedContentFrame() &&
   8538            spaceEndIter.item().IsWhitespace(aState)) {
   8539          bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
   8540 
   8541          // We drop the whitespace in the following cases:
   8542          // 1) If these are not trailing spaces and the next item wants a table
   8543          //    or table-part parent
   8544          // 2) If these are trailing spaces and aParentFrame is a
   8545          //    tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
   8546          //    (Being a tabular container pretty much means ourParentType is
   8547          //    not eTypeBlock besides the eTypeColGroup case, which won't
   8548          //    reach here.)
   8549          if ((!trailingSpaces &&
   8550               IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
   8551              (trailingSpaces && ourParentType != eTypeBlock)) {
   8552            bool updateStart = (iter == endIter);
   8553            endIter.DeleteItemsTo(this, spaceEndIter);
   8554            NS_ASSERTION(trailingSpaces == endIter.IsDone(),
   8555                         "These should match");
   8556 
   8557            if (updateStart) {
   8558              iter = endIter;
   8559            }
   8560 
   8561            if (trailingSpaces) {
   8562              break; /* Found group end */
   8563            }
   8564 
   8565            if (updateStart) {
   8566              // Update groupingParentType, since it might have been eTypeBlock
   8567              // just because of the whitespace.
   8568              groupingParentType = iter.item().DesiredParentType();
   8569            }
   8570          }
   8571        }
   8572 
   8573        // Now endIter points to a non-whitespace item or a non-droppable
   8574        // whitespace item. In the latter case, if this is the end of the group
   8575        // we'll traverse this whitespace again.  But it'll all just be quick
   8576        // DesiredParentType() checks which will match ourParentType (that's
   8577        // what it means that this is the group end), so it's OK.
   8578        // However, when we are grouping a ruby parent, and endIter points to
   8579        // a non-droppable whitespace, if the next non-whitespace item also
   8580        // wants a ruby parent, the whitespace should also be included into
   8581        // the current ruby container.
   8582        prevParentType = endIter.item().DesiredParentType();
   8583        if (prevParentType == ourParentType &&
   8584            (endIter == spaceEndIter || spaceEndIter.IsDone() ||
   8585             !IsRubyParentType(groupingParentType) ||
   8586             !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
   8587          // End the group at endIter.
   8588          break;
   8589        }
   8590 
   8591        if (ourParentType == eTypeTable &&
   8592            (prevParentType == eTypeColGroup) !=
   8593                (groupingParentType == eTypeColGroup)) {
   8594          // Either we started with columns and now found something else, or
   8595          // vice versa.  In any case, end the grouping.
   8596          break;
   8597        }
   8598 
   8599        // If we have some whitespace that we were not able to drop and there is
   8600        // an item after the whitespace that is already properly parented, then
   8601        // make sure to include the spaces in our group but stop the group after
   8602        // that.
   8603        if (spaceEndIter != endIter && !spaceEndIter.IsDone() &&
   8604            ourParentType == spaceEndIter.item().DesiredParentType()) {
   8605          endIter = spaceEndIter;
   8606          break;
   8607        }
   8608 
   8609        // Include the whitespace we didn't drop (if any) in the group.
   8610        endIter = spaceEndIter;
   8611        prevParentType = endIter.item().DesiredParentType();
   8612 
   8613        endIter.Next();
   8614      } while (!endIter.IsDone());
   8615    }
   8616 
   8617    if (iter == endIter) {
   8618      // Nothing to wrap here; just skipped some whitespace
   8619      continue;
   8620    }
   8621 
   8622    // Now group together all the items between iter and endIter.  The right
   8623    // parent type to use depends on ourParentType.
   8624    ParentType wrapperType;
   8625    switch (ourParentType) {
   8626      case eTypeRow:
   8627        // The parent type for a cell is eTypeBlock, since that's what a cell
   8628        // looks like to its kids.
   8629        wrapperType = eTypeBlock;
   8630        break;
   8631      case eTypeRowGroup:
   8632        wrapperType = eTypeRow;
   8633        break;
   8634      case eTypeTable:
   8635        // Either colgroup or rowgroup, depending on what we're grouping.
   8636        wrapperType =
   8637            groupingParentType == eTypeColGroup ? eTypeColGroup : eTypeRowGroup;
   8638        break;
   8639      case eTypeColGroup:
   8640        MOZ_CRASH("Colgroups should be suppresing non-col child items");
   8641      default:
   8642        NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type");
   8643        if (IsRubyParentType(groupingParentType)) {
   8644          wrapperType = eTypeRuby;
   8645        } else {
   8646          NS_ASSERTION(IsTableParentType(groupingParentType),
   8647                       "groupingParentType should be either Ruby or table");
   8648          wrapperType = eTypeTable;
   8649        }
   8650    }
   8651 
   8652    ComputedStyle* parentStyle = aParentFrame->Style();
   8653    WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
   8654                            wrapperType, iter, endIter);
   8655 
   8656    // Now |iter| points to the item that was the first one we didn't wrap;
   8657    // loop and see whether we need to skip it or wrap it in something
   8658    // different.
   8659  } while (!iter.IsDone());
   8660 }
   8661 
   8662 /**
   8663 * This method wraps frame construction item from |aIter| to
   8664 * |aEndIter|. After it returns, aIter points to the first item
   8665 * after the wrapper.
   8666 */
   8667 void nsCSSFrameConstructor::WrapItemsInPseudoParent(
   8668    nsIContent* aParentContent, ComputedStyle* aParentStyle,
   8669    ParentType aWrapperType, FCItemIterator& aIter,
   8670    const FCItemIterator& aEndIter) {
   8671  const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
   8672  PseudoStyleType pseudoType = pseudoData.mPseudoType;
   8673  auto& parentDisplay = *aParentStyle->StyleDisplay();
   8674  auto parentDisplayInside = parentDisplay.DisplayInside();
   8675 
   8676  // XXXmats should we use IsInlineInsideStyle() here instead? seems odd to
   8677  // exclude RubyBaseContainer/RubyTextContainer...
   8678  if (pseudoType == PseudoStyleType::table &&
   8679      (parentDisplay.IsInlineFlow() ||
   8680       parentDisplayInside == StyleDisplayInside::RubyBase ||
   8681       parentDisplayInside == StyleDisplayInside::RubyText)) {
   8682    pseudoType = PseudoStyleType::inlineTable;
   8683  }
   8684 
   8685  RefPtr<ComputedStyle> wrapperStyle;
   8686  if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX) {
   8687    wrapperStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   8688        pseudoType, aParentStyle);
   8689  } else {
   8690    wrapperStyle =
   8691        mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
   8692            pseudoType);
   8693  }
   8694 
   8695  // Use the content of our parent frame
   8696  auto* newItem = new (this) FrameConstructionItem(
   8697      &pseudoData.mFCData, aParentContent, wrapperStyle.forget(), true);
   8698 
   8699  const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
   8700  // Here we're cheating a tad... technically, table-internal items should be
   8701  // inline if aParentFrame is inline, but they'll get wrapped in an
   8702  // inline-table in the end, so it'll all work out.  In any case, arguably
   8703  // we don't need to maintain this state at this point... but it's better
   8704  // to, I guess.
   8705  newItem->mIsAllInline = disp->IsInlineOutsideStyle();
   8706 
   8707  bool isRuby = disp->IsRubyDisplayType();
   8708  if (!isRuby) {
   8709    // Table pseudo frames always induce line boundaries around their
   8710    // contents.
   8711    newItem->mChildItems.SetLineBoundaryAtStart(true);
   8712    newItem->mChildItems.SetLineBoundaryAtEnd(true);
   8713  }
   8714  // The parent of the items in aItems is also the parent of the items
   8715  // in mChildItems
   8716  newItem->mChildItems.SetParentHasNoShadowDOM(
   8717      aIter.List()->ParentHasNoShadowDOM());
   8718 
   8719  // Eat up all items between |aIter| and |aEndIter| and put them in our
   8720  // wrapper Advances |aIter| to point to |aEndIter|.
   8721  aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
   8722 
   8723  aIter.InsertItem(newItem);
   8724 }
   8725 
   8726 void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
   8727    nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
   8728    nsIFrame* aParentFrame) {
   8729  if (aItems.IsEmpty() || GetParentType(aParentFrame) != eTypeRuby) {
   8730    return;
   8731  }
   8732 
   8733  FCItemIterator iter(aItems);
   8734  StyleDisplay firstDisplay =
   8735      iter.item().mComputedStyle->StyleDisplay()->mDisplay;
   8736  if (firstDisplay == StyleDisplay::RubyBaseContainer) {
   8737    return;
   8738  }
   8739  NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,
   8740               "Child of ruby frame should either a rbc or a rtc");
   8741 
   8742  const PseudoParentData& pseudoData =
   8743      sPseudoParentData[eTypeRubyBaseContainer];
   8744  RefPtr<ComputedStyle> pseudoStyle =
   8745      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
   8746          pseudoData.mPseudoType, aParentFrame->Style());
   8747  FrameConstructionItem* newItem = new (this) FrameConstructionItem(
   8748      &pseudoData.mFCData,
   8749      // Use the content of the parent frame
   8750      aParentFrame->GetContent(), pseudoStyle.forget(), true);
   8751  newItem->mIsAllInline = true;
   8752  newItem->mChildItems.SetParentHasNoShadowDOM(true);
   8753  iter.InsertItem(newItem);
   8754 }
   8755 
   8756 #ifdef DEBUG
   8757 /**
   8758 * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
   8759 * rather than being a direct child of aContainerFrame.
   8760 *
   8761 * NOTE: aContainerFrame must be a flex or grid container - this function is
   8762 * purely for sanity-checking the children of these container types.
   8763 * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
   8764 * logic (which operates a bit earlier, on FCData instead of frames).
   8765 */
   8766 static bool FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
   8767                                          const nsIFrame* aFrame) {
   8768  MOZ_ASSERT(aContainerFrame->IsFlexOrGridContainer());
   8769 
   8770  // Any line-participant frames (e.g. text) definitely want to be wrapped in
   8771  // an anonymous flex/grid item.
   8772  if (aFrame->IsLineParticipant()) {
   8773    return true;
   8774  }
   8775 
   8776  // If the container is a -webkit-{inline-}box container, then placeholders
   8777  // also need to be wrapped, for compatibility.
   8778  if (IsFlexContainerForLegacyWebKitBox(aContainerFrame) &&
   8779      aFrame->IsPlaceholderFrame()) {
   8780    return true;
   8781  }
   8782 
   8783  return false;
   8784 }
   8785 #endif
   8786 
   8787 static void VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
   8788                                            const nsFrameList& aChildren) {
   8789 #ifdef DEBUG
   8790  if (!aParentFrame->IsFlexOrGridContainer()) {
   8791    return;
   8792  }
   8793 
   8794  bool prevChildWasAnonItem = false;
   8795  for (const nsIFrame* child : aChildren) {
   8796    MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(aParentFrame, child),
   8797               "frame wants to be inside an anonymous item, but it isn't");
   8798    if (IsAnonymousItem(child)) {
   8799      AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
   8800      MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row");
   8801      nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
   8802      MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty");
   8803      prevChildWasAnonItem = true;
   8804    } else {
   8805      prevChildWasAnonItem = false;
   8806    }
   8807  }
   8808 #endif
   8809 }
   8810 
   8811 static bool FrameHasOnlyPlaceholderPrevSiblings(const nsIFrame* aFrame) {
   8812  // Check for prev siblings, ignoring placeholder frames.
   8813  MOZ_ASSERT(aFrame, "frame must not be null");
   8814  const nsIFrame* prevSibling = aFrame;
   8815  do {
   8816    prevSibling = prevSibling->GetPrevSibling();
   8817  } while (prevSibling && prevSibling->IsPlaceholderFrame());
   8818  return !prevSibling;
   8819 }
   8820 
   8821 static bool FrameHasOnlyPlaceholderNextSiblings(const nsIFrame* aFrame) {
   8822  // Check for next siblings, ignoring placeholder frames.
   8823  MOZ_ASSERT(aFrame, "frame must not be null");
   8824  const nsIFrame* nextSibling = aFrame;
   8825  do {
   8826    nextSibling = nextSibling->GetNextSibling();
   8827  } while (nextSibling && nextSibling->IsPlaceholderFrame());
   8828  return !nextSibling;
   8829 }
   8830 
   8831 static void SetPageValues(nsIFrame* const aFrame,
   8832                          const nsAtom* const aAutoValue,
   8833                          const nsAtom* const aStartValue,
   8834                          const nsAtom* const aEndValue) {
   8835  MOZ_ASSERT(aAutoValue, "Auto page value should never be null");
   8836  MOZ_ASSERT(aStartValue || aEndValue, "Should not have called with no values");
   8837  nsIFrame::PageValues* pageValues =
   8838      aFrame->GetProperty(nsIFrame::PageValuesProperty());
   8839 
   8840  if (aStartValue) {
   8841    if (aStartValue == aAutoValue) {
   8842      // If the page value struct already exists, set the start value to null
   8843      // to indicate the auto value.
   8844      if (pageValues) {
   8845        pageValues->mStartPageValue = nullptr;
   8846      }
   8847    } else {
   8848      // The start value is not auto, so we need to store it, creating the
   8849      // page values struct if it does not already exist.
   8850      if (!pageValues) {
   8851        pageValues = new nsIFrame::PageValues();
   8852        aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
   8853      }
   8854      pageValues->mStartPageValue = aStartValue;
   8855    }
   8856  }
   8857  if (aEndValue) {
   8858    if (aEndValue == aAutoValue) {
   8859      // If the page value struct already exists, set the end value to null
   8860      // to indicate the auto value.
   8861      if (pageValues) {
   8862        pageValues->mEndPageValue = nullptr;
   8863      }
   8864    } else {
   8865      // The end value is not auto, so we need to store it, creating the
   8866      // page values struct if it does not already exist.
   8867      if (!pageValues) {
   8868        pageValues = new nsIFrame::PageValues();
   8869        aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
   8870      }
   8871      pageValues->mEndPageValue = aEndValue;
   8872    }
   8873  }
   8874 }
   8875 
   8876 inline void nsCSSFrameConstructor::ConstructFramesFromItemList(
   8877    nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
   8878    nsContainerFrame* aParentFrame, bool aParentIsWrapperAnonBox,
   8879    nsFrameList& aFrameList) {
   8880 #ifdef DEBUG
   8881  // The assertion condition should match the logic in
   8882  // MaybePushFloatContainingBlock().
   8883  MOZ_ASSERT(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
   8884               aParentFrame->IsFloatContainingBlock()) ||
   8885                 aState.mFloatCBCandidate == aParentFrame,
   8886             "Our caller or ProcessChildren()'s caller should call "
   8887             "MaybePushFloatContainingBlock() to handle the float containing "
   8888             "block candidate!");
   8889  aState.mFloatCBCandidate = nullptr;
   8890 #endif
   8891 
   8892  // Ensure aParentIsWrapperAnonBox is correct.  We _could_ compute it directly,
   8893  // but it would be a bit slow, which is why we pass it from callers, who have
   8894  // that information offhand in many cases.
   8895  MOZ_ASSERT(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox);
   8896 
   8897  // Note: we explicitly exclude TableColGroupFrame because it doesn't
   8898  // have the FCDATA_IS_WRAPPER_ANON_BOX on pseudos so aParentIsWrapperAnonBox
   8899  // is false for such pseudos (see sPseudoParentData below).
   8900  if (!aParentIsWrapperAnonBox && aState.mHasRenderedLegend &&
   8901      aParentFrame->GetContent()->IsHTMLElement(nsGkAtoms::fieldset) &&
   8902      !aParentFrame->IsTableColGroupFrame()) {
   8903    DebugOnly<bool> found = false;
   8904    for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
   8905      if (iter.item().mIsRenderedLegend) {
   8906        // This makes the rendered legend the first frame in the fieldset child
   8907        // list which makes keyboard traversal follow the visual order.
   8908        nsFieldSetFrame* fieldSetFrame = GetFieldSetFrameFor(aParentFrame);
   8909        nsFrameList renderedLegend;
   8910        ConstructFramesFromItem(aState, iter, fieldSetFrame, renderedLegend);
   8911        MOZ_ASSERT(renderedLegend.OnlyChild(),
   8912                   "a rendered legend should have exactly one frame");
   8913        fieldSetFrame->InsertFrames(FrameChildListID::Principal, nullptr,
   8914                                    nullptr, std::move(renderedLegend));
   8915        FCItemIterator next = iter;
   8916        next.Next();
   8917        iter.DeleteItemsTo(this, next);
   8918        found = true;
   8919        break;
   8920      }
   8921    }
   8922    MOZ_ASSERT(found, "should have found our rendered legend");
   8923  }
   8924 
   8925  CreateNeededPseudoContainers(aState, aItems, aParentFrame);
   8926  CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
   8927  CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
   8928  CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
   8929 
   8930  for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
   8931    MOZ_ASSERT(!iter.item().mIsRenderedLegend,
   8932               "Only one item can be the rendered legend, "
   8933               "and it should've been handled above");
   8934    NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
   8935                 "Needed pseudos didn't get created; expect bad things");
   8936    ConstructFramesFromItem(aState, iter, aParentFrame, aFrameList);
   8937  }
   8938 
   8939  VerifyGridFlexContainerChildren(aParentFrame, aFrameList);
   8940 
   8941  // Calculate and propagate page-name values for each frame in the frame list.
   8942  // We do not want to compute and propagate page-name values from frames that
   8943  // are children of any subclasses of block frames, but not actually a block
   8944  // frame. The page-name property does not apply to frames which cannot create
   8945  // class A breakpoints (currently no subclass of BlockFrame can). Because the
   8946  // property does not apply, those children also cannot propagate page-name
   8947  // values.
   8948  // This assumption helps avoid unnecessarily handling page-names for frames
   8949  // such as form controls, which also avoids bug 1819468.
   8950  if (aState.mPresContext->IsPaginated() && aParentFrame->IsBlockFrame()) {
   8951    // Set the start/end page values while iterating the frame list, to walk
   8952    // up the frame tree only once after iterating the frame list.
   8953    // This also avoids extra property lookups on these frames.
   8954    MOZ_ASSERT(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue(),
   8955               "aState.mAutoPageNameValue should have been equivalent to "
   8956               "the auto value stored on our parent frame.");
   8957    // Even though we store null for page values that equal the "auto" resolved
   8958    // value on frames, we always want startPageValue/endPageValue to be the
   8959    // actual atoms reflecting the start/end values. This is because when we
   8960    // propagate the values up the frame tree, we will need to compare them to
   8961    // the auto value for each ancestor. This value might be different than the
   8962    // auto value for this frame.
   8963    const nsAtom* startPageValue = nullptr;
   8964    const nsAtom* endPageValue = nullptr;
   8965    for (nsIFrame* f : aFrameList) {
   8966      if (f->IsPlaceholderFrame()) {
   8967        continue;
   8968      }
   8969      // Resolve auto against the parent frame's used page name, which has been
   8970      // determined and set on aState.mAutoPageNameValue. If this item is not
   8971      // block-level then we use the value that auto resolves to.
   8972      //
   8973      // This is to achieve the propagation behavior described in the spec:
   8974      //
   8975      // "A start page value and end page value is determined for each box as
   8976      //  the value (if any) propagated from its first or last child box
   8977      //  (respectively), else the used value on the box itself."
   8978      //
   8979      // "A child propagates its own start or end page value if and only if the
   8980      //  page property applies to it."
   8981      //
   8982      // The page property only applies to "boxes that create class A break
   8983      // points". When taken together, this means that non block-level children
   8984      // do not propagate start/end page values, and instead we use "the used
   8985      // value on the box itself", the "box itself" being aParentFrame. This
   8986      // value has been determined and saved as aState.mAutoPageNameValue
   8987      //
   8988      // https://www.w3.org/TR/css-page-3/#using-named-pages
   8989      // https://www.w3.org/TR/css-break-3/#btw-blocks
   8990      const StylePageName& pageName = f->StylePage()->mPage;
   8991      const nsAtom* const pageNameAtom =
   8992          (pageName.IsPageName() && f->IsBlockOutside())
   8993              ? pageName.AsPageName().AsAtom()
   8994              : aState.mAutoPageNameValue;
   8995      nsIFrame::PageValues* pageValues =
   8996          f->GetProperty(nsIFrame::PageValuesProperty());
   8997      // If this frame has any children, it will already have had its page
   8998      // values set at this point. However, if no page values have been set,
   8999      // we must ensure that the appropriate PageValuesProperty value has been
   9000      // set.
   9001      // If the page name is equal to the auto value, then PageValuesProperty
   9002      // should remain null to indicate that the start/end values are both
   9003      // equal to the auto value.
   9004      if (pageNameAtom != aState.mAutoPageNameValue && !pageValues) {
   9005        pageValues = new nsIFrame::PageValues{pageNameAtom, pageNameAtom};
   9006        f->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
   9007      }
   9008      // We don't want to use GetStartPageValue() or GetEndPageValue(), as each
   9009      // requires a property lookup which we can avoid here.
   9010      if (!startPageValue) {
   9011        startPageValue = (pageValues && pageValues->mStartPageValue)
   9012                             ? pageValues->mStartPageValue.get()
   9013                             : aState.mAutoPageNameValue;
   9014      }
   9015      endPageValue = (pageValues && pageValues->mEndPageValue)
   9016                         ? pageValues->mEndPageValue.get()
   9017                         : aState.mAutoPageNameValue;
   9018      MOZ_ASSERT(startPageValue && endPageValue,
   9019                 "Should have found start/end page value");
   9020    }
   9021    MOZ_ASSERT(!startPageValue == !endPageValue,
   9022               "Should have set both or neither page values");
   9023    if (startPageValue) {
   9024      // Walk up the frame tree from our parent frame, propagating start and
   9025      // end page values.
   9026      // As we go, if we find that, for a frame, we are not contributing one of
   9027      // the start/end page values, then our subtree will not contribute this
   9028      // value from that frame onward. startPageValue/endPageValue are set to
   9029      // null to indicate this.
   9030      // Stop iterating when we are not contributing either start or end
   9031      // values, when we hit the root frame (no parent), or when we find a
   9032      // frame that is not a block frame.
   9033      for (nsContainerFrame* ancestorFrame = aParentFrame;
   9034           (startPageValue || endPageValue) && ancestorFrame &&
   9035           ancestorFrame->IsBlockFrame();
   9036           ancestorFrame = ancestorFrame->GetParent()) {
   9037        MOZ_ASSERT(!ancestorFrame->GetPrevInFlow(),
   9038                   "Should not have fragmentation yet");
   9039        MOZ_ASSERT(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName,
   9040                   "Frame should have been visited by "
   9041                   "AutoFrameConstructionPageName");
   9042        {
   9043          // Get what the auto value is, based on this frame's parent.
   9044          // For the root frame, `auto` resolves to the empty atom.
   9045          const nsContainerFrame* const parent = ancestorFrame->GetParent();
   9046          const nsAtom* const parentAuto = MOZ_LIKELY(parent)
   9047                                               ? parent->GetAutoPageValue()
   9048                                               : nsGkAtoms::_empty;
   9049          SetPageValues(ancestorFrame, parentAuto, startPageValue,
   9050                        endPageValue);
   9051        }
   9052        // Once we stop contributing start/end values, we know there is a
   9053        // sibling subtree that contributed that value to our shared parent
   9054        // instead of our starting frame's subtree. This means once
   9055        // startPageValue/endPageValue becomes null, indicating that we are no
   9056        // longer contributing that page value, it should stay null and we no
   9057        // longer need to check for siblings in that direction.
   9058        if (startPageValue &&
   9059            !FrameHasOnlyPlaceholderPrevSiblings(ancestorFrame)) {
   9060          startPageValue = nullptr;
   9061        }
   9062        if (endPageValue &&
   9063            !FrameHasOnlyPlaceholderNextSiblings(ancestorFrame)) {
   9064          endPageValue = nullptr;
   9065        }
   9066      }
   9067    }
   9068  }
   9069 
   9070  if (aParentIsWrapperAnonBox) {
   9071    for (nsIFrame* f : aFrameList) {
   9072      f->SetParentIsWrapperAnonBox();
   9073    }
   9074  }
   9075 }
   9076 
   9077 void nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
   9078    nsFrameConstructorState& aState, nsContainerFrame* aFrame,
   9079    const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
   9080    FrameConstructionItemList& aItemsToConstruct,
   9081    const AutoFrameConstructionPageName&) {
   9082  for (const auto& info : aAnonymousItems) {
   9083    nsIContent* content = info.mContent;
   9084    // Gecko-styled nodes should have no pending restyle flags.
   9085    // Assert some things about this content
   9086    MOZ_ASSERT(!(content->GetFlags() &
   9087                 (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
   9088               "Should not be marked as needing frames");
   9089    MOZ_ASSERT(!content->GetPrimaryFrame(), "Should have no existing frame");
   9090    MOZ_ASSERT(!content->IsComment() && !content->IsProcessingInstruction(),
   9091               "Why is someone creating garbage anonymous content");
   9092 
   9093    // Make sure we eagerly performed the servo cascade when the anonymous
   9094    // nodes were created.
   9095    MOZ_ASSERT(!content->IsElement() || content->AsElement()->HasServoData());
   9096 
   9097    RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(content);
   9098 
   9099    AddFrameConstructionItemsInternal(aState, content, aFrame, true,
   9100                                      computedStyle, {ItemFlag::AllowPageBreak},
   9101                                      aItemsToConstruct);
   9102  }
   9103 }
   9104 
   9105 void nsCSSFrameConstructor::ProcessChildren(
   9106    nsFrameConstructorState& aState, nsIContent* aContent,
   9107    ComputedStyle* aComputedStyle, nsContainerFrame* aFrame,
   9108    const bool aCanHaveGeneratedContent, nsFrameList& aFrameList,
   9109    const bool aAllowBlockStyles, nsIFrame* aPossiblyLeafFrame) {
   9110  MOZ_ASSERT(aFrame, "Must have parent frame here");
   9111  MOZ_ASSERT(aFrame->GetContentInsertionFrame() == aFrame,
   9112             "Parent frame in ProcessChildren should be its own "
   9113             "content insertion frame");
   9114 
   9115  const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
   9116  static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
   9117  AutoRestore<uint16_t> savedDepth(mCurrentDepth);
   9118  if (mCurrentDepth != UINT16_MAX) {
   9119    ++mCurrentDepth;
   9120  }
   9121 
   9122  if (!aPossiblyLeafFrame) {
   9123    aPossiblyLeafFrame = aFrame;
   9124  }
   9125 
   9126  // XXXbz ideally, this would do all the pushing of various
   9127  // containing blocks as needed, so callers don't have to do it...
   9128 
   9129  // Check that our parent frame is a block before allowing ::first-letter/line.
   9130  // E.g. <button style="display:grid"> should not allow it.
   9131  const bool allowFirstPseudos =
   9132      aAllowBlockStyles && aFrame->IsBlockFrameOrSubclass();
   9133  bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
   9134  if (allowFirstPseudos) {
   9135    ShouldHaveSpecialBlockStyle(aContent, aComputedStyle, &haveFirstLetterStyle,
   9136                                &haveFirstLineStyle);
   9137  }
   9138 
   9139  AutoFrameConstructionItemList itemsToConstruct(this);
   9140  AutoFrameConstructionPageName pageNameTracker(aState, aFrame);
   9141 
   9142  // If we have first-letter or first-line style then frames can get
   9143  // moved around so don't set these flags.
   9144  if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
   9145    itemsToConstruct.SetLineBoundaryAtStart(true);
   9146    itemsToConstruct.SetLineBoundaryAtEnd(true);
   9147  }
   9148 
   9149  // Create any anonymous frames we need here.
   9150  AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
   9151  GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
   9152 #ifdef DEBUG
   9153  for (auto& item : anonymousItems) {
   9154    MOZ_ASSERT(item.mContent->IsRootOfNativeAnonymousSubtree(),
   9155               "Content should know it's an anonymous subtree");
   9156  }
   9157 #endif
   9158  AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
   9159                                itemsToConstruct, pageNameTracker);
   9160 
   9161  nsBlockFrame* listItem = nullptr;
   9162  bool isOutsideMarker = false;
   9163  if (!aPossiblyLeafFrame->IsLeaf()) {
   9164    // Generated content should have the same style parent as normal kids.
   9165    //
   9166    // Note that we don't use this style for looking up things like special
   9167    // block styles because in some cases involving table pseudo-frames it has
   9168    // nothing to do with the parent frame's desired behavior.
   9169    auto* styleParentFrame =
   9170        nsIFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo);
   9171    ComputedStyle* parentStyle = styleParentFrame->Style();
   9172    if (aCanHaveGeneratedContent) {
   9173      if (parentStyle->StyleDisplay()->mTopLayer == StyleTopLayer::Auto &&
   9174          !aContent->IsInNativeAnonymousSubtree()) {
   9175        CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
   9176                                   *parentStyle, PseudoStyleType::backdrop,
   9177                                   itemsToConstruct);
   9178      }
   9179      if (parentStyle->StyleDisplay()->IsListItem() &&
   9180          (listItem = do_QueryFrame(aFrame)) &&
   9181          !styleParentFrame->IsFieldSetFrame()) {
   9182        isOutsideMarker = parentStyle->StyleList()->mListStylePosition ==
   9183                          StyleListStylePosition::Outside;
   9184        ItemFlags extraFlags;
   9185        if (isOutsideMarker) {
   9186          extraFlags += ItemFlag::IsForOutsideMarker;
   9187        }
   9188        CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
   9189                                   *parentStyle, PseudoStyleType::marker,
   9190                                   itemsToConstruct, extraFlags);
   9191      }
   9192      // Probe for generated content before
   9193      CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
   9194                                 *parentStyle, PseudoStyleType::before,
   9195                                 itemsToConstruct);
   9196    }
   9197 
   9198    const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
   9199    if (!addChildItems) {
   9200      NS_WARNING("ProcessChildren max depth exceeded");
   9201    }
   9202 
   9203    FlattenedChildIterator iter(aContent);
   9204    const InsertionPoint insertion(aFrame, aContent);
   9205    for (nsIContent* child = iter.GetNextChild(); child;
   9206         child = iter.GetNextChild()) {
   9207      MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(child).mContainer,
   9208                 "GetInsertionPoint should agree with us");
   9209      if (addChildItems) {
   9210        AddFrameConstructionItems(aState, child, iter.ShadowDOMInvolved(),
   9211                                  *parentStyle, insertion, itemsToConstruct);
   9212      } else {
   9213        ClearLazyBits(child, child->GetNextSibling());
   9214      }
   9215    }
   9216    itemsToConstruct.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
   9217 
   9218    if (aCanHaveGeneratedContent) {
   9219      // Probe for generated content after
   9220      CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
   9221                                 *parentStyle, PseudoStyleType::after,
   9222                                 itemsToConstruct);
   9223    }
   9224  } else {
   9225    ClearLazyBits(aContent->GetFirstChild(), nullptr);
   9226  }
   9227 
   9228  ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
   9229                              /* aParentIsWrapperAnonBox = */ false,
   9230                              aFrameList);
   9231 
   9232  if (listItem) {
   9233    if (auto* markerFrame = nsLayoutUtils::GetMarkerFrame(aContent)) {
   9234      for (auto* childFrame : aFrameList) {
   9235        if (markerFrame == childFrame) {
   9236          if (isOutsideMarker) {
   9237            // SetMarkerFrameForListItem will add childFrame to the marker list.
   9238            aFrameList.RemoveFrame(childFrame);
   9239            auto* grandParent = listItem->GetParent()->GetParent();
   9240            if (listItem->Style()->GetPseudoType() ==
   9241                    PseudoStyleType::columnContent &&
   9242                grandParent && grandParent->IsColumnSetWrapperFrame()) {
   9243              listItem = do_QueryFrame(grandParent);
   9244              MOZ_ASSERT(listItem,
   9245                         "ColumnSetWrapperFrame is expected to be "
   9246                         "a nsBlockFrame subclass");
   9247              childFrame->SetParent(listItem);
   9248            }
   9249          }
   9250          listItem->SetMarkerFrameForListItem(childFrame);
   9251          MOZ_ASSERT(listItem->HasOutsideMarker() == isOutsideMarker);
   9252 #ifdef ACCESSIBILITY
   9253          if (nsAccessibilityService* accService = GetAccService()) {
   9254            auto* marker = markerFrame->GetContent();
   9255            accService->ContentRangeInserted(mPresShell, marker, nullptr);
   9256          }
   9257 #endif
   9258          break;
   9259        }
   9260      }
   9261    }
   9262  }
   9263 
   9264  if (haveFirstLetterStyle) {
   9265    WrapFramesInFirstLetterFrame(aFrame, aFrameList);
   9266  }
   9267  if (haveFirstLineStyle) {
   9268    WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr, aFrameList);
   9269  }
   9270 }
   9271 
   9272 //----------------------------------------------------------------------
   9273 
   9274 // Support for :first-line style
   9275 
   9276 // Special routine to handle placing a list of frames into a block
   9277 // frame that has first-line style. The routine ensures that the first
   9278 // collection of inline frames end up in a first-line frame.
   9279 // NOTE: aState may have containing block information related to a
   9280 // different part of the frame tree than where the first line occurs.
   9281 // In particular aState may be set up for where ContentInserted or
   9282 // ContentAppended is inserting content, which may be some
   9283 // non-first-in-flow continuation of the block to which the first-line
   9284 // belongs. So this function needs to be careful about how it uses
   9285 // aState.
   9286 void nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
   9287    nsFrameConstructorState& aState, nsIContent* aBlockContent,
   9288    nsContainerFrame* aBlockFrame, nsFirstLineFrame* aLineFrame,
   9289    nsFrameList& aFrameList) {
   9290  // Extract any initial inline frames from aFrameList so we can put them
   9291  // in the first-line.
   9292  nsFrameList firstLineChildren =
   9293      aFrameList.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
   9294 
   9295  if (firstLineChildren.IsEmpty()) {
   9296    // Nothing is supposed to go into the first-line; nothing to do
   9297    return;
   9298  }
   9299 
   9300  if (!aLineFrame) {
   9301    // Create line frame
   9302    ComputedStyle* parentStyle = nsIFrame::CorrectStyleParentFrame(
   9303                                     aBlockFrame, PseudoStyleType::firstLine)
   9304                                     ->Style();
   9305    RefPtr<ComputedStyle> firstLineStyle =
   9306        GetFirstLineStyle(aBlockContent, parentStyle);
   9307 
   9308    aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
   9309 
   9310    // Initialize the line frame
   9311    InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
   9312 
   9313    // The lineFrame will be the block's first child; the rest of the
   9314    // frame list (after lastInlineFrame) will be the second and
   9315    // subsequent children; insert lineFrame into aFrameList.
   9316    aFrameList.InsertFrame(nullptr, nullptr, aLineFrame);
   9317 
   9318    NS_ASSERTION(aLineFrame->Style() == firstLineStyle,
   9319                 "Bogus style on line frame");
   9320  }
   9321 
   9322  // Give the inline frames to the lineFrame <b>after</b> reparenting them
   9323  ReparentFrames(this, aLineFrame, firstLineChildren, true);
   9324  if (aLineFrame->PrincipalChildList().IsEmpty() &&
   9325      aLineFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
   9326    aLineFrame->SetInitialChildList(FrameChildListID::Principal,
   9327                                    std::move(firstLineChildren));
   9328  } else {
   9329    AppendFrames(aLineFrame, FrameChildListID::Principal,
   9330                 std::move(firstLineChildren));
   9331  }
   9332 }
   9333 
   9334 // Special routine to handle appending a new frame to a block frame's
   9335 // child list. Takes care of placing the new frame into the right
   9336 // place when first-line style is present.
   9337 void nsCSSFrameConstructor::AppendFirstLineFrames(
   9338    nsFrameConstructorState& aState, nsIContent* aBlockContent,
   9339    nsContainerFrame* aBlockFrame, nsFrameList& aFrameList) {
   9340  // It's possible that aBlockFrame needs to have a first-line frame
   9341  // created because it doesn't currently have any children.
   9342  const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
   9343  if (blockKids.IsEmpty()) {
   9344    WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, nullptr,
   9345                               aFrameList);
   9346    return;
   9347  }
   9348 
   9349  // Examine the last block child - if it's a first-line frame then
   9350  // appended frames need special treatment.
   9351  nsIFrame* lastBlockKid = blockKids.LastChild();
   9352  if (!lastBlockKid->IsLineFrame()) {
   9353    // No first-line frame at the end of the list, therefore there is
   9354    // an intervening block between any first-line frame the frames
   9355    // we are appending. Therefore, we don't need any special
   9356    // treatment of the appended frames.
   9357    return;
   9358  }
   9359 
   9360  nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
   9361  WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, lineFrame,
   9362                             aFrameList);
   9363 }
   9364 
   9365 void nsCSSFrameConstructor::CheckForFirstLineInsertion(
   9366    nsIFrame* aParentFrame, nsFrameList& aFrameList) {
   9367  MOZ_ASSERT(aParentFrame->Style()->IsInFirstLineSubtree(),
   9368             "Why were we called?");
   9369 
   9370  if (aFrameList.IsEmpty()) {
   9371    // Happens often enough, with the caption stuff.  No need to do the ancestor
   9372    // walk here.
   9373    return;
   9374  }
   9375 
   9376  class RestyleManager* restyleManager = RestyleManager();
   9377 
   9378  // Check whether there's a ::first-line on the path up from aParentFrame.
   9379  // Note that we can't stop until we've run out of ancestors with
   9380  // pseudo-element data, because the first-letter might be somewhere way up the
   9381  // tree; in particular it might be past our containing block.
   9382  nsIFrame* ancestor = aParentFrame;
   9383  while (ancestor) {
   9384    if (!ancestor->Style()->IsInFirstLineSubtree()) {
   9385      // We know we won't find a ::first-line now.
   9386      return;
   9387    }
   9388 
   9389    if (!ancestor->IsLineFrame()) {
   9390      ancestor = ancestor->GetParent();
   9391      continue;
   9392    }
   9393 
   9394    if (!ancestor->Style()->IsPseudoElement()) {
   9395      // This is a continuation lineframe, not the first line; no need to do
   9396      // anything to the styles.
   9397      return;
   9398    }
   9399 
   9400    // Fix up the styles of aFrameList for ::first-line.
   9401    for (nsIFrame* f : aFrameList) {
   9402      restyleManager->ReparentComputedStyleForFirstLine(f);
   9403    }
   9404    return;
   9405  }
   9406 }
   9407 
   9408 //----------------------------------------------------------------------
   9409 
   9410 // First-letter support
   9411 
   9412 // Determine how many characters in the text fragment apply to the
   9413 // first letter
   9414 static int32_t FirstLetterCount(
   9415    const CharacterDataBuffer* aCharacterDataBuffer) {
   9416  int32_t count = 0;
   9417  int32_t firstLetterLength = 0;
   9418 
   9419  const uint32_t n = aCharacterDataBuffer->GetLength();
   9420  for (uint32_t i = 0; i < n; i++) {
   9421    const char16_t ch = aCharacterDataBuffer->CharAt(i);
   9422    // FIXME: take content language into account when deciding whitespace.
   9423    if (dom::IsSpaceCharacter(ch)) {
   9424      if (firstLetterLength) {
   9425        break;
   9426      }
   9427      count++;
   9428      continue;
   9429    }
   9430    // XXX I18n
   9431    if ((ch == '\'') || (ch == '\"')) {
   9432      if (firstLetterLength) {
   9433        break;
   9434      }
   9435      // keep looping
   9436      firstLetterLength = 1;
   9437    } else {
   9438      count++;
   9439      break;
   9440    }
   9441  }
   9442 
   9443  return count;
   9444 }
   9445 
   9446 static bool NeedFirstLetterContinuation(Text* aText) {
   9447  MOZ_ASSERT(aText, "null ptr");
   9448  int32_t flc = FirstLetterCount(&aText->DataBuffer());
   9449  int32_t tl = aText->TextDataLength();
   9450  return flc < tl;
   9451 }
   9452 
   9453 static bool IsFirstLetterContent(Text* aText) {
   9454  return aText->TextDataLength() && !aText->TextIsOnlyWhitespace();
   9455 }
   9456 
   9457 /**
   9458 * Create a letter frame, only make it a floating frame.
   9459 */
   9460 nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
   9461    nsFrameConstructorState& aState, Text* aTextContent, nsIFrame* aTextFrame,
   9462    nsContainerFrame* aParentFrame, ComputedStyle* aParentStyle,
   9463    ComputedStyle* aComputedStyle, nsFrameList& aResult) {
   9464  MOZ_ASSERT(aParentStyle);
   9465 
   9466  nsFirstLetterFrame* letterFrame =
   9467      NS_NewFloatingFirstLetterFrame(mPresShell, aComputedStyle);
   9468  // We don't want to use a text content for a non-text frame (because we want
   9469  // its primary frame to be a text frame).
   9470  nsIContent* letterContent = aParentFrame->GetContent();
   9471  nsContainerFrame* containingBlock =
   9472      aState.GetGeometricParent(*aComputedStyle->StyleDisplay(), aParentFrame);
   9473  InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
   9474 
   9475  // Init the text frame to refer to the letter frame.
   9476  //
   9477  // Make sure we get a proper style for it (the one passed in is for the letter
   9478  // frame and will have the float property set on it; the text frame shouldn't
   9479  // have that set).
   9480  ServoStyleSet* styleSet = mPresShell->StyleSet();
   9481  RefPtr<ComputedStyle> textSC =
   9482      styleSet->ResolveStyleForText(aTextContent, aComputedStyle);
   9483  aTextFrame->SetComputedStyleWithoutNotification(textSC);
   9484  InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
   9485 
   9486  // And then give the text frame to the letter frame
   9487  SetInitialSingleChild(letterFrame, aTextFrame);
   9488 
   9489  // See if we will need to continue the text frame (does it contain
   9490  // more than just the first-letter text or not?) If it does, then we
   9491  // create (in advance) a continuation frame for it.
   9492  nsIFrame* nextTextFrame = nullptr;
   9493  if (NeedFirstLetterContinuation(aTextContent)) {
   9494    // Create continuation
   9495    nextTextFrame = CreateContinuingFrame(aTextFrame, aParentFrame);
   9496    RefPtr<ComputedStyle> newSC =
   9497        styleSet->ResolveStyleForText(aTextContent, aParentStyle);
   9498    nextTextFrame->SetComputedStyle(newSC);
   9499  }
   9500 
   9501  NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameList!");
   9502  // Put the new float before any of the floats in the block we're doing
   9503  // first-letter for, that is, before any floats whose parent is
   9504  // containingBlock.
   9505  nsIFrame* prevSibling = nullptr;
   9506  for (nsIFrame* f : aState.mFloatedList) {
   9507    if (f->GetParent() == containingBlock) {
   9508      break;
   9509    }
   9510    prevSibling = f;
   9511  }
   9512 
   9513  aState.AddChild(letterFrame, aResult, letterContent, aParentFrame, false,
   9514                  true, true, prevSibling);
   9515 
   9516  if (nextTextFrame) {
   9517    aResult.AppendFrame(nullptr, nextTextFrame);
   9518  }
   9519 
   9520  return letterFrame;
   9521 }
   9522 
   9523 /**
   9524 * Create a new letter frame for aTextFrame. The letter frame will be
   9525 * a child of aParentFrame.
   9526 */
   9527 void nsCSSFrameConstructor::CreateLetterFrame(
   9528    nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
   9529    Text* aTextContent, nsContainerFrame* aParentFrame, nsFrameList& aResult) {
   9530  NS_ASSERTION(aBlockFrame->IsBlockFrameOrSubclass(), "Not a block frame?");
   9531 
   9532  // Get a ComputedStyle for the first-letter-frame.
   9533  //
   9534  // Keep this in sync with nsBlockFrame::UpdatePseudoElementStyles.
   9535  nsIFrame* parentFrame = nsIFrame::CorrectStyleParentFrame(
   9536      aParentFrame, PseudoStyleType::firstLetter);
   9537 
   9538  ComputedStyle* parentComputedStyle = parentFrame->Style();
   9539  ComputedStyle* parentComputedStyleIgnoringFirstLine = parentComputedStyle;
   9540  if (parentFrame->IsLineFrame()) {
   9541    parentComputedStyleIgnoringFirstLine =
   9542        nsIFrame::CorrectStyleParentFrame(aBlockFrame,
   9543                                          PseudoStyleType::firstLetter)
   9544            ->Style();
   9545  }
   9546 
   9547  // Use content from containing block so that we can actually
   9548  // find a matching style rule.
   9549  nsIContent* blockContent = aBlockFrame->GetContent();
   9550 
   9551  // Create first-letter style rule, ignoring first line. If we already have a
   9552  // first-line we'll reparent the style below.
   9553  RefPtr<ComputedStyle> sc =
   9554      GetFirstLetterStyle(blockContent, parentComputedStyleIgnoringFirstLine);
   9555 
   9556  if (sc) {
   9557    if (parentComputedStyleIgnoringFirstLine != parentComputedStyle) {
   9558      sc = mPresShell->StyleSet()->ReparentComputedStyle(
   9559          sc, parentComputedStyle, parentComputedStyle,
   9560          blockContent->AsElement());
   9561    }
   9562 
   9563    RefPtr<ComputedStyle> textSC =
   9564        mPresShell->StyleSet()->ResolveStyleForText(aTextContent, sc);
   9565 
   9566    // Create a new text frame (the original one will be discarded)
   9567    // pass a temporary stylecontext, the correct one will be set
   9568    // later.  Start off by unsetting the primary frame for
   9569    // aTextContent, so it's no longer pointing to the to-be-destroyed
   9570    // frame.
   9571    // XXXbz it would be really nice to destroy the old frame _first_,
   9572    // then create the new one, so we could avoid this hack.
   9573    aTextContent->SetPrimaryFrame(nullptr);
   9574    nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
   9575 
   9576    NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
   9577                 "Containing block is confused");
   9578    nsFrameConstructorState state(
   9579        mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
   9580        GetAbsoluteContainingBlock(aParentFrame, ABS_POS), aBlockContinuation);
   9581 
   9582    // Create the right type of first-letter frame
   9583    const nsStyleDisplay* display = sc->StyleDisplay();
   9584    nsFirstLetterFrame* letterFrame;
   9585    if (display->IsFloatingStyle() && !aParentFrame->IsInSVGTextSubtree()) {
   9586      // Make a floating first-letter frame
   9587      letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
   9588                                              aParentFrame, parentComputedStyle,
   9589                                              sc, aResult);
   9590    } else {
   9591      // Make an inflow first-letter frame
   9592      letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
   9593 
   9594      // Initialize the first-letter-frame.  We don't want to use a text
   9595      // content for a non-text frame (because we want its primary frame to
   9596      // be a text frame).
   9597      nsIContent* letterContent = aParentFrame->GetContent();
   9598      letterFrame->Init(letterContent, aParentFrame, nullptr);
   9599 
   9600      InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
   9601 
   9602      SetInitialSingleChild(letterFrame, textFrame);
   9603      aResult.Clear();
   9604      aResult.AppendFrame(nullptr, letterFrame);
   9605      NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
   9606                   "should have the first continuation here");
   9607      aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
   9608    }
   9609    MOZ_ASSERT(
   9610        !aBlockFrame->GetPrevContinuation(),
   9611        "Setting up a first-letter frame on a non-first block continuation?");
   9612    auto parent =
   9613        static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
   9614    if (MOZ_UNLIKELY(parent->IsLineFrame())) {
   9615      parent = static_cast<nsContainerFrame*>(
   9616          parent->GetParent()->FirstContinuation());
   9617    }
   9618    parent->SetHasFirstLetterChild();
   9619    aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
   9620                             letterFrame);
   9621    aTextContent->SetPrimaryFrame(textFrame);
   9622  }
   9623 }
   9624 
   9625 void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
   9626    nsContainerFrame* aBlockFrame, nsFrameList& aBlockFrames) {
   9627  aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
   9628 
   9629  nsContainerFrame* parentFrame = nullptr;
   9630  nsIFrame* textFrame = nullptr;
   9631  nsIFrame* prevFrame = nullptr;
   9632  nsFrameList letterFrames;
   9633  bool stopLooking = false;
   9634  WrapFramesInFirstLetterFrame(
   9635      aBlockFrame, aBlockFrame, aBlockFrame, aBlockFrames.FirstChild(),
   9636      &parentFrame, &textFrame, &prevFrame, letterFrames, &stopLooking);
   9637  if (!parentFrame) {
   9638    return;
   9639  }
   9640  DestroyContext context(mPresShell);
   9641  if (parentFrame == aBlockFrame) {
   9642    // Take textFrame out of the block's frame list and substitute the
   9643    // letter frame(s) instead.
   9644    aBlockFrames.DestroyFrame(context, textFrame);
   9645    aBlockFrames.InsertFrames(nullptr, prevFrame, std::move(letterFrames));
   9646  } else {
   9647    // Take the old textFrame out of the inline parent's child list
   9648    RemoveFrame(context, FrameChildListID::Principal, textFrame);
   9649 
   9650    // Insert in the letter frame(s)
   9651    parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
   9652                              std::move(letterFrames));
   9653  }
   9654 }
   9655 
   9656 void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
   9657    nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
   9658    nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
   9659    nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
   9660    nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking) {
   9661  nsIFrame* prevFrame = nullptr;
   9662  nsIFrame* frame = aParentFrameList;
   9663 
   9664  // This loop attempts to implement "Finding the First Letter":
   9665  // https://drafts.csswg.org/css-pseudo-4/#application-in-css
   9666  // FIXME: we don't handle nested blocks correctly yet though (bug 214004)
   9667  while (frame) {
   9668    nsIFrame* nextFrame = frame->GetNextSibling();
   9669 
   9670    // Skip all ::markers and placeholders.
   9671    if (frame->Style()->GetPseudoType() == PseudoStyleType::marker ||
   9672        frame->IsPlaceholderFrame()) {
   9673      prevFrame = frame;
   9674      frame = nextFrame;
   9675      continue;
   9676    }
   9677    LayoutFrameType frameType = frame->Type();
   9678    if (LayoutFrameType::Text == frameType) {
   9679      // Wrap up first-letter content in a letter frame
   9680      Text* textContent = frame->GetContent()->AsText();
   9681      if (IsFirstLetterContent(textContent)) {
   9682        // Create letter frame to wrap up the text
   9683        CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
   9684                          aParentFrame, aLetterFrames);
   9685 
   9686        // Provide adjustment information for parent
   9687        *aModifiedParent = aParentFrame;
   9688        *aTextFrame = frame;
   9689        *aPrevFrame = prevFrame;
   9690        *aStopLooking = true;
   9691        return;
   9692      }
   9693    } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
   9694      nsIFrame* kids = frame->PrincipalChildList().FirstChild();
   9695      WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
   9696                                   static_cast<nsContainerFrame*>(frame), kids,
   9697                                   aModifiedParent, aTextFrame, aPrevFrame,
   9698                                   aLetterFrames, aStopLooking);
   9699      if (*aStopLooking) {
   9700        return;
   9701      }
   9702    } else {
   9703      // This will stop us looking to create more letter frames. For
   9704      // example, maybe the frame-type is "letterFrame" or
   9705      // "placeholderFrame". This keeps us from creating extra letter
   9706      // frames, and also prevents us from creating letter frames when
   9707      // the first real content child of a block is not text (e.g. an
   9708      // image, hr, etc.)
   9709      *aStopLooking = true;
   9710      break;
   9711    }
   9712 
   9713    prevFrame = frame;
   9714    frame = nextFrame;
   9715  }
   9716 }
   9717 
   9718 static nsIFrame* FindFirstLetterFrame(nsIFrame* aFrame,
   9719                                      FrameChildListID aListID) {
   9720  for (nsIFrame* f : aFrame->GetChildList(aListID)) {
   9721    if (f->IsLetterFrame()) {
   9722      return f;
   9723    }
   9724  }
   9725  return nullptr;
   9726 }
   9727 
   9728 static void ClearHasFirstLetterChildFrom(nsContainerFrame* aParentFrame) {
   9729  MOZ_ASSERT(aParentFrame);
   9730  auto* parent =
   9731      static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
   9732  if (MOZ_UNLIKELY(parent->IsLineFrame())) {
   9733    MOZ_ASSERT(!parent->HasFirstLetterChild());
   9734    parent = static_cast<nsContainerFrame*>(
   9735        parent->GetParent()->FirstContinuation());
   9736  }
   9737  MOZ_ASSERT(parent->HasFirstLetterChild());
   9738  parent->ClearHasFirstLetterChild();
   9739 }
   9740 
   9741 void nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
   9742    PresShell* aPresShell, nsIFrame* aBlockFrame) {
   9743  // Look for the first letter frame on the FrameChildListID::Float, then
   9744  // FrameChildListID::PushedFloats.
   9745  nsIFrame* floatFrame =
   9746      ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::Float);
   9747  if (!floatFrame) {
   9748    floatFrame =
   9749        ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::PushedFloats);
   9750    if (!floatFrame) {
   9751      return;
   9752    }
   9753  }
   9754 
   9755  // Take the text frame away from the letter frame (so it isn't
   9756  // destroyed when we destroy the letter frame).
   9757  nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
   9758  if (!textFrame) {
   9759    return;
   9760  }
   9761 
   9762  // Discover the placeholder frame for the letter frame
   9763  nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
   9764  if (!placeholderFrame) {
   9765    // Somethings really wrong
   9766    return;
   9767  }
   9768  nsContainerFrame* parentFrame = placeholderFrame->GetParent();
   9769  if (!parentFrame) {
   9770    // Somethings really wrong
   9771    return;
   9772  }
   9773 
   9774  ClearHasFirstLetterChildFrom(parentFrame);
   9775 
   9776  // Create a new text frame with the right style that maps all of the content
   9777  // that was previously part of the letter frame (and probably continued
   9778  // elsewhere).
   9779  ComputedStyle* parentSC = parentFrame->Style();
   9780  nsIContent* textContent = textFrame->GetContent();
   9781  if (!textContent) {
   9782    return;
   9783  }
   9784  RefPtr<ComputedStyle> newSC =
   9785      aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
   9786  nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
   9787  newTextFrame->Init(textContent, parentFrame, nullptr);
   9788 
   9789  // Destroy the old text frame's continuations (the old text frame
   9790  // will be destroyed when its letter frame is destroyed).
   9791  nsIFrame* frameToDelete = textFrame->LastContinuation();
   9792  DestroyContext context(mPresShell);
   9793  while (frameToDelete != textFrame) {
   9794    nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
   9795    RemoveFrame(context, FrameChildListID::Principal, frameToDelete);
   9796    frameToDelete = nextFrameToDelete;
   9797  }
   9798 
   9799  nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
   9800 
   9801  // Now that everything is set...
   9802 #ifdef NOISY_FIRST_LETTER
   9803  printf(
   9804      "RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p "
   9805      "newTextFrame=%p\n",
   9806      textContent.get(), textFrame, newTextFrame);
   9807 #endif
   9808 
   9809  // Remove placeholder frame and the float
   9810  RemoveFrame(context, FrameChildListID::Principal, placeholderFrame);
   9811 
   9812  // Now that the old frames are gone, we can start pointing to our
   9813  // new primary frame.
   9814  textContent->SetPrimaryFrame(newTextFrame);
   9815 
   9816  // Wallpaper bug 822910.
   9817  bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
   9818  if (offsetsNeedFixing) {
   9819    prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
   9820  }
   9821 
   9822  // Insert text frame in its place
   9823  InsertFrames(parentFrame, FrameChildListID::Principal, prevSibling,
   9824               nsFrameList(newTextFrame, newTextFrame));
   9825 
   9826  if (offsetsNeedFixing) {
   9827    prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
   9828  }
   9829 }
   9830 
   9831 void nsCSSFrameConstructor::RemoveFirstLetterFrames(
   9832    PresShell* aPresShell, nsContainerFrame* aFrame,
   9833    nsContainerFrame* aBlockFrame, bool* aStopLooking) {
   9834  nsIFrame* prevSibling = nullptr;
   9835  nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
   9836 
   9837  while (kid) {
   9838    if (kid->IsLetterFrame()) {
   9839      ClearHasFirstLetterChildFrom(aFrame);
   9840      nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
   9841      if (!textFrame) {
   9842        break;
   9843      }
   9844 
   9845      // Create a new textframe
   9846      ComputedStyle* parentSC = aFrame->Style();
   9847      if (!parentSC) {
   9848        break;
   9849      }
   9850      nsIContent* textContent = textFrame->GetContent();
   9851      if (!textContent) {
   9852        break;
   9853      }
   9854      RefPtr<ComputedStyle> newSC =
   9855          aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
   9856      textFrame = NS_NewTextFrame(aPresShell, newSC);
   9857      textFrame->Init(textContent, aFrame, nullptr);
   9858 
   9859      DestroyContext context(mPresShell);
   9860 
   9861      // Next rip out the kid and replace it with the text frame
   9862      RemoveFrame(context, FrameChildListID::Principal, kid);
   9863 
   9864      // Now that the old frames are gone, we can start pointing to our
   9865      // new primary frame.
   9866      textContent->SetPrimaryFrame(textFrame);
   9867 
   9868      // Wallpaper bug 822910.
   9869      bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
   9870      if (offsetsNeedFixing) {
   9871        prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
   9872      }
   9873 
   9874      // Insert text frame in its place
   9875      InsertFrames(aFrame, FrameChildListID::Principal, prevSibling,
   9876                   nsFrameList(textFrame, textFrame));
   9877 
   9878      if (offsetsNeedFixing) {
   9879        prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
   9880      }
   9881 
   9882      *aStopLooking = true;
   9883      NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
   9884                   "should have the first continuation here");
   9885      aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
   9886      break;
   9887    }
   9888    if (IsInlineFrame(kid)) {
   9889      nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
   9890      if (kidAsContainerFrame) {
   9891        // Look inside child inline frame for the letter frame.
   9892        RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame, aBlockFrame,
   9893                                aStopLooking);
   9894        if (*aStopLooking) {
   9895          break;
   9896        }
   9897      }
   9898    }
   9899    prevSibling = kid;
   9900    kid = kid->GetNextSibling();
   9901  }
   9902 }
   9903 
   9904 void nsCSSFrameConstructor::RemoveLetterFrames(PresShell* aPresShell,
   9905                                               nsContainerFrame* aBlockFrame) {
   9906  aBlockFrame =
   9907      static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
   9908  aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
   9909  nsContainerFrame* continuation = aBlockFrame;
   9910 
   9911  bool stopLooking = false;
   9912  do {
   9913    RemoveFloatingFirstLetterFrames(aPresShell, continuation);
   9914    RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
   9915                            &stopLooking);
   9916    if (stopLooking) {
   9917      break;
   9918    }
   9919    continuation =
   9920        static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
   9921  } while (continuation);
   9922 }
   9923 
   9924 // Fixup the letter frame situation for the given block
   9925 void nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame) {
   9926  aBlockFrame =
   9927      static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
   9928  nsContainerFrame* continuation = aBlockFrame;
   9929 
   9930  nsContainerFrame* parentFrame = nullptr;
   9931  nsIFrame* textFrame = nullptr;
   9932  nsIFrame* prevFrame = nullptr;
   9933  nsFrameList letterFrames;
   9934  bool stopLooking = false;
   9935  do {
   9936    // XXX shouldn't this bit be set already (bug 408493), assert instead?
   9937    continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
   9938    WrapFramesInFirstLetterFrame(
   9939        aBlockFrame, continuation, continuation,
   9940        continuation->PrincipalChildList().FirstChild(), &parentFrame,
   9941        &textFrame, &prevFrame, letterFrames, &stopLooking);
   9942    if (stopLooking) {
   9943      break;
   9944    }
   9945    continuation =
   9946        static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
   9947  } while (continuation);
   9948 
   9949  if (!parentFrame) {
   9950    return;
   9951  }
   9952  // Take the old textFrame out of the parent's child list
   9953  DestroyContext context(mPresShell);
   9954  RemoveFrame(context, FrameChildListID::Principal, textFrame);
   9955 
   9956  // Insert in the letter frame(s)
   9957  parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
   9958                            std::move(letterFrames));
   9959 }
   9960 
   9961 //----------------------------------------------------------------------
   9962 
   9963 void nsCSSFrameConstructor::ConstructBlock(
   9964    nsFrameConstructorState& aState, nsIContent* aContent,
   9965    nsContainerFrame* aParentFrame, nsContainerFrame* aContentParentFrame,
   9966    ComputedStyle* aComputedStyle, nsContainerFrame** aNewFrame,
   9967    nsFrameList& aFrameList, nsIFrame* aPositionedFrameForAbsPosContainer) {
   9968  // clang-format off
   9969  //
   9970  // If a block frame is in a multi-column subtree, its children may need to
   9971  // be chopped into runs of blocks containing column-spans and runs of
   9972  // blocks containing no column-spans. Each run containing column-spans
   9973  // will be wrapped by an anonymous block. See CreateColumnSpanSiblings() for
   9974  // the implementation.
   9975  //
   9976  // If a block frame is a multi-column container, its children will need to
   9977  // be processed as above. Moreover, it creates a ColumnSetWrapperFrame as
   9978  // its outermost frame, and its children which have no
   9979  // -moz-column-span-wrapper pseudo will be wrapped in ColumnSetFrames. See
   9980  // FinishBuildingColumns() for the implementation.
   9981  //
   9982  // The multi-column subtree maintains the following invariants:
   9983  //
   9984  // 1) All the frames have the frame state bit
   9985  //    NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR set, except for top-level
   9986  //    ColumnSetWrapperFrame and those children in the column-span subtrees.
   9987  //
   9988  // 2) The first and last frame under ColumnSetWrapperFrame are always
   9989  //    ColumnSetFrame.
   9990  //
   9991  // 3) ColumnSetFrames are linked together as continuations.
   9992  //
   9993  // 4) Those column-span wrappers are *not* linked together with themselves nor
   9994  //    with the original block frame. The continuation chain consists of the
   9995  //    original block frame and the original block's continuations wrapping
   9996  //    non-column-spans.
   9997  //
   9998  // For example, this HTML
   9999  //  <div id="x" style="column-count: 2;">
  10000  //    <div style="column-span: all">a</div>
  10001  //    <div id="y">
  10002  //      b
  10003  //      <div style="column-span: all">c</div>
  10004  //      <div style="column-span: all">d</div>
  10005  //      e
  10006  //    </div>
  10007  //  </div>
  10008  //  <div style="column-span: all">f</div>
  10009  //
  10010  //  yields the following frame tree.
  10011  //
  10012  // A) ColumnSetWrapper (original style)
  10013  // B)   ColumnSet (-moz-column-set)   <-- always created by BeginBuildingColumns
  10014  // C)     Block (-moz-column-content)
  10015  // D)   Block (-moz-column-span-wrapper, created by x)
  10016  // E)     Block (div)
  10017  // F)       Text ("a")
  10018  // G)   ColumnSet (-moz-column-set)
  10019  // H)     Block (-moz-column-content, created by x)
  10020  // I)       Block (div, y)
  10021  // J)         Text ("b")
  10022  // K)   Block (-moz-column-span-wrapper, created by x)
  10023  // L)     Block (-moz-column-span-wrapper, created by y)
  10024  // M)       Block (div, new BFC)
  10025  // N)         Text ("c")
  10026  // O)       Block (div, new BFC)
  10027  // P)         Text ("d")
  10028  // Q)   ColumnSet (-moz-column-set)
  10029  // R)     Block (-moz-column-content, created by x)
  10030  // S)       Block (div, y)
  10031  // T)         Text ("e")
  10032  // U) Block (div, new BFC)   <-- not in multi-column hierarchy
  10033  // V)   Text ("f")
  10034  //
  10035  // ColumnSet linkage described in 3): B -> G -> Q
  10036  //
  10037  // Block linkage described in 4): C -> H -> R  and  I -> S
  10038  //
  10039  // clang-format on
  10040 
  10041  nsBlockFrame* blockFrame = do_QueryFrame(*aNewFrame);
  10042  MOZ_ASSERT(blockFrame && blockFrame->IsBlockFrame(), "not a block frame?");
  10043 
  10044  // Create column hierarchy if necessary.
  10045  const bool needsColumn =
  10046      aComputedStyle->StyleColumn()->IsColumnContainerStyle();
  10047  if (needsColumn) {
  10048    *aNewFrame = BeginBuildingColumns(aState, aContent, aParentFrame,
  10049                                      blockFrame, aComputedStyle);
  10050 
  10051    if (aPositionedFrameForAbsPosContainer == blockFrame) {
  10052      aPositionedFrameForAbsPosContainer = *aNewFrame;
  10053    }
  10054  } else {
  10055    // No need to create column hierarchy. Initialize block frame.
  10056    blockFrame->SetComputedStyleWithoutNotification(aComputedStyle);
  10057    InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
  10058  }
  10059 
  10060  aState.AddChild(*aNewFrame, aFrameList, aContent,
  10061                  aContentParentFrame ? aContentParentFrame : aParentFrame);
  10062  if (!mRootElementFrame) {
  10063    mRootElementFrame = *aNewFrame;
  10064  }
  10065 
  10066  // We should make the outer frame be the absolute containing block,
  10067  // if one is required. We have to do this because absolute
  10068  // positioning must be computed with respect to the CSS dimensions
  10069  // of the element, which are the dimensions of the outer block. But
  10070  // we can't really do that because only blocks can have absolute
  10071  // children. So use the block and try to compensate with hacks
  10072  // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
  10073  nsFrameConstructorSaveState absoluteSaveState;
  10074  (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  10075  if (aPositionedFrameForAbsPosContainer) {
  10076    aState.PushAbsoluteContainingBlock(
  10077        *aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
  10078  }
  10079 
  10080  nsFrameConstructorSaveState floatSaveState;
  10081  aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
  10082 
  10083  if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
  10084      !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
  10085    blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10086  }
  10087 
  10088  // Process the child content
  10089  nsFrameList childList;
  10090  ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true, childList,
  10091                  true);
  10092 
  10093  if (!MayNeedToCreateColumnSpanSiblings(blockFrame, childList)) {
  10094    // No need to create column-span siblings.
  10095    blockFrame->SetInitialChildList(FrameChildListID::Principal,
  10096                                    std::move(childList));
  10097    return;
  10098  }
  10099 
  10100  // Extract any initial non-column-span kids, and put them in block frame's
  10101  // child list.
  10102  nsFrameList initialNonColumnSpanKids =
  10103      childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
  10104  blockFrame->SetInitialChildList(FrameChildListID::Principal,
  10105                                  std::move(initialNonColumnSpanKids));
  10106 
  10107  if (childList.IsEmpty()) {
  10108    // No more kids to process (there weren't any column-span kids).
  10109    return;
  10110  }
  10111 
  10112  nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
  10113      aState, blockFrame, childList,
  10114      // If we're constructing a column container, pass nullptr as
  10115      // aPositionedFrame to forbid reparenting absolute/fixed positioned frames
  10116      // to column contents or column-span wrappers.
  10117      needsColumn ? nullptr : aPositionedFrameForAbsPosContainer);
  10118 
  10119  if (needsColumn) {
  10120    // We're constructing a column container; need to finish building it.
  10121    FinishBuildingColumns(aState, *aNewFrame, blockFrame, columnSpanSiblings);
  10122  } else {
  10123    // We're constructing a normal block which has column-span children in a
  10124    // column hierarchy such as "x" in the following example.
  10125    //
  10126    // <div style="column-count: 2">
  10127    //   <div id="x">
  10128    //     <div>normal child</div>
  10129    //     <div style="column-span">spanner</div>
  10130    //   </div>
  10131    // </div>
  10132    aFrameList.AppendFrames(nullptr, std::move(columnSpanSiblings));
  10133  }
  10134 
  10135  MOZ_ASSERT(columnSpanSiblings.IsEmpty(),
  10136             "The column-span siblings should be moved to the proper place!");
  10137 }
  10138 
  10139 nsBlockFrame* nsCSSFrameConstructor::BeginBuildingColumns(
  10140    nsFrameConstructorState& aState, nsIContent* aContent,
  10141    nsContainerFrame* aParentFrame, nsContainerFrame* aColumnContent,
  10142    ComputedStyle* aComputedStyle) {
  10143  MOZ_ASSERT(aColumnContent->IsBlockFrame(),
  10144             "aColumnContent should be a block frame.");
  10145  MOZ_ASSERT(aComputedStyle->StyleColumn()->IsColumnContainerStyle(),
  10146             "No need to build a column hierarchy!");
  10147 
  10148  // The initial column hierarchy looks like this:
  10149  //
  10150  // ColumnSetWrapper (original style)
  10151  //   ColumnSet (-moz-column-set)
  10152  //     Block (-moz-column-content)
  10153  //
  10154  nsBlockFrame* columnSetWrapper = NS_NewColumnSetWrapperFrame(
  10155      mPresShell, aComputedStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
  10156  InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetWrapper);
  10157  if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
  10158      !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
  10159    columnSetWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10160  }
  10161 
  10162  AutoFrameConstructionPageName pageNameTracker(aState, columnSetWrapper);
  10163  RefPtr<ComputedStyle> columnSetStyle =
  10164      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
  10165          PseudoStyleType::columnSet, aComputedStyle);
  10166  nsContainerFrame* columnSet = NS_NewColumnSetFrame(
  10167      mPresShell, columnSetStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
  10168  InitAndRestoreFrame(aState, aContent, columnSetWrapper, columnSet);
  10169  columnSet->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10170 
  10171  RefPtr<ComputedStyle> blockStyle =
  10172      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
  10173          PseudoStyleType::columnContent, columnSetStyle);
  10174  aColumnContent->SetComputedStyleWithoutNotification(blockStyle);
  10175  InitAndRestoreFrame(aState, aContent, columnSet, aColumnContent);
  10176  aColumnContent->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10177 
  10178  // Set up the parent-child chain.
  10179  SetInitialSingleChild(columnSetWrapper, columnSet);
  10180  SetInitialSingleChild(columnSet, aColumnContent);
  10181 
  10182  return columnSetWrapper;
  10183 }
  10184 
  10185 void nsCSSFrameConstructor::FinishBuildingColumns(
  10186    nsFrameConstructorState& aState, nsContainerFrame* aColumnSetWrapper,
  10187    nsContainerFrame* aColumnContent, nsFrameList& aColumnContentSiblings) {
  10188  nsContainerFrame* prevColumnSet = aColumnContent->GetParent();
  10189 
  10190  MOZ_ASSERT(prevColumnSet->IsColumnSetFrame() &&
  10191                 prevColumnSet->GetParent() == aColumnSetWrapper,
  10192             "Should have established column hierarchy!");
  10193 
  10194  // Tag the first ColumnSet to have column-span siblings so that the bit can
  10195  // propagate to all the continuations. We don't want the last ColumnSet to
  10196  // have this bit, so we will unset the bit for it at the end of this function.
  10197  prevColumnSet->SetHasColumnSpanSiblings(true);
  10198 
  10199  nsFrameList finalList;
  10200  while (aColumnContentSiblings.NotEmpty()) {
  10201    nsIFrame* f = aColumnContentSiblings.RemoveFirstChild();
  10202    if (f->IsColumnSpan()) {
  10203      // Do nothing for column-span wrappers. Just move it to the final
  10204      // items.
  10205      finalList.AppendFrame(aColumnSetWrapper, f);
  10206    } else {
  10207      auto* continuingColumnSet = static_cast<nsContainerFrame*>(
  10208          CreateContinuingFrame(prevColumnSet, aColumnSetWrapper, false));
  10209      MOZ_ASSERT(continuingColumnSet->HasColumnSpanSiblings(),
  10210                 "The bit should propagate to the next continuation!");
  10211 
  10212      f->SetParent(continuingColumnSet);
  10213      SetInitialSingleChild(continuingColumnSet, f);
  10214      finalList.AppendFrame(aColumnSetWrapper, continuingColumnSet);
  10215      prevColumnSet = continuingColumnSet;
  10216    }
  10217  }
  10218 
  10219  // Unset the bit because the last ColumnSet has no column-span siblings.
  10220  prevColumnSet->SetHasColumnSpanSiblings(false);
  10221 
  10222  aColumnSetWrapper->AppendFrames(FrameChildListID::Principal,
  10223                                  std::move(finalList));
  10224 }
  10225 
  10226 bool nsCSSFrameConstructor::MayNeedToCreateColumnSpanSiblings(
  10227    nsContainerFrame* aBlockFrame, const nsFrameList& aChildList) {
  10228  if (!aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
  10229    // The block frame isn't in a multi-column block formatting context.
  10230    return false;
  10231  }
  10232 
  10233  if (ShouldSuppressColumnSpanDescendants(aBlockFrame)) {
  10234    // No need to create column-span siblings for a frame that suppresses them.
  10235    return false;
  10236  }
  10237 
  10238  if (aChildList.IsEmpty()) {
  10239    // No child needs to be processed.
  10240    return false;
  10241  }
  10242 
  10243  // Need to actually look into the child list.
  10244  return true;
  10245 }
  10246 
  10247 nsFrameList nsCSSFrameConstructor::CreateColumnSpanSiblings(
  10248    nsFrameConstructorState& aState, nsContainerFrame* aInitialBlock,
  10249    nsFrameList& aChildList, nsIFrame* aPositionedFrame) {
  10250  MOZ_ASSERT(aInitialBlock->IsBlockFrameOrSubclass());
  10251  MOZ_ASSERT(!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock());
  10252 
  10253  nsIContent* const content = aInitialBlock->GetContent();
  10254  nsContainerFrame* const parentFrame = aInitialBlock->GetParent();
  10255  const bool isInitialBlockFloatCB = aInitialBlock->IsFloatContainingBlock();
  10256 
  10257  nsFrameList siblings;
  10258  nsContainerFrame* lastNonColumnSpanWrapper = aInitialBlock;
  10259 
  10260  // Tag the first non-column-span wrapper to have column-span siblings so that
  10261  // the bit can propagate to all the continuations. We don't want the last
  10262  // wrapper to have this bit, so we will unset the bit for it at the end of
  10263  // this function.
  10264  lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(true);
  10265  do {
  10266    MOZ_ASSERT(aChildList.NotEmpty(), "Why call this if child list is empty?");
  10267    MOZ_ASSERT(aChildList.FirstChild()->IsColumnSpan(),
  10268               "Must have the child starting with column-span!");
  10269 
  10270    // Grab the consecutive column-span kids, and reparent them into a
  10271    // block frame.
  10272    RefPtr<ComputedStyle> columnSpanWrapperStyle =
  10273        mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
  10274            PseudoStyleType::columnSpanWrapper);
  10275    nsBlockFrame* columnSpanWrapper =
  10276        NS_NewBlockFrame(mPresShell, columnSpanWrapperStyle);
  10277    InitAndRestoreFrame(aState, content, parentFrame, columnSpanWrapper, false);
  10278    columnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
  10279                                    NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  10280 
  10281    nsFrameList columnSpanKids =
  10282        aChildList.Split([](nsIFrame* f) { return !f->IsColumnSpan(); });
  10283    columnSpanKids.ApplySetParent(columnSpanWrapper);
  10284    columnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
  10285                                           std::move(columnSpanKids));
  10286    if (aPositionedFrame) {
  10287      aState.ReparentAbsoluteItems(columnSpanWrapper);
  10288    }
  10289 
  10290    siblings.AppendFrame(nullptr, columnSpanWrapper);
  10291 
  10292    // Grab the consecutive non-column-span kids, and reparent them into a new
  10293    // continuation of the last non-column-span wrapper frame.
  10294    auto* nonColumnSpanWrapper = static_cast<nsContainerFrame*>(
  10295        CreateContinuingFrame(lastNonColumnSpanWrapper, parentFrame, false));
  10296    nonColumnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
  10297                                       NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  10298    MOZ_ASSERT(nonColumnSpanWrapper->HasColumnSpanSiblings(),
  10299               "The bit should propagate to the next continuation!");
  10300 
  10301    if (aChildList.NotEmpty()) {
  10302      nsFrameList nonColumnSpanKids =
  10303          aChildList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
  10304 
  10305      nonColumnSpanKids.ApplySetParent(nonColumnSpanWrapper);
  10306      nonColumnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
  10307                                                std::move(nonColumnSpanKids));
  10308      if (aPositionedFrame) {
  10309        aState.ReparentAbsoluteItems(nonColumnSpanWrapper);
  10310      }
  10311      if (isInitialBlockFloatCB) {
  10312        aState.ReparentFloats(nonColumnSpanWrapper);
  10313      }
  10314    }
  10315 
  10316    siblings.AppendFrame(nullptr, nonColumnSpanWrapper);
  10317 
  10318    lastNonColumnSpanWrapper = nonColumnSpanWrapper;
  10319  } while (aChildList.NotEmpty());
  10320 
  10321  // Unset the bit because the last non-column-span wrapper has no column-span
  10322  // siblings.
  10323  lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(false);
  10324 
  10325  return siblings;
  10326 }
  10327 
  10328 bool nsCSSFrameConstructor::MaybeRecreateForColumnSpan(
  10329    nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
  10330    nsFrameList& aFrameList, nsIFrame* aPrevSibling) {
  10331  if (!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
  10332    return false;
  10333  }
  10334 
  10335  if (aFrameList.IsEmpty()) {
  10336    return false;
  10337  }
  10338 
  10339  MOZ_ASSERT(!IsFramePartOfIBSplit(aParentFrame),
  10340             "We should have wiped aParentFrame in "
  10341             "WipeContainingBlock if it's part of IB split!");
  10342 
  10343  nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
  10344  if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
  10345    // We are appending a list of frames to the last continuation of a
  10346    // ::-moz-column-content. This is the case where we can fix the frame tree
  10347    // instead of reframing the containing block. Return false and let
  10348    // AppendFramesToParent() deal with this.
  10349    return false;
  10350  }
  10351 
  10352  auto HasColumnSpan = [](const nsFrameList& aList) {
  10353    for (nsIFrame* f : aList) {
  10354      if (f->IsColumnSpan()) {
  10355        return true;
  10356      }
  10357    }
  10358    return false;
  10359  };
  10360 
  10361  if (HasColumnSpan(aFrameList)) {
  10362    // If any frame in the frame list has "column-span:all" style, i.e. a
  10363    // -moz-column-span-wrapper frame, we need to reframe the multi-column
  10364    // containing block.
  10365    //
  10366    // We can only be here if none of the new inserted nsIContent* nodes (via
  10367    // ContentAppended or ContentRangeInserted) have column-span:all style, yet
  10368    // some of them have column-span:all descendants. Sadly, there's no way to
  10369    // detect this by checking FrameConstructionItems in WipeContainingBlock().
  10370    // Otherwise, we would have already wiped the multi-column containing block.
  10371    PROFILER_MARKER("Reframe multi-column after constructing frame list",
  10372                    LAYOUT, {}, Tracing, "Layout");
  10373 
  10374    // aFrameList can contain placeholder frames. In order to destroy their
  10375    // associated out-of-flow frames properly, we need to manually flush all the
  10376    // out-of-flow frames in aState to their container frames.
  10377    aState.ProcessFrameInsertionsForAllLists();
  10378    DestroyContext context(mPresShell);
  10379    aFrameList.DestroyFrames(context);
  10380    RecreateFramesForContent(
  10381        GetMultiColumnContainingBlockFor(aParentFrame)->GetContent(),
  10382        InsertionKind::Async);
  10383    return true;
  10384  }
  10385 
  10386  return false;
  10387 }
  10388 
  10389 nsIFrame* nsCSSFrameConstructor::ConstructInline(
  10390    nsFrameConstructorState& aState, FrameConstructionItem& aItem,
  10391    nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
  10392    nsFrameList& aFrameList) {
  10393  // If an inline frame has non-inline kids, then we chop up the child list
  10394  // into runs of blocks and runs of inlines, create anonymous block frames to
  10395  // contain the runs of blocks, inline frames with our style for the runs of
  10396  // inlines, and put all these frames, in order, into aFrameList.
  10397  //
  10398  // When there are column-span blocks in a run of blocks, instead of creating
  10399  // an anonymous block to wrap them, we create multiple anonymous blocks,
  10400  // wrapping runs of non-column-spans and runs of column-spans.
  10401  //
  10402  // We return the the first one.  The whole setup is called an {ib}
  10403  // split; in what follows "frames in the split" refers to the anonymous blocks
  10404  // and inlines that contain our children.
  10405  //
  10406  // {ib} splits maintain the following invariants:
  10407  // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
  10408  //    set.
  10409  //
  10410  // 2) Each frame in the split has the nsIFrame::IBSplitSibling
  10411  //    property pointing to the next frame in the split, except for the last
  10412  //    one, which does not have it set.
  10413  //
  10414  // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
  10415  //    property pointing to the previous frame in the split, except for the
  10416  //    first one, which does not have it set.
  10417  //
  10418  // 4) The first and last frame in the split are always inlines.
  10419  //
  10420  // 5) The frames wrapping runs of non-column-spans are linked together as
  10421  //    continuations. The frames wrapping runs of column-spans are *not*
  10422  //    linked with each other nor with other non-column-span wrappers.
  10423  //
  10424  // 6) The first and last frame in the chains of blocks are always wrapping
  10425  //    non-column-spans. Both of them are created even if they're empty.
  10426  //
  10427  // An invariant that is NOT maintained is that the wrappers are actually
  10428  // linked via GetNextSibling linkage.  A simple example is an inline
  10429  // containing an inline that contains a block.  The three parts of the inner
  10430  // inline end up with three different parents.
  10431  //
  10432  // For example, this HTML:
  10433  // <span>
  10434  //   <div>a</div>
  10435  //   <span>
  10436  //     b
  10437  //     <div>c</div>
  10438  //   </span>
  10439  //   d
  10440  //   <div>e</div>
  10441  //   f
  10442  //  </span>
  10443  // Gives the following frame tree:
  10444  //
  10445  // Inline (outer span)
  10446  // Block (anonymous, outer span)
  10447  //   Block (div)
  10448  //     Text("a")
  10449  // Inline (outer span)
  10450  //   Inline (inner span)
  10451  //     Text("b")
  10452  // Block (anonymous, outer span)
  10453  //   Block (anonymous, inner span)
  10454  //     Block (div)
  10455  //       Text("c")
  10456  // Inline (outer span)
  10457  //   Inline (inner span)
  10458  //   Text("d")
  10459  // Block (anonymous, outer span)
  10460  //   Block (div)
  10461  //     Text("e")
  10462  // Inline (outer span)
  10463  //   Text("f")
  10464 
  10465  nsIContent* const content = aItem.mContent;
  10466  ComputedStyle* const computedStyle = aItem.mComputedStyle;
  10467 
  10468  nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
  10469 
  10470  // Initialize the frame
  10471  InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
  10472 
  10473  // definition cannot be inside next block because the object's destructor is
  10474  // significant. this is part of the fix for bug 42372
  10475  nsFrameConstructorSaveState absoluteSaveState;
  10476 
  10477  bool isAbsPosCB = newFrame->IsAbsPosContainingBlock();
  10478  newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  10479  if (isAbsPosCB) {
  10480    // Relatively positioned frames becomes a container for child
  10481    // frames that are positioned
  10482    aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
  10483  }
  10484 
  10485  if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
  10486      !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
  10487    newFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10488  }
  10489 
  10490  // Process the child content
  10491  nsFrameList childList;
  10492  ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
  10493                              /* aParentIsWrapperAnonBox = */ false, childList);
  10494 
  10495  nsIFrame* firstBlock = nullptr;
  10496  if (!aItem.mIsAllInline) {
  10497    for (nsIFrame* f : childList) {
  10498      if (f->IsBlockOutside()) {
  10499        firstBlock = f;
  10500        break;
  10501      }
  10502    }
  10503  }
  10504 
  10505  if (aItem.mIsAllInline || !firstBlock) {
  10506    // This part is easy.  We either already know we have no non-inline kids,
  10507    // or haven't found any when constructing actual frames (the latter can
  10508    // happen only if out-of-flows that we thought had no containing block
  10509    // acquired one when ancestor inline frames and {ib} splits got
  10510    // constructed).  Just put all the kids into the single inline frame and
  10511    // bail.
  10512    newFrame->SetInitialChildList(FrameChildListID::Principal,
  10513                                  std::move(childList));
  10514    aState.AddChild(newFrame, aFrameList, content, aParentFrame);
  10515    return newFrame;
  10516  }
  10517 
  10518  // This inline frame contains several types of children. Therefore this frame
  10519  // has to be chopped into several pieces, as described above.
  10520 
  10521  // Grab the first inline's kids
  10522  nsFrameList firstInlineKids = childList.TakeFramesBefore(firstBlock);
  10523  newFrame->SetInitialChildList(FrameChildListID::Principal,
  10524                                std::move(firstInlineKids));
  10525 
  10526  aFrameList.AppendFrame(nullptr, newFrame);
  10527 
  10528  newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
  10529  CreateIBSiblings(aState, newFrame, isAbsPosCB, childList, aFrameList);
  10530 
  10531  return newFrame;
  10532 }
  10533 
  10534 void nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
  10535                                             nsContainerFrame* aInitialInline,
  10536                                             bool aIsAbsPosCB,
  10537                                             nsFrameList& aChildList,
  10538                                             nsFrameList& aSiblings) {
  10539  MOZ_ASSERT(aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock());
  10540 
  10541  nsIContent* content = aInitialInline->GetContent();
  10542  ComputedStyle* computedStyle = aInitialInline->Style();
  10543  nsContainerFrame* parentFrame = aInitialInline->GetParent();
  10544 
  10545  // Resolve the right style for our anonymous blocks.
  10546  //
  10547  // The distinction in styles is needed because of CSS 2.1, section
  10548  // 9.2.1.1, which says:
  10549  //
  10550  //   When such an inline box is affected by relative positioning, any
  10551  //   resulting translation also affects the block-level box contained
  10552  //   in the inline box.
  10553  RefPtr<ComputedStyle> blockSC =
  10554      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
  10555          PseudoStyleType::mozBlockInsideInlineWrapper, computedStyle);
  10556 
  10557  nsContainerFrame* lastNewInline =
  10558      static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
  10559  do {
  10560    // On entry to this loop aChildList is not empty and the first frame in it
  10561    // is block-level.
  10562    MOZ_ASSERT(aChildList.NotEmpty(), "Should have child items");
  10563    MOZ_ASSERT(aChildList.FirstChild()->IsBlockOutside(),
  10564               "Must have list starting with block");
  10565 
  10566    // The initial run of blocks belongs to an anonymous block that we create
  10567    // right now. The anonymous block will be the parent of these block
  10568    // children of the inline.
  10569    nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
  10570    InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
  10571    if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
  10572      blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10573    }
  10574 
  10575    // Find the first non-block child which defines the end of our block kids
  10576    // and the start of our next inline's kids
  10577    nsFrameList blockKids =
  10578        aChildList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
  10579 
  10580    if (!aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
  10581      MoveChildrenTo(aInitialInline, blockFrame, blockKids);
  10582 
  10583      SetFrameIsIBSplit(lastNewInline, blockFrame);
  10584      aSiblings.AppendFrame(nullptr, blockFrame);
  10585    } else {
  10586      // Extract any initial non-column-span frames, and put them in
  10587      // blockFrame's child list.
  10588      nsFrameList initialNonColumnSpanKids =
  10589          blockKids.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
  10590      MoveChildrenTo(aInitialInline, blockFrame, initialNonColumnSpanKids);
  10591 
  10592      SetFrameIsIBSplit(lastNewInline, blockFrame);
  10593      aSiblings.AppendFrame(nullptr, blockFrame);
  10594 
  10595      if (blockKids.NotEmpty()) {
  10596        // Although SetFrameIsIBSplit() will add NS_FRAME_PART_OF_IBSPLIT for
  10597        // blockFrame later, we manually add the bit earlier here to make all
  10598        // the continuations of blockFrame created in
  10599        // CreateColumnSpanSiblings(), i.e. non-column-span wrappers, have the
  10600        // bit via nsIFrame::Init().
  10601        blockFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
  10602 
  10603        nsFrameList columnSpanSiblings =
  10604            CreateColumnSpanSiblings(aState, blockFrame, blockKids,
  10605                                     aIsAbsPosCB ? aInitialInline : nullptr);
  10606        aSiblings.AppendFrames(nullptr, std::move(columnSpanSiblings));
  10607      }
  10608    }
  10609 
  10610    // Now grab the initial inlines in aChildList and put them into an inline
  10611    // frame.
  10612    nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
  10613    InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
  10614    inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  10615    if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
  10616      inlineFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  10617    }
  10618 
  10619    if (aIsAbsPosCB) {
  10620      inlineFrame->MarkAsAbsoluteContainingBlock();
  10621    }
  10622 
  10623    if (aChildList.NotEmpty()) {
  10624      nsFrameList inlineKids =
  10625          aChildList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
  10626      MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
  10627    }
  10628 
  10629    SetFrameIsIBSplit(blockFrame, inlineFrame);
  10630    aSiblings.AppendFrame(nullptr, inlineFrame);
  10631    lastNewInline = inlineFrame;
  10632  } while (aChildList.NotEmpty());
  10633 
  10634  SetFrameIsIBSplit(lastNewInline, nullptr);
  10635 }
  10636 
  10637 void nsCSSFrameConstructor::BuildInlineChildItems(
  10638    nsFrameConstructorState& aState, FrameConstructionItem& aParentItem,
  10639    bool aItemIsWithinSVGText, bool aItemAllowsTextPathChild) {
  10640  ComputedStyle* const parentStyle = aParentItem.mComputedStyle;
  10641  nsIContent* const parentContent = aParentItem.mContent;
  10642 
  10643  if (!aItemIsWithinSVGText) {
  10644    if (parentStyle->StyleDisplay()->IsListItem()) {
  10645      CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
  10646                                 *parentStyle, PseudoStyleType::marker,
  10647                                 aParentItem.mChildItems);
  10648    }
  10649    // Probe for generated content before
  10650    CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
  10651                               *parentStyle, PseudoStyleType::before,
  10652                               aParentItem.mChildItems);
  10653  }
  10654 
  10655  ItemFlags flags;
  10656  if (aItemIsWithinSVGText) {
  10657    flags += ItemFlag::IsWithinSVGText;
  10658  }
  10659  if (aItemAllowsTextPathChild &&
  10660      aParentItem.mContent->IsSVGElement(nsGkAtoms::a)) {
  10661    flags += ItemFlag::AllowTextPathChild;
  10662  }
  10663 
  10664  FlattenedChildIterator iter(parentContent);
  10665  for (nsIContent* content = iter.GetNextChild(); content;
  10666       content = iter.GetNextChild()) {
  10667    AddFrameConstructionItems(aState, content, iter.ShadowDOMInvolved(),
  10668                              *parentStyle, InsertionPoint(),
  10669                              aParentItem.mChildItems, flags);
  10670  }
  10671 
  10672  if (!aItemIsWithinSVGText) {
  10673    // Probe for generated content after
  10674    CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
  10675                               *parentStyle, PseudoStyleType::after,
  10676                               aParentItem.mChildItems);
  10677  }
  10678 
  10679  aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
  10680 }
  10681 
  10682 // return whether it's ok to append (in the AppendFrames sense) to
  10683 // aParentFrame if our nextSibling is aNextSibling.  aParentFrame must
  10684 // be an ib-split inline.
  10685 static bool IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame,
  10686                                          nsIFrame* aNextSibling) {
  10687  MOZ_ASSERT(IsInlineFrame(aParentFrame), "Must have an inline parent here");
  10688 
  10689  do {
  10690    NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),
  10691                 "How is this not part of an ib-split?");
  10692    if (aNextSibling || aParentFrame->GetNextContinuation() ||
  10693        GetIBSplitSibling(aParentFrame)) {
  10694      return false;
  10695    }
  10696 
  10697    aNextSibling = aParentFrame->GetNextSibling();
  10698    aParentFrame = aParentFrame->GetParent();
  10699  } while (IsInlineFrame(aParentFrame));
  10700 
  10701  return true;
  10702 }
  10703 
  10704 bool nsCSSFrameConstructor::WipeInsertionParent(nsContainerFrame* aFrame) {
  10705 #define TRACE(reason)                                                  \
  10706  PROFILER_MARKER("WipeInsertionParent: " reason, LAYOUT, {}, Tracing, \
  10707                  "Layout");
  10708 
  10709  const LayoutFrameType frameType = aFrame->Type();
  10710 
  10711  // FIXME(emilio): This looks terribly inefficient if you insert elements deep
  10712  // in a MathML subtree.
  10713  if (aFrame->IsMathMLFrame()) {
  10714    TRACE("MathML");
  10715    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
  10716    return true;
  10717  }
  10718 
  10719  // A ruby-related frame that's getting new children.
  10720  // The situation for ruby is complex, especially when interacting with
  10721  // spaces. It contains these two special cases apart from tables:
  10722  // 1) There are effectively three types of white spaces in ruby frames
  10723  //    we handle differently: leading/tailing/inter-level space,
  10724  //    inter-base/inter-annotation space, and inter-segment space.
  10725  //    These three types of spaces can be converted to each other when
  10726  //    their sibling changes.
  10727  // 2) The first effective child of a ruby frame must always be a ruby
  10728  //    base container. It should be created or destroyed accordingly.
  10729  if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
  10730      RubyUtils::IsRubyContainerBox(frameType)) {
  10731    // We want to optimize it better, and avoid reframing as much as
  10732    // possible. But given the cases above, and the fact that a ruby
  10733    // usually won't be very large, it should be fine to reframe it.
  10734    TRACE("Ruby");
  10735    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
  10736    return true;
  10737  }
  10738 
  10739  // Reframe the multi-column container whenever elements insert/append
  10740  // into it because we need to reconstruct column-span split.
  10741  if (aFrame->IsColumnSetWrapperFrame()) {
  10742    TRACE("Multi-column");
  10743    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
  10744    return true;
  10745  }
  10746 
  10747  return false;
  10748 
  10749 #undef TRACE
  10750 }
  10751 
  10752 bool nsCSSFrameConstructor::WipeContainingBlock(
  10753    nsFrameConstructorState& aState, nsIFrame* aContainingBlock,
  10754    nsIFrame* aFrame, FrameConstructionItemList& aItems, bool aIsAppend,
  10755    nsIFrame* aPrevSibling) {
  10756 #define TRACE(reason)                                                  \
  10757  PROFILER_MARKER("WipeContainingBlock: " reason, LAYOUT, {}, Tracing, \
  10758                  "Layout");
  10759 
  10760  if (aItems.IsEmpty()) {
  10761    return false;
  10762  }
  10763 
  10764  // Before we go and append the frames, we must check for several
  10765  // special situations.
  10766 
  10767  if (aFrame->GetContent() == mDocument->GetRootElement()) {
  10768    // Situation #1 is when we insert content that becomes the canonical body
  10769    // element, and its used WritingMode is different from the root element's
  10770    // used WritingMode.
  10771    // We need to reframe the root element so that the root element's frames has
  10772    // the correct writing-mode propagated from body element. (See
  10773    // nsCSSFrameConstructor::ConstructDocElementFrame.)
  10774    //
  10775    // Bug 1594297: When inserting a new <body>, we may need to reframe the old
  10776    // <body> which has a "overflow" value other than simple "visible". But it's
  10777    // tricky, see bug 1593752.
  10778    nsIContent* bodyElement = mDocument->GetBodyElement();
  10779    for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
  10780      const WritingMode bodyWM(iter.item().mComputedStyle);
  10781      if (iter.item().mContent == bodyElement &&
  10782          bodyWM != aFrame->GetWritingMode()) {
  10783        TRACE("Root");
  10784        RecreateFramesForContent(mDocument->GetRootElement(),
  10785                                 InsertionKind::Async);
  10786        return true;
  10787      }
  10788    }
  10789  }
  10790 
  10791  nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
  10792 
  10793  // Situation #2 is a flex / grid  container frame into which we're inserting
  10794  // new inline non-replaced children, adjacent to an existing anonymous flex or
  10795  // grid item.
  10796  if (aFrame->IsFlexOrGridContainer()) {
  10797    FCItemIterator iter(aItems);
  10798 
  10799    // Check if we're adding to-be-wrapped content right *after* an existing
  10800    // anonymous flex or grid item (which would need to absorb this content).
  10801    const bool isLegacyWebKitBox = IsFlexContainerForLegacyWebKitBox(aFrame);
  10802    if (aPrevSibling && IsAnonymousItem(aPrevSibling) &&
  10803        iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
  10804      TRACE("Inserting inline after anon flex or grid item");
  10805      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
  10806      return true;
  10807    }
  10808 
  10809    // Check if we're adding to-be-wrapped content right *before* an existing
  10810    // anonymous flex or grid item (which would need to absorb this content).
  10811    if (nextSibling && IsAnonymousItem(nextSibling)) {
  10812      // Jump to the last entry in the list
  10813      iter.SetToEnd();
  10814      iter.Prev();
  10815      if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
  10816        TRACE("Inserting inline before anon flex or grid item");
  10817        RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
  10818        return true;
  10819      }
  10820    }
  10821  }
  10822 
  10823  // Situation #3 is an anonymous flex or grid item that's getting new children
  10824  // who don't want to be wrapped.
  10825  if (IsAnonymousItem(aFrame)) {
  10826    AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
  10827 
  10828    // We need to push a null float containing block to be sure that
  10829    // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
  10830    // inserted content. (In particular, this is necessary in order for
  10831    // its "GetGeometricParent" call to return the correct result.)
  10832    // We're not honoring floats on this content because it has the
  10833    // _flex/grid container_ as its parent in the content tree.
  10834    nsFrameConstructorSaveState floatSaveState;
  10835    aState.PushFloatContainingBlock(nullptr, floatSaveState);
  10836 
  10837    FCItemIterator iter(aItems);
  10838    // Skip over things that _do_ need an anonymous flex item, because
  10839    // they're perfectly happy to go here -- they won't cause a reframe.
  10840    nsIFrame* containerFrame = aFrame->GetParent();
  10841    const bool isLegacyWebKitBox =
  10842        IsFlexContainerForLegacyWebKitBox(containerFrame);
  10843    if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
  10844      // We hit something that _doesn't_ need an anonymous flex item!
  10845      // Rebuild the flex container to bust it out.
  10846      TRACE("Inserting non-inlines inside anon flex or grid item");
  10847      RecreateFramesForContent(containerFrame->GetContent(),
  10848                               InsertionKind::Async);
  10849      return true;
  10850    }
  10851 
  10852    // If we get here, then everything in |aItems| needs to be wrapped in
  10853    // an anonymous flex or grid item.  That's where it's already going - good!
  10854  }
  10855 
  10856  // Situation #4 is a case when table pseudo-frames don't work out right
  10857  ParentType parentType = GetParentType(aFrame);
  10858  // If all the kids want a parent of the type that aFrame is, then we're all
  10859  // set to go.  Indeed, there won't be any table pseudo-frames created between
  10860  // aFrame and the kids, so those won't need to be merged with any table
  10861  // pseudo-frames that might already be kids of aFrame.  If aFrame itself is a
  10862  // table pseudo-frame, then all the kids in this list would have wanted a
  10863  // frame of that type wrapping them anyway, so putting them inside it is ok.
  10864  if (!aItems.AllWantParentType(parentType)) {
  10865    // Don't give up yet.  If parentType is not eTypeBlock and the parent is
  10866    // not a generated content frame, then try filtering whitespace out of the
  10867    // list.
  10868    if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
  10869      // For leading whitespace followed by a kid that wants our parent type,
  10870      // there are four cases:
  10871      // 1) We have a previous sibling which is not a table pseudo.  That means
  10872      //    that previous sibling wanted a (non-block) parent of the type we're
  10873      //    looking at.  Then the whitespace comes between two table-internal
  10874      //    elements, so should be collapsed out.
  10875      // 2) We have a previous sibling which is a table pseudo.  It might have
  10876      //    kids who want this whitespace, so we need to reframe.
  10877      // 3) We have no previous sibling and our parent frame is not a table
  10878      //    pseudo.  That means that we'll be at the beginning of our actual
  10879      //    non-block-type parent, and the whitespace is OK to collapse out.
  10880      //    If something is ever inserted before us, it'll find our own parent
  10881      //    as its parent and if it's something that would care about the
  10882      //    whitespace it'll want a block parent, so it'll trigger a reframe at
  10883      //    that point.
  10884      // 4) We have no previous sibling and our parent frame is a table pseudo.
  10885      //    Need to reframe.
  10886      // All that is predicated on finding the correct previous sibling.  We
  10887      // might have to walk backwards along continuations from aFrame to do so.
  10888      //
  10889      // It's always OK to drop whitespace between any two items that want a
  10890      // parent of type parentType.
  10891      //
  10892      // For trailing whitespace preceded by a kid that wants our parent type,
  10893      // there are four cases:
  10894      // 1) We have a next sibling which is not a table pseudo.  That means
  10895      //    that next sibling wanted a (non-block) parent of the type we're
  10896      //    looking at.  Then the whitespace comes between two table-internal
  10897      //    elements, so should be collapsed out.
  10898      // 2) We have a next sibling which is a table pseudo.  It might have
  10899      //    kids who want this whitespace, so we need to reframe.
  10900      // 3) We have no next sibling and our parent frame is not a table
  10901      //    pseudo.  That means that we'll be at the end of our actual
  10902      //    non-block-type parent, and the whitespace is OK to collapse out.
  10903      //    If something is ever inserted after us, it'll find our own parent
  10904      //    as its parent and if it's something that would care about the
  10905      //    whitespace it'll want a block parent, so it'll trigger a reframe at
  10906      //    that point.
  10907      // 4) We have no next sibling and our parent frame is a table pseudo.
  10908      //    Need to reframe.
  10909      // All that is predicated on finding the correct next sibling.  We might
  10910      // have to walk forward along continuations from aFrame to do so.  That
  10911      // said, in the case when nextSibling is null at this point and aIsAppend
  10912      // is true, we know we're in case 3.  Furthermore, in that case we don't
  10913      // even have to worry about the table pseudo situation; we know our
  10914      // parent is not a table pseudo there.
  10915      FCItemIterator iter(aItems);
  10916      FCItemIterator start(iter);
  10917      do {
  10918        if (iter.SkipItemsWantingParentType(parentType)) {
  10919          break;
  10920        }
  10921 
  10922        // iter points to an item that wants a different parent.  If it's not
  10923        // whitespace, we're done; no more point scanning the list.
  10924        if (!iter.item().IsWhitespace(aState)) {
  10925          break;
  10926        }
  10927 
  10928        if (iter == start) {
  10929          // Leading whitespace.  How to handle this depends on our
  10930          // previous sibling and aFrame.  See the long comment above.
  10931          nsIFrame* prevSibling = aPrevSibling;
  10932          if (!prevSibling) {
  10933            // Try to find one after all
  10934            nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
  10935            while (parentPrevCont) {
  10936              prevSibling = parentPrevCont->PrincipalChildList().LastChild();
  10937              if (prevSibling) {
  10938                break;
  10939              }
  10940              parentPrevCont = parentPrevCont->GetPrevContinuation();
  10941            }
  10942          };
  10943          if (prevSibling) {
  10944            if (IsTablePseudo(prevSibling)) {
  10945              // need to reframe
  10946              break;
  10947            }
  10948          } else if (IsTablePseudo(aFrame)) {
  10949            // need to reframe
  10950            break;
  10951          }
  10952        }
  10953 
  10954        FCItemIterator spaceEndIter(iter);
  10955        // Advance spaceEndIter past any whitespace
  10956        bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
  10957 
  10958        bool okToDrop;
  10959        if (trailingSpaces) {
  10960          // Trailing whitespace.  How to handle this depeds on aIsAppend, our
  10961          // next sibling and aFrame.  See the long comment above.
  10962          okToDrop = aIsAppend && !nextSibling;
  10963          if (!okToDrop) {
  10964            if (!nextSibling) {
  10965              // Try to find one after all
  10966              nsIFrame* parentNextCont = aFrame->GetNextContinuation();
  10967              while (parentNextCont) {
  10968                nextSibling = parentNextCont->PrincipalChildList().FirstChild();
  10969                if (nextSibling) {
  10970                  break;
  10971                }
  10972                parentNextCont = parentNextCont->GetNextContinuation();
  10973              }
  10974            }
  10975 
  10976            okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
  10977                       (!nextSibling && !IsTablePseudo(aFrame));
  10978          } else {
  10979            NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
  10980          }
  10981        } else {
  10982          okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
  10983        }
  10984 
  10985        if (okToDrop) {
  10986          iter.DeleteItemsTo(this, spaceEndIter);
  10987        } else {
  10988          // We're done: we don't want to drop the whitespace, and it has the
  10989          // wrong parent type.
  10990          break;
  10991        }
  10992 
  10993        // Now loop, since |iter| points to item right after the whitespace we
  10994        // removed.
  10995      } while (!iter.IsDone());
  10996    }
  10997 
  10998    // We might be able to figure out some sort of optimizations here, but they
  10999    // would have to depend on having a correct aPrevSibling and a correct next
  11000    // sibling.  For example, we can probably avoid reframing if none of
  11001    // aFrame, aPrevSibling, and next sibling are table pseudo-frames.  But it
  11002    // doesn't seem worth it to worry about that for now, especially since we
  11003    // in fact do not have a reliable aPrevSibling, nor any next sibling, in
  11004    // this method.
  11005 
  11006    // aItems might have changed, so recheck the parent type thing.  In fact,
  11007    // it might be empty, so recheck that too.
  11008    if (aItems.IsEmpty()) {
  11009      return false;
  11010    }
  11011 
  11012    // If aFrame is empty, the insertion process will be able to take care of
  11013    // creating any needed pseudo-parents.
  11014    if (!aItems.AllWantParentType(parentType) &&
  11015        !SafeToInsertPseudoNeedingChildren(aFrame)) {
  11016      // Reframing aFrame->GetContent() is good enough, since the content of
  11017      // table pseudo-frames is the ancestor content.
  11018      TRACE("Pseudo-frames going wrong");
  11019      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
  11020      return true;
  11021    }
  11022  }
  11023 
  11024  // Situation #5 is a frame in multicol subtree that's getting new children.
  11025  if (aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
  11026    bool anyColumnSpanItems = false;
  11027    for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
  11028      if (iter.item().mComputedStyle->StyleColumn()->IsColumnSpanStyle()) {
  11029        anyColumnSpanItems = true;
  11030        break;
  11031      }
  11032    }
  11033 
  11034    bool needsReframe =
  11035        // 1. Insert / append any column-span children.
  11036        anyColumnSpanItems ||
  11037        // 2. GetInsertionPrevSibling() modifies insertion parent. If the prev
  11038        // sibling is a column-span, aFrame ends up being the
  11039        // column-span-wrapper.
  11040        aFrame->Style()->GetPseudoType() ==
  11041            PseudoStyleType::columnSpanWrapper ||
  11042        // 3. Append into {ib} split container. There might be room for
  11043        // optimization, but let's reframe for correctness...
  11044        IsFramePartOfIBSplit(aFrame);
  11045 
  11046    if (needsReframe) {
  11047      TRACE("Multi-column");
  11048      RecreateFramesForContent(
  11049          GetMultiColumnContainingBlockFor(aFrame)->GetContent(),
  11050          InsertionKind::Async);
  11051      return true;
  11052    }
  11053 
  11054    // If we get here, then we need further check for {ib} split to decide
  11055    // whether to reframe. For example, appending a block into an empty inline
  11056    // that is not part of an {ib} split, but should become an {ib} split.
  11057  }
  11058 
  11059  // A <fieldset> may need to pick up a new rendered legend from aItems.
  11060  // We currently can't handle this case without recreating frames for
  11061  // the fieldset.
  11062  // XXXmats we should be able to optimize this when the fieldset doesn't
  11063  // currently have a rendered legend.  ContentRangeInserted needs to be fixed
  11064  // to use the inner frame as the content insertion frame in that case.
  11065  if (const auto* fieldset = GetFieldSetFrameFor(aFrame)) {
  11066    // Check if any item is eligible to be a rendered legend.
  11067    for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
  11068      const auto& item = iter.item();
  11069      if (!item.mContent->IsHTMLElement(nsGkAtoms::legend)) {
  11070        continue;
  11071      }
  11072      const auto* display = item.mComputedStyle->StyleDisplay();
  11073      if (display->IsFloatingStyle() ||
  11074          display->IsAbsolutelyPositionedStyle()) {
  11075        continue;
  11076      }
  11077      TRACE("Fieldset with rendered legend");
  11078      RecreateFramesForContent(fieldset->GetContent(), InsertionKind::Async);
  11079      return true;
  11080    }
  11081  }
  11082 
  11083  // Now we have several cases involving {ib} splits.  Put them all in a
  11084  // do/while with breaks to take us to the "go and reconstruct" code.
  11085  do {
  11086    if (IsInlineFrame(aFrame)) {
  11087      if (aItems.AreAllItemsInline()) {
  11088        // We can just put the kids in.
  11089        return false;
  11090      }
  11091 
  11092      if (!IsFramePartOfIBSplit(aFrame)) {
  11093        // Need to go ahead and reconstruct.
  11094        break;
  11095      }
  11096 
  11097      // Now we're adding kids including some blocks to an inline part of an
  11098      // {ib} split.  If we plan to call AppendFrames, and don't have a next
  11099      // sibling for the new frames, and our parent is the last continuation of
  11100      // the last part of the {ib} split, and the same is true of all our
  11101      // ancestor inlines (they have no following continuations and they're the
  11102      // last part of their {ib} splits and we'd be adding to the end for all
  11103      // of them), then AppendFrames will handle things for us.  Bail out in
  11104      // that case.
  11105      if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
  11106        return false;
  11107      }
  11108 
  11109      // Need to reconstruct.
  11110      break;
  11111    }
  11112 
  11113    // Now we know we have a block parent.  If it's not part of an
  11114    // ib-split, we're all set.
  11115    if (!IsFramePartOfIBSplit(aFrame)) {
  11116      return false;
  11117    }
  11118 
  11119    // We're adding some kids to a block part of an {ib} split.  If all the
  11120    // kids are blocks, we don't need to reconstruct.
  11121    if (aItems.AreAllItemsBlock()) {
  11122      return false;
  11123    }
  11124 
  11125    // We might have some inline kids for this block.  Just fall out of the
  11126    // loop and reconstruct.
  11127  } while (false);
  11128 
  11129  // If we don't have a containing block, start with aFrame and look for one.
  11130  if (!aContainingBlock) {
  11131    aContainingBlock = aFrame;
  11132  }
  11133 
  11134  // To find the right block to reframe, just walk up the tree until we find a
  11135  // frame that is:
  11136  // 1)  Not part of an IB split
  11137  // 2)  Not a pseudo-frame
  11138  // 3)  Not an inline frame
  11139  // We're guaranteed to find one, since ComputedStyle::ApplyStyleFixups
  11140  // enforces that the root is display:none, display:table, or display:block.
  11141  // Note that walking up "too far" is OK in terms of correctness, even if it
  11142  // might be a little inefficient.  This is why we walk out of all
  11143  // pseudo-frames -- telling which ones are or are not OK to walk out of is
  11144  // too hard (and I suspect that we do in fact need to walk out of all of
  11145  // them).
  11146  while (IsFramePartOfIBSplit(aContainingBlock) ||
  11147         aContainingBlock->IsInlineOutside() ||
  11148         aContainingBlock->Style()->IsPseudoOrAnonBox()) {
  11149    aContainingBlock = aContainingBlock->GetParent();
  11150    NS_ASSERTION(aContainingBlock,
  11151                 "Must have non-inline, non-ib-split, non-pseudo frame as "
  11152                 "root (or child of root, for a table root)!");
  11153  }
  11154 
  11155  // Tell parent of the containing block to reformulate the
  11156  // entire block. This is painful and definitely not optimal
  11157  // but it will *always* get the right answer.
  11158 
  11159  nsIContent* blockContent = aContainingBlock->GetContent();
  11160  TRACE("IB splits");
  11161  RecreateFramesForContent(blockContent, InsertionKind::Async);
  11162  return true;
  11163 #undef TRACE
  11164 }
  11165 
  11166 void nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) {
  11167  // XXXbz how exactly would we get here while isReflowing anyway?  Should this
  11168  // whole test be ifdef DEBUG?
  11169  if (mPresShell->IsReflowLocked()) {
  11170    // don't ReframeContainingBlock, this will result in a crash
  11171    // if we remove a tree that's in reflow - see bug 121368 for testcase
  11172    NS_ERROR(
  11173        "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
  11174        "Reflow!!!");
  11175    return;
  11176  }
  11177 
  11178  // Get the first "normal" ancestor of the target frame.
  11179  nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
  11180  if (containingBlock) {
  11181    // From here we look for the containing block in case the target
  11182    // frame is already a block (which can happen when an inline frame
  11183    // wraps some of its content in an anonymous block; see
  11184    // ConstructInline)
  11185 
  11186    // NOTE: We used to get the FloatContainingBlock here, but it was often
  11187    // wrong. GetIBContainingBlock works much better and provides the correct
  11188    // container in all cases so GetFloatContainingBlock(aFrame) has been
  11189    // removed
  11190 
  11191    // And get the containingBlock's content
  11192    if (nsIContent* blockContent = containingBlock->GetContent()) {
  11193 #ifdef DEBUG
  11194      if (gNoisyContentUpdates) {
  11195        printf("  ==> blockContent=%p\n", blockContent);
  11196      }
  11197 #endif
  11198      RecreateFramesForContent(blockContent, InsertionKind::Async);
  11199      return;
  11200    }
  11201  }
  11202 
  11203  // If we get here, we're screwed!
  11204  RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
  11205                           InsertionKind::Async);
  11206 }
  11207 
  11208 //////////////////////////////////////////////////////////
  11209 // nsCSSFrameConstructor::FrameConstructionItem methods //
  11210 //////////////////////////////////////////////////////////
  11211 bool nsCSSFrameConstructor::FrameConstructionItem::IsWhitespace(
  11212    nsFrameConstructorState& aState) const {
  11213  MOZ_ASSERT(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame(),
  11214             "How did that happen?");
  11215  if (!mIsText) {
  11216    return false;
  11217  }
  11218  mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
  11219                     NS_REFRAME_IF_WHITESPACE);
  11220  return mContent->TextIsOnlyWhitespace();
  11221 }
  11222 
  11223 //////////////////////////////////////////////////////////////
  11224 // nsCSSFrameConstructor::FrameConstructionItemList methods //
  11225 //////////////////////////////////////////////////////////////
  11226 void nsCSSFrameConstructor::FrameConstructionItemList::AdjustCountsForItem(
  11227    FrameConstructionItem* aItem, int32_t aDelta) {
  11228  MOZ_ASSERT(aDelta == 1 || aDelta == -1, "Unexpected delta");
  11229  mItemCount += aDelta;
  11230  if (aItem->mIsAllInline) {
  11231    mInlineCount += aDelta;
  11232  }
  11233  if (aItem->mIsBlock) {
  11234    mBlockCount += aDelta;
  11235  }
  11236  mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
  11237 }
  11238 
  11239 ////////////////////////////////////////////////////////////////////////
  11240 // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
  11241 ////////////////////////////////////////////////////////////////////////
  11242 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11243    SkipItemsWantingParentType(ParentType aParentType) {
  11244  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
  11245  while (item().DesiredParentType() == aParentType) {
  11246    Next();
  11247    if (IsDone()) {
  11248      return true;
  11249    }
  11250  }
  11251  return false;
  11252 }
  11253 
  11254 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11255    SkipItemsNotWantingParentType(ParentType aParentType) {
  11256  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
  11257  while (item().DesiredParentType() != aParentType) {
  11258    Next();
  11259    if (IsDone()) {
  11260      return true;
  11261    }
  11262  }
  11263  return false;
  11264 }
  11265 
  11266 // Note: we implement -webkit-{inline-}box using nsFlexContainerFrame, but we
  11267 // use different rules for what gets wrapped in an anonymous flex item.
  11268 bool nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem(
  11269    const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
  11270  if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
  11271    // This will be an inline non-replaced box.
  11272    return true;
  11273  }
  11274 
  11275  if (aIsLegacyWebKitBox) {
  11276    if (mComputedStyle->StyleDisplay()->IsInlineOutsideStyle()) {
  11277      // In an emulated legacy box, all inline-level content gets wrapped in an
  11278      // anonymous flex item.
  11279      return true;
  11280    }
  11281    if (mIsPopup ||
  11282        (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
  11283         aState.GetGeometricParent(*mComputedStyle->StyleDisplay(), nullptr))) {
  11284      // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
  11285      // placeholder which (because our container is an emulated legacy box)
  11286      // we'll need to wrap in an anonymous flex item.  So, we just treat
  11287      // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
  11288      // and then when we spawn the placeholder, it'll end up in the right
  11289      // spot.
  11290      return true;
  11291    }
  11292  }
  11293 
  11294  return false;
  11295 }
  11296 
  11297 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11298    SkipItemsThatNeedAnonFlexOrGridItem(const nsFrameConstructorState& aState,
  11299                                        bool aIsLegacyWebKitBox) {
  11300  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
  11301  while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox)) {
  11302    Next();
  11303    if (IsDone()) {
  11304      return true;
  11305    }
  11306  }
  11307  return false;
  11308 }
  11309 
  11310 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11311    SkipItemsThatDontNeedAnonFlexOrGridItem(
  11312        const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
  11313  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
  11314  while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox))) {
  11315    Next();
  11316    if (IsDone()) {
  11317      return true;
  11318    }
  11319  }
  11320  return false;
  11321 }
  11322 
  11323 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11324    SkipItemsNotWantingRubyParent() {
  11325  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
  11326  while (!IsRubyParentType(item().DesiredParentType())) {
  11327    Next();
  11328    if (IsDone()) {
  11329      return true;
  11330    }
  11331  }
  11332  return false;
  11333 }
  11334 
  11335 inline bool
  11336 nsCSSFrameConstructor::FrameConstructionItemList::Iterator::SkipWhitespace(
  11337    nsFrameConstructorState& aState) {
  11338  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
  11339  MOZ_ASSERT(item().IsWhitespace(aState), "Not pointing to whitespace?");
  11340  do {
  11341    Next();
  11342    if (IsDone()) {
  11343      return true;
  11344    }
  11345  } while (item().IsWhitespace(aState));
  11346 
  11347  return false;
  11348 }
  11349 
  11350 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11351    AppendItemToList(FrameConstructionItemList& aTargetList) {
  11352  NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
  11353  MOZ_ASSERT(!IsDone(), "should not be done");
  11354 
  11355  FrameConstructionItem* item = mCurrent;
  11356  Next();
  11357  item->remove();
  11358  aTargetList.mItems.insertBack(item);
  11359 
  11360  mList.AdjustCountsForItem(item, -1);
  11361  aTargetList.AdjustCountsForItem(item, 1);
  11362 }
  11363 
  11364 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
  11365    AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
  11366                      FrameConstructionItemList& aTargetList) {
  11367  NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
  11368  MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?");
  11369 
  11370  // We can't just move our guts to the other list if it already has
  11371  // some information or if we're not moving our entire list.
  11372  if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
  11373    do {
  11374      AppendItemToList(aTargetList);
  11375    } while (*this != aEnd);
  11376    return;
  11377  }
  11378 
  11379  // Move our entire list of items into the empty target list.
  11380  aTargetList.mItems = std::move(mList.mItems);
  11381 
  11382  // Copy over the various counters
  11383  aTargetList.mInlineCount = mList.mInlineCount;
  11384  aTargetList.mBlockCount = mList.mBlockCount;
  11385  aTargetList.mItemCount = mList.mItemCount;
  11386  memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
  11387         sizeof(aTargetList.mDesiredParentCounts));
  11388 
  11389  // reset mList
  11390  mList.Reset(aFCtor);
  11391 
  11392  // Point ourselves to aEnd, as advertised
  11393  SetToEnd();
  11394  MOZ_ASSERT(*this == aEnd, "How did that happen?");
  11395 }
  11396 
  11397 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::InsertItem(
  11398    FrameConstructionItem* aItem) {
  11399  if (IsDone()) {
  11400    mList.mItems.insertBack(aItem);
  11401  } else {
  11402    // Just insert the item before us.  There's no magic here.
  11403    mCurrent->setPrevious(aItem);
  11404  }
  11405  mList.AdjustCountsForItem(aItem, 1);
  11406 
  11407  MOZ_ASSERT(aItem->getNext() == mCurrent, "How did that happen?");
  11408 }
  11409 
  11410 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::DeleteItemsTo(
  11411    nsCSSFrameConstructor* aFCtor, const Iterator& aEnd) {
  11412  MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?");
  11413  MOZ_ASSERT(*this != aEnd, "Shouldn't be at aEnd yet");
  11414 
  11415  do {
  11416    NS_ASSERTION(!IsDone(), "Ran off end of list?");
  11417    FrameConstructionItem* item = mCurrent;
  11418    Next();
  11419    item->remove();
  11420    mList.AdjustCountsForItem(item, -1);
  11421    item->Delete(aFCtor);
  11422  } while (*this != aEnd);
  11423 }
  11424 
  11425 void nsCSSFrameConstructor::QuotesDirty() {
  11426  mQuotesDirty = true;
  11427  mPresShell->SetNeedLayoutFlush();
  11428 }
  11429 
  11430 void nsCSSFrameConstructor::CountersDirty() {
  11431  mCountersDirty = true;
  11432  mPresShell->SetNeedLayoutFlush();
  11433 }
  11434 
  11435 void* nsCSSFrameConstructor::AllocateFCItem() {
  11436  void* item;
  11437  if (mFirstFreeFCItem) {
  11438    item = mFirstFreeFCItem;
  11439    mFirstFreeFCItem = mFirstFreeFCItem->mNext;
  11440  } else {
  11441    item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
  11442  }
  11443  ++mFCItemsInUse;
  11444  return item;
  11445 }
  11446 
  11447 void nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem) {
  11448  MOZ_ASSERT(mFCItemsInUse != 0);
  11449  if (--mFCItemsInUse == 0) {
  11450    // The arena is now unused - clear it but retain one chunk.
  11451    mFirstFreeFCItem = nullptr;
  11452    mFCItemPool.Clear();
  11453  } else {
  11454    // Prepend it to the list of free items.
  11455    FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
  11456    item->mNext = mFirstFreeFCItem;
  11457    mFirstFreeFCItem = item;
  11458  }
  11459 }
  11460 
  11461 void nsCSSFrameConstructor::AddSizeOfIncludingThis(
  11462    nsWindowSizes& aSizes) const {
  11463  if (nsIFrame* rootFrame = GetRootFrame()) {
  11464    rootFrame->AddSizeOfExcludingThisForTree(aSizes);
  11465    if (RetainedDisplayListBuilder* builder =
  11466            rootFrame->GetProperty(RetainedDisplayListBuilder::Cached())) {
  11467      builder->AddSizeOfIncludingThis(aSizes);
  11468    }
  11469  }
  11470 
  11471  // This must be done after measuring from the frame tree, since frame
  11472  // manager will measure sizes of staled computed values and style
  11473  // structs, which only make sense after we know what are being used.
  11474  nsFrameManager::AddSizeOfIncludingThis(aSizes);
  11475 
  11476  // Measurement of the following members may be added later if DMD finds it
  11477  // is worthwhile:
  11478  // - mFCItemPool
  11479  // - mContainStyleScopeManager
  11480 }