layout/base/nsCSSFrameConstructor.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 // vim:cindent:ts=2:et:sw=2:
     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/. */
     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  */
    12 #include "nsCSSFrameConstructor.h"
    14 #include "mozilla/AutoRestore.h"
    15 #include "mozilla/DebugOnly.h"
    16 #include "mozilla/dom/HTMLSelectElement.h"
    17 #include "mozilla/EventStates.h"
    18 #include "mozilla/Likely.h"
    19 #include "mozilla/LinkedList.h"
    20 #include "nsAbsoluteContainingBlock.h"
    21 #include "nsIAtom.h"
    22 #include "nsIFrameInlines.h"
    23 #include "nsGkAtoms.h"
    24 #include "nsPresContext.h"
    25 #include "nsIDocument.h"
    26 #include "nsTableFrame.h"
    27 #include "nsTableColFrame.h"
    28 #include "nsIDOMHTMLDocument.h"
    29 #include "nsHTMLParts.h"
    30 #include "nsIPresShell.h"
    31 #include "nsUnicharUtils.h"
    32 #include "nsStyleSet.h"
    33 #include "nsViewManager.h"
    34 #include "nsStyleConsts.h"
    35 #include "nsIDOMXULElement.h"
    36 #include "nsContainerFrame.h"
    37 #include "nsNameSpaceManager.h"
    38 #include "nsIComboboxControlFrame.h"
    39 #include "nsIListControlFrame.h"
    40 #include "nsIDOMCharacterData.h"
    41 #include "nsPlaceholderFrame.h"
    42 #include "nsTableRowGroupFrame.h"
    43 #include "nsIFormControl.h"
    44 #include "nsCSSAnonBoxes.h"
    45 #include "nsTextFragment.h"
    46 #include "nsIAnonymousContentCreator.h"
    47 #include "nsBindingManager.h"
    48 #include "nsXBLBinding.h"
    49 #include "nsContentUtils.h"
    50 #include "nsIScriptError.h"
    51 #ifdef XP_MACOSX
    52 #include "nsIDocShell.h"
    53 #endif
    54 #include "ChildIterator.h"
    55 #include "nsError.h"
    56 #include "nsLayoutUtils.h"
    57 #include "nsAutoPtr.h"
    58 #include "nsBoxFrame.h"
    59 #include "nsBoxLayout.h"
    60 #include "nsFlexContainerFrame.h"
    61 #include "nsGridContainerFrame.h"
    62 #include "nsImageFrame.h"
    63 #include "nsIObjectLoadingContent.h"
    64 #include "nsTArray.h"
    65 #include "nsGenericDOMDataNode.h"
    66 #include "mozilla/dom/Element.h"
    67 #include "nsAutoLayoutPhase.h"
    68 #include "nsStyleStructInlines.h"
    69 #include "nsPageContentFrame.h"
    70 #include "RestyleManager.h"
    71 #include "StickyScrollContainer.h"
    72 #include "nsFieldSetFrame.h"
    74 #ifdef MOZ_XUL
    75 #include "nsIRootBox.h"
    76 #endif
    77 #ifdef ACCESSIBILITY
    78 #include "nsAccessibilityService.h"
    79 #endif
    81 #include "nsBlockFrame.h"
    83 #include "nsIScrollableFrame.h"
    85 #include "nsXBLService.h"
    87 #undef NOISY_FIRST_LETTER
    89 #include "nsMathMLParts.h"
    90 #include "mozilla/dom/SVGTests.h"
    91 #include "nsSVGUtils.h"
    93 #include "nsRefreshDriver.h"
    94 #include "nsRuleProcessorData.h"
    95 #include "nsTextNode.h"
    97 using namespace mozilla;
    98 using namespace mozilla::dom;
   100 // An alias for convenience.
   101 static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
   103 nsIFrame*
   104 NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   106 nsIFrame*
   107 NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   109 nsIFrame*
   110 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   111 nsIFrame*
   112 NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   113 nsIFrame*
   114 NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   115 nsIFrame*
   116 NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   117 nsIFrame*
   118 NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   119 nsIFrame*
   120 NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   121 nsIFrame*
   122 NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   123 nsIFrame*
   124 NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   125 nsIFrame*
   126 NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   127 nsIFrame*
   128 NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   129 nsIFrame*
   130 NS_NewSVGContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   131 nsIFrame*
   132 NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   133 nsIFrame*
   134 NS_NewSVGViewFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   135 extern nsIFrame*
   136 NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
   137 extern nsIFrame*
   138 NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
   139 extern nsIFrame*
   140 NS_NewSVGStopFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
   141 nsIFrame*
   142 NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   143 nsIFrame*
   144 NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   145 extern nsIFrame*
   146 NS_NewSVGImageFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
   147 nsIFrame*
   148 NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   149 nsIFrame*
   150 NS_NewSVGFilterFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
   151 nsIFrame*
   152 NS_NewSVGPatternFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   153 nsIFrame*
   154 NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   155 nsIFrame*
   156 NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   157 nsIFrame*
   158 NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   159 nsIFrame*
   160 NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   161 nsIFrame*
   162 NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   164 #include "nsINodeInfo.h"
   165 #include "prenv.h"
   166 #include "nsNodeInfoManager.h"
   167 #include "nsContentCreatorFunctions.h"
   169 #ifdef DEBUG
   170 // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
   171 // more of the following flags (comma separated) for handy debug
   172 // output.
   173 static bool gNoisyContentUpdates = false;
   174 static bool gReallyNoisyContentUpdates = false;
   175 static bool gNoisyInlineConstruction = false;
   177 struct FrameCtorDebugFlags {
   178   const char* name;
   179   bool* on;
   180 };
   182 static FrameCtorDebugFlags gFlags[] = {
   183   { "content-updates",              &gNoisyContentUpdates },
   184   { "really-noisy-content-updates", &gReallyNoisyContentUpdates },
   185   { "noisy-inline",                 &gNoisyInlineConstruction }
   186 };
   188 #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
   189 #endif
   192 #ifdef MOZ_XUL
   193 #include "nsMenuFrame.h"
   194 #include "nsPopupSetFrame.h"
   195 #include "nsTreeColFrame.h"
   196 #include "nsIBoxObject.h"
   197 #include "nsPIListBoxObject.h"
   198 #include "nsListBoxBodyFrame.h"
   199 #include "nsListItemFrame.h"
   200 #include "nsXULLabelFrame.h"
   202 //------------------------------------------------------------------
   204 nsIFrame*
   205 NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   207 nsIFrame*
   208 NS_NewRootBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   210 nsIFrame*
   211 NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   213 nsIFrame*
   214 NS_NewThumbFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   216 nsIFrame*
   217 NS_NewDeckFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   219 nsIFrame*
   220 NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   222 nsIFrame*
   223 NS_NewStackFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   225 nsIFrame*
   226 NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   228 nsIFrame*
   229 NS_NewRangeFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   231 nsIFrame*
   232 NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   234 nsIFrame*
   235 NS_NewTextBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   237 nsIFrame*
   238 NS_NewGroupBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   240 nsIFrame*
   241 NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   243 nsIFrame*
   244 NS_NewSplitterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   246 nsIFrame*
   247 NS_NewMenuPopupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   249 nsIFrame*
   250 NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   252 nsIFrame*
   253 NS_NewMenuFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, uint32_t aFlags);
   255 nsIFrame*
   256 NS_NewMenuBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   258 nsIFrame*
   259 NS_NewTreeBodyFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   261 // grid
   262 nsresult
   263 NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsBoxLayout** aNewLayout );
   264 nsIFrame*
   265 NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   266 nsIFrame*
   267 NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   269 // end grid
   271 nsIFrame*
   272 NS_NewTitleBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   274 nsIFrame*
   275 NS_NewResizerFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   278 #endif
   280 nsIFrame*
   281 NS_NewHTMLScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot);
   283 nsIFrame*
   284 NS_NewXULScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext,
   285                       bool aIsRoot, bool aClipAllDescendants);
   287 nsIFrame*
   288 NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   290 nsIFrame*
   291 NS_NewScrollbarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   293 nsIFrame*
   294 NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
   297 #ifdef NOISY_FINDFRAME
   298 static int32_t FFWC_totalCount=0;
   299 static int32_t FFWC_doLoop=0;
   300 static int32_t FFWC_doSibling=0;
   301 static int32_t FFWC_recursions=0;
   302 static int32_t FFWC_nextInFlows=0;
   303 #endif
   305 // Returns true if aFrame is an anonymous flex item
   306 static inline bool
   307 IsAnonymousFlexItem(const nsIFrame* aFrame)
   308 {
   309   const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
   310   return pseudoType == nsCSSAnonBoxes::anonymousFlexItem;
   311 }
   313 static inline nsIFrame*
   314 GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
   315 {
   316   // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
   317   nsIFrame* firstChild = aFieldsetFrame->GetFirstPrincipalChild();
   318   nsIFrame* inner = firstChild && firstChild->GetNextSibling() ? firstChild->GetNextSibling() : firstChild;
   319   return inner ? inner->GetContentInsertionFrame() : nullptr;
   320 }
   322 #define FCDATA_DECL(_flags, _func)                          \
   323   { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr }
   324 #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box)  \
   325   { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS,        \
   326       { (FrameCreationFunc)_func }, nullptr, &_anon_box }
   328 //----------------------------------------------------------------------
   330 /**
   331  * True if aFrame is an actual inline frame in the sense of non-replaced
   332  * display:inline CSS boxes.  In other words, it can be affected by {ib}
   333  * splitting and can contain first-letter frames.  Basically, this is either an
   334  * inline frame (positioned or otherwise) or an line frame (this last because
   335  * it can contain first-letter and because inserting blocks in the middle of it
   336  * needs to terminate it).
   337  */
   338 static bool
   339 IsInlineFrame(const nsIFrame* aFrame)
   340 {
   341   return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
   342 }
   344 /**
   345  * True if aFrame is an instance of an SVG frame class or is an inline/block
   346  * frame being used for SVG text.
   347  */
   348 static bool
   349 IsFrameForSVG(const nsIFrame* aFrame)
   350 {
   351   return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
   352          aFrame->IsSVGText();
   353 }
   355 /**
   356  * Returns true iff aFrame explicitly prevents its descendants from floating
   357  * (at least, down to the level of descendants which themselves are
   358  * float-containing blocks -- those will manage the floating status of any
   359  * lower-level descendents inside them, of course).
   360  */
   361 static bool
   362 ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
   363 {
   364   return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
   365     aFrame->IsBoxFrame() ||
   366     aFrame->GetType() == nsGkAtoms::flexContainerFrame ||
   367     aFrame->GetType() == nsGkAtoms::gridContainerFrame;
   368 }
   370 /**
   371  * If any children require a block parent, return the first such child.
   372  * Otherwise return null.
   373  */
   374 static nsIContent*
   375 AnyKidsNeedBlockParent(nsIFrame *aFrameList)
   376 {
   377   for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
   378     // Line participants, such as text and inline frames, can't be
   379     // directly inside a XUL box; they must be wrapped in an
   380     // intermediate block.
   381     if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
   382       return k->GetContent();
   383     }
   384   }
   385   return nullptr;
   386 }
   388 // Reparent a frame into a wrapper frame that is a child of its old parent.
   389 static void
   390 ReparentFrame(RestyleManager* aRestyleManager,
   391               nsIFrame* aNewParentFrame,
   392               nsIFrame* aFrame)
   393 {
   394   aFrame->SetParent(aNewParentFrame);
   395   aRestyleManager->ReparentStyleContext(aFrame);
   396 }
   398 static void
   399 ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
   400                nsIFrame* aNewParentFrame,
   401                const nsFrameList& aFrameList)
   402 {
   403   RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
   404   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
   405     ReparentFrame(restyleManager, aNewParentFrame, e.get());
   406   }
   407 }
   409 //----------------------------------------------------------------------
   410 //
   411 // When inline frames get weird and have block frames in them, we
   412 // annotate them to help us respond to incremental content changes
   413 // more easily.
   415 static inline bool
   416 IsFramePartOfIBSplit(nsIFrame* aFrame)
   417 {
   418   return (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0;
   419 }
   421 static nsIFrame* GetIBSplitSibling(nsIFrame* aFrame)
   422 {
   423   NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
   425   // We only store the "ib-split sibling" annotation with the first
   426   // frame in the continuation chain. Walk back to find that frame now.
   427   return static_cast<nsIFrame*>
   428     (aFrame->FirstContinuation()->
   429        Properties().Get(nsIFrame::IBSplitSibling()));
   430 }
   432 static nsIFrame* GetIBSplitPrevSibling(nsIFrame* aFrame)
   433 {
   434   NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
   436   // We only store the ib-split sibling annotation with the first
   437   // frame in the continuation chain. Walk back to find that frame now.
   438   return static_cast<nsIFrame*>
   439     (aFrame->FirstContinuation()->
   440        Properties().Get(nsIFrame::IBSplitPrevSibling()));
   441 }
   443 static nsIFrame*
   444 GetLastIBSplitSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline)
   445 {
   446   for (nsIFrame *frame = aFrame, *next; ; frame = next) {
   447     next = GetIBSplitSibling(frame);
   448     if (!next ||
   449         (!aReturnEmptyTrailingInline && !next->GetFirstPrincipalChild() &&
   450          !GetIBSplitSibling(next))) {
   451       NS_ASSERTION(!next || !frame->IsInlineOutside(),
   452                    "Should have a block here!");
   453       return frame;
   454     }
   455   }
   456   NS_NOTREACHED("unreachable code");
   457   return nullptr;
   458 }
   460 static void
   461 SetFrameIsIBSplit(nsIFrame* aFrame, nsIFrame* aIBSplitSibling)
   462 {
   463   NS_PRECONDITION(aFrame, "bad args!");
   465   // We should be the only continuation
   466   NS_ASSERTION(!aFrame->GetPrevContinuation(),
   467                "assigning ib-split sibling to other than first continuation!");
   468   NS_ASSERTION(!aFrame->GetNextContinuation() ||
   469                IsFramePartOfIBSplit(aFrame->GetNextContinuation()),
   470                "should have no non-ib-split continuations here");
   472   // Mark the frame as ib-split.
   473   aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
   475   if (aIBSplitSibling) {
   476     NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),
   477                  "assigning something other than the first continuation as the "
   478                  "ib-split sibling");
   480     // Store the ib-split sibling (if we were given one) with the
   481     // first frame in the flow.
   482     FramePropertyTable* props = aFrame->PresContext()->PropertyTable();
   483     props->Set(aFrame, nsIFrame::IBSplitSibling(), aIBSplitSibling);
   484     props->Set(aIBSplitSibling, nsIFrame::IBSplitPrevSibling(), aFrame);
   485   }
   486 }
   488 static nsIFrame*
   489 GetIBContainingBlockFor(nsIFrame* aFrame)
   490 {
   491   NS_PRECONDITION(IsFramePartOfIBSplit(aFrame),
   492                   "GetIBContainingBlockFor() should only be called on known IB frames");
   494   // Get the first "normal" ancestor of the target frame.
   495   nsIFrame* parentFrame;
   496   do {
   497     parentFrame = aFrame->GetParent();
   499     if (! parentFrame) {
   500       NS_ERROR("no unsplit block frame in IB hierarchy");
   501       return aFrame;
   502     }
   504     // Note that we ignore non-ib-split frames which have a pseudo on their
   505     // style context -- they're not the frames we're looking for!  In
   506     // particular, they may be hiding a real parent that _is_ in an ib-split.
   507     if (!IsFramePartOfIBSplit(parentFrame) &&
   508         !parentFrame->StyleContext()->GetPseudo())
   509       break;
   511     aFrame = parentFrame;
   512   } while (1);
   514   // post-conditions
   515   NS_ASSERTION(parentFrame, "no normal ancestor found for ib-split frame "
   516                             "in GetIBContainingBlockFor");
   517   NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt");
   519   return parentFrame;
   520 }
   522 //----------------------------------------------------------------------
   524 // Block/inline frame construction logic. We maintain a few invariants here:
   525 //
   526 // 1. Block frames contain block and inline frames.
   527 //
   528 // 2. Inline frames only contain inline frames. If an inline parent has a block
   529 // child then the block child is migrated upward until it lands in a block
   530 // parent (the inline frames containing block is where it will end up).
   532 // After this function returns, aLink is pointing to the first link at or
   533 // after its starting position for which the next frame is a block.  If there
   534 // is no such link, it points to the end of the list.
   535 static void
   536 FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink)
   537 {
   538   for ( ; !aLink.AtEnd(); aLink.Next()) {
   539     if (!aLink.NextFrame()->IsInlineOutside()) {
   540       return;
   541     }
   542   }
   543 }
   545 // This function returns a frame link enumerator pointing to the first link in
   546 // the list for which the next frame is not block.  If there is no such link,
   547 // it points to the end of the list.
   548 static nsFrameList::FrameLinkEnumerator
   549 FindFirstNonBlock(const nsFrameList& aList)
   550 {
   551   nsFrameList::FrameLinkEnumerator link(aList);
   552   for (; !link.AtEnd(); link.Next()) {
   553     if (link.NextFrame()->IsInlineOutside()) {
   554       break;
   555     }
   556   }
   557   return link;
   558 }
   560 inline void
   561 SetInitialSingleChild(nsIFrame* aParent, nsIFrame* aFrame)
   562 {
   563   NS_PRECONDITION(!aFrame->GetNextSibling(), "Should be using a frame list");
   564   nsFrameList temp(aFrame, aFrame);
   565   aParent->SetInitialChildList(kPrincipalList, temp);
   566 }
   568 // -----------------------------------------------------------
   570 // Structure used when constructing formatting object trees.
   571 struct nsFrameItems : public nsFrameList
   572 {
   573   // Appends the frame to the end of the list
   574   void AddChild(nsIFrame* aChild);
   575 };
   577 void
   578 nsFrameItems::AddChild(nsIFrame* aChild)
   579 {
   580   NS_PRECONDITION(aChild, "nsFrameItems::AddChild");
   582   // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild) here,
   583   // but some of our callers put frames that have different
   584   // parents (caption, I'm looking at you) on the same framelist, and
   585   // nsFrameList asserts if you try to do that.
   586   if (IsEmpty()) {
   587     SetFrames(aChild);
   588   }
   589   else {
   590     NS_ASSERTION(aChild != mLastChild,
   591                  "Same frame being added to frame list twice?");
   592     mLastChild->SetNextSibling(aChild);
   593     mLastChild = nsLayoutUtils::GetLastSibling(aChild);
   594   }
   595 }
   597 // -----------------------------------------------------------
   599 // Structure used when constructing formatting object trees. Contains
   600 // state information needed for absolutely positioned elements
   601 struct nsAbsoluteItems : nsFrameItems {
   602   // containing block for absolutely positioned elements
   603   nsIFrame* containingBlock;
   605   nsAbsoluteItems(nsIFrame* aContainingBlock);
   606 #ifdef DEBUG
   607   // XXXbz Does this need a debug-only assignment operator that nulls out the
   608   // childList in the nsAbsoluteItems we're copying?  Introducing a difference
   609   // between debug and non-debug behavior seems bad, so I guess not...
   610   ~nsAbsoluteItems() {
   611     NS_ASSERTION(!FirstChild(),
   612                  "Dangling child list.  Someone forgot to insert it?");
   613   }
   614 #endif
   616   // Appends the frame to the end of the list
   617   void AddChild(nsIFrame* aChild);
   618 };
   620 nsAbsoluteItems::nsAbsoluteItems(nsIFrame* aContainingBlock)
   621   : containingBlock(aContainingBlock)
   622 {
   623 }
   625 // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
   626 void
   627 nsAbsoluteItems::AddChild(nsIFrame* aChild)
   628 {
   629   NS_ASSERTION(aChild->PresContext()->FrameManager()->
   630                GetPlaceholderFrameFor(aChild),
   631                "Child without placeholder being added to nsAbsoluteItems?");
   632   aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
   633   nsFrameItems::AddChild(aChild);
   634 }
   636 // -----------------------------------------------------------
   638 // Structure for saving the existing state when pushing/poping containing
   639 // blocks. The destructor restores the state to its previous state
   640 class MOZ_STACK_CLASS nsFrameConstructorSaveState {
   641 public:
   642   typedef nsIFrame::ChildListID ChildListID;
   643   nsFrameConstructorSaveState();
   644   ~nsFrameConstructorSaveState();
   646 private:
   647   nsAbsoluteItems* mItems;      // pointer to struct whose data we save/restore
   648   nsAbsoluteItems  mSavedItems; // copy of original data
   650   // The name of the child list in which our frames would belong
   651   ChildListID mChildListID;
   652   nsFrameConstructorState* mState;
   654   // State used only when we're saving the abs-pos state for a transformed
   655   // element.
   656   nsAbsoluteItems mSavedFixedItems;
   658   bool mSavedFixedPosIsAbsPos;
   660   friend class nsFrameConstructorState;
   661 };
   663 // Structure used to keep track of a list of bindings we need to call
   664 // AddToAttachedQueue on.  These should be in post-order depth-first
   665 // flattened tree traversal order.
   666 struct PendingBinding : public LinkedListElement<PendingBinding>
   667 {
   668 #ifdef NS_BUILD_REFCNT_LOGGING
   669   PendingBinding() {
   670     MOZ_COUNT_CTOR(PendingBinding);
   671   }
   672   ~PendingBinding() {
   673     MOZ_COUNT_DTOR(PendingBinding);
   674   }
   675 #endif
   677   nsRefPtr<nsXBLBinding> mBinding;
   678 };
   680 // Structure used for maintaining state information during the
   681 // frame construction process
   682 class MOZ_STACK_CLASS nsFrameConstructorState {
   683 public:
   684   typedef nsIFrame::ChildListID ChildListID;
   686   nsPresContext            *mPresContext;
   687   nsIPresShell             *mPresShell;
   688   nsFrameManager           *mFrameManager;
   690 #ifdef MOZ_XUL
   691   // Frames destined for the kPopupList.
   692   nsAbsoluteItems           mPopupItems;
   693 #endif
   695   // Containing block information for out-of-flow frames.
   696   nsAbsoluteItems           mFixedItems;
   697   nsAbsoluteItems           mAbsoluteItems;
   698   nsAbsoluteItems           mFloatedItems;
   700   nsCOMPtr<nsILayoutHistoryState> mFrameState;
   701   // These bits will be added to the state bits of any frame we construct
   702   // using this state.
   703   nsFrameState              mAdditionalStateBits;
   705   // When working with the -moz-transform property, we want to hook
   706   // the abs-pos and fixed-pos lists together, since transformed
   707   // elements are fixed-pos containing blocks.  This flag determines
   708   // whether or not we want to wire the fixed-pos and abs-pos lists
   709   // together.
   710   bool                      mFixedPosIsAbsPos;
   712   // A boolean to indicate whether we have a "pending" popupgroup.  That is, we
   713   // have already created the FrameConstructionItem for the root popupgroup but
   714   // we have not yet created the relevant frame.
   715   bool                      mHavePendingPopupgroup;
   717   // If false (which is the default) then call SetPrimaryFrame() as needed
   718   // during frame construction.  If true, don't make any SetPrimaryFrame()
   719   // calls, except for generated content which doesn't have a primary frame
   720   // yet.  The mCreatingExtraFrames == true mode is meant to be used for
   721   // construction of random "extra" frames for elements via normal frame
   722   // construction APIs (e.g. replication of things across pages in paginated
   723   // mode).
   724   bool                      mCreatingExtraFrames;
   726   nsCOMArray<nsIContent>    mGeneratedTextNodesWithInitializer;
   728   TreeMatchContext          mTreeMatchContext;
   730   // Constructor
   731   // Use the passed-in history state.
   732   nsFrameConstructorState(nsIPresShell*          aPresShell,
   733                           nsIFrame*              aFixedContainingBlock,
   734                           nsIFrame*              aAbsoluteContainingBlock,
   735                           nsIFrame*              aFloatContainingBlock,
   736                           nsILayoutHistoryState* aHistoryState);
   737   // Get the history state from the pres context's pres shell.
   738   nsFrameConstructorState(nsIPresShell*          aPresShell,
   739                           nsIFrame*              aFixedContainingBlock,
   740                           nsIFrame*              aAbsoluteContainingBlock,
   741                           nsIFrame*              aFloatContainingBlock);
   743   ~nsFrameConstructorState();
   745   // Function to push the existing absolute containing block state and
   746   // create a new scope. Code that uses this function should get matching
   747   // logic in GetAbsoluteContainingBlock.
   748   // Also makes aNewAbsoluteContainingBlock the containing block for
   749   // fixed-pos elements if necessary.
   750   // aPositionedFrame is the frame whose style actually makes
   751   // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
   752   // aPositionedFrame is the element's primary frame and
   753   // aNewAbsoluteContainingBlock is the scrolled frame.
   754   void PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock,
   755                                    nsIFrame* aPositionedFrame,
   756                                    nsFrameConstructorSaveState& aSaveState);
   758   // Function to push the existing float containing block state and
   759   // create a new scope. Code that uses this function should get matching
   760   // logic in GetFloatContainingBlock.
   761   // Pushing a null float containing block forbids any frames from being
   762   // floated until a new float containing block is pushed.
   763   // XXX we should get rid of null float containing blocks and teach the
   764   // various frame classes to deal with floats instead.
   765   void PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock,
   766                                 nsFrameConstructorSaveState& aSaveState);
   768   // Function to return the proper geometric parent for a frame with display
   769   // struct given by aStyleDisplay and parent's frame given by
   770   // aContentParentFrame.
   771   nsIFrame* GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
   772                                nsIFrame* aContentParentFrame) const;
   774   /**
   775    * Function to add a new frame to the right frame list.  This MUST be called
   776    * on frames before their children have been processed if the frames might
   777    * conceivably be out-of-flow; otherwise cleanup in error cases won't work
   778    * right.  Also, this MUST be called on frames after they have been
   779    * initialized.
   780    * @param aNewFrame the frame to add
   781    * @param aFrameItems the list to add in-flow frames to
   782    * @param aContent the content pointer for aNewFrame
   783    * @param aStyleContext the style context resolved for aContent
   784    * @param aParentFrame the parent frame for the content if it were in-flow
   785    * @param aCanBePositioned pass false if the frame isn't allowed to be
   786    *        positioned
   787    * @param aCanBeFloated pass false if the frame isn't allowed to be
   788    *        floated
   789    * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
   790    *        (XUL-only)
   791    */
   792   void AddChild(nsIFrame* aNewFrame,
   793                 nsFrameItems& aFrameItems,
   794                 nsIContent* aContent,
   795                 nsStyleContext* aStyleContext,
   796                 nsIFrame* aParentFrame,
   797                 bool aCanBePositioned = true,
   798                 bool aCanBeFloated = true,
   799                 bool aIsOutOfFlowPopup = false,
   800                 bool aInsertAfter = false,
   801                 nsIFrame* aInsertAfterFrame = nullptr);
   803   /**
   804    * Function to return the fixed-pos element list.  Normally this will just hand back the
   805    * fixed-pos element list, but in case we're dealing with a transformed element that's
   806    * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list.  Callers should
   807    * use this function if they want to get the list acting as the fixed-pos item parent.
   808    */
   809   nsAbsoluteItems& GetFixedItems()
   810   {
   811     return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
   812   }
   813   const nsAbsoluteItems& GetFixedItems() const
   814   {
   815     return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
   816   }
   819   /**
   820    * class to automatically push and pop a pending binding in the frame
   821    * constructor state.  See nsCSSFrameConstructor::FrameConstructionItem
   822    * mPendingBinding documentation.
   823    */
   824   class PendingBindingAutoPusher;
   825   friend class PendingBindingAutoPusher;
   826   class MOZ_STACK_CLASS PendingBindingAutoPusher {
   827   public:
   828     PendingBindingAutoPusher(nsFrameConstructorState& aState,
   829                              PendingBinding* aPendingBinding) :
   830       mState(aState),
   831       mPendingBinding(aState.mCurrentPendingBindingInsertionPoint)
   832         {
   833           if (aPendingBinding) {
   834             aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
   835           }
   836         }
   838     ~PendingBindingAutoPusher()
   839       {
   840         mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
   841       }
   843   private:
   844     nsFrameConstructorState& mState;
   845     PendingBinding* mPendingBinding;
   846   };
   848   /**
   849    * Add a new pending binding to the list
   850    */
   851   void AddPendingBinding(PendingBinding* aPendingBinding) {
   852     if (mCurrentPendingBindingInsertionPoint) {
   853       mCurrentPendingBindingInsertionPoint->setPrevious(aPendingBinding);
   854     } else {
   855       mPendingBindings.insertBack(aPendingBinding);
   856     }
   857   }
   859 protected:
   860   friend class nsFrameConstructorSaveState;
   862   /**
   863    * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
   864    * kids to the aChildListID child list of |aFrameItems.containingBlock|.
   865    */
   866   void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
   867                               ChildListID aChildListID);
   869   // Our list of all pending bindings.  When we're done, we need to call
   870   // AddToAttachedQueue on all of them, in order.
   871   LinkedList<PendingBinding> mPendingBindings;
   873   PendingBinding* mCurrentPendingBindingInsertionPoint;
   874 };
   876 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell*          aPresShell,
   877                                                  nsIFrame*              aFixedContainingBlock,
   878                                                  nsIFrame*              aAbsoluteContainingBlock,
   879                                                  nsIFrame*              aFloatContainingBlock,
   880                                                  nsILayoutHistoryState* aHistoryState)
   881   : mPresContext(aPresShell->GetPresContext()),
   882     mPresShell(aPresShell),
   883     mFrameManager(aPresShell->FrameManager()),
   884 #ifdef MOZ_XUL
   885     mPopupItems(nullptr),
   886 #endif
   887     mFixedItems(aFixedContainingBlock),
   888     mAbsoluteItems(aAbsoluteContainingBlock),
   889     mFloatedItems(aFloatContainingBlock),
   890     // See PushAbsoluteContaningBlock below
   891     mFrameState(aHistoryState),
   892     mAdditionalStateBits(nsFrameState(0)),
   893     // If the fixed-pos containing block is equal to the abs-pos containing
   894     // block, use the abs-pos containing block's abs-pos list for fixed-pos
   895 	// frames.
   896     mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
   897     mHavePendingPopupgroup(false),
   898     mCreatingExtraFrames(false),
   899     mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
   900                       aPresShell->GetDocument()),
   901     mCurrentPendingBindingInsertionPoint(nullptr)
   902 {
   903 #ifdef MOZ_XUL
   904   nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
   905   if (rootBox) {
   906     mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
   907   }
   908 #endif
   909   MOZ_COUNT_CTOR(nsFrameConstructorState);
   910 }
   912 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
   913                                                  nsIFrame*     aFixedContainingBlock,
   914                                                  nsIFrame*     aAbsoluteContainingBlock,
   915                                                  nsIFrame*     aFloatContainingBlock)
   916   : mPresContext(aPresShell->GetPresContext()),
   917     mPresShell(aPresShell),
   918     mFrameManager(aPresShell->FrameManager()),
   919 #ifdef MOZ_XUL
   920     mPopupItems(nullptr),
   921 #endif
   922     mFixedItems(aFixedContainingBlock),
   923     mAbsoluteItems(aAbsoluteContainingBlock),
   924     mFloatedItems(aFloatContainingBlock),
   925     // See PushAbsoluteContaningBlock below
   926     mAdditionalStateBits(nsFrameState(0)),
   927     // If the fixed-pos containing block is equal to the abs-pos containing
   928     // block, use the abs-pos containing block's abs-pos list for fixed-pos
   929 	// frames.
   930     mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
   931     mHavePendingPopupgroup(false),
   932     mCreatingExtraFrames(false),
   933     mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
   934                       aPresShell->GetDocument()),
   935     mCurrentPendingBindingInsertionPoint(nullptr)
   936 {
   937 #ifdef MOZ_XUL
   938   nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
   939   if (rootBox) {
   940     mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
   941   }
   942 #endif
   943   MOZ_COUNT_CTOR(nsFrameConstructorState);
   944   mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState();
   945 }
   947 nsFrameConstructorState::~nsFrameConstructorState()
   948 {
   949   // Frame order comparison functions only work properly when the placeholders
   950   // have been inserted into the frame tree. So for example if we have a new float
   951   // containing the placeholder for a new abs-pos frame, and we process the abs-pos
   952   // insertion first, then we won't be able to find the right place to insert in
   953   // in the abs-pos list. So put floats in first, because they can contain placeholders
   954   // for abs-pos and fixed-pos items whose containing blocks are outside the floats.
   955   // Then put abs-pos frames in, because they can contain placeholders for fixed-pos
   956   // items whose containing block is outside the abs-pos frames.
   957   MOZ_COUNT_DTOR(nsFrameConstructorState);
   958   ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
   959   ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
   960   ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
   961 #ifdef MOZ_XUL
   962   ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList);
   963 #endif
   964   for (int32_t i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
   965     mGeneratedTextNodesWithInitializer[i]->
   966       DeleteProperty(nsGkAtoms::genConInitializerProperty);
   967   }
   968   if (!mPendingBindings.isEmpty()) {
   969     nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager();
   970     do {
   971       nsAutoPtr<PendingBinding> pendingBinding;
   972       pendingBinding = mPendingBindings.popFirst();
   973       bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
   974     } while (!mPendingBindings.isEmpty());
   975     mCurrentPendingBindingInsertionPoint = nullptr;
   976   }
   977 }
   979 static nsIFrame*
   980 AdjustAbsoluteContainingBlock(nsIFrame* aContainingBlockIn)
   981 {
   982   if (!aContainingBlockIn) {
   983     return nullptr;
   984   }
   986   // Always use the container's first continuation. (Inline frames can have
   987   // non-fluid bidi continuations...)
   988   return aContainingBlockIn->FirstContinuation();
   989 }
   991 void
   992 nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock,
   993                                                      nsIFrame* aPositionedFrame,
   994                                                      nsFrameConstructorSaveState& aSaveState)
   995 {
   996   aSaveState.mItems = &mAbsoluteItems;
   997   aSaveState.mSavedItems = mAbsoluteItems;
   998   aSaveState.mChildListID = nsIFrame::kAbsoluteList;
   999   aSaveState.mState = this;
  1000   aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
  1002   if (mFixedPosIsAbsPos) {
  1003     // Since we're going to replace mAbsoluteItems, we need to save it into
  1004     // mFixedItems now (and save the current value of mFixedItems).
  1005     aSaveState.mSavedFixedItems = mFixedItems;
  1006     mFixedItems = mAbsoluteItems;
  1009   mAbsoluteItems =
  1010     nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
  1012   /* See if we're wiring the fixed-pos and abs-pos lists together.  This happens iff
  1013    * we're a transformed element.
  1014    */
  1015   mFixedPosIsAbsPos = aPositionedFrame &&
  1016       (aPositionedFrame->StyleDisplay()->HasTransform(aPositionedFrame) ||
  1017        aPositionedFrame->StyleDisplay()->HasPerspectiveStyle());
  1019   if (aNewAbsoluteContainingBlock) {
  1020     aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
  1024 void
  1025 nsFrameConstructorState::PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock,
  1026                                                   nsFrameConstructorSaveState& aSaveState)
  1028   NS_PRECONDITION(!aNewFloatContainingBlock ||
  1029                   aNewFloatContainingBlock->IsFloatContainingBlock(),
  1030                   "Please push a real float containing block!");
  1031   NS_ASSERTION(!aNewFloatContainingBlock ||
  1032                !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),
  1033                "We should not push a frame that is supposed to _suppress_ "
  1034                "floats as a float containing block!");
  1035   aSaveState.mItems = &mFloatedItems;
  1036   aSaveState.mSavedItems = mFloatedItems;
  1037   aSaveState.mChildListID = nsIFrame::kFloatList;
  1038   aSaveState.mState = this;
  1039   mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock);
  1042 nsIFrame*
  1043 nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
  1044                                             nsIFrame* aContentParentFrame) const
  1046   NS_PRECONDITION(aStyleDisplay, "Must have display struct!");
  1048   // If there is no container for a fixed, absolute, or floating root
  1049   // frame, we will ignore the positioning.  This hack is originally
  1050   // brought to you by the letter T: tables, since other roots don't
  1051   // even call into this code.  See bug 178855.
  1052   //
  1053   // XXX Disabling positioning in this case is a hack.  If one was so inclined,
  1054   // one could support this either by (1) inserting a dummy block between the
  1055   // table and the canvas or (2) teaching the canvas how to reflow positioned
  1056   // elements. (1) has the usual problems when multiple frames share the same
  1057   // content (notice all the special cases in this file dealing with inner
  1058   // tables and outer tables which share the same content). (2) requires some
  1059   // work and possible factoring.
  1060   //
  1061   // XXXbz couldn't we just force position to "static" on roots and
  1062   // float to "none"?  That's OK per CSS 2.1, as far as I can tell.
  1064   if (aContentParentFrame && aContentParentFrame->IsSVGText()) {
  1065     return aContentParentFrame;
  1068   if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) {
  1069     NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(),
  1070                  "Absolutely positioned _and_ floating?");
  1071     return mFloatedItems.containingBlock;
  1074   if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
  1075       mAbsoluteItems.containingBlock) {
  1076     return mAbsoluteItems.containingBlock;
  1079   if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
  1080       GetFixedItems().containingBlock) {
  1081     return GetFixedItems().containingBlock;
  1084   return aContentParentFrame;
  1087 void
  1088 nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
  1089                                   nsFrameItems& aFrameItems,
  1090                                   nsIContent* aContent,
  1091                                   nsStyleContext* aStyleContext,
  1092                                   nsIFrame* aParentFrame,
  1093                                   bool aCanBePositioned,
  1094                                   bool aCanBeFloated,
  1095                                   bool aIsOutOfFlowPopup,
  1096                                   bool aInsertAfter,
  1097                                   nsIFrame* aInsertAfterFrame)
  1099   NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen");
  1101   const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
  1103   // The comments in GetGeometricParent regarding root table frames
  1104   // all apply here, unfortunately.
  1106   bool needPlaceholder = false;
  1107   nsFrameState placeholderType;
  1108   nsFrameItems* frameItems = &aFrameItems;
  1109 #ifdef MOZ_XUL
  1110   if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
  1111       NS_ASSERTION(aNewFrame->GetParent() == mPopupItems.containingBlock,
  1112                    "Popup whose parent is not the popup containing block?");
  1113       NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!");
  1114       needPlaceholder = true;
  1115       frameItems = &mPopupItems;
  1116       placeholderType = PLACEHOLDER_FOR_POPUP;
  1118   else
  1119 #endif // MOZ_XUL
  1120   if (aCanBeFloated && aNewFrame->IsFloating() &&
  1121       mFloatedItems.containingBlock) {
  1122     NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock,
  1123                  "Float whose parent is not the float containing block?");
  1124     needPlaceholder = true;
  1125     frameItems = &mFloatedItems;
  1126     placeholderType = PLACEHOLDER_FOR_FLOAT;
  1128   else if (aCanBePositioned) {
  1129     if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
  1130         mAbsoluteItems.containingBlock) {
  1131       NS_ASSERTION(aNewFrame->GetParent() == mAbsoluteItems.containingBlock,
  1132                    "Abs pos whose parent is not the abs pos containing block?");
  1133       needPlaceholder = true;
  1134       frameItems = &mAbsoluteItems;
  1135       placeholderType = PLACEHOLDER_FOR_ABSPOS;
  1137     if (disp->mPosition == NS_STYLE_POSITION_FIXED &&
  1138         GetFixedItems().containingBlock) {
  1139       NS_ASSERTION(aNewFrame->GetParent() == GetFixedItems().containingBlock,
  1140                    "Fixed pos whose parent is not the fixed pos containing block?");
  1141       needPlaceholder = true;
  1142       frameItems = &GetFixedItems();
  1143       placeholderType = PLACEHOLDER_FOR_FIXEDPOS;
  1147   if (needPlaceholder) {
  1148     NS_ASSERTION(frameItems != &aFrameItems,
  1149                  "Putting frame in-flow _and_ want a placeholder?");
  1150     nsIFrame* placeholderFrame =
  1151       nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell,
  1152                                                        aContent,
  1153                                                        aNewFrame,
  1154                                                        aStyleContext,
  1155                                                        aParentFrame,
  1156                                                        nullptr,
  1157                                                        placeholderType);
  1159     placeholderFrame->AddStateBits(mAdditionalStateBits);
  1160     // Add the placeholder frame to the flow
  1161     aFrameItems.AddChild(placeholderFrame);
  1163 #ifdef DEBUG
  1164   else {
  1165     NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
  1166                  "In-flow frame has wrong parent");
  1168 #endif
  1170   if (aInsertAfter) {
  1171     frameItems->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
  1172   } else {
  1173     frameItems->AddChild(aNewFrame);
  1177 void
  1178 nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
  1179                                                 ChildListID aChildListID)
  1181 #define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems &&            \
  1182                              aChildListID == nsIFrame::kFloatList)    ||  \
  1183                             (&aFrameItems == &mAbsoluteItems &&           \
  1184                              aChildListID == nsIFrame::kAbsoluteList) ||  \
  1185                             (&aFrameItems == &mFixedItems &&              \
  1186                              aChildListID == nsIFrame::kFixedList)
  1187 #ifdef MOZ_XUL
  1188   NS_PRECONDITION(NS_NONXUL_LIST_TEST ||
  1189                   (&aFrameItems == &mPopupItems &&
  1190                    aChildListID == nsIFrame::kPopupList),
  1191                   "Unexpected aFrameItems/aChildListID combination");
  1192 #else
  1193   NS_PRECONDITION(NS_NONXUL_LIST_TEST,
  1194                   "Unexpected aFrameItems/aChildListID combination");
  1195 #endif
  1197   if (aFrameItems.IsEmpty()) {
  1198     return;
  1201   nsIFrame* containingBlock = aFrameItems.containingBlock;
  1203   NS_ASSERTION(containingBlock,
  1204                "Child list without containing block?");
  1206   if (aChildListID == nsIFrame::kFixedList) {
  1207     // Put this frame on the transformed-frame's abs-pos list instead, if
  1208     // it has abs-pos children instead of fixed-pos children.
  1209     aChildListID = containingBlock->GetAbsoluteListID();
  1212   // Insert the frames hanging out in aItems.  We can use SetInitialChildList()
  1213   // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
  1214   // is set) and doesn't have any frames in the aChildListID child list yet.
  1215   const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
  1216   DebugOnly<nsresult> rv = NS_OK;
  1217   if (childList.IsEmpty() &&
  1218       (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  1219     // If we're injecting absolutely positioned frames, inject them on the
  1220     // absolute containing block
  1221     if (aChildListID == containingBlock->GetAbsoluteListID()) {
  1222       rv = containingBlock->GetAbsoluteContainingBlock()->
  1223            SetInitialChildList(containingBlock, aChildListID, aFrameItems);
  1224     } else {
  1225       rv = containingBlock->SetInitialChildList(aChildListID, aFrameItems);
  1227   } else {
  1228     // Note that whether the frame construction context is doing an append or
  1229     // not is not helpful here, since it could be appending to some frame in
  1230     // the middle of the document, which means we're not necessarily
  1231     // appending to the children of the containing block.
  1232     //
  1233     // We need to make sure the 'append to the end of document' case is fast.
  1234     // So first test the last child of the containing block
  1235     nsIFrame* lastChild = childList.LastChild();
  1237     // CompareTreePosition uses placeholder hierarchy for out of flow frames,
  1238     // so this will make out-of-flows respect the ordering of placeholders,
  1239     // which is great because it takes care of anonymous content.
  1240     nsIFrame* firstNewFrame = aFrameItems.FirstChild();
  1242     // Cache the ancestor chain so that we can reuse it if needed.
  1243     nsAutoTArray<nsIFrame*, 20> firstNewFrameAncestors;
  1244     nsIFrame* notCommonAncestor = nullptr;
  1245     if (lastChild) {
  1246       notCommonAncestor = nsLayoutUtils::FillAncestors(firstNewFrame,
  1247                                                        containingBlock,
  1248                                                        &firstNewFrameAncestors);
  1251     if (!lastChild ||
  1252         nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame,
  1253                                            firstNewFrameAncestors,
  1254                                            notCommonAncestor ?
  1255                                              containingBlock : nullptr) < 0) {
  1256       // no lastChild, or lastChild comes before the new children, so just append
  1257       rv = mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
  1258     } else {
  1259       // Try the other children. First collect them to an array so that a
  1260       // reasonable fast binary search can be used to find the insertion point.
  1261       nsAutoTArray<nsIFrame*, 128> children;
  1262       for (nsIFrame* f = childList.FirstChild(); f != lastChild;
  1263            f = f->GetNextSibling()) {
  1264         children.AppendElement(f);
  1267       nsIFrame* insertionPoint = nullptr;
  1268       int32_t imin = 0;
  1269       int32_t max = children.Length();
  1270       while (max > imin) {
  1271         int32_t imid = imin + ((max - imin) / 2);
  1272         nsIFrame* f = children[imid];
  1273         int32_t compare =
  1274           nsLayoutUtils::CompareTreePosition(f, firstNewFrame, firstNewFrameAncestors,
  1275                                              notCommonAncestor ? containingBlock : nullptr);
  1276         if (compare > 0) {
  1277           // f is after the new frame.
  1278           max = imid;
  1279           insertionPoint = imid > 0 ? children[imid - 1] : nullptr;
  1280         } else if (compare < 0) {
  1281           // f is before the new frame.
  1282           imin = imid + 1;
  1283           insertionPoint = f;
  1284         } else {
  1285           // This is for the old behavior. Should be removed once it is
  1286           // guaranteed that CompareTreePosition can't return 0!
  1287           // See bug 928645.
  1288           NS_WARNING("Something odd happening???");
  1289           insertionPoint = nullptr;
  1290           for (uint32_t i = 0; i < children.Length(); ++i) {
  1291             nsIFrame* f = children[i];
  1292             if (nsLayoutUtils::CompareTreePosition(f, firstNewFrame,
  1293                                                    firstNewFrameAncestors,
  1294                                                    notCommonAncestor ?
  1295                                                      containingBlock : nullptr) > 0) {
  1296               break;
  1298             insertionPoint = f;
  1300           break;
  1303       rv = mFrameManager->InsertFrames(containingBlock, aChildListID,
  1304                                        insertionPoint, aFrameItems);
  1308   NS_POSTCONDITION(aFrameItems.IsEmpty(), "How did that happen?");
  1310   // XXXbz And if NS_FAILED(rv), what?  I guess we need to clean up the list
  1311   // and deal with all the placeholders... but what if the placeholders aren't
  1312   // in the document yet?  Could that happen?
  1313   NS_ASSERTION(NS_SUCCEEDED(rv), "Frames getting lost!");
  1317 nsFrameConstructorSaveState::nsFrameConstructorSaveState()
  1318   : mItems(nullptr),
  1319     mSavedItems(nullptr),
  1320     mChildListID(kPrincipalList),
  1321     mState(nullptr),
  1322     mSavedFixedItems(nullptr),
  1323     mSavedFixedPosIsAbsPos(false)
  1327 nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
  1329   // Restore the state
  1330   if (mItems) {
  1331     NS_ASSERTION(mState, "Can't have mItems set without having a state!");
  1332     mState->ProcessFrameInsertions(*mItems, mChildListID);
  1333     *mItems = mSavedItems;
  1334 #ifdef DEBUG
  1335     // We've transferred the child list, so drop the pointer we held to it.
  1336     // Note that this only matters for the assert in ~nsAbsoluteItems.
  1337     mSavedItems.Clear();
  1338 #endif
  1339     if (mItems == &mState->mAbsoluteItems) {
  1340       mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
  1341       if (mSavedFixedPosIsAbsPos) {
  1342         // mAbsoluteItems was moved to mFixedItems, so move mFixedItems back
  1343         // and repair the old mFixedItems now.
  1344         mState->mAbsoluteItems = mState->mFixedItems;
  1345         mState->mFixedItems = mSavedFixedItems;
  1346 #ifdef DEBUG
  1347         mSavedFixedItems.Clear();
  1348 #endif
  1351     NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(),
  1352                  "Something corrupted our list");
  1356 static
  1357 bool IsBorderCollapse(nsIFrame* aFrame)
  1359   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
  1360     if (nsGkAtoms::tableFrame == frame->GetType()) {
  1361       return ((nsTableFrame*)frame)->IsBorderCollapse();
  1364   NS_ASSERTION(false, "program error");
  1365   return false;
  1368 /**
  1369  * Moves aFrameList from aOldParent to aNewParent.  This updates the parent
  1370  * pointer of the frames in the list, and reparents their views as needed.
  1371  * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
  1372  * ancestors as needed. Then it sets the list as the initial child list
  1373  * on aNewParent, unless aNewParent either already has kids or has been
  1374  * reflowed; in that case it appends the new frames.  Note that this
  1375  * method differs from ReparentFrames in that it doesn't change the kids'
  1376  * style contexts.
  1377  */
  1378 // XXXbz Since this is only used for {ib} splits, could we just copy the view
  1379 // bits from aOldParent to aNewParent and then use the
  1380 // nsFrameList::ApplySetParent?  That would still leave us doing two passes
  1381 // over the list, of course; if we really wanted to we could factor out the
  1382 // relevant part of ReparentFrameViewList, I suppose...  Or just get rid of
  1383 // views, which would make most of this function go away.
  1384 static void
  1385 MoveChildrenTo(nsPresContext* aPresContext,
  1386                nsIFrame* aOldParent,
  1387                nsIFrame* aNewParent,
  1388                nsFrameList& aFrameList)
  1390   bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent();
  1392   if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) {
  1393     // Move the frames into the new view
  1394     nsContainerFrame::ReparentFrameViewList(aFrameList, aOldParent, aNewParent);
  1397   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  1398     e.get()->SetParent(aNewParent);
  1401   if (aNewParent->PrincipalChildList().IsEmpty() &&
  1402       (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  1403     aNewParent->SetInitialChildList(kPrincipalList, aFrameList);
  1404   } else {
  1405     aNewParent->AppendFrames(kPrincipalList, aFrameList);
  1409 //----------------------------------------------------------------------
  1411 nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
  1412                                              nsIPresShell *aPresShell,
  1413                                              nsStyleSet* aStyleSet)
  1414   : nsFrameManager(aPresShell, aStyleSet)
  1415   , mDocument(aDocument)
  1416   , mRootElementFrame(nullptr)
  1417   , mRootElementStyleFrame(nullptr)
  1418   , mFixedContainingBlock(nullptr)
  1419   , mDocElementContainingBlock(nullptr)
  1420   , mGfxScrollFrame(nullptr)
  1421   , mPageSequenceFrame(nullptr)
  1422   , mCurrentDepth(0)
  1423   , mUpdateCount(0)
  1424   , mQuotesDirty(false)
  1425   , mCountersDirty(false)
  1426   , mIsDestroyingFrameTree(false)
  1427   , mHasRootAbsPosContainingBlock(false)
  1428   , mAlwaysCreateFramesForIgnorableWhitespace(false)
  1430 #ifdef DEBUG
  1431   static bool gFirstTime = true;
  1432   if (gFirstTime) {
  1433     gFirstTime = false;
  1434     char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
  1435     if (flags) {
  1436       bool error = false;
  1437       for (;;) {
  1438         char* comma = PL_strchr(flags, ',');
  1439         if (comma)
  1440           *comma = '\0';
  1442         bool found = false;
  1443         FrameCtorDebugFlags* flag = gFlags;
  1444         FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
  1445         while (flag < limit) {
  1446           if (PL_strcasecmp(flag->name, flags) == 0) {
  1447             *(flag->on) = true;
  1448             printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag->name);
  1449             found = true;
  1450             break;
  1452           ++flag;
  1455         if (! found)
  1456           error = true;
  1458         if (! comma)
  1459           break;
  1461         *comma = ',';
  1462         flags = comma + 1;
  1465       if (error) {
  1466         printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
  1467         FrameCtorDebugFlags* flag = gFlags;
  1468         FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
  1469         while (flag < limit) {
  1470           printf("  %s\n", flag->name);
  1471           ++flag;
  1473         printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
  1474         printf("names (no whitespace)\n");
  1478 #endif
  1481 void
  1482 nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
  1484   NS_PRECONDITION(mUpdateCount != 0,
  1485                   "Should be in an update while destroying frames");
  1487   if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
  1488     if (mQuoteList.DestroyNodesFor(aFrame))
  1489       QuotesDirty();
  1492   if (mCounterManager.DestroyNodesFor(aFrame)) {
  1493     // Technically we don't need to update anything if we destroyed only
  1494     // USE nodes.  However, this is unlikely to happen in the real world
  1495     // since USE nodes generally go along with INCREMENT nodes.
  1496     CountersDirty();
  1499   RestyleManager()->NotifyDestroyingFrame(aFrame);
  1501   nsFrameManager::NotifyDestroyingFrame(aFrame);
  1504 struct nsGenConInitializer {
  1505   nsAutoPtr<nsGenConNode> mNode;
  1506   nsGenConList*           mList;
  1507   void (nsCSSFrameConstructor::*mDirtyAll)();
  1509   nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
  1510                       void (nsCSSFrameConstructor::*aDirtyAll)())
  1511     : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {}
  1512 };
  1514 already_AddRefed<nsIContent>
  1515 nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState,
  1516                                             const nsString& aString,
  1517                                             nsCOMPtr<nsIDOMCharacterData>* aText,
  1518                                             nsGenConInitializer* aInitializer)
  1520   nsRefPtr<nsTextNode> content = new nsTextNode(mDocument->NodeInfoManager());
  1521   content->SetText(aString, false);
  1522   if (aText) {
  1523     *aText = content;
  1525   if (aInitializer) {
  1526     content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
  1527                          nsINode::DeleteProperty<nsGenConInitializer>);
  1528     aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
  1530   return content.forget();
  1533 already_AddRefed<nsIContent>
  1534 nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
  1535                                               nsIContent*     aParentContent,
  1536                                               nsStyleContext* aStyleContext,
  1537                                               uint32_t        aContentIndex)
  1539   // Get the content value
  1540   const nsStyleContentData &data =
  1541     aStyleContext->StyleContent()->ContentAt(aContentIndex);
  1542   nsStyleContentType type = data.mType;
  1544   if (eStyleContentType_Image == type) {
  1545     if (!data.mContent.mImage) {
  1546       // CSS had something specified that couldn't be converted to an
  1547       // image object
  1548       return nullptr;
  1551     // Create an image content object and pass it the image request.
  1552     // XXX Check if it's an image type we can handle...
  1554     nsCOMPtr<nsINodeInfo> nodeInfo;
  1555     nodeInfo = mDocument->NodeInfoManager()->
  1556       GetNodeInfo(nsGkAtoms::mozgeneratedcontentimage, nullptr,
  1557                   kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE);
  1559     nsCOMPtr<nsIContent> content;
  1560     NS_NewGenConImageContent(getter_AddRefs(content), nodeInfo.forget(),
  1561                              data.mContent.mImage);
  1562     return content.forget();
  1565   switch (type) {
  1566   case eStyleContentType_String:
  1567     return CreateGenConTextNode(aState,
  1568                                 nsDependentString(data.mContent.mString),
  1569                                 nullptr, nullptr);
  1571   case eStyleContentType_Attr:
  1573       nsCOMPtr<nsIAtom> attrName;
  1574       int32_t attrNameSpace = kNameSpaceID_None;
  1575       nsAutoString contentString(data.mContent.mString);
  1577       int32_t barIndex = contentString.FindChar('|'); // CSS namespace delimiter
  1578       if (-1 != barIndex) {
  1579         nsAutoString  nameSpaceVal;
  1580         contentString.Left(nameSpaceVal, barIndex);
  1581         nsresult error;
  1582         attrNameSpace = nameSpaceVal.ToInteger(&error);
  1583         contentString.Cut(0, barIndex + 1);
  1584         if (contentString.Length()) {
  1585           if (mDocument->IsHTML() && aParentContent->IsHTML()) {
  1586             ToLowerCase(contentString);
  1588           attrName = do_GetAtom(contentString);
  1591       else {
  1592         if (mDocument->IsHTML() && aParentContent->IsHTML()) {
  1593           ToLowerCase(contentString);
  1595         attrName = do_GetAtom(contentString);
  1598       if (!attrName) {
  1599         return nullptr;
  1602       nsCOMPtr<nsIContent> content;
  1603       NS_NewAttributeContent(mDocument->NodeInfoManager(),
  1604                              attrNameSpace, attrName, getter_AddRefs(content));
  1605       return content.forget();
  1608   case eStyleContentType_Counter:
  1609   case eStyleContentType_Counters:
  1611       nsCSSValue::Array* counters = data.mContent.mCounters;
  1612       nsCounterList* counterList = mCounterManager.CounterListFor(
  1613           nsDependentString(counters->Item(0).GetStringBufferValue()));
  1614       if (!counterList)
  1615         return nullptr;
  1617       nsCounterUseNode* node =
  1618         new nsCounterUseNode(counters, aContentIndex,
  1619                              type == eStyleContentType_Counters);
  1621       nsGenConInitializer* initializer =
  1622         new nsGenConInitializer(node, counterList,
  1623                                 &nsCSSFrameConstructor::CountersDirty);
  1624       return CreateGenConTextNode(aState, EmptyString(), &node->mText,
  1625                                   initializer);
  1628   case eStyleContentType_Image:
  1629     NS_NOTREACHED("handled by if above");
  1630     return nullptr;
  1632   case eStyleContentType_OpenQuote:
  1633   case eStyleContentType_CloseQuote:
  1634   case eStyleContentType_NoOpenQuote:
  1635   case eStyleContentType_NoCloseQuote:
  1637       nsQuoteNode* node =
  1638         new nsQuoteNode(type, aContentIndex);
  1640       nsGenConInitializer* initializer =
  1641         new nsGenConInitializer(node, &mQuoteList,
  1642                                 &nsCSSFrameConstructor::QuotesDirty);
  1643       return CreateGenConTextNode(aState, EmptyString(), &node->mText,
  1644                                   initializer);
  1647   case eStyleContentType_AltContent:
  1649       // Use the "alt" attribute; if that fails and the node is an HTML
  1650       // <input>, try the value attribute and then fall back to some default
  1651       // localized text we have.
  1652       // XXX what if the 'alt' attribute is added later, how will we
  1653       // detect that and do the right thing here?
  1654       if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
  1655         nsCOMPtr<nsIContent> content;
  1656         NS_NewAttributeContent(mDocument->NodeInfoManager(),
  1657                                kNameSpaceID_None, nsGkAtoms::alt, getter_AddRefs(content));
  1658         return content.forget();
  1661       if (aParentContent->IsHTML() &&
  1662           aParentContent->NodeInfo()->Equals(nsGkAtoms::input)) {
  1663         if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
  1664           nsCOMPtr<nsIContent> content;
  1665           NS_NewAttributeContent(mDocument->NodeInfoManager(),
  1666                                  kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content));
  1667           return content.forget();
  1670         nsXPIDLString temp;
  1671         nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
  1672                                            "Submit", temp);
  1673         return CreateGenConTextNode(aState, temp, nullptr, nullptr);
  1676       break;
  1679   case eStyleContentType_Uninitialized:
  1680     NS_NOTREACHED("uninitialized content type");
  1681     return nullptr;
  1682   } // switch
  1684   return nullptr;
  1687 /*
  1688  * aParentFrame - the frame that should be the parent of the generated
  1689  *   content.  This is the frame for the corresponding content node,
  1690  *   which must not be a leaf frame.
  1692  * Any items created are added to aItems.
  1694  * We create an XML element (tag _moz_generated_content_before or
  1695  * _moz_generated_content_after) representing the pseudoelement. We
  1696  * create a DOM node for each 'content' item and make those nodes the
  1697  * children of the XML element. Then we create a frame subtree for
  1698  * the XML element as if it were a regular child of
  1699  * aParentFrame/aParentContent, giving the XML element the ::before or
  1700  * ::after style.
  1701  */
  1702 void
  1703 nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState,
  1704                                                   nsIFrame*        aParentFrame,
  1705                                                   nsIContent*      aParentContent,
  1706                                                   nsStyleContext*  aStyleContext,
  1707                                                   nsCSSPseudoElements::Type aPseudoElement,
  1708                                                   FrameConstructionItemList& aItems)
  1710   // XXXbz is this ever true?
  1711   if (!aParentContent->IsElement()) {
  1712     NS_ERROR("Bogus generated content parent");
  1713     return;
  1716   nsStyleSet *styleSet = mPresShell->StyleSet();
  1718   // Probe for the existence of the pseudo-element
  1719   nsRefPtr<nsStyleContext> pseudoStyleContext;
  1720   pseudoStyleContext =
  1721     styleSet->ProbePseudoElementStyle(aParentContent->AsElement(),
  1722                                       aPseudoElement,
  1723                                       aStyleContext,
  1724                                       aState.mTreeMatchContext);
  1725   if (!pseudoStyleContext)
  1726     return;
  1727   // |ProbePseudoStyleFor| checked the 'display' property and the
  1728   // |ContentCount()| of the 'content' property for us.
  1729   nsCOMPtr<nsINodeInfo> nodeInfo;
  1730   nsIAtom* elemName = aPseudoElement == nsCSSPseudoElements::ePseudo_before ?
  1731     nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
  1732   nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nullptr,
  1733                                                        kNameSpaceID_None,
  1734                                                        nsIDOMNode::ELEMENT_NODE);
  1735   nsCOMPtr<Element> container;
  1736   nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
  1737   if (NS_FAILED(rv))
  1738     return;
  1739   container->SetIsNativeAnonymousRoot();
  1741   rv = container->BindToTree(mDocument, aParentContent, aParentContent, true);
  1742   if (NS_FAILED(rv)) {
  1743     container->UnbindFromTree();
  1744     return;
  1747   uint32_t contentCount = pseudoStyleContext->StyleContent()->ContentCount();
  1748   for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
  1749     nsCOMPtr<nsIContent> content =
  1750       CreateGeneratedContent(aState, aParentContent, pseudoStyleContext,
  1751                              contentIndex);
  1752     if (content) {
  1753       container->AppendChildTo(content, false);
  1757   AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
  1758                                     kNameSpaceID_None, true,
  1759                                     pseudoStyleContext,
  1760                                     ITEM_IS_GENERATED_CONTENT, nullptr,
  1761                                     aItems);
  1764 /****************************************************
  1765  **  BEGIN TABLE SECTION
  1766  ****************************************************/
  1768 // The term pseudo frame is being used instead of anonymous frame, since anonymous
  1769 // frame has been used elsewhere to refer to frames that have generated content
  1771 // Return whether the given frame is a table pseudo-frame.  Note that
  1772 // cell-content and table-outer frames have pseudo-types, but are always
  1773 // created, even for non-anonymous cells and tables respectively.  So for those
  1774 // we have to examine the cell or table frame to see whether it's a pseudo
  1775 // frame.  In particular, a lone table caption will have an outer table as its
  1776 // parent, but will also trigger construction of an empty inner table, which
  1777 // will be the one we can examine to see whether the outer was a pseudo-frame.
  1778 static bool
  1779 IsTablePseudo(nsIFrame* aFrame)
  1781   nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
  1782   return pseudoType &&
  1783     (pseudoType == nsCSSAnonBoxes::table ||
  1784      pseudoType == nsCSSAnonBoxes::inlineTable ||
  1785      pseudoType == nsCSSAnonBoxes::tableColGroup ||
  1786      pseudoType == nsCSSAnonBoxes::tableRowGroup ||
  1787      pseudoType == nsCSSAnonBoxes::tableRow ||
  1788      pseudoType == nsCSSAnonBoxes::tableCell ||
  1789      (pseudoType == nsCSSAnonBoxes::cellContent &&
  1790       aFrame->GetParent()->StyleContext()->GetPseudo() ==
  1791         nsCSSAnonBoxes::tableCell) ||
  1792      (pseudoType == nsCSSAnonBoxes::tableOuter &&
  1793       (aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo() ==
  1794          nsCSSAnonBoxes::table ||
  1795        aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo() ==
  1796          nsCSSAnonBoxes::inlineTable)));
  1799 /* static */
  1800 nsCSSFrameConstructor::ParentType
  1801 nsCSSFrameConstructor::GetParentType(nsIAtom* aFrameType)
  1803   if (aFrameType == nsGkAtoms::tableFrame) {
  1804     return eTypeTable;
  1806   if (aFrameType == nsGkAtoms::tableRowGroupFrame) {
  1807     return eTypeRowGroup;
  1809   if (aFrameType == nsGkAtoms::tableRowFrame) {
  1810     return eTypeRow;
  1812   if (aFrameType == nsGkAtoms::tableColGroupFrame) {
  1813     return eTypeColGroup;
  1816   return eTypeBlock;
  1819 static nsIFrame*
  1820 AdjustCaptionParentFrame(nsIFrame* aParentFrame)
  1822   if (nsGkAtoms::tableFrame == aParentFrame->GetType()) {
  1823     return aParentFrame->GetParent();;
  1825   return aParentFrame;
  1828 /**
  1829  * If the parent frame is a |tableFrame| and the child is a
  1830  * |captionFrame|, then we want to insert the frames beneath the
  1831  * |tableFrame|'s parent frame. Returns |true| if the parent frame
  1832  * needed to be fixed up.
  1833  */
  1834 static bool
  1835 GetCaptionAdjustedParent(nsIFrame*        aParentFrame,
  1836                          const nsIFrame*  aChildFrame,
  1837                          nsIFrame**       aAdjParentFrame)
  1839   *aAdjParentFrame = aParentFrame;
  1840   bool haveCaption = false;
  1842   if (nsGkAtoms::tableCaptionFrame == aChildFrame->GetType()) {
  1843     haveCaption = true;
  1844     *aAdjParentFrame = AdjustCaptionParentFrame(aParentFrame);
  1846   return haveCaption;
  1849 void
  1850 nsCSSFrameConstructor::AdjustParentFrame(nsIFrame* &                  aParentFrame,
  1851                                          const FrameConstructionData* aFCData,
  1852                                          nsStyleContext*              aStyleContext)
  1854   NS_PRECONDITION(aStyleContext, "Must have child's style context");
  1855   NS_PRECONDITION(aFCData, "Must have frame construction data");
  1857   bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0);
  1859   if (tablePart && aStyleContext->StyleDisplay()->mDisplay ==
  1860       NS_STYLE_DISPLAY_TABLE_CAPTION) {
  1861     aParentFrame = AdjustCaptionParentFrame(aParentFrame);
  1865 // Pull all the captions present in aItems out  into aCaptions
  1866 static void
  1867 PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions)
  1869   nsIFrame *child = aItems.FirstChild();
  1870   while (child) {
  1871     nsIFrame *nextSibling = child->GetNextSibling();
  1872     if (nsGkAtoms::tableCaptionFrame == child->GetType()) {
  1873       aItems.RemoveFrame(child);
  1874       aCaptions.AddChild(child);
  1876     child = nextSibling;
  1881 // Construct the outer, inner table frames and the children frames for the table.
  1882 // XXX Page break frames for pseudo table frames are not constructed to avoid the risk
  1883 // associated with revising the pseudo frame mechanism. The long term solution
  1884 // of having frames handle page-break-before/after will solve the problem.
  1885 nsIFrame*
  1886 nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
  1887                                       FrameConstructionItem&   aItem,
  1888                                       nsIFrame*                aParentFrame,
  1889                                       const nsStyleDisplay*    aDisplay,
  1890                                       nsFrameItems&            aFrameItems)
  1892   NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE ||
  1893                   aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE,
  1894                   "Unexpected call");
  1896   nsIContent* const content = aItem.mContent;
  1897   nsStyleContext* const styleContext = aItem.mStyleContext;
  1898   const uint32_t nameSpaceID = aItem.mNameSpaceID;
  1900   // create the pseudo SC for the outer table as a child of the inner SC
  1901   nsRefPtr<nsStyleContext> outerStyleContext;
  1902   outerStyleContext = mPresShell->StyleSet()->
  1903     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableOuter, styleContext);
  1905   // Create the outer table frame which holds the caption and inner table frame
  1906   nsIFrame* newFrame;
  1907   if (kNameSpaceID_MathML == nameSpaceID)
  1908     newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerStyleContext);
  1909   else
  1910     newFrame = NS_NewTableOuterFrame(mPresShell, outerStyleContext);
  1912   nsIFrame* geometricParent =
  1913     aState.GetGeometricParent(outerStyleContext->StyleDisplay(),
  1914                               aParentFrame);
  1916   // Init the table outer frame
  1917   InitAndRestoreFrame(aState, content, geometricParent, newFrame);
  1919   // Create the inner table frame
  1920   nsIFrame* innerFrame;
  1921   if (kNameSpaceID_MathML == nameSpaceID)
  1922     innerFrame = NS_NewMathMLmtableFrame(mPresShell, styleContext);
  1923   else
  1924     innerFrame = NS_NewTableFrame(mPresShell, styleContext);
  1926   InitAndRestoreFrame(aState, content, newFrame, innerFrame);
  1928   // Put the newly created frames into the right child list
  1929   SetInitialSingleChild(newFrame, innerFrame);
  1931   aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
  1933   if (!mRootElementFrame) {
  1934     // The frame we're constructing will be the root element frame.
  1935     // Set mRootElementFrame before processing children.
  1936     mRootElementFrame = newFrame;
  1939   nsFrameItems childItems;
  1941   // Process children
  1942   nsFrameConstructorSaveState absoluteSaveState;
  1943   const nsStyleDisplay* display = outerStyleContext->StyleDisplay();
  1945   // Mark the table frame as an absolute container if needed
  1946   newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  1947   if (display->IsPositioned(newFrame)) {
  1948     aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
  1950   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
  1951                "nsIAnonymousContentCreator::CreateAnonymousContent "
  1952                "implementations for table frames are not currently expected "
  1953                "to output a list where the items have their own children");
  1954   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
  1955     ConstructFramesFromItemList(aState, aItem.mChildItems,
  1956                                 innerFrame, childItems);
  1957   } else {
  1958     ProcessChildren(aState, content, styleContext, innerFrame,
  1959                     true, childItems, false, aItem.mPendingBinding);
  1962   nsFrameItems captionItems;
  1963   PullOutCaptionFrames(childItems, captionItems);
  1965   // Set the inner table frame's initial primary list
  1966   innerFrame->SetInitialChildList(kPrincipalList, childItems);
  1968   // Set the outer table frame's secondary childlist lists
  1969   if (captionItems.NotEmpty()) {
  1970     newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems);
  1973   return newFrame;
  1976 static void
  1977 MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState&     aState,
  1978                                              const nsStyleDisplay*        aDisplay,
  1979                                              nsFrameConstructorSaveState& aAbsSaveState,
  1980                                              nsIFrame*                    aFrame)
  1982   // If we're positioned, then we need to become an absolute containing block
  1983   // for any absolutely positioned children and register for post-reflow fixup.
  1984   //
  1985   // Note that usually if a frame type can be an absolute containing block, we
  1986   // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not.
  1987   // However, in this case flag serves the additional purpose of indicating that
  1988   // the frame was registered with its table frame. This allows us to avoid the
  1989   // overhead of unregistering the frame in most cases.
  1990   if (aDisplay->IsPositioned(aFrame)) {
  1991     aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  1992     aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
  1993     nsTableFrame::RegisterPositionedTablePart(aFrame);
  1997 nsIFrame*
  1998 nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
  1999                                                    FrameConstructionItem&   aItem,
  2000                                                    nsIFrame*                aParentFrame,
  2001                                                    const nsStyleDisplay*    aDisplay,
  2002                                                    nsFrameItems&            aFrameItems)
  2004   NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW ||
  2005                   aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW_GROUP ||
  2006                   aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP ||
  2007                   aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_HEADER_GROUP,
  2008                   "Unexpected call");
  2009   MOZ_ASSERT(aItem.mStyleContext->StyleDisplay() == aDisplay,
  2010              "Display style doesn't match style context");
  2011   nsIContent* const content = aItem.mContent;
  2012   nsStyleContext* const styleContext = aItem.mStyleContext;
  2013   const uint32_t nameSpaceID = aItem.mNameSpaceID;
  2015   nsIFrame* newFrame;
  2016   if (aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW) {
  2017     if (kNameSpaceID_MathML == nameSpaceID)
  2018       newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext);
  2019     else
  2020       newFrame = NS_NewTableRowFrame(mPresShell, styleContext);
  2021   } else {
  2022     newFrame = NS_NewTableRowGroupFrame(mPresShell, styleContext);
  2025   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
  2027   nsFrameConstructorSaveState absoluteSaveState;
  2028   MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
  2029                                                absoluteSaveState,
  2030                                                newFrame);
  2032   nsFrameItems childItems;
  2033   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
  2034                "nsIAnonymousContentCreator::CreateAnonymousContent "
  2035                "implementations for table frames are not currently expected "
  2036                "to output a list where the items have their own children");
  2037   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
  2038     ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
  2039                                 childItems);
  2040   } else {
  2041     ProcessChildren(aState, content, styleContext, newFrame,
  2042                     true, childItems, false, aItem.mPendingBinding);
  2045   newFrame->SetInitialChildList(kPrincipalList, childItems);
  2046   aFrameItems.AddChild(newFrame);
  2047   return newFrame;
  2050 nsIFrame*
  2051 nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState& aState,
  2052                                          FrameConstructionItem&   aItem,
  2053                                          nsIFrame*                aParentFrame,
  2054                                          const nsStyleDisplay*    aStyleDisplay,
  2055                                          nsFrameItems&            aFrameItems)
  2057   nsIContent* const content = aItem.mContent;
  2058   nsStyleContext* const styleContext = aItem.mStyleContext;
  2060   nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, styleContext);
  2061   InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
  2063   NS_ASSERTION(colFrame->StyleContext() == styleContext,
  2064                "Unexpected style context");
  2066   aFrameItems.AddChild(colFrame);
  2068   // construct additional col frames if the col frame has a span > 1
  2069   int32_t span = colFrame->GetSpan();
  2070   for (int32_t spanX = 1; spanX < span; spanX++) {
  2071     nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, styleContext);
  2072     InitAndRestoreFrame(aState, content, aParentFrame, newCol, false);
  2073     aFrameItems.LastChild()->SetNextContinuation(newCol);
  2074     newCol->SetPrevContinuation(aFrameItems.LastChild());
  2075     aFrameItems.AddChild(newCol);
  2076     newCol->SetColType(eColAnonymousCol);
  2079   return colFrame;
  2082 nsIFrame*
  2083 nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState,
  2084                                           FrameConstructionItem&   aItem,
  2085                                           nsIFrame*                aParentFrame,
  2086                                           const nsStyleDisplay*    aDisplay,
  2087                                           nsFrameItems&            aFrameItems)
  2089   NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL,
  2090                   "Unexpected call");
  2092   nsIContent* const content = aItem.mContent;
  2093   nsStyleContext* const styleContext = aItem.mStyleContext;
  2094   const uint32_t nameSpaceID = aItem.mNameSpaceID;
  2096   bool borderCollapse = IsBorderCollapse(aParentFrame);
  2097   nsIFrame* newFrame;
  2098   // <mtable> is border separate in mathml.css and the MathML code doesn't implement
  2099   // border collapse. For those users who style <mtable> with border collapse,
  2100   // give them the default non-MathML table frames that understand border collapse.
  2101   // This won't break us because MathML table frames are all subclasses of the default
  2102   // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
  2103   // What will happen is just that non-MathML frames won't understand MathML attributes
  2104   // and will therefore miss the special handling that the MathML code does.
  2105   if (kNameSpaceID_MathML == nameSpaceID && !borderCollapse)
  2106     newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext);
  2107   else
  2108     // Warning: If you change this and add a wrapper frame around table cell
  2109     // frames, make sure Bug 368554 doesn't regress!
  2110     // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
  2111     newFrame = NS_NewTableCellFrame(mPresShell, styleContext, borderCollapse);
  2113   // Initialize the table cell frame
  2114   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
  2116   // Resolve pseudo style and initialize the body cell frame
  2117   nsRefPtr<nsStyleContext> innerPseudoStyle;
  2118   innerPseudoStyle = mPresShell->StyleSet()->
  2119     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent, styleContext);
  2121   // Create a block frame that will format the cell's content
  2122   bool isBlock;
  2123   nsIFrame* cellInnerFrame;
  2124   if (kNameSpaceID_MathML == nameSpaceID) {
  2125     cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
  2126     isBlock = false;
  2127   } else {
  2128     cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
  2129     isBlock = true;
  2132   InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame);
  2134   nsFrameConstructorSaveState absoluteSaveState;
  2135   MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
  2136                                                absoluteSaveState,
  2137                                                newFrame);
  2139   nsFrameItems childItems;
  2140   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
  2141                "nsIAnonymousContentCreator::CreateAnonymousContent "
  2142                "implementations for table frames are not currently expected "
  2143                "to output a list where the items have their own children");
  2144   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
  2145     // Need to push ourselves as a float containing block.
  2146     // XXXbz it might be nice to work on getting the parent
  2147     // FrameConstructionItem down into ProcessChildren and just making use of
  2148     // the push there, but that's a bit of work.
  2149     nsFrameConstructorSaveState floatSaveState;
  2150     if (!isBlock) { /* MathML case */
  2151       aState.PushFloatContainingBlock(nullptr, floatSaveState);
  2152     } else {
  2153       aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
  2156     ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
  2157                                 childItems);
  2158   } else {
  2159     // Process the child content
  2160     ProcessChildren(aState, content, styleContext, cellInnerFrame,
  2161                     true, childItems, isBlock, aItem.mPendingBinding);
  2164   cellInnerFrame->SetInitialChildList(kPrincipalList, childItems);
  2165   SetInitialSingleChild(newFrame, cellInnerFrame);
  2166   aFrameItems.AddChild(newFrame);
  2167   return newFrame;
  2170 static inline bool
  2171 NeedFrameFor(const nsFrameConstructorState& aState,
  2172              nsIFrame*   aParentFrame,
  2173              nsIContent* aChildContent)
  2175   // XXX the GetContent() != aChildContent check is needed due to bug 135040.
  2176   // Remove it once that's fixed.
  2177   NS_PRECONDITION(!aChildContent->GetPrimaryFrame() ||
  2178                   aState.mCreatingExtraFrames ||
  2179                   aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
  2180                   "Why did we get called?");
  2182   // don't create a whitespace frame if aParentFrame doesn't want it.
  2183   // always create frames for children in generated content. counter(),
  2184   // quotes, and attr() content can easily change dynamically and we don't
  2185   // want to be reconstructing frames. It's not even clear that these
  2186   // should be considered ignorable just because they evaluate to
  2187   // whitespace.
  2189   // We could handle all this in CreateNeededTablePseudos or some other place
  2190   // after we build our frame construction items, but that would involve
  2191   // creating frame construction items for whitespace kids of
  2192   // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
  2193   // all anyway, and involve an extra walk down the frame construction item
  2194   // list.
  2195   if (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
  2196       aParentFrame->IsGeneratedContentFrame() ||
  2197       !aChildContent->IsNodeOfType(nsINode::eTEXT)) {
  2198     return true;
  2201   aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
  2202                           NS_REFRAME_IF_WHITESPACE);
  2203   return !aChildContent->TextIsOnlyWhitespace();
  2206 /***********************************************
  2207  * END TABLE SECTION
  2208  ***********************************************/
  2210 static bool CheckOverflow(nsPresContext* aPresContext,
  2211                             const nsStyleDisplay* aDisplay)
  2213   if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
  2214     return false;
  2216   if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
  2217     aPresContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN,
  2218                                               NS_STYLE_OVERFLOW_HIDDEN);
  2219   else
  2220     aPresContext->SetViewportOverflowOverride(aDisplay->mOverflowX,
  2221                                               aDisplay->mOverflowY);
  2222   return true;
  2225 /**
  2226  * This checks the root element and the HTML BODY, if any, for an "overflow" property
  2227  * that should be applied to the viewport. If one is found then we return the
  2228  * element that we took the overflow from (which should then be treated as
  2229  * "overflow:visible"), and we store the overflow style in the prescontext.
  2230  * @return if scroll was propagated from some content node, the content node it
  2231  *         was propagated from.
  2232  */
  2233 nsIContent*
  2234 nsCSSFrameConstructor::PropagateScrollToViewport()
  2236   // Set default
  2237   nsPresContext* presContext = mPresShell->GetPresContext();
  2238   presContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_AUTO,
  2239                                            NS_STYLE_OVERFLOW_AUTO);
  2241   // We never mess with the viewport scroll state
  2242   // when printing or in print preview
  2243   if (presContext->IsPaginated()) {
  2244     return nullptr;
  2247   Element* docElement = mDocument->GetRootElement();
  2249   // Check the style on the document root element
  2250   nsStyleSet *styleSet = mPresShell->StyleSet();
  2251   nsRefPtr<nsStyleContext> rootStyle;
  2252   rootStyle = styleSet->ResolveStyleFor(docElement, nullptr);
  2253   if (CheckOverflow(presContext, rootStyle->StyleDisplay())) {
  2254     // tell caller we stole the overflow style from the root element
  2255     return docElement;
  2258   // Don't look in the BODY for non-HTML documents or HTML documents
  2259   // with non-HTML roots
  2260   // XXX this should be earlier; we shouldn't even look at the document root
  2261   // for non-HTML documents. Fix this once we support explicit CSS styling
  2262   // of the viewport
  2263   // XXX what about XHTML?
  2264   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
  2265   if (!htmlDoc || !docElement->IsHTML()) {
  2266     return nullptr;
  2269   nsCOMPtr<nsIDOMHTMLElement> body;
  2270   htmlDoc->GetBody(getter_AddRefs(body));
  2271   nsCOMPtr<nsIContent> bodyElement = do_QueryInterface(body);
  2273   if (!bodyElement ||
  2274       !bodyElement->NodeInfo()->Equals(nsGkAtoms::body)) {
  2275     // The body is not a <body> tag, it's a <frameset>.
  2276     return nullptr;
  2279   nsRefPtr<nsStyleContext> bodyStyle;
  2280   bodyStyle = styleSet->ResolveStyleFor(bodyElement->AsElement(), rootStyle);
  2282   if (CheckOverflow(presContext, bodyStyle->StyleDisplay())) {
  2283     // tell caller we stole the overflow style from the body element
  2284     return bodyElement;
  2287   return nullptr;
  2290 nsIFrame*
  2291 nsCSSFrameConstructor::ConstructDocElementFrame(Element*                 aDocElement,
  2292                                                 nsILayoutHistoryState*   aFrameState)
  2294   NS_PRECONDITION(mFixedContainingBlock,
  2295                   "No viewport?  Someone forgot to call ConstructRootFrame!");
  2296   NS_PRECONDITION(mFixedContainingBlock == GetRootFrame(),
  2297                   "Unexpected mFixedContainingBlock");
  2298   NS_PRECONDITION(!mDocElementContainingBlock,
  2299                   "Shouldn't have a doc element containing block here");
  2301   // Make sure to call PropagateScrollToViewport before
  2302   // SetUpDocElementContainingBlock, since it sets up our scrollbar state
  2303   // properly.
  2304 #ifdef DEBUG
  2305   nsIContent* propagatedScrollFrom =
  2306 #endif
  2307     PropagateScrollToViewport();
  2309   SetUpDocElementContainingBlock(aDocElement);
  2311   NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
  2313   nsFrameConstructorState state(mPresShell, mFixedContainingBlock, nullptr,
  2314                                 nullptr, aFrameState);
  2315   // Initialize the ancestor filter with null for now; we'll push
  2316   // aDocElement once we finish resolving style for it.
  2317   state.mTreeMatchContext.InitAncestors(nullptr);
  2319   // XXXbz why, exactly?
  2320   if (!mTempFrameTreeState)
  2321     state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
  2323   // Make sure that we'll handle restyles for this document element in
  2324   // the future.  We need this, because the document element might
  2325   // have stale restyle bits from a previous frame constructor for
  2326   // this document.  Unlike in AddFrameConstructionItems, it's safe to
  2327   // unset all element restyle flags, since we don't have any
  2328   // siblings.
  2329   aDocElement->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
  2331   // --------- CREATE AREA OR BOX FRAME -------
  2332   nsRefPtr<nsStyleContext> styleContext;
  2333   styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
  2334                                                          nullptr);
  2336   const nsStyleDisplay* display = styleContext->StyleDisplay();
  2338   // Ensure that our XBL bindings are installed.
  2339   if (display->mBinding) {
  2340     // Get the XBL loader.
  2341     nsresult rv;
  2342     bool resolveStyle;
  2344     nsXBLService* xblService = nsXBLService::GetInstance();
  2345     if (!xblService) {
  2346       return nullptr;
  2349     nsRefPtr<nsXBLBinding> binding;
  2350     rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
  2351                                   display->mBinding->mOriginPrincipal,
  2352                                   getter_AddRefs(binding), &resolveStyle);
  2353     if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
  2354       return nullptr; // Binding will load asynchronously.
  2356     if (binding) {
  2357       // For backwards compat, keep firing the root's constructor
  2358       // after all of its kids' constructors.  So tell the binding
  2359       // manager about it right now.
  2360       mDocument->BindingManager()->AddToAttachedQueue(binding);
  2363     if (resolveStyle) {
  2364       styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
  2365                                                              nullptr);
  2366       display = styleContext->StyleDisplay();
  2370   // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
  2372 #ifdef DEBUG
  2373   NS_ASSERTION(!display->IsScrollableOverflow() ||
  2374                state.mPresContext->IsPaginated() ||
  2375                propagatedScrollFrom == aDocElement,
  2376                "Scrollbars should have been propagated to the viewport");
  2377 #endif
  2379   if (MOZ_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) {
  2380     SetUndisplayedContent(aDocElement, styleContext);
  2381     return nullptr;
  2384   TreeMatchContext::AutoAncestorPusher ancestorPusher(state.mTreeMatchContext);
  2385   ancestorPusher.PushAncestorAndStyleScope(aDocElement);
  2387   // Make sure to start any background image loads for the root element now.
  2388   styleContext->StartBackgroundImageLoads();
  2390   nsFrameConstructorSaveState absoluteSaveState;
  2391   if (mHasRootAbsPosContainingBlock) {
  2392     // Push the absolute containing block now so we can absolutely position
  2393     // the root element
  2394     mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  2395     state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
  2396                                       mDocElementContainingBlock,
  2397                                       absoluteSaveState);
  2400   // The rules from CSS 2.1, section 9.2.4, have already been applied
  2401   // by the style system, so we can assume that display->mDisplay is
  2402   // either NONE, BLOCK, or TABLE.
  2404   // contentFrame is the primary frame for the root element. newFrame
  2405   // is the frame that will be the child of the initial containing block.
  2406   // These are usually the same frame but they can be different, in
  2407   // particular if the root frame is positioned, in which case
  2408   // contentFrame is the out-of-flow frame and newFrame is the
  2409   // placeholder.
  2410   nsIFrame* contentFrame;
  2411   nsIFrame* newFrame;
  2412   bool processChildren = false;
  2414   // Check whether we need to build a XUL box or SVG root frame
  2415 #ifdef MOZ_XUL
  2416   if (aDocElement->IsXUL()) {
  2417     contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext);
  2418     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
  2419                         contentFrame);
  2420     newFrame = contentFrame;
  2421     processChildren = true;
  2423   else
  2424 #endif
  2425   if (aDocElement->IsSVG()) {
  2426     if (aDocElement->Tag() != nsGkAtoms::svg) {
  2427       return nullptr;
  2429     // We're going to call the right function ourselves, so no need to give a
  2430     // function to this FrameConstructionData.
  2432     // XXXbz on the other hand, if we converted this whole function to
  2433     // FrameConstructionData/Item, then we'd need the right function
  2434     // here... but would probably be able to get away with less code in this
  2435     // function in general.
  2436     // Use a null PendingBinding, since our binding is not in fact pending.
  2437     static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
  2438     already_AddRefed<nsStyleContext> extraRef =
  2439       nsRefPtr<nsStyleContext>(styleContext).forget();
  2440     FrameConstructionItem item(&rootSVGData, aDocElement,
  2441                                aDocElement->Tag(), kNameSpaceID_SVG,
  2442                                nullptr, extraRef, true, nullptr);
  2444     nsFrameItems frameItems;
  2445     contentFrame = ConstructOuterSVG(state, item, mDocElementContainingBlock,
  2446                                      styleContext->StyleDisplay(),
  2447                                      frameItems);
  2448     newFrame = frameItems.FirstChild();
  2449     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
  2450   } else if (display->mDisplay == NS_STYLE_DISPLAY_FLEX) {
  2451     contentFrame = NS_NewFlexContainerFrame(mPresShell, styleContext);
  2452     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
  2453                         contentFrame);
  2454     newFrame = contentFrame;
  2455     processChildren = true;
  2456   } else if (display->mDisplay == NS_STYLE_DISPLAY_GRID) {
  2457     contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
  2458     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
  2459                         contentFrame);
  2460     newFrame = contentFrame;
  2461     processChildren = true;
  2462   } else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) {
  2463     // We're going to call the right function ourselves, so no need to give a
  2464     // function to this FrameConstructionData.
  2466     // XXXbz on the other hand, if we converted this whole function to
  2467     // FrameConstructionData/Item, then we'd need the right function
  2468     // here... but would probably be able to get away with less code in this
  2469     // function in general.
  2470     // Use a null PendingBinding, since our binding is not in fact pending.
  2471     static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
  2472     already_AddRefed<nsStyleContext> extraRef =
  2473       nsRefPtr<nsStyleContext>(styleContext).forget();
  2474     FrameConstructionItem item(&rootTableData, aDocElement,
  2475                                aDocElement->Tag(), kNameSpaceID_None,
  2476                                nullptr, extraRef, true, nullptr);
  2478     nsFrameItems frameItems;
  2479     // if the document is a table then just populate it.
  2480     contentFrame = ConstructTable(state, item, mDocElementContainingBlock,
  2481                                   styleContext->StyleDisplay(),
  2482                                   frameItems);
  2483     newFrame = frameItems.FirstChild();
  2484     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
  2485   } else {
  2486     MOZ_ASSERT(display->mDisplay == NS_STYLE_DISPLAY_BLOCK,
  2487                "Unhandled display type for root element");
  2488     contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
  2489     nsFrameItems frameItems;
  2490     // Use a null PendingBinding, since our binding is not in fact pending.
  2491     ConstructBlock(state, display, aDocElement,
  2492                    state.GetGeometricParent(display,
  2493                                             mDocElementContainingBlock),
  2494                    mDocElementContainingBlock, styleContext,
  2495                    &contentFrame, frameItems,
  2496                    display->IsPositioned(contentFrame) ? contentFrame : nullptr,
  2497                    nullptr);
  2498     newFrame = frameItems.FirstChild();
  2499     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
  2502   MOZ_ASSERT(newFrame);
  2503   MOZ_ASSERT(contentFrame);
  2505   NS_ASSERTION(processChildren ? !mRootElementFrame :
  2506                  mRootElementFrame == contentFrame,
  2507                "unexpected mRootElementFrame");
  2508   mRootElementFrame = contentFrame;
  2510   // Figure out which frame has the main style for the document element,
  2511   // assigning it to mRootElementStyleFrame.
  2512   // Backgrounds should be propagated from that frame to the viewport.
  2513   mRootElementStyleFrame = contentFrame->GetParentStyleContextFrame();
  2514   bool isChild = mRootElementStyleFrame &&
  2515                  mRootElementStyleFrame->GetParent() == contentFrame;
  2516   if (!isChild) {
  2517     mRootElementStyleFrame = mRootElementFrame;
  2520   if (processChildren) {
  2521     // Still need to process the child content
  2522     nsFrameItems childItems;
  2524     NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) &&
  2525                  !contentFrame->IsFrameOfType(nsIFrame::eSVG),
  2526                  "Only XUL frames should reach here");
  2527     // Use a null PendingBinding, since our binding is not in fact pending.
  2528     ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
  2529                     childItems, false, nullptr);
  2531     // Set the initial child lists
  2532     contentFrame->SetInitialChildList(kPrincipalList, childItems);
  2535   // set the primary frame
  2536   aDocElement->SetPrimaryFrame(contentFrame);
  2538   SetInitialSingleChild(mDocElementContainingBlock, newFrame);
  2540   return newFrame;
  2544 nsIFrame*
  2545 nsCSSFrameConstructor::ConstructRootFrame()
  2547   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
  2549   nsStyleSet *styleSet = mPresShell->StyleSet();
  2551   // Set up our style rule observer.
  2552   // XXXbz wouldn't this make more sense as part of presshell init?
  2554     styleSet->SetBindingManager(mDocument->BindingManager());
  2557   // --------- BUILD VIEWPORT -----------
  2558   nsIFrame*                 viewportFrame = nullptr;
  2559   nsRefPtr<nsStyleContext> viewportPseudoStyle;
  2561   viewportPseudoStyle =
  2562     styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewport, nullptr);
  2564   viewportFrame = NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
  2566   // XXXbz do we _have_ to pass a null content pointer to that frame?
  2567   // Would it really kill us to pass in the root element or something?
  2568   // What would that break?
  2569   viewportFrame->Init(nullptr, nullptr, nullptr);
  2571   // Bind the viewport frame to the root view
  2572   nsView* rootView = mPresShell->GetViewManager()->GetRootView();
  2573   viewportFrame->SetView(rootView);
  2575   nsContainerFrame::SyncFrameViewProperties(mPresShell->GetPresContext(), viewportFrame,
  2576                                             viewportPseudoStyle, rootView);
  2577   nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
  2578                                          rootView);
  2580   // The viewport is the containing block for 'fixed' elements
  2581   mFixedContainingBlock = viewportFrame;
  2582   // Make it an absolute container for fixed-pos elements
  2583   mFixedContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  2584   mFixedContainingBlock->MarkAsAbsoluteContainingBlock();
  2586   return viewportFrame;
  2589 void
  2590 nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
  2592   NS_PRECONDITION(aDocElement, "No element?");
  2593   NS_PRECONDITION(!aDocElement->GetParent(), "Not root content?");
  2594   NS_PRECONDITION(aDocElement->GetCurrentDoc(), "Not in a document?");
  2595   NS_PRECONDITION(aDocElement->GetCurrentDoc()->GetRootElement() ==
  2596                   aDocElement, "Not the root of the document?");
  2598   /*
  2599     how the root frame hierarchy should look
  2601   Galley presentation, non-XUL, with scrolling:
  2603       ViewportFrame [fixed-cb]
  2604         nsHTMLScrollFrame
  2605           nsCanvasFrame [abs-cb]
  2606             root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
  2607                                 nsTableOuterFrame, nsPlaceholderFrame)
  2609   Galley presentation, XUL
  2611       ViewportFrame [fixed-cb]
  2612         nsRootBoxFrame
  2613           root element frame (nsDocElementBoxFrame)
  2615   Print presentation, non-XUL
  2617       ViewportFrame
  2618         nsSimplePageSequenceFrame
  2619           nsPageFrame [fixed-cb]
  2620             nsPageContentFrame
  2621               nsCanvasFrame [abs-cb]
  2622                 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
  2623                                     nsTableOuterFrame, nsPlaceholderFrame)
  2625   Print-preview presentation, non-XUL
  2627       ViewportFrame
  2628         nsHTMLScrollFrame
  2629           nsSimplePageSequenceFrame
  2630             nsPageFrame [fixed-cb]
  2631               nsPageContentFrame
  2632                 nsCanvasFrame [abs-cb]
  2633                   root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
  2634                                       nsTableOuterFrame, nsPlaceholderFrame)
  2636   Print/print preview of XUL is not supported.
  2637   [fixed-cb]: the default containing block for fixed-pos content
  2638   [abs-cb]: the default containing block for abs-pos content
  2640   Meaning of nsCSSFrameConstructor fields:
  2641     mRootElementFrame is "root element frame".  This is the primary frame for
  2642       the root element.
  2643     mDocElementContainingBlock is the parent of mRootElementFrame
  2644       (i.e. nsCanvasFrame or nsRootBoxFrame)
  2645     mFixedContainingBlock is the [fixed-cb]
  2646     mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one
  2647     mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
  2648   */
  2650   // --------- CREATE ROOT FRAME -------
  2653   // Create the root frame. The document element's frame is a child of the
  2654   // root frame.
  2655   //
  2656   // The root frame serves two purposes:
  2657   // - reserves space for any margins needed for the document element's frame
  2658   // - renders the document element's background. This ensures the background covers
  2659   //   the entire canvas as specified by the CSS2 spec
  2661   nsPresContext* presContext = mPresShell->GetPresContext();
  2662   bool isPaginated = presContext->IsRootPaginatedDocument();
  2663   nsIFrame* viewportFrame = mFixedContainingBlock;
  2664   nsStyleContext* viewportPseudoStyle = viewportFrame->StyleContext();
  2666   nsIFrame* rootFrame = nullptr;
  2667   nsIAtom* rootPseudo;
  2669   if (!isPaginated) {
  2670 #ifdef MOZ_XUL
  2671     if (aDocElement->IsXUL())
  2673       // pass a temporary stylecontext, the correct one will be set later
  2674       rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
  2675     } else
  2676 #endif
  2678       // pass a temporary stylecontext, the correct one will be set later
  2679       rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
  2680       mHasRootAbsPosContainingBlock = true;
  2683     rootPseudo = nsCSSAnonBoxes::canvas;
  2684     mDocElementContainingBlock = rootFrame;
  2685   } else {
  2686     // Create a page sequence frame
  2687     rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
  2688     mPageSequenceFrame = rootFrame;
  2689     rootPseudo = nsCSSAnonBoxes::pageSequence;
  2693   // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
  2695   // If the device supports scrolling (e.g., in galley mode on the screen and
  2696   // for print-preview, but not when printing), then create a scroll frame that
  2697   // will act as the scrolling mechanism for the viewport.
  2698   // XXX Do we even need a viewport when printing to a printer?
  2700   bool isHTML = aDocElement->IsHTML();
  2701   bool isXUL = false;
  2703   if (!isHTML) {
  2704     isXUL = aDocElement->IsXUL();
  2707   // Never create scrollbars for XUL documents
  2708   bool isScrollable = isPaginated ? presContext->HasPaginatedScrolling() : !isXUL;
  2710   // We no longer need to do overflow propagation here. It's taken care of
  2711   // when we construct frames for the element whose overflow might be
  2712   // propagated
  2713   NS_ASSERTION(!isScrollable || !isXUL,
  2714                "XUL documents should never be scrollable - see above");
  2716   nsIFrame* newFrame = rootFrame;
  2717   nsRefPtr<nsStyleContext> rootPseudoStyle;
  2718   // we must create a state because if the scrollbars are GFX it needs the
  2719   // state to build the scrollbar frames.
  2720   nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
  2722   // Start off with the viewport as parent; we'll adjust it as needed.
  2723   nsIFrame* parentFrame = viewportFrame;
  2725   nsStyleSet* styleSet = mPresShell->StyleSet();
  2726   // If paginated, make sure we don't put scrollbars in
  2727   if (!isScrollable) {
  2728     rootPseudoStyle = styleSet->ResolveAnonymousBoxStyle(rootPseudo,
  2729                                                          viewportPseudoStyle);
  2730   } else {
  2731       if (rootPseudo == nsCSSAnonBoxes::canvas) {
  2732         rootPseudo = nsCSSAnonBoxes::scrolledCanvas;
  2733       } else {
  2734         NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence,
  2735                      "Unknown root pseudo");
  2736         rootPseudo = nsCSSAnonBoxes::scrolledPageSequence;
  2739       // Build the frame. We give it the content we are wrapping which is the
  2740       // document element, the root frame, the parent view port frame, and we
  2741       // should get back the new frame and the scrollable view if one was
  2742       // created.
  2744       // resolve a context for the scrollframe
  2745       nsRefPtr<nsStyleContext>  styleContext;
  2746       styleContext = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll,
  2747                                                         viewportPseudoStyle);
  2749       // Note that the viewport scrollframe is always built with
  2750       // overflow:auto style. This forces the scroll frame to create
  2751       // anonymous content for both scrollbars. This is necessary even
  2752       // if the HTML or BODY elements are overriding the viewport
  2753       // scroll style to 'hidden' --- dynamic style changes might put
  2754       // scrollbars back on the viewport and we don't want to have to
  2755       // reframe the viewport to create the scrollbar content.
  2756       newFrame = nullptr;
  2757       rootPseudoStyle = BeginBuildingScrollFrame( state,
  2758                                                   aDocElement,
  2759                                                   styleContext,
  2760                                                   viewportFrame,
  2761                                                   rootPseudo,
  2762                                                   true,
  2763                                                   newFrame);
  2764       parentFrame = newFrame;
  2765       mGfxScrollFrame = newFrame;
  2768   rootFrame->SetStyleContextWithoutNotification(rootPseudoStyle);
  2769   rootFrame->Init(aDocElement, parentFrame, nullptr);
  2771   if (isScrollable) {
  2772     FinishBuildingScrollFrame(parentFrame, rootFrame);
  2775   if (isPaginated) { // paginated
  2776     // Create the first page
  2777     // Set the initial child lists
  2778     nsIFrame* canvasFrame;
  2779     nsIFrame* pageFrame =
  2780       ConstructPageFrame(mPresShell, presContext, rootFrame, nullptr,
  2781                          canvasFrame);
  2782     SetInitialSingleChild(rootFrame, pageFrame);
  2784     // The eventual parent of the document element frame.
  2785     // XXX should this be set for every new page (in ConstructPageFrame)?
  2786     mDocElementContainingBlock = canvasFrame;
  2787     mHasRootAbsPosContainingBlock = true;
  2790   if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
  2791     SetInitialSingleChild(viewportFrame, newFrame);
  2792   } else {
  2793     nsFrameList newFrameList(newFrame, newFrame);
  2794     viewportFrame->AppendFrames(kPrincipalList, newFrameList);
  2798 nsIFrame*
  2799 nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell*  aPresShell,
  2800                                           nsPresContext* aPresContext,
  2801                                           nsIFrame*      aParentFrame,
  2802                                           nsIFrame*      aPrevPageFrame,
  2803                                           nsIFrame*&     aCanvasFrame)
  2805   nsStyleContext* parentStyleContext = aParentFrame->StyleContext();
  2806   nsStyleSet *styleSet = aPresShell->StyleSet();
  2808   nsRefPtr<nsStyleContext> pagePseudoStyle;
  2809   pagePseudoStyle = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::page,
  2810                                                        parentStyleContext);
  2812   nsIFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
  2814   // Initialize the page frame and force it to have a view. This makes printing of
  2815   // the pages easier and faster.
  2816   pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
  2818   nsRefPtr<nsStyleContext> pageContentPseudoStyle;
  2819   pageContentPseudoStyle =
  2820     styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageContent,
  2821                                        pagePseudoStyle);
  2823   nsIFrame* pageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
  2825   // Initialize the page content frame and force it to have a view. Also make it the
  2826   // containing block for fixed elements which are repeated on every page.
  2827   nsIFrame* prevPageContentFrame = nullptr;
  2828   if (aPrevPageFrame) {
  2829     prevPageContentFrame = aPrevPageFrame->GetFirstPrincipalChild();
  2830     NS_ASSERTION(prevPageContentFrame, "missing page content frame");
  2832   pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
  2833   SetInitialSingleChild(pageFrame, pageContentFrame);
  2834   mFixedContainingBlock = pageContentFrame;
  2835   // Make it an absolute container for fixed-pos elements
  2836   mFixedContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  2837   mFixedContainingBlock->MarkAsAbsoluteContainingBlock();
  2839   nsRefPtr<nsStyleContext> canvasPseudoStyle;
  2840   canvasPseudoStyle = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::canvas,
  2841                                                          pageContentPseudoStyle);
  2843   aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
  2845   nsIFrame* prevCanvasFrame = nullptr;
  2846   if (prevPageContentFrame) {
  2847     prevCanvasFrame = prevPageContentFrame->GetFirstPrincipalChild();
  2848     NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
  2850   aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
  2851   SetInitialSingleChild(pageContentFrame, aCanvasFrame);
  2852   return pageFrame;
  2855 /* static */
  2856 nsIFrame*
  2857 nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell*    aPresShell,
  2858                                                  nsIContent*      aContent,
  2859                                                  nsIFrame*        aFrame,
  2860                                                  nsStyleContext*  aStyleContext,
  2861                                                  nsIFrame*        aParentFrame,
  2862                                                  nsIFrame*        aPrevInFlow,
  2863                                                  nsFrameState     aTypeBit)
  2865   nsRefPtr<nsStyleContext> placeholderStyle = aPresShell->StyleSet()->
  2866     ResolveStyleForNonElement(aStyleContext->GetParent());
  2868   // The placeholder frame gets a pseudo style context
  2869   nsPlaceholderFrame* placeholderFrame =
  2870     (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
  2871                                                 aTypeBit);
  2873   placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
  2875   // The placeholder frame has a pointer back to the out-of-flow frame
  2876   placeholderFrame->SetOutOfFlowFrame(aFrame);
  2878   aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
  2880   // Add mapping from absolutely positioned frame to its placeholder frame
  2881   aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame);
  2883   return placeholderFrame;
  2886 // Clears any lazy bits set in the range [aStartContent, aEndContent).  If
  2887 // aEndContent is null, that means to clear bits in all siblings starting with
  2888 // aStartContent.  aStartContent must not be null unless aEndContent is also
  2889 // null.  We do this so that when new children are inserted under elements whose
  2890 // frame is a leaf the new children don't cause us to try to construct frames
  2891 // for the existing children again.
  2892 static inline void
  2893 ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent)
  2895   NS_PRECONDITION(aStartContent || !aEndContent,
  2896                   "Must have start child if we have an end child");
  2897   for (nsIContent* cur = aStartContent; cur != aEndContent;
  2898        cur = cur->GetNextSibling()) {
  2899     cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
  2903 nsIFrame*
  2904 nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
  2905                                             FrameConstructionItem&   aItem,
  2906                                             nsIFrame*                aParentFrame,
  2907                                             const nsStyleDisplay*    aStyleDisplay,
  2908                                             nsFrameItems&            aFrameItems)
  2910   nsIContent* const content = aItem.mContent;
  2911   nsStyleContext* const styleContext = aItem.mStyleContext;
  2913   // Construct a frame-based listbox or combobox
  2914   dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromContent(content);
  2915   MOZ_ASSERT(sel);
  2916   if (sel->IsCombobox()) {
  2917     // Construct a frame-based combo box.
  2918     // The frame-based combo box is built out of three parts. A display area, a button and
  2919     // a dropdown list. The display area and button are created through anonymous content.
  2920     // The drop-down list's frame is created explicitly. The combobox frame shares its content
  2921     // with the drop-down list.
  2922     nsFrameState flags = NS_BLOCK_FLOAT_MGR;
  2923     nsIFrame* comboboxFrame = NS_NewComboboxControlFrame(mPresShell, styleContext, flags);
  2925     // Save the history state so we don't restore during construction
  2926     // since the complete tree is required before we restore.
  2927     nsILayoutHistoryState *historyState = aState.mFrameState;
  2928     aState.mFrameState = nullptr;
  2929     // Initialize the combobox frame
  2930     InitAndRestoreFrame(aState, content,
  2931                         aState.GetGeometricParent(aStyleDisplay, aParentFrame),
  2932                         comboboxFrame);
  2934     aState.AddChild(comboboxFrame, aFrameItems, content, styleContext,
  2935                     aParentFrame);
  2937     nsIComboboxControlFrame* comboBox = do_QueryFrame(comboboxFrame);
  2938     NS_ASSERTION(comboBox, "NS_NewComboboxControlFrame returned frame that "
  2939                  "doesn't implement nsIComboboxControlFrame");
  2941     // Resolve pseudo element style for the dropdown list
  2942     nsRefPtr<nsStyleContext> listStyle;
  2943     listStyle = mPresShell->StyleSet()->
  2944       ResolveAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList, styleContext);
  2946     // Create a listbox
  2947     nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
  2949     // Notify the listbox that it is being used as a dropdown list.
  2950     nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
  2951     if (listControlFrame) {
  2952       listControlFrame->SetComboboxFrame(comboboxFrame);
  2954     // Notify combobox that it should use the listbox as it's popup
  2955     comboBox->SetDropDown(listFrame);
  2957     NS_ASSERTION(!listFrame->IsPositioned(),
  2958                  "Ended up with positioned dropdown list somehow.");
  2959     NS_ASSERTION(!listFrame->IsFloating(),
  2960                  "Ended up with floating dropdown list somehow.");
  2962     // Initialize the scroll frame positioned. Note that it is NOT
  2963     // initialized as absolutely positioned.
  2964     nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(mPresShell, styleContext, flags);
  2966     InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
  2967                           comboboxFrame, listStyle, true,
  2968                           aItem.mPendingBinding, aFrameItems);
  2970     NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nullptr");
  2972     // Create display and button frames from the combobox's anonymous content.
  2973     // The anonymous content is appended to existing anonymous content for this
  2974     // element (the scrollbars).
  2976     nsFrameItems childItems;
  2977     CreateAnonymousFrames(aState, content, comboboxFrame,
  2978                           aItem.mPendingBinding, childItems);
  2980     comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
  2982     // Initialize the additional popup child list which contains the
  2983     // dropdown list frame.
  2984     nsFrameItems popupItems;
  2985     popupItems.AddChild(listFrame);
  2986     comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList,
  2987                                        popupItems);
  2989     aState.mFrameState = historyState;
  2990     if (aState.mFrameState) {
  2991       // Restore frame state for the entire subtree of |comboboxFrame|.
  2992       RestoreFrameState(comboboxFrame, aState.mFrameState);
  2994     return comboboxFrame;
  2997   // Listbox, not combobox
  2998   nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, styleContext);
  3000   nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(
  3001       mPresShell, styleContext, NS_BLOCK_FLOAT_MGR);
  3003   // ******* this code stolen from Initialze ScrollFrame ********
  3004   // please adjust this code to use BuildScrollFrame.
  3006   InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
  3007                         aParentFrame, styleContext, false,
  3008                         aItem.mPendingBinding, aFrameItems);
  3010   return listFrame;
  3013 /**
  3014  * Used to be InitializeScrollFrame but now it's only used for the select tag
  3015  * But the select tag should really be fixed to use GFX scrollbars that can
  3016  * be create with BuildScrollFrame.
  3017  */
  3018 nsresult
  3019 nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
  3020                                              nsIFrame*                scrollFrame,
  3021                                              nsIFrame*                scrolledFrame,
  3022                                              nsIContent*              aContent,
  3023                                              nsIFrame*                aParentFrame,
  3024                                              nsStyleContext*          aStyleContext,
  3025                                              bool                     aBuildCombobox,
  3026                                              PendingBinding*          aPendingBinding,
  3027                                              nsFrameItems&            aFrameItems)
  3029   const nsStyleDisplay* display = aStyleContext->StyleDisplay();
  3031   // Initialize it
  3032   nsIFrame* geometricParent = aState.GetGeometricParent(display, aParentFrame);
  3034   // We don't call InitAndRestoreFrame for scrollFrame because we can only
  3035   // restore the frame state after its parts have been created (in particular,
  3036   // the scrollable view). So we have to split Init and Restore.
  3038   // Initialize the frame
  3039   scrollFrame->Init(aContent, geometricParent, nullptr);
  3041   if (!aBuildCombobox) {
  3042     aState.AddChild(scrollFrame, aFrameItems, aContent,
  3043                     aStyleContext, aParentFrame);
  3046   if (aBuildCombobox) {
  3047     nsContainerFrame::CreateViewForFrame(scrollFrame, true);
  3050   BuildScrollFrame(aState, aContent, aStyleContext, scrolledFrame,
  3051                    geometricParent, scrollFrame);
  3053   if (aState.mFrameState) {
  3054     // Restore frame state for the scroll frame
  3055     RestoreFrameStateFor(scrollFrame, aState.mFrameState);
  3058   // Process children
  3059   nsFrameItems                childItems;
  3061   ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, false,
  3062                   childItems, false, aPendingBinding);
  3064   // Set the scrolled frame's initial child lists
  3065   scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
  3066   return NS_OK;
  3069 nsIFrame*
  3070 nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
  3071                                               FrameConstructionItem&   aItem,
  3072                                               nsIFrame*                aParentFrame,
  3073                                               const nsStyleDisplay*    aStyleDisplay,
  3074                                               nsFrameItems&            aFrameItems)
  3076   nsIContent* const content = aItem.mContent;
  3077   nsStyleContext* const styleContext = aItem.mStyleContext;
  3079   nsIFrame* fieldsetFrame = NS_NewFieldSetFrame(mPresShell, styleContext);
  3081   // Initialize it
  3082   InitAndRestoreFrame(aState, content,
  3083                       aState.GetGeometricParent(aStyleDisplay, aParentFrame),
  3084                       fieldsetFrame);
  3086   // Resolve style and initialize the frame
  3087   nsRefPtr<nsStyleContext> fieldsetContentStyle;
  3088   fieldsetContentStyle = mPresShell->StyleSet()->
  3089     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent, styleContext);
  3091   const nsStyleDisplay* fieldsetContentDisplay = fieldsetContentStyle->StyleDisplay();
  3092   bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
  3093   nsIFrame* scrollFrame = nullptr;
  3094   if (isScrollable) {
  3095     fieldsetContentStyle =
  3096       BeginBuildingScrollFrame(aState, content, fieldsetContentStyle,
  3097                                fieldsetFrame, nsCSSAnonBoxes::scrolledContent,
  3098                                false, scrollFrame);
  3101   nsIFrame* blockFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle,
  3102                                           NS_BLOCK_FLOAT_MGR |
  3103                                           NS_BLOCK_MARGIN_ROOT);
  3104   InitAndRestoreFrame(aState, content,
  3105     scrollFrame ? scrollFrame : fieldsetFrame, blockFrame);
  3107   aState.AddChild(fieldsetFrame, aFrameItems, content, styleContext, aParentFrame);
  3109   // Process children
  3110   nsFrameConstructorSaveState absoluteSaveState;
  3111   nsFrameItems                childItems;
  3113   blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  3114   if (fieldsetFrame->IsPositioned()) {
  3115     aState.PushAbsoluteContainingBlock(blockFrame, fieldsetFrame, absoluteSaveState);
  3118   ProcessChildren(aState, content, styleContext, blockFrame, true,
  3119                   childItems, true, aItem.mPendingBinding);
  3121   nsFrameItems fieldsetKids;
  3122   fieldsetKids.AddChild(scrollFrame ? scrollFrame : blockFrame);
  3124   for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
  3125     nsIFrame* child = e.get();
  3126     if (child->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame) {
  3127       // We want the legend to be the first frame in the fieldset child list.
  3128       // That way the EventStateManager will do the right thing when tabbing
  3129       // from a selection point within the legend (bug 236071), which is
  3130       // used for implementing legend access keys (bug 81481).
  3131       // GetAdjustedParentFrame() below depends on this frame order.
  3132       childItems.RemoveFrame(child);
  3133       // Make sure to reparent the legend so it has the fieldset as the parent.
  3134       fieldsetKids.InsertFrame(fieldsetFrame, nullptr, child);
  3135       if (scrollFrame) {
  3136         StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(
  3137             child, blockFrame);
  3139       break;
  3143   if (isScrollable) {
  3144     FinishBuildingScrollFrame(scrollFrame, blockFrame);
  3147   // Set the inner frame's initial child lists
  3148   blockFrame->SetInitialChildList(kPrincipalList, childItems);
  3150   // Set the outer frame's initial child list
  3151   fieldsetFrame->SetInitialChildList(kPrincipalList, fieldsetKids);
  3153   fieldsetFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
  3155   // Our new frame returned is the outer frame, which is the fieldset frame.
  3156   return fieldsetFrame;
  3159 static nsIFrame*
  3160 FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame)
  3162   for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
  3163     NS_ASSERTION(f->IsGeneratedContentFrame(),
  3164                  "should not have exited generated content");
  3165     nsIAtom* pseudo = f->StyleContext()->GetPseudo();
  3166     if (pseudo == nsCSSPseudoElements::before ||
  3167         pseudo == nsCSSPseudoElements::after)
  3168       return f;
  3170   return nullptr;
  3173 #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
  3174 #define FULL_CTOR_FCDATA(_flags, _func)                             \
  3175   { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nullptr }, _func, nullptr }
  3177 /* static */
  3178 const nsCSSFrameConstructor::FrameConstructionData*
  3179 nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame)
  3181   if (aParentFrame && IsFrameForSVG(aParentFrame)) {
  3182     nsIFrame *ancestorFrame =
  3183       nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
  3184     if (ancestorFrame) {
  3185       static const FrameConstructionData sSVGTextData =
  3186         FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT,
  3187                     NS_NewTextFrame);
  3188       if (ancestorFrame->IsSVGText()) {
  3189         return &sSVGTextData;
  3192     return nullptr;
  3195   static const FrameConstructionData sTextData =
  3196     FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
  3197   return &sTextData;
  3200 void
  3201 nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData,
  3202                                           nsFrameConstructorState& aState,
  3203                                           nsIContent*              aContent,
  3204                                           nsIFrame*                aParentFrame,
  3205                                           nsStyleContext*          aStyleContext,
  3206                                           nsFrameItems&            aFrameItems)
  3208   NS_PRECONDITION(aData, "Must have frame construction data");
  3210   nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aStyleContext);
  3212   InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
  3214   // We never need to create a view for a text frame.
  3216   if (newFrame->IsGeneratedContentFrame()) {
  3217     nsAutoPtr<nsGenConInitializer> initializer;
  3218     initializer =
  3219       static_cast<nsGenConInitializer*>(
  3220         aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
  3221     if (initializer) {
  3222       if (initializer->mNode->InitTextFrame(initializer->mList,
  3223               FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
  3224         (this->*(initializer->mDirtyAll))();
  3226       initializer->mNode.forget();
  3230   // Add the newly constructed frame to the flow
  3231   aFrameItems.AddChild(newFrame);
  3233   if (!aState.mCreatingExtraFrames)
  3234     aContent->SetPrimaryFrame(newFrame);
  3237 /* static */
  3238 const nsCSSFrameConstructor::FrameConstructionData*
  3239 nsCSSFrameConstructor::FindDataByInt(int32_t aInt,
  3240                                      Element* aElement,
  3241                                      nsStyleContext* aStyleContext,
  3242                                      const FrameConstructionDataByInt* aDataPtr,
  3243                                      uint32_t aDataLength)
  3245   for (const FrameConstructionDataByInt *curData = aDataPtr,
  3246          *endData = aDataPtr + aDataLength;
  3247        curData != endData;
  3248        ++curData) {
  3249     if (curData->mInt == aInt) {
  3250       const FrameConstructionData* data = &curData->mData;
  3251       if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
  3252         return data->mFunc.mDataGetter(aElement, aStyleContext);
  3255       return data;
  3259   return nullptr;
  3262 /* static */
  3263 const nsCSSFrameConstructor::FrameConstructionData*
  3264 nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
  3265                                      Element* aElement,
  3266                                      nsStyleContext* aStyleContext,
  3267                                      const FrameConstructionDataByTag* aDataPtr,
  3268                                      uint32_t aDataLength)
  3270   for (const FrameConstructionDataByTag *curData = aDataPtr,
  3271          *endData = aDataPtr + aDataLength;
  3272        curData != endData;
  3273        ++curData) {
  3274     if (*curData->mTag == aTag) {
  3275       const FrameConstructionData* data = &curData->mData;
  3276       if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
  3277         return data->mFunc.mDataGetter(aElement, aStyleContext);
  3280       return data;
  3284   return nullptr;
  3287 #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nullptr)
  3288 #define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
  3289 #define SIMPLE_INT_CHAIN(_int, _func)                       \
  3290   { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
  3291 #define COMPLEX_INT_CREATE(_int, _func)         \
  3292   { _int, FULL_CTOR_FCDATA(0, _func) }
  3294 #define SIMPLE_TAG_CREATE(_tag, _func)          \
  3295   { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
  3296 #define SIMPLE_TAG_CHAIN(_tag, _func)                                   \
  3297   { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER,  _func) }
  3298 #define COMPLEX_TAG_CREATE(_tag, _func)             \
  3299   { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
  3301 static bool
  3302 IsFrameForFieldSet(nsIFrame* aFrame, nsIAtom* aFrameType)
  3304   nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
  3305   if (pseudo == nsCSSAnonBoxes::fieldsetContent ||
  3306       pseudo == nsCSSAnonBoxes::scrolledContent) {
  3307     return IsFrameForFieldSet(aFrame->GetParent(), aFrame->GetParent()->GetType());
  3309   return aFrameType == nsGkAtoms::fieldSetFrame;
  3312 /* static */
  3313 const nsCSSFrameConstructor::FrameConstructionData*
  3314 nsCSSFrameConstructor::FindHTMLData(Element* aElement,
  3315                                     nsIAtom* aTag,
  3316                                     int32_t aNameSpaceID,
  3317                                     nsIFrame* aParentFrame,
  3318                                     nsStyleContext* aStyleContext)
  3320   // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
  3321   // a valid HTML namespace.  This check must match the one in
  3322   // ShouldHaveFirstLineStyle.
  3323   if (aNameSpaceID != kNameSpaceID_XHTML) {
  3324     return nullptr;
  3327   NS_ASSERTION(!aParentFrame ||
  3328                aParentFrame->StyleContext()->GetPseudo() !=
  3329                  nsCSSAnonBoxes::fieldsetContent ||
  3330                aParentFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame,
  3331                "Unexpected parent for fieldset content anon box");
  3332   if (aTag == nsGkAtoms::legend &&
  3333       (!aParentFrame ||
  3334        !IsFrameForFieldSet(aParentFrame, aParentFrame->GetType()) ||
  3335        !aElement->GetParent() ||
  3336        !aElement->GetParent()->IsHTML(nsGkAtoms::fieldset) ||
  3337        aStyleContext->StyleDisplay()->IsFloatingStyle() ||
  3338        aStyleContext->StyleDisplay()->IsAbsolutelyPositionedStyle())) {
  3339     // <legend> is only special inside fieldset, check both the frame tree
  3340     // parent and content tree parent due to XBL issues. For floated or
  3341     // absolutely positioned legends we want to construct by display type and
  3342     // not do special legend stuff.
  3343     // XXXbz it would be nice if we could just decide this based on the parent
  3344     // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the
  3345     // fact that with XBL we could end up with this legend element in some
  3346     // totally weird insertion point makes that chancy, I think.
  3347     return nullptr;
  3350   static const FrameConstructionDataByTag sHTMLData[] = {
  3351     SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
  3352     SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
  3353                      nsCSSFrameConstructor::FindImgData),
  3354     { &nsGkAtoms::br,
  3355       FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
  3356                   NS_NewBRFrame) },
  3357     SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
  3358     SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
  3359     SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
  3360     COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
  3361     SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
  3362     SIMPLE_TAG_CHAIN(applet, nsCSSFrameConstructor::FindObjectData),
  3363     SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
  3364     COMPLEX_TAG_CREATE(fieldset,
  3365                        &nsCSSFrameConstructor::ConstructFieldSetFrame),
  3366     { &nsGkAtoms::legend,
  3367       FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
  3368                   NS_NewLegendFrame) },
  3369     SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
  3370     SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
  3371     { &nsGkAtoms::button,
  3372       FCDATA_WITH_WRAPPING_BLOCK(FCDATA_ALLOW_BLOCK_STYLES,
  3373                                  NS_NewHTMLButtonControlFrame,
  3374                                  nsCSSAnonBoxes::buttonContent) },
  3375     SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
  3376     SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
  3377     SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
  3378     SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
  3379     SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame)
  3380   };
  3382   return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
  3383                        ArrayLength(sHTMLData));
  3386 /* static */
  3387 const nsCSSFrameConstructor::FrameConstructionData*
  3388 nsCSSFrameConstructor::FindImgData(Element* aElement,
  3389                                    nsStyleContext* aStyleContext)
  3391   if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
  3392     return nullptr;
  3395   static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
  3396   return &sImgData;
  3399 /* static */
  3400 const nsCSSFrameConstructor::FrameConstructionData*
  3401 nsCSSFrameConstructor::FindImgControlData(Element* aElement,
  3402                                           nsStyleContext* aStyleContext)
  3404   if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
  3405     return nullptr;
  3408   static const FrameConstructionData sImgControlData =
  3409     SIMPLE_FCDATA(NS_NewImageControlFrame);
  3410   return &sImgControlData;
  3413 /* static */
  3414 const nsCSSFrameConstructor::FrameConstructionData*
  3415 nsCSSFrameConstructor::FindInputData(Element* aElement,
  3416                                      nsStyleContext* aStyleContext)
  3418   static const FrameConstructionDataByInt sInputData[] = {
  3419     SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewGfxCheckboxControlFrame),
  3420     SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewGfxRadioControlFrame),
  3421     SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
  3422     SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
  3423                      nsCSSFrameConstructor::FindImgControlData),
  3424     SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame),
  3425     SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame),
  3426     SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
  3427     SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame),
  3428     SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame),
  3429     SIMPLE_INT_CREATE(NS_FORM_INPUT_RANGE, NS_NewRangeFrame),
  3430     SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
  3431     { NS_FORM_INPUT_COLOR,
  3432       FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewColorControlFrame,
  3433                                  nsCSSAnonBoxes::buttonContent) },
  3434     // TODO: this is temporary until a frame is written: bug 635240.
  3435     SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
  3436     // TODO: this is temporary until a frame is written: bug 773205.
  3437     SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame),
  3438     // TODO: this is temporary until a frame is written: bug 773205
  3439     SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame),
  3440     { NS_FORM_INPUT_SUBMIT,
  3441       FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
  3442                                  nsCSSAnonBoxes::buttonContent) },
  3443     { NS_FORM_INPUT_RESET,
  3444       FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
  3445                                  nsCSSAnonBoxes::buttonContent) },
  3446     { NS_FORM_INPUT_BUTTON,
  3447       FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
  3448                                  nsCSSAnonBoxes::buttonContent) }
  3449     // Keeping hidden inputs out of here on purpose for so they get frames by
  3450     // display (in practice, none).
  3451   };
  3453   nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
  3454   NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
  3456   return FindDataByInt(control->GetType(), aElement, aStyleContext,
  3457                        sInputData, ArrayLength(sInputData));
  3460 /* static */
  3461 const nsCSSFrameConstructor::FrameConstructionData*
  3462 nsCSSFrameConstructor::FindObjectData(Element* aElement,
  3463                                       nsStyleContext* aStyleContext)
  3465   // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
  3466   // cases when the object is broken/suppressed/etc (e.g. a broken image), but
  3467   // we want to treat those cases as TYPE_NULL
  3468   uint32_t type;
  3469   if (aElement->State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
  3470                                               NS_EVENT_STATE_USERDISABLED |
  3471                                               NS_EVENT_STATE_SUPPRESSED)) {
  3472     type = nsIObjectLoadingContent::TYPE_NULL;
  3473   } else {
  3474     nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement));
  3475     NS_ASSERTION(objContent,
  3476                  "applet, embed and object must implement "
  3477                  "nsIObjectLoadingContent!");
  3479     objContent->GetDisplayedType(&type);
  3482   static const FrameConstructionDataByInt sObjectData[] = {
  3483     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
  3484                       NS_NewEmptyFrame),
  3485     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
  3486                       NS_NewObjectFrame),
  3487     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
  3488                       NS_NewImageFrame),
  3489     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
  3490                       NS_NewSubDocumentFrame)
  3491     // Nothing for TYPE_NULL so we'll construct frames by display there
  3492   };
  3494   return FindDataByInt((int32_t)type, aElement, aStyleContext,
  3495                        sObjectData, ArrayLength(sObjectData));
  3498 /* static */
  3499 const nsCSSFrameConstructor::FrameConstructionData*
  3500 nsCSSFrameConstructor::FindCanvasData(Element* aElement,
  3501                                       nsStyleContext* aStyleContext)
  3503   // We want to check whether script is enabled on the document that
  3504   // could be painting to the canvas.  That's the owner document of
  3505   // the canvas, except when the owner document is a static document,
  3506   // in which case it's the original document it was cloned from.
  3507   nsIDocument* doc = aElement->OwnerDoc();
  3508   if (doc->IsStaticDocument()) {
  3509     doc = doc->GetOriginalDocument();
  3511   if (!doc->IsScriptEnabled()) {
  3512     return nullptr;
  3515   static const FrameConstructionData sCanvasData =
  3516     FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
  3517                                nsCSSAnonBoxes::htmlCanvasContent);
  3518   return &sCanvasData;
  3521 void
  3522 nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
  3523                                                       nsFrameConstructorState& aState,
  3524                                                       nsIFrame* aParentFrame,
  3525                                                       nsFrameItems& aFrameItems)
  3527   const FrameConstructionData* data = aItem.mFCData;
  3528   NS_ASSERTION(data, "Must have frame construction data");
  3530   uint32_t bits = data->mBits;
  3532   NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
  3533                "Should have dealt with this inside the data finder");
  3535   // Some sets of bits are not compatible with each other
  3536 #define CHECK_ONLY_ONE_BIT(_bit1, _bit2)               \
  3537   NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2),     \
  3538                "Only one of these bits should be set")
  3539   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
  3540   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
  3541   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
  3542   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
  3543   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
  3544   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
  3545                      FCDATA_DISALLOW_GENERATED_CONTENT);
  3546   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
  3547   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
  3548                      FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
  3549   CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
  3550                      FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
  3551 #undef CHECK_ONLY_ONE_BIT
  3552   NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
  3553                ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
  3554                 data->mFullConstructor ==
  3555                   &nsCSSFrameConstructor::ConstructNonScrollableBlock),
  3556                "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
  3558   // Don't create a subdocument frame for iframes if we're creating extra frames
  3559   if (aState.mCreatingExtraFrames && aItem.mContent->IsHTML() &&
  3560       aItem.mContent->Tag() == nsGkAtoms::iframe)
  3562     return;
  3565   nsStyleContext* const styleContext = aItem.mStyleContext;
  3566   const nsStyleDisplay* display = styleContext->StyleDisplay();
  3567   nsIContent* const content = aItem.mContent;
  3569   // Get the parent of the content and check if it is a XBL children element.
  3570   // Push the children element as an ancestor here because it does
  3571   // not have a frame and would not otherwise be pushed as an ancestor. It is
  3572   // necessary to do so in order to correctly handle style resolution on
  3573   // descendants.
  3574   nsIContent* parent = content->GetParent();
  3575   TreeMatchContext::AutoAncestorPusher
  3576     insertionPointPusher(aState.mTreeMatchContext);
  3577   if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
  3578     if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
  3579       insertionPointPusher.PushAncestorAndStyleScope(parent);
  3580     } else {
  3581       insertionPointPusher.PushStyleScope(parent);
  3585   // Push the content as a style ancestor now, so we don't have to do
  3586   // it in our various full-constructor functions.  In particular,
  3587   // since a number of full-constructor functions don't actually call
  3588   // ProcessChildren in some cases (e.g. for CSS anonymous table boxes
  3589   // or for situations where only anonymouse children are having
  3590   // frames constructed), this is the best place to bottleneck the
  3591   // pushing of the content instead of having to do it in multiple
  3592   // places.
  3593   TreeMatchContext::AutoAncestorPusher
  3594     ancestorPusher(aState.mTreeMatchContext);
  3595   if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
  3596     ancestorPusher.PushAncestorAndStyleScope(content);
  3597   } else {
  3598     ancestorPusher.PushStyleScope(content);
  3601   nsIFrame* newFrame;
  3602   nsIFrame* primaryFrame;
  3603   if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
  3604     newFrame =
  3605       (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
  3606                                         display, aFrameItems);
  3607     MOZ_ASSERT(newFrame, "Full constructor failed");
  3608     primaryFrame = newFrame;
  3609   } else {
  3610     newFrame =
  3611       (*data->mFunc.mCreationFunc)(mPresShell, styleContext);
  3613     bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
  3614     bool isPopup = aItem.mIsPopup;
  3615     NS_ASSERTION(!isPopup ||
  3616                  (aState.mPopupItems.containingBlock &&
  3617                   aState.mPopupItems.containingBlock->GetType() ==
  3618                     nsGkAtoms::popupSetFrame),
  3619                  "Should have a containing block here!");
  3621     nsIFrame* geometricParent =
  3622       isPopup ? aState.mPopupItems.containingBlock :
  3623       (allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame)
  3624                       : aParentFrame);
  3626     // Must init frameToAddToList to null, since it's inout
  3627     nsIFrame* frameToAddToList = nullptr;
  3628     if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
  3629         display->IsScrollableOverflow()) {
  3630       BuildScrollFrame(aState, content, styleContext, newFrame,
  3631                        geometricParent, frameToAddToList);
  3632     } else {
  3633       InitAndRestoreFrame(aState, content, geometricParent, newFrame);
  3634       // See whether we need to create a view
  3635       nsContainerFrame::CreateViewForFrame(newFrame, false);
  3636       frameToAddToList = newFrame;
  3639     // Use frameToAddToList as the primary frame.  In the non-scrollframe case
  3640     // they're equal, but in the scrollframe case newFrame is the scrolled
  3641     // frame, while frameToAddToList is the scrollframe (and should be the
  3642     // primary frame).
  3643     primaryFrame = frameToAddToList;
  3645     // If we need to create a block formatting context to wrap our
  3646     // kids, do it now.
  3647     const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display;
  3648     nsIFrame* maybeAbsoluteContainingBlock = newFrame;
  3649     nsIFrame* possiblyLeafFrame = newFrame;
  3650     if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
  3651       nsRefPtr<nsStyleContext> blockContext;
  3652       blockContext =
  3653         mPresShell->StyleSet()->ResolveAnonymousBoxStyle(*data->mAnonBoxPseudo,
  3654                                                          styleContext);
  3655       nsIFrame* blockFrame =
  3656         NS_NewBlockFormattingContext(mPresShell, blockContext);
  3658       InitAndRestoreFrame(aState, content, newFrame, blockFrame);
  3660       SetInitialSingleChild(newFrame, blockFrame);
  3662       // Now figure out whether newFrame or blockFrame should be the
  3663       // absolute container.  It should be the latter if it's
  3664       // positioned, otherwise the former.
  3665       const nsStyleDisplay* blockDisplay = blockContext->StyleDisplay();
  3666       if (blockDisplay->IsPositioned(blockFrame)) {
  3667         maybeAbsoluteContainingBlockDisplay = blockDisplay;
  3668         maybeAbsoluteContainingBlock = blockFrame;
  3671       // Our kids should go into the blockFrame
  3672       newFrame = blockFrame;
  3675     aState.AddChild(frameToAddToList, aFrameItems, content, styleContext,
  3676                     aParentFrame, allowOutOfFlow, allowOutOfFlow, isPopup);
  3678 #ifdef MOZ_XUL
  3679     // Icky XUL stuff, sadly
  3681     if (aItem.mIsRootPopupgroup) {
  3682       NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) &&
  3683                    nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
  3684                      newFrame,
  3685                    "Unexpected PopupSetFrame");
  3686       aState.mPopupItems.containingBlock = newFrame;
  3687       aState.mHavePendingPopupgroup = false;
  3689 #endif /* MOZ_XUL */
  3691     // Process the child content if requested
  3692     nsFrameItems childItems;
  3693     nsFrameConstructorSaveState absoluteSaveState;
  3695     if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
  3696       aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
  3697     } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
  3698       nsIFrame* cb = maybeAbsoluteContainingBlock;
  3699       cb->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  3700       // This check is identical to nsStyleDisplay::IsPositioned except without
  3701       // the assertion that the style display and frame match. When constructing
  3702       // scroll frames we intentionally use the style display for the outer, but
  3703       // make the inner the containing block.
  3704       if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() ||
  3705            maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() ||
  3706            (maybeAbsoluteContainingBlockDisplay->HasTransformStyle() &&
  3707             cb->IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) ||
  3708            maybeAbsoluteContainingBlockDisplay->HasPerspectiveStyle()) &&
  3709           !cb->IsSVGText()) {
  3710         aState.PushAbsoluteContainingBlock(cb, cb, absoluteSaveState);
  3714     if (!aItem.mAnonChildren.IsEmpty()) {
  3715       NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS),
  3716                    "We should not have both anonymous and non-anonymous "
  3717                    "children in a given FrameConstructorItem");
  3718       AddFCItemsForAnonymousContent(aState, newFrame, aItem.mAnonChildren,
  3719                                     aItem.mChildItems);
  3720       bits |= FCDATA_USE_CHILD_ITEMS;
  3723     if (bits & FCDATA_USE_CHILD_ITEMS) {
  3724       nsFrameConstructorSaveState floatSaveState;
  3726       if (ShouldSuppressFloatingOfDescendants(newFrame)) {
  3727         aState.PushFloatContainingBlock(nullptr, floatSaveState);
  3728       } else if (newFrame->IsFloatContainingBlock()) {
  3729         aState.PushFloatContainingBlock(newFrame, floatSaveState);
  3731       ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
  3732                                   childItems);
  3733     } else {
  3734       // Process the child frames.
  3735       ProcessChildren(aState, content, styleContext, newFrame,
  3736                       !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
  3737                       childItems,
  3738                       (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
  3739                       aItem.mPendingBinding, possiblyLeafFrame);
  3742 #ifdef MOZ_XUL
  3743     // More icky XUL stuff
  3744     if (aItem.mNameSpaceID == kNameSpaceID_XUL &&
  3745         (aItem.mTag == nsGkAtoms::treechildren || // trees always need titletips
  3746          content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext) ||
  3747          content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltip))) {
  3748       nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
  3749       if (rootBox) {
  3750         rootBox->AddTooltipSupport(content);
  3753 #endif
  3755     if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) {
  3756       nsFrameItems newItems;
  3757       nsFrameItems currentBlockItems;
  3758       nsIFrame* f;
  3759       while ((f = childItems.FirstChild()) != nullptr) {
  3760         bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
  3761         if (!wrapFrame) {
  3762           FlushAccumulatedBlock(aState, content, newFrame,
  3763                                 currentBlockItems, newItems);
  3766         childItems.RemoveFrame(f);
  3767         if (wrapFrame) {
  3768           currentBlockItems.AddChild(f);
  3769         } else {
  3770           newItems.AddChild(f);
  3773       FlushAccumulatedBlock(aState, content, newFrame,
  3774                             currentBlockItems, newItems);
  3776       if (childItems.NotEmpty()) {
  3777         // an error must have occurred, delete unprocessed frames
  3778         childItems.DestroyFrames();
  3781       childItems = newItems;
  3784     // Set the frame's initial child list
  3785     // Note that MathML depends on this being called even if
  3786     // childItems is empty!
  3787     newFrame->SetInitialChildList(kPrincipalList, childItems);
  3790   NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
  3791                ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
  3792                "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
  3794   if (aItem.mIsAnonymousContentCreatorContent) {
  3795     primaryFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
  3798   // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
  3799   // generated content that doesn't have one yet.  Note that we have to examine
  3800   // the frame bit, because by this point mIsGeneratedContent has been cleared
  3801   // on aItem.
  3802   if ((!aState.mCreatingExtraFrames ||
  3803        ((primaryFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) &&
  3804         !aItem.mContent->GetPrimaryFrame())) &&
  3805        !(bits & FCDATA_SKIP_FRAMESET)) {
  3806     aItem.mContent->SetPrimaryFrame(primaryFrame);
  3810 // after the node has been constructed and initialized create any
  3811 // anonymous content a node needs.
  3812 nsresult
  3813 nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
  3814                                              nsIContent*              aParent,
  3815                                              nsIFrame*                aParentFrame,
  3816                                              PendingBinding*          aPendingBinding,
  3817                                              nsFrameItems&            aChildItems)
  3819   nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> newAnonymousItems;
  3820   nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems);
  3821   NS_ENSURE_SUCCESS(rv, rv);
  3823   uint32_t count = newAnonymousItems.Length();
  3824   if (count == 0) {
  3825     return NS_OK;
  3828   nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
  3829                                                            aPendingBinding);
  3830   TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
  3831   if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
  3832     ancestorPusher.PushAncestorAndStyleScope(aParent->AsElement());
  3833   } else {
  3834     ancestorPusher.PushStyleScope(aParent->AsElement());
  3837   nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
  3838   NS_ASSERTION(creator,
  3839                "How can that happen if we have nodes to construct frames for?");
  3841   for (uint32_t i=0; i < count; i++) {
  3842     nsIContent* content = newAnonymousItems[i].mContent;
  3843     NS_ASSERTION(content, "null anonymous content?");
  3844     NS_ASSERTION(!newAnonymousItems[i].mStyleContext, "Unexpected style context");
  3845     NS_ASSERTION(newAnonymousItems[i].mChildren.IsEmpty(),
  3846                  "This method is not currently used with frames that implement "
  3847                  "nsIAnonymousContentCreator::CreateAnonymousContent to "
  3848                  "output a list where the items have their own children");
  3850     nsIFrame* newFrame = creator->CreateFrameFor(content);
  3851     if (newFrame) {
  3852       NS_ASSERTION(content->GetPrimaryFrame(),
  3853                    "Content must have a primary frame now");
  3854       newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
  3855       aChildItems.AddChild(newFrame);
  3856     } else {
  3857       FrameConstructionItemList items;
  3859         // Skip flex item style-fixup during our AddFrameConstructionItems() call:
  3860         TreeMatchContext::AutoFlexItemStyleFixupSkipper
  3861           flexItemStyleFixupSkipper(aState.mTreeMatchContext);
  3863         AddFrameConstructionItems(aState, content, true, aParentFrame, items);
  3865       ConstructFramesFromItemList(aState, items, aParentFrame, aChildItems);
  3869   return NS_OK;
  3872 static void
  3873 SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet)
  3875 #ifdef DEBUG
  3876   // Make sure that the node passed to us doesn't have any XBL children
  3878     FlattenedChildIterator iter(aNode);
  3879     NS_ASSERTION(!iter.XBLInvolved() || !iter.GetNextChild(),
  3880                  "The node should not have any XBL children");
  3882 #endif
  3884   // Set the flag on the node itself
  3885   aNode->SetFlags(aFlagsToSet);
  3887   // Set the flag on all of its children recursively
  3888   uint32_t count;
  3889   nsIContent * const *children = aNode->GetChildArray(&count);
  3891   for (uint32_t index = 0; index < count; ++index) {
  3892     SetFlagsOnSubtree(children[index], aFlagsToSet);
  3896 /**
  3897  * This function takes a tree of nsIAnonymousContentCreator::ContentInfo
  3898  * objects where the nsIContent nodes have just been created, and appends the
  3899  * nsIContent children in the tree to their parent. The leaf nsIContent objects
  3900  * are appended first to minimize the number of notifications that are sent
  3901  * out (i.e. by appending as many descendants as posible while their parent is
  3902  * not yet in the document tree).
  3904  * This function is used simply as a convenience so that implementations of
  3905  * nsIAnonymousContentCreator::CreateAnonymousContent don't all have to have
  3906  * their own code to connect the elements that they create.
  3907  */
  3908 static void
  3909 ConnectAnonymousTreeDescendants(nsIContent* aParent,
  3910                                 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
  3912   uint32_t count = aContent.Length();
  3913   for (uint32_t i=0; i < count; i++) {
  3914     nsIContent* content = aContent[i].mContent;
  3915     NS_ASSERTION(content, "null anonymous content?");
  3917     ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
  3919     aParent->AppendChildTo(content, false);
  3923 nsresult
  3924 nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
  3925                                            nsIFrame* aParentFrame,
  3926                                            nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
  3928   nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
  3929   if (!creator)
  3930     return NS_OK;
  3932   nsresult rv = creator->CreateAnonymousContent(aContent);
  3933   NS_ENSURE_SUCCESS(rv, rv);
  3935   uint32_t count = aContent.Length();
  3936   for (uint32_t i=0; i < count; i++) {
  3937     // get our child's content and set its parent to our content
  3938     nsIContent* content = aContent[i].mContent;
  3939     NS_ASSERTION(content, "null anonymous content?");
  3941     // least-surprise CSS binding until we do the SVG specified
  3942     // cascading rules for <svg:use> - bug 265894
  3943     if (aParentFrame->GetType() == nsGkAtoms::svgUseFrame) {
  3944       content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
  3945     } else {
  3946       content->SetIsNativeAnonymousRoot();
  3949     ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
  3951     bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
  3952     rv = content->BindToTree(mDocument, aParent, aParent, true);
  3953     // If the anonymous content creator requested that the content should be
  3954     // editable, honor its request.
  3955     // We need to set the flag on the whole subtree, because existing
  3956     // children's flags have already been set as part of the BindToTree operation.
  3957     if (anonContentIsEditable) {
  3958       NS_ASSERTION(aParentFrame->GetType() == nsGkAtoms::textInputFrame,
  3959                    "We only expect this for anonymous content under a text control frame");
  3960       SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
  3962     if (NS_FAILED(rv)) {
  3963       content->UnbindFromTree();
  3964       return rv;
  3968   return NS_OK;
  3971 static
  3972 bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
  3974   return (aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX ||
  3975 #ifdef MOZ_XUL
  3976           aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_XUL_GRID ||
  3977           aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_STACK ||
  3978 #endif
  3979           aDisplay->mDisplay == NS_STYLE_DISPLAY_BOX
  3980 #ifdef MOZ_XUL
  3981           || aDisplay->mDisplay == NS_STYLE_DISPLAY_XUL_GRID ||
  3982           aDisplay->mDisplay == NS_STYLE_DISPLAY_STACK ||
  3983           aDisplay->mDisplay == NS_STYLE_DISPLAY_XUL_GRID_GROUP ||
  3984           aDisplay->mDisplay == NS_STYLE_DISPLAY_XUL_GRID_LINE ||
  3985           aDisplay->mDisplay == NS_STYLE_DISPLAY_DECK ||
  3986           aDisplay->mDisplay == NS_STYLE_DISPLAY_POPUP ||
  3987           aDisplay->mDisplay == NS_STYLE_DISPLAY_GROUPBOX
  3988 #endif
  3989           );
  3993 // XUL frames are not allowed to be out of flow.
  3994 #define SIMPLE_XUL_FCDATA(_func)                                        \
  3995   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH,    \
  3996               _func)
  3997 #define SCROLLABLE_XUL_FCDATA(_func)                                    \
  3998   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |   \
  3999               FCDATA_MAY_NEED_SCROLLFRAME, _func)
  4000 // .. but we allow some XUL frames to be _containers_ for out-of-flow content
  4001 // (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
  4002 #define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func)                   \
  4003   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                             \
  4004               FCDATA_MAY_NEED_SCROLLFRAME, _func)
  4006 #define SIMPLE_XUL_CREATE(_tag, _func)            \
  4007   { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
  4008 #define SCROLLABLE_XUL_CREATE(_tag, _func)            \
  4009   { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
  4010 #define SIMPLE_XUL_INT_CREATE(_int, _func)      \
  4011   { _int, SIMPLE_XUL_FCDATA(_func) }
  4012 #define SCROLLABLE_XUL_INT_CREATE(_int, _func)                          \
  4013   { _int, SCROLLABLE_XUL_FCDATA(_func) }
  4014 #define SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(_int, _func)         \
  4015   { _int, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) }
  4017 static
  4018 nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
  4019                              nsStyleContext* aStyleContext)
  4021   nsCOMPtr<nsBoxLayout> layout;
  4022   NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
  4023   return NS_NewBoxFrame(aPresShell, aStyleContext, false, layout);
  4026 /* static */
  4027 const nsCSSFrameConstructor::FrameConstructionData*
  4028 nsCSSFrameConstructor::FindXULTagData(Element* aElement,
  4029                                       nsIAtom* aTag,
  4030                                       int32_t aNameSpaceID,
  4031                                       nsStyleContext* aStyleContext)
  4033   if (aNameSpaceID != kNameSpaceID_XUL) {
  4034     return nullptr;
  4037   static const FrameConstructionDataByTag sXULTagData[] = {
  4038 #ifdef MOZ_XUL
  4039     SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
  4040     SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
  4041     SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
  4042     SCROLLABLE_XUL_CREATE(autorepeatbutton, NS_NewAutoRepeatBoxFrame),
  4043     SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
  4044     SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
  4045     SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
  4046     SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
  4047     SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
  4048     SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
  4049     SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
  4050     SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
  4051     SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
  4052     SIMPLE_TAG_CHAIN(description, nsCSSFrameConstructor::FindXULDescriptionData),
  4053     SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
  4054     SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
  4055     SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
  4056 #ifdef XP_MACOSX
  4057     SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
  4058 #else
  4059     SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
  4060 #endif /* XP_MACOSX */
  4061     SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData),
  4062     SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
  4063     SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
  4064     SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame),
  4065     SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame),
  4066     SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame),
  4067     SIMPLE_TAG_CHAIN(listboxbody,
  4068                      nsCSSFrameConstructor::FindXULListBoxBodyData),
  4069     SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData),
  4070 #endif /* MOZ_XUL */
  4071     SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
  4072     SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
  4073     SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
  4074 };
  4076   return FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
  4077                        ArrayLength(sXULTagData));
  4080 #ifdef MOZ_XUL
  4081 /* static */
  4082 const nsCSSFrameConstructor::FrameConstructionData*
  4083 nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
  4084                                           nsStyleContext* /* unused */)
  4086   if (!aElement->IsRootOfNativeAnonymousSubtree()) {
  4087     return nullptr;
  4090   static const FrameConstructionData sPopupSetData =
  4091     SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
  4092   return &sPopupSetData;
  4095 /* static */
  4096 const nsCSSFrameConstructor::FrameConstructionData
  4097 nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
  4099 /* static */
  4100 const nsCSSFrameConstructor::FrameConstructionData*
  4101 nsCSSFrameConstructor::FindXULLabelData(Element* aElement,
  4102                                         nsStyleContext* /* unused */)
  4104   if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
  4105     return &sXULTextBoxData;
  4108   static const FrameConstructionData sLabelData =
  4109     SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
  4110   return &sLabelData;
  4113 static nsIFrame*
  4114 NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, nsStyleContext *aContext)
  4116   // XXXbz do we really need to set those flags?  If the parent is not
  4117   // a block we'll get them anyway, and if it is, do we want them?
  4118   return NS_NewBlockFrame(aPresShell, aContext,
  4119                           NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT);
  4122 /* static */
  4123 const nsCSSFrameConstructor::FrameConstructionData*
  4124 nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement,
  4125                                               nsStyleContext* /* unused */)
  4127   if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
  4128     return &sXULTextBoxData;
  4131   static const FrameConstructionData sDescriptionData =
  4132     SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame);
  4133   return &sDescriptionData;
  4136 #ifdef XP_MACOSX
  4137 /* static */
  4138 const nsCSSFrameConstructor::FrameConstructionData*
  4139 nsCSSFrameConstructor::FindXULMenubarData(Element* aElement,
  4140                                           nsStyleContext* aStyleContext)
  4142   nsCOMPtr<nsIDocShell> treeItem =
  4143     aStyleContext->PresContext()->GetDocShell();
  4144   if (treeItem && nsIDocShellTreeItem::typeChrome == treeItem->ItemType()) {
  4145     nsCOMPtr<nsIDocShellTreeItem> parent;
  4146     treeItem->GetParent(getter_AddRefs(parent));
  4147     if (!parent) {
  4148       // This is the root.  Suppress the menubar, since on Mac
  4149       // window menus are not attached to the window.
  4150       static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
  4151       return &sSuppressData;
  4155   static const FrameConstructionData sMenubarData =
  4156     SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
  4157   return &sMenubarData;
  4159 #endif /* XP_MACOSX */
  4161 /* static */
  4162 const nsCSSFrameConstructor::FrameConstructionData*
  4163 nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
  4164                                               nsStyleContext* aStyleContext)
  4166   if (aStyleContext->StyleDisplay()->mDisplay !=
  4167         NS_STYLE_DISPLAY_XUL_GRID_GROUP) {
  4168     return nullptr;
  4171   static const FrameConstructionData sListBoxBodyData =
  4172     SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame);
  4173   return &sListBoxBodyData;
  4176 /* static */
  4177 const nsCSSFrameConstructor::FrameConstructionData*
  4178 nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
  4179                                            nsStyleContext* aStyleContext)
  4181   if (aStyleContext->StyleDisplay()->mDisplay !=
  4182         NS_STYLE_DISPLAY_XUL_GRID_LINE) {
  4183     return nullptr;
  4186   static const FrameConstructionData sListItemData =
  4187     SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame);
  4188   return &sListItemData;
  4191 #endif /* MOZ_XUL */
  4193 /* static */
  4194 const nsCSSFrameConstructor::FrameConstructionData*
  4195 nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
  4196                                           Element* aElement,
  4197                                           nsStyleContext* aStyleContext)
  4199   static const FrameConstructionDataByInt sXULDisplayData[] = {
  4200     SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX,
  4201                                                NS_NewBoxFrame),
  4202     SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX,
  4203                                                NS_NewBoxFrame),
  4204 #ifdef MOZ_XUL
  4205     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_XUL_GRID, NS_NewGridBoxFrame),
  4206     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_XUL_GRID, NS_NewGridBoxFrame),
  4207     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_XUL_GRID_GROUP,
  4208                               NS_NewGridRowGroupFrame),
  4209     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_XUL_GRID_LINE,
  4210                               NS_NewGridRowLeafFrame),
  4211     SIMPLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_DECK, NS_NewDeckFrame),
  4212     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GROUPBOX, NS_NewGroupBoxFrame),
  4213     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_STACK, NS_NewStackFrame),
  4214     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_STACK, NS_NewStackFrame),
  4215     { NS_STYLE_DISPLAY_POPUP,
  4216       FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
  4217                   FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame) }
  4218 #endif /* MOZ_XUL */
  4219   };
  4221   // Processing by display here:
  4222   return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext,
  4223                        sXULDisplayData, ArrayLength(sXULDisplayData));
  4226 already_AddRefed<nsStyleContext>
  4227 nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
  4228                                                 nsIContent*              aContent,
  4229                                                 nsStyleContext*          aContentStyle,
  4230                                                 nsIFrame*                aParentFrame,
  4231                                                 nsIAtom*                 aScrolledPseudo,
  4232                                                 bool                     aIsRoot,
  4233                                                 nsIFrame*&               aNewFrame)
  4235   nsIFrame* gfxScrollFrame = aNewFrame;
  4237   nsFrameItems anonymousItems;
  4239   nsRefPtr<nsStyleContext> contentStyle = aContentStyle;
  4241   if (!gfxScrollFrame) {
  4242     // Build a XULScrollFrame when the child is a box, otherwise an
  4243     // HTMLScrollFrame
  4244     // XXXbz this is the lone remaining consumer of IsXULDisplayType.
  4245     // I wonder whether we can eliminate that somehow.
  4246     const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay();
  4247     if (IsXULDisplayType(displayStyle)) {
  4248       gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot,
  4249           displayStyle->mDisplay == NS_STYLE_DISPLAY_STACK ||
  4250           displayStyle->mDisplay == NS_STYLE_DISPLAY_INLINE_STACK);
  4251     } else {
  4252       gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
  4255     InitAndRestoreFrame(aState, aContent, aParentFrame, gfxScrollFrame);
  4258   // if there are any anonymous children for the scroll frame, create
  4259   // frames for them.
  4260   // Pass a null pending binding: we don't care how constructors for any of
  4261   // this anonymous content order with anything else.  It's never been
  4262   // consistent anyway.
  4263   CreateAnonymousFrames(aState, aContent, gfxScrollFrame, nullptr,
  4264                         anonymousItems);
  4266   aNewFrame = gfxScrollFrame;
  4268   // we used the style that was passed in. So resolve another one.
  4269   nsStyleSet *styleSet = mPresShell->StyleSet();
  4270   nsRefPtr<nsStyleContext> scrolledChildStyle =
  4271     styleSet->ResolveAnonymousBoxStyle(aScrolledPseudo, contentStyle);
  4273   if (gfxScrollFrame) {
  4274      gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems);
  4277   return scrolledChildStyle.forget();
  4280 void
  4281 nsCSSFrameConstructor::FinishBuildingScrollFrame(nsIFrame* aScrollFrame,
  4282                                                  nsIFrame* aScrolledFrame)
  4284   nsFrameList scrolled(aScrolledFrame, aScrolledFrame);
  4285   aScrollFrame->AppendFrames(kPrincipalList, scrolled);
  4289 /**
  4290  * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
  4292  * ------- for gfx scrollbars ------
  4295  *            ScrollFrame
  4296  *                 ^
  4297  *                 |
  4298  *               Frame (scrolled frame you passed in)
  4301  *-----------------------------------
  4302  * LEGEND:
  4304  * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
  4306  * @param aContent the content node of the child to wrap.
  4307  * @param aScrolledFrame The frame of the content to wrap. This should not be
  4308  *                    Initialized. This method will initialize it with a scrolled pseudo
  4309  *                    and no nsIContent. The content will be attached to the scrollframe
  4310  *                    returned.
  4311  * @param aContentStyle the style context that has already been resolved for the content being passed in.
  4313  * @param aParentFrame The parent to attach the scroll frame to
  4315  * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
  4316  *                  scrolled frame you passed in. (returned)
  4317  *                  If this is not null, we'll just use it
  4318  * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
  4319  */
  4320 nsresult
  4321 nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
  4322                                         nsIContent*              aContent,
  4323                                         nsStyleContext*          aContentStyle,
  4324                                         nsIFrame*                aScrolledFrame,
  4325                                         nsIFrame*                aParentFrame,
  4326                                         nsIFrame*&               aNewFrame)
  4328     nsRefPtr<nsStyleContext> scrolledContentStyle =
  4329       BeginBuildingScrollFrame(aState, aContent, aContentStyle, aParentFrame,
  4330                                nsCSSAnonBoxes::scrolledContent,
  4331                                false, aNewFrame);
  4333     aScrolledFrame->SetStyleContextWithoutNotification(scrolledContentStyle);
  4334     InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
  4336     FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
  4337     return NS_OK;
  4340 const nsCSSFrameConstructor::FrameConstructionData*
  4341 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
  4342                                        Element* aElement,
  4343                                        nsIFrame* aParentFrame,
  4344                                        nsStyleContext* aStyleContext)
  4346   PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)));
  4348   // The style system ensures that floated and positioned frames are
  4349   // block-level.
  4350   NS_ASSERTION(!(aDisplay->IsFloatingStyle() ||
  4351                  aDisplay->IsAbsolutelyPositionedStyle()) ||
  4352                aDisplay->IsBlockOutsideStyle(),
  4353                "Style system did not apply CSS2.1 section 9.7 fixups");
  4355   // If this is "body", try propagating its scroll style to the viewport
  4356   // Note that we need to do this even if the body is NOT scrollable;
  4357   // it might have dynamically changed from scrollable to not scrollable,
  4358   // and that might need to be propagated.
  4359   // XXXbz is this the right place to do this?  If this code moves,
  4360   // make this function static.
  4361   bool propagatedScrollToViewport = false;
  4362   if (aElement->IsHTML(nsGkAtoms::body)) {
  4363     propagatedScrollToViewport =
  4364       PropagateScrollToViewport() == aElement;
  4367   NS_ASSERTION(!propagatedScrollToViewport ||
  4368                !mPresShell->GetPresContext()->IsPaginated(),
  4369                "Shouldn't propagate scroll in paginated contexts");
  4371   // If the frame is a block-level frame and is scrollable, then wrap it in a
  4372   // scroll frame.
  4373   // XXX Ignore tables for the time being
  4374   // XXXbz it would be nice to combine this with the other block
  4375   // case... Think about how do do this?
  4376   if (aDisplay->IsBlockInsideStyle() &&
  4377       aDisplay->IsScrollableOverflow() &&
  4378       !propagatedScrollToViewport) {
  4379     // Except we don't want to do that for paginated contexts for
  4380     // frames that are block-outside and aren't frames for native
  4381     // anonymous stuff.
  4382     if (mPresShell->GetPresContext()->IsPaginated() &&
  4383         aDisplay->IsBlockOutsideStyle() &&
  4384         !aElement->IsInNativeAnonymousSubtree()) {
  4385       static const FrameConstructionData sForcedNonScrollableBlockData =
  4386         FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
  4387                          &nsCSSFrameConstructor::ConstructNonScrollableBlock);
  4388       return &sForcedNonScrollableBlockData;
  4391     static const FrameConstructionData sScrollableBlockData =
  4392       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock);
  4393     return &sScrollableBlockData;
  4396   // Handle various non-scrollable blocks
  4397   if (aDisplay->IsBlockInsideStyle()) {
  4398     static const FrameConstructionData sNonScrollableBlockData =
  4399       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock);
  4400     return &sNonScrollableBlockData;
  4403   static const FrameConstructionDataByInt sDisplayData[] = {
  4404     // To keep the hash table small don't add inline frames (they're
  4405     // typically things like FONT and B), because we can quickly
  4406     // find them if we need to.
  4407     // XXXbz the "quickly" part is a bald-faced lie!
  4408     { NS_STYLE_DISPLAY_INLINE,
  4409       FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
  4410                        &nsCSSFrameConstructor::ConstructInline) },
  4411     { NS_STYLE_DISPLAY_FLEX,
  4412       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame) },
  4413     { NS_STYLE_DISPLAY_INLINE_FLEX,
  4414       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame) },
  4415     { NS_STYLE_DISPLAY_GRID,
  4416       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
  4417     { NS_STYLE_DISPLAY_INLINE_GRID,
  4418       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
  4419     { NS_STYLE_DISPLAY_TABLE,
  4420       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
  4421     { NS_STYLE_DISPLAY_INLINE_TABLE,
  4422       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
  4423     // NOTE: In the unlikely event that we add another table-part here that has
  4424     // a desired-parent-type (& hence triggers table fixup), we'll need to also
  4425     // update the flexbox chunk in nsStyleContext::ApplyStyleFixups().
  4426     { NS_STYLE_DISPLAY_TABLE_CAPTION,
  4427       FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_ALLOW_BLOCK_STYLES |
  4428                   FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
  4429                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  4430                   NS_NewTableCaptionFrame) },
  4431     { NS_STYLE_DISPLAY_TABLE_ROW_GROUP,
  4432       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
  4433                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  4434                        &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) },
  4435     { NS_STYLE_DISPLAY_TABLE_HEADER_GROUP,
  4436       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
  4437                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  4438                        &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) },
  4439     { NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP,
  4440       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
  4441                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  4442                        &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) },
  4443     { NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP,
  4444       FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
  4445                   FCDATA_SKIP_ABSPOS_PUSH |
  4446                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  4447                   NS_NewTableColGroupFrame) },
  4448     { NS_STYLE_DISPLAY_TABLE_COLUMN,
  4449       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
  4450                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup),
  4451                        &nsCSSFrameConstructor::ConstructTableCol) },
  4452     { NS_STYLE_DISPLAY_TABLE_ROW,
  4453       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
  4454                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
  4455                        &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) },
  4456     { NS_STYLE_DISPLAY_TABLE_CELL,
  4457       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
  4458                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
  4459                        &nsCSSFrameConstructor::ConstructTableCell) }
  4460   };
  4462   return FindDataByInt(aDisplay->mDisplay,
  4463                        aElement, aStyleContext, sDisplayData,
  4464                        ArrayLength(sDisplayData));
  4467 nsIFrame*
  4468 nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState,
  4469                                                 FrameConstructionItem&   aItem,
  4470                                                 nsIFrame*                aParentFrame,
  4471                                                 const nsStyleDisplay*    aDisplay,
  4472                                                 nsFrameItems&            aFrameItems)
  4474   nsIContent* const content = aItem.mContent;
  4475   nsStyleContext* const styleContext = aItem.mStyleContext;
  4477   nsIFrame* newFrame = nullptr;
  4478   nsRefPtr<nsStyleContext> scrolledContentStyle
  4479     = BeginBuildingScrollFrame(aState, content, styleContext,
  4480                                aState.GetGeometricParent(aDisplay, aParentFrame),
  4481                                nsCSSAnonBoxes::scrolledContent,
  4482                                false, newFrame);
  4484   // Create our block frame
  4485   // pass a temporary stylecontext, the correct one will be set later
  4486   nsIFrame* scrolledFrame =
  4487     NS_NewBlockFormattingContext(mPresShell, styleContext);
  4489   // Make sure to AddChild before we call ConstructBlock so that we
  4490   // end up before our descendants in fixed-pos lists as needed.
  4491   aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
  4493   nsFrameItems blockItem;
  4494   ConstructBlock(aState, scrolledContentStyle->StyleDisplay(), content,
  4495                  newFrame, newFrame, scrolledContentStyle,
  4496                  &scrolledFrame, blockItem,
  4497                  aDisplay->IsPositioned(newFrame) ? newFrame : nullptr,
  4498                  aItem.mPendingBinding);
  4500   NS_ASSERTION(blockItem.FirstChild() == scrolledFrame,
  4501                "Scrollframe's frameItems should be exactly the scrolled frame");
  4502   FinishBuildingScrollFrame(newFrame, scrolledFrame);
  4504   return newFrame;
  4507 nsIFrame*
  4508 nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState& aState,
  4509                                                    FrameConstructionItem&   aItem,
  4510                                                    nsIFrame*                aParentFrame,
  4511                                                    const nsStyleDisplay*    aDisplay,
  4512                                                    nsFrameItems&            aFrameItems)
  4514   nsStyleContext* const styleContext = aItem.mStyleContext;
  4516   // We want a block formatting context root in paginated contexts for
  4517   // every block that would be scrollable in a non-paginated context.
  4518   // We mark our blocks with a bit here if this condition is true, so
  4519   // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
  4520   bool clipPaginatedOverflow =
  4521     (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
  4522   nsIFrame* newFrame;
  4523   if ((aDisplay->IsAbsolutelyPositionedStyle() ||
  4524        aDisplay->IsFloatingStyle() ||
  4525        NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay ||
  4526        clipPaginatedOverflow) &&
  4527       !aParentFrame->IsSVGText()) {
  4528     newFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
  4529     if (clipPaginatedOverflow) {
  4530       newFrame->AddStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW);
  4532   } else {
  4533     newFrame = NS_NewBlockFrame(mPresShell, styleContext);
  4536   ConstructBlock(aState, aDisplay, aItem.mContent,
  4537                  aState.GetGeometricParent(aDisplay, aParentFrame),
  4538                  aParentFrame, styleContext, &newFrame,
  4539                  aFrameItems,
  4540                  aDisplay->IsPositioned(newFrame) ? newFrame : nullptr,
  4541                  aItem.mPendingBinding);
  4542   return newFrame;
  4546 void
  4547 nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
  4548                                            nsIContent*              aContent,
  4549                                            nsIFrame*                aParentFrame,
  4550                                            nsIFrame*                aNewFrame,
  4551                                            bool                     aAllowCounters)
  4553   NS_PRECONDITION(mUpdateCount != 0,
  4554                   "Should be in an update while creating frames");
  4556   MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized");
  4558   // Initialize the frame
  4559   aNewFrame->Init(aContent, aParentFrame, nullptr);
  4560   aNewFrame->AddStateBits(aState.mAdditionalStateBits);
  4562   if (aState.mFrameState) {
  4563     // Restore frame state for just the newly created frame.
  4564     RestoreFrameStateFor(aNewFrame, aState.mFrameState);
  4567   if (aAllowCounters &&
  4568       mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
  4569     CountersDirty();
  4573 already_AddRefed<nsStyleContext>
  4574 nsCSSFrameConstructor::ResolveStyleContext(nsIFrame*         aParentFrame,
  4575                                            nsIContent*       aContent,
  4576                                            nsFrameConstructorState* aState)
  4578   nsStyleContext* parentStyleContext = nullptr;
  4579   NS_ASSERTION(aContent->GetParent(), "Must have parent here");
  4581   aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nullptr);
  4583   if (aParentFrame) {
  4584     // Resolve the style context based on the content object and the parent
  4585     // style context
  4586     parentStyleContext = aParentFrame->StyleContext();
  4587   } else {
  4588     // Perhaps aParentFrame is a canvasFrame and we're replicating
  4589     // fixed-pos frames.
  4590     // XXX should we create a way to tell ConstructFrame which style
  4591     // context to use, and pass it the style context for the
  4592     // previous page's fixed-pos frame?
  4595   return ResolveStyleContext(parentStyleContext, aContent, aState);
  4598 already_AddRefed<nsStyleContext>
  4599 nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
  4600                                            nsIContent* aContent,
  4601                                            nsFrameConstructorState* aState)
  4603   nsStyleSet *styleSet = mPresShell->StyleSet();
  4604   aContent->OwnerDoc()->FlushPendingLinkUpdates();
  4606   if (aContent->IsElement()) {
  4607     if (aState) {
  4608       return styleSet->ResolveStyleFor(aContent->AsElement(),
  4609                                        aParentStyleContext,
  4610                                        aState->mTreeMatchContext);
  4612     return styleSet->ResolveStyleFor(aContent->AsElement(), aParentStyleContext);
  4616   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
  4617                "shouldn't waste time creating style contexts for "
  4618                "comments and processing instructions");
  4620   return styleSet->ResolveStyleForNonElement(aParentStyleContext);
  4623 // MathML Mod - RBS
  4624 void
  4625 nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
  4626                                              nsIContent* aContent,
  4627                                              nsIFrame* aParentFrame,
  4628                                              nsFrameItems& aBlockItems,
  4629                                              nsFrameItems& aNewItems)
  4631   if (aBlockItems.IsEmpty()) {
  4632     // Nothing to do
  4633     return;
  4636   nsIAtom* anonPseudo = nsCSSAnonBoxes::mozMathMLAnonymousBlock;
  4638   nsStyleContext* parentContext =
  4639     nsFrame::CorrectStyleParentFrame(aParentFrame,
  4640                                      anonPseudo)->StyleContext();
  4641   nsStyleSet* styleSet = mPresShell->StyleSet();
  4642   nsRefPtr<nsStyleContext> blockContext;
  4643   blockContext = styleSet->
  4644     ResolveAnonymousBoxStyle(anonPseudo, parentContext);
  4647   // then, create a block frame that will wrap the child frames. Make it a
  4648   // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
  4649   // is not a suitable block.
  4650   nsIFrame* blockFrame =
  4651       NS_NewMathMLmathBlockFrame(mPresShell, blockContext,
  4652                                  NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT);
  4654   InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
  4655   ReparentFrames(this, blockFrame, aBlockItems);
  4656   // abs-pos and floats are disabled in MathML children so we don't have to
  4657   // worry about messing up those.
  4658   blockFrame->SetInitialChildList(kPrincipalList, aBlockItems);
  4659   NS_ASSERTION(aBlockItems.IsEmpty(), "What happened?");
  4660   aBlockItems.Clear();
  4661   aNewItems.AddChild(blockFrame);
  4664 // Only <math> elements can be floated or positioned.  All other MathML
  4665 // should be in-flow.
  4666 #define SIMPLE_MATHML_CREATE(_tag, _func)                               \
  4667   { &nsGkAtoms::_tag,                                                   \
  4668       FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                         \
  4669                   FCDATA_FORCE_NULL_ABSPOS_CONTAINER |                  \
  4670                   FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
  4672 /* static */
  4673 const nsCSSFrameConstructor::FrameConstructionData*
  4674 nsCSSFrameConstructor::FindMathMLData(Element* aElement,
  4675                                       nsIAtom* aTag,
  4676                                       int32_t aNameSpaceID,
  4677                                       nsStyleContext* aStyleContext)
  4679   // Make sure that we remain confined in the MathML world
  4680   if (aNameSpaceID != kNameSpaceID_MathML)
  4681     return nullptr;
  4683   // Handle <math> specially, because it sometimes produces inlines
  4684   if (aTag == nsGkAtoms::math) {
  4685     // This needs to match the test in EnsureBlockDisplay in
  4686     // nsRuleNode.cpp.  Though the behavior here for the display:table
  4687     // case is pretty weird...
  4688     if (aStyleContext->StyleDisplay()->IsBlockOutsideStyle()) {
  4689       static const FrameConstructionData sBlockMathData =
  4690         FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
  4691                     FCDATA_WRAP_KIDS_IN_BLOCKS,
  4692                     NS_CreateNewMathMLmathBlockFrame);
  4693       return &sBlockMathData;
  4696     static const FrameConstructionData sInlineMathData =
  4697       FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
  4698                   FCDATA_IS_LINE_PARTICIPANT |
  4699                   FCDATA_WRAP_KIDS_IN_BLOCKS,
  4700                   NS_NewMathMLmathInlineFrame);
  4701     return &sInlineMathData;
  4705   static const FrameConstructionDataByTag sMathMLData[] = {
  4706     SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame),
  4707     SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame),
  4708     SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
  4709     SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
  4710     SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
  4711     SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
  4712     SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
  4713     SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
  4714     SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame),
  4715     SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame),
  4716     SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame),
  4717     SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
  4718     SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
  4719     SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
  4720     SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmphantomFrame),
  4721     SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
  4722     SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
  4723     SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
  4724     SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
  4725     SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame),
  4726     SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame),
  4727     SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmrowFrame),
  4728     SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame),
  4729     SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame),
  4730     SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame),
  4731     SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame),
  4732     SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame),
  4733     SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame),
  4734     SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)
  4735   };
  4737   return FindDataByTag(aTag, aElement, aStyleContext, sMathMLData,
  4738                        ArrayLength(sMathMLData));
  4742 nsIFrame*
  4743 nsCSSFrameConstructor::ConstructFrameWithAnonymousChild(
  4744                                    nsFrameConstructorState& aState,
  4745                                    FrameConstructionItem&   aItem,
  4746                                    nsIFrame*                aParentFrame,
  4747                                    const nsStyleDisplay*    aDisplay,
  4748                                    nsFrameItems&            aFrameItems,
  4749                                    FrameCreationFunc        aConstructor,
  4750                                    FrameCreationFunc        aInnerConstructor,
  4751                                    nsICSSAnonBoxPseudo*     aInnerPseudo,
  4752                                    bool                     aCandidateRootFrame)
  4754   nsIContent* const content = aItem.mContent;
  4755   nsStyleContext* const styleContext = aItem.mStyleContext;
  4757   // Create the outer frame:
  4758   nsIFrame* newFrame = aConstructor(mPresShell, styleContext);
  4760   InitAndRestoreFrame(aState, content,
  4761                       aCandidateRootFrame ?
  4762                         aState.GetGeometricParent(styleContext->StyleDisplay(),
  4763                                                   aParentFrame) :
  4764                         aParentFrame,
  4765                       newFrame);
  4767   // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
  4768   nsRefPtr<nsStyleContext> scForAnon;
  4769   scForAnon = mPresShell->StyleSet()->
  4770     ResolveAnonymousBoxStyle(aInnerPseudo, styleContext);
  4772   // Create the anonymous inner wrapper frame
  4773   nsIFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
  4775   InitAndRestoreFrame(aState, content, newFrame, innerFrame);
  4777   // Put the newly created frames into the right child list
  4778   SetInitialSingleChild(newFrame, innerFrame);
  4780   aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame,
  4781                   aCandidateRootFrame, aCandidateRootFrame);
  4783   if (!mRootElementFrame && aCandidateRootFrame) {
  4784     // The frame we're constructing will be the root element frame.
  4785     // Set mRootElementFrame before processing children.
  4786     mRootElementFrame = newFrame;
  4789   nsFrameItems childItems;
  4791   // Process children
  4792   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
  4793                "nsIAnonymousContentCreator::CreateAnonymousContent should not "
  4794                "be implemented for frames for which we explicitly create an "
  4795                "anonymous child to wrap its child frames");
  4796   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
  4797     ConstructFramesFromItemList(aState, aItem.mChildItems,
  4798                                 innerFrame, childItems);
  4799   } else {
  4800     ProcessChildren(aState, content, styleContext, innerFrame,
  4801                     true, childItems, false, aItem.mPendingBinding);
  4804   // Set the inner wrapper frame's initial primary list
  4805   innerFrame->SetInitialChildList(kPrincipalList, childItems);
  4807   return newFrame;
  4810 nsIFrame*
  4811 nsCSSFrameConstructor::ConstructOuterSVG(nsFrameConstructorState& aState,
  4812                                          FrameConstructionItem&   aItem,
  4813                                          nsIFrame*                aParentFrame,
  4814                                          const nsStyleDisplay*    aDisplay,
  4815                                          nsFrameItems&            aFrameItems)
  4817   return ConstructFrameWithAnonymousChild(
  4818       aState, aItem, aParentFrame, aDisplay, aFrameItems,
  4819       NS_NewSVGOuterSVGFrame, NS_NewSVGOuterSVGAnonChildFrame,
  4820       nsCSSAnonBoxes::mozSVGOuterSVGAnonChild, true);
  4823 nsIFrame*
  4824 nsCSSFrameConstructor::ConstructMarker(nsFrameConstructorState& aState,
  4825                                        FrameConstructionItem&   aItem,
  4826                                        nsIFrame*                aParentFrame,
  4827                                        const nsStyleDisplay*    aDisplay,
  4828                                        nsFrameItems&            aFrameItems)
  4830   return ConstructFrameWithAnonymousChild(
  4831       aState, aItem, aParentFrame, aDisplay, aFrameItems,
  4832       NS_NewSVGMarkerFrame, NS_NewSVGMarkerAnonChildFrame,
  4833       nsCSSAnonBoxes::mozSVGMarkerAnonChild, false);
  4836 // Only outer <svg> elements can be floated or positioned.  All other SVG
  4837 // should be in-flow.
  4838 #define SIMPLE_SVG_FCDATA(_func)                                        \
  4839   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                             \
  4840               FCDATA_SKIP_ABSPOS_PUSH |                                 \
  4841               FCDATA_DISALLOW_GENERATED_CONTENT,  _func)
  4842 #define SIMPLE_SVG_CREATE(_tag, _func)            \
  4843   { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
  4845 static bool
  4846 IsFilterPrimitiveChildTag(const nsIAtom* aTag)
  4848   return aTag == nsGkAtoms::feDistantLight ||
  4849          aTag == nsGkAtoms::fePointLight ||
  4850          aTag == nsGkAtoms::feSpotLight ||
  4851          aTag == nsGkAtoms::feFuncR ||
  4852          aTag == nsGkAtoms::feFuncG ||
  4853          aTag == nsGkAtoms::feFuncB ||
  4854          aTag == nsGkAtoms::feFuncA ||
  4855          aTag == nsGkAtoms::feMergeNode;
  4858 /* static */
  4859 const nsCSSFrameConstructor::FrameConstructionData*
  4860 nsCSSFrameConstructor::FindSVGData(Element* aElement,
  4861                                    nsIAtom* aTag,
  4862                                    int32_t aNameSpaceID,
  4863                                    nsIFrame* aParentFrame,
  4864                                    bool aIsWithinSVGText,
  4865                                    bool aAllowsTextPathChild,
  4866                                    nsStyleContext* aStyleContext)
  4868   if (aNameSpaceID != kNameSpaceID_SVG) {
  4869     return nullptr;
  4872   static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
  4873   static const FrameConstructionData sContainerData =
  4874     SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
  4876   bool parentIsSVG = aIsWithinSVGText;
  4877   nsIContent* parentContent =
  4878     aParentFrame ? aParentFrame->GetContent() : nullptr;
  4879   // XXXbz should this really be based on the XBL-resolved tag of the parent
  4880   // frame's content?  Should it not be based on the type of the parent frame
  4881   // (e.g. whether it's an SVG frame)?
  4882   if (parentContent) {
  4883     int32_t parentNSID;
  4884     nsIAtom* parentTag =
  4885       parentContent->OwnerDoc()->BindingManager()->
  4886         ResolveTag(parentContent, &parentNSID);
  4888     // It's not clear whether the SVG spec intends to allow any SVG
  4889     // content within svg:foreignObject at all (SVG 1.1, section
  4890     // 23.2), but if it does, it better be svg:svg.  So given that
  4891     // we're allowing it, treat it as a non-SVG parent.
  4892     parentIsSVG = parentNSID == kNameSpaceID_SVG &&
  4893                   parentTag != nsGkAtoms::foreignObject;
  4896   if ((aTag != nsGkAtoms::svg && !parentIsSVG) ||
  4897       (aTag == nsGkAtoms::desc || aTag == nsGkAtoms::title)) {
  4898     // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
  4899     // svg:svg not contained within svg:svg are incorrect, although they
  4900     // don't seem to specify error handling.  Ignore them, since many of
  4901     // our frame classes can't deal.  It *may* be that the document
  4902     // should at that point be considered in error according to F.2, but
  4903     // it's hard to tell.
  4904     //
  4905     // Style mutation can't change this situation, so don't bother
  4906     // adding to the undisplayed content map.
  4907     //
  4908     // We don't currently handle any UI for desc/title
  4909     return &sSuppressData;
  4912   // We don't need frames for animation elements
  4913   if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
  4914     return &sSuppressData;
  4917   if (aTag == nsGkAtoms::svg && !parentIsSVG) {
  4918     // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
  4919     // of whether they fail conditional processing attributes, since various
  4920     // SVG frames assume that one exists.  We handle the non-rendering
  4921     // of failing outer <svg> element contents like <switch> statements,
  4922     // and do the PassesConditionalProcessingTests call in
  4923     // nsSVGOuterSVGFrame::Init.
  4924     static const FrameConstructionData sOuterSVGData =
  4925       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
  4926     return &sOuterSVGData;
  4929   if (aTag == nsGkAtoms::marker) {
  4930     static const FrameConstructionData sMarkerSVGData =
  4931       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructMarker);
  4932     return &sMarkerSVGData;
  4935   nsCOMPtr<SVGTests> tests(do_QueryInterface(aElement));
  4936   if (tests && !tests->PassesConditionalProcessingTests()) {
  4937     // Elements with failing conditional processing attributes never get
  4938     // rendered.  Note that this is not where we select which frame in a
  4939     // <switch> to render!  That happens in nsSVGSwitchFrame::PaintSVG.
  4940     return &sContainerData;
  4943   // Prevent bad frame types being children of filters or parents of filter
  4944   // primitives.  If aParentFrame is null, we know that the frame that will
  4945   // be created will be an nsInlineFrame, so it can never be a filter.
  4946   bool parentIsFilter = aParentFrame &&
  4947     aParentFrame->GetType() == nsGkAtoms::svgFilterFrame;
  4948   bool filterPrimitive = aElement->IsNodeOfType(nsINode::eFILTER);
  4949   if ((parentIsFilter && !filterPrimitive) ||
  4950       (!parentIsFilter && filterPrimitive)) {
  4951     return &sSuppressData;
  4954   // Prevent bad frame types being children of filter primitives or parents of
  4955   // filter primitive children.  If aParentFrame is null, we know that the frame
  4956   // that will be created will be an nsInlineFrame, so it can never be a filter
  4957   // primitive.
  4958   bool parentIsFEContainerFrame = aParentFrame &&
  4959     aParentFrame->GetType() == nsGkAtoms::svgFEContainerFrame;
  4960   if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(aTag)) ||
  4961       (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(aTag))) {
  4962     return &sSuppressData;
  4965   // Special cases for text/tspan/textPath, because the kind of frame
  4966   // they get depends on the parent frame.  We ignore 'a' elements when
  4967   // determining the parent, however.
  4968   if (aIsWithinSVGText) {
  4969     // If aIsWithinSVGText is true, then we know that the "SVG text uses
  4970     // CSS frames" pref was true when this SVG fragment was first constructed.
  4972     // We don't use ConstructInline because we want different behavior
  4973     // for generated content.
  4974     static const FrameConstructionData sTSpanData =
  4975       FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |
  4976                   FCDATA_SKIP_ABSPOS_PUSH |
  4977                   FCDATA_DISALLOW_GENERATED_CONTENT |
  4978                   FCDATA_IS_LINE_PARTICIPANT |
  4979                   FCDATA_IS_INLINE |
  4980                   FCDATA_USE_CHILD_ITEMS,
  4981                   NS_NewInlineFrame);
  4982     if (aTag == nsGkAtoms::textPath) {
  4983       if (aAllowsTextPathChild) {
  4984         return &sTSpanData;
  4986     } else if (aTag == nsGkAtoms::tspan ||
  4987                aTag == nsGkAtoms::altGlyph ||
  4988                aTag == nsGkAtoms::a) {
  4989       return &sTSpanData;
  4991     return &sSuppressData;
  4992   } else if (aTag == nsGkAtoms::text) {
  4993     static const FrameConstructionData sTextData =
  4994       FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW |
  4995                                  FCDATA_ALLOW_BLOCK_STYLES,
  4996                                  NS_NewSVGTextFrame,
  4997                                  nsCSSAnonBoxes::mozSVGText);
  4998     return &sTextData;
  4999   } else if (aTag == nsGkAtoms::tspan ||
  5000              aTag == nsGkAtoms::altGlyph ||
  5001              aTag == nsGkAtoms::textPath) {
  5002     return &sSuppressData;
  5005   static const FrameConstructionDataByTag sSVGData[] = {
  5006     SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
  5007     SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
  5008     SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
  5009     SIMPLE_SVG_CREATE(polygon, NS_NewSVGPathGeometryFrame),
  5010     SIMPLE_SVG_CREATE(polyline, NS_NewSVGPathGeometryFrame),
  5011     SIMPLE_SVG_CREATE(circle, NS_NewSVGPathGeometryFrame),
  5012     SIMPLE_SVG_CREATE(ellipse, NS_NewSVGPathGeometryFrame),
  5013     SIMPLE_SVG_CREATE(line, NS_NewSVGPathGeometryFrame),
  5014     SIMPLE_SVG_CREATE(rect, NS_NewSVGPathGeometryFrame),
  5015     SIMPLE_SVG_CREATE(path, NS_NewSVGPathGeometryFrame),
  5016     SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
  5017     SIMPLE_SVG_CREATE(generic_, NS_NewSVGGenericContainerFrame),
  5018     { &nsGkAtoms::foreignObject,
  5019       FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW,
  5020                                  NS_NewSVGForeignObjectFrame,
  5021                                  nsCSSAnonBoxes::mozSVGForeignContent) },
  5022     SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
  5023     SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
  5024     SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
  5025     SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
  5026     SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
  5027     SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame),
  5028     SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
  5029     SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
  5030     SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
  5031     SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
  5032     SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
  5033     SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
  5034     SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
  5035     SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
  5036     SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
  5037     SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
  5038     SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
  5039     SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
  5040     SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
  5041     SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
  5042     SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
  5043     SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
  5044     SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
  5045     SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
  5046     SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
  5047     SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
  5048     SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
  5049     SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
  5050     SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
  5051     SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
  5052     SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
  5053     SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
  5054     SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
  5055     SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
  5056     SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
  5057     SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)
  5058   };
  5060   const FrameConstructionData* data =
  5061     FindDataByTag(aTag, aElement, aStyleContext, sSVGData,
  5062                   ArrayLength(sSVGData));
  5064   if (!data) {
  5065     data = &sContainerData;
  5068   return data;
  5071 void
  5072 nsCSSFrameConstructor::AddPageBreakItem(nsIContent* aContent,
  5073                                         nsStyleContext* aMainStyleContext,
  5074                                         FrameConstructionItemList& aItems)
  5076   // Use the same parent style context that |aMainStyleContext| has, since
  5077   // that's easier to re-resolve and it doesn't matter in practice.
  5078   // (Getting different parents can result in framechange hints, e.g.,
  5079   // for user-modify.)
  5080   nsRefPtr<nsStyleContext> pseudoStyle =
  5081     mPresShell->StyleSet()->
  5082       ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak,
  5083                                aMainStyleContext->GetParent());
  5085   NS_ASSERTION(pseudoStyle->StyleDisplay()->mDisplay ==
  5086                  NS_STYLE_DISPLAY_BLOCK, "Unexpected display");
  5088   static const FrameConstructionData sPageBreakData =
  5089     FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
  5091   // Lie about the tag and namespace so we don't trigger anything
  5092   // interesting during frame construction.
  5093   aItems.AppendItem(&sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
  5094                     kNameSpaceID_None, nullptr, pseudoStyle.forget(),
  5095                     true, nullptr);
  5098 void
  5099 nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState,
  5100                                                  nsIContent* aContent,
  5101                                                  bool aSuppressWhiteSpaceOptimizations,
  5102                                                  nsIFrame* aParentFrame,
  5103                                                  FrameConstructionItemList& aItems)
  5105   aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
  5106   if (aContent->IsElement()) {
  5107     // We can't just remove our pending restyle flags, since we may
  5108     // have restyle-later-siblings set on us.  But we _can_ remove the
  5109     // "is possible restyle root" flags, and need to.  Otherwise we can
  5110     // end up with stale such flags (e.g. if we used to have a
  5111     // display:none parent when our last restyle was posted and
  5112     // processed and now no longer do).
  5113     aContent->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS &
  5114                          ~ELEMENT_PENDING_RESTYLE_FLAGS);
  5117   // XXX the GetContent() != aContent check is needed due to bug 135040.
  5118   // Remove it once that's fixed.
  5119   if (aContent->GetPrimaryFrame() &&
  5120       aContent->GetPrimaryFrame()->GetContent() == aContent &&
  5121       !aState.mCreatingExtraFrames) {
  5122     NS_ERROR("asked to create frame construction item for a node that already "
  5123              "has a frame");
  5124     return;
  5127   // don't create a whitespace frame if aParent doesn't want it
  5128   if (!NeedFrameFor(aState, aParentFrame, aContent)) {
  5129     return;
  5132   // never create frames for comments or PIs
  5133   if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
  5134       aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION))
  5135     return;
  5137   nsRefPtr<nsStyleContext> styleContext;
  5138   styleContext = ResolveStyleContext(aParentFrame, aContent, &aState);
  5140   uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
  5141   if (aParentFrame->IsSVGText()) {
  5142     flags |= ITEM_IS_WITHIN_SVG_TEXT;
  5144   if (aParentFrame->GetType() == nsGkAtoms::blockFrame &&
  5145       aParentFrame->GetParent() &&
  5146       aParentFrame->GetParent()->GetType() == nsGkAtoms::svgTextFrame) {
  5147     flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
  5149   AddFrameConstructionItemsInternal(aState, aContent, aParentFrame,
  5150                                     aContent->Tag(), aContent->GetNameSpaceID(),
  5151                                     aSuppressWhiteSpaceOptimizations,
  5152                                     styleContext,
  5153                                     flags, nullptr,
  5154                                     aItems);
  5157 /* static */ void
  5158 nsCSSFrameConstructor::SetAsUndisplayedContent(FrameConstructionItemList& aList,
  5159                                                nsIContent* aContent,
  5160                                                nsStyleContext* aStyleContext,
  5161                                                bool aIsGeneratedContent)
  5163   if (aStyleContext->GetPseudo()) {
  5164     if (aIsGeneratedContent) {
  5165       aContent->UnbindFromTree();
  5167     return;
  5170   NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
  5171   aList.AppendUndisplayedItem(aContent, aStyleContext);
  5174 void
  5175 nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
  5176                                                          nsIContent* aContent,
  5177                                                          nsIFrame* aParentFrame,
  5178                                                          nsIAtom* aTag,
  5179                                                          int32_t aNameSpaceID,
  5180                                                          bool aSuppressWhiteSpaceOptimizations,
  5181                                                          nsStyleContext* aStyleContext,
  5182                                                          uint32_t aFlags,
  5183                                                          nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
  5184                                                          FrameConstructionItemList& aItems)
  5186   NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT) ||
  5187                   aContent->IsElement(),
  5188                   "Shouldn't get anything else here!");
  5190   // The following code allows the user to specify the base tag
  5191   // of an element using XBL.  XUL and HTML objects (like boxes, menus, etc.)
  5192   // can then be extended arbitrarily.
  5193   const nsStyleDisplay* display = aStyleContext->StyleDisplay();
  5194   nsRefPtr<nsStyleContext> styleContext(aStyleContext);
  5195   PendingBinding* pendingBinding = nullptr;
  5196   if ((aFlags & ITEM_ALLOW_XBL_BASE) && display->mBinding)
  5198     // Ensure that our XBL bindings are installed.
  5200     nsXBLService* xblService = nsXBLService::GetInstance();
  5201     if (!xblService)
  5202       return;
  5204     bool resolveStyle;
  5206     nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
  5208     nsresult rv = xblService->LoadBindings(aContent, display->mBinding->GetURI(),
  5209                                            display->mBinding->mOriginPrincipal,
  5210                                            getter_AddRefs(newPendingBinding->mBinding),
  5211                                            &resolveStyle);
  5212     if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
  5213       return;
  5215     if (newPendingBinding->mBinding) {
  5216       pendingBinding = newPendingBinding;
  5217       // aState takes over owning newPendingBinding
  5218       aState.AddPendingBinding(newPendingBinding.forget());
  5221     if (resolveStyle) {
  5222       styleContext =
  5223         ResolveStyleContext(styleContext->GetParent(), aContent, &aState);
  5224       display = styleContext->StyleDisplay();
  5225       aStyleContext = styleContext;
  5228     aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID);
  5231   bool isGeneratedContent = ((aFlags & ITEM_IS_GENERATED_CONTENT) != 0);
  5233   // Pre-check for display "none" - if we find that, don't create
  5234   // any frame at all
  5235   if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
  5236     SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent);
  5237     return;
  5240   bool isText = !aContent->IsElement();
  5242   // never create frames for non-option/optgroup kids of <select> and
  5243   // non-option kids of <optgroup> inside a <select>.
  5244   // XXXbz it's not clear how this should best work with XBL.
  5245   nsIContent *parent = aContent->GetParent();
  5246   if (parent) {
  5247     // Check tag first, since that check will usually fail
  5248     nsIAtom* parentTag = parent->Tag();
  5249     if ((parentTag == nsGkAtoms::select || parentTag == nsGkAtoms::optgroup) &&
  5250         parent->IsHTML() &&
  5251         // <option> is ok no matter what
  5252         !aContent->IsHTML(nsGkAtoms::option) &&
  5253         // <optgroup> is OK in <select> but not in <optgroup>
  5254         (!aContent->IsHTML(nsGkAtoms::optgroup) ||
  5255          parentTag != nsGkAtoms::select) &&
  5256         // Allow native anonymous content no matter what
  5257         !aContent->IsRootOfNativeAnonymousSubtree()) {
  5258       // No frame for aContent
  5259       if (!isText) {
  5260         SetAsUndisplayedContent(aItems, aContent, styleContext,
  5261                                 isGeneratedContent);
  5263       return;
  5267   bool isPopup = false;
  5268   // Try to find frame construction data for this content
  5269   const FrameConstructionData* data;
  5270   if (isText) {
  5271     data = FindTextData(aParentFrame);
  5272     if (!data) {
  5273       // Nothing to do here; suppressed text inside SVG
  5274       return;
  5276   } else {
  5277     Element* element = aContent->AsElement();
  5279     // Don't create frames for non-SVG element children of SVG elements.
  5280     if (aNameSpaceID != kNameSpaceID_SVG &&
  5281         ((aParentFrame &&
  5282           IsFrameForSVG(aParentFrame) &&
  5283           !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) ||
  5284          (aFlags & ITEM_IS_WITHIN_SVG_TEXT))) {
  5285       SetAsUndisplayedContent(aItems, element, styleContext,
  5286                               isGeneratedContent);
  5287       return;
  5290     data = FindHTMLData(element, aTag, aNameSpaceID, aParentFrame,
  5291                         styleContext);
  5292     if (!data) {
  5293       data = FindXULTagData(element, aTag, aNameSpaceID, styleContext);
  5295     if (!data) {
  5296       data = FindMathMLData(element, aTag, aNameSpaceID, styleContext);
  5298     if (!data) {
  5299       data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
  5300                          aFlags & ITEM_IS_WITHIN_SVG_TEXT,
  5301                          aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
  5302                          styleContext);
  5305     // Now check for XUL display types
  5306     if (!data) {
  5307       data = FindXULDisplayData(display, element, styleContext);
  5310     // And general display types
  5311     if (!data) {
  5312       data = FindDisplayData(display, element, aParentFrame, styleContext);
  5315     NS_ASSERTION(data, "Should have frame construction data now");
  5317     if (data->mBits & FCDATA_SUPPRESS_FRAME) {
  5318       SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent);
  5319       return;
  5322 #ifdef MOZ_XUL
  5323     if ((data->mBits & FCDATA_IS_POPUP) &&
  5324         (!aParentFrame || // Parent is inline
  5325          aParentFrame->GetType() != nsGkAtoms::menuFrame)) {
  5326       if (!aState.mPopupItems.containingBlock &&
  5327           !aState.mHavePendingPopupgroup) {
  5328         SetAsUndisplayedContent(aItems, element, styleContext,
  5329                                 isGeneratedContent);
  5330         return;
  5333       isPopup = true;
  5335 #endif /* MOZ_XUL */
  5338   uint32_t bits = data->mBits;
  5340   // Inside colgroups, suppress everything except columns.
  5341   if (aParentFrame &&
  5342       aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame &&
  5343       (!(bits & FCDATA_IS_TABLE_PART) ||
  5344        display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) {
  5345     SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent);
  5346     return;
  5349   bool canHavePageBreak =
  5350     (aFlags & ITEM_ALLOW_PAGE_BREAK) &&
  5351     aState.mPresContext->IsPaginated() &&
  5352     !display->IsAbsolutelyPositionedStyle() &&
  5353     !(bits & FCDATA_IS_TABLE_PART) &&
  5354     !(bits & FCDATA_IS_SVG_TEXT);
  5356   if (canHavePageBreak && display->mBreakBefore) {
  5357     AddPageBreakItem(aContent, aStyleContext, aItems);
  5360   FrameConstructionItem* item =
  5361     aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
  5362                       pendingBinding, styleContext.forget(),
  5363                       aSuppressWhiteSpaceOptimizations, aAnonChildren);
  5364   if (!item) {
  5365     if (isGeneratedContent) {
  5366       aContent->UnbindFromTree();
  5368     return;
  5371   item->mIsText = isText;
  5372   item->mIsGeneratedContent = isGeneratedContent;
  5373   item->mIsAnonymousContentCreatorContent =
  5374     aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
  5375   if (isGeneratedContent) {
  5376     NS_ADDREF(item->mContent);
  5378   item->mIsRootPopupgroup =
  5379     aNameSpaceID == kNameSpaceID_XUL && aTag == nsGkAtoms::popupgroup &&
  5380     aContent->IsRootOfNativeAnonymousSubtree();
  5381   if (item->mIsRootPopupgroup) {
  5382     aState.mHavePendingPopupgroup = true;
  5384   item->mIsPopup = isPopup;
  5385   item->mIsForSVGAElement = aNameSpaceID == kNameSpaceID_SVG &&
  5386                             aTag == nsGkAtoms::a;
  5388   if (canHavePageBreak && display->mBreakAfter) {
  5389     AddPageBreakItem(aContent, aStyleContext, aItems);
  5392   if (bits & FCDATA_IS_INLINE) {
  5393     // To correctly set item->mIsAllInline we need to build up our child items
  5394     // right now.
  5395     BuildInlineChildItems(aState, *item,
  5396                           aFlags & ITEM_IS_WITHIN_SVG_TEXT,
  5397                           aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD);
  5398     item->mHasInlineEnds = true;
  5399     item->mIsBlock = false;
  5400   } else {
  5401     // Compute a boolean isInline which is guaranteed to be false for blocks
  5402     // (but may also be false for some inlines).
  5403     bool isInline =
  5404       // Table-internal things are inline-outside if and only if they're kids of
  5405       // inlines, since they'll trigger construction of inline-table
  5406       // pseudos.
  5407       ((bits & FCDATA_IS_TABLE_PART) &&
  5408        (!aParentFrame || // No aParentFrame means inline
  5409         aParentFrame->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE)) ||
  5410       // Things that are inline-outside but aren't inline frames are inline
  5411       display->IsInlineOutsideStyle() ||
  5412       // Popups that are certainly out of flow.
  5413       isPopup;
  5415     // Set mIsAllInline conservatively.  It just might be that even an inline
  5416     // that has mIsAllInline false doesn't need an {ib} split.  So this is just
  5417     // an optimization to keep from doing too much work in cases when we can
  5418     // show that mIsAllInline is true..
  5419     item->mIsAllInline = item->mHasInlineEnds = isInline ||
  5420       // Figure out whether we're guaranteed this item will be out of flow.
  5421       // This is not a precise test, since one of our ancestor inlines might add
  5422       // an absolute containing block (if it's relatively positioned) when there
  5423       // wasn't such a containing block before.  But it's conservative in the
  5424       // sense that anything that will really end up as an in-flow non-inline
  5425       // will test false here.  In other words, if this test is true we're
  5426       // guaranteed to be inline; if it's false we don't know what we'll end up
  5427       // as.
  5428       //
  5429       // If we make this test precise, we can remove some of the code dealing
  5430       // with the imprecision in ConstructInline and adjust the comments on
  5431       // mIsAllInline and mIsBlock in the header.  And probably remove mIsBlock
  5432       // altogether, since then it will always be equal to !mHasInlineEnds.
  5433       (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
  5434        aState.GetGeometricParent(display, nullptr));
  5436     // Set mIsBlock conservatively.  It's OK to set it false for some real
  5437     // blocks, but not OK to set it true for things that aren't blocks.  Since
  5438     // isOutOfFlow might be false even in cases when the frame will end up
  5439     // out-of-flow, we can't use it here.  But we _can_ say that the frame will
  5440     // for sure end up in-flow if it's not floated or absolutely positioned.
  5441     item->mIsBlock = !isInline &&
  5442                      !display->IsAbsolutelyPositionedStyle() &&
  5443                      !display->IsFloatingStyle() &&
  5444                      !(bits & FCDATA_IS_SVG_TEXT);
  5447   if (item->mIsAllInline) {
  5448     aItems.InlineItemAdded();
  5449   } else if (item->mIsBlock) {
  5450     aItems.BlockItemAdded();
  5453   // Our item should be treated as a line participant if we have the relevant
  5454   // bit and are going to be in-flow.  Note that this really only matters if
  5455   // our ancestor is a box or some such, so the fact that we might have an
  5456   // inline ancestor that might become a containing block is not relevant here.
  5457   if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
  5458       ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
  5459        !aState.GetGeometricParent(display, nullptr))) {
  5460     item->mIsLineParticipant = true;
  5461     aItems.LineParticipantItemAdded();
  5465 static void
  5466 DestroyContent(void* aPropertyValue)
  5468   nsIContent* content = static_cast<nsIContent*>(aPropertyValue);
  5469   content->UnbindFromTree();
  5470   NS_RELEASE(content);
  5473 NS_DECLARE_FRAME_PROPERTY(BeforeProperty, DestroyContent)
  5474 NS_DECLARE_FRAME_PROPERTY(AfterProperty, DestroyContent)
  5476 static const FramePropertyDescriptor*
  5477 GenConPseudoToProperty(nsIAtom* aPseudo)
  5479   NS_ASSERTION(aPseudo == nsCSSPseudoElements::before ||
  5480                aPseudo == nsCSSPseudoElements::after,
  5481                "Bad gen-con pseudo");
  5482   return aPseudo == nsCSSPseudoElements::before ? BeforeProperty()
  5483       : AfterProperty();
  5486 /**
  5487  * Return true if the frame construction item pointed to by aIter will
  5488  * create a frame adjacent to a line boundary in the frame tree, and that
  5489  * line boundary is induced by a content node adjacent to the frame's
  5490  * content node in the content tree. The latter condition is necessary so
  5491  * that ContentAppended/ContentInserted/ContentRemoved can easily find any
  5492  * text nodes that were suppressed here.
  5493  */
  5494 bool
  5495 nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter)
  5497   if (aIter.item().mSuppressWhiteSpaceOptimizations) {
  5498     return false;
  5501   if (aIter.AtStart()) {
  5502     if (aIter.List()->HasLineBoundaryAtStart() &&
  5503         !aIter.item().mContent->GetPreviousSibling())
  5504       return true;
  5505   } else {
  5506     FCItemIterator prev = aIter;
  5507     prev.Prev();
  5508     if (prev.item().IsLineBoundary() &&
  5509         !prev.item().mSuppressWhiteSpaceOptimizations &&
  5510         aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
  5511       return true;
  5514   FCItemIterator next = aIter;
  5515   next.Next();
  5516   if (next.IsDone()) {
  5517     if (aIter.List()->HasLineBoundaryAtEnd() &&
  5518         !aIter.item().mContent->GetNextSibling())
  5519       return true;
  5520   } else {
  5521     if (next.item().IsLineBoundary() &&
  5522         !next.item().mSuppressWhiteSpaceOptimizations &&
  5523         aIter.item().mContent->GetNextSibling() == next.item().mContent)
  5524       return true;
  5527   return false;
  5530 void
  5531 nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
  5532                                                FCItemIterator& aIter,
  5533                                                nsIFrame* aParentFrame,
  5534                                                nsFrameItems& aFrameItems)
  5536   nsIFrame* adjParentFrame = aParentFrame;
  5537   FrameConstructionItem& item = aIter.item();
  5538   nsStyleContext* styleContext = item.mStyleContext;
  5539   AdjustParentFrame(adjParentFrame, item.mFCData, styleContext);
  5541   if (item.mIsText) {
  5542     // If this is collapsible whitespace next to a line boundary,
  5543     // don't create a frame. item.IsWhitespace() also sets the
  5544     // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
  5545     // end up creating a frame, nsTextFrame::Init will clear the flag.)
  5546     // We don't do this for generated content, because some generated
  5547     // text content is empty text nodes that are about to be initialized.
  5548     // (We check mAdditionalStateBits because only the generated content
  5549     // container's frame construction item is marked with
  5550     // mIsGeneratedContent, and we might not have an aParentFrame.)
  5551     // We don't do it for content that may have XBL anonymous siblings,
  5552     // because they make it difficult to correctly create the frame
  5553     // due to dynamic changes.
  5554     // We don't do it for SVG text, since we might need to position and
  5555     // measure the white space glyphs due to x/y/dx/dy attributes.
  5556     if (AtLineBoundary(aIter) &&
  5557         !styleContext->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
  5558         aIter.List()->ParentHasNoXBLChildren() &&
  5559         !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
  5560         (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
  5561         !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
  5562         !mAlwaysCreateFramesForIgnorableWhitespace &&
  5563         item.IsWhitespace(aState))
  5564       return;
  5566     ConstructTextFrame(item.mFCData, aState, item.mContent,
  5567                        adjParentFrame, styleContext,
  5568                        aFrameItems);
  5569     return;
  5572   // Start background loads during frame construction so that we're
  5573   // guaranteed that they will be started before onload fires.
  5574   styleContext->StartBackgroundImageLoads();
  5576   nsFrameState savedStateBits = aState.mAdditionalStateBits;
  5577   if (item.mIsGeneratedContent) {
  5578     // Ensure that frames created here are all tagged with
  5579     // NS_FRAME_GENERATED_CONTENT.
  5580     aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
  5582     // Note that we're not necessarily setting this property on the primary
  5583     // frame for the content for which this is generated content.  We might be
  5584     // setting it on a table pseudo-frame inserted under that instead.  That's
  5585     // OK, though; we just need to do the property set so that the content will
  5586     // get cleaned up when the frame is destroyed.
  5587     aParentFrame->Properties().Set(GenConPseudoToProperty(styleContext->GetPseudo()),
  5588                                    item.mContent);
  5590     // Now that we've passed ownership of item.mContent to the frame, unset
  5591     // our generated content flag so we don't release or unbind it ourselves.
  5592     item.mIsGeneratedContent = false;
  5595   // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
  5596   ConstructFrameFromItemInternal(item, aState, adjParentFrame, aFrameItems);
  5598   aState.mAdditionalStateBits = savedStateBits;
  5602 inline bool
  5603 IsRootBoxFrame(nsIFrame *aFrame)
  5605   return (aFrame->GetType() == nsGkAtoms::rootFrame);
  5608 nsresult
  5609 nsCSSFrameConstructor::ReconstructDocElementHierarchy()
  5611   Element* rootElement = mDocument->GetRootElement();
  5612   if (!rootElement) {
  5613     /* nothing to do */
  5614     return NS_OK;
  5616   return RecreateFramesForContent(rootElement, false);
  5619 nsIFrame*
  5620 nsCSSFrameConstructor::GetFrameFor(nsIContent* aContent)
  5622   // Get the primary frame associated with the content
  5623   nsIFrame* frame = aContent->GetPrimaryFrame();
  5625   if (!frame)
  5626     return nullptr;
  5628   // If the content of the frame is not the desired content then this is not
  5629   // really a frame for the desired content.
  5630   // XXX This check is needed due to bug 135040. Remove it once that's fixed.
  5631   if (frame->GetContent() != aContent) {
  5632     return nullptr;
  5635   nsIFrame* insertionFrame = frame->GetContentInsertionFrame();
  5637   NS_ASSERTION(insertionFrame == frame || !frame->IsLeaf(),
  5638     "The insertion frame is the primary frame or the primary frame isn't a leaf");
  5640   return insertionFrame;
  5643 nsIFrame*
  5644 nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame,
  5645                                                   ContainingBlockType aType)
  5647   NS_PRECONDITION(nullptr != mRootElementFrame, "no root element frame");
  5649   // Starting with aFrame, look for a frame that is absolutely positioned or
  5650   // relatively positioned (and transformed, if aType is FIXED)
  5651   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
  5652     if (frame->IsFrameOfType(nsIFrame::eMathML)) {
  5653       // If it's mathml, bail out -- no absolute positioning out from inside
  5654       // mathml frames.  Note that we don't make this part of the loop
  5655       // condition because of the stuff at the end of this method...
  5656       return nullptr;
  5659     // If the frame is positioned, we will probably return it as the containing
  5660     // block (see the exceptions below).  Otherwise, we'll start looking at the
  5661     // parent frame, unless we're dealing with a scrollframe.
  5662     // Scrollframes are special since they're not positioned, but their
  5663     // scrolledframe might be.  So, we need to check this special case to return
  5664     // the correct containing block (the scrolledframe) in that case.
  5665     // If we're looking for a fixed-pos containing block and the frame is
  5666     // not transformed, skip it.
  5667     if (!frame->IsPositioned() ||
  5668         (aType == FIXED_POS &&
  5669          !frame->StyleDisplay()->HasTransform(frame) &&
  5670          !frame->StyleDisplay()->HasPerspectiveStyle())) {
  5671       continue;
  5673     nsIFrame* absPosCBCandidate = frame;
  5674     nsIAtom* type = absPosCBCandidate->GetType();
  5675     if (type == nsGkAtoms::fieldSetFrame) {
  5676       absPosCBCandidate = static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
  5677       if (!absPosCBCandidate) {
  5678         continue;
  5680       type = absPosCBCandidate->GetType();
  5682     if (type == nsGkAtoms::scrollFrame) {
  5683       nsIScrollableFrame* scrollFrame = do_QueryFrame(absPosCBCandidate);
  5684       absPosCBCandidate = scrollFrame->GetScrolledFrame();
  5685       if (!absPosCBCandidate) {
  5686         continue;
  5688       type = absPosCBCandidate->GetType();
  5690     // Only first continuations can be containing blocks.
  5691     absPosCBCandidate = absPosCBCandidate->FirstContinuation();
  5692     // Is the frame really an absolute container?
  5693     if (!absPosCBCandidate->IsAbsoluteContainer()) {
  5694       continue;
  5697     // For tables, skip the inner frame and consider the outer table frame.
  5698     if (type == nsGkAtoms::tableFrame) {
  5699       continue;
  5701     // For outer table frames, we can just return absPosCBCandidate.
  5702     return absPosCBCandidate;
  5705   // It is possible for the search for the containing block to fail, because
  5706   // no absolute container can be found in the parent chain.  In those cases,
  5707   // we fall back to the document element's containing block.
  5708   if (aType == FIXED_POS) {
  5709     return mFixedContainingBlock;
  5711   return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr;
  5714 nsIFrame*
  5715 nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
  5717   // Starting with aFrame, look for a frame that is a float containing block.
  5718   // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
  5719   // frames, because they don't seem to be able to deal.
  5720   // The logic here needs to match the logic in ProcessChildren()
  5721   for (nsIFrame* containingBlock = aFrame;
  5722        containingBlock &&
  5723          !ShouldSuppressFloatingOfDescendants(containingBlock);
  5724        containingBlock = containingBlock->GetParent()) {
  5725     if (containingBlock->IsFloatContainingBlock()) {
  5726       return containingBlock;
  5730   // If we didn't find a containing block, then there just isn't
  5731   // one.... return null
  5732   return nullptr;
  5735 /**
  5736  * This function will check whether aContainer has :after generated content.
  5737  * If so, appending to it should actually insert.  The return value is the
  5738  * parent to use for newly-appended content.  *aAfterFrame points to the :after
  5739  * frame before which appended content should go, if there is one.
  5740  */
  5741 static nsIFrame*
  5742 AdjustAppendParentForAfterContent(nsPresContext* aPresContext,
  5743                                   nsIContent* aContainer,
  5744                                   nsIFrame* aParentFrame,
  5745                                   nsIFrame** aAfterFrame)
  5747   // See if the parent has an :after pseudo-element.  Check for the presence
  5748   // of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive.
  5749   nsStyleContext* parentStyle = aParentFrame->StyleContext();
  5750   if (nsLayoutUtils::HasPseudoStyle(aContainer, parentStyle,
  5751                                     nsCSSPseudoElements::ePseudo_after,
  5752                                     aPresContext)) {
  5753     // Ensure that the :after frame is on the principal child list.
  5754     aParentFrame->DrainSelfOverflowList();
  5756     nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aParentFrame);
  5757     if (afterFrame) {
  5758       *aAfterFrame = afterFrame;
  5759       return afterFrame->GetParent();
  5763   *aAfterFrame = nullptr;
  5765   if (IsFramePartOfIBSplit(aParentFrame)) {
  5766     // We might be in a situation where the last part of the {ib} split was
  5767     // empty.  Since we have no ::after pseudo-element, we do in fact want to be
  5768     // appending to that last part, so advance to it if needed.  Note that here
  5769     // aParentFrame is the result of a GetLastIBSplitSibling call, so must be
  5770     // either the last or next to last ib-split sibling.
  5771     nsIFrame* trailingInline = GetIBSplitSibling(aParentFrame);
  5772     if (trailingInline) {
  5773       aParentFrame = trailingInline;
  5776     // Always make sure to look at the last continuation of the frame
  5777     // for the {ib} case, even if that continuation is empty.  We
  5778     // don't do this for the non-ib-split-frame case, since in the
  5779     // other cases appending to the last nonempty continuation is fine
  5780     // and in fact not doing that can confuse code that doesn't know
  5781     // to pull kids from continuations other than its next one.
  5782     aParentFrame = aParentFrame->LastContinuation();
  5785   return aParentFrame;
  5788 /**
  5789  * This function will get the previous sibling to use for an append operation.
  5790  * it takes a parent frame (must not be null) and its :after frame (may be
  5791  * null).
  5792  */
  5793 static nsIFrame*
  5794 FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame)
  5796   if (aAfterFrame) {
  5797     NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent");
  5798     NS_ASSERTION(aAfterFrame->GetPrevSibling() ||
  5799                  aParentFrame->GetFirstPrincipalChild() == aAfterFrame,
  5800                  ":after frame must be on the principal child list here");
  5801     return aAfterFrame->GetPrevSibling();
  5804   aParentFrame->DrainSelfOverflowList();
  5806   return aParentFrame->GetLastChild(kPrincipalList);
  5809 /**
  5810  * This function will get the next sibling for a frame insert operation given
  5811  * the parent and previous sibling.  aPrevSibling may be null.
  5812  */
  5813 static nsIFrame*
  5814 GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
  5816   if (aPrevSibling) {
  5817     return aPrevSibling->GetNextSibling();
  5820   return aParentFrame->GetFirstPrincipalChild();
  5823 /**
  5824  * This function is called by ContentAppended() and ContentInserted() when
  5825  * appending flowed frames to a parent's principal child list. It handles the
  5826  * case where the parent is the trailing inline of an {ib} split.
  5827  */
  5828 nsresult
  5829 nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState&       aState,
  5830                                             nsIFrame*                      aParentFrame,
  5831                                             nsFrameItems&                  aFrameList,
  5832                                             nsIFrame*                      aPrevSibling,
  5833                                             bool                           aIsRecursiveCall)
  5835   NS_PRECONDITION(!IsFramePartOfIBSplit(aParentFrame) ||
  5836                   !GetIBSplitSibling(aParentFrame) ||
  5837                   !GetIBSplitSibling(aParentFrame)->GetFirstPrincipalChild(),
  5838                   "aParentFrame has a ib-split sibling with kids?");
  5839   NS_PRECONDITION(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
  5840                   "Parent and prevsibling don't match");
  5842   nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
  5844   NS_ASSERTION(nextSibling ||
  5845                !aParentFrame->GetNextContinuation() ||
  5846                !aParentFrame->GetNextContinuation()->GetFirstPrincipalChild() ||
  5847                aIsRecursiveCall,
  5848                "aParentFrame has later continuations with kids?");
  5849   NS_ASSERTION(nextSibling ||
  5850                !IsFramePartOfIBSplit(aParentFrame) ||
  5851                (IsInlineFrame(aParentFrame) &&
  5852                 !GetIBSplitSibling(aParentFrame) &&
  5853                 !aParentFrame->GetNextContinuation()) ||
  5854                aIsRecursiveCall,
  5855                "aParentFrame is not last?");
  5857   // If we're inserting a list of frames at the end of the trailing inline
  5858   // of an {ib} split, we may need to create additional {ib} siblings to parent
  5859   // them.
  5860   if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
  5861     // When we get here, our frame list might start with a block.  If it does
  5862     // so, and aParentFrame is an inline, and it and all its previous
  5863     // continuations have no siblings, then put the initial blocks from the
  5864     // frame list into the previous block of the {ib} split.  Note that we
  5865     // didn't want to stop at the block part of the split when figuring out
  5866     // initial parent, because that could screw up float parenting; it's easier
  5867     // to do this little fixup here instead.
  5868     if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) {
  5869       // See whether our trailing inline is empty
  5870       nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
  5871       if (firstContinuation->PrincipalChildList().IsEmpty()) {
  5872         // Our trailing inline is empty.  Collect our starting blocks from
  5873         // aFrameList, get the right parent frame for them, and put them in.
  5874         nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator =
  5875           FindFirstNonBlock(aFrameList);
  5876         nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator);
  5877         NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
  5879         nsIFrame* prevBlock =
  5880           GetIBSplitPrevSibling(firstContinuation)->LastContinuation();
  5881         NS_ASSERTION(prevBlock, "Should have previous block here");
  5883         MoveChildrenTo(aState.mPresContext, aParentFrame, prevBlock, blockKids);
  5887     // We want to put some of the frames into this inline frame.
  5888     nsFrameList::FrameLinkEnumerator firstBlockEnumerator(aFrameList);
  5889     FindFirstBlock(firstBlockEnumerator);
  5891     nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
  5892     if (!inlineKids.IsEmpty()) {
  5893       AppendFrames(aParentFrame, kPrincipalList, inlineKids);
  5896     if (!aFrameList.IsEmpty()) {
  5897       bool positioned = aParentFrame->IsRelativelyPositioned();
  5898       nsFrameItems ibSiblings;
  5899       CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
  5900                        ibSiblings);
  5902       // Make sure to trigger reflow of the inline that used to be our
  5903       // last one and now isn't anymore, since its GetSkipSides() has
  5904       // changed.
  5905       mPresShell->FrameNeedsReflow(aParentFrame,
  5906                                    nsIPresShell::eTreeChange,
  5907                                    NS_FRAME_HAS_DIRTY_CHILDREN);
  5909       // Recurse so we create new ib siblings as needed for aParentFrame's parent
  5910       return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
  5911                                   aParentFrame, true);
  5914     return NS_OK;
  5917   // Insert the frames after our aPrevSibling
  5918   return InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
  5921 #define UNSET_DISPLAY 255
  5923 // This gets called to see if the frames corresponding to aSibling and aContent
  5924 // should be siblings in the frame tree. Although (1) rows and cols, (2) row
  5925 // groups and col groups, (3) row groups and captions, (4) legends and content
  5926 // inside fieldsets, (5) popups and other kids of the menu are siblings from a
  5927 // content perspective, they are not considered siblings in the frame tree.
  5928 bool
  5929 nsCSSFrameConstructor::IsValidSibling(nsIFrame*              aSibling,
  5930                                       nsIContent*            aContent,
  5931                                       uint8_t&               aDisplay)
  5933   nsIFrame* parentFrame = aSibling->GetParent();
  5934   nsIAtom* parentType = nullptr;
  5935   if (parentFrame) {
  5936     parentType = parentFrame->GetType();
  5939   uint8_t siblingDisplay = aSibling->GetDisplay();
  5940   if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == siblingDisplay) ||
  5941       (NS_STYLE_DISPLAY_TABLE_COLUMN       == siblingDisplay) ||
  5942       (NS_STYLE_DISPLAY_TABLE_CAPTION      == siblingDisplay) ||
  5943       (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == siblingDisplay) ||
  5944       (NS_STYLE_DISPLAY_TABLE_ROW_GROUP    == siblingDisplay) ||
  5945       (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == siblingDisplay) ||
  5946       nsGkAtoms::menuFrame == parentType) {
  5947     // if we haven't already, construct a style context to find the display type of aContent
  5948     if (UNSET_DISPLAY == aDisplay) {
  5949       nsRefPtr<nsStyleContext> styleContext;
  5950       nsIFrame* styleParent = aSibling->GetParentStyleContextFrame();
  5951       if (!styleParent) {
  5952         NS_NOTREACHED("Shouldn't happen");
  5953         return false;
  5955       // XXXbz when this code is killed, the state argument to
  5956       // ResolveStyleContext can be made non-optional.
  5957       styleContext = ResolveStyleContext(styleParent, aContent, nullptr);
  5958       const nsStyleDisplay* display = styleContext->StyleDisplay();
  5959       aDisplay = display->mDisplay;
  5961     if (nsGkAtoms::menuFrame == parentType) {
  5962       return
  5963         (NS_STYLE_DISPLAY_POPUP == aDisplay) ==
  5964         (NS_STYLE_DISPLAY_POPUP == siblingDisplay);
  5966     // To have decent performance we want to return false in cases in which
  5967     // reordering the two siblings has no effect on display.  To ensure
  5968     // correctness, we MUST return false in cases where the two siblings have
  5969     // the same desired parent type and live on different display lists.
  5970     // Specificaly, columns and column groups should only consider columns and
  5971     // column groups as valid siblings.  Captions should only consider other
  5972     // captions.  All other things should consider each other as valid
  5973     // siblings.  The restriction in the |if| above on siblingDisplay is ok,
  5974     // because for correctness the only part that really needs to happen is to
  5975     // not consider captions, column groups, and row/header/footer groups
  5976     // siblings of each other.  Treating a column or colgroup as a valid
  5977     // sibling of a non-table-related frame will just mean we end up reframing.
  5978     if ((siblingDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION) !=
  5979         (aDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) {
  5980       // One's a caption and the other is not.  Not valid siblings.
  5981       return false;
  5984     if ((siblingDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP ||
  5985          siblingDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN) !=
  5986         (aDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP ||
  5987          aDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN)) {
  5988       // One's a column or column group and the other is not.  Not valid
  5989       // siblings.
  5990       return false;
  5992     // Fall through; it's possible that the display type was overridden and
  5993     // a different sort of frame was constructed, so we may need to return false
  5994     // below.
  5997   if (IsFrameForFieldSet(parentFrame, parentType)) {
  5998     // Legends can be sibling of legends but not of other content in the fieldset
  5999     nsIAtom* sibType = aSibling->GetContentInsertionFrame()->GetType();
  6000     bool legendContent = aContent->IsHTML(nsGkAtoms::legend);
  6002     if ((legendContent  && (nsGkAtoms::legendFrame != sibType)) ||
  6003         (!legendContent && (nsGkAtoms::legendFrame == sibType)))
  6004       return false;
  6007   return true;
  6010 nsIFrame*
  6011 nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
  6012                                                   nsIContent* aTargetContent,
  6013                                                   uint8_t& aTargetContentDisplay,
  6014                                                   bool aPrevSibling)
  6016   nsIFrame* sibling = aContent->GetPrimaryFrame();
  6017   if (!sibling || sibling->GetContent() != aContent) {
  6018     // XXX the GetContent() != aContent check is needed due to bug 135040.
  6019     // Remove it once that's fixed.
  6020     return nullptr;
  6023   // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
  6024   // out-of-flow frame; we want the placeholder.
  6025   if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  6026     nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling);
  6027     NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
  6028     sibling = placeholderFrame;
  6031   // The frame we have now should never be a continuation
  6032   NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?");
  6034   if (aPrevSibling) {
  6035     // The frame may be a ib-split frame (a split inline frame that
  6036     // contains a block).  Get the last part of that split.
  6037     if (IsFramePartOfIBSplit(sibling)) {
  6038       sibling = GetLastIBSplitSibling(sibling, true);
  6041     // The frame may have a continuation. If so, we want the last
  6042     // non-overflow-container continuation as our previous sibling.
  6043     sibling = sibling->GetTailContinuation();
  6046   if (aTargetContent &&
  6047       !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) {
  6048     sibling = nullptr;
  6051   return sibling;
  6054 nsIFrame*
  6055 nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter,
  6056                                            uint8_t& aTargetContentDisplay)
  6058   nsIContent* child = aIter.Get();
  6060   // Note: not all content objects are associated with a frame (e.g., if it's
  6061   // `display: none') so keep looking until we find a previous frame
  6062   while (nsIContent* sibling = aIter.GetPreviousChild()) {
  6063     nsIFrame* prevSibling =
  6064       FindFrameForContentSibling(sibling, child, aTargetContentDisplay, true);
  6066     if (prevSibling) {
  6067       // Found a previous sibling, we're done!
  6068       return prevSibling;
  6072   return nullptr;
  6075 nsIFrame*
  6076 nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter,
  6077                                        uint8_t& aTargetContentDisplay)
  6079   nsIContent* child = aIter.Get();
  6081   while (nsIContent* sibling = aIter.GetNextChild()) {
  6082     nsIFrame* nextSibling =
  6083       FindFrameForContentSibling(sibling, child, aTargetContentDisplay, false);
  6085     if (nextSibling) {
  6086       // We found a next sibling, we're done!
  6087       return nextSibling;
  6091   return nullptr;
  6094 // For fieldsets, returns the area frame, if the child is not a legend.
  6095 static nsIFrame*
  6096 GetAdjustedParentFrame(nsIFrame*       aParentFrame,
  6097                        nsIAtom*        aParentFrameType,
  6098                        nsIContent*     aChildContent)
  6100   NS_PRECONDITION(nsGkAtoms::tableOuterFrame != aParentFrameType,
  6101                   "Shouldn't be happening!");
  6103   nsIFrame* newParent = nullptr;
  6105   if (nsGkAtoms::fieldSetFrame == aParentFrameType) {
  6106     // If the parent is a fieldSet, use the fieldSet's area frame as the
  6107     // parent unless the new content is a legend.
  6108     if (!aChildContent->IsHTML(nsGkAtoms::legend)) {
  6109       newParent = GetFieldSetBlockFrame(aParentFrame);
  6112   return (newParent) ? newParent : aParentFrame;
  6115 nsIFrame*
  6116 nsCSSFrameConstructor::GetInsertionPrevSibling(nsIFrame*& aParentFrame,
  6117                                                nsIContent* aContainer,
  6118                                                nsIContent* aChild,
  6119                                                bool* aIsAppend,
  6120                                                bool* aIsRangeInsertSafe,
  6121                                                nsIContent* aStartSkipChild,
  6122                                                nsIContent* aEndSkipChild)
  6124   *aIsAppend = false;
  6126   // Find the frame that precedes the insertion point. Walk backwards
  6127   // from the parent frame to get the parent content, because if an
  6128   // XBL insertion point is involved, we'll need to use _that_ to find
  6129   // the preceding frame.
  6131   NS_PRECONDITION(aParentFrame, "Must have parent frame to start with");
  6132   nsIContent* container = aParentFrame->GetContent();
  6134   FlattenedChildIterator iter(container);
  6135   bool xblCase = iter.XBLInvolved() || container != aContainer;
  6136   if (xblCase || !aChild->IsRootOfAnonymousSubtree()) {
  6137     // The check for IsRootOfAnonymousSubtree() is because editor is
  6138     // severely broken and calls us directly for native anonymous
  6139     // nodes that it creates.
  6140     if (aStartSkipChild) {
  6141       iter.Seek(aStartSkipChild);
  6142     } else {
  6143       iter.Seek(aChild);
  6145   } else {
  6146     // Prime the iterator for the call to FindPreviousSibling.
  6147     iter.GetNextChild();
  6148     NS_WARNING("Someone passed native anonymous content directly into frame "
  6149                "construction.  Stop doing that!");
  6152   // Note that FindPreviousSibling is passed the iterator by value, so that
  6153   // the later usage of the iterator starts from the same place.
  6154   uint8_t childDisplay = UNSET_DISPLAY;
  6155   nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
  6157   // Now, find the geometric parent so that we can handle
  6158   // continuations properly. Use the prev sibling if we have it;
  6159   // otherwise use the next sibling.
  6160   if (prevSibling) {
  6161     aParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
  6163   else {
  6164     // If there is no previous sibling, then find the frame that follows
  6165     if (aEndSkipChild) {
  6166       iter.Seek(aEndSkipChild);
  6167       iter.GetPreviousChild();
  6169     nsIFrame* nextSibling = FindNextSibling(iter, childDisplay);
  6171     if (nextSibling) {
  6172       aParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
  6174     else {
  6175       // No previous or next sibling, so treat this like an appended frame.
  6176       *aIsAppend = true;
  6177       if (IsFramePartOfIBSplit(aParentFrame)) {
  6178         // Since we're appending, we'll walk to the last anonymous frame
  6179         // that was created for the broken inline frame.  But don't walk
  6180         // to the trailing inline if it's empty; stop at the block.
  6181         aParentFrame = GetLastIBSplitSibling(aParentFrame, false);
  6183       // Get continuation that parents the last child.  This MUST be done
  6184       // before the AdjustAppendParentForAfterContent call.
  6185       aParentFrame = nsLayoutUtils::LastContinuationWithChild(aParentFrame);
  6186       // Deal with fieldsets
  6187       aParentFrame = ::GetAdjustedParentFrame(aParentFrame,
  6188                                               aParentFrame->GetType(),
  6189                                               aChild);
  6190       nsIFrame* appendAfterFrame;
  6191       aParentFrame =
  6192         ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
  6193                                             container, aParentFrame,
  6194                                             &appendAfterFrame);
  6195       prevSibling = ::FindAppendPrevSibling(aParentFrame, appendAfterFrame);
  6199   *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
  6200   return prevSibling;
  6203 static bool
  6204 IsSpecialFramesetChild(nsIContent* aContent)
  6206   // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
  6207   return aContent->IsHTML() &&
  6208     (aContent->Tag() == nsGkAtoms::frameset ||
  6209      aContent->Tag() == nsGkAtoms::frame);
  6212 static void
  6213 InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
  6215 #ifdef MOZ_XUL
  6217 static
  6218 bool
  6219 IsXULListBox(nsIContent* aContainer)
  6221   return (aContainer->IsXUL() && aContainer->Tag() == nsGkAtoms::listbox);
  6224 static
  6225 nsListBoxBodyFrame*
  6226 MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild)
  6228   if (!aContainer)
  6229     return nullptr;
  6231   if (IsXULListBox(aContainer) &&
  6232       aChild->IsXUL() && aChild->Tag() == nsGkAtoms::listitem) {
  6233     nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(aContainer);
  6234     nsCOMPtr<nsIBoxObject> boxObject;
  6235     xulElement->GetBoxObject(getter_AddRefs(boxObject));
  6236     nsCOMPtr<nsPIListBoxObject> listBoxObject = do_QueryInterface(boxObject);
  6237     if (listBoxObject) {
  6238       return listBoxObject->GetListBoxBody(false);
  6242   return nullptr;
  6244 #endif
  6246 void
  6247 nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState& aState,
  6248                                            nsIFrame* aParentFrame,
  6249                                            nsIContent* aPossibleTextContent,
  6250                                            FrameConstructionItemList& aItems)
  6252   NS_PRECONDITION(aPossibleTextContent, "Must have node");
  6253   if (!aPossibleTextContent->IsNodeOfType(nsINode::eTEXT) ||
  6254       !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
  6255     // Not text, or not suppressed due to being all-whitespace (if it
  6256     // were being suppressed, it would have the
  6257     // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
  6258     return;
  6260   NS_ASSERTION(!aPossibleTextContent->GetPrimaryFrame(),
  6261                "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
  6262   AddFrameConstructionItems(aState, aPossibleTextContent, false,
  6263                             aParentFrame, aItems);
  6266 void
  6267 nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent,
  6268                                            nsIContent* aContent)
  6270   if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
  6271       !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
  6272     // Not text, or not suppressed due to being all-whitespace (if it
  6273     // were being suppressed, it would have the
  6274     // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
  6275     return;
  6277   NS_ASSERTION(!aContent->GetPrimaryFrame(),
  6278                "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
  6279   ContentInserted(aParentContent, aContent, nullptr, false);
  6282 // For inserts aChild should be valid, for appends it should be null.
  6283 // Returns true if this operation can be lazy, false if not.
  6284 bool
  6285 nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
  6286                                             nsIContent* aContainer,
  6287                                             nsIContent* aChild)
  6289   if (mPresShell->GetPresContext()->IsChrome() || !aContainer ||
  6290       aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXUL()) {
  6291     return false;
  6294   if (aOperation == CONTENTINSERT) {
  6295     if (aChild->IsRootOfAnonymousSubtree() ||
  6296         aChild->HasFlag(NODE_IS_IN_SHADOW_TREE) ||
  6297         aChild->IsEditable() || aChild->IsXUL()) {
  6298       return false;
  6300   } else { // CONTENTAPPEND
  6301     NS_ASSERTION(aOperation == CONTENTAPPEND,
  6302                  "operation should be either insert or append");
  6303     for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
  6304       NS_ASSERTION(!child->IsRootOfAnonymousSubtree(),
  6305                    "Should be coming through the CONTENTAPPEND case");
  6306       if (child->IsXUL() || child->IsEditable()) {
  6307         return false;
  6312   // We can construct lazily; just need to set suitable bits in the content
  6313   // tree.
  6315   // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
  6316   nsIContent* content = aContainer;
  6317 #ifdef DEBUG
  6318   // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
  6319   // we want to assert, but leaf frames that process their own children and may
  6320   // ignore anonymous children (eg framesets) make this complicated. So we set
  6321   // these two booleans if we encounter these situations and unset them if we
  6322   // hit a node with a leaf frame.
  6323   bool noPrimaryFrame = false;
  6324   bool needsFrameBitSet = false;
  6325 #endif
  6326   while (content &&
  6327          !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
  6328 #ifdef DEBUG
  6329     if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
  6330       noPrimaryFrame = needsFrameBitSet = false;
  6332     if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
  6333       noPrimaryFrame = true;
  6335     if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
  6336       needsFrameBitSet = true;
  6338 #endif
  6339     content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
  6340     content = content->GetFlattenedTreeParent();
  6342 #ifdef DEBUG
  6343   if (content && content->GetPrimaryFrame() &&
  6344       content->GetPrimaryFrame()->IsLeaf()) {
  6345     noPrimaryFrame = needsFrameBitSet = false;
  6347   NS_ASSERTION(!noPrimaryFrame, "Ancestors of nodes with frames to be "
  6348     "constructed lazily should have frames");
  6349   NS_ASSERTION(!needsFrameBitSet, "Ancestors of nodes with frames to be "
  6350     "constructed lazily should not have NEEDS_FRAME bit set");
  6351 #endif
  6353   // Set NODE_NEEDS_FRAME on the new nodes.
  6354   if (aOperation == CONTENTINSERT) {
  6355     NS_ASSERTION(!aChild->GetPrimaryFrame() ||
  6356                  aChild->GetPrimaryFrame()->GetContent() != aChild,
  6357                  //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
  6358                  // check is needed due to bug 135040. Remove it once that's
  6359                  // fixed.
  6360                  "setting NEEDS_FRAME on a node that already has a frame?");
  6361     aChild->SetFlags(NODE_NEEDS_FRAME);
  6362   } else { // CONTENTAPPEND
  6363     for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
  6364       NS_ASSERTION(!child->GetPrimaryFrame() ||
  6365                    child->GetPrimaryFrame()->GetContent() != child,
  6366                    //XXX the child->GetPrimaryFrame()->GetContent() != child
  6367                    // check is needed due to bug 135040. Remove it once that's
  6368                    // fixed.
  6369                    "setting NEEDS_FRAME on a node that already has a frame?");
  6370       child->SetFlags(NODE_NEEDS_FRAME);
  6374   RestyleManager()->PostRestyleEventForLazyConstruction();
  6375   return true;
  6378 void
  6379 nsCSSFrameConstructor::CreateNeededFrames(nsIContent* aContent)
  6381   NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME),
  6382     "shouldn't get here with a content node that has needs frame bit set");
  6383   NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
  6384     "should only get here with a content node that has descendants needing frames");
  6386   aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
  6388   // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
  6389   // set) or issue content notifications for our kids first. In absence of
  6390   // anything definitive either way we'll go with the latter.
  6392   // It might be better to use GetChildArray and scan it completely first and
  6393   // then issue all notifications. (We have to scan it completely first because
  6394   // constructing frames can set attributes, which can change the storage of
  6395   // child lists).
  6397   // Scan the children of aContent to see what operations (if any) we need to
  6398   // perform.
  6399   uint32_t childCount = aContent->GetChildCount();
  6400   bool inRun = false;
  6401   nsIContent* firstChildInRun = nullptr;
  6402   for (uint32_t i = 0; i < childCount; i++) {
  6403     nsIContent* child = aContent->GetChildAt(i);
  6404     if (child->HasFlag(NODE_NEEDS_FRAME)) {
  6405       NS_ASSERTION(!child->GetPrimaryFrame() ||
  6406                    child->GetPrimaryFrame()->GetContent() != child,
  6407                    //XXX the child->GetPrimaryFrame()->GetContent() != child
  6408                    // check is needed due to bug 135040. Remove it once that's
  6409                    // fixed.
  6410                    "NEEDS_FRAME set on a node that already has a frame?");
  6411       if (!inRun) {
  6412         inRun = true;
  6413         firstChildInRun = child;
  6415     } else {
  6416       if (inRun) {
  6417         inRun = false;
  6418         // generate a ContentRangeInserted for [startOfRun,i)
  6419         ContentRangeInserted(aContent, firstChildInRun, child, nullptr,
  6420                              false);
  6424   if (inRun) {
  6425     ContentAppended(aContent, firstChildInRun, false);
  6428   // Now descend.
  6429   FlattenedChildIterator iter(aContent);
  6430   for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
  6431     if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
  6432       CreateNeededFrames(child);
  6437 void nsCSSFrameConstructor::CreateNeededFrames()
  6439   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
  6440                "Someone forgot a script blocker");
  6442   Element* rootElement = mDocument->GetRootElement();
  6443   NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME),
  6444     "root element should not have frame created lazily");
  6445   if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
  6446     BeginUpdate();
  6447     CreateNeededFrames(rootElement);
  6448     EndUpdate();
  6452 void
  6453 nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
  6454                                                     nsIContent* aStartChild,
  6455                                                     nsIContent* aEndChild,
  6456                                                     bool aAllowLazyConstruction)
  6458   for (nsIContent* child = aStartChild;
  6459        child != aEndChild;
  6460        child = child->GetNextSibling()) {
  6461     if ((child->GetPrimaryFrame() ||
  6462          GetUndisplayedContent(child))
  6463 #ifdef MOZ_XUL
  6464         //  Except listboxes suck, so do NOT skip anything here if
  6465         //  we plan to notify a listbox.
  6466         && !MaybeGetListBoxBodyFrame(aContainer, child)
  6467 #endif
  6468         ) {
  6469       // Already have a frame or undisplayed entry for this content; a
  6470       // previous ContentInserted in this loop must have reconstructed
  6471       // its insertion parent.  Skip it.
  6472       continue;
  6474     // Call ContentInserted with this node.
  6475     ContentInserted(aContainer, child, mTempFrameTreeState,
  6476                     aAllowLazyConstruction);
  6480 nsIFrame*
  6481 nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aContainer,
  6482                                               nsIContent* aStartChild,
  6483                                               nsIContent* aEndChild,
  6484                                               bool aAllowLazyConstruction)
  6486   // See if we have an XBL insertion point. If so, then that's our
  6487   // real parent frame; if not, then the frame hasn't been built yet
  6488   // and we just bail.
  6489   bool multiple = false;
  6490   nsIFrame* insertionPoint = GetInsertionPoint(aContainer, nullptr, &multiple);
  6491   if (!insertionPoint && !multiple)
  6492     return nullptr; // Don't build the frames.
  6494   bool hasInsertion = false;
  6495   if (!multiple) {
  6496     // XXXbz XBL2/sXBL issue
  6497     nsIDocument* document = aStartChild->GetDocument();
  6498     // XXXbz how would |document| be null here?
  6499     if (document && aStartChild->GetXBLInsertionParent()) {
  6500       hasInsertion = true;
  6504   if (multiple || hasInsertion) {
  6505     // We have an insertion point.  There are some additional tests we need to do
  6506     // in order to ensure that an append is a safe operation.
  6507     uint32_t childCount = 0;
  6509     if (!multiple) {
  6510       // We may need to make multiple ContentInserted calls instead.  A
  6511       // reasonable heuristic to employ (in order to maintain good performance)
  6512       // is to find out if the insertion point's content node contains any
  6513       // explicit children.  If it does not, then it is highly likely that
  6514       // an append is occurring.  (Note it is not definite, and there are insane
  6515       // cases we will not deal with by employing this heuristic, but it beats
  6516       // always falling back to multiple ContentInserted calls).
  6517       //
  6518       // In the multiple insertion point case, we know we're going to need to do
  6519       // multiple ContentInserted calls anyway.
  6520       // XXXndeakin This test doesn't work in the new world. Or rather, it works, but
  6521       // it's slow
  6522       childCount = insertionPoint->GetContent()->GetChildCount();
  6525     // If we have multiple insertion points or if we have an insertion point
  6526     // and the operation is not a true append or if the insertion point already
  6527     // has explicit children, then we must fall back.
  6528     if (multiple || aEndChild != nullptr || childCount > 0) {
  6529       // Now comes the fun part.  For each inserted child, make a
  6530       // ContentInserted call as if it had just gotten inserted and
  6531       // let ContentInserted handle the mess.
  6532       IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
  6533                                    aAllowLazyConstruction);
  6534       return nullptr;
  6538   return insertionPoint;
  6541 bool
  6542 nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
  6543                                                 nsIContent* aStartChild,
  6544                                                 nsIContent* aEndChild)
  6546   if (aParentFrame->GetType() == nsGkAtoms::frameSetFrame) {
  6547     // Check whether we have any kids we care about.
  6548     for (nsIContent* cur = aStartChild;
  6549          cur != aEndChild;
  6550          cur = cur->GetNextSibling()) {
  6551       if (IsSpecialFramesetChild(cur)) {
  6552         // Just reframe the parent, since framesets are weird like that.
  6553         RecreateFramesForContent(aParentFrame->GetContent(), false);
  6554         return true;
  6558   return false;
  6561 nsresult
  6562 nsCSSFrameConstructor::ContentAppended(nsIContent*     aContainer,
  6563                                        nsIContent*     aFirstNewContent,
  6564                                        bool            aAllowLazyConstruction)
  6566   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
  6567   NS_PRECONDITION(mUpdateCount != 0,
  6568                   "Should be in an update while creating frames");
  6570 #ifdef DEBUG
  6571   if (gNoisyContentUpdates) {
  6572     printf("nsCSSFrameConstructor::ContentAppended container=%p "
  6573            "first-child=%p lazy=%d\n",
  6574            static_cast<void*>(aContainer), aFirstNewContent,
  6575            aAllowLazyConstruction);
  6576     if (gReallyNoisyContentUpdates && aContainer) {
  6577       aContainer->List(stdout, 0);
  6580 #endif
  6582 #ifdef DEBUG
  6583   for (nsIContent* child = aFirstNewContent;
  6584        child;
  6585        child = child->GetNextSibling()) {
  6586     // XXX the GetContent() != child check is needed due to bug 135040.
  6587     // Remove it once that's fixed.
  6588     NS_ASSERTION(!child->GetPrimaryFrame() ||
  6589                  child->GetPrimaryFrame()->GetContent() != child,
  6590                  "asked to construct a frame for a node that already has a frame");
  6592 #endif
  6594 #ifdef MOZ_XUL
  6595   if (aContainer) {
  6596     int32_t namespaceID;
  6597     nsIAtom* tag =
  6598       mDocument->BindingManager()->ResolveTag(aContainer, &namespaceID);
  6600     // Just ignore tree tags, anyway we don't create any frames for them.
  6601     if (tag == nsGkAtoms::treechildren ||
  6602         tag == nsGkAtoms::treeitem ||
  6603         tag == nsGkAtoms::treerow)
  6604       return NS_OK;
  6607 #endif // MOZ_XUL
  6609   if (aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  6610     // Recreate frames if content is appended into a ShadowRoot
  6611     // because children of ShadowRoot are rendered in place of children
  6612     // of the host.
  6613     nsIContent* bindingParent = aContainer->GetBindingParent();
  6614     LAYOUT_PHASE_TEMP_EXIT();
  6615     nsresult rv = RecreateFramesForContent(bindingParent, false);
  6616     LAYOUT_PHASE_TEMP_REENTER();
  6617     return rv;
  6620   // Get the frame associated with the content
  6621   nsIFrame* parentFrame = GetFrameFor(aContainer);
  6623   // See comment in ContentRangeInserted for why this is necessary.
  6624   if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
  6625     return NS_OK;
  6628   if (aAllowLazyConstruction &&
  6629       MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
  6630     return NS_OK;
  6633   LAYOUT_PHASE_TEMP_EXIT();
  6634   parentFrame = GetRangeInsertionPoint(aContainer,
  6635                                        aFirstNewContent, nullptr,
  6636                                        aAllowLazyConstruction);
  6637   LAYOUT_PHASE_TEMP_REENTER();
  6638   if (!parentFrame) {
  6639     return NS_OK;
  6642   LAYOUT_PHASE_TEMP_EXIT();
  6643   if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
  6644     LAYOUT_PHASE_TEMP_REENTER();
  6645     return NS_OK;
  6647   LAYOUT_PHASE_TEMP_REENTER();
  6649   if (parentFrame->IsLeaf()) {
  6650     // Nothing to do here; we shouldn't be constructing kids of leaves
  6651     // Clear lazy bits so we don't try to construct again.
  6652     ClearLazyBits(aFirstNewContent, nullptr);
  6653     return NS_OK;
  6656   if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
  6657     LAYOUT_PHASE_TEMP_EXIT();
  6658     nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
  6659     LAYOUT_PHASE_TEMP_REENTER();
  6660     return rv;
  6663   // If the frame we are manipulating is a ib-split frame (that is, one
  6664   // that's been created as a result of a block-in-inline situation) then we
  6665   // need to append to the last ib-split sibling, not to the frame itself.
  6666   bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
  6667   if (parentIBSplit) {
  6668 #ifdef DEBUG
  6669     if (gNoisyContentUpdates) {
  6670       printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
  6671       nsFrame::ListTag(stdout, parentFrame);
  6672       printf(" is ib-split\n");
  6674 #endif
  6676     // Since we're appending, we'll walk to the last anonymous frame
  6677     // that was created for the broken inline frame.  But don't walk
  6678     // to the trailing inline if it's empty; stop at the block.
  6679     parentFrame = GetLastIBSplitSibling(parentFrame, false);
  6682   // Get continuation that parents the last child.  This MUST be done
  6683   // before the AdjustAppendParentForAfterContent call.
  6684   parentFrame = nsLayoutUtils::LastContinuationWithChild(parentFrame);
  6686   // We should never get here with fieldsets, since they have multiple
  6687   // insertion points.
  6688   NS_ASSERTION(parentFrame->GetType() != nsGkAtoms::fieldSetFrame,
  6689                "Unexpected parent");
  6691   // Deal with possible :after generated content on the parent
  6692   nsIFrame* parentAfterFrame;
  6693   parentFrame =
  6694     ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
  6695                                         aContainer, parentFrame,
  6696                                         &parentAfterFrame);
  6698   // Create some new frames
  6699   nsFrameConstructorState state(mPresShell,
  6700                                 GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
  6701                                 GetAbsoluteContainingBlock(parentFrame, ABS_POS),
  6702                                 GetFloatContainingBlock(parentFrame));
  6703   state.mTreeMatchContext.InitAncestors(aContainer->AsElement());
  6705   // See if the containing block has :first-letter style applied.
  6706   bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
  6707   nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
  6708   if (containingBlock) {
  6709     haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
  6710     haveFirstLineStyle =
  6711       ShouldHaveFirstLineStyle(containingBlock->GetContent(),
  6712                                containingBlock->StyleContext());
  6715   if (haveFirstLetterStyle) {
  6716     // Before we get going, remove the current letter frames
  6717     RemoveLetterFrames(state.mPresContext, state.mPresShell,
  6718                        containingBlock);
  6721   nsIAtom* frameType = parentFrame->GetType();
  6723   FlattenedChildIterator iter(aContainer);
  6724   bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
  6725   FrameConstructionItemList items;
  6726   if (aFirstNewContent->GetPreviousSibling() &&
  6727       GetParentType(frameType) == eTypeBlock &&
  6728       haveNoXBLChildren) {
  6729     // If there's a text node in the normal content list just before the new
  6730     // items, and it has no frame, make a frame construction item for it. If it
  6731     // doesn't need a frame, ConstructFramesFromItemList below won't give it
  6732     // one.  No need to do all this if our parent type is not block, though,
  6733     // since WipeContainingBlock already handles that situation.
  6734     //
  6735     // Because we're appending, we don't need to worry about any text
  6736     // after the appended content; there can only be XBL anonymous content
  6737     // (text in an XBL binding is not suppressed) or generated content
  6738     // (and bare text nodes are not generated). Native anonymous content
  6739     // generated by frames never participates in inline layout.
  6740     AddTextItemIfNeeded(state, parentFrame,
  6741                         aFirstNewContent->GetPreviousSibling(), items);
  6743   for (nsIContent* child = aFirstNewContent;
  6744        child;
  6745        child = child->GetNextSibling()) {
  6746     AddFrameConstructionItems(state, child, false, parentFrame, items);
  6749   nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame);
  6751   // Perform special check for diddling around with the frames in
  6752   // a ib-split inline frame.
  6753   // If we're appending before :after content, then we're not really
  6754   // appending, so let WipeContainingBlock know that.
  6755   LAYOUT_PHASE_TEMP_EXIT();
  6756   if (WipeContainingBlock(state, containingBlock, parentFrame, items,
  6757                           true, prevSibling)) {
  6758     LAYOUT_PHASE_TEMP_REENTER();
  6759     return NS_OK;
  6761   LAYOUT_PHASE_TEMP_REENTER();
  6763   // If the parent is a block frame, and we're not in a special case
  6764   // where frames can be moved around, determine if the list is for the
  6765   // start or end of the block.
  6766   if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
  6767       !haveFirstLineStyle && !parentIBSplit) {
  6768     items.SetLineBoundaryAtStart(!prevSibling ||
  6769         !prevSibling->IsInlineOutside() ||
  6770         prevSibling->GetType() == nsGkAtoms::brFrame);
  6771     // :after content can't be <br> so no need to check it
  6772     items.SetLineBoundaryAtEnd(!parentAfterFrame ||
  6773         !parentAfterFrame->IsInlineOutside());
  6775   // To suppress whitespace-only text frames, we have to verify that
  6776   // our container's DOM child list matches its flattened tree child list.
  6777   items.SetParentHasNoXBLChildren(haveNoXBLChildren);
  6779   nsFrameItems frameItems;
  6780   ConstructFramesFromItemList(state, items, parentFrame, frameItems);
  6782   for (nsIContent* child = aFirstNewContent;
  6783        child;
  6784        child = child->GetNextSibling()) {
  6785     // Invalidate now instead of before the WipeContainingBlock call, just in
  6786     // case we do wipe; in that case we don't need to do this walk at all.
  6787     // XXXbz does that matter?  Would it make more sense to save some virtual
  6788     // GetChildAt calls instead and do this during construction of our
  6789     // FrameConstructionItemList?
  6790     InvalidateCanvasIfNeeded(mPresShell, child);
  6793   // if the container is a table and a caption was appended, it needs to be put
  6794   // in the outer table frame's additional child list.
  6795   nsFrameItems captionItems;
  6796   if (nsGkAtoms::tableFrame == frameType) {
  6797     // Pull out the captions.  Note that we don't want to do that as we go,
  6798     // because processing a single caption can add a whole bunch of things to
  6799     // the frame items due to pseudoframe processing.  So we'd have to pull
  6800     // captions from a list anyway; might as well do that here.
  6801     // XXXbz this is no longer true; we could pull captions directly out of the
  6802     // FrameConstructionItemList now.
  6803     PullOutCaptionFrames(frameItems, captionItems);
  6806   if (haveFirstLineStyle && parentFrame == containingBlock) {
  6807     // It's possible that some of the new frames go into a
  6808     // first-line frame. Look at them and see...
  6809     AppendFirstLineFrames(state, containingBlock->GetContent(),
  6810                           containingBlock, frameItems);
  6813   // Notify the parent frame passing it the list of new frames
  6814   // Append the flowed frames to the principal child list; captions
  6815   // need special treatment
  6816   if (captionItems.NotEmpty()) { // append the caption to the outer table
  6817     NS_ASSERTION(nsGkAtoms::tableFrame == frameType, "how did that happen?");
  6818     nsIFrame* outerTable = parentFrame->GetParent();
  6819     AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
  6822   if (frameItems.NotEmpty()) { // append the in-flow kids
  6823     AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
  6826   // Recover first-letter frames
  6827   if (haveFirstLetterStyle) {
  6828     RecoverLetterFrames(containingBlock);
  6831 #ifdef DEBUG
  6832   if (gReallyNoisyContentUpdates) {
  6833     printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
  6834     parentFrame->List(stdout, 0);
  6836 #endif
  6838 #ifdef ACCESSIBILITY
  6839   nsAccessibilityService* accService = nsIPresShell::AccService();
  6840   if (accService) {
  6841     accService->ContentRangeInserted(mPresShell, aContainer,
  6842                                      aFirstNewContent, nullptr);
  6844 #endif
  6846   return NS_OK;
  6849 #ifdef MOZ_XUL
  6851 enum content_operation
  6853     CONTENT_INSERTED,
  6854     CONTENT_REMOVED
  6855 };
  6857 // Helper function to lookup the listbox body frame and send a notification
  6858 // for insertion or removal of content
  6859 static
  6860 bool NotifyListBoxBody(nsPresContext*    aPresContext,
  6861                          nsIContent*        aContainer,
  6862                          nsIContent*        aChild,
  6863                          // Only used for the removed notification
  6864                          nsIContent*        aOldNextSibling,
  6865                          nsIDocument*       aDocument,
  6866                          nsIFrame*          aChildFrame,
  6867                          content_operation  aOperation)
  6869   nsListBoxBodyFrame* listBoxBodyFrame =
  6870     MaybeGetListBoxBodyFrame(aContainer, aChild);
  6871   if (listBoxBodyFrame) {
  6872     if (aOperation == CONTENT_REMOVED) {
  6873       // Except if we have an aChildFrame and its parent is not the right
  6874       // thing, then we don't do this.  Pseudo frames are so much fun....
  6875       if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) {
  6876         listBoxBodyFrame->OnContentRemoved(aPresContext, aContainer,
  6877                                            aChildFrame, aOldNextSibling);
  6878         return true;
  6880     } else {
  6881       listBoxBodyFrame->OnContentInserted(aPresContext, aChild);
  6882       return true;
  6886   return false;
  6888 #endif // MOZ_XUL
  6890 nsresult
  6891 nsCSSFrameConstructor::ContentInserted(nsIContent*            aContainer,
  6892                                        nsIContent*            aChild,
  6893                                        nsILayoutHistoryState* aFrameState,
  6894                                        bool                   aAllowLazyConstruction)
  6896   return ContentRangeInserted(aContainer,
  6897                               aChild,
  6898                               aChild->GetNextSibling(),
  6899                               aFrameState,
  6900                               aAllowLazyConstruction);
  6903 // ContentRangeInserted handles creating frames for a range of nodes that
  6904 // aren't at the end of their childlist. ContentRangeInserted isn't a real
  6905 // content notification, but rather it handles regular ContentInserted calls
  6906 // for a single node as well as the lazy construction of frames for a range of
  6907 // nodes when called from CreateNeededFrames. For a range of nodes to be
  6908 // suitable to have its frames constructed all at once they must meet the same
  6909 // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
  6910 // these), plus more. Namely when finding the insertion prevsibling we must not
  6911 // need to consult something specific to any one node in the range, so that the
  6912 // insertion prevsibling would be the same for each node in the range. So we
  6913 // pass the first node in the range to GetInsertionPrevSibling, and if
  6914 // IsValidSibling (the only place GetInsertionPrevSibling might look at the
  6915 // passed in node itself) needs to resolve style on the node we record this and
  6916 // return that this range needs to be split up and inserted separately. Table
  6917 // captions need extra attention as we need to determine where to insert them
  6918 // in the caption list, while skipping any nodes in the range being inserted
  6919 // (because when we treat the caption frames the other nodes have had their
  6920 // frames constructed but not yet inserted into the frame tree).
  6921 nsresult
  6922 nsCSSFrameConstructor::ContentRangeInserted(nsIContent*            aContainer,
  6923                                             nsIContent*            aStartChild,
  6924                                             nsIContent*            aEndChild,
  6925                                             nsILayoutHistoryState* aFrameState,
  6926                                             bool                   aAllowLazyConstruction)
  6928   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
  6929   NS_PRECONDITION(mUpdateCount != 0,
  6930                   "Should be in an update while creating frames");
  6932   NS_PRECONDITION(aStartChild, "must always pass a child");
  6934   // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
  6935   // the :empty pseudo-class?
  6936 #ifdef DEBUG
  6937   if (gNoisyContentUpdates) {
  6938     printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
  6939            "start-child=%p end-child=%p lazy=%d\n",
  6940            static_cast<void*>(aContainer),
  6941            static_cast<void*>(aStartChild), static_cast<void*>(aEndChild),
  6942            aAllowLazyConstruction);
  6943     if (gReallyNoisyContentUpdates) {
  6944       if (aContainer) {
  6945         aContainer->List(stdout,0);
  6946       } else {
  6947         aStartChild->List(stdout, 0);
  6951 #endif
  6953 #ifdef DEBUG
  6954   for (nsIContent* child = aStartChild;
  6955        child != aEndChild;
  6956        child = child->GetNextSibling()) {
  6957     // XXX the GetContent() != child check is needed due to bug 135040.
  6958     // Remove it once that's fixed.
  6959     NS_ASSERTION(!child->GetPrimaryFrame() ||
  6960                  child->GetPrimaryFrame()->GetContent() != child,
  6961                  "asked to construct a frame for a node that already has a frame");
  6963 #endif
  6965   bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
  6966   NS_ASSERTION(isSingleInsert || !aAllowLazyConstruction,
  6967                "range insert shouldn't be lazy");
  6968   NS_ASSERTION(isSingleInsert || aEndChild,
  6969                "range should not include all nodes after aStartChild");
  6971 #ifdef MOZ_XUL
  6972   if (aContainer && IsXULListBox(aContainer)) {
  6973     if (isSingleInsert) {
  6974       if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer,
  6975                             // The insert case in NotifyListBoxBody
  6976                             // doesn't use "old next sibling".
  6977                             aStartChild, nullptr,
  6978                             mDocument, nullptr, CONTENT_INSERTED)) {
  6979         return NS_OK;
  6981     } else {
  6982       // We don't handle a range insert to a listbox parent, issue single
  6983       // ContertInserted calls for each node inserted.
  6984       LAYOUT_PHASE_TEMP_EXIT();
  6985       IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
  6986                                    aAllowLazyConstruction);
  6987       LAYOUT_PHASE_TEMP_REENTER();
  6988       return NS_OK;
  6991 #endif // MOZ_XUL
  6993   // If we have a null parent, then this must be the document element being
  6994   // inserted, or some other child of the document in the DOM (might be a PI,
  6995   // say).
  6996   if (! aContainer) {
  6997     NS_ASSERTION(isSingleInsert,
  6998                  "root node insertion should be a single insertion");
  6999     Element *docElement = mDocument->GetRootElement();
  7001     if (aStartChild != docElement) {
  7002       // Not the root element; just bail out
  7003       return NS_OK;
  7006     NS_PRECONDITION(nullptr == mRootElementFrame,
  7007                     "root element frame already created");
  7009     // Create frames for the document element and its child elements
  7010     nsIFrame* docElementFrame =
  7011       ConstructDocElementFrame(docElement, aFrameState);
  7013     if (docElementFrame) {
  7014       InvalidateCanvasIfNeeded(mPresShell, aStartChild);
  7015 #ifdef DEBUG
  7016       if (gReallyNoisyContentUpdates) {
  7017         printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
  7018                "model:\n");
  7019         mFixedContainingBlock->List(stdout, 0);
  7021 #endif
  7024     if (aFrameState) {
  7025       // Restore frame state for the root scroll frame if there is one
  7026       nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame();
  7027       if (rootScrollFrame) {
  7028         RestoreFrameStateFor(rootScrollFrame, aFrameState);
  7032 #ifdef ACCESSIBILITY
  7033     nsAccessibilityService* accService = nsIPresShell::AccService();
  7034     if (accService) {
  7035       accService->ContentRangeInserted(mPresShell, aContainer,
  7036                                        aStartChild, aEndChild);
  7038 #endif
  7040     return NS_OK;
  7043   if (aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  7044     // Recreate frames if content is inserted into a ShadowRoot
  7045     // because children of ShadowRoot are rendered in place of
  7046     // the children of the host.
  7047     nsIContent* bindingParent = aContainer->GetBindingParent();
  7048     LAYOUT_PHASE_TEMP_EXIT();
  7049     nsresult rv = RecreateFramesForContent(bindingParent, false);
  7050     LAYOUT_PHASE_TEMP_REENTER();
  7051     return rv;
  7054   nsIFrame* parentFrame = GetFrameFor(aContainer);
  7055   // The xbl:children element won't have a frame, but default content can have the children as
  7056   // a parent. While its uncommon to change the structure of the default content itself, a label,
  7057   // for example, can be reframed by having its value attribute set or removed.
  7058   if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
  7059     return NS_OK;
  7062   // Otherwise, we've got parent content. Find its frame.
  7063   NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer, "New XBL code is possibly wrong!");
  7065   if (aAllowLazyConstruction &&
  7066       MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
  7067     return NS_OK;
  7070   if (isSingleInsert) {
  7071     // See if we have an XBL insertion point. If so, then that's our
  7072     // real parent frame; if not, then the frame hasn't been built yet
  7073     // and we just bail.
  7074     parentFrame = GetInsertionPoint(aContainer, aStartChild);
  7075   } else {
  7076     // Get our insertion point. If we need to issue single ContentInserted's
  7077     // GetRangeInsertionPoint will take care of that for us.
  7078     LAYOUT_PHASE_TEMP_EXIT();
  7079     parentFrame = GetRangeInsertionPoint(aContainer, aStartChild, aEndChild,
  7080                                          aAllowLazyConstruction);
  7081     LAYOUT_PHASE_TEMP_REENTER();
  7084   if (!parentFrame) {
  7085     return NS_OK;
  7088   bool isAppend, isRangeInsertSafe;
  7089   nsIFrame* prevSibling =
  7090     GetInsertionPrevSibling(parentFrame, aContainer, aStartChild,
  7091                             &isAppend, &isRangeInsertSafe);
  7093   // check if range insert is safe
  7094   if (!isSingleInsert && !isRangeInsertSafe) {
  7095     // must fall back to a single ContertInserted for each child in the range
  7096     LAYOUT_PHASE_TEMP_EXIT();
  7097     IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
  7098                                  aAllowLazyConstruction);
  7099     LAYOUT_PHASE_TEMP_REENTER();
  7100     return NS_OK;
  7103   nsIContent* container = parentFrame->GetContent();
  7105   nsIAtom* frameType = parentFrame->GetType();
  7106   LAYOUT_PHASE_TEMP_EXIT();
  7107   if (MaybeRecreateForFrameset(parentFrame, aStartChild, aEndChild)) {
  7108     LAYOUT_PHASE_TEMP_REENTER();
  7109     return NS_OK;
  7111   LAYOUT_PHASE_TEMP_REENTER();
  7113   // We should only get here with fieldsets when doing a single insert, because
  7114   // fieldsets have multiple insertion points.
  7115   NS_ASSERTION(isSingleInsert || frameType != nsGkAtoms::fieldSetFrame,
  7116                "Unexpected parent");
  7117   if (IsFrameForFieldSet(parentFrame, frameType) &&
  7118       aStartChild->Tag() == nsGkAtoms::legend) {
  7119     // Just reframe the parent, since figuring out whether this
  7120     // should be the new legend and then handling it is too complex.
  7121     // We could do a little better here --- check if the fieldset already
  7122     // has a legend which occurs earlier in its child list than this node,
  7123     // and if so, proceed. But we'd have to extend nsFieldSetFrame
  7124     // to locate this legend in the inserted frames and extract it.
  7125     LAYOUT_PHASE_TEMP_EXIT();
  7126     nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
  7127     LAYOUT_PHASE_TEMP_REENTER();
  7128     return rv;
  7131   // Don't construct kids of leaves
  7132   if (parentFrame->IsLeaf()) {
  7133     // Clear lazy bits so we don't try to construct again.
  7134     ClearLazyBits(aStartChild, aEndChild);
  7135     return NS_OK;
  7138   if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
  7139     LAYOUT_PHASE_TEMP_EXIT();
  7140     nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
  7141     LAYOUT_PHASE_TEMP_REENTER();
  7142     return rv;
  7145   nsFrameConstructorState state(mPresShell,
  7146                                 GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
  7147                                 GetAbsoluteContainingBlock(parentFrame, ABS_POS),
  7148                                 GetFloatContainingBlock(parentFrame),
  7149                                 aFrameState);
  7150   state.mTreeMatchContext.InitAncestors(aContainer ?
  7151                                           aContainer->AsElement() :
  7152                                           nullptr);
  7154   // Recover state for the containing block - we need to know if
  7155   // it has :first-letter or :first-line style applied to it. The
  7156   // reason we care is that the internal structure in these cases
  7157   // is not the normal structure and requires custom updating
  7158   // logic.
  7159   nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
  7160   bool haveFirstLetterStyle = false;
  7161   bool haveFirstLineStyle = false;
  7163   // In order to shave off some cycles, we only dig up the
  7164   // containing block haveFirst* flags if the parent frame where
  7165   // the insertion/append is occurring is an inline or block
  7166   // container. For other types of containers this isn't relevant.
  7167   uint8_t parentDisplay = parentFrame->GetDisplay();
  7169   // Examine the parentFrame where the insertion is taking
  7170   // place. If it's a certain kind of container then some special
  7171   // processing is done.
  7172   if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay) ||
  7173       (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay) ||
  7174       (NS_STYLE_DISPLAY_INLINE == parentDisplay) ||
  7175       (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay)) {
  7176     // Recover the special style flags for the containing block
  7177     if (containingBlock) {
  7178       haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
  7179       haveFirstLineStyle =
  7180         ShouldHaveFirstLineStyle(containingBlock->GetContent(),
  7181                                  containingBlock->StyleContext());
  7184     if (haveFirstLetterStyle) {
  7185       // If our current parentFrame is a Letter frame, use its parent as our
  7186       // new parent hint
  7187       if (parentFrame->GetType() == nsGkAtoms::letterFrame) {
  7188         // If parentFrame is out of flow, then we actually want the parent of
  7189         // the placeholder frame.
  7190         if (parentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  7191           nsPlaceholderFrame* placeholderFrame =
  7192             GetPlaceholderFrameFor(parentFrame);
  7193           NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
  7194           parentFrame = placeholderFrame->GetParent();
  7195         } else {
  7196           parentFrame = parentFrame->GetParent();
  7200       // Remove the old letter frames before doing the insertion
  7201       RemoveLetterFrames(state.mPresContext, mPresShell,
  7202                          state.mFloatedItems.containingBlock);
  7204       // Removing the letterframes messes around with the frame tree, removing
  7205       // and creating frames.  We need to reget our prevsibling, parent frame,
  7206       // etc.
  7207       prevSibling = GetInsertionPrevSibling(parentFrame, aContainer,
  7208                                             aStartChild, &isAppend,
  7209                                             &isRangeInsertSafe);
  7211       // Need check whether a range insert is still safe.
  7212       if (!isSingleInsert && !isRangeInsertSafe) {
  7213         // Need to recover the letter frames first.
  7214         RecoverLetterFrames(state.mFloatedItems.containingBlock);
  7216         // must fall back to a single ContertInserted for each child in the range
  7217         LAYOUT_PHASE_TEMP_EXIT();
  7218         IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
  7219                                      aAllowLazyConstruction);
  7220         LAYOUT_PHASE_TEMP_REENTER();
  7221         return NS_OK;
  7224       container = parentFrame->GetContent();
  7225       frameType = parentFrame->GetType();
  7229   if (!prevSibling) {
  7230     // We're inserting the new frames as the first child. See if the
  7231     // parent has a :before pseudo-element
  7232     nsIFrame* firstChild = parentFrame->GetFirstPrincipalChild();
  7234     if (firstChild &&
  7235         nsLayoutUtils::IsGeneratedContentFor(container, firstChild,
  7236                                              nsCSSPseudoElements::before)) {
  7237       // Insert the new frames after the last continuation of the :before
  7238       prevSibling = firstChild->GetTailContinuation();
  7239       parentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
  7240       // Don't change isAppend here; we'll can call AppendFrames as needed, and
  7241       // the change to our prevSibling doesn't affect that.
  7245   FrameConstructionItemList items;
  7246   ParentType parentType = GetParentType(frameType);
  7247   FlattenedChildIterator iter(aContainer);
  7248   bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
  7249   if (aStartChild->GetPreviousSibling() &&
  7250       parentType == eTypeBlock && haveNoXBLChildren) {
  7251     // If there's a text node in the normal content list just before the
  7252     // new nodes, and it has no frame, make a frame construction item for
  7253     // it, because it might need a frame now.  No need to do this if our
  7254     // parent type is not block, though, since WipeContainingBlock
  7255     // already handles that sitation.
  7256     AddTextItemIfNeeded(state, parentFrame, aStartChild->GetPreviousSibling(),
  7257                         items);
  7260   if (isSingleInsert) {
  7261     AddFrameConstructionItems(state, aStartChild,
  7262                               aStartChild->IsRootOfAnonymousSubtree(),
  7263                               parentFrame, items);
  7264   } else {
  7265     for (nsIContent* child = aStartChild;
  7266          child != aEndChild;
  7267          child = child->GetNextSibling()){
  7268       AddFrameConstructionItems(state, child, false, parentFrame, items);
  7272   if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) {
  7273     // If there's a text node in the normal content list just after the
  7274     // new nodes, and it has no frame, make a frame construction item for
  7275     // it, because it might need a frame now.  No need to do this if our
  7276     // parent type is not block, though, since WipeContainingBlock
  7277     // already handles that sitation.
  7278     AddTextItemIfNeeded(state, parentFrame, aEndChild, items);
  7281   // Perform special check for diddling around with the frames in
  7282   // a special inline frame.
  7283   // If we're appending before :after content, then we're not really
  7284   // appending, so let WipeContainingBlock know that.
  7285   LAYOUT_PHASE_TEMP_EXIT();
  7286   if (WipeContainingBlock(state, containingBlock, parentFrame, items,
  7287                           isAppend, prevSibling)) {
  7288     LAYOUT_PHASE_TEMP_REENTER();
  7289     return NS_OK;
  7291   LAYOUT_PHASE_TEMP_REENTER();
  7293   // If the container is a table and a caption will be appended, it needs to be
  7294   // put in the outer table frame's additional child list.
  7295   // We make no attempt here to set flags to indicate whether the list
  7296   // will be at the start or end of a block. It doesn't seem worthwhile.
  7297   nsFrameItems frameItems, captionItems;
  7298   ConstructFramesFromItemList(state, items, parentFrame, frameItems);
  7300   if (frameItems.NotEmpty()) {
  7301     for (nsIContent* child = aStartChild;
  7302          child != aEndChild;
  7303          child = child->GetNextSibling()){
  7304       InvalidateCanvasIfNeeded(mPresShell, child);
  7307     if (nsGkAtoms::tableFrame == frameType ||
  7308         nsGkAtoms::tableOuterFrame == frameType) {
  7309       PullOutCaptionFrames(frameItems, captionItems);
  7313   // If the parent of our current prevSibling is different from the frame we'll
  7314   // actually use as the parent, then the calculated insertion point is now
  7315   // invalid and as it is unknown where to insert correctly we append instead
  7316   // (bug 341858).
  7317   // This can affect our prevSibling and isAppend, but should not have any
  7318   // effect on the WipeContainingBlock above, since this should only happen
  7319   // when neither parent is a ib-split frame and should not affect whitespace
  7320   // handling inside table-related frames (and in fact, can only happen when
  7321   // one of the parents is an outer table and one is an inner table or when the
  7322   // parent is a fieldset or fieldset content frame).  So it won't affect the
  7323   // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo
  7324   // handling will only be affected by us maybe thinking we're not inserting
  7325   // at the beginning, whereas we really are.  That would have made us reframe
  7326   // unnecessarily, but that's ok.
  7327   // XXXbz we should push our frame construction item code up higher, so we
  7328   // know what our items are by the time we start figuring out previous
  7329   // siblings
  7330   if (prevSibling && frameItems.NotEmpty() &&
  7331       frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) {
  7332 #ifdef DEBUG
  7333     nsIFrame* frame1 = frameItems.FirstChild()->GetParent();
  7334     nsIFrame* frame2 = prevSibling->GetParent();
  7335     NS_ASSERTION(!IsFramePartOfIBSplit(frame1) &&
  7336                  !IsFramePartOfIBSplit(frame2),
  7337                  "Neither should be ib-split");
  7338     NS_ASSERTION((frame1->GetType() == nsGkAtoms::tableFrame &&
  7339                   frame2->GetType() == nsGkAtoms::tableOuterFrame) ||
  7340                  (frame1->GetType() == nsGkAtoms::tableOuterFrame &&
  7341                   frame2->GetType() == nsGkAtoms::tableFrame) ||
  7342                  frame1->GetType() == nsGkAtoms::fieldSetFrame ||
  7343                  (frame1->GetParent() &&
  7344                   frame1->GetParent()->GetType() == nsGkAtoms::fieldSetFrame),
  7345                  "Unexpected frame types");
  7346 #endif
  7347     isAppend = true;
  7348     nsIFrame* appendAfterFrame;
  7349     parentFrame =
  7350       ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
  7351                                           container,
  7352                                           frameItems.FirstChild()->GetParent(),
  7353                                           &appendAfterFrame);
  7354     prevSibling = ::FindAppendPrevSibling(parentFrame, appendAfterFrame);
  7357   if (haveFirstLineStyle && parentFrame == containingBlock) {
  7358     // It's possible that the new frame goes into a first-line
  7359     // frame. Look at it and see...
  7360     if (isAppend) {
  7361       // Use append logic when appending
  7362       AppendFirstLineFrames(state, containingBlock->GetContent(),
  7363                             containingBlock, frameItems);
  7365     else {
  7366       // Use more complicated insert logic when inserting
  7367       // XXXbz this method is a no-op, so it's easy for the args being passed
  7368       // here to make no sense without anyone noticing...  If it ever stops
  7369       // being a no-op, vet them carefully!
  7370       InsertFirstLineFrames(state, container, containingBlock, &parentFrame,
  7371                             prevSibling, frameItems);
  7375   // We might have captions; put them into the caption list of the
  7376   // outer table frame.
  7377   if (captionItems.NotEmpty()) {
  7378     NS_ASSERTION(nsGkAtoms::tableFrame == frameType ||
  7379                  nsGkAtoms::tableOuterFrame == frameType,
  7380                  "parent for caption is not table?");
  7381     // We need to determine where to put the caption items; start with the
  7382     // the parent frame that has already been determined and get the insertion
  7383     // prevsibling of the first caption item.
  7384     nsIFrame* captionParent = parentFrame;
  7385     bool captionIsAppend;
  7386     nsIFrame* captionPrevSibling = nullptr;
  7388     // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
  7389     bool ignored;
  7390     if (isSingleInsert) {
  7391       captionPrevSibling =
  7392         GetInsertionPrevSibling(captionParent, aContainer, aStartChild,
  7393                                 &captionIsAppend, &ignored);
  7394     } else {
  7395       nsIContent* firstCaption = captionItems.FirstChild()->GetContent();
  7396       // It is very important here that we skip the children in
  7397       // [aStartChild,aEndChild) when looking for a
  7398       // prevsibling.
  7399       captionPrevSibling =
  7400         GetInsertionPrevSibling(captionParent, aContainer, firstCaption,
  7401                                 &captionIsAppend, &ignored,
  7402                                 aStartChild, aEndChild);
  7405     nsIFrame* outerTable = nullptr;
  7406     if (GetCaptionAdjustedParent(captionParent, captionItems.FirstChild(),
  7407                                  &outerTable)) {
  7408       // If the parent is not an outer table frame we will try to add frames
  7409       // to a named child list that the parent does not honour and the frames
  7410       // will get lost
  7411       NS_ASSERTION(nsGkAtoms::tableOuterFrame == outerTable->GetType(),
  7412                    "Pseudo frame construction failure; "
  7413                    "a caption can be only a child of an outer table frame");
  7415       // If the parent of our current prevSibling is different from the frame
  7416       // we'll actually use as the parent, then the calculated insertion
  7417       // point is now invalid (bug 341382).
  7418       if (captionPrevSibling &&
  7419           captionPrevSibling->GetParent() != outerTable) {
  7420           captionPrevSibling = nullptr;
  7422       if (captionIsAppend) {
  7423         AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
  7424       } else {
  7425         InsertFrames(outerTable, nsIFrame::kCaptionList,
  7426                      captionPrevSibling, captionItems);
  7431   if (frameItems.NotEmpty()) {
  7432     // Notify the parent frame
  7433     if (isAppend) {
  7434       AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
  7435     } else {
  7436       InsertFrames(parentFrame, kPrincipalList, prevSibling, frameItems);
  7440   if (haveFirstLetterStyle) {
  7441     // Recover the letter frames for the containing block when
  7442     // it has first-letter style.
  7443     RecoverLetterFrames(state.mFloatedItems.containingBlock);
  7446 #ifdef DEBUG
  7447   if (gReallyNoisyContentUpdates && parentFrame) {
  7448     printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
  7449     parentFrame->List(stdout, 0);
  7451 #endif
  7453 #ifdef ACCESSIBILITY
  7454   nsAccessibilityService* accService = nsIPresShell::AccService();
  7455   if (accService) {
  7456     accService->ContentRangeInserted(mPresShell, aContainer,
  7457                                      aStartChild, aEndChild);
  7459 #endif
  7461   return NS_OK;
  7464 nsresult
  7465 nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
  7466                                       nsIContent* aChild,
  7467                                       nsIContent* aOldNextSibling,
  7468                                       RemoveFlags aFlags,
  7469                                       bool*     aDidReconstruct)
  7471   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
  7472   NS_PRECONDITION(mUpdateCount != 0,
  7473                   "Should be in an update while destroying frames");
  7475   *aDidReconstruct = false;
  7477   // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
  7478   // the :empty pseudo-class?
  7480 #ifdef DEBUG
  7481   if (gNoisyContentUpdates) {
  7482     printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
  7483            "old-next-sibling=%p\n",
  7484            static_cast<void*>(aContainer),
  7485            static_cast<void*>(aChild),
  7486            static_cast<void*>(aOldNextSibling));
  7487     if (gReallyNoisyContentUpdates) {
  7488       aContainer->List(stdout, 0);
  7491 #endif
  7493   nsPresContext *presContext = mPresShell->GetPresContext();
  7494   nsresult                  rv = NS_OK;
  7496   // Find the child frame that maps the content
  7497   nsIFrame* childFrame = aChild->GetPrimaryFrame();
  7499   if (!childFrame || childFrame->GetContent() != aChild) {
  7500     // XXXbz the GetContent() != aChild check is needed due to bug 135040.
  7501     // Remove it once that's fixed.
  7502     ClearUndisplayedContentIn(aChild, aContainer);
  7505 #ifdef MOZ_XUL
  7506   if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
  7507                         mDocument, childFrame, CONTENT_REMOVED))
  7508     return NS_OK;
  7510 #endif // MOZ_XUL
  7512   // If we're removing the root, then make sure to remove things starting at
  7513   // the viewport's child instead of the primary frame (which might even be
  7514   // null if the root had an XBL binding or display:none, even though the
  7515   // frames above it got created).  We do the adjustment after the childFrame
  7516   // check above, because we do want to clear any undisplayed content we might
  7517   // have for the root.  Detecting removal of a root is a little exciting; in
  7518   // particular, having a null aContainer is necessary but NOT sufficient.  Due
  7519   // to how we process reframes, the content node might not even be in our
  7520   // document by now.  So explicitly check whether the viewport's first kid's
  7521   // content node is aChild.
  7522   bool isRoot = false;
  7523   if (!aContainer) {
  7524     nsIFrame* viewport = GetRootFrame();
  7525     if (viewport) {
  7526       nsIFrame* firstChild = viewport->GetFirstPrincipalChild();
  7527       if (firstChild && firstChild->GetContent() == aChild) {
  7528         isRoot = true;
  7529         childFrame = firstChild;
  7530         NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
  7535   if (aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  7536     // Recreate frames if content is removed from a ShadowRoot
  7537     // because it may contain an insertion point which can change
  7538     // how the host is rendered.
  7539     nsIContent* bindingParent = aContainer->GetBindingParent();
  7540     *aDidReconstruct = true;
  7541     LAYOUT_PHASE_TEMP_EXIT();
  7542     nsresult rv = RecreateFramesForContent(bindingParent, false);
  7543     LAYOUT_PHASE_TEMP_REENTER();
  7544     return rv;
  7547   if (childFrame) {
  7548     InvalidateCanvasIfNeeded(mPresShell, aChild);
  7550     // See whether we need to remove more than just childFrame
  7551     LAYOUT_PHASE_TEMP_EXIT();
  7552     if (MaybeRecreateContainerForFrameRemoval(childFrame, &rv)) {
  7553       LAYOUT_PHASE_TEMP_REENTER();
  7554       *aDidReconstruct = true;
  7555       return rv;
  7557     LAYOUT_PHASE_TEMP_REENTER();
  7559     // Get the childFrame's parent frame
  7560     nsIFrame* parentFrame = childFrame->GetParent();
  7561     nsIAtom* parentType = parentFrame->GetType();
  7563     if (parentType == nsGkAtoms::frameSetFrame &&
  7564         IsSpecialFramesetChild(aChild)) {
  7565       // Just reframe the parent, since framesets are weird like that.
  7566       *aDidReconstruct = true;
  7567       LAYOUT_PHASE_TEMP_EXIT();
  7568       nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
  7569       LAYOUT_PHASE_TEMP_REENTER();
  7570       return rv;
  7573     // If we're a child of MathML, then we should reframe the MathML content.
  7574     // If we're non-MathML, then we would be wrapped in a block so we need to
  7575     // check our grandparent in that case.
  7576     nsIFrame* possibleMathMLAncestor = parentType == nsGkAtoms::blockFrame ?
  7577          parentFrame->GetParent() : parentFrame;
  7578     if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
  7579       *aDidReconstruct = true;
  7580       LAYOUT_PHASE_TEMP_EXIT();
  7581       nsresult rv = RecreateFramesForContent(possibleMathMLAncestor->GetContent(), false);
  7582       LAYOUT_PHASE_TEMP_REENTER();
  7583       return rv;
  7586     // Undo XUL wrapping if it's no longer needed.
  7587     // (If we're in the XUL block-wrapping situation, parentFrame is the
  7588     // wrapper frame.)
  7589     nsIFrame* grandparentFrame = parentFrame->GetParent();
  7590     if (grandparentFrame && grandparentFrame->IsBoxFrame() &&
  7591         (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
  7592         // check if this frame is the only one needing wrapping
  7593         aChild == AnyKidsNeedBlockParent(parentFrame->GetFirstPrincipalChild()) &&
  7594         !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
  7595       *aDidReconstruct = true;
  7596       LAYOUT_PHASE_TEMP_EXIT();
  7597       nsresult rv = RecreateFramesForContent(grandparentFrame->GetContent(), true);
  7598       LAYOUT_PHASE_TEMP_REENTER();
  7599       return rv;
  7602 #ifdef ACCESSIBILITY
  7603     nsAccessibilityService* accService = nsIPresShell::AccService();
  7604     if (accService) {
  7605       accService->ContentRemoved(mPresShell, aContainer, aChild);
  7607 #endif
  7609     // Examine the containing-block for the removed content and see if
  7610     // :first-letter style applies.
  7611     nsIFrame* inflowChild = childFrame;
  7612     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  7613       inflowChild = GetPlaceholderFrameFor(childFrame);
  7614       NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
  7616     nsIFrame* containingBlock =
  7617       GetFloatContainingBlock(inflowChild->GetParent());
  7618     bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
  7619     if (haveFLS) {
  7620       // Trap out to special routine that handles adjusting a blocks
  7621       // frame tree when first-letter style is present.
  7622 #ifdef NOISY_FIRST_LETTER
  7623       printf("ContentRemoved: containingBlock=");
  7624       nsFrame::ListTag(stdout, containingBlock);
  7625       printf(" parentFrame=");
  7626       nsFrame::ListTag(stdout, parentFrame);
  7627       printf(" childFrame=");
  7628       nsFrame::ListTag(stdout, childFrame);
  7629       printf("\n");
  7630 #endif
  7632       // First update the containing blocks structure by removing the
  7633       // existing letter frames. This makes the subsequent logic
  7634       // simpler.
  7635       RemoveLetterFrames(presContext, mPresShell, containingBlock);
  7637       // Recover childFrame and parentFrame
  7638       childFrame = aChild->GetPrimaryFrame();
  7639       if (!childFrame || childFrame->GetContent() != aChild) {
  7640         // XXXbz the GetContent() != aChild check is needed due to bug 135040.
  7641         // Remove it once that's fixed.
  7642         ClearUndisplayedContentIn(aChild, aContainer);
  7643         return NS_OK;
  7645       parentFrame = childFrame->GetParent();
  7646       parentType = parentFrame->GetType();
  7648 #ifdef NOISY_FIRST_LETTER
  7649       printf("  ==> revised parentFrame=");
  7650       nsFrame::ListTag(stdout, parentFrame);
  7651       printf(" childFrame=");
  7652       nsFrame::ListTag(stdout, childFrame);
  7653       printf("\n");
  7654 #endif
  7657 #ifdef DEBUG
  7658     if (gReallyNoisyContentUpdates) {
  7659       printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
  7660       nsFrame::ListTag(stdout, childFrame);
  7661       putchar('\n');
  7662       parentFrame->List(stdout, 0);
  7664 #endif
  7667     // Notify the parent frame that it should delete the frame
  7668     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  7669       childFrame = GetPlaceholderFrameFor(childFrame);
  7670       NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
  7671       parentFrame = childFrame->GetParent();
  7673     rv = RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame),
  7674                      childFrame);
  7675     //XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
  7677     if (isRoot) {
  7678       mRootElementFrame = nullptr;
  7679       mRootElementStyleFrame = nullptr;
  7680       mDocElementContainingBlock = nullptr;
  7681       mPageSequenceFrame = nullptr;
  7682       mGfxScrollFrame = nullptr;
  7683       mHasRootAbsPosContainingBlock = false;
  7684       mFixedContainingBlock = GetRootFrame();
  7687     if (haveFLS && mRootElementFrame) {
  7688       RecoverLetterFrames(containingBlock);
  7691     // If we're just reconstructing frames for the element, then the
  7692     // following ContentInserted notification on the element will
  7693     // take care of fixing up any adjacent text nodes.  We don't need
  7694     // to do this if the table parent type of our parent type is not
  7695     // eTypeBlock, though, because in that case the whitespace isn't
  7696     // being suppressed due to us anyway.
  7697     if (aContainer && !aChild->IsRootOfAnonymousSubtree() &&
  7698         aFlags != REMOVE_FOR_RECONSTRUCTION &&
  7699         GetParentType(parentType) == eTypeBlock) {
  7700       // Adjacent whitespace-only text nodes might have been suppressed if
  7701       // this node does not have inline ends. Create frames for them now
  7702       // if necessary.
  7703       // Reframe any text node just before the node being removed, if there is
  7704       // one, and if it's not the last child or the first child. If a whitespace
  7705       // textframe was being suppressed and it's now the last child or first
  7706       // child then it can stay suppressed since the parent must be a block
  7707       // and hence it's adjacent to a block end.
  7708       // If aOldNextSibling is null, then the text node before the node being
  7709       // removed is the last node, and we don't need to worry about it.
  7710       if (aOldNextSibling) {
  7711         nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
  7712         if (prevSibling && prevSibling->GetPreviousSibling()) {
  7713           LAYOUT_PHASE_TEMP_EXIT();
  7714           ReframeTextIfNeeded(aContainer, prevSibling);
  7715           LAYOUT_PHASE_TEMP_REENTER();
  7718       // Reframe any text node just after the node being removed, if there is
  7719       // one, and if it's not the last child or the first child.
  7720       if (aOldNextSibling && aOldNextSibling->GetNextSibling() &&
  7721           aOldNextSibling->GetPreviousSibling()) {
  7722         LAYOUT_PHASE_TEMP_EXIT();
  7723         ReframeTextIfNeeded(aContainer, aOldNextSibling);
  7724         LAYOUT_PHASE_TEMP_REENTER();
  7728 #ifdef DEBUG
  7729     if (gReallyNoisyContentUpdates && parentFrame) {
  7730       printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
  7731       parentFrame->List(stdout, 0);
  7733 #endif
  7736   return rv;
  7739 /**
  7740  * This method invalidates the canvas when frames are removed or added for a
  7741  * node that might have its background propagated to the canvas, i.e., a
  7742  * document root node or an HTML BODY which is a child of the root node.
  7744  * @param aFrame a frame for a content node about to be removed or a frame that
  7745  *               was just created for a content node that was inserted.
  7746  */
  7747 static void
  7748 InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node)
  7750   NS_PRECONDITION(presShell->GetRootFrame(), "What happened here?");
  7751   NS_PRECONDITION(presShell->GetPresContext(), "Say what?");
  7753   //  Note that both in ContentRemoved and ContentInserted the content node
  7754   //  will still have the right parent pointer, so looking at that is ok.
  7756   nsIContent* parent = node->GetParent();
  7757   if (parent) {
  7758     // Has a parent; might not be what we want
  7759     nsIContent* grandParent = parent->GetParent();
  7760     if (grandParent) {
  7761       // Has a grandparent, so not what we want
  7762       return;
  7765     // Check whether it's an HTML body
  7766     if (node->Tag() != nsGkAtoms::body ||
  7767         !node->IsHTML()) {
  7768       return;
  7772   // At this point the node has no parent or it's an HTML <body> child of the
  7773   // root.  We might not need to invalidate in this case (eg we might be in
  7774   // XHTML or something), but chances are we want to.  Play it safe.
  7775   // Invalidate the viewport.
  7777   nsIFrame* rootFrame = presShell->GetRootFrame();
  7778   rootFrame->InvalidateFrameSubtree();
  7781 nsIFrame*
  7782 nsCSSFrameConstructor::EnsureFrameForTextNode(nsGenericDOMDataNode* aContent)
  7784   if (aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
  7785       !mAlwaysCreateFramesForIgnorableWhitespace) {
  7786     // Text frame may have been suppressed. Disable suppression and signal
  7787     // that a flush should be performed. We do this on a document-wide
  7788     // basis so that pages that repeatedly query metrics for
  7789     // collapsed-whitespace text nodes don't trigger pathological behavior.
  7790     mAlwaysCreateFramesForIgnorableWhitespace = true;
  7791     nsAutoScriptBlocker blocker;
  7792     BeginUpdate();
  7793     ReconstructDocElementHierarchy();
  7794     EndUpdate();
  7796   return aContent->GetPrimaryFrame();
  7799 nsresult
  7800 nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
  7801                                             CharacterDataChangeInfo* aInfo)
  7803   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
  7804   nsresult      rv = NS_OK;
  7806   if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
  7807        !aContent->TextIsOnlyWhitespace()) ||
  7808       (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
  7809        aContent->TextIsOnlyWhitespace())) {
  7810 #ifdef DEBUG
  7811     nsIFrame* frame = aContent->GetPrimaryFrame();
  7812     NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
  7813                  "Bit should never be set on generated content");
  7814 #endif
  7815     LAYOUT_PHASE_TEMP_EXIT();
  7816     nsresult rv = RecreateFramesForContent(aContent, false);
  7817     LAYOUT_PHASE_TEMP_REENTER();
  7818     return rv;
  7821   // Find the child frame
  7822   nsIFrame* frame = aContent->GetPrimaryFrame();
  7824   // Notify the first frame that maps the content. It will generate a reflow
  7825   // command
  7827   // It's possible the frame whose content changed isn't inserted into the
  7828   // frame hierarchy yet, or that there is no frame that maps the content
  7829   if (nullptr != frame) {
  7830 #if 0
  7831     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
  7832        ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
  7833         aContent, ContentTag(aContent, 0),
  7834         aSubContent, frame));
  7835 #endif
  7837     // Special check for text content that is a child of a letter frame.  If
  7838     // this happens, we should remove the letter frame, do whatever we're
  7839     // planning to do with this notification, then put the letter frame back.
  7840     // Note that this is basically what RecreateFramesForContent ends up doing;
  7841     // the reason we dont' want to call that here is that our text content
  7842     // could be native anonymous, in which case RecreateFramesForContent would
  7843     // completely barf on it.  And recreating the non-anonymous ancestor would
  7844     // just lead us to come back into this notification (e.g. if quotes or
  7845     // counters are involved), leading to a loop.
  7846     nsIFrame* block = GetFloatContainingBlock(frame);
  7847     bool haveFirstLetterStyle = false;
  7848     if (block) {
  7849       // See if the block has first-letter style applied to it.
  7850       haveFirstLetterStyle = HasFirstLetterStyle(block);
  7851       if (haveFirstLetterStyle) {
  7852         RemoveLetterFrames(mPresShell->GetPresContext(), mPresShell,
  7853                            block);
  7854         // Reget |frame|, since we might have killed it.
  7855         // Do we really need to call CharacterDataChanged in this case, though?
  7856         frame = aContent->GetPrimaryFrame();
  7857         NS_ASSERTION(frame, "Should have frame here!");
  7861     frame->CharacterDataChanged(aInfo);
  7863     if (haveFirstLetterStyle) {
  7864       RecoverLetterFrames(block);
  7868   return rv;
  7871 void
  7872 nsCSSFrameConstructor::BeginUpdate() {
  7873   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
  7874                "Someone forgot a script blocker");
  7876   nsRootPresContext* rootPresContext =
  7877     mPresShell->GetPresContext()->GetRootPresContext();
  7878   if (rootPresContext) {
  7879     rootPresContext->IncrementDOMGeneration();
  7882   ++sGlobalGenerationNumber;
  7883   ++mUpdateCount;
  7886 void
  7887 nsCSSFrameConstructor::EndUpdate()
  7889   if (mUpdateCount == 1) {
  7890     // This is the end of our last update.  Before we decrement
  7891     // mUpdateCount, recalc quotes and counters as needed.
  7893     RecalcQuotesAndCounters();
  7894     NS_ASSERTION(mUpdateCount == 1, "Odd update count");
  7896   NS_ASSERTION(mUpdateCount, "Negative mUpdateCount!");
  7897   --mUpdateCount;
  7900 void
  7901 nsCSSFrameConstructor::RecalcQuotesAndCounters()
  7903   if (mQuotesDirty) {
  7904     mQuotesDirty = false;
  7905     mQuoteList.RecalcAll();
  7908   if (mCountersDirty) {
  7909     mCountersDirty = false;
  7910     mCounterManager.RecalcAll();
  7913   NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
  7914   NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
  7917 void
  7918 nsCSSFrameConstructor::WillDestroyFrameTree()
  7920 #if defined(DEBUG_dbaron_off)
  7921   mCounterManager.Dump();
  7922 #endif
  7924   mIsDestroyingFrameTree = true;
  7926   // Prevent frame tree destruction from being O(N^2)
  7927   mQuoteList.Clear();
  7928   mCounterManager.Clear();
  7930   // Remove our presshell as a style flush observer.  But leave
  7931   // RestyleManager::mObservingRefreshDriver true so we don't readd to
  7932   // it even if someone tries to post restyle events on us from this
  7933   // point on for some reason.
  7934   mPresShell->GetPresContext()->RefreshDriver()->
  7935     RemoveStyleFlushObserver(mPresShell);
  7937   nsFrameManager::Destroy();
  7940 //STATIC
  7942 // XXXbz I'd really like this method to go away. Once we have inline-block and
  7943 // I can just use that for sized broken images, that can happen, maybe.
  7944 void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent*    aContent,
  7945                                                 nsIAtom*       aTag,  // content object's tag
  7946                                                 nsXPIDLString& aAltText)
  7948   // The "alt" attribute specifies alternate text that is rendered
  7949   // when the image can not be displayed
  7951   // If there's no "alt" attribute, and aContent is an input
  7952   // element, then use the value of the "value" attribute
  7953   if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText) &&
  7954       nsGkAtoms::input == aTag) {
  7955     // If there's no "value" attribute either, then use the localized string
  7956     // for "Submit" as the alternate text.
  7957     if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
  7958       nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
  7959                                          "Submit", aAltText);
  7964 nsIFrame*
  7965 nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell*    aPresShell,
  7966                                                        nsPresContext*  aPresContext,
  7967                                                        nsIFrame*        aFrame,
  7968                                                        nsIFrame*        aParentFrame,
  7969                                                        nsIContent*      aContent,
  7970                                                        nsStyleContext*  aStyleContext)
  7972   nsIFrame* newFrame = NS_NewTableOuterFrame(aPresShell, aStyleContext);
  7974   newFrame->Init(aContent, aParentFrame, aFrame);
  7976   // Create a continuing inner table frame, and if there's a caption then
  7977   // replicate the caption
  7978   nsFrameItems  newChildFrames;
  7980   nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
  7981   if (childFrame) {
  7982     nsIFrame* continuingTableFrame =
  7983       CreateContinuingFrame(aPresContext, childFrame, newFrame);
  7984     newChildFrames.AddChild(continuingTableFrame);
  7986     NS_ASSERTION(!childFrame->GetNextSibling(),"there can be only one inner table frame");
  7989   // Set the outer table's initial child list
  7990   newFrame->SetInitialChildList(kPrincipalList, newChildFrames);
  7992   return newFrame;
  7995 nsIFrame*
  7996 nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
  7997                                                   nsPresContext*  aPresContext,
  7998                                                   nsIFrame*        aFrame,
  7999                                                   nsIFrame*        aParentFrame,
  8000                                                   nsIContent*      aContent,
  8001                                                   nsStyleContext*  aStyleContext)
  8003   nsIFrame* newFrame = NS_NewTableFrame(aPresShell, aStyleContext);
  8005   newFrame->Init(aContent, aParentFrame, aFrame);
  8007   // Replicate any header/footer frames
  8008   nsFrameItems  childFrames;
  8009   nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
  8010   for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
  8011     // See if it's a header/footer, possibly wrapped in a scroll frame.
  8012     nsTableRowGroupFrame* rowGroupFrame =
  8013       static_cast<nsTableRowGroupFrame*>(childFrame);
  8014     // If the row group was continued, then don't replicate it.
  8015     nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
  8016     if (rgNextInFlow) {
  8017       rowGroupFrame->SetRepeatable(false);
  8019     else if (rowGroupFrame->IsRepeatable()) {
  8020       // Replicate the header/footer frame.
  8021       nsTableRowGroupFrame*   headerFooterFrame;
  8022       nsFrameItems            childItems;
  8023       nsFrameConstructorState state(mPresShell,
  8024                                     GetAbsoluteContainingBlock(newFrame, FIXED_POS),
  8025                                     GetAbsoluteContainingBlock(newFrame, ABS_POS),
  8026                                     nullptr);
  8027       state.mCreatingExtraFrames = true;
  8029       nsStyleContext* const headerFooterStyleContext = rowGroupFrame->StyleContext();
  8030       headerFooterFrame = static_cast<nsTableRowGroupFrame*>
  8031                                      (NS_NewTableRowGroupFrame(aPresShell, headerFooterStyleContext));
  8033       nsIContent* headerFooter = rowGroupFrame->GetContent();
  8034       headerFooterFrame->Init(headerFooter, newFrame, nullptr);
  8036       nsFrameConstructorSaveState absoluteSaveState;
  8037       MakeTablePartAbsoluteContainingBlockIfNeeded(state,
  8038                                                    headerFooterStyleContext->StyleDisplay(),
  8039                                                    absoluteSaveState,
  8040                                                    headerFooterFrame);
  8042       ProcessChildren(state, headerFooter, rowGroupFrame->StyleContext(),
  8043                       headerFooterFrame, true, childItems, false,
  8044                       nullptr);
  8045       NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
  8046       headerFooterFrame->SetInitialChildList(kPrincipalList, childItems);
  8047       headerFooterFrame->SetRepeatable(true);
  8049       // Table specific initialization
  8050       headerFooterFrame->InitRepeatedFrame(aPresContext, rowGroupFrame);
  8052       // XXX Deal with absolute and fixed frames...
  8053       childFrames.AddChild(headerFooterFrame);
  8057   // Set the table frame's initial child list
  8058   newFrame->SetInitialChildList(kPrincipalList, childFrames);
  8060   return newFrame;
  8063 nsIFrame*
  8064 nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
  8065                                              nsIFrame*       aFrame,
  8066                                              nsIFrame*       aParentFrame,
  8067                                              bool            aIsFluid)
  8069   nsIPresShell*              shell = aPresContext->PresShell();
  8070   nsStyleContext*            styleContext = aFrame->StyleContext();
  8071   nsIFrame*                  newFrame = nullptr;
  8072   nsIFrame*                  nextContinuation = aFrame->GetNextContinuation();
  8073   nsIFrame*                  nextInFlow = aFrame->GetNextInFlow();
  8075   // Use the frame type to determine what type of frame to create
  8076   nsIAtom* frameType = aFrame->GetType();
  8077   nsIContent* content = aFrame->GetContent();
  8079   NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE,
  8080                "why CreateContinuingFrame for a non-splittable frame?");
  8082   if (nsGkAtoms::textFrame == frameType) {
  8083     newFrame = NS_NewContinuingTextFrame(shell, styleContext);
  8084     newFrame->Init(content, aParentFrame, aFrame);
  8085   } else if (nsGkAtoms::inlineFrame == frameType) {
  8086     newFrame = NS_NewInlineFrame(shell, styleContext);
  8087     newFrame->Init(content, aParentFrame, aFrame);
  8088   } else if (nsGkAtoms::blockFrame == frameType) {
  8089     newFrame = NS_NewBlockFrame(shell, styleContext);
  8090     newFrame->Init(content, aParentFrame, aFrame);
  8091 #ifdef MOZ_XUL
  8092   } else if (nsGkAtoms::XULLabelFrame == frameType) {
  8093     newFrame = NS_NewXULLabelFrame(shell, styleContext);
  8094     newFrame->Init(content, aParentFrame, aFrame);
  8095 #endif
  8096   } else if (nsGkAtoms::columnSetFrame == frameType) {
  8097     newFrame = NS_NewColumnSetFrame(shell, styleContext, nsFrameState(0));
  8098     newFrame->Init(content, aParentFrame, aFrame);
  8099   } else if (nsGkAtoms::pageFrame == frameType) {
  8100     nsIFrame* canvasFrame;
  8101     newFrame = ConstructPageFrame(shell, aPresContext, aParentFrame, aFrame,
  8102                                   canvasFrame);
  8103   } else if (nsGkAtoms::tableOuterFrame == frameType) {
  8104     newFrame =
  8105       CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
  8106                                       content, styleContext);
  8108   } else if (nsGkAtoms::tableFrame == frameType) {
  8109     newFrame =
  8110       CreateContinuingTableFrame(shell, aPresContext, aFrame, aParentFrame,
  8111                                  content, styleContext);
  8113   } else if (nsGkAtoms::tableRowGroupFrame == frameType) {
  8114     newFrame = NS_NewTableRowGroupFrame(shell, styleContext);
  8115     newFrame->Init(content, aParentFrame, aFrame);
  8116     if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
  8117       nsTableFrame::RegisterPositionedTablePart(newFrame);
  8119   } else if (nsGkAtoms::tableRowFrame == frameType) {
  8120     newFrame = NS_NewTableRowFrame(shell, styleContext);
  8122     newFrame->Init(content, aParentFrame, aFrame);
  8123     if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
  8124       nsTableFrame::RegisterPositionedTablePart(newFrame);
  8127     // Create a continuing frame for each table cell frame
  8128     nsFrameItems  newChildList;
  8129     nsIFrame* cellFrame = aFrame->GetFirstPrincipalChild();
  8130     while (cellFrame) {
  8131       // See if it's a table cell frame
  8132       if (IS_TABLE_CELL(cellFrame->GetType())) {
  8133         nsIFrame* continuingCellFrame =
  8134           CreateContinuingFrame(aPresContext, cellFrame, newFrame);
  8135         newChildList.AddChild(continuingCellFrame);
  8137       cellFrame = cellFrame->GetNextSibling();
  8140     // Set the table cell's initial child list
  8141     newFrame->SetInitialChildList(kPrincipalList, newChildList);
  8143   } else if (IS_TABLE_CELL(frameType)) {
  8144     // Warning: If you change this and add a wrapper frame around table cell
  8145     // frames, make sure Bug 368554 doesn't regress!
  8146     // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
  8147     newFrame = NS_NewTableCellFrame(shell, styleContext, IsBorderCollapse(aParentFrame));
  8149     newFrame->Init(content, aParentFrame, aFrame);
  8150     if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
  8151       nsTableFrame::RegisterPositionedTablePart(newFrame);
  8154     // Create a continuing area frame
  8155     nsIFrame* blockFrame = aFrame->GetFirstPrincipalChild();
  8156     nsIFrame* continuingBlockFrame =
  8157       CreateContinuingFrame(aPresContext, blockFrame, newFrame);
  8159     // Set the table cell's initial child list
  8160     SetInitialSingleChild(newFrame, continuingBlockFrame);
  8161   } else if (nsGkAtoms::lineFrame == frameType) {
  8162     newFrame = NS_NewFirstLineFrame(shell, styleContext);
  8163     newFrame->Init(content, aParentFrame, aFrame);
  8164   } else if (nsGkAtoms::letterFrame == frameType) {
  8165     newFrame = NS_NewFirstLetterFrame(shell, styleContext);
  8166     newFrame->Init(content, aParentFrame, aFrame);
  8167   } else if (nsGkAtoms::imageFrame == frameType) {
  8168     newFrame = NS_NewImageFrame(shell, styleContext);
  8169     newFrame->Init(content, aParentFrame, aFrame);
  8170   } else if (nsGkAtoms::imageControlFrame == frameType) {
  8171     newFrame = NS_NewImageControlFrame(shell, styleContext);
  8172     newFrame->Init(content, aParentFrame, aFrame);
  8173   } else if (nsGkAtoms::placeholderFrame == frameType) {
  8174     // create a continuing out of flow frame
  8175     nsIFrame* oofFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
  8176     nsIFrame* oofContFrame =
  8177       CreateContinuingFrame(aPresContext, oofFrame, aParentFrame);
  8178     newFrame =
  8179       CreatePlaceholderFrameFor(shell, content, oofContFrame, styleContext,
  8180                                 aParentFrame, aFrame,
  8181                                 aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK);
  8182   } else if (nsGkAtoms::fieldSetFrame == frameType) {
  8183     newFrame = NS_NewFieldSetFrame(shell, styleContext);
  8185     newFrame->Init(content, aParentFrame, aFrame);
  8187     // Create a continuing area frame
  8188     // XXXbz we really shouldn't have to do this by hand!
  8189     nsIFrame* blockFrame = GetFieldSetBlockFrame(aFrame);
  8190     if (blockFrame) {
  8191       nsIFrame* continuingBlockFrame =
  8192         CreateContinuingFrame(aPresContext, blockFrame, newFrame);
  8193       // Set the fieldset's initial child list
  8194       SetInitialSingleChild(newFrame, continuingBlockFrame);
  8195     } else {
  8196       MOZ_ASSERT(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
  8197                  "FieldSet block may only be null for overflow containers");
  8199   } else if (nsGkAtoms::legendFrame == frameType) {
  8200     newFrame = NS_NewLegendFrame(shell, styleContext);
  8201     newFrame->Init(content, aParentFrame, aFrame);
  8202   } else if (nsGkAtoms::flexContainerFrame == frameType) {
  8203     newFrame = NS_NewFlexContainerFrame(shell, styleContext);
  8204     newFrame->Init(content, aParentFrame, aFrame);
  8205   } else {
  8206     NS_RUNTIMEABORT("unexpected frame type");
  8209   // Init() set newFrame to be a fluid continuation of aFrame.
  8210   // If we want a non-fluid continuation, we need to call SetPrevContinuation()
  8211   // to reset NS_FRAME_IS_FLUID_CONTINUATION.
  8212   if (!aIsFluid) {
  8213     newFrame->SetPrevContinuation(aFrame);
  8216   // A continuation of generated content is also generated content
  8217   if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
  8218     newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
  8221   // A continuation of nsIAnonymousContentCreator content is also
  8222   // nsIAnonymousContentCreator created content
  8223   if (aFrame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
  8224     newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
  8227   // A continuation of an out-of-flow is also an out-of-flow
  8228   if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  8229     newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
  8232   if (nextInFlow) {
  8233     nextInFlow->SetPrevInFlow(newFrame);
  8234     newFrame->SetNextInFlow(nextInFlow);
  8235   } else if (nextContinuation) {
  8236     nextContinuation->SetPrevContinuation(newFrame);
  8237     newFrame->SetNextContinuation(nextContinuation);
  8240   NS_POSTCONDITION(!newFrame->GetNextSibling(), "unexpected sibling");
  8241   return newFrame;
  8244 nsresult
  8245 nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
  8247   // Now deal with fixed-pos things....  They should appear on all pages,
  8248   // so we want to move over the placeholders when processing the child
  8249   // of the pageContentFrame.
  8251   nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
  8252   if (!prevPageContentFrame) {
  8253     return NS_OK;
  8255   nsIFrame* canvasFrame = aParentFrame->GetFirstPrincipalChild();
  8256   nsIFrame* prevCanvasFrame = prevPageContentFrame->GetFirstPrincipalChild();
  8257   if (!canvasFrame || !prevCanvasFrame) {
  8258     // document's root element frame missing
  8259     return NS_ERROR_UNEXPECTED;
  8262   nsFrameItems fixedPlaceholders;
  8263   nsIFrame* firstFixed = prevPageContentFrame->GetFirstChild(nsIFrame::kFixedList);
  8264   if (!firstFixed) {
  8265     return NS_OK;
  8268   // Don't allow abs-pos descendants of the fixed content to escape the content.
  8269   // This should not normally be possible (because fixed-pos elements should
  8270   // be absolute containers) but fixed-pos tables currently aren't abs-pos
  8271   // containers.
  8272   nsFrameConstructorState state(mPresShell, aParentFrame,
  8273                                 nullptr,
  8274                                 mRootElementFrame);
  8275   state.mCreatingExtraFrames = true;
  8277   // We can't use an ancestor filter here, because we're not going to
  8278   // be usefully recurring down the tree.  This means that other
  8279   // places in frame construction can't assume a filter is
  8280   // initialized!
  8282   // Iterate across fixed frames and replicate each whose placeholder is a
  8283   // descendant of aFrame. (We don't want to explicitly copy placeholders that
  8284   // are within fixed frames, because that would cause duplicates on the new
  8285   // page - bug 389619)
  8286   for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
  8287     nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed);
  8288     if (prevPlaceholder &&
  8289         nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
  8290       // We want to use the same style as the primary style frame for
  8291       // our content
  8292       nsIContent* content = fixed->GetContent();
  8293       nsStyleContext* styleContext =
  8294         nsLayoutUtils::GetStyleFrame(content)->StyleContext();
  8295       FrameConstructionItemList items;
  8296       AddFrameConstructionItemsInternal(state, content, canvasFrame,
  8297                                         content->Tag(),
  8298                                         content->GetNameSpaceID(),
  8299                                         true,
  8300                                         styleContext,
  8301                                         ITEM_ALLOW_XBL_BASE |
  8302                                           ITEM_ALLOW_PAGE_BREAK,
  8303                                         nullptr, items);
  8304       ConstructFramesFromItemList(state, items, canvasFrame, fixedPlaceholders);
  8308   // Add the placeholders to our primary child list.
  8309   // XXXbz this is a little screwed up, since the fixed frames will have
  8310   // broken auto-positioning. Oh, well.
  8311   NS_ASSERTION(!canvasFrame->GetFirstPrincipalChild(),
  8312                "leaking frames; doc root continuation must be empty");
  8313   canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders);
  8314   return NS_OK;
  8317 nsIFrame*
  8318 nsCSSFrameConstructor::GetInsertionPoint(nsIContent*   aContainer,
  8319                                          nsIContent*   aChildContent,
  8320                                          bool*         aMultiple)
  8322   nsBindingManager *bindingManager = mDocument->BindingManager();
  8324   nsIContent* insertionElement;
  8325   if (aChildContent) {
  8326     // We've got an explicit insertion child. Check to see if it's
  8327     // anonymous.
  8328     if (aChildContent->GetBindingParent() == aContainer) {
  8329       // This child content is anonymous. Don't use the insertion
  8330       // point, since that's only for the explicit kids.
  8331       return GetFrameFor(aContainer);
  8334     insertionElement = bindingManager->FindNestedInsertionPoint(aContainer, aChildContent);
  8336   else {
  8337     bool multiple;
  8338     insertionElement = bindingManager->FindNestedSingleInsertionPoint(aContainer, &multiple);
  8340     if (multiple) {
  8341       if (aMultiple) {
  8342         *aMultiple = true;
  8344       return nullptr;
  8348   if (!insertionElement) {
  8349     insertionElement = aContainer;
  8352   nsIFrame* insertionPoint = GetFrameFor(insertionElement);
  8354   // fieldsets have multiple insertion points.  Note that we might
  8355   // have to look at insertionElement here...
  8356   if (aMultiple && insertionElement->IsHTML(nsGkAtoms::fieldset)) {
  8357     *aMultiple = true;
  8360   return insertionPoint;
  8363 // Capture state for the frame tree rooted at the frame associated with the
  8364 // content object, aContent
  8365 void
  8366 nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
  8367                                                nsILayoutHistoryState* aHistoryState)
  8369   if (!aHistoryState) {
  8370     return;
  8372   nsIFrame* frame = aContent->GetPrimaryFrame();
  8373   if (frame == mRootElementFrame) {
  8374     frame = mFixedContainingBlock;
  8376   for ( ; frame;
  8377         frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
  8378     CaptureFrameState(frame, aHistoryState);
  8382 static bool EqualURIs(mozilla::css::URLValue *aURI1,
  8383                       mozilla::css::URLValue *aURI2)
  8385   return aURI1 == aURI2 ||    // handle null==null, and optimize
  8386          (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
  8389 nsresult
  8390 nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
  8392   nsRefPtr<nsStyleContext> oldContext = GetUndisplayedContent(aElement);
  8393   if (!oldContext) {
  8394     return NS_OK;
  8397   // The parent has a frame, so try resolving a new context.
  8398   nsRefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->
  8399     ResolveStyleFor(aElement, oldContext->GetParent());
  8401   ChangeUndisplayedContent(aElement, newContext);
  8402   const nsStyleDisplay* disp = newContext->StyleDisplay();
  8403   if (disp->mDisplay == NS_STYLE_DISPLAY_NONE) {
  8404     // We can skip trying to recreate frames here, but only if our style
  8405     // context does not have a binding URI that differs from our old one.
  8406     // Otherwise, we should try to recreate, because we may want to apply the
  8407     // new binding
  8408     if (!disp->mBinding) {
  8409       return NS_OK;
  8411     const nsStyleDisplay* oldDisp = oldContext->PeekStyleDisplay();
  8412     if (oldDisp && EqualURIs(disp->mBinding, oldDisp->mBinding)) {
  8413       return NS_OK;
  8417   return RecreateFramesForContent(aElement, false);
  8420 static nsIFrame*
  8421 FindFirstNonWhitespaceChild(nsIFrame* aParentFrame)
  8423   nsIFrame* f = aParentFrame->GetFirstPrincipalChild();
  8424   while (f && f->GetType() == nsGkAtoms::textFrame &&
  8425          f->GetContent()->TextIsOnlyWhitespace()) {
  8426     f = f->GetNextSibling();
  8428   return f;
  8431 static nsIFrame*
  8432 FindNextNonWhitespaceSibling(nsIFrame* aFrame)
  8434   nsIFrame* f = aFrame;
  8435   do {
  8436     f = f->GetNextSibling();
  8437   } while (f && f->GetType() == nsGkAtoms::textFrame &&
  8438            f->GetContent()->TextIsOnlyWhitespace());
  8439   return f;
  8442 static nsIFrame*
  8443 FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
  8445   nsIFrame* f = aFrame;
  8446   do {
  8447     f = f->GetPrevSibling();
  8448   } while (f && f->GetType() == nsGkAtoms::textFrame &&
  8449            f->GetContent()->TextIsOnlyWhitespace());
  8450   return f;
  8453 bool
  8454 nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
  8455                                                              nsresult* aResult)
  8457   NS_PRECONDITION(aFrame, "Must have a frame");
  8458   NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
  8459   NS_PRECONDITION(aResult, "Null out param?");
  8460   NS_PRECONDITION(aFrame == aFrame->FirstContinuation(),
  8461                   "aFrame not the result of GetPrimaryFrame()?");
  8463   if (IsFramePartOfIBSplit(aFrame)) {
  8464     // The removal functions can't handle removal of an {ib} split directly; we
  8465     // need to rebuild the containing block.
  8466 #ifdef DEBUG
  8467     if (gNoisyContentUpdates) {
  8468       printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
  8469              "frame=");
  8470       nsFrame::ListTag(stdout, aFrame);
  8471       printf(" is ib-split\n");
  8473 #endif
  8475     *aResult = ReframeContainingBlock(aFrame);
  8476     return true;
  8479   if (aFrame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame &&
  8480       aFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame) {
  8481     // When we remove the legend for a fieldset, we should reframe
  8482     // the fieldset to ensure another legend is used, if there is one
  8483     *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(), false);
  8484     return true;
  8487   // Now check for possibly needing to reconstruct due to a pseudo parent
  8488   nsIFrame* inFlowFrame =
  8489     (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
  8490       GetPlaceholderFrameFor(aFrame) : aFrame;
  8491   MOZ_ASSERT(inFlowFrame, "How did that happen?");
  8492   MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
  8493              "placeholder for primary frame has previous continuations?");
  8494   nsIFrame* parent = inFlowFrame->GetParent();
  8495   if (IsTablePseudo(parent)) {
  8496     if (FindFirstNonWhitespaceChild(parent) == inFlowFrame ||
  8497         !FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()) ||
  8498         // If we're a table-column-group, then the GetFirstChild check above is
  8499         // not going to catch cases when we're the first child.
  8500         (inFlowFrame->GetType() == nsGkAtoms::tableColGroupFrame &&
  8501          parent->GetFirstChild(nsIFrame::kColGroupList) == inFlowFrame) ||
  8502         // Similar if we're a table-caption.
  8503         (inFlowFrame->GetType() == nsGkAtoms::tableCaptionFrame &&
  8504          parent->GetFirstChild(nsIFrame::kCaptionList) == inFlowFrame)) {
  8505       // We're the first or last frame in the pseudo.  Need to reframe.
  8506       // Good enough to recreate frames for |parent|'s content
  8507       *aResult = RecreateFramesForContent(parent->GetContent(), true);
  8508       return true;
  8512   // Might need to reconstruct things if this frame's nextSibling is a table
  8513   // pseudo, since removal of this frame might mean that this pseudo needs to
  8514   // get merged with the frame's prevSibling if that's also a table pseudo.
  8515   nsIFrame* nextSibling =
  8516     FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
  8517   NS_ASSERTION(!IsTablePseudo(inFlowFrame), "Shouldn't happen here");
  8518   if (nextSibling && IsTablePseudo(nextSibling)) {
  8519     nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
  8520     if (prevSibling && IsTablePseudo(prevSibling)) {
  8521 #ifdef DEBUG
  8522       if (gNoisyContentUpdates) {
  8523         printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
  8524                  "frame=");
  8525         nsFrame::ListTag(stdout, aFrame);
  8526         printf(" has a table pseudo next sibling of different type and a "
  8527                  "table pseudo prevsibling\n");
  8529 #endif
  8530       // Good enough to recreate frames for aFrame's parent's content; even if
  8531       // aFrame's parent is a table pseudo, that'll be the right content node.
  8532       *aResult = RecreateFramesForContent(parent->GetContent(), true);
  8533       return true;
  8537   // Might need to reconstruct things if the removed frame's nextSibling is an
  8538   // anonymous flex item.  The removed frame might've been what divided two
  8539   // runs of inline content into two anonymous flex items, which would now
  8540   // need to be merged.
  8541   // NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
  8542   // we're only interested in anonymous flex items here, and those can never
  8543   // be adjacent to whitespace, since they absorb contiguous runs of inline
  8544   // non-replaced content (including whitespace).
  8545   if (nextSibling && IsAnonymousFlexItem(nextSibling)) {
  8546     NS_ABORT_IF_FALSE(parent->GetType() == nsGkAtoms::flexContainerFrame,
  8547                       "anonymous flex items should only exist as children "
  8548                       "of flex container frames");
  8549 #ifdef DEBUG
  8550     if (gNoisyContentUpdates) {
  8551       printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
  8552              "frame=");
  8553       nsFrame::ListTag(stdout, aFrame);
  8554       printf(" has an anonymous flex item as its next sibling\n");
  8556 #endif // DEBUG
  8557     // Recreate frames for the flex container (the removed frame's parent)
  8558     *aResult = RecreateFramesForContent(parent->GetContent(), true);
  8559     return true;
  8562   // Might need to reconstruct things if the removed frame's nextSibling is
  8563   // null and its parent is an anonymous flex item. (This might be the last
  8564   // remaining child of that anonymous flex item, which can then go away.)
  8565   if (!nextSibling && IsAnonymousFlexItem(parent)) {
  8566     NS_ABORT_IF_FALSE(parent->GetParent() &&
  8567                       parent->GetParent()->GetType() == nsGkAtoms::flexContainerFrame,
  8568                       "anonymous flex items should only exist as children "
  8569                       "of flex container frames");
  8570 #ifdef DEBUG
  8571     if (gNoisyContentUpdates) {
  8572       printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
  8573              "frame=");
  8574       nsFrame::ListTag(stdout, aFrame);
  8575       printf(" has an anonymous flex item as its parent\n");
  8577 #endif // DEBUG
  8578     // Recreate frames for the flex container (the removed frame's grandparent)
  8579     *aResult = RecreateFramesForContent(parent->GetParent()->GetContent(),
  8580                                         true);
  8581     return true;
  8584 #ifdef MOZ_XUL
  8585   if (aFrame->GetType() == nsGkAtoms::popupSetFrame) {
  8586     nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
  8587     if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
  8588       *aResult = ReconstructDocElementHierarchy();
  8589       return true;
  8592 #endif
  8594   // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
  8595   // a non-fluid continuation, i.e. it was split by bidi resolution
  8596   if (!inFlowFrame->GetPrevSibling() &&
  8597       !inFlowFrame->GetNextSibling() &&
  8598       ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
  8599        (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
  8600     *aResult = RecreateFramesForContent(parent->GetContent(), true);
  8601     return true;
  8604   // We might still need to reconstruct things if the parent of inFlowFrame is
  8605   // ib-split, since in that case the removal of aFrame might affect the
  8606   // splitting of its parent.
  8607   if (!IsFramePartOfIBSplit(parent)) {
  8608     return false;
  8611   // If inFlowFrame is not the only in-flow child of |parent|, then removing
  8612   // it will change nothing about the {ib} split.
  8613   if (inFlowFrame != parent->GetFirstPrincipalChild() ||
  8614       inFlowFrame->LastContinuation()->GetNextSibling()) {
  8615     return false;
  8618   // If the parent is the first or last part of the {ib} split, then
  8619   // removing one of its kids will have no effect on the splitting.
  8620   // Get the first continuation up front so we don't have to do it twice.
  8621   nsIFrame* parentFirstContinuation = parent->FirstContinuation();
  8622   if (!GetIBSplitSibling(parentFirstContinuation) ||
  8623       !GetIBSplitPrevSibling(parentFirstContinuation)) {
  8624     return false;
  8627 #ifdef DEBUG
  8628   if (gNoisyContentUpdates) {
  8629     printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
  8630            "frame=");
  8631     nsFrame::ListTag(stdout, parent);
  8632     printf(" is ib-split\n");
  8634 #endif
  8636   *aResult = ReframeContainingBlock(parent);
  8637   return true;
  8640 nsresult
  8641 nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
  8642                                                 bool aAsyncInsert)
  8644   NS_PRECONDITION(!aAsyncInsert || aContent->IsElement(),
  8645                   "Can only insert elements async");
  8646   // If there is no document, we don't want to recreate frames for it.  (You
  8647   // shouldn't generally be giving this method content without a document
  8648   // anyway).
  8649   // Rebuilding the frame tree can have bad effects, especially if it's the
  8650   // frame tree for chrome (see bug 157322).
  8651   NS_ENSURE_TRUE(aContent->GetDocument(), NS_ERROR_FAILURE);
  8653   // Is the frame ib-split? If so, we need to reframe the containing
  8654   // block *here*, rather than trying to remove and re-insert the
  8655   // content (which would otherwise result in *two* nested reframe
  8656   // containing block from ContentRemoved() and ContentInserted(),
  8657   // below!).  We'd really like to optimize away one of those
  8658   // containing block reframes, hence the code here.
  8660   nsIFrame* frame = aContent->GetPrimaryFrame();
  8661   if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
  8662     // Reframe the topmost MathML element to prevent exponential blowup
  8663     // (see bug 397518)
  8664     while (true) {
  8665       nsIContent* parentContent = aContent->GetParent();
  8666       nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame();
  8667       if (!parentContentFrame || !parentContentFrame->IsFrameOfType(nsIFrame::eMathML))
  8668         break;
  8669       aContent = parentContent;
  8670       frame = parentContentFrame;
  8674   if (frame) {
  8675     nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
  8676     if (nonGeneratedAncestor->GetContent() != aContent) {
  8677       return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), aAsyncInsert);
  8680     if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
  8681       // Recreate the frames for the entire nsIAnonymousContentCreator tree
  8682       // since |frame| or one of its descendants may need an nsStyleContext
  8683       // that associates it to a CSS pseudo-element, and only the
  8684       // nsIAnonymousContentCreator that created this content knows how to make
  8685       // that happen.
  8686       nsIAnonymousContentCreator* acc = nullptr;
  8687       nsIFrame* ancestor = frame->GetParent();
  8688       while (!(acc = do_QueryFrame(ancestor))) {
  8689         ancestor = ancestor->GetParent();
  8691       NS_ASSERTION(acc, "Where is the nsIAnonymousContentCreator? We may fail "
  8692                         "to recreate its content correctly");
  8693       // nsSVGUseFrame is special, and we know this is unnecessary for it.
  8694       if (ancestor->GetType() != nsGkAtoms::svgUseFrame) {
  8695         NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
  8696                      "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
  8697         return RecreateFramesForContent(ancestor->GetContent(), aAsyncInsert);
  8701     nsIFrame* parent = frame->GetParent();
  8702     nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
  8703     // If the parent frame is a leaf then the subsequent insert will fail to
  8704     // create a frame, so we need to recreate the parent content. This happens
  8705     // with native anonymous content from the editor.
  8706     if (parent && parent->IsLeaf() && parentContent &&
  8707         parentContent != aContent) {
  8708       return RecreateFramesForContent(parentContent, aAsyncInsert);
  8712   nsresult rv = NS_OK;
  8714   if (frame && MaybeRecreateContainerForFrameRemoval(frame, &rv)) {
  8715     return rv;
  8718   nsINode* containerNode = aContent->GetParentNode();
  8719   // XXXbz how can containerNode be null here?
  8720   if (containerNode) {
  8721     // Before removing the frames associated with the content object,
  8722     // ask them to save their state onto a temporary state object.
  8723     CaptureStateForFramesOf(aContent, mTempFrameTreeState);
  8725     // Need the nsIContent parent, which might be null here, since we need to
  8726     // pass it to ContentInserted and ContentRemoved.
  8727     nsCOMPtr<nsIContent> container = aContent->GetParent();
  8729     // Remove the frames associated with the content object.
  8730     bool didReconstruct;
  8731     rv = ContentRemoved(container, aContent,
  8732                         aContent->IsRootOfAnonymousSubtree() ?
  8733                           nullptr :
  8734                           aContent->GetNextSibling(),
  8735                         REMOVE_FOR_RECONSTRUCTION, &didReconstruct);
  8737     if (NS_SUCCEEDED(rv) && !didReconstruct) {
  8738       // Now, recreate the frames associated with this content object. If
  8739       // ContentRemoved triggered reconstruction, then we don't need to do this
  8740       // because the frames will already have been built.
  8741       if (aAsyncInsert) {
  8742         RestyleManager()->PostRestyleEvent(
  8743           aContent->AsElement(), nsRestyleHint(0), nsChangeHint_ReconstructFrame);
  8744       } else {
  8745         rv = ContentInserted(container, aContent, mTempFrameTreeState, false);
  8750   return rv;
  8753 //////////////////////////////////////////////////////////////////////
  8755 // Block frame construction code
  8757 already_AddRefed<nsStyleContext>
  8758 nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
  8759                                            nsStyleContext* aStyleContext)
  8761   if (aContent) {
  8762     return mPresShell->StyleSet()->
  8763       ResolvePseudoElementStyle(aContent->AsElement(),
  8764                                 nsCSSPseudoElements::ePseudo_firstLetter,
  8765                                 aStyleContext,
  8766                                 nullptr);
  8768   return nullptr;
  8771 already_AddRefed<nsStyleContext>
  8772 nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
  8773                                          nsStyleContext* aStyleContext)
  8775   if (aContent) {
  8776     return mPresShell->StyleSet()->
  8777       ResolvePseudoElementStyle(aContent->AsElement(),
  8778                                 nsCSSPseudoElements::ePseudo_firstLine,
  8779                                 aStyleContext,
  8780                                 nullptr);
  8782   return nullptr;
  8785 // Predicate to see if a given content (block element) has
  8786 // first-letter style applied to it.
  8787 bool
  8788 nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
  8789                                                   nsStyleContext* aStyleContext)
  8791   return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
  8792                                        nsCSSPseudoElements::ePseudo_firstLetter,
  8793                                        mPresShell->GetPresContext());
  8796 bool
  8797 nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame)
  8799   NS_PRECONDITION(aBlockFrame, "Need a frame");
  8800   NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
  8801                "Not a block frame?");
  8803   return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0;
  8806 bool
  8807 nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
  8808                                                 nsStyleContext* aStyleContext)
  8810   bool hasFirstLine =
  8811     nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
  8812                                   nsCSSPseudoElements::ePseudo_firstLine,
  8813                                   mPresShell->GetPresContext());
  8814   if (hasFirstLine) {
  8815     // But disable for fieldsets
  8816     int32_t namespaceID;
  8817     nsIAtom* tag = mDocument->BindingManager()->ResolveTag(aContent,
  8818                                                            &namespaceID);
  8819     // This check must match the one in FindHTMLData.
  8820     hasFirstLine = tag != nsGkAtoms::fieldset ||
  8821       namespaceID != kNameSpaceID_XHTML;
  8824   return hasFirstLine;
  8827 void
  8828 nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent* aContent,
  8829                                                    nsStyleContext* aStyleContext,
  8830                                                    bool* aHaveFirstLetterStyle,
  8831                                                    bool* aHaveFirstLineStyle)
  8833   *aHaveFirstLetterStyle =
  8834     ShouldHaveFirstLetterStyle(aContent, aStyleContext);
  8835   *aHaveFirstLineStyle =
  8836     ShouldHaveFirstLineStyle(aContent, aStyleContext);
  8839 /* static */
  8840 const nsCSSFrameConstructor::PseudoParentData
  8841 nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
  8842   { // Cell
  8843     FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
  8844                      FCDATA_USE_CHILD_ITEMS |
  8845                      FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
  8846                      &nsCSSFrameConstructor::ConstructTableCell),
  8847     &nsCSSAnonBoxes::tableCell
  8848   },
  8849   { // Row
  8850     FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
  8851                      FCDATA_USE_CHILD_ITEMS |
  8852                      FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
  8853                      &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
  8854     &nsCSSAnonBoxes::tableRow
  8855   },
  8856   { // Row group
  8857     FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
  8858                      FCDATA_USE_CHILD_ITEMS |
  8859                      FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  8860                      &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
  8861     &nsCSSAnonBoxes::tableRowGroup
  8862   },
  8863   { // Column group
  8864     FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
  8865                 FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
  8866                 FCDATA_SKIP_ABSPOS_PUSH |
  8867                 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
  8868                 NS_NewTableColGroupFrame),
  8869     &nsCSSAnonBoxes::tableColGroup
  8870   },
  8871   { // Table
  8872     FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
  8873                      &nsCSSFrameConstructor::ConstructTable),
  8874     &nsCSSAnonBoxes::table
  8876 };
  8878 void
  8879 nsCSSFrameConstructor::CreateNeededAnonFlexItems(
  8880   nsFrameConstructorState& aState,
  8881   FrameConstructionItemList& aItems,
  8882   nsIFrame* aParentFrame)
  8884   if (aItems.IsEmpty() ||
  8885       aParentFrame->GetType() != nsGkAtoms::flexContainerFrame) {
  8886     return;
  8889   FCItemIterator iter(aItems);
  8890   do {
  8891     // Advance iter past children that don't want to be wrapped
  8892     if (iter.SkipItemsThatDontNeedAnonFlexItem(aState)) {
  8893       // Hit the end of the items without finding any remaining children that
  8894       // need to be wrapped. We're finished!
  8895       return;
  8898     // If our next potentially-wrappable child is whitespace, then see if
  8899     // there's anything wrappable immediately after it. If not, we just drop
  8900     // the whitespace and move on. (We're not supposed to create any anonymous
  8901     // flex items that _only_ contain whitespace).
  8902     // (BUT if this is generated content, then we don't give whitespace nodes
  8903     // any special treatment, because they're probably not really whitespace --
  8904     // they're just temporarily empty, waiting for their generated text.)
  8905     // XXXdholbert If this node's generated text will *actually end up being
  8906     // entirely whitespace*, then we technically should still skip over it, per
  8907     // the flexbox spec. I'm not bothering with that at this point, since it's
  8908     // a pretty extreme edge case.
  8909     if (!aParentFrame->IsGeneratedContentFrame() &&
  8910         iter.item().IsWhitespace(aState)) {
  8911       FCItemIterator afterWhitespaceIter(iter);
  8912       bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
  8913       bool nextChildNeedsAnonFlexItem =
  8914         !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexItem(aState);
  8916       if (!nextChildNeedsAnonFlexItem) {
  8917         // There's nothing after the whitespace that we need to wrap, so we
  8918         // just drop this run of whitespace.
  8919         iter.DeleteItemsTo(afterWhitespaceIter);
  8920         if (hitEnd) {
  8921           // Nothing left to do -- we're finished!
  8922           return;
  8924         // else, we have a next child and it does not want to be wrapped.  So,
  8925         // we jump back to the beginning of the loop to skip over that child
  8926         // (and anything else non-wrappable after it)
  8927         NS_ABORT_IF_FALSE(!iter.IsDone() &&
  8928                           !iter.item().NeedsAnonFlexItem(aState),
  8929                           "hitEnd and/or nextChildNeedsAnonFlexItem lied");
  8930         continue;
  8934     // Now |iter| points to the first child that needs to be wrapped in an
  8935     // anonymous flex item. Now we see how many children after it also want
  8936     // to be wrapped in an anonymous flex item.
  8937     FCItemIterator endIter(iter); // iterator to find the end of the group
  8938     endIter.SkipItemsThatNeedAnonFlexItem(aState);
  8940     NS_ASSERTION(iter != endIter,
  8941                  "Should've had at least one wrappable child to seek past");
  8943     // Now, we create the anonymous flex item to contain the children
  8944     // between |iter| and |endIter|.
  8945     nsIAtom* pseudoType = nsCSSAnonBoxes::anonymousFlexItem;
  8946     nsStyleContext* parentStyle = aParentFrame->StyleContext();
  8947     nsIContent* parentContent = aParentFrame->GetContent();
  8948     already_AddRefed<nsStyleContext> wrapperStyle =
  8949       mPresShell->StyleSet()->ResolveAnonymousBoxStyle(pseudoType, parentStyle);
  8951     static const FrameConstructionData sBlockFormattingContextFCData =
  8952       FCDATA_DECL(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
  8953                   NS_NewBlockFormattingContext);
  8955     FrameConstructionItem* newItem =
  8956       new FrameConstructionItem(&sBlockFormattingContextFCData,
  8957                                 // Use the content of our parent frame
  8958                                 parentContent,
  8959                                 // Lie about the tag; it doesn't matter anyway
  8960                                 pseudoType,
  8961                                 iter.item().mNameSpaceID,
  8962                                 // no pending binding
  8963                                 nullptr,
  8964                                 wrapperStyle,
  8965                                 true, nullptr);
  8967     newItem->mIsAllInline = newItem->mHasInlineEnds =
  8968       newItem->mStyleContext->StyleDisplay()->IsInlineOutsideStyle();
  8969     newItem->mIsBlock = !newItem->mIsAllInline;
  8971     NS_ABORT_IF_FALSE(!newItem->mIsAllInline && newItem->mIsBlock,
  8972                       "expecting anonymous flex items to be block-level "
  8973                       "(this will make a difference when we encounter "
  8974                       "'flex-align: baseline')");
  8976     // Anonymous flex items induce line boundaries around their
  8977     // contents.
  8978     newItem->mChildItems.SetLineBoundaryAtStart(true);
  8979     newItem->mChildItems.SetLineBoundaryAtEnd(true);
  8980     // The parent of the items in aItems is also the parent of the items
  8981     // in mChildItems
  8982     newItem->mChildItems.SetParentHasNoXBLChildren(
  8983       aItems.ParentHasNoXBLChildren());
  8985     // Eat up all items between |iter| and |endIter| and put them in our
  8986     // wrapper. This advances |iter| to point to |endIter|.
  8987     iter.AppendItemsToList(endIter, newItem->mChildItems);
  8989     iter.InsertItem(newItem);
  8990   } while (!iter.IsDone());
  8993 /*
  8994  * This function works as follows: we walk through the child list (aItems) and
  8995  * find items that cannot have aParentFrame as their parent.  We wrap
  8996  * continuous runs of such items into a FrameConstructionItem for a frame that
  8997  * gets them closer to their desired parents.  For example, a run of non-row
  8998  * children of a row-group will get wrapped in a row.  When we later construct
  8999  * the frame for this wrapper (in this case for the row), it'll be the correct
  9000  * parent for the cells in the set of items we wrapped or we'll wrap cells
  9001  * around everything else.  At the end of this method, aItems is guaranteed to
  9002  * contain only items for frames that can be direct kids of aParentFrame.
  9003  */
  9004 void
  9005 nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
  9006                                                 FrameConstructionItemList& aItems,
  9007                                                 nsIFrame* aParentFrame)
  9009   ParentType ourParentType = GetParentType(aParentFrame);
  9010   if (aItems.AllWantParentType(ourParentType)) {
  9011     // Nothing to do here
  9012     return;
  9015   FCItemIterator iter(aItems);
  9016   do {
  9017     if (iter.SkipItemsWantingParentType(ourParentType)) {
  9018       // Nothing else to do here; we're finished
  9019       return;
  9022     // Now we're pointing to the first child that wants a different parent
  9023     // type.
  9025     // Now try to figure out what kids we can group together.  We can generally
  9026     // group everything that has a different desired parent type from us.  Two
  9027     // exceptions to this:
  9028     // 1) If our parent type is table, we can't group columns with anything
  9029     //    else other than whitespace.
  9030     // 2) Whitespace that lies between two things we can group which both want
  9031     //    a non-block parent should be dropped, even if we can't group them
  9032     //    with each other and even if the whitespace wants a parent of
  9033     //    ourParentType.  Ends of the list count as things that don't want a
  9034     //    block parent (so that for example we'll drop a whitespace-only list).
  9036     FCItemIterator endIter(iter); /* iterator to find the end of the group */
  9037     ParentType groupingParentType = endIter.item().DesiredParentType();
  9038     if (aItems.AllWantParentType(groupingParentType) &&
  9039         groupingParentType != eTypeBlock) {
  9040       // Just group them all and be done with it.  We need the check for
  9041       // eTypeBlock here to catch the "all the items are whitespace" case
  9042       // described above.
  9043       endIter.SetToEnd();
  9044     } else {
  9045       // Locate the end of the group.
  9047       // Keep track of the type the previous item wanted, in case we have to
  9048       // deal with whitespace.  Start it off with ourParentType, since that's
  9049       // the last thing |iter| would have skipped over.
  9050       ParentType prevParentType = ourParentType;
  9051       do {
  9052         /* Walk an iterator past any whitespace that we might be able to drop from the list */
  9053         FCItemIterator spaceEndIter(endIter);
  9054         if (prevParentType != eTypeBlock &&
  9055             !aParentFrame->IsGeneratedContentFrame() &&
  9056             spaceEndIter.item().IsWhitespace(aState)) {
  9057           bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
  9059           // We drop the whitespace if these are not trailing spaces and the next item
  9060           // does not want a block parent (see case 2 above)
  9061           // if these are trailing spaces and aParentFrame is a tabular container
  9062           // according to rule 1.3 of CSS 2.1 Sec 17.2.1. (Being a tabular container
  9063           // pretty much means ourParentType != eTypeBlock besides the eTypeColGroup case,
  9064           // which won't reach here.)
  9065           if ((trailingSpaces && ourParentType != eTypeBlock) ||
  9066               (!trailingSpaces && spaceEndIter.item().DesiredParentType() !=
  9067                eTypeBlock)) {
  9068             bool updateStart = (iter == endIter);
  9069             endIter.DeleteItemsTo(spaceEndIter);
  9070             NS_ASSERTION(trailingSpaces == endIter.IsDone(), "These should match");
  9072             if (updateStart) {
  9073               iter = endIter;
  9076             if (trailingSpaces) {
  9077               break; /* Found group end */
  9080             if (updateStart) {
  9081               // Update groupingParentType, since it might have been eTypeBlock
  9082               // just because of the whitespace.
  9083               groupingParentType = iter.item().DesiredParentType();
  9088         // Now endIter points to a non-whitespace item or a non-droppable
  9089         // whitespace item. In the latter case, if this is the end of the group
  9090         // we'll traverse this whitespace again.  But it'll all just be quick
  9091         // DesiredParentType() checks which will match ourParentType (that's
  9092         // what it means that this is the group end), so it's OK.
  9093         prevParentType = endIter.item().DesiredParentType();
  9094         if (prevParentType == ourParentType) {
  9095           // End the group at endIter.
  9096           break;
  9099         if (ourParentType == eTypeTable &&
  9100             (prevParentType == eTypeColGroup) !=
  9101             (groupingParentType == eTypeColGroup)) {
  9102           // Either we started with columns and now found something else, or vice
  9103           // versa.  In any case, end the grouping.
  9104           break;
  9107         // Include the whitespace we didn't drop (if any) in the group, since
  9108         // this is not the end of the group.  Note that this doesn't change
  9109         // prevParentType, since if we didn't drop the whitespace then we ended
  9110         // at something that wants a block parent.
  9111         endIter = spaceEndIter;
  9113         endIter.Next();
  9114       } while (!endIter.IsDone());
  9117     if (iter == endIter) {
  9118       // Nothing to wrap here; just skipped some whitespace
  9119       continue;
  9122     // Now group together all the items between iter and endIter.  The right
  9123     // parent type to use depends on ourParentType.
  9124     ParentType wrapperType;
  9125     switch (ourParentType) {
  9126       case eTypeBlock:
  9127         wrapperType = eTypeTable;
  9128         break;
  9129       case eTypeRow:
  9130         // The parent type for a cell is eTypeBlock, since that's what a cell
  9131         // looks like to its kids.
  9132         wrapperType = eTypeBlock;
  9133         break;
  9134       case eTypeRowGroup:
  9135         wrapperType = eTypeRow;
  9136         break;
  9137       case eTypeTable:
  9138         // Either colgroup or rowgroup, depending on what we're grouping.
  9139         wrapperType = groupingParentType == eTypeColGroup ?
  9140           eTypeColGroup : eTypeRowGroup;
  9141         break;
  9142       default:
  9143         MOZ_CRASH("Colgroups should be suppresing non-col child items");
  9146     const PseudoParentData& pseudoData = sPseudoParentData[wrapperType];
  9147     nsIAtom* pseudoType = *pseudoData.mPseudoType;
  9148     nsStyleContext* parentStyle = aParentFrame->StyleContext();
  9149     nsIContent* parentContent = aParentFrame->GetContent();
  9151     if (pseudoType == nsCSSAnonBoxes::table &&
  9152         parentStyle->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE) {
  9153       pseudoType = nsCSSAnonBoxes::inlineTable;
  9156     already_AddRefed<nsStyleContext> wrapperStyle =
  9157       mPresShell->StyleSet()->ResolveAnonymousBoxStyle(pseudoType, parentStyle);
  9158     FrameConstructionItem* newItem =
  9159       new FrameConstructionItem(&pseudoData.mFCData,
  9160                                 // Use the content of our parent frame
  9161                                 parentContent,
  9162                                 // Lie about the tag; it doesn't matter anyway
  9163                                 pseudoType,
  9164                                 // The namespace does matter, however; it needs
  9165                                 // to match that of our first child item to
  9166                                 // match the old behavior
  9167                                 iter.item().mNameSpaceID,
  9168                                 // no pending binding
  9169                                 nullptr,
  9170                                 wrapperStyle,
  9171                                 true, nullptr);
  9173     // Here we're cheating a tad... technically, table-internal items should be
  9174     // inline if aParentFrame is inline, but they'll get wrapped in an
  9175     // inline-table in the end, so it'll all work out.  In any case, arguably
  9176     // we don't need to maintain this state at this point... but it's better
  9177     // to, I guess.
  9178     newItem->mIsAllInline = newItem->mHasInlineEnds =
  9179       newItem->mStyleContext->StyleDisplay()->IsInlineOutsideStyle();
  9181     // Table pseudo frames always induce line boundaries around their
  9182     // contents.
  9183     newItem->mChildItems.SetLineBoundaryAtStart(true);
  9184     newItem->mChildItems.SetLineBoundaryAtEnd(true);
  9185     // The parent of the items in aItems is also the parent of the items
  9186     // in mChildItems
  9187     newItem->mChildItems.SetParentHasNoXBLChildren(
  9188       aItems.ParentHasNoXBLChildren());
  9190     // Eat up all items between |iter| and |endIter| and put them in our wrapper
  9191     // Advances |iter| to point to |endIter|.
  9192     iter.AppendItemsToList(endIter, newItem->mChildItems);
  9194     iter.InsertItem(newItem);
  9196     // Now |iter| points to the item that was the first one we didn't wrap;
  9197     // loop and see whether we need to skip it or wrap it in something
  9198     // different.
  9199   } while (!iter.IsDone());
  9202 inline void
  9203 nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState,
  9204                                                    FrameConstructionItemList& aItems,
  9205                                                    nsIFrame* aParentFrame,
  9206                                                    nsFrameItems& aFrameItems)
  9208   CreateNeededTablePseudos(aState, aItems, aParentFrame);
  9209   CreateNeededAnonFlexItems(aState, aItems, aParentFrame);
  9211   aItems.SetTriedConstructingFrames();
  9212   for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
  9213     NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
  9214                  "Needed pseudos didn't get created; expect bad things");
  9215     ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
  9218   NS_ASSERTION(!aState.mHavePendingPopupgroup,
  9219                "Should have proccessed it by now");
  9222 void
  9223 nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
  9224             nsFrameConstructorState& aState,
  9225             nsIFrame* aFrame,
  9226             nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
  9227             FrameConstructionItemList& aItemsToConstruct,
  9228             uint32_t aExtraFlags)
  9230   for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) {
  9231     nsIContent* content = aAnonymousItems[i].mContent;
  9232 #ifdef DEBUG
  9233     nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame);
  9234     NS_ASSERTION(!creator || !creator->CreateFrameFor(content),
  9235                  "If you need to use CreateFrameFor, you need to call "
  9236                  "CreateAnonymousFrames manually and not follow the standard "
  9237                  "ProcessChildren() codepath for this frame");
  9238 #endif
  9239     // Assert some things about this content
  9240     NS_ABORT_IF_FALSE(!(content->GetFlags() &
  9241                         (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
  9242                       "Should not be marked as needing frames");
  9243     NS_ABORT_IF_FALSE(!content->IsElement() ||
  9244                       !(content->GetFlags() & ELEMENT_ALL_RESTYLE_FLAGS),
  9245                       "Should have no pending restyle flags");
  9246     NS_ABORT_IF_FALSE(!content->GetPrimaryFrame(),
  9247                       "Should have no existing frame");
  9248     NS_ABORT_IF_FALSE(!content->IsNodeOfType(nsINode::eCOMMENT) &&
  9249                       !content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION),
  9250                       "Why is someone creating garbage anonymous content");
  9252     nsRefPtr<nsStyleContext> styleContext;
  9253     TreeMatchContext::AutoFlexItemStyleFixupSkipper
  9254       flexItemStyleFixupSkipper(aState.mTreeMatchContext);
  9255     if (aAnonymousItems[i].mStyleContext) {
  9256       styleContext = aAnonymousItems[i].mStyleContext.forget();
  9257     } else {
  9258       styleContext = ResolveStyleContext(aFrame, content, &aState);
  9261     nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
  9262     if (!aAnonymousItems[i].mChildren.IsEmpty()) {
  9263       anonChildren = &aAnonymousItems[i].mChildren;
  9266     uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK |
  9267                      ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags;
  9269     AddFrameConstructionItemsInternal(aState, content, aFrame,
  9270                                       content->Tag(), content->GetNameSpaceID(),
  9271                                       true, styleContext, flags,
  9272                                       anonChildren, aItemsToConstruct);
  9276 void
  9277 nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
  9278                                        nsIContent*              aContent,
  9279                                        nsStyleContext*          aStyleContext,
  9280                                        nsIFrame*                aFrame,
  9281                                        const bool               aCanHaveGeneratedContent,
  9282                                        nsFrameItems&            aFrameItems,
  9283                                        const bool               aAllowBlockStyles,
  9284                                        PendingBinding*          aPendingBinding,
  9285                                        nsIFrame*                aPossiblyLeafFrame)
  9287   NS_PRECONDITION(aFrame, "Must have parent frame here");
  9288   NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
  9289                   "Parent frame in ProcessChildren should be its own "
  9290                   "content insertion frame");
  9291   const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
  9292   static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
  9293   AutoRestore<uint16_t> savedDepth(mCurrentDepth);
  9294   if (mCurrentDepth != UINT16_MAX) {
  9295     ++mCurrentDepth;
  9298   if (!aPossiblyLeafFrame) {
  9299     aPossiblyLeafFrame = aFrame;
  9302   // XXXbz ideally, this would do all the pushing of various
  9303   // containing blocks as needed, so callers don't have to do it...
  9305   bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
  9306   if (aAllowBlockStyles) {
  9307     ShouldHaveSpecialBlockStyle(aContent, aStyleContext, &haveFirstLetterStyle,
  9308                                 &haveFirstLineStyle);
  9311   // The logic here needs to match the logic in GetFloatContainingBlock()
  9312   nsFrameConstructorSaveState floatSaveState;
  9313   if (ShouldSuppressFloatingOfDescendants(aFrame)) {
  9314     aState.PushFloatContainingBlock(nullptr, floatSaveState);
  9315   } else if (aFrame->IsFloatContainingBlock()) {
  9316     aState.PushFloatContainingBlock(aFrame, floatSaveState);
  9319   nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
  9320                                                            aPendingBinding);
  9322   FrameConstructionItemList itemsToConstruct;
  9324   // If we have first-letter or first-line style then frames can get
  9325   // moved around so don't set these flags.
  9326   if (aAllowBlockStyles && !haveFirstLetterStyle && !haveFirstLineStyle) {
  9327     itemsToConstruct.SetLineBoundaryAtStart(true);
  9328     itemsToConstruct.SetLineBoundaryAtEnd(true);
  9331   // Create any anonymous frames we need here.  This must happen before the
  9332   // non-anonymous children are processed to ensure that popups are never
  9333   // constructed before the popupset.
  9334   nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
  9335   GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
  9336 #ifdef DEBUG
  9337   for (uint32_t i = 0; i < anonymousItems.Length(); ++i) {
  9338     NS_ABORT_IF_FALSE(anonymousItems[i].mContent->IsRootOfAnonymousSubtree(),
  9339                       "Content should know it's an anonymous subtree");
  9341 #endif
  9342   AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
  9343                                 itemsToConstruct);
  9345   if (!aPossiblyLeafFrame->IsLeaf()) {
  9346     // :before/:after content should have the same style context parent
  9347     // as normal kids.
  9348     // Note that we don't use this style context for looking up things like
  9349     // special block styles because in some cases involving table pseudo-frames
  9350     // it has nothing to do with the parent frame's desired behavior.
  9351     nsStyleContext* styleContext;
  9353     if (aCanHaveGeneratedContent) {
  9354       aFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
  9355       styleContext =
  9356         nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->StyleContext();
  9357       // Probe for generated content before
  9358       CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
  9359                                  nsCSSPseudoElements::ePseudo_before,
  9360                                  itemsToConstruct);
  9363     const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
  9364     if (!addChildItems) {
  9365       NS_WARNING("ProcessChildren max depth exceeded");
  9368     FlattenedChildIterator iter(aContent);
  9369     for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
  9370       // Get the parent of the content and check if it is a XBL children element
  9371       // (if the content is a children element then parent != aContent because the
  9372       // FlattenedChildIterator will transitively iterate through <xbl:children>
  9373       // for default content). Push the children element as an ancestor here because
  9374       // it does not have a frame and would not otherwise be pushed as an ancestor.
  9375       nsIContent* parent = child->GetParent();
  9376       MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
  9377       TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
  9378       if (parent != aContent && parent->IsElement()) {
  9379         if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
  9380           ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
  9381         } else {
  9382           ancestorPusher.PushStyleScope(parent->AsElement());
  9386       // Frame construction item construction should not post
  9387       // restyles, so removing restyle flags here is safe.
  9388       if (child->IsElement()) {
  9389         child->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
  9391       if (addChildItems) {
  9392         AddFrameConstructionItems(aState, child, iter.XBLInvolved(), aFrame,
  9393                                   itemsToConstruct);
  9394       } else {
  9395         ClearLazyBits(child, child->GetNextSibling());
  9398     itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
  9400     if (aCanHaveGeneratedContent) {
  9401       // Probe for generated content after
  9402       CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
  9403                                  nsCSSPseudoElements::ePseudo_after,
  9404                                  itemsToConstruct);
  9406   } else {
  9407     ClearLazyBits(aContent->GetFirstChild(), nullptr);
  9410   ConstructFramesFromItemList(aState, itemsToConstruct, aFrame, aFrameItems);
  9412   NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsBoxFrame(),
  9413                "can't be both block and box");
  9415   if (haveFirstLetterStyle) {
  9416     WrapFramesInFirstLetterFrame(aContent, aFrame, aFrameItems);
  9418   if (haveFirstLineStyle) {
  9419     WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr,
  9420                                aFrameItems);
  9423   // We might end up with first-line frames that change
  9424   // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
  9425   // should never happen for cases whan aFrame->IsBoxFrame().
  9426   NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsBoxFrame(),
  9427                "Shouldn't have first-line style if we're a box");
  9428   NS_ASSERTION(!aFrame->IsBoxFrame() ||
  9429                itemsToConstruct.AnyItemsNeedBlockParent() ==
  9430                  (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr),
  9431                "Something went awry in our block parent calculations");
  9433   if (aFrame->IsBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
  9434     // XXXbz we could do this on the FrameConstructionItemList level,
  9435     // no?  And if we cared we could look through the item list
  9436     // instead of groveling through the framelist here..
  9437     nsStyleContext *frameStyleContext = aFrame->StyleContext();
  9438     // Report a warning for non-GC frames, for chrome:
  9439     if (!aFrame->IsGeneratedContentFrame() &&
  9440         mPresShell->GetPresContext()->IsChrome()) {
  9441       nsIContent *badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild());
  9442       nsDependentAtomString parentTag(aContent->Tag()), kidTag(badKid->Tag());
  9443       const char16_t* params[] = { parentTag.get(), kidTag.get() };
  9444       const nsStyleDisplay *display = frameStyleContext->StyleDisplay();
  9445       const char *message =
  9446         (display->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX)
  9447           ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
  9448       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  9449                                       NS_LITERAL_CSTRING("FrameConstructor"),
  9450                                       mDocument,
  9451                                       nsContentUtils::eXUL_PROPERTIES,
  9452                                       message,
  9453                                       params, ArrayLength(params));
  9456     nsRefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()->
  9457       ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock,
  9458                                frameStyleContext);
  9459     nsIFrame *blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
  9460     // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
  9461     // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
  9462     // a real block placed here wouldn't get those set on it.
  9464     InitAndRestoreFrame(aState, aContent, aFrame, blockFrame, false);
  9466     NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
  9467     ReparentFrames(this, blockFrame, aFrameItems);
  9469     blockFrame->SetInitialChildList(kPrincipalList, aFrameItems);
  9470     NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?");
  9471     aFrameItems.Clear();
  9472     aFrameItems.AddChild(blockFrame);
  9474     aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
  9478 //----------------------------------------------------------------------
  9480 // Support for :first-line style
  9482 // Special routine to handle placing a list of frames into a block
  9483 // frame that has first-line style. The routine ensures that the first
  9484 // collection of inline frames end up in a first-line frame.
  9485 // NOTE: aState may have containing block information related to a
  9486 // different part of the frame tree than where the first line occurs.
  9487 // In particular aState may be set up for where ContentInserted or
  9488 // ContentAppended is inserting content, which may be some
  9489 // non-first-in-flow continuation of the block to which the first-line
  9490 // belongs. So this function needs to be careful about how it uses
  9491 // aState.
  9492 void
  9493 nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
  9494   nsFrameConstructorState& aState,
  9495   nsIContent*              aBlockContent,
  9496   nsIFrame*                aBlockFrame,
  9497   nsIFrame*                aLineFrame,
  9498   nsFrameItems&            aFrameItems)
  9500   // Find the part of aFrameItems that we want to put in the first-line
  9501   nsFrameList::FrameLinkEnumerator link(aFrameItems);
  9502   while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) {
  9503     link.Next();
  9506   nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
  9508   if (firstLineChildren.IsEmpty()) {
  9509     // Nothing is supposed to go into the first-line; nothing to do
  9510     return;
  9513   if (!aLineFrame) {
  9514     // Create line frame
  9515     nsStyleContext* parentStyle =
  9516       nsFrame::CorrectStyleParentFrame(aBlockFrame,
  9517                                        nsCSSPseudoElements::firstLine)->
  9518         StyleContext();
  9519     nsRefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent,
  9520                                                                 parentStyle);
  9522     aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
  9524     // Initialize the line frame
  9525     InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
  9527     // The lineFrame will be the block's first child; the rest of the
  9528     // frame list (after lastInlineFrame) will be the second and
  9529     // subsequent children; insert lineFrame into aFrameItems.
  9530     aFrameItems.InsertFrame(nullptr, nullptr, aLineFrame);
  9532     NS_ASSERTION(aLineFrame->StyleContext() == firstLineStyle,
  9533                  "Bogus style context on line frame");
  9536   // Give the inline frames to the lineFrame <b>after</b> reparenting them
  9537   ReparentFrames(this, aLineFrame, firstLineChildren);
  9538   if (aLineFrame->PrincipalChildList().IsEmpty() &&
  9539       (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  9540     aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren);
  9541   } else {
  9542     AppendFrames(aLineFrame, kPrincipalList, firstLineChildren);
  9546 // Special routine to handle appending a new frame to a block frame's
  9547 // child list. Takes care of placing the new frame into the right
  9548 // place when first-line style is present.
  9549 void
  9550 nsCSSFrameConstructor::AppendFirstLineFrames(
  9551   nsFrameConstructorState& aState,
  9552   nsIContent*              aBlockContent,
  9553   nsIFrame*                aBlockFrame,
  9554   nsFrameItems&            aFrameItems)
  9556   // It's possible that aBlockFrame needs to have a first-line frame
  9557   // created because it doesn't currently have any children.
  9558   const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
  9559   if (blockKids.IsEmpty()) {
  9560     WrapFramesInFirstLineFrame(aState, aBlockContent,
  9561                                aBlockFrame, nullptr, aFrameItems);
  9562     return;
  9565   // Examine the last block child - if it's a first-line frame then
  9566   // appended frames need special treatment.
  9567   nsIFrame* lastBlockKid = blockKids.LastChild();
  9568   if (lastBlockKid->GetType() != nsGkAtoms::lineFrame) {
  9569     // No first-line frame at the end of the list, therefore there is
  9570     // an intervening block between any first-line frame the frames
  9571     // we are appending. Therefore, we don't need any special
  9572     // treatment of the appended frames.
  9573     return;
  9576   WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame,
  9577                              lastBlockKid, aFrameItems);
  9580 // Special routine to handle inserting a new frame into a block
  9581 // frame's child list. Takes care of placing the new frame into the
  9582 // right place when first-line style is present.
  9583 nsresult
  9584 nsCSSFrameConstructor::InsertFirstLineFrames(
  9585   nsFrameConstructorState& aState,
  9586   nsIContent*              aContent,
  9587   nsIFrame*                aBlockFrame,
  9588   nsIFrame**               aParentFrame,
  9589   nsIFrame*                aPrevSibling,
  9590   nsFrameItems&            aFrameItems)
  9592   nsresult rv = NS_OK;
  9593   // XXXbz If you make this method actually do something, check to
  9594   // make sure that the caller is passing what you expect.  In
  9595   // particular, which content is aContent?  And audit the rest of
  9596   // this code too; it makes bogus assumptions and may not build.
  9597 #if 0
  9598   nsIFrame* parentFrame = *aParentFrame;
  9599   nsIFrame* newFrame = aFrameItems.childList;
  9600   bool isInline = IsInlineOutside(newFrame);
  9602   if (!aPrevSibling) {
  9603     // Insertion will become the first frame. Two cases: we either
  9604     // already have a first-line frame or we don't.
  9605     nsIFrame* firstBlockKid = aBlockFrame->GetFirstPrincipalChild();
  9606     if (firstBlockKid->GetType() == nsGkAtoms::lineFrame) {
  9607       // We already have a first-line frame
  9608       nsIFrame* lineFrame = firstBlockKid;
  9610       if (isInline) {
  9611         // Easy case: the new inline frame will go into the lineFrame.
  9612         ReparentFrame(this, lineFrame, newFrame);
  9613         InsertFrames(lineFrame, kPrincipalList, nullptr, newFrame);
  9615         // Since the frame is going into the lineFrame, don't let it
  9616         // go into the block too.
  9617         aFrameItems.childList = nullptr;
  9618         aFrameItems.lastChild = nullptr;
  9620       else {
  9621         // Harder case: We are about to insert a block level element
  9622         // before the first-line frame.
  9623         // XXX need a method to steal away frames from the line-frame
  9626     else {
  9627       // We do not have a first-line frame
  9628       if (isInline) {
  9629         // We now need a first-line frame to contain the inline frame.
  9630         nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle);
  9632         if (NS_SUCCEEDED(rv)) {
  9633           // Lookup first-line style context
  9634           nsStyleContext* parentStyle =
  9635             nsFrame::CorrectStyleParentFrame(aBlockFrame,
  9636                                              nsCSSPseudoElements::firstLine)->
  9637               StyleContext();
  9638           nsRefPtr<nsStyleContext> firstLineStyle =
  9639             GetFirstLineStyle(aContent, parentStyle);
  9641           // Initialize the line frame
  9642           InitAndRestoreFrame(aState, aContent, aBlockFrame, lineFrame);
  9644           // Make sure the caller inserts the lineFrame into the
  9645           // blocks list of children.
  9646           aFrameItems.childList = lineFrame;
  9647           aFrameItems.lastChild = lineFrame;
  9649           // Give the inline frames to the lineFrame <b>after</b>
  9650           // reparenting them
  9651           NS_ASSERTION(lineFrame->StyleContext() == firstLineStyle,
  9652                        "Bogus style context on line frame");
  9653           ReparentFrame(aPresContext, lineFrame, newFrame);
  9654           lineFrame->SetInitialChildList(kPrincipalList, newFrame);
  9657       else {
  9658         // Easy case: the regular insertion logic can insert the new
  9659         // frame because it's a block frame.
  9663   else {
  9664     // Insertion will not be the first frame.
  9665     nsIFrame* prevSiblingParent = aPrevSibling->GetParent();
  9666     if (prevSiblingParent == aBlockFrame) {
  9667       // Easy case: The prev-siblings parent is the block
  9668       // frame. Therefore the prev-sibling is not currently in a
  9669       // line-frame. Therefore the new frame which is going after it,
  9670       // regardless of type, is not going into a line-frame.
  9672     else {
  9673       // If the prevSiblingParent is not the block-frame then it must
  9674       // be a line-frame (if it were a letter-frame, that logic would
  9675       // already have adjusted the prev-sibling to be the
  9676       // letter-frame).
  9677       if (isInline) {
  9678         // Easy case: the insertion can go where the caller thinks it
  9679         // should go (which is into prevSiblingParent).
  9681       else {
  9682         // Block elements don't end up in line-frames, therefore
  9683         // change the insertion point to aBlockFrame. However, there
  9684         // might be more inline elements following aPrevSibling that
  9685         // need to be pulled out of the line-frame and become children
  9686         // of the block.
  9687         nsIFrame* nextSibling = aPrevSibling->GetNextSibling();
  9688         nsIFrame* nextLineFrame = prevSiblingParent->GetNextInFlow();
  9689         if (nextSibling || nextLineFrame) {
  9690           // Oy. We have work to do. Create a list of the new frames
  9691           // that are going into the block by stripping them away from
  9692           // the line-frame(s).
  9693           if (nextSibling) {
  9694             nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent;
  9695             nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling);
  9696             // XXX do something with 'tail'
  9699           nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame;
  9700           for (;;) {
  9701             nextLineFrame = nextLineFrame->GetNextInFlow();
  9702             if (!nextLineFrame) {
  9703               break;
  9705             nsIFrame* kids = nextLineFrame->GetFirstPrincipalChild();
  9708         else {
  9709           // We got lucky: aPrevSibling was the last inline frame in
  9710           // the line-frame.
  9711           ReparentFrame(this, aBlockFrame, newFrame);
  9712           InsertFrames(aBlockFrame, kPrincipalList,
  9713                        prevSiblingParent, newFrame);
  9714           aFrameItems.childList = nullptr;
  9715           aFrameItems.lastChild = nullptr;
  9721 #endif
  9722   return rv;
  9725 //----------------------------------------------------------------------
  9727 // First-letter support
  9729 // Determine how many characters in the text fragment apply to the
  9730 // first letter
  9731 static int32_t
  9732 FirstLetterCount(const nsTextFragment* aFragment)
  9734   int32_t count = 0;
  9735   int32_t firstLetterLength = 0;
  9737   int32_t i, n = aFragment->GetLength();
  9738   for (i = 0; i < n; i++) {
  9739     char16_t ch = aFragment->CharAt(i);
  9740     // FIXME: take content language into account when deciding whitespace.
  9741     if (dom::IsSpaceCharacter(ch)) {
  9742       if (firstLetterLength) {
  9743         break;
  9745       count++;
  9746       continue;
  9748     // XXX I18n
  9749     if ((ch == '\'') || (ch == '\"')) {
  9750       if (firstLetterLength) {
  9751         break;
  9753       // keep looping
  9754       firstLetterLength = 1;
  9756     else {
  9757       count++;
  9758       break;
  9762   return count;
  9765 static bool
  9766 NeedFirstLetterContinuation(nsIContent* aContent)
  9768   NS_PRECONDITION(aContent, "null ptr");
  9770   bool result = false;
  9771   if (aContent) {
  9772     const nsTextFragment* frag = aContent->GetText();
  9773     if (frag) {
  9774       int32_t flc = FirstLetterCount(frag);
  9775       int32_t tl = frag->GetLength();
  9776       if (flc < tl) {
  9777         result = true;
  9781   return result;
  9784 static bool IsFirstLetterContent(nsIContent* aContent)
  9786   return aContent->TextLength() &&
  9787          !aContent->TextIsOnlyWhitespace();
  9790 /**
  9791  * Create a letter frame, only make it a floating frame.
  9792  */
  9793 void
  9794 nsCSSFrameConstructor::CreateFloatingLetterFrame(
  9795   nsFrameConstructorState& aState,
  9796   nsIFrame* aBlockFrame,
  9797   nsIContent* aTextContent,
  9798   nsIFrame* aTextFrame,
  9799   nsIContent* aBlockContent,
  9800   nsIFrame* aParentFrame,
  9801   nsStyleContext* aStyleContext,
  9802   nsFrameItems& aResult)
  9804   // Create the first-letter-frame
  9805   nsIFrame* letterFrame;
  9806   nsStyleSet *styleSet = mPresShell->StyleSet();
  9808   letterFrame = NS_NewFirstLetterFrame(mPresShell, aStyleContext);
  9809   // We don't want to use a text content for a non-text frame (because we want
  9810   // its primary frame to be a text frame).  So use its parent for the
  9811   // first-letter.
  9812   nsIContent* letterContent = aTextContent->GetParent();
  9813   nsIFrame* containingBlock = aState.GetGeometricParent(
  9814     aStyleContext->StyleDisplay(), aParentFrame);
  9815   InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
  9817   // Init the text frame to refer to the letter frame. Make sure we
  9818   // get a proper style context for it (the one passed in is for the
  9819   // letter frame and will have the float property set on it; the text
  9820   // frame shouldn't have that set).
  9821   nsRefPtr<nsStyleContext> textSC;
  9822   textSC = styleSet->ResolveStyleForNonElement(aStyleContext);
  9823   aTextFrame->SetStyleContextWithoutNotification(textSC);
  9824   InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
  9826   // And then give the text frame to the letter frame
  9827   SetInitialSingleChild(letterFrame, aTextFrame);
  9829   // See if we will need to continue the text frame (does it contain
  9830   // more than just the first-letter text or not?) If it does, then we
  9831   // create (in advance) a continuation frame for it.
  9832   nsIFrame* nextTextFrame = nullptr;
  9833   if (NeedFirstLetterContinuation(aTextContent)) {
  9834     // Create continuation
  9835     nextTextFrame =
  9836       CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame);
  9837     // Repair the continuations style context
  9838     nsStyleContext* parentStyleContext = aStyleContext->GetParent();
  9839     if (parentStyleContext) {
  9840       nsRefPtr<nsStyleContext> newSC;
  9841       newSC = styleSet->ResolveStyleForNonElement(parentStyleContext);
  9842       nextTextFrame->SetStyleContext(newSC);
  9846   NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
  9847   // Put the new float before any of the floats in the block we're doing
  9848   // first-letter for, that is, before any floats whose parent is
  9849   // containingBlock.
  9850   nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
  9851   while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) {
  9852     link.Next();
  9855   aState.AddChild(letterFrame, aResult, letterContent, aStyleContext,
  9856                   aParentFrame, false, true, false, true,
  9857                   link.PrevFrame());
  9859   if (nextTextFrame) {
  9860     aResult.AddChild(nextTextFrame);
  9864 /**
  9865  * Create a new letter frame for aTextFrame. The letter frame will be
  9866  * a child of aParentFrame.
  9867  */
  9868 void
  9869 nsCSSFrameConstructor::CreateLetterFrame(nsIFrame* aBlockFrame,
  9870                                          nsIFrame* aBlockContinuation,
  9871                                          nsIContent* aTextContent,
  9872                                          nsIFrame* aParentFrame,
  9873                                          nsFrameItems& aResult)
  9875   NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT),
  9876                   "aTextContent isn't text");
  9877   NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
  9878                  "Not a block frame?");
  9880   // Get style context for the first-letter-frame
  9881   nsStyleContext* parentStyleContext =
  9882     nsFrame::CorrectStyleParentFrame(aParentFrame,
  9883                                      nsCSSPseudoElements::firstLetter)->
  9884       StyleContext();
  9886   // Use content from containing block so that we can actually
  9887   // find a matching style rule.
  9888   nsIContent* blockContent = aBlockFrame->GetContent();
  9890   // Create first-letter style rule
  9891   nsRefPtr<nsStyleContext> sc = GetFirstLetterStyle(blockContent,
  9892                                                     parentStyleContext);
  9893   if (sc) {
  9894     nsRefPtr<nsStyleContext> textSC;
  9895     textSC = mPresShell->StyleSet()->ResolveStyleForNonElement(sc);
  9897     // Create a new text frame (the original one will be discarded)
  9898     // pass a temporary stylecontext, the correct one will be set
  9899     // later.  Start off by unsetting the primary frame for
  9900     // aTextContent, so it's no longer pointing to the to-be-destroyed
  9901     // frame.
  9902     // XXXbz it would be really nice to destroy the old frame _first_,
  9903     // then create the new one, so we could avoid this hack.
  9904     aTextContent->SetPrimaryFrame(nullptr);
  9905     nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
  9907     NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
  9908                  "Containing block is confused");
  9909     nsFrameConstructorState state(mPresShell,
  9910                                   GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
  9911                                   GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
  9912                                   aBlockContinuation);
  9914     // Create the right type of first-letter frame
  9915     const nsStyleDisplay* display = sc->StyleDisplay();
  9916     if (display->IsFloatingStyle() && !aParentFrame->IsSVGText()) {
  9917       // Make a floating first-letter frame
  9918       CreateFloatingLetterFrame(state, aBlockFrame, aTextContent, textFrame,
  9919                                 blockContent, aParentFrame, sc, aResult);
  9921     else {
  9922       // Make an inflow first-letter frame
  9923       nsIFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
  9925       // Initialize the first-letter-frame.  We don't want to use a text
  9926       // content for a non-text frame (because we want its primary frame to
  9927       // be a text frame).  So use its parent for the first-letter.
  9928       nsIContent* letterContent = aTextContent->GetParent();
  9929       letterFrame->Init(letterContent, aParentFrame, nullptr);
  9931       InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
  9933       SetInitialSingleChild(letterFrame, textFrame);
  9934       aResult.Clear();
  9935       aResult.AddChild(letterFrame);
  9936       NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
  9937                    "should have the first continuation here");
  9938       aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
  9940     aTextContent->SetPrimaryFrame(textFrame);
  9944 void
  9945 nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
  9946   nsIContent*              aBlockContent,
  9947   nsIFrame*                aBlockFrame,
  9948   nsFrameItems&            aBlockFrames)
  9950   aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
  9952   nsIFrame* parentFrame = nullptr;
  9953   nsIFrame* textFrame = nullptr;
  9954   nsIFrame* prevFrame = nullptr;
  9955   nsFrameItems letterFrames;
  9956   bool stopLooking = false;
  9957   WrapFramesInFirstLetterFrame(aBlockFrame, aBlockFrame, aBlockFrame,
  9958                                aBlockFrames.FirstChild(),
  9959                                &parentFrame, &textFrame, &prevFrame,
  9960                                letterFrames, &stopLooking);
  9961   if (parentFrame) {
  9962     if (parentFrame == aBlockFrame) {
  9963       // Take textFrame out of the block's frame list and substitute the
  9964       // letter frame(s) instead.
  9965       aBlockFrames.DestroyFrame(textFrame);
  9966       aBlockFrames.InsertFrames(nullptr, prevFrame, letterFrames);
  9968     else {
  9969       // Take the old textFrame out of the inline parent's child list
  9970       RemoveFrame(kPrincipalList, textFrame);
  9972       // Insert in the letter frame(s)
  9973       parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
  9978 void
  9979 nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
  9980   nsIFrame*                aBlockFrame,
  9981   nsIFrame*                aBlockContinuation,
  9982   nsIFrame*                aParentFrame,
  9983   nsIFrame*                aParentFrameList,
  9984   nsIFrame**               aModifiedParent,
  9985   nsIFrame**               aTextFrame,
  9986   nsIFrame**               aPrevFrame,
  9987   nsFrameItems&            aLetterFrames,
  9988   bool*                  aStopLooking)
  9990   nsIFrame* prevFrame = nullptr;
  9991   nsIFrame* frame = aParentFrameList;
  9993   while (frame) {
  9994     nsIFrame* nextFrame = frame->GetNextSibling();
  9996     nsIAtom* frameType = frame->GetType();
  9997     if (nsGkAtoms::textFrame == frameType) {
  9998       // Wrap up first-letter content in a letter frame
  9999       nsIContent* textContent = frame->GetContent();
 10000       if (IsFirstLetterContent(textContent)) {
 10001         // Create letter frame to wrap up the text
 10002         CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
 10003                           aParentFrame, aLetterFrames);
 10005         // Provide adjustment information for parent
 10006         *aModifiedParent = aParentFrame;
 10007         *aTextFrame = frame;
 10008         *aPrevFrame = prevFrame;
 10009         *aStopLooking = true;
 10010         return;
 10013     else if (IsInlineFrame(frame) && frameType != nsGkAtoms::brFrame) {
 10014       nsIFrame* kids = frame->GetFirstPrincipalChild();
 10015       WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation, frame,
 10016                                    kids, aModifiedParent, aTextFrame,
 10017                                    aPrevFrame, aLetterFrames, aStopLooking);
 10018       if (*aStopLooking) {
 10019         return;
 10022     else {
 10023       // This will stop us looking to create more letter frames. For
 10024       // example, maybe the frame-type is "letterFrame" or
 10025       // "placeholderFrame". This keeps us from creating extra letter
 10026       // frames, and also prevents us from creating letter frames when
 10027       // the first real content child of a block is not text (e.g. an
 10028       // image, hr, etc.)
 10029       *aStopLooking = true;
 10030       break;
 10033     prevFrame = frame;
 10034     frame = nextFrame;
 10038 static nsIFrame*
 10039 FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID)
 10041   nsFrameList list = aFrame->GetChildList(aListID);
 10042   for (nsFrameList::Enumerator e(list); !e.AtEnd(); e.Next()) {
 10043     if (nsGkAtoms::letterFrame == e.get()->GetType()) {
 10044       return e.get();
 10047   return nullptr;
 10050 nsresult
 10051 nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
 10052   nsPresContext* aPresContext,
 10053   nsIPresShell* aPresShell,
 10054   nsIFrame* aBlockFrame,
 10055   bool* aStopLooking)
 10057   // Look for the first letter frame on the kFloatList, then kPushedFloatsList.
 10058   nsIFrame* floatFrame =
 10059     ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kFloatList);
 10060   if (!floatFrame) {
 10061     floatFrame =
 10062       ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList);
 10063     if (!floatFrame) {
 10064       return NS_OK;
 10068   // Take the text frame away from the letter frame (so it isn't
 10069   // destroyed when we destroy the letter frame).
 10070   nsIFrame* textFrame = floatFrame->GetFirstPrincipalChild();
 10071   if (!textFrame) {
 10072     return NS_OK;
 10075   // Discover the placeholder frame for the letter frame
 10076   nsIFrame* parentFrame;
 10077   nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame);
 10079   if (!placeholderFrame) {
 10080     // Somethings really wrong
 10081     return NS_OK;
 10083   parentFrame = placeholderFrame->GetParent();
 10084   if (!parentFrame) {
 10085     // Somethings really wrong
 10086     return NS_OK;
 10089   // Create a new text frame with the right style context that maps
 10090   // all of the content that was previously part of the letter frame
 10091   // (and probably continued elsewhere).
 10092   nsStyleContext* parentSC = parentFrame->StyleContext();
 10093   nsIContent* textContent = textFrame->GetContent();
 10094   if (!textContent) {
 10095     return NS_OK;
 10097   nsRefPtr<nsStyleContext> newSC;
 10098   newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
 10099   nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
 10100   newTextFrame->Init(textContent, parentFrame, nullptr);
 10102   // Destroy the old text frame's continuations (the old text frame
 10103   // will be destroyed when its letter frame is destroyed).
 10104   nsIFrame* frameToDelete = textFrame->LastContinuation();
 10105   while (frameToDelete != textFrame) {
 10106     nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
 10107     RemoveFrame(kPrincipalList, frameToDelete);
 10108     frameToDelete = nextFrameToDelete;
 10111   nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
 10113   // Now that everything is set...
 10114 #ifdef NOISY_FIRST_LETTER
 10115   printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
 10116          textContent.get(), textFrame, newTextFrame);
 10117 #endif
 10119   // Remove placeholder frame and the float
 10120   RemoveFrame(kPrincipalList, placeholderFrame);
 10122   // Now that the old frames are gone, we can start pointing to our
 10123   // new primary frame.
 10124   textContent->SetPrimaryFrame(newTextFrame);
 10126   // Wallpaper bug 822910.
 10127   bool offsetsNeedFixing =
 10128     prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame;
 10129   if (offsetsNeedFixing) {
 10130     prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
 10133   // Insert text frame in its place
 10134   nsFrameList textList(newTextFrame, newTextFrame);
 10135   InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
 10137   if (offsetsNeedFixing) {
 10138     prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
 10141   return NS_OK;
 10144 nsresult
 10145 nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext,
 10146                                                nsIPresShell* aPresShell,
 10147                                                nsIFrame* aFrame,
 10148                                                nsIFrame* aBlockFrame,
 10149                                                bool* aStopLooking)
 10151   nsIFrame* prevSibling = nullptr;
 10152   nsIFrame* kid = aFrame->GetFirstPrincipalChild();
 10154   while (kid) {
 10155     if (nsGkAtoms::letterFrame == kid->GetType()) {
 10156       // Bingo. Found it. First steal away the text frame.
 10157       nsIFrame* textFrame = kid->GetFirstPrincipalChild();
 10158       if (!textFrame) {
 10159         break;
 10162       // Create a new textframe
 10163       nsStyleContext* parentSC = aFrame->StyleContext();
 10164       if (!parentSC) {
 10165         break;
 10167       nsIContent* textContent = textFrame->GetContent();
 10168       if (!textContent) {
 10169         break;
 10171       nsRefPtr<nsStyleContext> newSC;
 10172       newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
 10173       textFrame = NS_NewTextFrame(aPresShell, newSC);
 10174       textFrame->Init(textContent, aFrame, nullptr);
 10176       // Next rip out the kid and replace it with the text frame
 10177       RemoveFrame(kPrincipalList, kid);
 10179       // Now that the old frames are gone, we can start pointing to our
 10180       // new primary frame.
 10181       textContent->SetPrimaryFrame(textFrame);
 10183       // Wallpaper bug 822910.
 10184       bool offsetsNeedFixing =
 10185         prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame;
 10186       if (offsetsNeedFixing) {
 10187         prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
 10190       // Insert text frame in its place
 10191       nsFrameList textList(textFrame, textFrame);
 10192       InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
 10194       if (offsetsNeedFixing) {
 10195         prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
 10198       *aStopLooking = true;
 10199       NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
 10200                    "should have the first continuation here");
 10201       aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
 10202       break;
 10204     else if (IsInlineFrame(kid)) {
 10205       // Look inside child inline frame for the letter frame
 10206       RemoveFirstLetterFrames(aPresContext, aPresShell,
 10207                               kid, aBlockFrame, aStopLooking);
 10208       if (*aStopLooking) {
 10209         break;
 10212     prevSibling = kid;
 10213     kid = kid->GetNextSibling();
 10216   return NS_OK;
 10219 nsresult
 10220 nsCSSFrameConstructor::RemoveLetterFrames(nsPresContext* aPresContext,
 10221                                           nsIPresShell* aPresShell,
 10222                                           nsIFrame* aBlockFrame)
 10224   aBlockFrame = aBlockFrame->FirstContinuation();
 10225   nsIFrame* continuation = aBlockFrame;
 10227   bool stopLooking = false;
 10228   nsresult rv;
 10229   do {
 10230     rv = RemoveFloatingFirstLetterFrames(aPresContext, aPresShell,
 10231                                          continuation, &stopLooking);
 10232     if (NS_SUCCEEDED(rv) && !stopLooking) {
 10233       rv = RemoveFirstLetterFrames(aPresContext, aPresShell,
 10234                                    continuation, aBlockFrame, &stopLooking);
 10236     if (stopLooking) {
 10237       break;
 10239     continuation = continuation->GetNextContinuation();
 10240   }  while (continuation);
 10241   return rv;
 10244 // Fixup the letter frame situation for the given block
 10245 void
 10246 nsCSSFrameConstructor::RecoverLetterFrames(nsIFrame* aBlockFrame)
 10248   aBlockFrame = aBlockFrame->FirstContinuation();
 10249   nsIFrame* continuation = aBlockFrame;
 10251   nsIFrame* parentFrame = nullptr;
 10252   nsIFrame* textFrame = nullptr;
 10253   nsIFrame* prevFrame = nullptr;
 10254   nsFrameItems letterFrames;
 10255   bool stopLooking = false;
 10256   do {
 10257     // XXX shouldn't this bit be set already (bug 408493), assert instead?
 10258     continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
 10259     WrapFramesInFirstLetterFrame(aBlockFrame, continuation, continuation,
 10260                                  continuation->GetFirstPrincipalChild(),
 10261                                  &parentFrame, &textFrame, &prevFrame,
 10262                                  letterFrames, &stopLooking);
 10263     if (stopLooking) {
 10264       break;
 10266     continuation = continuation->GetNextContinuation();
 10267   } while (continuation);
 10269   if (parentFrame) {
 10270     // Take the old textFrame out of the parents child list
 10271     RemoveFrame(kPrincipalList, textFrame);
 10273     // Insert in the letter frame(s)
 10274     parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
 10278 //----------------------------------------------------------------------
 10280 // listbox Widget Routines
 10282 nsresult
 10283 nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext,
 10284                                             nsIFrame*       aParentFrame,
 10285                                             nsIFrame*       aPrevFrame,
 10286                                             nsIContent*     aChild,
 10287                                             nsIFrame**      aNewFrame,
 10288                                             bool            aIsAppend,
 10289                                             bool            aIsScrollbar,
 10290                                             nsILayoutHistoryState* aFrameState)
 10292 #ifdef MOZ_XUL
 10293   nsresult rv = NS_OK;
 10295   // Construct a new frame
 10296   if (nullptr != aParentFrame) {
 10297     nsFrameItems            frameItems;
 10298     nsFrameConstructorState state(mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
 10299                                   GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
 10300                                   GetFloatContainingBlock(aParentFrame),
 10301                                   mTempFrameTreeState);
 10303     // If we ever initialize the ancestor filter on |state|, make sure
 10304     // to push the right parent!
 10306     nsRefPtr<nsStyleContext> styleContext;
 10307     styleContext = ResolveStyleContext(aParentFrame, aChild, &state);
 10309     // Pre-check for display "none" - only if we find that, do we create
 10310     // any frame at all
 10311     const nsStyleDisplay* display = styleContext->StyleDisplay();
 10313     if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
 10314       *aNewFrame = nullptr;
 10315       return NS_OK;
 10318     BeginUpdate();
 10320     FrameConstructionItemList items;
 10321     AddFrameConstructionItemsInternal(state, aChild, aParentFrame,
 10322                                       aChild->Tag(), aChild->GetNameSpaceID(),
 10323                                       true, styleContext,
 10324                                       ITEM_ALLOW_XBL_BASE, nullptr, items);
 10325     ConstructFramesFromItemList(state, items, aParentFrame, frameItems);
 10327     nsIFrame* newFrame = frameItems.FirstChild();
 10328     *aNewFrame = newFrame;
 10330     if (newFrame) {
 10331       // Notify the parent frame
 10332       if (aIsAppend)
 10333         rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
 10334       else
 10335         rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
 10338     EndUpdate();
 10340 #ifdef ACCESSIBILITY
 10341     if (newFrame) {
 10342       nsAccessibilityService* accService = nsIPresShell::AccService();
 10343       if (accService) {
 10344         accService->ContentRangeInserted(mPresShell, aChild->GetParent(),
 10345                                          aChild, aChild->GetNextSibling());
 10348 #endif
 10351   return rv;
 10352 #else
 10353   return NS_ERROR_FAILURE;
 10354 #endif
 10357 //----------------------------------------
 10359 void
 10360 nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
 10361                                       const nsStyleDisplay*    aDisplay,
 10362                                       nsIContent*              aContent,
 10363                                       nsIFrame*                aParentFrame,
 10364                                       nsIFrame*                aContentParentFrame,
 10365                                       nsStyleContext*          aStyleContext,
 10366                                       nsIFrame**               aNewFrame,
 10367                                       nsFrameItems&            aFrameItems,
 10368                                       nsIFrame*                aPositionedFrameForAbsPosContainer,
 10369                                       PendingBinding*          aPendingBinding)
 10371   // Create column wrapper if necessary
 10372   nsIFrame* blockFrame = *aNewFrame;
 10373   NS_ASSERTION(blockFrame->GetType() == nsGkAtoms::blockFrame, "not a block frame?");
 10374   nsIFrame* parent = aParentFrame;
 10375   nsRefPtr<nsStyleContext> blockStyle = aStyleContext;
 10376   const nsStyleColumn* columns = aStyleContext->StyleColumn();
 10378   if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO
 10379       || columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
 10380     nsIFrame* columnSetFrame = nullptr;
 10381     columnSetFrame =
 10382       NS_NewColumnSetFrame(mPresShell, aStyleContext, nsFrameState(0));
 10384     InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
 10385     blockStyle = mPresShell->StyleSet()->
 10386       ResolveAnonymousBoxStyle(nsCSSAnonBoxes::columnContent, aStyleContext);
 10387     parent = columnSetFrame;
 10388     *aNewFrame = columnSetFrame;
 10390     SetInitialSingleChild(columnSetFrame, blockFrame);
 10393   blockFrame->SetStyleContextWithoutNotification(blockStyle);
 10394   InitAndRestoreFrame(aState, aContent, parent, blockFrame);
 10396   aState.AddChild(*aNewFrame, aFrameItems, aContent, aStyleContext,
 10397                   aContentParentFrame ? aContentParentFrame :
 10398                                         aParentFrame);
 10399   if (!mRootElementFrame) {
 10400     // The frame we're constructing will be the root element frame.
 10401     // Set mRootElementFrame before processing children.
 10402     mRootElementFrame = *aNewFrame;
 10405   // We should make the outer frame be the absolute containing block,
 10406   // if one is required. We have to do this because absolute
 10407   // positioning must be computed with respect to the CSS dimensions
 10408   // of the element, which are the dimensions of the outer block. But
 10409   // we can't really do that because only blocks can have absolute
 10410   // children. So use the block and try to compensate with hacks
 10411   // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
 10412   nsFrameConstructorSaveState absoluteSaveState;
 10413   (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
 10414   if (aPositionedFrameForAbsPosContainer) {
 10415     //    NS_ASSERTION(aRelPos, "should have made area frame for this");
 10416     aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
 10419   // Process the child content
 10420   nsFrameItems childItems;
 10421   ProcessChildren(aState, aContent, aStyleContext, blockFrame, true,
 10422                   childItems, true, aPendingBinding);
 10424   // Set the frame's initial child list
 10425   blockFrame->SetInitialChildList(kPrincipalList, childItems);
 10428 nsIFrame*
 10429 nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
 10430                                        FrameConstructionItem&   aItem,
 10431                                        nsIFrame*                aParentFrame,
 10432                                        const nsStyleDisplay*    aDisplay,
 10433                                        nsFrameItems&            aFrameItems)
 10435   // If an inline frame has non-inline kids, then we chop up the child list
 10436   // into runs of blocks and runs of inlines, create anonymous block frames to
 10437   // contain the runs of blocks, inline frames with our style context for the
 10438   // runs of inlines, and put all these frames, in order, into aFrameItems.  We
 10439   // return the the first one.  The whole setup is called an {ib}
 10440   // split; in what follows "frames in the split" refers to the anonymous blocks
 10441   // and inlines that contain our children.
 10442   //
 10443   // {ib} splits maintain the following invariants:
 10444   // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
 10445   //    set.
 10446   // 2) Each frame in the split has the nsIFrame::IBSplitSibling
 10447   //    property pointing to the next frame in the split, except for the last
 10448   //    one, which does not have it set.
 10449   // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
 10450   //    property pointing to the previous frame in the split, except for the
 10451   //    first one, which does not have it set.
 10452   // 4) The first and last frame in the split are always inlines.
 10453   //
 10454   // An invariant that is NOT maintained is that the wrappers are actually
 10455   // linked via GetNextSibling linkage.  A simple example is an inline
 10456   // containing an inline that contains a block.  The three parts of the inner
 10457   // inline end up with three different parents.
 10458   //
 10459   // For example, this HTML:
 10460   // <span>
 10461   //   <div>a</div>
 10462   //   <span>
 10463   //     b
 10464   //     <div>c</div>
 10465   //   </span>
 10466   //   d
 10467   //   <div>e</div>
 10468   //   f
 10469   //  </span>
 10470   // Gives the following frame tree:
 10471   //
 10472   // Inline (outer span)
 10473   // Block (anonymous, outer span)
 10474   //   Block (div)
 10475   //     Text("a")
 10476   // Inline (outer span)
 10477   //   Inline (inner span)
 10478   //     Text("b")
 10479   // Block (anonymous, outer span)
 10480   //   Block (anonymous, inner span)
 10481   //     Block (div)
 10482   //       Text("c")
 10483   // Inline (outer span)
 10484   //   Inline (inner span)
 10485   //   Text("d")
 10486   // Block (anonymous, outer span)
 10487   //   Block (div)
 10488   //     Text("e")
 10489   // Inline (outer span)
 10490   //   Text("f")
 10492   nsIContent* const content = aItem.mContent;
 10493   nsStyleContext* const styleContext = aItem.mStyleContext;
 10495   bool positioned =
 10496     NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay &&
 10497     aDisplay->IsRelativelyPositionedStyle() &&
 10498     !aParentFrame->IsSVGText();
 10500   nsIFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext);
 10502   // Initialize the frame
 10503   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
 10505   // Inline frames can always have generated content
 10506   newFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
 10508   nsFrameConstructorSaveState absoluteSaveState;  // definition cannot be inside next block
 10509                                                   // because the object's destructor is significant
 10510                                                   // this is part of the fix for bug 42372
 10512   newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
 10513   if (positioned) {
 10514     // Relatively positioned frames becomes a container for child
 10515     // frames that are positioned
 10516     aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
 10519   // Process the child content
 10520   nsFrameItems childItems;
 10521   ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame, childItems);
 10523   nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
 10524   if (!aItem.mIsAllInline) {
 10525     FindFirstBlock(firstBlockEnumerator);
 10528   if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) {
 10529     // This part is easy.  We either already know we have no non-inline kids,
 10530     // or haven't found any when constructing actual frames (the latter can
 10531     // happen only if out-of-flows that we thought had no containing block
 10532     // acquired one when ancestor inline frames and {ib} splits got
 10533     // constructed).  Just put all the kids into the single inline frame and
 10534     // bail.
 10535     newFrame->SetInitialChildList(kPrincipalList, childItems);
 10536     aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
 10537     return newFrame;
 10540   // This inline frame contains several types of children. Therefore this frame
 10541   // has to be chopped into several pieces, as described above.
 10543   // Grab the first inline's kids
 10544   nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
 10545   newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
 10547   aFrameItems.AddChild(newFrame);
 10549   CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
 10551   return newFrame;
 10554 void
 10555 nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
 10556                                         nsIFrame* aInitialInline,
 10557                                         bool aIsPositioned,
 10558                                         nsFrameItems& aChildItems,
 10559                                         nsFrameItems& aSiblings)
 10561   nsIContent* content = aInitialInline->GetContent();
 10562   nsStyleContext* styleContext = aInitialInline->StyleContext();
 10563   nsIFrame* parentFrame = aInitialInline->GetParent();
 10565   // Resolve the right style context for our anonymous blocks.
 10566   // The distinction in styles is needed because of CSS 2.1, section
 10567   // 9.2.1.1, which says:
 10568   //   When such an inline box is affected by relative positioning, any
 10569   //   resulting translation also affects the block-level box contained
 10570   //   in the inline box.
 10571   nsRefPtr<nsStyleContext> blockSC =
 10572     mPresShell->StyleSet()->
 10573       ResolveAnonymousBoxStyle(aIsPositioned ?
 10574                                  nsCSSAnonBoxes::mozAnonymousPositionedBlock :
 10575                                  nsCSSAnonBoxes::mozAnonymousBlock,
 10576                                styleContext);
 10578   nsIFrame* lastNewInline = aInitialInline->FirstContinuation();
 10579   do {
 10580     // On entry to this loop aChildItems is not empty and the first frame in it
 10581     // is block-level.
 10582     NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items");
 10583     NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(),
 10584                     "Must have list starting with block");
 10586     // The initial run of blocks belongs to an anonymous block that we create
 10587     // right now. The anonymous block will be the parent of these block
 10588     // children of the inline.
 10589     nsIFrame* blockFrame;
 10590     blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
 10592     InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
 10594     // Find the first non-block child which defines the end of our block kids
 10595     // and the start of our next inline's kids
 10596     nsFrameList::FrameLinkEnumerator firstNonBlock =
 10597       FindFirstNonBlock(aChildItems);
 10598     nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock);
 10600     MoveChildrenTo(aState.mPresContext, aInitialInline, blockFrame, blockKids);
 10602     SetFrameIsIBSplit(lastNewInline, blockFrame);
 10603     aSiblings.AddChild(blockFrame);
 10605     // Now grab the initial inlines in aChildItems and put them into an inline
 10606     // frame
 10607     nsIFrame* inlineFrame = NS_NewInlineFrame(mPresShell, styleContext);
 10609     InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
 10611     inlineFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
 10612                               NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
 10613     if (aIsPositioned) {
 10614       inlineFrame->MarkAsAbsoluteContainingBlock();
 10617     if (aChildItems.NotEmpty()) {
 10618       nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
 10619       FindFirstBlock(firstBlock);
 10620       nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
 10622       MoveChildrenTo(aState.mPresContext, aInitialInline, inlineFrame,
 10623                      inlineKids);
 10626     SetFrameIsIBSplit(blockFrame, inlineFrame);
 10627     aSiblings.AddChild(inlineFrame);
 10628     lastNewInline = inlineFrame;
 10629   } while (aChildItems.NotEmpty());
 10631   SetFrameIsIBSplit(lastNewInline, nullptr);
 10634 void
 10635 nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
 10636                                              FrameConstructionItem& aParentItem,
 10637                                              bool aItemIsWithinSVGText,
 10638                                              bool aItemAllowsTextPathChild)
 10640   // XXXbz should we preallocate aParentItem.mChildItems to some sane
 10641   // length?  Maybe even to parentContent->GetChildCount()?
 10642   nsFrameConstructorState::PendingBindingAutoPusher
 10643     pusher(aState, aParentItem.mPendingBinding);
 10645   nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
 10646   nsIContent* const parentContent = aParentItem.mContent;
 10648   TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
 10649   if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
 10650     ancestorPusher.PushAncestorAndStyleScope(parentContent->AsElement());
 10651   } else {
 10652     ancestorPusher.PushStyleScope(parentContent->AsElement());
 10655   if (!aItemIsWithinSVGText) {
 10656     // Probe for generated content before
 10657     CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext,
 10658                                nsCSSPseudoElements::ePseudo_before,
 10659                                aParentItem.mChildItems);
 10662   uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
 10663   if (aItemIsWithinSVGText) {
 10664     flags |= ITEM_IS_WITHIN_SVG_TEXT;
 10666   if (aItemAllowsTextPathChild && aParentItem.mIsForSVGAElement) {
 10667     flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
 10670   if (!aParentItem.mAnonChildren.IsEmpty()) {
 10671     // Use the anon-children list instead of the content tree child list so
 10672     // that we use any special style context that should be associated with
 10673     // the children, and so that we won't try to construct grandchildren frame
 10674     // constructor items before the frame is available for their parent.
 10675     AddFCItemsForAnonymousContent(aState, nullptr, aParentItem.mAnonChildren,
 10676                                   aParentItem.mChildItems, flags);
 10677   } else {
 10678     // Use the content tree child list:
 10679     FlattenedChildIterator iter(parentContent);
 10680     for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
 10681       // Get the parent of the content and check if it is a XBL children element
 10682       // (if the content is a children element then contentParent != parentContent because the
 10683       // FlattenedChildIterator will transitively iterate through <xbl:children>
 10684       // for default content). Push the children element as an ancestor here because
 10685       // it does not have a frame and would not otherwise be pushed as an ancestor.
 10686       nsIContent* contentParent = content->GetParent();
 10687       MOZ_ASSERT(contentParent, "Parent must be non-null because we are iterating children.");
 10688       TreeMatchContext::AutoAncestorPusher insertionPointPusher(aState.mTreeMatchContext);
 10689       if (contentParent != parentContent && contentParent->IsElement()) {
 10690         if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
 10691           insertionPointPusher.PushAncestorAndStyleScope(contentParent->AsElement());
 10692         } else {
 10693           insertionPointPusher.PushStyleScope(contentParent->AsElement());
 10697       // Manually check for comments/PIs, since we don't have a frame to pass to
 10698       // AddFrameConstructionItems.  We know our parent is a non-replaced inline,
 10699       // so there is no need to do the NeedFrameFor check.
 10700       content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
 10701       if (content->IsNodeOfType(nsINode::eCOMMENT) ||
 10702           content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
 10703         continue;
 10705       if (content->IsElement()) {
 10706         // See comment explaining why we need to remove the "is possible
 10707         // restyle root" flags in AddFrameConstructionItems.  But note
 10708         // that we can remove all restyle flags, just like in
 10709         // ProcessChildren and for the same reason.
 10710         content->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
 10713       nsRefPtr<nsStyleContext> childContext =
 10714         ResolveStyleContext(parentStyleContext, content, &aState);
 10716       AddFrameConstructionItemsInternal(aState, content, nullptr, content->Tag(),
 10717                                         content->GetNameSpaceID(),
 10718                                         iter.XBLInvolved(), childContext,
 10719                                         flags, nullptr,
 10720                                         aParentItem.mChildItems);
 10724   if (!aItemIsWithinSVGText) {
 10725     // Probe for generated content after
 10726     CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext,
 10727                                nsCSSPseudoElements::ePseudo_after,
 10728                                aParentItem.mChildItems);
 10731   aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
 10734 // return whether it's ok to append (in the AppendFrames sense) to
 10735 // aParentFrame if our nextSibling is aNextSibling.  aParentFrame must
 10736 // be an ib-split inline.
 10737 static bool
 10738 IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
 10740   NS_PRECONDITION(IsInlineFrame(aParentFrame),
 10741                   "Must have an inline parent here");
 10742   do {
 10743     NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),
 10744                  "How is this not part of an ib-split?");
 10745     if (aNextSibling || aParentFrame->GetNextContinuation() ||
 10746         GetIBSplitSibling(aParentFrame)) {
 10747       return false;
 10750     aNextSibling = aParentFrame->GetNextSibling();
 10751     aParentFrame = aParentFrame->GetParent();
 10752   } while (IsInlineFrame(aParentFrame));
 10754   return true;
 10757 bool
 10758 nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
 10759                                            nsIFrame* aContainingBlock,
 10760                                            nsIFrame* aFrame,
 10761                                            FrameConstructionItemList& aItems,
 10762                                            bool aIsAppend,
 10763                                            nsIFrame* aPrevSibling)
 10765   if (aItems.IsEmpty()) {
 10766     return false;
 10769   // Before we go and append the frames, we must check for several
 10770   // special situations.
 10772   // Situation #1 is a XUL frame that contains frames that are required
 10773   // to be wrapped in blocks.
 10774   if (aFrame->IsBoxFrame() &&
 10775       !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
 10776       aItems.AnyItemsNeedBlockParent()) {
 10777     RecreateFramesForContent(aFrame->GetContent(), true);
 10778     return true;
 10781   nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
 10783   // Situation #2 is a flex container frame into which we're inserting new
 10784   // inline non-replaced children, adjacent to an existing anonymous flex item.
 10785   if (aFrame->GetType() == nsGkAtoms::flexContainerFrame) {
 10786     FCItemIterator iter(aItems);
 10788     // Check if we're adding to-be-wrapped content right *after* an existing
 10789     // anonymous flex item (which would need to absorb this content).
 10790     if (aPrevSibling && IsAnonymousFlexItem(aPrevSibling) &&
 10791         iter.item().NeedsAnonFlexItem(aState)) {
 10792       RecreateFramesForContent(aFrame->GetContent(), true);
 10793       return true;
 10796     // Check if we're adding to-be-wrapped content right *before* an existing
 10797     // anonymous flex item (which would need to absorb this content).
 10798     if (nextSibling && IsAnonymousFlexItem(nextSibling)) {
 10799       // Jump to the last entry in the list
 10800       iter.SetToEnd();
 10801       iter.Prev();
 10802       if (iter.item().NeedsAnonFlexItem(aState)) {
 10803         RecreateFramesForContent(aFrame->GetContent(), true);
 10804         return true;
 10809   // Situation #3 is an anonymous flex item that's getting new children who
 10810   // don't want to be wrapped.
 10811   if (IsAnonymousFlexItem(aFrame)) {
 10812     nsIFrame* flexContainerFrame = aFrame->GetParent();
 10813     NS_ABORT_IF_FALSE(flexContainerFrame &&
 10814                       flexContainerFrame->GetType() == nsGkAtoms::flexContainerFrame,
 10815                       "anonymous flex items should only exist as children "
 10816                       "of flex container frames");
 10818     // We need to push a null float containing block to be sure that
 10819     // "NeedsAnonFlexItem" will know we're not honoring floats for this
 10820     // inserted content. (In particular, this is necessary in order for
 10821     // NeedsAnonFlexItem's "GetGeometricParent" call to return the correct
 10822     // result.) We're not honoring floats on this content because it has the
 10823     // _flex container_ as its parent in the content tree.
 10824     nsFrameConstructorSaveState floatSaveState;
 10825     aState.PushFloatContainingBlock(nullptr, floatSaveState);
 10827     FCItemIterator iter(aItems);
 10828     // Skip over things that _do_ need an anonymous flex item, because
 10829     // they're perfectly happy to go here -- they won't cause a reframe.
 10830     if (!iter.SkipItemsThatNeedAnonFlexItem(aState)) {
 10831       // We hit something that _doesn't_ need an anonymous flex item!
 10832       // Rebuild the flex container to bust it out.
 10833       RecreateFramesForContent(flexContainerFrame->GetContent(), true);
 10834       return true;
 10837     // If we get here, then everything in |aItems| needs to be wrapped in
 10838     // an anonymous flex item.  That's where it's already going - good!
 10841   // Situation #4 is a case when table pseudo-frames don't work out right
 10842   ParentType parentType = GetParentType(aFrame);
 10843   // If all the kids want a parent of the type that aFrame is, then we're all
 10844   // set to go.  Indeed, there won't be any table pseudo-frames created between
 10845   // aFrame and the kids, so those won't need to be merged with any table
 10846   // pseudo-frames that might already be kids of aFrame.  If aFrame itself is a
 10847   // table pseudo-frame, then all the kids in this list would have wanted a
 10848   // frame of that type wrapping them anyway, so putting them inside it is ok.
 10849   if (!aItems.AllWantParentType(parentType)) {
 10850     // Don't give up yet.  If parentType is not eTypeBlock and the parent is
 10851     // not a generated content frame, then try filtering whitespace out of the
 10852     // list.
 10853     if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
 10854       // For leading whitespace followed by a kid that wants our parent type,
 10855       // there are four cases:
 10856       // 1) We have a previous sibling which is not a table pseudo.  That means
 10857       //    that previous sibling wanted a (non-block) parent of the type we're
 10858       //    looking at.  Then the whitespace comes between two table-internal
 10859       //    elements, so should be collapsed out.
 10860       // 2) We have a previous sibling which is a table pseudo.  It might have
 10861       //    kids who want this whitespace, so we need to reframe.
 10862       // 3) We have no previous sibling and our parent frame is not a table
 10863       //    pseudo.  That means that we'll be at the beginning of our actual
 10864       //    non-block-type parent, and the whitespace is OK to collapse out.
 10865       //    If something is ever inserted before us, it'll find our own parent
 10866       //    as its parent and if it's something that would care about the
 10867       //    whitespace it'll want a block parent, so it'll trigger a reframe at
 10868       //    that point.
 10869       // 4) We have no previous sibling and our parent frame is a table pseudo.
 10870       //    Need to reframe.
 10871       // All that is predicated on finding the correct previous sibling.  We
 10872       // might have to walk backwards along continuations from aFrame to do so.
 10873       //
 10874       // It's always OK to drop whitespace between any two items that want a
 10875       // parent of type parentType.
 10876       //
 10877       // For trailing whitespace preceded by a kid that wants our parent type,
 10878       // there are four cases:
 10879       // 1) We have a next sibling which is not a table pseudo.  That means
 10880       //    that next sibling wanted a (non-block) parent of the type we're
 10881       //    looking at.  Then the whitespace comes between two table-internal
 10882       //    elements, so should be collapsed out.
 10883       // 2) We have a next sibling which is a table pseudo.  It might have
 10884       //    kids who want this whitespace, so we need to reframe.
 10885       // 3) We have no next sibling and our parent frame is not a table
 10886       //    pseudo.  That means that we'll be at the end of our actual
 10887       //    non-block-type parent, and the whitespace is OK to collapse out.
 10888       //    If something is ever inserted after us, it'll find our own parent
 10889       //    as its parent and if it's something that would care about the
 10890       //    whitespace it'll want a block parent, so it'll trigger a reframe at
 10891       //    that point.
 10892       // 4) We have no next sibling and our parent frame is a table pseudo.
 10893       //    Need to reframe.
 10894       // All that is predicated on finding the correct next sibling.  We might
 10895       // have to walk forward along continuations from aFrame to do so.  That
 10896       // said, in the case when nextSibling is null at this point and aIsAppend
 10897       // is true, we know we're in case 3.  Furthermore, in that case we don't
 10898       // even have to worry about the table pseudo situation; we know our
 10899       // parent is not a table pseudo there.
 10900       FCItemIterator iter(aItems);
 10901       FCItemIterator start(iter);
 10902       do {
 10903         if (iter.SkipItemsWantingParentType(parentType)) {
 10904           break;
 10907         // iter points to an item that wants a different parent.  If it's not
 10908         // whitespace, we're done; no more point scanning the list.
 10909         if (!iter.item().IsWhitespace(aState)) {
 10910           break;
 10913         if (iter == start) {
 10914           // Leading whitespace.  How to handle this depends on our
 10915           // previous sibling and aFrame.  See the long comment above.
 10916           nsIFrame* prevSibling = aPrevSibling;
 10917           if (!prevSibling) {
 10918             // Try to find one after all
 10919             nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
 10920             while (parentPrevCont) {
 10921               prevSibling = parentPrevCont->GetLastChild(kPrincipalList);
 10922               if (prevSibling) {
 10923                 break;
 10925               parentPrevCont = parentPrevCont->GetPrevContinuation();
 10927           };
 10928           if (prevSibling) {
 10929             if (IsTablePseudo(prevSibling)) {
 10930               // need to reframe
 10931               break;
 10933           } else if (IsTablePseudo(aFrame)) {
 10934             // need to reframe
 10935             break;
 10939         FCItemIterator spaceEndIter(iter);
 10940         // Advance spaceEndIter past any whitespace
 10941         bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
 10943         bool okToDrop;
 10944         if (trailingSpaces) {
 10945           // Trailing whitespace.  How to handle this depeds on aIsAppend, our
 10946           // next sibling and aFrame.  See the long comment above.
 10947           okToDrop = aIsAppend && !nextSibling;
 10948           if (!okToDrop) {
 10949             if (!nextSibling) {
 10950               // Try to find one after all
 10951               nsIFrame* parentNextCont = aFrame->GetNextContinuation();
 10952               while (parentNextCont) {
 10953                 nextSibling = parentNextCont->GetFirstPrincipalChild();
 10954                 if (nextSibling) {
 10955                   break;
 10957                 parentNextCont = parentNextCont->GetNextContinuation();
 10961             okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
 10962                        (!nextSibling && !IsTablePseudo(aFrame));
 10964 #ifdef DEBUG
 10965           else {
 10966             NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
 10968 #endif
 10969         } else {
 10970           okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
 10973         if (okToDrop) {
 10974           iter.DeleteItemsTo(spaceEndIter);
 10975         } else {
 10976           // We're done: we don't want to drop the whitespace, and it has the
 10977           // wrong parent type.
 10978           break;
 10981         // Now loop, since |iter| points to item right after the whitespace we
 10982         // removed.
 10983       } while (!iter.IsDone());
 10986     // We might be able to figure out some sort of optimizations here, but they
 10987     // would have to depend on having a correct aPrevSibling and a correct next
 10988     // sibling.  For example, we can probably avoid reframing if none of
 10989     // aFrame, aPrevSibling, and next sibling are table pseudo-frames.  But it
 10990     // doesn't seem worth it to worry about that for now, especially since we
 10991     // in fact do not have a reliable aPrevSibling, nor any next sibling, in
 10992     // this method.
 10994     // aItems might have changed, so recheck the parent type thing.  In fact,
 10995     // it might be empty, so recheck that too.
 10996     if (aItems.IsEmpty()) {
 10997       return false;
 11000     if (!aItems.AllWantParentType(parentType)) {
 11001       // Reframing aFrame->GetContent() is good enough, since the content of
 11002       // table pseudo-frames is the ancestor content.
 11003       RecreateFramesForContent(aFrame->GetContent(), true);
 11004       return true;
 11008   // Now we have several cases involving {ib} splits.  Put them all in a
 11009   // do/while with breaks to take us to the "go and reconstruct" code.
 11010   do {
 11011     if (IsInlineFrame(aFrame)) {
 11012       if (aItems.AreAllItemsInline()) {
 11013         // We can just put the kids in.
 11014         return false;
 11017       if (!IsFramePartOfIBSplit(aFrame)) {
 11018         // Need to go ahead and reconstruct.
 11019         break;
 11022       // Now we're adding kids including some blocks to an inline part of an
 11023       // {ib} split.  If we plan to call AppendFrames, and don't have a next
 11024       // sibling for the new frames, and our parent is the last continuation of
 11025       // the last part of the {ib} split, and the same is true of all our
 11026       // ancestor inlines (they have no following continuations and they're the
 11027       // last part of their {ib} splits and we'd be adding to the end for all
 11028       // of them), then AppendFrames will handle things for us.  Bail out in
 11029       // that case.
 11030       if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
 11031         return false;
 11034       // Need to reconstruct.
 11035       break;
 11038     // Now we know we have a block parent.  If it's not part of an
 11039     // ib-split, we're all set.
 11040     if (!IsFramePartOfIBSplit(aFrame)) {
 11041       return false;
 11044     // We're adding some kids to a block part of an {ib} split.  If all the
 11045     // kids are blocks, we don't need to reconstruct.
 11046     if (aItems.AreAllItemsBlock()) {
 11047       return false;
 11050     // We might have some inline kids for this block.  Just reconstruct.
 11051     break;
 11052   } while (0);
 11054   // If we don't have a containing block, start with aFrame and look for one.
 11055   if (!aContainingBlock) {
 11056     aContainingBlock = aFrame;
 11059   // To find the right block to reframe, just walk up the tree until we find a
 11060   // frame that is:
 11061   // 1)  Not part of an IB split
 11062   // 2)  Not a pseudo-frame
 11063   // 3)  Not an inline frame
 11064   // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
 11065   // enforces that the root is display:none, display:table, or display:block.
 11066   // Note that walking up "too far" is OK in terms of correctness, even if it
 11067   // might be a little inefficient.  This is why we walk out of all
 11068   // pseudo-frames -- telling which ones are or are not OK to walk out of is
 11069   // too hard (and I suspect that we do in fact need to walk out of all of
 11070   // them).
 11071   while (IsFramePartOfIBSplit(aContainingBlock) ||
 11072          aContainingBlock->IsInlineOutside() ||
 11073          aContainingBlock->StyleContext()->GetPseudo()) {
 11074     aContainingBlock = aContainingBlock->GetParent();
 11075     NS_ASSERTION(aContainingBlock,
 11076                  "Must have non-inline, non-ib-split, non-pseudo frame as "
 11077                  "root (or child of root, for a table root)!");
 11080   // Tell parent of the containing block to reformulate the
 11081   // entire block. This is painful and definitely not optimal
 11082   // but it will *always* get the right answer.
 11084   nsIContent *blockContent = aContainingBlock->GetContent();
 11085 #ifdef DEBUG
 11086   if (gNoisyContentUpdates) {
 11087     printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
 11088            static_cast<void*>(blockContent));
 11090 #endif
 11091   RecreateFramesForContent(blockContent, true);
 11092   return true;
 11095 nsresult
 11096 nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
 11099 #ifdef DEBUG
 11100   // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
 11101   // so I want to see when it is happening!  Unfortunately, it is happening way to often because
 11102   // so much content on the web causes block-in-inline frame situations and we handle them
 11103   // very poorly
 11104   if (gNoisyContentUpdates) {
 11105     printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
 11106            static_cast<void*>(aFrame));
 11108 #endif
 11110   // XXXbz how exactly would we get here while isReflowing anyway?  Should this
 11111   // whole test be ifdef DEBUG?
 11112   if (mPresShell->IsReflowLocked()) {
 11113     // don't ReframeContainingBlock, this will result in a crash
 11114     // if we remove a tree that's in reflow - see bug 121368 for testcase
 11115     NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
 11116     return NS_OK;
 11119   // Get the first "normal" ancestor of the target frame.
 11120   nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
 11121   if (containingBlock) {
 11122     // From here we look for the containing block in case the target
 11123     // frame is already a block (which can happen when an inline frame
 11124     // wraps some of its content in an anonymous block; see
 11125     // ConstructInline)
 11127     // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
 11128     // GetIBContainingBlock works much better and provides the correct container in all cases
 11129     // so GetFloatContainingBlock(aFrame) has been removed
 11131     // And get the containingBlock's content
 11132     nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent();
 11133     if (blockContent) {
 11134 #ifdef DEBUG
 11135       if (gNoisyContentUpdates) {
 11136         printf("  ==> blockContent=%p\n", static_cast<void*>(blockContent));
 11138 #endif
 11139       return RecreateFramesForContent(blockContent, true);
 11143   // If we get here, we're screwed!
 11144   return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
 11145 				  true);
 11148 nsresult
 11149 nsCSSFrameConstructor::GenerateChildFrames(nsIFrame* aFrame)
 11152     nsAutoScriptBlocker scriptBlocker;
 11153     BeginUpdate();
 11155     nsFrameItems childItems;
 11156     nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
 11157     // We don't have a parent frame with a pending binding constructor here,
 11158     // so no need to worry about ordering of the kids' constructors with it.
 11159     // Pass null for the PendingBinding.
 11160     ProcessChildren(state, aFrame->GetContent(), aFrame->StyleContext(),
 11161                     aFrame, false, childItems, false,
 11162                     nullptr);
 11164     aFrame->SetInitialChildList(kPrincipalList, childItems);
 11166     EndUpdate();
 11169 #ifdef ACCESSIBILITY
 11170   nsAccessibilityService* accService = nsIPresShell::AccService();
 11171   if (accService) {
 11172     nsIContent* container = aFrame->GetContent();
 11173     nsIContent* child = container->GetFirstChild();
 11174     if (child) {
 11175       accService->ContentRangeInserted(mPresShell, container, child, nullptr);
 11178 #endif
 11180   // call XBL constructors after the frames are created
 11181   mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
 11183   return NS_OK;
 11186 //////////////////////////////////////////////////////////
 11187 // nsCSSFrameConstructor::FrameConstructionItem methods //
 11188 //////////////////////////////////////////////////////////
 11189 bool
 11190 nsCSSFrameConstructor::
 11191 FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const
 11193   NS_PRECONDITION(aState.mCreatingExtraFrames ||
 11194                   !mContent->GetPrimaryFrame(), "How did that happen?");
 11195   if (!mIsText) {
 11196     return false;
 11198   mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
 11199                      NS_REFRAME_IF_WHITESPACE);
 11200   return mContent->TextIsOnlyWhitespace();
 11203 //////////////////////////////////////////////////////////////
 11204 // nsCSSFrameConstructor::FrameConstructionItemList methods //
 11205 //////////////////////////////////////////////////////////////
 11206 void
 11207 nsCSSFrameConstructor::FrameConstructionItemList::
 11208 AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta)
 11210   NS_PRECONDITION(aDelta == 1 || aDelta == -1, "Unexpected delta");
 11211   mItemCount += aDelta;
 11212   if (aItem->mIsAllInline) {
 11213     mInlineCount += aDelta;
 11215   if (aItem->mIsBlock) {
 11216     mBlockCount += aDelta;
 11218   if (aItem->mIsLineParticipant) {
 11219     mLineParticipantCount += aDelta;
 11221   mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
 11224 ////////////////////////////////////////////////////////////////////////
 11225 // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
 11226 ////////////////////////////////////////////////////////////////////////
 11227 inline bool
 11228 nsCSSFrameConstructor::FrameConstructionItemList::
 11229 Iterator::SkipItemsWantingParentType(ParentType aParentType)
 11231   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
 11232   while (item().DesiredParentType() == aParentType) {
 11233     Next();
 11234     if (IsDone()) {
 11235       return true;
 11238   return false;
 11241 bool
 11242 nsCSSFrameConstructor::FrameConstructionItem::
 11243   NeedsAnonFlexItem(const nsFrameConstructorState& aState)
 11245   if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
 11246     // This will be an inline non-replaced box.
 11247     return true;
 11250   if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
 11251       aState.GetGeometricParent(mStyleContext->StyleDisplay(), nullptr)) {
 11252     // We're abspos or fixedpos, which means we'll spawn a placeholder which
 11253     // we'll need to wrap in an anonymous flex item.  So, we just treat
 11254     // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
 11255     // and then when we spawn the placeholder, it'll end up in the right spot.
 11256     return true;
 11259   return false;
 11262 inline bool
 11263 nsCSSFrameConstructor::FrameConstructionItemList::
 11264 Iterator::SkipItemsThatNeedAnonFlexItem(
 11265   const nsFrameConstructorState& aState)
 11267   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
 11268   while (item().NeedsAnonFlexItem(aState)) {
 11269     Next();
 11270     if (IsDone()) {
 11271       return true;
 11274   return false;
 11277 inline bool
 11278 nsCSSFrameConstructor::FrameConstructionItemList::
 11279 Iterator::SkipItemsThatDontNeedAnonFlexItem(
 11280   const nsFrameConstructorState& aState)
 11282   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
 11283   while (!(item().NeedsAnonFlexItem(aState))) {
 11284     Next();
 11285     if (IsDone()) {
 11286       return true;
 11289   return false;
 11292 inline bool
 11293 nsCSSFrameConstructor::FrameConstructionItemList::
 11294 Iterator::SkipWhitespace(nsFrameConstructorState& aState)
 11296   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
 11297   NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?");
 11298   do {
 11299     Next();
 11300     if (IsDone()) {
 11301       return true;
 11303   } while (item().IsWhitespace(aState));
 11305   return false;
 11308 void
 11309 nsCSSFrameConstructor::FrameConstructionItemList::
 11310 Iterator::AppendItemToList(FrameConstructionItemList& aTargetList)
 11312   NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
 11313   NS_PRECONDITION(!IsDone(), "should not be done");
 11315   FrameConstructionItem* item = ToItem(mCurrent);
 11316   Next();
 11317   PR_REMOVE_LINK(item);
 11318   PR_APPEND_LINK(item, &aTargetList.mItems);
 11320   mList.AdjustCountsForItem(item, -1);
 11321   aTargetList.AdjustCountsForItem(item, 1);
 11324 void
 11325 nsCSSFrameConstructor::FrameConstructionItemList::
 11326 Iterator::AppendItemsToList(const Iterator& aEnd,
 11327                             FrameConstructionItemList& aTargetList)
 11329   NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
 11330   NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?");
 11332   // We can't just move our guts to the other list if it already has
 11333   // some information or if we're not moving our entire list.
 11334   if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() ||
 11335       !aTargetList.mUndisplayedItems.IsEmpty()) {
 11336     do {
 11337       AppendItemToList(aTargetList);
 11338     } while (*this != aEnd);
 11339     return;
 11342   // move over the list of items
 11343   PR_INSERT_AFTER(&aTargetList.mItems, &mList.mItems);
 11344   // Need to init when we remove to makd ~FrameConstructionItemList work right.
 11345   PR_REMOVE_AND_INIT_LINK(&mList.mItems);
 11347   // Copy over the various counters
 11348   aTargetList.mInlineCount = mList.mInlineCount;
 11349   aTargetList.mBlockCount = mList.mBlockCount;
 11350   aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
 11351   aTargetList.mItemCount = mList.mItemCount;
 11352   memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
 11353          sizeof(aTargetList.mDesiredParentCounts));
 11355   // Swap out undisplayed item arrays, before we nuke the array on our end
 11356   aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
 11358   // reset mList
 11359   mList.~FrameConstructionItemList();
 11360   new (&mList) FrameConstructionItemList();
 11362   // Point ourselves to aEnd, as advertised
 11363   mCurrent = mEnd = &mList.mItems;
 11364   NS_POSTCONDITION(*this == aEnd, "How did that happen?");
 11367 void
 11368 nsCSSFrameConstructor::FrameConstructionItemList::
 11369 Iterator::InsertItem(FrameConstructionItem* aItem)
 11371   // Just insert the item before us.  There's no magic here.
 11372   PR_INSERT_BEFORE(aItem, mCurrent);
 11373   mList.AdjustCountsForItem(aItem, 1);
 11375   NS_POSTCONDITION(PR_NEXT_LINK(aItem) == mCurrent, "How did that happen?");
 11378 void
 11379 nsCSSFrameConstructor::FrameConstructionItemList::
 11380 Iterator::DeleteItemsTo(const Iterator& aEnd)
 11382   NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?");
 11383   NS_PRECONDITION(*this != aEnd, "Shouldn't be at aEnd yet");
 11385   do {
 11386     NS_ASSERTION(!IsDone(), "Ran off end of list?");
 11387     FrameConstructionItem* item = ToItem(mCurrent);
 11388     Next();
 11389     PR_REMOVE_LINK(item);
 11390     mList.AdjustCountsForItem(item, -1);
 11391     delete item;
 11392   } while (*this != aEnd);

mercurial