1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /*
8  * construction of a frame tree that is nearly isomorphic to the content
9  * tree and updating of that tree in response to dynamic changes
10  */
11 
12 #include "nsCSSFrameConstructor.h"
13 
14 #include "mozilla/AutoRestore.h"
15 #include "mozilla/DebugOnly.h"
16 #include "mozilla/ErrorResult.h"
17 #include "mozilla/dom/HTMLDetailsElement.h"
18 #include "mozilla/dom/HTMLSelectElement.h"
19 #include "mozilla/dom/HTMLSummaryElement.h"
20 #include "mozilla/EventStates.h"
21 #include "mozilla/Likely.h"
22 #include "mozilla/LinkedList.h"
23 #include "mozilla/MemoryReporting.h"
24 #include "mozilla/PresShell.h"
25 #include "mozilla/ServoBindings.h"
26 #include "nsAbsoluteContainingBlock.h"
27 #include "nsCSSPseudoElements.h"
28 #include "nsAtom.h"
29 #include "nsIFrameInlines.h"
30 #include "nsGkAtoms.h"
31 #include "nsPresContext.h"
32 #include "nsIDocument.h"
33 #include "nsIDocumentInlines.h"
34 #include "nsTableFrame.h"
35 #include "nsTableColFrame.h"
36 #include "nsTableRowFrame.h"
37 #include "nsTableCellFrame.h"
38 #include "nsHTMLParts.h"
39 #include "nsIPresShell.h"
40 #include "nsUnicharUtils.h"
41 #include "mozilla/StyleSetHandle.h"
42 #include "mozilla/StyleSetHandleInlines.h"
43 #include "nsViewManager.h"
44 #include "nsStyleConsts.h"
45 #ifdef MOZ_XUL
46 #include "nsXULElement.h"
47 #include "mozilla/dom/BoxObject.h"
48 #endif  // MOZ_XUL
49 #include "nsContainerFrame.h"
50 #include "nsNameSpaceManager.h"
51 #include "nsIComboboxControlFrame.h"
52 #include "nsComboboxControlFrame.h"
53 #include "nsIListControlFrame.h"
54 #include "nsIDOMCharacterData.h"
55 #include "nsPlaceholderFrame.h"
56 #include "nsTableRowGroupFrame.h"
57 #include "nsIFormControl.h"
58 #include "nsCSSAnonBoxes.h"
59 #include "nsTextFragment.h"
60 #include "nsIAnonymousContentCreator.h"
61 #include "nsBindingManager.h"
62 #include "nsXBLBinding.h"
63 #include "nsContentUtils.h"
64 #include "nsIScriptError.h"
65 #ifdef XP_MACOSX
66 #include "nsIDocShell.h"
67 #endif
68 #include "ChildIterator.h"
69 #include "nsError.h"
70 #include "nsLayoutUtils.h"
71 #include "nsAutoPtr.h"
72 #include "nsBoxFrame.h"
73 #include "nsBoxLayout.h"
74 #include "nsFlexContainerFrame.h"
75 #include "nsGridContainerFrame.h"
76 #include "RubyUtils.h"
77 #include "nsRubyFrame.h"
78 #include "nsRubyBaseFrame.h"
79 #include "nsRubyBaseContainerFrame.h"
80 #include "nsRubyTextFrame.h"
81 #include "nsRubyTextContainerFrame.h"
82 #include "nsImageFrame.h"
83 #include "nsIObjectLoadingContent.h"
84 #include "nsTArray.h"
85 #include "nsGenericDOMDataNode.h"
86 #include "mozilla/dom/Element.h"
87 #include "mozilla/dom/ElementInlines.h"
88 #include "nsAutoLayoutPhase.h"
89 #include "nsStyleContextInlines.h"
90 #include "nsStyleStructInlines.h"
91 #include "nsPageContentFrame.h"
92 #include "mozilla/RestyleManager.h"
93 #include "mozilla/RestyleManagerInlines.h"
94 #include "mozilla/StylePrefs.h"
95 #include "StickyScrollContainer.h"
96 #include "nsFieldSetFrame.h"
97 #include "nsInlineFrame.h"
98 #include "nsBlockFrame.h"
99 #include "nsCanvasFrame.h"
100 #include "nsFirstLetterFrame.h"
101 #include "nsGfxScrollFrame.h"
102 #include "nsPageFrame.h"
103 #include "nsSimplePageSequenceFrame.h"
104 #include "nsTableWrapperFrame.h"
105 #include "nsIScrollableFrame.h"
106 #include "nsBackdropFrame.h"
107 #include "nsTransitionManager.h"
108 #include "DetailsFrame.h"
109 #include "nsThemeConstants.h"
110 
111 #ifdef MOZ_XUL
112 #include "nsIRootBox.h"
113 #endif
114 #ifdef ACCESSIBILITY
115 #include "nsAccessibilityService.h"
116 #endif
117 
118 #include "nsXBLService.h"
119 
120 #undef NOISY_FIRST_LETTER
121 
122 #include "nsMathMLParts.h"
123 #include "mozilla/dom/SVGTests.h"
124 #include "nsSVGUtils.h"
125 
126 #include "nsRefreshDriver.h"
127 #include "nsRuleProcessorData.h"
128 #include "nsTextNode.h"
129 #include "ActiveLayerTracker.h"
130 #include "nsIPresShellInlines.h"
131 
132 using namespace mozilla;
133 using namespace mozilla::dom;
134 
135 // An alias for convenience.
136 static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
137 
138 nsIFrame* NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell,
139                                 nsStyleContext* aContext);
140 
141 nsIFrame* NS_NewHTMLVideoFrame(nsIPresShell* aPresShell,
142                                nsStyleContext* aContext);
143 
144 nsContainerFrame* NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell,
145                                          nsStyleContext* aContext);
146 nsContainerFrame* NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell,
147                                                   nsStyleContext* aContext);
148 nsIFrame* NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell,
149                                  nsStyleContext* aContext);
150 nsIFrame* NS_NewSVGGeometryFrame(nsIPresShell* aPresShell,
151                                  nsStyleContext* aContext);
152 nsIFrame* NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
153 nsIFrame* NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell,
154                                          nsStyleContext* aContext);
155 nsContainerFrame* NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell,
156                                               nsStyleContext* aContext);
157 nsIFrame* NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
158 nsIFrame* NS_NewSVGSwitchFrame(nsIPresShell* aPresShell,
159                                nsStyleContext* aContext);
160 nsIFrame* NS_NewSVGSymbolFrame(nsIPresShell* aPresShell,
161                                nsStyleContext* aContext);
162 nsIFrame* NS_NewSVGTextFrame(nsIPresShell* aPresShell,
163                              nsStyleContext* aContext);
164 nsIFrame* NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
165                                   nsStyleContext* aContext);
166 nsIFrame* NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
167 nsIFrame* NS_NewSVGViewFrame(nsIPresShell* aPresShell,
168                              nsStyleContext* aContext);
169 extern nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
170                                               nsStyleContext* aContext);
171 extern nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
172                                               nsStyleContext* aContext);
173 extern nsIFrame* NS_NewSVGStopFrame(nsIPresShell* aPresShell,
174                                     nsStyleContext* aContext);
175 nsContainerFrame* NS_NewSVGMarkerFrame(nsIPresShell* aPresShell,
176                                        nsStyleContext* aContext);
177 nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell,
178                                                 nsStyleContext* aContext);
179 extern nsIFrame* NS_NewSVGImageFrame(nsIPresShell* aPresShell,
180                                      nsStyleContext* aContext);
181 nsIFrame* NS_NewSVGClipPathFrame(nsIPresShell* aPresShell,
182                                  nsStyleContext* aContext);
183 nsIFrame* NS_NewSVGFilterFrame(nsIPresShell* aPresShell,
184                                nsStyleContext* aContext);
185 nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
186                                 nsStyleContext* aContext);
187 nsIFrame* NS_NewSVGMaskFrame(nsIPresShell* aPresShell,
188                              nsStyleContext* aContext);
189 nsIFrame* NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell,
190                                     nsStyleContext* aContext);
191 nsIFrame* NS_NewSVGFELeafFrame(nsIPresShell* aPresShell,
192                                nsStyleContext* aContext);
193 nsIFrame* NS_NewSVGFEImageFrame(nsIPresShell* aPresShell,
194                                 nsStyleContext* aContext);
195 nsIFrame* NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell,
196                                        nsStyleContext* aContext);
197 
198 #include "mozilla/dom/NodeInfo.h"
199 #include "prenv.h"
200 #include "nsNodeInfoManager.h"
201 #include "nsContentCreatorFunctions.h"
202 
203 #ifdef DEBUG
204 // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
205 // more of the following flags (comma separated) for handy debug
206 // output.
207 static bool gNoisyContentUpdates = false;
208 static bool gReallyNoisyContentUpdates = false;
209 static bool gNoisyInlineConstruction = false;
210 
211 struct FrameCtorDebugFlags {
212   const char* name;
213   bool* on;
214 };
215 
216 static FrameCtorDebugFlags gFlags[] = {
217     {"content-updates", &gNoisyContentUpdates},
218     {"really-noisy-content-updates", &gReallyNoisyContentUpdates},
219     {"noisy-inline", &gNoisyInlineConstruction}};
220 
221 #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
222 #endif
223 
224 #ifdef MOZ_XUL
225 #include "nsMenuFrame.h"
226 #include "nsPopupSetFrame.h"
227 #include "nsTreeColFrame.h"
228 #include "nsIBoxObject.h"
229 #include "nsPIListBoxObject.h"
230 #include "nsListBoxBodyFrame.h"
231 #include "nsListItemFrame.h"
232 #include "nsXULLabelFrame.h"
233 
234 //------------------------------------------------------------------
235 
236 nsIFrame* NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell,
237                                    nsStyleContext* aContext);
238 
239 nsContainerFrame* NS_NewRootBoxFrame(nsIPresShell* aPresShell,
240                                      nsStyleContext* aContext);
241 
242 nsContainerFrame* NS_NewDocElementBoxFrame(nsIPresShell* aPresShell,
243                                            nsStyleContext* aContext);
244 
245 nsIFrame* NS_NewDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
246 
247 nsIFrame* NS_NewLeafBoxFrame(nsIPresShell* aPresShell,
248                              nsStyleContext* aContext);
249 
250 nsIFrame* NS_NewStackFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
251 
252 nsIFrame* NS_NewProgressMeterFrame(nsIPresShell* aPresShell,
253                                    nsStyleContext* aContext);
254 
255 nsIFrame* NS_NewRangeFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
256 
257 nsIFrame* NS_NewImageBoxFrame(nsIPresShell* aPresShell,
258                               nsStyleContext* aContext);
259 
260 nsIFrame* NS_NewTextBoxFrame(nsIPresShell* aPresShell,
261                              nsStyleContext* aContext);
262 
263 nsIFrame* NS_NewGroupBoxFrame(nsIPresShell* aPresShell,
264                               nsStyleContext* aContext);
265 
266 nsIFrame* NS_NewButtonBoxFrame(nsIPresShell* aPresShell,
267                                nsStyleContext* aContext);
268 
269 nsIFrame* NS_NewSplitterFrame(nsIPresShell* aPresShell,
270                               nsStyleContext* aContext);
271 
272 nsIFrame* NS_NewMenuPopupFrame(nsIPresShell* aPresShell,
273                                nsStyleContext* aContext);
274 
275 nsIFrame* NS_NewPopupSetFrame(nsIPresShell* aPresShell,
276                               nsStyleContext* aContext);
277 
278 nsIFrame* NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
279                           uint32_t aFlags);
280 
281 nsIFrame* NS_NewMenuBarFrame(nsIPresShell* aPresShell,
282                              nsStyleContext* aContext);
283 
284 nsIFrame* NS_NewTreeBodyFrame(nsIPresShell* aPresShell,
285                               nsStyleContext* aContext);
286 
287 // grid
288 nsresult NS_NewGridLayout2(nsIPresShell* aPresShell, nsBoxLayout** aNewLayout);
289 nsIFrame* NS_NewGridRowLeafFrame(nsIPresShell* aPresShell,
290                                  nsStyleContext* aContext);
291 nsIFrame* NS_NewGridRowGroupFrame(nsIPresShell* aPresShell,
292                                   nsStyleContext* aContext);
293 
294 // end grid
295 
296 nsIFrame* NS_NewTitleBarFrame(nsIPresShell* aPresShell,
297                               nsStyleContext* aContext);
298 
299 nsIFrame* NS_NewResizerFrame(nsIPresShell* aPresShell,
300                              nsStyleContext* aContext);
301 
302 #endif
303 
304 nsHTMLScrollFrame* NS_NewHTMLScrollFrame(nsIPresShell* aPresShell,
305                                          nsStyleContext* aContext,
306                                          bool aIsRoot);
307 
308 nsXULScrollFrame* NS_NewXULScrollFrame(nsIPresShell* aPresShell,
309                                        nsStyleContext* aContext, bool aIsRoot,
310                                        bool aClipAllDescendants);
311 
312 nsIFrame* NS_NewSliderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
313 
314 nsIFrame* NS_NewScrollbarFrame(nsIPresShell* aPresShell,
315                                nsStyleContext* aContext);
316 
317 nsIFrame* NS_NewScrollbarButtonFrame(nsIPresShell* aPresShell,
318                                      nsStyleContext* aContext);
319 
320 #ifdef NOISY_FINDFRAME
321 static int32_t FFWC_totalCount = 0;
322 static int32_t FFWC_doLoop = 0;
323 static int32_t FFWC_doSibling = 0;
324 static int32_t FFWC_recursions = 0;
325 static int32_t FFWC_nextInFlows = 0;
326 #endif
327 
328 #ifdef MOZ_OLD_STYLE
329 
330 // Wrapper class to handle stack-construction a TreeMatchContext only if we're
331 // using the Gecko style system.
332 class MOZ_STACK_CLASS TreeMatchContextHolder {
333  public:
TreeMatchContextHolder(nsIDocument * aDocument)334   explicit TreeMatchContextHolder(nsIDocument* aDocument) {
335     if (!aDocument->IsStyledByServo()) {
336       mMaybeTreeMatchContext.emplace(aDocument,
337                                      TreeMatchContext::ForFrameConstruction);
338     }
339   }
340 
Exists() const341   bool Exists() const { return mMaybeTreeMatchContext.isSome(); }
operator TreeMatchContext*()342   operator TreeMatchContext*() { return mMaybeTreeMatchContext.ptrOr(nullptr); }
343 
operator ->()344   TreeMatchContext* operator->() {
345     MOZ_ASSERT(mMaybeTreeMatchContext.isSome());
346     return mMaybeTreeMatchContext.ptr();
347   }
348 
349  private:
350   Maybe<TreeMatchContext> mMaybeTreeMatchContext;
351 };
352 
353 #else
354 
355 // Define this dummy class so there are fewer call sites to change when the old
356 // style system code is compiled out.
357 class TreeMatchContextHolder {
358  public:
TreeMatchContextHolder(nsIDocument * aDocument)359   explicit TreeMatchContextHolder(nsIDocument* aDocument) {}
Exists() const360   bool Exists() const { return false; }
operator TreeMatchContext*()361   operator TreeMatchContext*() { return nullptr; }
operator ->()362   TreeMatchContext* operator->() { MOZ_CRASH("old style system disabled"); }
363 };
364 
365 #endif
366 
367 // Returns true if aFrame is an anonymous flex/grid item.
IsAnonymousFlexOrGridItem(const nsIFrame * aFrame)368 static inline bool IsAnonymousFlexOrGridItem(const nsIFrame* aFrame) {
369   const nsAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
370   return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
371          pseudoType == nsCSSAnonBoxes::anonymousGridItem;
372 }
373 
374 // Returns true if aFrame is a flex/grid container.
IsFlexOrGridContainer(const nsIFrame * aFrame)375 static inline bool IsFlexOrGridContainer(const nsIFrame* aFrame) {
376   const LayoutFrameType t = aFrame->Type();
377   return t == LayoutFrameType::FlexContainer ||
378          t == LayoutFrameType::GridContainer;
379 }
380 
381 // Returns true IFF the given nsIFrame is a nsFlexContainerFrame and
382 // represents a -webkit-{inline-}box or -moz-{inline-}box container.
IsFlexContainerForLegacyBox(const nsIFrame * aFrame)383 static inline bool IsFlexContainerForLegacyBox(const nsIFrame* aFrame) {
384   return aFrame->IsFlexContainerFrame() &&
385          aFrame->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX);
386 }
387 
388 #if DEBUG
AssertAnonymousFlexOrGridItemParent(const nsIFrame * aChild,const nsIFrame * aParent)389 static void AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
390                                                 const nsIFrame* aParent) {
391   MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
392              "expected an anonymous flex or grid item child frame");
393   MOZ_ASSERT(aParent, "expected a parent frame");
394   const nsAtom* pseudoType = aChild->StyleContext()->GetPseudo();
395   if (pseudoType == nsCSSAnonBoxes::anonymousFlexItem) {
396     MOZ_ASSERT(aParent->IsFlexContainerFrame(),
397                "anonymous flex items should only exist as children "
398                "of flex container frames");
399   } else {
400     MOZ_ASSERT(aParent->IsGridContainerFrame(),
401                "anonymous grid items should only exist as children "
402                "of grid container frames");
403   }
404 }
405 #else
406 #define AssertAnonymousFlexOrGridItemParent(x, y) \
407   do { /* nothing */                              \
408   } while (0)
409 #endif
410 
GetFieldSetBlockFrame(nsIFrame * aFieldsetFrame)411 static inline nsContainerFrame* GetFieldSetBlockFrame(
412     nsIFrame* aFieldsetFrame) {
413   // Depends on the fieldset child frame order - see ConstructFieldSetFrame()
414   // below.
415   nsIFrame* firstChild = aFieldsetFrame->PrincipalChildList().FirstChild();
416   nsIFrame* inner = firstChild && firstChild->GetNextSibling()
417                         ? firstChild->GetNextSibling()
418                         : firstChild;
419   return inner ? inner->GetContentInsertionFrame() : nullptr;
420 }
421 
422 #define FCDATA_DECL(_flags, _func) \
423   { _flags, {(FrameCreationFunc)_func}, nullptr, nullptr }
424 #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box) \
425   {                                                          \
426     _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS,       \
427         {(FrameCreationFunc)_func}, nullptr, &_anon_box      \
428   }
429 
430 #define UNREACHABLE_FCDATA() \
431   { 0, {(FrameCreationFunc) nullptr}, nullptr, nullptr }
432 //----------------------------------------------------------------------
433 
434 /**
435  * True if aFrame is an actual inline frame in the sense of non-replaced
436  * display:inline CSS boxes.  In other words, it can be affected by {ib}
437  * splitting and can contain first-letter frames.  Basically, this is either an
438  * inline frame (positioned or otherwise) or an line frame (this last because
439  * it can contain first-letter and because inserting blocks in the middle of it
440  * needs to terminate it).
441  */
IsInlineFrame(const nsIFrame * aFrame)442 static bool IsInlineFrame(const nsIFrame* aFrame) {
443   return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
444 }
445 
446 /**
447  * True if aFrame is an instance of an SVG frame class or is an inline/block
448  * frame being used for SVG text.
449  */
IsFrameForSVG(const nsIFrame * aFrame)450 static bool IsFrameForSVG(const nsIFrame* aFrame) {
451   return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
452          nsSVGUtils::IsInSVGTextSubtree(aFrame);
453 }
454 
455 /**
456  * Returns true iff aFrame explicitly prevents its descendants from floating
457  * (at least, down to the level of descendants which themselves are
458  * float-containing blocks -- those will manage the floating status of any
459  * lower-level descendents inside them, of course).
460  */
ShouldSuppressFloatingOfDescendants(nsIFrame * aFrame)461 static bool ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame) {
462   return aFrame->IsFrameOfType(nsIFrame::eMathML) || aFrame->IsXULBoxFrame() ||
463          ::IsFlexOrGridContainer(aFrame);
464 }
465 
466 /**
467  * If any children require a block parent, return the first such child.
468  * Otherwise return null.
469  */
AnyKidsNeedBlockParent(nsIFrame * aFrameList)470 static nsIContent* AnyKidsNeedBlockParent(nsIFrame* aFrameList) {
471   for (nsIFrame* k = aFrameList; k; k = k->GetNextSibling()) {
472     // Line participants, such as text and inline frames, can't be
473     // directly inside a XUL box; they must be wrapped in an
474     // intermediate block.
475     if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
476       return k->GetContent();
477     }
478   }
479   return nullptr;
480 }
481 
482 // Reparent a frame into a wrapper frame that is a child of its old parent.
ReparentFrame(RestyleManager * aRestyleManager,nsContainerFrame * aNewParentFrame,nsIFrame * aFrame,bool aForceStyleReparent)483 static void ReparentFrame(RestyleManager* aRestyleManager,
484                           nsContainerFrame* aNewParentFrame, nsIFrame* aFrame,
485                           bool aForceStyleReparent) {
486   aFrame->SetParent(aNewParentFrame);
487   // We reparent frames for two reasons: to put them inside ::first-line, and to
488   // put them inside some wrapper anonymous boxes.
489   //
490   // The latter shouldn't affect any styles in practice, so only needs style
491   // context reparenting in the Gecko backend, to make our style context tree
492   // assertions happy.  The former passes aForceStyleReparent == true.
493   if (aForceStyleReparent || aRestyleManager->IsGecko()) {
494     aRestyleManager->ReparentStyleContext(aFrame);
495   }
496 }
497 
ReparentFrames(nsCSSFrameConstructor * aFrameConstructor,nsContainerFrame * aNewParentFrame,const nsFrameList & aFrameList,bool aForceStyleReparent)498 static void ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
499                            nsContainerFrame* aNewParentFrame,
500                            const nsFrameList& aFrameList,
501                            bool aForceStyleReparent) {
502   RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
503   for (nsIFrame* f : aFrameList) {
504     ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
505   }
506 }
507 
508 //----------------------------------------------------------------------
509 //
510 // When inline frames get weird and have block frames in them, we
511 // annotate them to help us respond to incremental content changes
512 // more easily.
513 
IsFramePartOfIBSplit(nsIFrame * aFrame)514 static inline bool IsFramePartOfIBSplit(nsIFrame* aFrame) {
515   bool result = (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0;
516   MOZ_ASSERT(!result || static_cast<nsBlockFrame*>(do_QueryFrame(aFrame)) ||
517                  static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)),
518              "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT");
519   return result;
520 }
521 
GetIBSplitSibling(nsIFrame * aFrame)522 static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) {
523   NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
524 
525   // We only store the "ib-split sibling" annotation with the first
526   // frame in the continuation chain. Walk back to find that frame now.
527   return aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
528 }
529 
GetIBSplitPrevSibling(nsIFrame * aFrame)530 static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) {
531   NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
532 
533   // We only store the ib-split sibling annotation with the first
534   // frame in the continuation chain. Walk back to find that frame now.
535   return aFrame->FirstContinuation()->GetProperty(
536       nsIFrame::IBSplitPrevSibling());
537 }
538 
GetLastIBSplitSibling(nsIFrame * aFrame)539 static nsContainerFrame* GetLastIBSplitSibling(nsIFrame* aFrame) {
540   for (nsIFrame *frame = aFrame, *next;; frame = next) {
541     next = GetIBSplitSibling(frame);
542     if (!next) {
543       return static_cast<nsContainerFrame*>(frame);
544     }
545   }
546   NS_NOTREACHED("unreachable code");
547   return nullptr;
548 }
549 
SetFrameIsIBSplit(nsContainerFrame * aFrame,nsContainerFrame * aIBSplitSibling)550 static void SetFrameIsIBSplit(nsContainerFrame* aFrame,
551                               nsContainerFrame* aIBSplitSibling) {
552   NS_PRECONDITION(aFrame, "bad args!");
553 
554   // We should be the only continuation
555   NS_ASSERTION(!aFrame->GetPrevContinuation(),
556                "assigning ib-split sibling to other than first continuation!");
557   NS_ASSERTION(!aFrame->GetNextContinuation() ||
558                    IsFramePartOfIBSplit(aFrame->GetNextContinuation()),
559                "should have no non-ib-split continuations here");
560 
561   // Mark the frame as ib-split.
562   aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
563 
564   if (aIBSplitSibling) {
565     NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),
566                  "assigning something other than the first continuation as the "
567                  "ib-split sibling");
568 
569     // Store the ib-split sibling (if we were given one) with the
570     // first frame in the flow.
571     aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
572     aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
573   }
574 }
575 
GetIBContainingBlockFor(nsIFrame * aFrame)576 static nsIFrame* GetIBContainingBlockFor(nsIFrame* aFrame) {
577   NS_PRECONDITION(
578       IsFramePartOfIBSplit(aFrame),
579       "GetIBContainingBlockFor() should only be called on known IB frames");
580 
581   // Get the first "normal" ancestor of the target frame.
582   nsIFrame* parentFrame;
583   do {
584     parentFrame = aFrame->GetParent();
585 
586     if (!parentFrame) {
587       NS_ERROR("no unsplit block frame in IB hierarchy");
588       return aFrame;
589     }
590 
591     // Note that we ignore non-ib-split frames which have a pseudo on their
592     // style context -- they're not the frames we're looking for!  In
593     // particular, they may be hiding a real parent that _is_ in an ib-split.
594     if (!IsFramePartOfIBSplit(parentFrame) &&
595         !parentFrame->StyleContext()->GetPseudo())
596       break;
597 
598     aFrame = parentFrame;
599   } while (1);
600 
601   // post-conditions
602   NS_ASSERTION(parentFrame,
603                "no normal ancestor found for ib-split frame "
604                "in GetIBContainingBlockFor");
605   NS_ASSERTION(parentFrame != aFrame,
606                "parentFrame is actually the child frame - bogus reslt");
607 
608   return parentFrame;
609 }
610 
611 // This is a bit slow, but sometimes we need it.
ParentIsWrapperAnonBox(nsIFrame * aParent)612 static bool ParentIsWrapperAnonBox(nsIFrame* aParent) {
613   nsIFrame* maybeAnonBox = aParent;
614   if (maybeAnonBox->StyleContext()->GetPseudo() ==
615       nsCSSAnonBoxes::cellContent) {
616     // The thing that would maybe be a wrapper anon box is the cell.
617     maybeAnonBox = maybeAnonBox->GetParent();
618   }
619   return maybeAnonBox->StyleContext()->IsWrapperAnonBox();
620 }
621 
622 //----------------------------------------------------------------------
623 
624 // Block/inline frame construction logic. We maintain a few invariants here:
625 //
626 // 1. Block frames contain block and inline frames.
627 //
628 // 2. Inline frames only contain inline frames. If an inline parent has a block
629 // child then the block child is migrated upward until it lands in a block
630 // parent (the inline frames containing block is where it will end up).
631 
632 // After this function returns, aLink is pointing to the first link at or
633 // after its starting position for which the next frame is a block.  If there
634 // is no such link, it points to the end of the list.
FindFirstBlock(nsFrameList::FrameLinkEnumerator & aLink)635 static void FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink) {
636   for (; !aLink.AtEnd(); aLink.Next()) {
637     if (!aLink.NextFrame()->IsInlineOutside()) {
638       return;
639     }
640   }
641 }
642 
643 // This function returns a frame link enumerator pointing to the first link in
644 // the list for which the next frame is not block.  If there is no such link,
645 // it points to the end of the list.
FindFirstNonBlock(const nsFrameList & aList)646 static nsFrameList::FrameLinkEnumerator FindFirstNonBlock(
647     const nsFrameList& aList) {
648   nsFrameList::FrameLinkEnumerator link(aList);
649   for (; !link.AtEnd(); link.Next()) {
650     if (link.NextFrame()->IsInlineOutside()) {
651       break;
652     }
653   }
654   return link;
655 }
656 
SetInitialSingleChild(nsContainerFrame * aParent,nsIFrame * aFrame)657 inline void SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame) {
658   NS_PRECONDITION(!aFrame->GetNextSibling(), "Should be using a frame list");
659   nsFrameList temp(aFrame, aFrame);
660   aParent->SetInitialChildList(kPrincipalList, temp);
661 }
662 
663 // -----------------------------------------------------------
664 
665 // Structure used when constructing formatting object trees.
666 struct nsFrameItems : public nsFrameList {
667   // Appends the frame to the end of the list
668   void AddChild(nsIFrame* aChild);
669 };
670 
AddChild(nsIFrame * aChild)671 void nsFrameItems::AddChild(nsIFrame* aChild) {
672   NS_PRECONDITION(aChild, "nsFrameItems::AddChild");
673 
674   // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild)
675   // here, but some of our callers put frames that have different parents
676   // (caption, I'm looking at you) on the same framelist, and nsFrameList
677   // asserts if you try to do that.
678   if (IsEmpty()) {
679     SetFrames(aChild);
680   } else {
681     NS_ASSERTION(aChild != mLastChild,
682                  "Same frame being added to frame list twice?");
683     mLastChild->SetNextSibling(aChild);
684     mLastChild = nsLayoutUtils::GetLastSibling(aChild);
685   }
686 }
687 
688 // -----------------------------------------------------------
689 
690 // Structure used when constructing formatting object trees. Contains
691 // state information needed for absolutely positioned elements
692 struct nsAbsoluteItems : nsFrameItems {
693   // containing block for absolutely positioned elements
694   nsContainerFrame* containingBlock;
695 
696   explicit nsAbsoluteItems(nsContainerFrame* aContainingBlock);
697 #ifdef DEBUG
698   // XXXbz Does this need a debug-only assignment operator that nulls out the
699   // childList in the nsAbsoluteItems we're copying?  Introducing a difference
700   // between debug and non-debug behavior seems bad, so I guess not...
~nsAbsoluteItemsnsAbsoluteItems701   ~nsAbsoluteItems() {
702     NS_ASSERTION(!FirstChild(),
703                  "Dangling child list.  Someone forgot to insert it?");
704   }
705 #endif
706 
707   // Appends the frame to the end of the list
708   void AddChild(nsIFrame* aChild);
709 };
710 
nsAbsoluteItems(nsContainerFrame * aContainingBlock)711 nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock)
712     : containingBlock(aContainingBlock) {}
713 
714 // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
AddChild(nsIFrame * aChild)715 void nsAbsoluteItems::AddChild(nsIFrame* aChild) {
716   aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
717   NS_ASSERTION(aChild->GetPlaceholderFrame(),
718                "Child without placeholder being added to nsAbsoluteItems?");
719   nsFrameItems::AddChild(aChild);
720 }
721 
722 // -----------------------------------------------------------
723 
724 // Structure for saving the existing state when pushing/poping containing
725 // blocks. The destructor restores the state to its previous state
726 class MOZ_STACK_CLASS nsFrameConstructorSaveState {
727  public:
728   typedef nsIFrame::ChildListID ChildListID;
729   nsFrameConstructorSaveState();
730   ~nsFrameConstructorSaveState();
731 
732  private:
733   nsAbsoluteItems* mItems;      // pointer to struct whose data we save/restore
734   nsAbsoluteItems mSavedItems;  // copy of original data
735 
736   // The name of the child list in which our frames would belong
737   ChildListID mChildListID;
738   nsFrameConstructorState* mState;
739 
740   // State used only when we're saving the abs-pos state for a transformed
741   // element.
742   nsAbsoluteItems mSavedFixedItems;
743 
744   bool mSavedFixedPosIsAbsPos;
745 
746   friend class nsFrameConstructorState;
747 };
748 
749 // Structure used to keep track of a list of bindings we need to call
750 // AddToAttachedQueue on.  These should be in post-order depth-first
751 // flattened tree traversal order.
752 struct PendingBinding : public LinkedListElement<PendingBinding> {
753 #ifdef NS_BUILD_REFCNT_LOGGING
PendingBindingPendingBinding754   PendingBinding() { MOZ_COUNT_CTOR(PendingBinding); }
~PendingBindingPendingBinding755   ~PendingBinding() { MOZ_COUNT_DTOR(PendingBinding); }
756 #endif
757 
758   RefPtr<nsXBLBinding> mBinding;
759 };
760 
761 // Structure used for maintaining state information during the
762 // frame construction process
763 class MOZ_STACK_CLASS nsFrameConstructorState {
764  public:
765   typedef nsIFrame::ChildListID ChildListID;
766 
767   nsPresContext* mPresContext;
768   nsIPresShell* mPresShell;
769   nsFrameManager* mFrameManager;
770 
771 #ifdef MOZ_XUL
772   // Frames destined for the kPopupList.
773   nsAbsoluteItems mPopupItems;
774 #endif
775 
776   // Containing block information for out-of-flow frames.
777   nsAbsoluteItems mFixedItems;
778   nsAbsoluteItems mAbsoluteItems;
779   nsAbsoluteItems mFloatedItems;
780   // The containing block of a frame in the top layer is defined by the
781   // spec: fixed-positioned frames are children of the viewport frame,
782   // and absolutely-positioned frames are children of the initial
783   // containing block. They would not be caught by any other containing
784   // block, e.g. frames with transform or filter.
785   nsAbsoluteItems mTopLayerFixedItems;
786   nsAbsoluteItems mTopLayerAbsoluteItems;
787 
788   nsCOMPtr<nsILayoutHistoryState> mFrameState;
789   // These bits will be added to the state bits of any frame we construct
790   // using this state.
791   nsFrameState mAdditionalStateBits;
792 
793   // When working with the transform and filter properties, we want to hook
794   // the abs-pos and fixed-pos lists together, since such
795   // elements are fixed-pos containing blocks.  This flag determines
796   // whether or not we want to wire the fixed-pos and abs-pos lists
797   // together.
798   bool mFixedPosIsAbsPos;
799 
800   // A boolean to indicate whether we have a "pending" popupgroup.  That is, we
801   // have already created the FrameConstructionItem for the root popupgroup but
802   // we have not yet created the relevant frame.
803   bool mHavePendingPopupgroup;
804 
805   // If false (which is the default) then call SetPrimaryFrame() as needed
806   // during frame construction.  If true, don't make any SetPrimaryFrame()
807   // calls, except for generated content which doesn't have a primary frame
808   // yet.  The mCreatingExtraFrames == true mode is meant to be used for
809   // construction of random "extra" frames for elements via normal frame
810   // construction APIs (e.g. replication of things across pages in paginated
811   // mode).
812   bool mCreatingExtraFrames;
813 
814   nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
815 
816   // Selector matching context for. This is null when we're using the Servo
817   // style system.
818   TreeMatchContext* mTreeMatchContext;
819 
820   // Constructor
821   // Use the passed-in history state.
822   //
823   // aTreeMatchContext is null when we're using the Servo style system.
824   nsFrameConstructorState(
825       nsIPresShell* aPresShell, TreeMatchContext* aTreeMatchContext,
826       nsContainerFrame* aFixedContainingBlock,
827       nsContainerFrame* aAbsoluteContainingBlock,
828       nsContainerFrame* aFloatContainingBlock,
829       already_AddRefed<nsILayoutHistoryState> aHistoryState);
830   // Get the history state from the pres context's pres shell.
831   nsFrameConstructorState(nsIPresShell* aPresShell,
832                           TreeMatchContext* aTreeMatchContext,
833                           nsContainerFrame* aFixedContainingBlock,
834                           nsContainerFrame* aAbsoluteContainingBlock,
835                           nsContainerFrame* aFloatContainingBlock);
836 
837   ~nsFrameConstructorState();
838 
HasAncestorFilter()839   bool HasAncestorFilter() {
840 #ifdef MOZ_OLD_STYLE
841     return mTreeMatchContext && mTreeMatchContext->mAncestorFilter.HasFilter();
842 #else
843     return false;
844 #endif
845   }
846 
847   // Function to push the existing absolute containing block state and
848   // create a new scope. Code that uses this function should get matching
849   // logic in GetAbsoluteContainingBlock.
850   // Also makes aNewAbsoluteContainingBlock the containing block for
851   // fixed-pos elements if necessary.
852   // aPositionedFrame is the frame whose style actually makes
853   // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable
854   // element aPositionedFrame is the element's primary frame and
855   // aNewAbsoluteContainingBlock is the scrolled frame.
856   void PushAbsoluteContainingBlock(
857       nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
858       nsFrameConstructorSaveState& aSaveState);
859 
860   // Function to push the existing float containing block state and
861   // create a new scope. Code that uses this function should get matching
862   // logic in GetFloatContainingBlock.
863   // Pushing a null float containing block forbids any frames from being
864   // floated until a new float containing block is pushed.
865   // XXX we should get rid of null float containing blocks and teach the
866   // various frame classes to deal with floats instead.
867   void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
868                                 nsFrameConstructorSaveState& aSaveState);
869 
870   // Function to return the proper geometric parent for a frame with display
871   // struct given by aStyleDisplay and parent's frame given by
872   // aContentParentFrame.
873   nsContainerFrame* GetGeometricParent(
874       const nsStyleDisplay* aStyleDisplay,
875       nsContainerFrame* aContentParentFrame) const;
876 
877   /**
878    * Function to add a new frame to the right frame list.  This MUST be called
879    * on frames before their children have been processed if the frames might
880    * conceivably be out-of-flow; otherwise cleanup in error cases won't work
881    * right.  Also, this MUST be called on frames after they have been
882    * initialized.
883    * @param aNewFrame the frame to add
884    * @param aFrameItems the list to add in-flow frames to
885    * @param aContent the content pointer for aNewFrame
886    * @param aParentFrame the parent frame for the content if it were in-flow
887    * @param aCanBePositioned pass false if the frame isn't allowed to be
888    *        positioned
889    * @param aCanBeFloated pass false if the frame isn't allowed to be
890    *        floated
891    * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
892    *        (XUL-only)
893    */
894   void AddChild(nsIFrame* aNewFrame, nsFrameItems& aFrameItems,
895                 nsIContent* aContent, nsContainerFrame* aParentFrame,
896                 bool aCanBePositioned = true, bool aCanBeFloated = true,
897                 bool aIsOutOfFlowPopup = false, bool aInsertAfter = false,
898                 nsIFrame* aInsertAfterFrame = nullptr);
899 
900   /**
901    * Function to return the fixed-pos element list.  Normally this will just
902    * hand back the fixed-pos element list, but in case we're dealing with a
903    * transformed element that's acting as an abs-pos and fixed-pos container,
904    * we'll hand back the abs-pos list.  Callers should use this function if they
905    * want to get the list acting as the fixed-pos item parent.
906    */
GetFixedItems()907   nsAbsoluteItems& GetFixedItems() {
908     return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
909   }
GetFixedItems() const910   const nsAbsoluteItems& GetFixedItems() const {
911     return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
912   }
913 
914   /**
915    * class to automatically push and pop a pending binding in the frame
916    * constructor state.  See nsCSSFrameConstructor::FrameConstructionItem
917    * mPendingBinding documentation.
918    */
919   class PendingBindingAutoPusher;
920   friend class PendingBindingAutoPusher;
921   class MOZ_STACK_CLASS PendingBindingAutoPusher {
922    public:
PendingBindingAutoPusher(nsFrameConstructorState & aState,PendingBinding * aPendingBinding)923     PendingBindingAutoPusher(nsFrameConstructorState& aState,
924                              PendingBinding* aPendingBinding)
925         : mState(aState),
926           mPendingBinding(aState.mCurrentPendingBindingInsertionPoint) {
927       if (aPendingBinding) {
928         aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
929       }
930     }
931 
~PendingBindingAutoPusher()932     ~PendingBindingAutoPusher() {
933       mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
934     }
935 
936    private:
937     nsFrameConstructorState& mState;
938     PendingBinding* mPendingBinding;
939   };
940 
941   /**
942    * Add a new pending binding to the list
943    */
AddPendingBinding(PendingBinding * aPendingBinding)944   void AddPendingBinding(PendingBinding* aPendingBinding) {
945     if (mCurrentPendingBindingInsertionPoint) {
946       mCurrentPendingBindingInsertionPoint->setPrevious(aPendingBinding);
947     } else {
948       mPendingBindings.insertBack(aPendingBinding);
949     }
950   }
951 
952  protected:
953   friend class nsFrameConstructorSaveState;
954 
955   /**
956    * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
957    * kids to the aChildListID child list of |aFrameItems.containingBlock|.
958    */
959   void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
960                               ChildListID aChildListID);
961 
962   /**
963    * GetOutOfFlowFrameItems selects the out-of-flow frame list the new
964    * frame should be added to. If the frame shouldn't be added to any
965    * out-of-flow list, it returns nullptr. The corresponding type of
966    * placeholder is also returned via the aPlaceholderType parameter
967    * if this method doesn't return nullptr. The caller should check
968    * whether the returned list really has a containing block.
969    */
970   nsAbsoluteItems* GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
971                                           bool aCanBePositioned,
972                                           bool aCanBeFloated,
973                                           bool aIsOutOfFlowPopup,
974                                           nsFrameState* aPlaceholderType);
975 
976   void ConstructBackdropFrameFor(nsIContent* aContent, nsIFrame* aFrame);
977 
978   // Our list of all pending bindings.  When we're done, we need to call
979   // AddToAttachedQueue on all of them, in order.
980   LinkedList<PendingBinding> mPendingBindings;
981 
982   PendingBinding* mCurrentPendingBindingInsertionPoint;
983 };
984 
985 #ifndef MOZ_OLD_STYLE
986 
987 namespace mozilla {
988 
989 class AutoDisplayContentsAncestorPusher {
990  public:
AutoDisplayContentsAncestorPusher(TreeMatchContext & aTreeMatchContext,nsPresContext * aPresContext,nsIContent * aParent)991   AutoDisplayContentsAncestorPusher(TreeMatchContext& aTreeMatchContext,
992                                     nsPresContext* aPresContext,
993                                     nsIContent* aParent) {}
IsEmpty() const994   bool IsEmpty() const { return false; }
995 };
996 
997 }  // namespace mozilla
998 
999 #endif
1000 
nsFrameConstructorState(nsIPresShell * aPresShell,TreeMatchContext * aTreeMatchContext,nsContainerFrame * aFixedContainingBlock,nsContainerFrame * aAbsoluteContainingBlock,nsContainerFrame * aFloatContainingBlock,already_AddRefed<nsILayoutHistoryState> aHistoryState)1001 nsFrameConstructorState::nsFrameConstructorState(
1002     nsIPresShell* aPresShell, TreeMatchContext* aTreeMatchContext,
1003     nsContainerFrame* aFixedContainingBlock,
1004     nsContainerFrame* aAbsoluteContainingBlock,
1005     nsContainerFrame* aFloatContainingBlock,
1006     already_AddRefed<nsILayoutHistoryState> aHistoryState)
1007     : mPresContext(aPresShell->GetPresContext()),
1008       mPresShell(aPresShell),
1009       mFrameManager(aPresShell->FrameConstructor()),
1010 #ifdef MOZ_XUL
1011       mPopupItems(nullptr),
1012 #endif
1013       mFixedItems(aFixedContainingBlock),
1014       mAbsoluteItems(aAbsoluteContainingBlock),
1015       mFloatedItems(aFloatContainingBlock),
1016       mTopLayerFixedItems(
1017           static_cast<nsContainerFrame*>(mFrameManager->GetRootFrame())),
1018       mTopLayerAbsoluteItems(
1019           aPresShell->FrameConstructor()->GetDocElementContainingBlock()),
1020       // See PushAbsoluteContaningBlock below
1021       mFrameState(aHistoryState),
1022       mAdditionalStateBits(nsFrameState(0)),
1023       // If the fixed-pos containing block is equal to the abs-pos containing
1024       // block, use the abs-pos containing block's abs-pos list for fixed-pos
1025       // frames.
1026       mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
1027       mHavePendingPopupgroup(false),
1028       mCreatingExtraFrames(false),
1029       mTreeMatchContext(aTreeMatchContext),
1030       mCurrentPendingBindingInsertionPoint(nullptr) {
1031 #ifdef MOZ_XUL
1032   nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
1033   if (rootBox) {
1034     mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
1035   }
1036 #endif
1037   MOZ_COUNT_CTOR(nsFrameConstructorState);
1038 }
1039 
nsFrameConstructorState(nsIPresShell * aPresShell,TreeMatchContext * aTreeMatchContext,nsContainerFrame * aFixedContainingBlock,nsContainerFrame * aAbsoluteContainingBlock,nsContainerFrame * aFloatContainingBlock)1040 nsFrameConstructorState::nsFrameConstructorState(
1041     nsIPresShell* aPresShell, TreeMatchContext* aTreeMatchContext,
1042     nsContainerFrame* aFixedContainingBlock,
1043     nsContainerFrame* aAbsoluteContainingBlock,
1044     nsContainerFrame* aFloatContainingBlock)
1045     : nsFrameConstructorState(
1046           aPresShell, aTreeMatchContext, aFixedContainingBlock,
1047           aAbsoluteContainingBlock, aFloatContainingBlock,
1048           aPresShell->GetDocument()->GetLayoutHistoryState()) {}
1049 
~nsFrameConstructorState()1050 nsFrameConstructorState::~nsFrameConstructorState() {
1051   MOZ_COUNT_DTOR(nsFrameConstructorState);
1052   ProcessFrameInsertions(mTopLayerFixedItems, nsIFrame::kFixedList);
1053   ProcessFrameInsertions(mTopLayerAbsoluteItems, nsIFrame::kAbsoluteList);
1054   ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
1055   ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
1056   ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
1057 #ifdef MOZ_XUL
1058   ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList);
1059 #endif
1060   for (int32_t i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0;
1061        --i) {
1062     mGeneratedTextNodesWithInitializer[i]->DeleteProperty(
1063         nsGkAtoms::genConInitializerProperty);
1064   }
1065   if (!mPendingBindings.isEmpty()) {
1066     nsBindingManager* bindingManager =
1067         mPresShell->GetDocument()->BindingManager();
1068     do {
1069       nsAutoPtr<PendingBinding> pendingBinding;
1070       pendingBinding = mPendingBindings.popFirst();
1071       bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
1072     } while (!mPendingBindings.isEmpty());
1073     mCurrentPendingBindingInsertionPoint = nullptr;
1074   }
1075 }
1076 
AdjustAbsoluteContainingBlock(nsContainerFrame * aContainingBlockIn)1077 static nsContainerFrame* AdjustAbsoluteContainingBlock(
1078     nsContainerFrame* aContainingBlockIn) {
1079   if (!aContainingBlockIn) {
1080     return nullptr;
1081   }
1082 
1083   // Always use the container's first continuation. (Inline frames can have
1084   // non-fluid bidi continuations...)
1085   return static_cast<nsContainerFrame*>(
1086       aContainingBlockIn->FirstContinuation());
1087 }
1088 
PushAbsoluteContainingBlock(nsContainerFrame * aNewAbsoluteContainingBlock,nsIFrame * aPositionedFrame,nsFrameConstructorSaveState & aSaveState)1089 void nsFrameConstructorState::PushAbsoluteContainingBlock(
1090     nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
1091     nsFrameConstructorSaveState& aSaveState) {
1092   aSaveState.mItems = &mAbsoluteItems;
1093   aSaveState.mSavedItems = mAbsoluteItems;
1094   aSaveState.mChildListID = nsIFrame::kAbsoluteList;
1095   aSaveState.mState = this;
1096   aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
1097 
1098   if (mFixedPosIsAbsPos) {
1099     // Since we're going to replace mAbsoluteItems, we need to save it into
1100     // mFixedItems now (and save the current value of mFixedItems).
1101     aSaveState.mSavedFixedItems = mFixedItems;
1102     mFixedItems = mAbsoluteItems;
1103   }
1104 
1105   mAbsoluteItems = nsAbsoluteItems(
1106       AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
1107 
1108   /* See if we're wiring the fixed-pos and abs-pos lists together.  This happens
1109    * iff we're a transformed element.
1110    */
1111   mFixedPosIsAbsPos =
1112       aPositionedFrame && aPositionedFrame->IsFixedPosContainingBlock();
1113 
1114   if (aNewAbsoluteContainingBlock) {
1115     aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
1116   }
1117 }
1118 
PushFloatContainingBlock(nsContainerFrame * aNewFloatContainingBlock,nsFrameConstructorSaveState & aSaveState)1119 void nsFrameConstructorState::PushFloatContainingBlock(
1120     nsContainerFrame* aNewFloatContainingBlock,
1121     nsFrameConstructorSaveState& aSaveState) {
1122   NS_PRECONDITION(!aNewFloatContainingBlock ||
1123                       aNewFloatContainingBlock->IsFloatContainingBlock(),
1124                   "Please push a real float containing block!");
1125   NS_ASSERTION(
1126       !aNewFloatContainingBlock ||
1127           !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),
1128       "We should not push a frame that is supposed to _suppress_ "
1129       "floats as a float containing block!");
1130   aSaveState.mItems = &mFloatedItems;
1131   aSaveState.mSavedItems = mFloatedItems;
1132   aSaveState.mChildListID = nsIFrame::kFloatList;
1133   aSaveState.mState = this;
1134   mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock);
1135 }
1136 
GetGeometricParent(const nsStyleDisplay * aStyleDisplay,nsContainerFrame * aContentParentFrame) const1137 nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
1138     const nsStyleDisplay* aStyleDisplay,
1139     nsContainerFrame* aContentParentFrame) const {
1140   NS_PRECONDITION(aStyleDisplay, "Must have display struct!");
1141 
1142   // If there is no container for a fixed, absolute, or floating root
1143   // frame, we will ignore the positioning.  This hack is originally
1144   // brought to you by the letter T: tables, since other roots don't
1145   // even call into this code.  See bug 178855.
1146   //
1147   // XXX Disabling positioning in this case is a hack.  If one was so inclined,
1148   // one could support this either by (1) inserting a dummy block between the
1149   // table and the canvas or (2) teaching the canvas how to reflow positioned
1150   // elements. (1) has the usual problems when multiple frames share the same
1151   // content (notice all the special cases in this file dealing with inner
1152   // tables and table wrappers which share the same content). (2) requires some
1153   // work and possible factoring.
1154   //
1155   // XXXbz couldn't we just force position to "static" on roots and
1156   // float to "none"?  That's OK per CSS 2.1, as far as I can tell.
1157 
1158   if (aContentParentFrame &&
1159       nsSVGUtils::IsInSVGTextSubtree(aContentParentFrame)) {
1160     return aContentParentFrame;
1161   }
1162 
1163   if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) {
1164     NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(),
1165                  "Absolutely positioned _and_ floating?");
1166     return mFloatedItems.containingBlock;
1167   }
1168 
1169   if (aStyleDisplay->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1170     MOZ_ASSERT(aStyleDisplay->mTopLayer == NS_STYLE_TOP_LAYER_TOP,
1171                "-moz-top-layer should be either none or top");
1172     MOZ_ASSERT(aStyleDisplay->IsAbsolutelyPositionedStyle(),
1173                "Top layer items should always be absolutely positioned");
1174     if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED) {
1175       MOZ_ASSERT(mTopLayerFixedItems.containingBlock, "No root frame?");
1176       return mTopLayerFixedItems.containingBlock;
1177     }
1178     MOZ_ASSERT(aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE);
1179     MOZ_ASSERT(mTopLayerAbsoluteItems.containingBlock);
1180     return mTopLayerAbsoluteItems.containingBlock;
1181   }
1182 
1183   if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
1184       mAbsoluteItems.containingBlock) {
1185     return mAbsoluteItems.containingBlock;
1186   }
1187 
1188   if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
1189       GetFixedItems().containingBlock) {
1190     return GetFixedItems().containingBlock;
1191   }
1192 
1193   return aContentParentFrame;
1194 }
1195 
GetOutOfFlowFrameItems(nsIFrame * aNewFrame,bool aCanBePositioned,bool aCanBeFloated,bool aIsOutOfFlowPopup,nsFrameState * aPlaceholderType)1196 nsAbsoluteItems* nsFrameConstructorState::GetOutOfFlowFrameItems(
1197     nsIFrame* aNewFrame, bool aCanBePositioned, bool aCanBeFloated,
1198     bool aIsOutOfFlowPopup, nsFrameState* aPlaceholderType) {
1199 #ifdef MOZ_XUL
1200   if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
1201     MOZ_ASSERT(mPopupItems.containingBlock, "Must have a popup set frame!");
1202     *aPlaceholderType = PLACEHOLDER_FOR_POPUP;
1203     return &mPopupItems;
1204   }
1205 #endif  // MOZ_XUL
1206   if (aCanBeFloated && aNewFrame->IsFloating()) {
1207     *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1208     return &mFloatedItems;
1209   }
1210 
1211   if (aCanBePositioned) {
1212     const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1213     if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1214       *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1215       if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1216         *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
1217         return &mTopLayerFixedItems;
1218       }
1219       *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
1220       return &mTopLayerAbsoluteItems;
1221     }
1222     if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) {
1223       *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1224       return &mAbsoluteItems;
1225     }
1226     if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1227       *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1228       return &GetFixedItems();
1229     }
1230   }
1231   return nullptr;
1232 }
1233 
ConstructBackdropFrameFor(nsIContent * aContent,nsIFrame * aFrame)1234 void nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent,
1235                                                         nsIFrame* aFrame) {
1236   MOZ_ASSERT(aFrame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1237   nsContainerFrame* frame = do_QueryFrame(aFrame);
1238   if (!frame) {
1239     NS_WARNING("Cannot create backdrop frame for non-container frame");
1240     return;
1241   }
1242 
1243   RefPtr<nsStyleContext> style =
1244       mPresShell->StyleSet()->ResolvePseudoElementStyle(
1245           aContent->AsElement(), CSSPseudoElementType::backdrop,
1246           /* aParentStyleContext */ nullptr,
1247           /* aPseudoElement */ nullptr);
1248   MOZ_ASSERT(style->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1249   nsContainerFrame* parentFrame =
1250       GetGeometricParent(style->StyleDisplay(), nullptr);
1251 
1252   nsBackdropFrame* backdropFrame = new (mPresShell) nsBackdropFrame(style);
1253   backdropFrame->Init(aContent, parentFrame, nullptr);
1254 
1255   nsFrameState placeholderType;
1256   nsAbsoluteItems* frameItems = GetOutOfFlowFrameItems(
1257       backdropFrame, true, true, false, &placeholderType);
1258   MOZ_ASSERT(placeholderType & PLACEHOLDER_FOR_TOPLAYER);
1259 
1260   nsIFrame* placeholder = nsCSSFrameConstructor::CreatePlaceholderFrameFor(
1261       mPresShell, aContent, backdropFrame, frame, nullptr, placeholderType);
1262   nsFrameList temp(placeholder, placeholder);
1263   frame->SetInitialChildList(nsIFrame::kBackdropList, temp);
1264 
1265   frameItems->AddChild(backdropFrame);
1266 }
1267 
AddChild(nsIFrame * aNewFrame,nsFrameItems & aFrameItems,nsIContent * aContent,nsContainerFrame * aParentFrame,bool aCanBePositioned,bool aCanBeFloated,bool aIsOutOfFlowPopup,bool aInsertAfter,nsIFrame * aInsertAfterFrame)1268 void nsFrameConstructorState::AddChild(
1269     nsIFrame* aNewFrame, nsFrameItems& aFrameItems, nsIContent* aContent,
1270     nsContainerFrame* aParentFrame, bool aCanBePositioned, bool aCanBeFloated,
1271     bool aIsOutOfFlowPopup, bool aInsertAfter, nsIFrame* aInsertAfterFrame) {
1272   NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen");
1273 
1274   nsFrameState placeholderType;
1275   nsAbsoluteItems* outOfFlowFrameItems =
1276       GetOutOfFlowFrameItems(aNewFrame, aCanBePositioned, aCanBeFloated,
1277                              aIsOutOfFlowPopup, &placeholderType);
1278 
1279   // The comments in GetGeometricParent regarding root table frames
1280   // all apply here, unfortunately. Thus, we need to check whether
1281   // the returned frame items really has containing block.
1282   nsFrameItems* frameItems;
1283   if (outOfFlowFrameItems && outOfFlowFrameItems->containingBlock) {
1284     MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameItems->containingBlock,
1285                "Parent of the frame is not the containing block?");
1286     frameItems = outOfFlowFrameItems;
1287   } else {
1288     frameItems = &aFrameItems;
1289     placeholderType = nsFrameState(0);
1290   }
1291 
1292   if (placeholderType) {
1293     NS_ASSERTION(frameItems != &aFrameItems,
1294                  "Putting frame in-flow _and_ want a placeholder?");
1295     nsIFrame* placeholderFrame =
1296         nsCSSFrameConstructor::CreatePlaceholderFrameFor(
1297             mPresShell, aContent, aNewFrame, aParentFrame, nullptr,
1298             placeholderType);
1299 
1300     placeholderFrame->AddStateBits(mAdditionalStateBits);
1301     // Add the placeholder frame to the flow
1302     aFrameItems.AddChild(placeholderFrame);
1303 
1304     if (placeholderType & PLACEHOLDER_FOR_TOPLAYER) {
1305       ConstructBackdropFrameFor(aContent, aNewFrame);
1306     }
1307   }
1308 #ifdef DEBUG
1309   else {
1310     NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
1311                  "In-flow frame has wrong parent");
1312   }
1313 #endif
1314 
1315   if (aInsertAfter) {
1316     frameItems->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1317   } else {
1318     frameItems->AddChild(aNewFrame);
1319   }
1320 }
1321 
ProcessFrameInsertions(nsAbsoluteItems & aFrameItems,ChildListID aChildListID)1322 void nsFrameConstructorState::ProcessFrameInsertions(
1323     nsAbsoluteItems& aFrameItems, ChildListID aChildListID) {
1324 #define NS_NONXUL_LIST_TEST                                                   \
1325   (&aFrameItems == &mFloatedItems && aChildListID == nsIFrame::kFloatList) || \
1326       ((&aFrameItems == &mAbsoluteItems ||                                    \
1327         &aFrameItems == &mTopLayerAbsoluteItems) &&                           \
1328        aChildListID == nsIFrame::kAbsoluteList) ||                            \
1329       ((&aFrameItems == &mFixedItems ||                                       \
1330         &aFrameItems == &mTopLayerFixedItems) &&                              \
1331        aChildListID == nsIFrame::kFixedList)
1332 #ifdef MOZ_XUL
1333   NS_PRECONDITION(NS_NONXUL_LIST_TEST || (&aFrameItems == &mPopupItems &&
1334                                           aChildListID == nsIFrame::kPopupList),
1335                   "Unexpected aFrameItems/aChildListID combination");
1336 #else
1337   NS_PRECONDITION(NS_NONXUL_LIST_TEST,
1338                   "Unexpected aFrameItems/aChildListID combination");
1339 #endif
1340 
1341   if (aFrameItems.IsEmpty()) {
1342     return;
1343   }
1344 
1345   nsContainerFrame* containingBlock = aFrameItems.containingBlock;
1346 
1347   NS_ASSERTION(containingBlock, "Child list without containing block?");
1348 
1349   if (aChildListID == nsIFrame::kFixedList) {
1350     // Put this frame on the transformed-frame's abs-pos list instead, if
1351     // it has abs-pos children instead of fixed-pos children.
1352     aChildListID = containingBlock->GetAbsoluteListID();
1353   }
1354 
1355   // Insert the frames hanging out in aItems.  We can use SetInitialChildList()
1356   // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1357   // is set) and doesn't have any frames in the aChildListID child list yet.
1358   const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1359   if (childList.IsEmpty() &&
1360       (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1361     // If we're injecting absolutely positioned frames, inject them on the
1362     // absolute containing block
1363     if (aChildListID == containingBlock->GetAbsoluteListID()) {
1364       containingBlock->GetAbsoluteContainingBlock()->SetInitialChildList(
1365           containingBlock, aChildListID, aFrameItems);
1366     } else {
1367       containingBlock->SetInitialChildList(aChildListID, aFrameItems);
1368     }
1369   } else if (aChildListID == nsIFrame::kFixedList ||
1370              aChildListID == nsIFrame::kAbsoluteList) {
1371     // The order is not important for abs-pos/fixed-pos frame list, just
1372     // append the frame items to the list directly.
1373     mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1374   } else {
1375     // Note that whether the frame construction context is doing an append or
1376     // not is not helpful here, since it could be appending to some frame in
1377     // the middle of the document, which means we're not necessarily
1378     // appending to the children of the containing block.
1379     //
1380     // We need to make sure the 'append to the end of document' case is fast.
1381     // So first test the last child of the containing block
1382     nsIFrame* lastChild = childList.LastChild();
1383 
1384     // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1385     // so this will make out-of-flows respect the ordering of placeholders,
1386     // which is great because it takes care of anonymous content.
1387     nsIFrame* firstNewFrame = aFrameItems.FirstChild();
1388 
1389     // Cache the ancestor chain so that we can reuse it if needed.
1390     AutoTArray<nsIFrame*, 20> firstNewFrameAncestors;
1391     nsIFrame* notCommonAncestor = nullptr;
1392     if (lastChild) {
1393       notCommonAncestor = nsLayoutUtils::FillAncestors(
1394           firstNewFrame, containingBlock, &firstNewFrameAncestors);
1395     }
1396 
1397     if (!lastChild || nsLayoutUtils::CompareTreePosition(
1398                           lastChild, firstNewFrame, firstNewFrameAncestors,
1399                           notCommonAncestor ? containingBlock : nullptr) < 0) {
1400       // no lastChild, or lastChild comes before the new children, so just
1401       // append
1402       mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1403     } else {
1404       // Try the other children. First collect them to an array so that a
1405       // reasonable fast binary search can be used to find the insertion point.
1406       AutoTArray<nsIFrame*, 128> children;
1407       for (nsIFrame* f = childList.FirstChild(); f != lastChild;
1408            f = f->GetNextSibling()) {
1409         children.AppendElement(f);
1410       }
1411 
1412       nsIFrame* insertionPoint = nullptr;
1413       int32_t imin = 0;
1414       int32_t max = children.Length();
1415       while (max > imin) {
1416         int32_t imid = imin + ((max - imin) / 2);
1417         nsIFrame* f = children[imid];
1418         int32_t compare = nsLayoutUtils::CompareTreePosition(
1419             f, firstNewFrame, firstNewFrameAncestors,
1420             notCommonAncestor ? containingBlock : nullptr);
1421         if (compare > 0) {
1422           // f is after the new frame.
1423           max = imid;
1424           insertionPoint = imid > 0 ? children[imid - 1] : nullptr;
1425         } else if (compare < 0) {
1426           // f is before the new frame.
1427           imin = imid + 1;
1428           insertionPoint = f;
1429         } else {
1430           // This is for the old behavior. Should be removed once it is
1431           // guaranteed that CompareTreePosition can't return 0!
1432           // See bug 928645.
1433           NS_WARNING("Something odd happening???");
1434           insertionPoint = nullptr;
1435           for (uint32_t i = 0; i < children.Length(); ++i) {
1436             nsIFrame* f = children[i];
1437             if (nsLayoutUtils::CompareTreePosition(
1438                     f, firstNewFrame, firstNewFrameAncestors,
1439                     notCommonAncestor ? containingBlock : nullptr) > 0) {
1440               break;
1441             }
1442             insertionPoint = f;
1443           }
1444           break;
1445         }
1446       }
1447       mFrameManager->InsertFrames(containingBlock, aChildListID, insertionPoint,
1448                                   aFrameItems);
1449     }
1450   }
1451 
1452   MOZ_ASSERT(aFrameItems.IsEmpty(), "How did that happen?");
1453 }
1454 
nsFrameConstructorSaveState()1455 nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1456     : mItems(nullptr),
1457       mSavedItems(nullptr),
1458       mChildListID(kPrincipalList),
1459       mState(nullptr),
1460       mSavedFixedItems(nullptr),
1461       mSavedFixedPosIsAbsPos(false) {}
1462 
~nsFrameConstructorSaveState()1463 nsFrameConstructorSaveState::~nsFrameConstructorSaveState() {
1464   // Restore the state
1465   if (mItems) {
1466     NS_ASSERTION(mState, "Can't have mItems set without having a state!");
1467     mState->ProcessFrameInsertions(*mItems, mChildListID);
1468     *mItems = mSavedItems;
1469 #ifdef DEBUG
1470     // We've transferred the child list, so drop the pointer we held to it.
1471     // Note that this only matters for the assert in ~nsAbsoluteItems.
1472     mSavedItems.Clear();
1473 #endif
1474     if (mItems == &mState->mAbsoluteItems) {
1475       mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
1476       if (mSavedFixedPosIsAbsPos) {
1477         // mAbsoluteItems was moved to mFixedItems, so move mFixedItems back
1478         // and repair the old mFixedItems now.
1479         mState->mAbsoluteItems = mState->mFixedItems;
1480         mState->mFixedItems = mSavedFixedItems;
1481 #ifdef DEBUG
1482         mSavedFixedItems.Clear();
1483 #endif
1484       }
1485     }
1486     NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(),
1487                  "Something corrupted our list");
1488   }
1489 }
1490 
1491 /**
1492  * Moves aFrameList from aOldParent to aNewParent.  This updates the parent
1493  * pointer of the frames in the list, and reparents their views as needed.
1494  * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1495  * ancestors as needed. Then it sets the list as the initial child list
1496  * on aNewParent, unless aNewParent either already has kids or has been
1497  * reflowed; in that case it appends the new frames.  Note that this
1498  * method differs from ReparentFrames in that it doesn't change the kids'
1499  * style contexts.
1500  */
1501 // XXXbz Since this is only used for {ib} splits, could we just copy the view
1502 // bits from aOldParent to aNewParent and then use the
1503 // nsFrameList::ApplySetParent?  That would still leave us doing two passes
1504 // over the list, of course; if we really wanted to we could factor out the
1505 // relevant part of ReparentFrameViewList, I suppose...  Or just get rid of
1506 // views, which would make most of this function go away.
MoveChildrenTo(nsIFrame * aOldParent,nsContainerFrame * aNewParent,nsFrameList & aFrameList)1507 static void MoveChildrenTo(nsIFrame* aOldParent, nsContainerFrame* aNewParent,
1508                            nsFrameList& aFrameList) {
1509   bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent();
1510 
1511   if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) {
1512     // Move the frames into the new view
1513     nsContainerFrame::ReparentFrameViewList(aFrameList, aOldParent, aNewParent);
1514   }
1515 
1516   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
1517     e.get()->SetParent(aNewParent);
1518   }
1519 
1520   if (aNewParent->PrincipalChildList().IsEmpty() &&
1521       (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1522     aNewParent->SetInitialChildList(kPrincipalList, aFrameList);
1523   } else {
1524     aNewParent->AppendFrames(kPrincipalList, aFrameList);
1525   }
1526 }
1527 
1528 //----------------------------------------------------------------------
1529 
nsCSSFrameConstructor(nsIDocument * aDocument,nsIPresShell * aPresShell)1530 nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument* aDocument,
1531                                              nsIPresShell* aPresShell)
1532     : nsFrameManager(aPresShell),
1533       mDocument(aDocument),
1534       mRootElementFrame(nullptr),
1535       mRootElementStyleFrame(nullptr),
1536       mDocElementContainingBlock(nullptr),
1537       mPageSequenceFrame(nullptr),
1538       mFirstFreeFCItem(nullptr),
1539       mFCItemsInUse(0),
1540       mCurrentDepth(0),
1541       mQuotesDirty(false),
1542       mCountersDirty(false),
1543       mIsDestroyingFrameTree(false),
1544       mHasRootAbsPosContainingBlock(false),
1545       mAlwaysCreateFramesForIgnorableWhitespace(false) {
1546 #ifdef DEBUG
1547   static bool gFirstTime = true;
1548   if (gFirstTime) {
1549     gFirstTime = false;
1550     char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1551     if (flags) {
1552       bool error = false;
1553       for (;;) {
1554         char* comma = PL_strchr(flags, ',');
1555         if (comma) *comma = '\0';
1556 
1557         bool found = false;
1558         FrameCtorDebugFlags* flag = gFlags;
1559         FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1560         while (flag < limit) {
1561           if (PL_strcasecmp(flag->name, flags) == 0) {
1562             *(flag->on) = true;
1563             printf("nsCSSFrameConstructor: setting %s debug flag on\n",
1564                    flag->name);
1565             found = true;
1566             break;
1567           }
1568           ++flag;
1569         }
1570 
1571         if (!found) error = true;
1572 
1573         if (!comma) break;
1574 
1575         *comma = ',';
1576         flags = comma + 1;
1577       }
1578 
1579       if (error) {
1580         printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1581         FrameCtorDebugFlags* flag = gFlags;
1582         FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1583         while (flag < limit) {
1584           printf("  %s\n", flag->name);
1585           ++flag;
1586         }
1587         printf(
1588             "Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of "
1589             "flag\n");
1590         printf("names (no whitespace)\n");
1591       }
1592     }
1593   }
1594 #endif
1595 }
1596 
NotifyDestroyingFrame(nsIFrame * aFrame)1597 void nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) {
1598   if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
1599     if (mQuoteList.DestroyNodesFor(aFrame)) QuotesDirty();
1600   }
1601 
1602   if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1603       mCounterManager.DestroyNodesFor(aFrame)) {
1604     // Technically we don't need to update anything if we destroyed only
1605     // USE nodes.  However, this is unlikely to happen in the real world
1606     // since USE nodes generally go along with INCREMENT nodes.
1607     CountersDirty();
1608   }
1609 
1610   RestyleManager()->NotifyDestroyingFrame(aFrame);
1611 
1612   nsFrameManager::NotifyDestroyingFrame(aFrame);
1613 }
1614 
1615 struct nsGenConInitializer {
1616   nsAutoPtr<nsGenConNode> mNode;
1617   nsGenConList* mList;
1618   void (nsCSSFrameConstructor::*mDirtyAll)();
1619 
nsGenConInitializernsGenConInitializer1620   nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
1621                       void (nsCSSFrameConstructor::*aDirtyAll)())
1622       : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {}
1623 };
1624 
CreateGenConTextNode(nsFrameConstructorState & aState,const nsString & aString,RefPtr<nsTextNode> * aText,nsGenConInitializer * aInitializer)1625 already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
1626     nsFrameConstructorState& aState, const nsString& aString,
1627     RefPtr<nsTextNode>* aText, nsGenConInitializer* aInitializer) {
1628   RefPtr<nsTextNode> content = new nsTextNode(mDocument->NodeInfoManager());
1629   content->SetText(aString, false);
1630   if (aText) {
1631     *aText = content;
1632   }
1633   if (aInitializer) {
1634     content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
1635                          nsINode::DeleteProperty<nsGenConInitializer>);
1636     aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
1637   }
1638   return content.forget();
1639 }
1640 
CreateGeneratedContent(nsFrameConstructorState & aState,Element * aParentContent,nsStyleContext * aStyleContext,uint32_t aContentIndex)1641 already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
1642     nsFrameConstructorState& aState, Element* aParentContent,
1643     nsStyleContext* aStyleContext, uint32_t aContentIndex) {
1644   // Get the content value
1645   const nsStyleContentData& data =
1646       aStyleContext->StyleContent()->ContentAt(aContentIndex);
1647   nsStyleContentType type = data.GetType();
1648 
1649   switch (type) {
1650     case eStyleContentType_Image: {
1651       imgRequestProxy* image = data.GetImage();
1652       if (!image) {
1653         // CSS had something specified that couldn't be converted to an
1654         // image object
1655         return nullptr;
1656       }
1657 
1658       // Create an image content object and pass it the image request.
1659       // XXX Check if it's an image type we can handle...
1660 
1661       return CreateGenConImageContent(mDocument, image);
1662     }
1663 
1664     case eStyleContentType_String:
1665       return CreateGenConTextNode(aState, nsDependentString(data.GetString()),
1666                                   nullptr, nullptr);
1667 
1668     case eStyleContentType_Attr: {
1669       RefPtr<nsAtom> attrName;
1670       int32_t attrNameSpace = kNameSpaceID_None;
1671       nsAutoString contentString(data.GetString());
1672 
1673       int32_t barIndex =
1674           contentString.FindChar('|');  // CSS namespace delimiter
1675       if (-1 != barIndex) {
1676         nsAutoString nameSpaceVal;
1677         contentString.Left(nameSpaceVal, barIndex);
1678         nsresult error;
1679         attrNameSpace = nameSpaceVal.ToInteger(&error);
1680         contentString.Cut(0, barIndex + 1);
1681         if (contentString.Length()) {
1682           if (mDocument->IsHTMLDocument() && aParentContent->IsHTMLElement()) {
1683             ToLowerCase(contentString);
1684           }
1685           attrName = NS_Atomize(contentString);
1686         }
1687       } else {
1688         if (mDocument->IsHTMLDocument() && aParentContent->IsHTMLElement()) {
1689           ToLowerCase(contentString);
1690         }
1691         attrName = NS_Atomize(contentString);
1692       }
1693 
1694       if (!attrName) {
1695         return nullptr;
1696       }
1697 
1698       nsCOMPtr<nsIContent> content;
1699       NS_NewAttributeContent(mDocument->NodeInfoManager(), attrNameSpace,
1700                              attrName, getter_AddRefs(content));
1701       return content.forget();
1702     }
1703 
1704     case eStyleContentType_Counter:
1705     case eStyleContentType_Counters: {
1706       nsStyleContentData::CounterFunction* counters = data.GetCounters();
1707       nsCounterList* counterList =
1708           mCounterManager.CounterListFor(counters->mIdent);
1709 
1710       nsCounterUseNode* node = new nsCounterUseNode(
1711           counters, aContentIndex, type == eStyleContentType_Counters);
1712 
1713       nsGenConInitializer* initializer = new nsGenConInitializer(
1714           node, counterList, &nsCSSFrameConstructor::CountersDirty);
1715       return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1716                                   initializer);
1717     }
1718 
1719     case eStyleContentType_OpenQuote:
1720     case eStyleContentType_CloseQuote:
1721     case eStyleContentType_NoOpenQuote:
1722     case eStyleContentType_NoCloseQuote: {
1723       nsQuoteNode* node = new nsQuoteNode(type, aContentIndex);
1724 
1725       nsGenConInitializer* initializer = new nsGenConInitializer(
1726           node, &mQuoteList, &nsCSSFrameConstructor::QuotesDirty);
1727       return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1728                                   initializer);
1729     }
1730 
1731     case eStyleContentType_AltContent: {
1732       // Use the "alt" attribute; if that fails and the node is an HTML
1733       // <input>, try the value attribute and then fall back to some default
1734       // localized text we have.
1735       // XXX what if the 'alt' attribute is added later, how will we
1736       // detect that and do the right thing here?
1737       if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
1738         nsCOMPtr<nsIContent> content;
1739         NS_NewAttributeContent(mDocument->NodeInfoManager(), kNameSpaceID_None,
1740                                nsGkAtoms::alt, getter_AddRefs(content));
1741         return content.forget();
1742       }
1743 
1744       if (aParentContent->IsHTMLElement(nsGkAtoms::input)) {
1745         if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
1746           nsCOMPtr<nsIContent> content;
1747           NS_NewAttributeContent(mDocument->NodeInfoManager(),
1748                                  kNameSpaceID_None, nsGkAtoms::value,
1749                                  getter_AddRefs(content));
1750           return content.forget();
1751         }
1752 
1753         nsAutoString temp;
1754         nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
1755                                            "Submit", temp);
1756         return CreateGenConTextNode(aState, temp, nullptr, nullptr);
1757       }
1758 
1759       break;
1760     }
1761 
1762     case eStyleContentType_Uninitialized:
1763       NS_NOTREACHED("uninitialized content type");
1764       return nullptr;
1765   }
1766 
1767   return nullptr;
1768 }
1769 
1770 /*
1771  * aParentFrame - the frame that should be the parent of the generated
1772  *   content.  This is the frame for the corresponding content node,
1773  *   which must not be a leaf frame.
1774  *
1775  * Any items created are added to aItems.
1776  *
1777  * We create an XML element (tag _moz_generated_content_before or
1778  * _moz_generated_content_after) representing the pseudoelement. We
1779  * create a DOM node for each 'content' item and make those nodes the
1780  * children of the XML element. Then we create a frame subtree for
1781  * the XML element as if it were a regular child of
1782  * aParentFrame/aParentContent, giving the XML element the ::before or
1783  * ::after style.
1784  */
CreateGeneratedContentItem(nsFrameConstructorState & aState,nsContainerFrame * aParentFrame,Element * aParentContent,nsStyleContext * aStyleContext,CSSPseudoElementType aPseudoElement,FrameConstructionItemList & aItems)1785 void nsCSSFrameConstructor::CreateGeneratedContentItem(
1786     nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
1787     Element* aParentContent, nsStyleContext* aStyleContext,
1788     CSSPseudoElementType aPseudoElement, FrameConstructionItemList& aItems) {
1789   MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before ||
1790                  aPseudoElement == CSSPseudoElementType::after,
1791              "unexpected aPseudoElement");
1792 
1793   StyleSetHandle styleSet = mPresShell->StyleSet();
1794 
1795   // Probe for the existence of the pseudo-element
1796   RefPtr<nsStyleContext> pseudoStyleContext;
1797   pseudoStyleContext = styleSet->ProbePseudoElementStyle(
1798       aParentContent, aPseudoElement, aStyleContext, aState.mTreeMatchContext);
1799   if (!pseudoStyleContext) return;
1800 
1801   bool isBefore = aPseudoElement == CSSPseudoElementType::before;
1802 
1803   // |ProbePseudoStyleFor| checked the 'display' property and the
1804   // |ContentCount()| of the 'content' property for us.
1805   RefPtr<NodeInfo> nodeInfo;
1806   nsAtom* elemName = isBefore ? nsGkAtoms::mozgeneratedcontentbefore
1807                               : nsGkAtoms::mozgeneratedcontentafter;
1808   nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
1809       elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
1810   nsCOMPtr<Element> container;
1811   nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1812   if (NS_FAILED(rv)) return;
1813 
1814   // Cleared when the pseudo is unbound from the tree, so no need to store a
1815   // strong reference, nor a destructor.
1816   nsAtom* property = isBefore ? nsGkAtoms::beforePseudoProperty
1817                               : nsGkAtoms::afterPseudoProperty;
1818   aParentContent->SetProperty(property, container.get());
1819 
1820   container->SetIsNativeAnonymousRoot();
1821   container->SetPseudoElementType(aPseudoElement);
1822 
1823   // If the parent is in a shadow tree, make sure we don't
1824   // bind with a document because shadow roots and its descendants
1825   // are not in document.
1826   nsIDocument* bindDocument =
1827       aParentContent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
1828   rv =
1829       container->BindToTree(bindDocument, aParentContent, aParentContent, true);
1830   if (NS_FAILED(rv)) {
1831     container->UnbindFromTree();
1832     return;
1833   }
1834 
1835   // Servo has already eagerly computed the style for the container, so we can
1836   // just stick the style on the element and avoid an additional traversal.
1837   //
1838   // We don't do this for pseudos that may trigger animations or transitions,
1839   // since those need to be kicked off by the traversal machinery.
1840   auto* servoStyle = pseudoStyleContext->GetAsServo();
1841   if (servoStyle) {
1842     bool hasServoAnimations =
1843         Servo_ComputedValues_SpecifiesAnimationsOrTransitions(servoStyle);
1844     if (!hasServoAnimations) {
1845       Servo_SetExplicitStyle(container, servoStyle);
1846     } else {
1847       // If animations are involved, we avoid the SetExplicitStyle optimization
1848       // above. We need to grab style with animations from the pseudo element
1849       // and replace old one.
1850       mPresShell->StyleSet()->AsServo()->StyleNewSubtree(container);
1851       pseudoStyleContext = styleSet->AsServo()->ResolveServoStyle(container);
1852     }
1853   } else {
1854 #ifdef MOZ_OLD_STYLE
1855     mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->AsGecko();
1856     GeckoRestyleManager::ReframingStyleContexts* rsc =
1857         geckoRM->GetReframingStyleContexts();
1858 
1859     if (rsc) {
1860       RefPtr<GeckoStyleContext> newContext =
1861           GeckoStyleContext::TakeRef(pseudoStyleContext.forget());
1862       if (auto* oldStyleContext = rsc->Get(container, aPseudoElement)) {
1863         GeckoRestyleManager::TryInitiatingTransition(
1864             aState.mPresContext, container, oldStyleContext, &newContext);
1865       } else {
1866         aState.mPresContext->TransitionManager()->PruneCompletedTransitions(
1867             aParentContent->AsElement(), aPseudoElement, newContext);
1868       }
1869       pseudoStyleContext = newContext.forget();
1870     }
1871 #else
1872     MOZ_CRASH("old style system disabled");
1873 #endif
1874   }
1875 
1876   uint32_t contentCount = pseudoStyleContext->StyleContent()->ContentCount();
1877   for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
1878     nsCOMPtr<nsIContent> content = CreateGeneratedContent(
1879         aState, aParentContent, pseudoStyleContext, contentIndex);
1880     if (content) {
1881       // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
1882       // here; it would get set under AppendChildTo.  But AppendChildTo might
1883       // think that we're going from not being anonymous to being anonymous and
1884       // do some extra work; setting the flag here avoids that.
1885       content->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1886       container->AppendChildTo(content, false);
1887       if (content->IsElement() && servoStyle) {
1888         // If we created any children elements, Servo needs to traverse them,
1889         // but the root is already set up.
1890         mPresShell->StyleSet()->AsServo()->StyleNewSubtree(
1891             content->AsElement());
1892       }
1893     }
1894   }
1895 
1896   AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
1897                                     kNameSpaceID_None, true, pseudoStyleContext,
1898                                     ITEM_IS_GENERATED_CONTENT, nullptr, aItems);
1899 }
1900 
1901 /****************************************************
1902  **  BEGIN TABLE SECTION
1903  ****************************************************/
1904 
1905 // The term pseudo frame is being used instead of anonymous frame, since
1906 // anonymous frame has been used elsewhere to refer to frames that have
1907 // generated content
1908 
1909 // Return whether the given frame is a table pseudo-frame. Note that
1910 // cell-content and table-outer frames have pseudo-types, but are always
1911 // created, even for non-anonymous cells and tables respectively.  So for those
1912 // we have to examine the cell or table frame to see whether it's a pseudo
1913 // frame. In particular, a lone table caption will have a table wrapper as its
1914 // parent, but will also trigger construction of an empty inner table, which
1915 // will be the one we can examine to see whether the wrapper was a pseudo-frame.
IsTablePseudo(nsIFrame * aFrame)1916 static bool IsTablePseudo(nsIFrame* aFrame) {
1917   nsAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
1918   return pseudoType &&
1919          (pseudoType == nsCSSAnonBoxes::table ||
1920           pseudoType == nsCSSAnonBoxes::inlineTable ||
1921           pseudoType == nsCSSAnonBoxes::tableColGroup ||
1922           pseudoType == nsCSSAnonBoxes::tableRowGroup ||
1923           pseudoType == nsCSSAnonBoxes::tableRow ||
1924           pseudoType == nsCSSAnonBoxes::tableCell ||
1925           (pseudoType == nsCSSAnonBoxes::cellContent &&
1926            aFrame->GetParent()->StyleContext()->GetPseudo() ==
1927                nsCSSAnonBoxes::tableCell) ||
1928           (pseudoType == nsCSSAnonBoxes::tableWrapper &&
1929            (aFrame->PrincipalChildList()
1930                     .FirstChild()
1931                     ->StyleContext()
1932                     ->GetPseudo() == nsCSSAnonBoxes::table ||
1933             aFrame->PrincipalChildList()
1934                     .FirstChild()
1935                     ->StyleContext()
1936                     ->GetPseudo() == nsCSSAnonBoxes::inlineTable)));
1937 }
1938 
IsRubyPseudo(nsIFrame * aFrame)1939 static bool IsRubyPseudo(nsIFrame* aFrame) {
1940   return RubyUtils::IsRubyPseudo(aFrame->StyleContext()->GetPseudo());
1941 }
1942 
IsTableOrRubyPseudo(nsIFrame * aFrame)1943 static bool IsTableOrRubyPseudo(nsIFrame* aFrame) {
1944   return IsTablePseudo(aFrame) || IsRubyPseudo(aFrame);
1945 }
1946 
1947 /* static */
GetParentType(LayoutFrameType aFrameType)1948 nsCSSFrameConstructor::ParentType nsCSSFrameConstructor::GetParentType(
1949     LayoutFrameType aFrameType) {
1950   if (aFrameType == LayoutFrameType::Table) {
1951     return eTypeTable;
1952   }
1953   if (aFrameType == LayoutFrameType::TableRowGroup) {
1954     return eTypeRowGroup;
1955   }
1956   if (aFrameType == LayoutFrameType::TableRow) {
1957     return eTypeRow;
1958   }
1959   if (aFrameType == LayoutFrameType::TableColGroup) {
1960     return eTypeColGroup;
1961   }
1962   if (aFrameType == LayoutFrameType::RubyBaseContainer) {
1963     return eTypeRubyBaseContainer;
1964   }
1965   if (aFrameType == LayoutFrameType::RubyTextContainer) {
1966     return eTypeRubyTextContainer;
1967   }
1968   if (aFrameType == LayoutFrameType::Ruby) {
1969     return eTypeRuby;
1970   }
1971 
1972   return eTypeBlock;
1973 }
1974 
AdjustCaptionParentFrame(nsContainerFrame * aParentFrame)1975 static nsContainerFrame* AdjustCaptionParentFrame(
1976     nsContainerFrame* aParentFrame) {
1977   if (aParentFrame->IsTableFrame()) {
1978     return aParentFrame->GetParent();
1979   }
1980   return aParentFrame;
1981 }
1982 
1983 /**
1984  * If the parent frame is a |tableFrame| and the child is a
1985  * |captionFrame|, then we want to insert the frames beneath the
1986  * |tableFrame|'s parent frame. Returns |true| if the parent frame
1987  * needed to be fixed up.
1988  */
GetCaptionAdjustedParent(nsContainerFrame * aParentFrame,const nsIFrame * aChildFrame,nsContainerFrame ** aAdjParentFrame)1989 static bool GetCaptionAdjustedParent(nsContainerFrame* aParentFrame,
1990                                      const nsIFrame* aChildFrame,
1991                                      nsContainerFrame** aAdjParentFrame) {
1992   *aAdjParentFrame = aParentFrame;
1993   bool haveCaption = false;
1994 
1995   if (aChildFrame->IsTableCaption()) {
1996     haveCaption = true;
1997     *aAdjParentFrame = ::AdjustCaptionParentFrame(aParentFrame);
1998   }
1999   return haveCaption;
2000 }
2001 
AdjustParentFrame(nsContainerFrame ** aParentFrame,const FrameConstructionData * aFCData,nsStyleContext * aStyleContext)2002 void nsCSSFrameConstructor::AdjustParentFrame(
2003     nsContainerFrame** aParentFrame, const FrameConstructionData* aFCData,
2004     nsStyleContext* aStyleContext) {
2005   NS_PRECONDITION(aStyleContext, "Must have child's style context");
2006   NS_PRECONDITION(aFCData, "Must have frame construction data");
2007 
2008   bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0);
2009 
2010   if (tablePart &&
2011       aStyleContext->StyleDisplay()->mDisplay == StyleDisplay::TableCaption) {
2012     *aParentFrame = ::AdjustCaptionParentFrame(*aParentFrame);
2013   }
2014 }
2015 
2016 // Pull all the captions present in aItems out  into aCaptions
PullOutCaptionFrames(nsFrameItems & aItems,nsFrameItems & aCaptions)2017 static void PullOutCaptionFrames(nsFrameItems& aItems,
2018                                  nsFrameItems& aCaptions) {
2019   nsIFrame* child = aItems.FirstChild();
2020   while (child) {
2021     nsIFrame* nextSibling = child->GetNextSibling();
2022     if (child->IsTableCaption()) {
2023       aItems.RemoveFrame(child);
2024       aCaptions.AddChild(child);
2025     }
2026     child = nextSibling;
2027   }
2028 }
2029 
2030 // Construct the outer, inner table frames and the children frames for the
2031 // table.
2032 // XXX Page break frames for pseudo table frames are not constructed to avoid
2033 // the risk associated with revising the pseudo frame mechanism. The long term
2034 // solution of having frames handle page-break-before/after will solve the
2035 // problem.
ConstructTable(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)2036 nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
2037                                                 FrameConstructionItem& aItem,
2038                                                 nsContainerFrame* aParentFrame,
2039                                                 const nsStyleDisplay* aDisplay,
2040                                                 nsFrameItems& aFrameItems) {
2041   NS_PRECONDITION(aDisplay->mDisplay == StyleDisplay::Table ||
2042                       aDisplay->mDisplay == StyleDisplay::InlineTable,
2043                   "Unexpected call");
2044 
2045   nsIContent* const content = aItem.mContent;
2046   nsStyleContext* const styleContext = aItem.mStyleContext;
2047   const uint32_t nameSpaceID = aItem.mNameSpaceID;
2048 
2049   // create the pseudo SC for the table wrapper as a child of the inner SC
2050   RefPtr<nsStyleContext> outerStyleContext;
2051   outerStyleContext =
2052       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2053           nsCSSAnonBoxes::tableWrapper, styleContext);
2054 
2055   // Create the table wrapper frame which holds the caption and inner table
2056   // frame
2057   nsContainerFrame* newFrame;
2058   if (kNameSpaceID_MathML == nameSpaceID)
2059     newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerStyleContext);
2060   else
2061     newFrame = NS_NewTableWrapperFrame(mPresShell, outerStyleContext);
2062 
2063   nsContainerFrame* geometricParent = aState.GetGeometricParent(
2064       outerStyleContext->StyleDisplay(), aParentFrame);
2065 
2066   // Init the table wrapper frame
2067   InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2068 
2069   // Create the inner table frame
2070   nsContainerFrame* innerFrame;
2071   if (kNameSpaceID_MathML == nameSpaceID)
2072     innerFrame = NS_NewMathMLmtableFrame(mPresShell, styleContext);
2073   else
2074     innerFrame = NS_NewTableFrame(mPresShell, styleContext);
2075 
2076   InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2077   innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2078 
2079   // Put the newly created frames into the right child list
2080   SetInitialSingleChild(newFrame, innerFrame);
2081 
2082   aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
2083 
2084   if (!mRootElementFrame) {
2085     // The frame we're constructing will be the root element frame.
2086     // Set mRootElementFrame before processing children.
2087     mRootElementFrame = newFrame;
2088   }
2089 
2090   nsFrameItems childItems;
2091 
2092   // Process children
2093   nsFrameConstructorSaveState absoluteSaveState;
2094   const nsStyleDisplay* display = outerStyleContext->StyleDisplay();
2095 
2096   // Mark the table frame as an absolute container if needed
2097   newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2098   if (display->IsAbsPosContainingBlock(newFrame)) {
2099     aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2100   }
2101   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2102                "nsIAnonymousContentCreator::CreateAnonymousContent "
2103                "implementations for table frames are not currently expected "
2104                "to output a list where the items have their own children");
2105   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2106     ConstructFramesFromItemList(
2107         aState, aItem.mChildItems, innerFrame,
2108         aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childItems);
2109   } else {
2110     ProcessChildren(aState, content, styleContext, innerFrame, true, childItems,
2111                     false, aItem.mPendingBinding);
2112   }
2113 
2114   nsFrameItems captionItems;
2115   PullOutCaptionFrames(childItems, captionItems);
2116 
2117   // Set the inner table frame's initial primary list
2118   innerFrame->SetInitialChildList(kPrincipalList, childItems);
2119 
2120   // Set the table wrapper frame's secondary childlist lists
2121   if (captionItems.NotEmpty()) {
2122     newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems);
2123   }
2124 
2125   return newFrame;
2126 }
2127 
MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState & aState,const nsStyleDisplay * aDisplay,nsFrameConstructorSaveState & aAbsSaveState,nsContainerFrame * aFrame)2128 static void MakeTablePartAbsoluteContainingBlockIfNeeded(
2129     nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay,
2130     nsFrameConstructorSaveState& aAbsSaveState, nsContainerFrame* aFrame) {
2131   // If we're positioned, then we need to become an absolute containing block
2132   // for any absolutely positioned children and register for post-reflow fixup.
2133   //
2134   // Note that usually if a frame type can be an absolute containing block, we
2135   // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or
2136   // not. However, in this case flag serves the additional purpose of indicating
2137   // that the frame was registered with its table frame. This allows us to avoid
2138   // the overhead of unregistering the frame in most cases.
2139   if (aDisplay->IsAbsPosContainingBlock(aFrame)) {
2140     aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2141     aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2142     nsTableFrame::RegisterPositionedTablePart(aFrame);
2143   }
2144 }
2145 
ConstructTableRowOrRowGroup(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)2146 nsIFrame* nsCSSFrameConstructor::ConstructTableRowOrRowGroup(
2147     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2148     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2149     nsFrameItems& aFrameItems) {
2150   MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableRow ||
2151                  aDisplay->mDisplay == StyleDisplay::TableRowGroup ||
2152                  aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
2153                  aDisplay->mDisplay == StyleDisplay::TableHeaderGroup,
2154              "Not a row or row group");
2155   MOZ_ASSERT(aItem.mStyleContext->StyleDisplay() == aDisplay,
2156              "Display style doesn't match style context");
2157   nsIContent* const content = aItem.mContent;
2158   nsStyleContext* const styleContext = aItem.mStyleContext;
2159   const uint32_t nameSpaceID = aItem.mNameSpaceID;
2160 
2161   nsContainerFrame* newFrame;
2162   if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2163     if (kNameSpaceID_MathML == nameSpaceID)
2164       newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext);
2165     else
2166       newFrame = NS_NewTableRowFrame(mPresShell, styleContext);
2167   } else {
2168     newFrame = NS_NewTableRowGroupFrame(mPresShell, styleContext);
2169   }
2170 
2171   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2172 
2173   nsFrameConstructorSaveState absoluteSaveState;
2174   MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2175                                                absoluteSaveState, newFrame);
2176 
2177   nsFrameItems childItems;
2178   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2179                "nsIAnonymousContentCreator::CreateAnonymousContent "
2180                "implementations for table frames are not currently expected "
2181                "to output a list where the items have their own children");
2182   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2183     ConstructFramesFromItemList(
2184         aState, aItem.mChildItems, newFrame,
2185         aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childItems);
2186   } else {
2187     ProcessChildren(aState, content, styleContext, newFrame, true, childItems,
2188                     false, aItem.mPendingBinding);
2189   }
2190 
2191   newFrame->SetInitialChildList(kPrincipalList, childItems);
2192   aFrameItems.AddChild(newFrame);
2193   return newFrame;
2194 }
2195 
ConstructTableCol(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aStyleDisplay,nsFrameItems & aFrameItems)2196 nsIFrame* nsCSSFrameConstructor::ConstructTableCol(
2197     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2198     nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
2199     nsFrameItems& aFrameItems) {
2200   nsIContent* const content = aItem.mContent;
2201   nsStyleContext* const styleContext = aItem.mStyleContext;
2202 
2203   nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, styleContext);
2204   InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2205 
2206   NS_ASSERTION(colFrame->StyleContext() == styleContext,
2207                "Unexpected style context");
2208 
2209   aFrameItems.AddChild(colFrame);
2210 
2211   // construct additional col frames if the col frame has a span > 1
2212   int32_t span = colFrame->GetSpan();
2213   for (int32_t spanX = 1; spanX < span; spanX++) {
2214     nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, styleContext);
2215     InitAndRestoreFrame(aState, content, aParentFrame, newCol, false);
2216     aFrameItems.LastChild()->SetNextContinuation(newCol);
2217     newCol->SetPrevContinuation(aFrameItems.LastChild());
2218     aFrameItems.AddChild(newCol);
2219     newCol->SetColType(eColAnonymousCol);
2220   }
2221 
2222   return colFrame;
2223 }
2224 
ConstructTableCell(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)2225 nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
2226     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2227     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2228     nsFrameItems& aFrameItems) {
2229   MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableCell, "Unexpected call");
2230 
2231   nsIContent* const content = aItem.mContent;
2232   nsStyleContext* const styleContext = aItem.mStyleContext;
2233   const uint32_t nameSpaceID = aItem.mNameSpaceID;
2234 
2235   nsTableFrame* tableFrame =
2236       static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2237   nsContainerFrame* newFrame;
2238   // <mtable> is border separate in mathml.css and the MathML code doesn't
2239   // implement border collapse. For those users who style <mtable> with border
2240   // collapse, give them the default non-MathML table frames that understand
2241   // border collapse. This won't break us because MathML table frames are all
2242   // subclasses of the default table code, and so we can freely mix <mtable>
2243   // with <mtr> or <tr>, <mtd> or <td>. What will happen is just that non-MathML
2244   // frames won't understand MathML attributes and will therefore miss the
2245   // special handling that the MathML code does.
2246   if (kNameSpaceID_MathML == nameSpaceID && !tableFrame->IsBorderCollapse()) {
2247     newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext, tableFrame);
2248   } else {
2249     // Warning: If you change this and add a wrapper frame around table cell
2250     // frames, make sure Bug 368554 doesn't regress!
2251     // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2252     newFrame = NS_NewTableCellFrame(mPresShell, styleContext, tableFrame);
2253   }
2254 
2255   // Initialize the table cell frame
2256   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2257   newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2258 
2259   // Resolve pseudo style and initialize the body cell frame
2260   RefPtr<nsStyleContext> innerPseudoStyle;
2261   innerPseudoStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2262       nsCSSAnonBoxes::cellContent, styleContext);
2263 
2264   // Create a block frame that will format the cell's content
2265   bool isBlock;
2266   nsContainerFrame* cellInnerFrame;
2267   if (kNameSpaceID_MathML == nameSpaceID) {
2268     cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2269     isBlock = false;
2270   } else {
2271     cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
2272     isBlock = true;
2273   }
2274 
2275   InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame);
2276 
2277   nsFrameConstructorSaveState absoluteSaveState;
2278   MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2279                                                absoluteSaveState, newFrame);
2280 
2281   nsFrameItems childItems;
2282   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2283                "nsIAnonymousContentCreator::CreateAnonymousContent "
2284                "implementations for table frames are not currently expected "
2285                "to output a list where the items have their own children");
2286   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2287     // Need to push ourselves as a float containing block.
2288     // XXXbz it might be nice to work on getting the parent
2289     // FrameConstructionItem down into ProcessChildren and just making use of
2290     // the push there, but that's a bit of work.
2291     nsFrameConstructorSaveState floatSaveState;
2292     if (!isBlock) { /* MathML case */
2293       aState.PushFloatContainingBlock(nullptr, floatSaveState);
2294     } else {
2295       aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
2296     }
2297 
2298     ConstructFramesFromItemList(
2299         aState, aItem.mChildItems, cellInnerFrame,
2300         aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childItems);
2301   } else {
2302     // Process the child content
2303     ProcessChildren(aState, content, styleContext, cellInnerFrame, true,
2304                     childItems, isBlock, aItem.mPendingBinding);
2305   }
2306 
2307   cellInnerFrame->SetInitialChildList(kPrincipalList, childItems);
2308   SetInitialSingleChild(newFrame, cellInnerFrame);
2309   aFrameItems.AddChild(newFrame);
2310   return newFrame;
2311 }
2312 
NeedFrameFor(const nsFrameConstructorState & aState,nsIFrame * aParentFrame,nsIContent * aChildContent)2313 static inline bool NeedFrameFor(const nsFrameConstructorState& aState,
2314                                 nsIFrame* aParentFrame,
2315                                 nsIContent* aChildContent) {
2316   // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2317   // Remove it once that's fixed.
2318   NS_PRECONDITION(
2319       !aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
2320           aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
2321       "Why did we get called?");
2322 
2323   // don't create a whitespace frame if aParentFrame doesn't want it.
2324   // always create frames for children in generated content. counter(),
2325   // quotes, and attr() content can easily change dynamically and we don't
2326   // want to be reconstructing frames. It's not even clear that these
2327   // should be considered ignorable just because they evaluate to
2328   // whitespace.
2329 
2330   // We could handle all this in CreateNeededPseudoContainers or some other
2331   // place after we build our frame construction items, but that would involve
2332   // creating frame construction items for whitespace kids of
2333   // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2334   // all anyway, and involve an extra walk down the frame construction item
2335   // list.
2336   if ((aParentFrame &&
2337        (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
2338         aParentFrame->IsGeneratedContentFrame())) ||
2339       !aChildContent->IsNodeOfType(nsINode::eTEXT)) {
2340     return true;
2341   }
2342 
2343   aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2344                           NS_REFRAME_IF_WHITESPACE);
2345   return !aChildContent->TextIsOnlyWhitespace();
2346 }
2347 
2348 /***********************************************
2349  * END TABLE SECTION
2350  ***********************************************/
2351 
ConstructDocElementFrame(Element * aDocElement,nsILayoutHistoryState * aFrameState)2352 nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
2353     Element* aDocElement, nsILayoutHistoryState* aFrameState) {
2354   MOZ_ASSERT(GetRootFrame(),
2355              "No viewport?  Someone forgot to call ConstructRootFrame!");
2356   MOZ_ASSERT(!mDocElementContainingBlock,
2357              "Shouldn't have a doc element containing block here");
2358 
2359   // Resolve a new style context for the viewport since it may be affected
2360   // by a new root element style (e.g. a propagated 'direction').
2361   // @see nsStyleContext::ApplyStyleFixups
2362   {
2363     RefPtr<nsStyleContext> sc =
2364         mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2365             nsCSSAnonBoxes::viewport, nullptr);
2366     GetRootFrame()->SetStyleContextWithoutNotification(sc);
2367   }
2368 
2369   // Make sure to call UpdateViewportScrollbarStylesOverride before
2370   // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2371   // properly.
2372   DebugOnly<nsIContent*> propagatedScrollFrom;
2373   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2374     propagatedScrollFrom = presContext->UpdateViewportScrollbarStylesOverride();
2375   }
2376 
2377   SetUpDocElementContainingBlock(aDocElement);
2378 
2379   NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
2380 
2381   TreeMatchContextHolder matchContext(mDocument);
2382   // Initialize the ancestor filter with null for now; we'll push
2383   // aDocElement once we finish resolving style for it.
2384   if (matchContext.Exists()) {
2385     matchContext->InitAncestors(nullptr);
2386   }
2387   nsFrameConstructorState state(
2388       mPresShell, matchContext,
2389       GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2390       nullptr, nullptr, do_AddRef(aFrameState));
2391 
2392   // XXXbz why, exactly?
2393   if (!mTempFrameTreeState)
2394     state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
2395 
2396   // Make sure that we'll handle restyles for this document element in
2397   // the future.  We need this, because the document element might
2398   // have stale restyle bits from a previous frame constructor for
2399   // this document.  Unlike in AddFrameConstructionItems, it's safe to
2400   // unset all element restyle flags, since we don't have any
2401   // siblings.
2402   aDocElement->UnsetRestyleFlagsIfGecko();
2403 
2404   // --------- CREATE AREA OR BOX FRAME -------
2405   if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
2406     // Ensure the document element is styled at this point.
2407     if (!aDocElement->HasServoData()) {
2408       // NOTE(emilio): If the root has a non-null binding, we'll stop at the
2409       // document element and won't process any children, loading the bindings
2410       // (or failing to do so) will take care of the rest.
2411       set->StyleNewSubtree(aDocElement);
2412     }
2413   }
2414 
2415   // FIXME: Should this use ResolveStyleContext?  (The calls in this
2416   // function are the only case in nsCSSFrameConstructor where we don't
2417   // do so for the construction of a style context for an element.)
2418   RefPtr<nsStyleContext> styleContext = mPresShell->StyleSet()->ResolveStyleFor(
2419       aDocElement, nullptr, LazyComputeBehavior::Assert);
2420 
2421   const nsStyleDisplay* display = styleContext->StyleDisplay();
2422 
2423   // Ensure that our XBL bindings are installed.
2424   if (display->mBinding) {
2425     // Get the XBL loader.
2426     nsresult rv;
2427     bool resolveStyle;
2428 
2429     nsXBLService* xblService = nsXBLService::GetInstance();
2430     if (!xblService) {
2431       return nullptr;
2432     }
2433 
2434     RefPtr<nsXBLBinding> binding;
2435     rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
2436                                   display->mBinding->mExtraData->GetPrincipal(),
2437                                   getter_AddRefs(binding), &resolveStyle);
2438     if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
2439       // Binding will load asynchronously.
2440       return nullptr;
2441     }
2442 
2443     if (binding) {
2444       // For backwards compat, keep firing the root's constructor
2445       // after all of its kids' constructors.  So tell the binding
2446       // manager about it right now.
2447       mDocument->BindingManager()->AddToAttachedQueue(binding);
2448     }
2449 
2450     if (resolveStyle) {
2451       // FIXME: Should this use ResolveStyleContext?  (The calls in this
2452       // function are the only case in nsCSSFrameConstructor where we don't do
2453       // so for the construction of a style context for an element.)
2454       styleContext = mPresShell->StyleSet()->ResolveStyleFor(
2455           aDocElement, nullptr, LazyComputeBehavior::Assert);
2456       display = styleContext->StyleDisplay();
2457     }
2458   }
2459 
2460   // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2461 
2462   NS_ASSERTION(!display->IsScrollableOverflow() ||
2463                    state.mPresContext->IsPaginated() ||
2464                    propagatedScrollFrom == aDocElement,
2465                "Scrollbars should have been propagated to the viewport");
2466 
2467   if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
2468     RegisterDisplayNoneStyleFor(aDocElement, styleContext);
2469     return nullptr;
2470   }
2471 
2472   TreeMatchContext::AutoAncestorPusher ancestorPusher(state.mTreeMatchContext);
2473   ancestorPusher.PushAncestorAndStyleScope(aDocElement);
2474 
2475   // Make sure to start any background image loads for the root element now.
2476   styleContext->StartBackgroundImageLoads();
2477 
2478   nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
2479   if (mHasRootAbsPosContainingBlock) {
2480     // Push the absolute containing block now so we can absolutely position
2481     // the root element
2482     mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2483     state.PushAbsoluteContainingBlock(
2484         mDocElementContainingBlock, mDocElementContainingBlock,
2485         docElementContainingBlockAbsoluteSaveState);
2486   }
2487 
2488   // The rules from CSS 2.1, section 9.2.4, have already been applied
2489   // by the style system, so we can assume that display->mDisplay is
2490   // either NONE, BLOCK, or TABLE.
2491 
2492   // contentFrame is the primary frame for the root element. newFrame
2493   // is the frame that will be the child of the initial containing block.
2494   // These are usually the same frame but they can be different, in
2495   // particular if the root frame is positioned, in which case
2496   // contentFrame is the out-of-flow frame and newFrame is the
2497   // placeholder.
2498   nsContainerFrame* contentFrame;
2499   nsIFrame* newFrame;
2500   bool processChildren = false;
2501 
2502   nsFrameConstructorSaveState absoluteSaveState;
2503 
2504   // Check whether we need to build a XUL box or SVG root frame
2505 #ifdef MOZ_XUL
2506   if (aDocElement->IsXULElement()) {
2507     contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext);
2508     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2509                         contentFrame);
2510     newFrame = contentFrame;
2511     processChildren = true;
2512   } else
2513 #endif
2514       if (aDocElement->IsSVGElement()) {
2515     if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2516       return nullptr;
2517     }
2518     // We're going to call the right function ourselves, so no need to give a
2519     // function to this FrameConstructionData.
2520 
2521     // XXXbz on the other hand, if we converted this whole function to
2522     // FrameConstructionData/Item, then we'd need the right function
2523     // here... but would probably be able to get away with less code in this
2524     // function in general.
2525     // Use a null PendingBinding, since our binding is not in fact pending.
2526     static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
2527     already_AddRefed<nsStyleContext> extraRef =
2528         RefPtr<nsStyleContext>(styleContext).forget();
2529     AutoFrameConstructionItem item(
2530         this, &rootSVGData, aDocElement, aDocElement->NodeInfo()->NameAtom(),
2531         kNameSpaceID_SVG, nullptr, extraRef, true, nullptr);
2532 
2533     nsFrameItems frameItems;
2534     contentFrame = static_cast<nsContainerFrame*>(
2535         ConstructOuterSVG(state, item, mDocElementContainingBlock,
2536                           styleContext->StyleDisplay(), frameItems));
2537     newFrame = frameItems.FirstChild();
2538     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2539   } else if (display->mDisplay == StyleDisplay::Flex ||
2540              display->mDisplay == StyleDisplay::WebkitBox ||
2541              (StylePrefs::sEmulateMozBoxWithFlex &&
2542               display->mDisplay == StyleDisplay::MozBox)) {
2543     contentFrame = NS_NewFlexContainerFrame(mPresShell, styleContext);
2544     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2545                         contentFrame);
2546     newFrame = contentFrame;
2547     processChildren = true;
2548 
2549     newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2550     if (display->IsAbsPosContainingBlock(newFrame)) {
2551       state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2552                                         absoluteSaveState);
2553     }
2554 
2555   } else if (display->mDisplay == StyleDisplay::Grid) {
2556     contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
2557     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2558                         contentFrame);
2559     newFrame = contentFrame;
2560     processChildren = true;
2561 
2562     newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2563     if (display->IsAbsPosContainingBlock(newFrame)) {
2564       state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2565                                         absoluteSaveState);
2566     }
2567   } else if (display->mDisplay == StyleDisplay::Table) {
2568     // We're going to call the right function ourselves, so no need to give a
2569     // function to this FrameConstructionData.
2570 
2571     // XXXbz on the other hand, if we converted this whole function to
2572     // FrameConstructionData/Item, then we'd need the right function
2573     // here... but would probably be able to get away with less code in this
2574     // function in general.
2575     // Use a null PendingBinding, since our binding is not in fact pending.
2576     static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
2577     already_AddRefed<nsStyleContext> extraRef =
2578         RefPtr<nsStyleContext>(styleContext).forget();
2579     AutoFrameConstructionItem item(
2580         this, &rootTableData, aDocElement, aDocElement->NodeInfo()->NameAtom(),
2581         kNameSpaceID_None, nullptr, extraRef, true, nullptr);
2582 
2583     nsFrameItems frameItems;
2584     // if the document is a table then just populate it.
2585     contentFrame = static_cast<nsContainerFrame*>(
2586         ConstructTable(state, item, mDocElementContainingBlock,
2587                        styleContext->StyleDisplay(), frameItems));
2588     newFrame = frameItems.FirstChild();
2589     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2590   } else {
2591     MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||
2592                    display->mDisplay == StyleDisplay::FlowRoot,
2593                "Unhandled display type for root element");
2594     contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
2595     nsFrameItems frameItems;
2596     // Use a null PendingBinding, since our binding is not in fact pending.
2597     ConstructBlock(
2598         state, aDocElement,
2599         state.GetGeometricParent(display, mDocElementContainingBlock),
2600         mDocElementContainingBlock, styleContext, &contentFrame, frameItems,
2601         display->IsAbsPosContainingBlock(contentFrame) ? contentFrame : nullptr,
2602         nullptr);
2603     newFrame = frameItems.FirstChild();
2604     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2605   }
2606 
2607   MOZ_ASSERT(newFrame);
2608   MOZ_ASSERT(contentFrame);
2609 
2610   NS_ASSERTION(
2611       processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame,
2612       "unexpected mRootElementFrame");
2613   mRootElementFrame = contentFrame;
2614 
2615   // Figure out which frame has the main style for the document element,
2616   // assigning it to mRootElementStyleFrame.
2617   // Backgrounds should be propagated from that frame to the viewport.
2618   contentFrame->GetParentStyleContext(&mRootElementStyleFrame);
2619   bool isChild = mRootElementStyleFrame &&
2620                  mRootElementStyleFrame->GetParent() == contentFrame;
2621   if (!isChild) {
2622     mRootElementStyleFrame = mRootElementFrame;
2623   }
2624 
2625   if (processChildren) {
2626     // Still need to process the child content
2627     nsFrameItems childItems;
2628 
2629     NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) &&
2630                      !contentFrame->IsFrameOfType(nsIFrame::eSVG),
2631                  "Only XUL frames should reach here");
2632     // Use a null PendingBinding, since our binding is not in fact pending.
2633     ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
2634                     childItems, false, nullptr);
2635 
2636     // Set the initial child lists
2637     contentFrame->SetInitialChildList(kPrincipalList, childItems);
2638   }
2639 
2640   // set the primary frame
2641   aDocElement->SetPrimaryFrame(contentFrame);
2642 
2643   SetInitialSingleChild(mDocElementContainingBlock, newFrame);
2644 
2645   // Create frames for anonymous contents if there is a canvas frame.
2646   if (mDocElementContainingBlock->IsCanvasFrame()) {
2647     ConstructAnonymousContentForCanvas(state, mDocElementContainingBlock,
2648                                        aDocElement);
2649   }
2650 
2651   return newFrame;
2652 }
2653 
ConstructRootFrame()2654 nsIFrame* nsCSSFrameConstructor::ConstructRootFrame() {
2655   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
2656 
2657   StyleSetHandle styleSet = mPresShell->StyleSet();
2658 
2659   // --------- BUILD VIEWPORT -----------
2660   RefPtr<nsStyleContext> viewportPseudoStyle =
2661       styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport,
2662                                                    nullptr);
2663   ViewportFrame* viewportFrame =
2664       NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2665 
2666   // XXXbz do we _have_ to pass a null content pointer to that frame?
2667   // Would it really kill us to pass in the root element or something?
2668   // What would that break?
2669   viewportFrame->Init(nullptr, nullptr, nullptr);
2670 
2671   viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2672 
2673   // Bind the viewport frame to the root view
2674   nsView* rootView = mPresShell->GetViewManager()->GetRootView();
2675   viewportFrame->SetView(rootView);
2676 
2677   viewportFrame->SyncFrameViewProperties(rootView);
2678   nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(),
2679                                          viewportFrame, rootView, nullptr,
2680                                          nsContainerFrame::SET_ASYNC);
2681 
2682   // Make it an absolute container for fixed-pos elements
2683   viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2684   viewportFrame->MarkAsAbsoluteContainingBlock();
2685 
2686   return viewportFrame;
2687 }
2688 
SetUpDocElementContainingBlock(nsIContent * aDocElement)2689 void nsCSSFrameConstructor::SetUpDocElementContainingBlock(
2690     nsIContent* aDocElement) {
2691   NS_PRECONDITION(aDocElement, "No element?");
2692   NS_PRECONDITION(!aDocElement->GetParent(), "Not root content?");
2693   NS_PRECONDITION(aDocElement->GetUncomposedDoc(), "Not in a document?");
2694   NS_PRECONDITION(
2695       aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement,
2696       "Not the root of the document?");
2697 
2698   /*
2699     how the root frame hierarchy should look
2700 
2701   Galley presentation, non-XUL, with scrolling:
2702 
2703       ViewportFrame [fixed-cb]
2704         nsHTMLScrollFrame
2705           nsCanvasFrame [abs-cb]
2706             root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2707                                 nsTableWrapperFrame, nsPlaceholderFrame)
2708 
2709   Galley presentation, XUL
2710 
2711       ViewportFrame [fixed-cb]
2712         nsRootBoxFrame
2713           root element frame (nsDocElementBoxFrame)
2714 
2715   Print presentation, non-XUL
2716 
2717       ViewportFrame
2718         nsSimplePageSequenceFrame
2719           nsPageFrame
2720             nsPageContentFrame [fixed-cb]
2721               nsCanvasFrame [abs-cb]
2722                 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2723                                     nsTableWrapperFrame, nsPlaceholderFrame)
2724 
2725   Print-preview presentation, non-XUL
2726 
2727       ViewportFrame
2728         nsHTMLScrollFrame
2729           nsSimplePageSequenceFrame
2730             nsPageFrame
2731               nsPageContentFrame [fixed-cb]
2732                 nsCanvasFrame [abs-cb]
2733                   root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2734                                       nsTableWrapperFrame, nsPlaceholderFrame)
2735 
2736   Print/print preview of XUL is not supported.
2737   [fixed-cb]: the default containing block for fixed-pos content
2738   [abs-cb]: the default containing block for abs-pos content
2739 
2740   Meaning of nsCSSFrameConstructor fields:
2741     mRootElementFrame is "root element frame".  This is the primary frame for
2742       the root element.
2743     mDocElementContainingBlock is the parent of mRootElementFrame
2744       (i.e. nsCanvasFrame or nsRootBoxFrame)
2745 
2746     mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't
2747   one
2748   */
2749 
2750   // --------- CREATE ROOT FRAME -------
2751 
2752   // Create the root frame. The document element's frame is a child of the
2753   // root frame.
2754   //
2755   // The root frame serves two purposes:
2756   // - reserves space for any margins needed for the document element's frame
2757   // - renders the document element's background. This ensures the background
2758   // covers
2759   //   the entire canvas as specified by the CSS2 spec
2760 
2761   nsPresContext* presContext = mPresShell->GetPresContext();
2762   bool isPaginated = presContext->IsRootPaginatedDocument();
2763   nsContainerFrame* viewportFrame =
2764       static_cast<nsContainerFrame*>(GetRootFrame());
2765   nsStyleContext* viewportPseudoStyle = viewportFrame->StyleContext();
2766 
2767   nsContainerFrame* rootFrame = nullptr;
2768   nsAtom* rootPseudo;
2769 
2770   if (!isPaginated) {
2771 #ifdef MOZ_XUL
2772     if (aDocElement->IsXULElement()) {
2773       // pass a temporary stylecontext, the correct one will be set later
2774       rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
2775     } else
2776 #endif
2777     {
2778       // pass a temporary stylecontext, the correct one will be set later
2779       rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2780       mHasRootAbsPosContainingBlock = true;
2781     }
2782 
2783     rootPseudo = nsCSSAnonBoxes::canvas;
2784     mDocElementContainingBlock = rootFrame;
2785   } else {
2786     // Create a page sequence frame
2787     rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
2788     mPageSequenceFrame = rootFrame;
2789     rootPseudo = nsCSSAnonBoxes::pageSequence;
2790     rootFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2791   }
2792 
2793   // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2794 
2795   // If the device supports scrolling (e.g., in galley mode on the screen and
2796   // for print-preview, but not when printing), then create a scroll frame that
2797   // will act as the scrolling mechanism for the viewport.
2798   // XXX Do we even need a viewport when printing to a printer?
2799 
2800   bool isHTML = aDocElement->IsHTMLElement();
2801   bool isXUL = false;
2802 
2803   if (!isHTML) {
2804     isXUL = aDocElement->IsXULElement();
2805   }
2806 
2807   // Never create scrollbars for XUL documents
2808   bool isScrollable =
2809       isPaginated ? presContext->HasPaginatedScrolling() : !isXUL;
2810 
2811   // We no longer need to do overflow propagation here. It's taken care of
2812   // when we construct frames for the element whose overflow might be
2813   // propagated
2814   NS_ASSERTION(!isScrollable || !isXUL,
2815                "XUL documents should never be scrollable - see above");
2816 
2817   nsContainerFrame* newFrame = rootFrame;
2818   RefPtr<nsStyleContext> rootPseudoStyle;
2819   // we must create a state because if the scrollbars are GFX it needs the
2820   // state to build the scrollbar frames.
2821   TreeMatchContextHolder matchContext(mDocument);
2822   nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr,
2823                                 nullptr);
2824 
2825   // Start off with the viewport as parent; we'll adjust it as needed.
2826   nsContainerFrame* parentFrame = viewportFrame;
2827 
2828   StyleSetHandle styleSet = mPresShell->StyleSet();
2829   // If paginated, make sure we don't put scrollbars in
2830   if (!isScrollable) {
2831     rootPseudoStyle = styleSet->ResolveInheritingAnonymousBoxStyle(
2832         rootPseudo, viewportPseudoStyle);
2833   } else {
2834     if (rootPseudo == nsCSSAnonBoxes::canvas) {
2835       rootPseudo = nsCSSAnonBoxes::scrolledCanvas;
2836     } else {
2837       NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence,
2838                    "Unknown root pseudo");
2839       rootPseudo = nsCSSAnonBoxes::scrolledPageSequence;
2840     }
2841 
2842     // Build the frame. We give it the content we are wrapping which is the
2843     // document element, the root frame, the parent view port frame, and we
2844     // should get back the new frame and the scrollable view if one was
2845     // created.
2846 
2847     // resolve a context for the scrollframe
2848     RefPtr<nsStyleContext> styleContext;
2849     styleContext = styleSet->ResolveInheritingAnonymousBoxStyle(
2850         nsCSSAnonBoxes::viewportScroll, viewportPseudoStyle);
2851 
2852     // Note that the viewport scrollframe is always built with
2853     // overflow:auto style. This forces the scroll frame to create
2854     // anonymous content for both scrollbars. This is necessary even
2855     // if the HTML or BODY elements are overriding the viewport
2856     // scroll style to 'hidden' --- dynamic style changes might put
2857     // scrollbars back on the viewport and we don't want to have to
2858     // reframe the viewport to create the scrollbar content.
2859     newFrame = nullptr;
2860     rootPseudoStyle =
2861         BeginBuildingScrollFrame(state, aDocElement, styleContext,
2862                                  viewportFrame, rootPseudo, true, newFrame);
2863     parentFrame = newFrame;
2864   }
2865 
2866   rootFrame->SetStyleContextWithoutNotification(rootPseudoStyle);
2867   rootFrame->Init(aDocElement, parentFrame, nullptr);
2868 
2869   if (isScrollable) {
2870     FinishBuildingScrollFrame(parentFrame, rootFrame);
2871   }
2872 
2873   if (isPaginated) {
2874     // Create the first page
2875     // Set the initial child lists
2876     nsContainerFrame* canvasFrame;
2877     nsContainerFrame* pageFrame =
2878         ConstructPageFrame(mPresShell, rootFrame, nullptr, canvasFrame);
2879     pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2880     SetInitialSingleChild(rootFrame, pageFrame);
2881 
2882     // The eventual parent of the document element frame.
2883     // XXX should this be set for every new page (in ConstructPageFrame)?
2884     mDocElementContainingBlock = canvasFrame;
2885     mHasRootAbsPosContainingBlock = true;
2886   }
2887 
2888   if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
2889     SetInitialSingleChild(viewportFrame, newFrame);
2890   } else {
2891     nsFrameList newFrameList(newFrame, newFrame);
2892     viewportFrame->AppendFrames(kPrincipalList, newFrameList);
2893   }
2894 }
2895 
ConstructAnonymousContentForCanvas(nsFrameConstructorState & aState,nsIFrame * aFrame,nsIContent * aDocElement)2896 void nsCSSFrameConstructor::ConstructAnonymousContentForCanvas(
2897     nsFrameConstructorState& aState, nsIFrame* aFrame,
2898     nsIContent* aDocElement) {
2899   NS_ASSERTION(aFrame->IsCanvasFrame(), "aFrame should be canvas frame!");
2900 
2901   AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
2902   GetAnonymousContent(aDocElement, aFrame, anonymousItems);
2903   if (anonymousItems.IsEmpty()) {
2904     return;
2905   }
2906 
2907   AutoFrameConstructionItemList itemsToConstruct(this);
2908   nsContainerFrame* frameAsContainer = do_QueryFrame(aFrame);
2909   AddFCItemsForAnonymousContent(aState, frameAsContainer, anonymousItems,
2910                                 itemsToConstruct);
2911 
2912   nsFrameItems frameItems;
2913   ConstructFramesFromItemList(aState, itemsToConstruct, frameAsContainer,
2914                               /* aParentIsWrapperAnonBox = */ false,
2915                               frameItems);
2916   frameAsContainer->AppendFrames(kPrincipalList, frameItems);
2917 }
2918 
ConstructPageFrame(nsIPresShell * aPresShell,nsContainerFrame * aParentFrame,nsIFrame * aPrevPageFrame,nsContainerFrame * & aCanvasFrame)2919 nsContainerFrame* nsCSSFrameConstructor::ConstructPageFrame(
2920     nsIPresShell* aPresShell, nsContainerFrame* aParentFrame,
2921     nsIFrame* aPrevPageFrame, nsContainerFrame*& aCanvasFrame) {
2922   nsStyleContext* parentStyleContext = aParentFrame->StyleContext();
2923   StyleSetHandle styleSet = aPresShell->StyleSet();
2924 
2925   RefPtr<nsStyleContext> pagePseudoStyle;
2926   pagePseudoStyle = styleSet->ResolveInheritingAnonymousBoxStyle(
2927       nsCSSAnonBoxes::page, parentStyleContext);
2928 
2929   nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2930 
2931   // Initialize the page frame and force it to have a view. This makes printing
2932   // of the pages easier and faster.
2933   pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
2934 
2935   RefPtr<nsStyleContext> pageContentPseudoStyle;
2936   pageContentPseudoStyle = styleSet->ResolveInheritingAnonymousBoxStyle(
2937       nsCSSAnonBoxes::pageContent, pagePseudoStyle);
2938 
2939   nsContainerFrame* pageContentFrame =
2940       NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
2941 
2942   // Initialize the page content frame and force it to have a view. Also make it
2943   // the containing block for fixed elements which are repeated on every page.
2944   nsIFrame* prevPageContentFrame = nullptr;
2945   if (aPrevPageFrame) {
2946     prevPageContentFrame = aPrevPageFrame->PrincipalChildList().FirstChild();
2947     NS_ASSERTION(prevPageContentFrame, "missing page content frame");
2948   }
2949   pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
2950   if (!prevPageContentFrame) {
2951     pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2952   }
2953   SetInitialSingleChild(pageFrame, pageContentFrame);
2954   // Make it an absolute container for fixed-pos elements
2955   pageContentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2956   pageContentFrame->MarkAsAbsoluteContainingBlock();
2957 
2958   RefPtr<nsStyleContext> canvasPseudoStyle;
2959   canvasPseudoStyle = styleSet->ResolveInheritingAnonymousBoxStyle(
2960       nsCSSAnonBoxes::canvas, pageContentPseudoStyle);
2961 
2962   aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
2963 
2964   nsIFrame* prevCanvasFrame = nullptr;
2965   if (prevPageContentFrame) {
2966     prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
2967     NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
2968   }
2969   aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
2970   SetInitialSingleChild(pageContentFrame, aCanvasFrame);
2971   return pageFrame;
2972 }
2973 
2974 /* static */
CreatePlaceholderFrameFor(nsIPresShell * aPresShell,nsIContent * aContent,nsIFrame * aFrame,nsContainerFrame * aParentFrame,nsIFrame * aPrevInFlow,nsFrameState aTypeBit)2975 nsIFrame* nsCSSFrameConstructor::CreatePlaceholderFrameFor(
2976     nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* aFrame,
2977     nsContainerFrame* aParentFrame, nsIFrame* aPrevInFlow,
2978     nsFrameState aTypeBit) {
2979   RefPtr<nsStyleContext> placeholderStyle =
2980       aPresShell->StyleSet()->ResolveStyleForPlaceholder();
2981 
2982   // The placeholder frame gets a pseudo style context
2983   nsPlaceholderFrame* placeholderFrame =
2984       (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
2985                                                   aTypeBit);
2986 
2987   placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
2988 
2989   // Associate the placeholder/out-of-flow with each other.
2990   placeholderFrame->SetOutOfFlowFrame(aFrame);
2991   aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
2992 
2993   aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
2994 
2995   return placeholderFrame;
2996 }
2997 
2998 // Clears any lazy bits set in the range [aStartContent, aEndContent).  If
2999 // aEndContent is null, that means to clear bits in all siblings starting with
3000 // aStartContent.  aStartContent must not be null unless aEndContent is also
3001 // null.  We do this so that when new children are inserted under elements whose
3002 // frame is a leaf the new children don't cause us to try to construct frames
3003 // for the existing children again.
ClearLazyBits(nsIContent * aStartContent,nsIContent * aEndContent)3004 static inline void ClearLazyBits(nsIContent* aStartContent,
3005                                  nsIContent* aEndContent) {
3006   NS_PRECONDITION(aStartContent || !aEndContent,
3007                   "Must have start child if we have an end child");
3008   for (nsIContent* cur = aStartContent; cur != aEndContent;
3009        cur = cur->GetNextSibling()) {
3010     cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
3011   }
3012 }
3013 
ConstructSelectFrame(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aStyleDisplay,nsFrameItems & aFrameItems)3014 nsIFrame* nsCSSFrameConstructor::ConstructSelectFrame(
3015     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3016     nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3017     nsFrameItems& aFrameItems) {
3018   nsIContent* const content = aItem.mContent;
3019   nsStyleContext* const styleContext = aItem.mStyleContext;
3020 
3021   // Construct a frame-based listbox or combobox
3022   dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromContent(content);
3023   MOZ_ASSERT(sel);
3024   if (sel->IsCombobox()) {
3025     // Construct a frame-based combo box.
3026     // The frame-based combo box is built out of three parts. A display area, a
3027     // button and a dropdown list. The display area and button are created
3028     // through anonymous content. The drop-down list's frame is created
3029     // explicitly. The combobox frame shares its content with the drop-down
3030     // list.
3031     nsFrameState flags = NS_BLOCK_FLOAT_MGR;
3032     nsComboboxControlFrame* comboboxFrame =
3033         NS_NewComboboxControlFrame(mPresShell, styleContext, flags);
3034 
3035     // Save the history state so we don't restore during construction
3036     // since the complete tree is required before we restore.
3037     nsILayoutHistoryState* historyState = aState.mFrameState;
3038     aState.mFrameState = nullptr;
3039     // Initialize the combobox frame
3040     InitAndRestoreFrame(aState, content,
3041                         aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3042                         comboboxFrame);
3043 
3044     comboboxFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3045 
3046     aState.AddChild(comboboxFrame, aFrameItems, content, aParentFrame);
3047 
3048     // Resolve pseudo element style for the dropdown list
3049     RefPtr<nsStyleContext> listStyle;
3050     listStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3051         nsCSSAnonBoxes::dropDownList, styleContext);
3052 
3053     // Create a listbox
3054     nsContainerFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
3055 
3056     // Notify the listbox that it is being used as a dropdown list.
3057     nsIListControlFrame* listControlFrame = do_QueryFrame(listFrame);
3058     if (listControlFrame) {
3059       listControlFrame->SetComboboxFrame(comboboxFrame);
3060     }
3061     // Notify combobox that it should use the listbox as it's popup
3062     comboboxFrame->SetDropDown(listFrame);
3063 
3064     if (!nsLayoutUtils::IsContentSelectEnabled()) {
3065       // TODO(kuoe0) Remove this assertion when content-select is shipped.
3066       NS_ASSERTION(!listFrame->IsAbsPosContainingBlock(),
3067                    "Ended up with positioned dropdown list somehow.");
3068     }
3069     NS_ASSERTION(!listFrame->IsFloating(),
3070                  "Ended up with floating dropdown list somehow.");
3071 
3072     // child frames of combobox frame
3073     nsFrameItems childItems;
3074 
3075     // Initialize the scroll frame positioned. Note that it is NOT
3076     // initialized as absolutely positioned.
3077     nsContainerFrame* scrolledFrame =
3078         NS_NewSelectsAreaFrame(mPresShell, styleContext, flags);
3079 
3080     InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3081                           comboboxFrame, listStyle, true, aItem.mPendingBinding,
3082                           childItems);
3083 
3084     if (!nsLayoutUtils::IsContentSelectEnabled()) {
3085       // TODO(kuoe0) Remove this assertion when content-select is shipped.
3086       NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nullptr");
3087     }
3088 
3089     // Create display and button frames from the combobox's anonymous content.
3090     // The anonymous content is appended to existing anonymous content for this
3091     // element (the scrollbars).
3092     //
3093     // nsComboboxControlFrame needs special frame creation behavior for its
3094     // first piece of anonymous content, which means that we can't take the
3095     // normal ProcessChildren path.
3096     AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
3097     DebugOnly<nsresult> rv =
3098         GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
3099     MOZ_ASSERT(NS_SUCCEEDED(rv));
3100     MOZ_ASSERT(newAnonymousItems.Length() == 2);
3101 
3102     // Manually create a frame for the special NAC.
3103     MOZ_ASSERT(newAnonymousItems[0].mContent ==
3104                comboboxFrame->GetDisplayNode());
3105     newAnonymousItems.RemoveElementAt(0);
3106     nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
3107     MOZ_ASSERT(customFrame);
3108     customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
3109     childItems.AddChild(customFrame);
3110 
3111     // The other piece of NAC can take the normal path.
3112     AutoFrameConstructionItemList fcItems(this);
3113     AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
3114                                   fcItems);
3115     ConstructFramesFromItemList(aState, fcItems, comboboxFrame,
3116                                 /* aParentIsWrapperAnonBox = */ false,
3117                                 childItems);
3118 
3119     comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
3120 
3121     if (!nsLayoutUtils::IsContentSelectEnabled()) {
3122       // Initialize the additional popup child list which contains the
3123       // dropdown list frame.
3124       nsFrameItems popupItems;
3125       popupItems.AddChild(listFrame);
3126       comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList,
3127                                          popupItems);
3128     }
3129 
3130     aState.mFrameState = historyState;
3131     if (aState.mFrameState) {
3132       // Restore frame state for the entire subtree of |comboboxFrame|.
3133       RestoreFrameState(comboboxFrame, aState.mFrameState);
3134     }
3135     return comboboxFrame;
3136   }
3137 
3138   // Listbox, not combobox
3139   nsContainerFrame* listFrame =
3140       NS_NewListControlFrame(mPresShell, styleContext);
3141 
3142   nsContainerFrame* scrolledFrame =
3143       NS_NewSelectsAreaFrame(mPresShell, styleContext, NS_BLOCK_FLOAT_MGR);
3144 
3145   // ******* this code stolen from Initialze ScrollFrame ********
3146   // please adjust this code to use BuildScrollFrame.
3147 
3148   InitializeSelectFrame(aState, listFrame, scrolledFrame, content, aParentFrame,
3149                         styleContext, false, aItem.mPendingBinding,
3150                         aFrameItems);
3151 
3152   return listFrame;
3153 }
3154 
3155 /**
3156  * Used to be InitializeScrollFrame but now it's only used for the select tag
3157  * But the select tag should really be fixed to use GFX scrollbars that can
3158  * be create with BuildScrollFrame.
3159  */
InitializeSelectFrame(nsFrameConstructorState & aState,nsContainerFrame * scrollFrame,nsContainerFrame * scrolledFrame,nsIContent * aContent,nsContainerFrame * aParentFrame,nsStyleContext * aStyleContext,bool aBuildCombobox,PendingBinding * aPendingBinding,nsFrameItems & aFrameItems)3160 void nsCSSFrameConstructor::InitializeSelectFrame(
3161     nsFrameConstructorState& aState, nsContainerFrame* scrollFrame,
3162     nsContainerFrame* scrolledFrame, nsIContent* aContent,
3163     nsContainerFrame* aParentFrame, nsStyleContext* aStyleContext,
3164     bool aBuildCombobox, PendingBinding* aPendingBinding,
3165     nsFrameItems& aFrameItems) {
3166   // Initialize it
3167   nsContainerFrame* geometricParent =
3168       aState.GetGeometricParent(aStyleContext->StyleDisplay(), aParentFrame);
3169 
3170   // We don't call InitAndRestoreFrame for scrollFrame because we can only
3171   // restore the frame state after its parts have been created (in particular,
3172   // the scrollable view). So we have to split Init and Restore.
3173 
3174   scrollFrame->Init(aContent, geometricParent, nullptr);
3175 
3176   if (!aBuildCombobox || nsLayoutUtils::IsContentSelectEnabled()) {
3177     aState.AddChild(scrollFrame, aFrameItems, aContent, aParentFrame);
3178   }
3179 
3180   BuildScrollFrame(aState, aContent, aStyleContext, scrolledFrame,
3181                    geometricParent, scrollFrame);
3182 
3183   if (aState.mFrameState) {
3184     // Restore frame state for the scroll frame
3185     RestoreFrameStateFor(scrollFrame, aState.mFrameState);
3186   }
3187 
3188   // Process children
3189   nsFrameItems childItems;
3190 
3191   ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, false,
3192                   childItems, false, aPendingBinding);
3193 
3194   // Set the scrolled frame's initial child lists
3195   scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
3196 }
3197 
ConstructFieldSetFrame(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aStyleDisplay,nsFrameItems & aFrameItems)3198 nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
3199     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3200     nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3201     nsFrameItems& aFrameItems) {
3202   nsIContent* const content = aItem.mContent;
3203   nsStyleContext* const styleContext = aItem.mStyleContext;
3204 
3205   nsContainerFrame* fieldsetFrame =
3206       NS_NewFieldSetFrame(mPresShell, styleContext);
3207 
3208   // Initialize it
3209   InitAndRestoreFrame(aState, content,
3210                       aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3211                       fieldsetFrame);
3212 
3213   fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3214 
3215   // Resolve style and initialize the frame
3216   RefPtr<nsStyleContext> fieldsetContentStyle;
3217   fieldsetContentStyle =
3218       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3219           nsCSSAnonBoxes::fieldsetContent, styleContext);
3220 
3221   const nsStyleDisplay* fieldsetContentDisplay =
3222       fieldsetContentStyle->StyleDisplay();
3223   bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3224   nsContainerFrame* scrollFrame = nullptr;
3225   if (isScrollable) {
3226     fieldsetContentStyle = BeginBuildingScrollFrame(
3227         aState, content, fieldsetContentStyle, fieldsetFrame,
3228         nsCSSAnonBoxes::scrolledContent, false, scrollFrame);
3229   }
3230 
3231   nsContainerFrame* absPosContainer = nullptr;
3232   if (fieldsetFrame->IsAbsPosContainingBlock()) {
3233     absPosContainer = fieldsetFrame;
3234   }
3235 
3236   // Create the inner ::-moz-fieldset-content frame.
3237   nsContainerFrame* contentFrameTop;
3238   nsContainerFrame* contentFrame;
3239   auto parent = scrollFrame ? scrollFrame : fieldsetFrame;
3240   switch (fieldsetContentDisplay->mDisplay) {
3241     case StyleDisplay::Flex:
3242       contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3243       InitAndRestoreFrame(aState, content, parent, contentFrame);
3244       contentFrameTop = contentFrame;
3245       break;
3246     case StyleDisplay::Grid:
3247       contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3248       InitAndRestoreFrame(aState, content, parent, contentFrame);
3249       contentFrameTop = contentFrame;
3250       break;
3251     default: {
3252       MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
3253                  "bug in nsRuleNode::ComputeDisplayData?");
3254 
3255       nsContainerFrame* columnSetFrame = nullptr;
3256       RefPtr<nsStyleContext> innerSC = fieldsetContentStyle;
3257       const nsStyleColumn* columns = fieldsetContentStyle->StyleColumn();
3258       if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
3259           columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
3260         columnSetFrame =
3261             NS_NewColumnSetFrame(mPresShell, fieldsetContentStyle,
3262                                  nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
3263         InitAndRestoreFrame(aState, content, parent, columnSetFrame);
3264         innerSC = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3265             nsCSSAnonBoxes::columnContent, fieldsetContentStyle);
3266         if (absPosContainer) {
3267           absPosContainer = columnSetFrame;
3268         }
3269       }
3270       contentFrame = NS_NewBlockFormattingContext(mPresShell, innerSC);
3271       if (columnSetFrame) {
3272         InitAndRestoreFrame(aState, content, columnSetFrame, contentFrame);
3273         SetInitialSingleChild(columnSetFrame, contentFrame);
3274         contentFrameTop = columnSetFrame;
3275       } else {
3276         InitAndRestoreFrame(aState, content, parent, contentFrame);
3277         contentFrameTop = contentFrame;
3278       }
3279       break;
3280     }
3281   }
3282 
3283   aState.AddChild(fieldsetFrame, aFrameItems, content, aParentFrame);
3284 
3285   // Process children
3286   nsFrameConstructorSaveState absoluteSaveState;
3287   nsFrameItems childItems;
3288 
3289   contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3290   if (absPosContainer) {
3291     aState.PushAbsoluteContainingBlock(contentFrame, absPosContainer,
3292                                        absoluteSaveState);
3293   }
3294 
3295   ProcessChildren(aState, content, styleContext, contentFrame, true, childItems,
3296                   true, aItem.mPendingBinding);
3297 
3298   nsFrameItems fieldsetKids;
3299   fieldsetKids.AddChild(scrollFrame ? scrollFrame : contentFrameTop);
3300 
3301   for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
3302     nsIFrame* child = e.get();
3303     nsContainerFrame* cif = child->GetContentInsertionFrame();
3304     if (cif && cif->IsLegendFrame()) {
3305       // We want the legend to be the first frame in the fieldset child list.
3306       // That way the EventStateManager will do the right thing when tabbing
3307       // from a selection point within the legend (bug 236071), which is
3308       // used for implementing legend access keys (bug 81481).
3309       // GetAdjustedParentFrame() below depends on this frame order.
3310       childItems.RemoveFrame(child);
3311       // Make sure to reparent the legend so it has the fieldset as the parent.
3312       fieldsetKids.InsertFrame(fieldsetFrame, nullptr, child);
3313       if (scrollFrame) {
3314         StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(
3315             child, contentFrame);
3316       }
3317       break;
3318     }
3319   }
3320 
3321   if (isScrollable) {
3322     FinishBuildingScrollFrame(scrollFrame, contentFrameTop);
3323   }
3324 
3325   // Set the inner frame's initial child lists
3326   contentFrame->SetInitialChildList(kPrincipalList, childItems);
3327 
3328   // Set the outer frame's initial child list
3329   fieldsetFrame->SetInitialChildList(kPrincipalList, fieldsetKids);
3330 
3331   fieldsetFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
3332 
3333   // Our new frame returned is the outer frame, which is the fieldset frame.
3334   return fieldsetFrame;
3335 }
3336 
ConstructDetailsFrame(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aStyleDisplay,nsFrameItems & aFrameItems)3337 nsIFrame* nsCSSFrameConstructor::ConstructDetailsFrame(
3338     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3339     nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3340     nsFrameItems& aFrameItems) {
3341   if (!aStyleDisplay->IsScrollableOverflow()) {
3342     return ConstructNonScrollableBlockWithConstructor(
3343         aState, aItem, aParentFrame, aStyleDisplay, aFrameItems,
3344         NS_NewDetailsFrame);
3345   }
3346 
3347   // Build a scroll frame to wrap details frame if necessary.
3348   return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3349                                                  aStyleDisplay, aFrameItems,
3350                                                  NS_NewDetailsFrame);
3351 }
3352 
FindAncestorWithGeneratedContentPseudo(nsIFrame * aFrame)3353 static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) {
3354   for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3355     NS_ASSERTION(f->IsGeneratedContentFrame(),
3356                  "should not have exited generated content");
3357     nsAtom* pseudo = f->StyleContext()->GetPseudo();
3358     if (pseudo == nsCSSPseudoElements::before ||
3359         pseudo == nsCSSPseudoElements::after)
3360       return f;
3361   }
3362   return nullptr;
3363 }
3364 
3365 #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3366 #define FULL_CTOR_FCDATA(_flags, _func) \
3367   { _flags | FCDATA_FUNC_IS_FULL_CTOR, {nullptr}, _func, nullptr }
3368 
3369 /* static */
3370 const nsCSSFrameConstructor::FrameConstructionData*
FindTextData(nsIFrame * aParentFrame)3371 nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame) {
3372   if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3373     nsIFrame* ancestorFrame =
3374         nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
3375     if (ancestorFrame) {
3376       static const FrameConstructionData sSVGTextData = FCDATA_DECL(
3377           FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT, NS_NewTextFrame);
3378       if (nsSVGUtils::IsInSVGTextSubtree(ancestorFrame)) {
3379         return &sSVGTextData;
3380       }
3381     }
3382     return nullptr;
3383   }
3384 
3385   static const FrameConstructionData sTextData =
3386       FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
3387   return &sTextData;
3388 }
3389 
ConstructTextFrame(const FrameConstructionData * aData,nsFrameConstructorState & aState,nsIContent * aContent,nsContainerFrame * aParentFrame,nsStyleContext * aStyleContext,nsFrameItems & aFrameItems)3390 void nsCSSFrameConstructor::ConstructTextFrame(
3391     const FrameConstructionData* aData, nsFrameConstructorState& aState,
3392     nsIContent* aContent, nsContainerFrame* aParentFrame,
3393     nsStyleContext* aStyleContext, nsFrameItems& aFrameItems) {
3394   NS_PRECONDITION(aData, "Must have frame construction data");
3395 
3396   nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aStyleContext);
3397 
3398   InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3399 
3400   // We never need to create a view for a text frame.
3401 
3402   if (newFrame->IsGeneratedContentFrame()) {
3403     nsAutoPtr<nsGenConInitializer> initializer;
3404     initializer = static_cast<nsGenConInitializer*>(
3405         aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
3406     if (initializer) {
3407       if (initializer->mNode->InitTextFrame(
3408               initializer->mList,
3409               FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
3410         (this->*(initializer->mDirtyAll))();
3411       }
3412       initializer->mNode.forget();
3413     }
3414   }
3415 
3416   // Add the newly constructed frame to the flow
3417   aFrameItems.AddChild(newFrame);
3418 
3419   if (!aState.mCreatingExtraFrames) aContent->SetPrimaryFrame(newFrame);
3420 }
3421 
3422 /* static */
3423 const nsCSSFrameConstructor::FrameConstructionData*
FindDataByInt(int32_t aInt,Element * aElement,nsStyleContext * aStyleContext,const FrameConstructionDataByInt * aDataPtr,uint32_t aDataLength)3424 nsCSSFrameConstructor::FindDataByInt(int32_t aInt, Element* aElement,
3425                                      nsStyleContext* aStyleContext,
3426                                      const FrameConstructionDataByInt* aDataPtr,
3427                                      uint32_t aDataLength) {
3428   for (const FrameConstructionDataByInt *curData = aDataPtr,
3429                                         *endData = aDataPtr + aDataLength;
3430        curData != endData; ++curData) {
3431     if (curData->mInt == aInt) {
3432       const FrameConstructionData* data = &curData->mData;
3433       if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3434         return data->mFunc.mDataGetter(aElement, aStyleContext);
3435       }
3436 
3437       return data;
3438     }
3439   }
3440 
3441   return nullptr;
3442 }
3443 
3444 /* static */
3445 const nsCSSFrameConstructor::FrameConstructionData*
FindDataByTag(nsAtom * aTag,Element * aElement,nsStyleContext * aStyleContext,const FrameConstructionDataByTag * aDataPtr,uint32_t aDataLength,bool * aTagFound)3446 nsCSSFrameConstructor::FindDataByTag(nsAtom* aTag, Element* aElement,
3447                                      nsStyleContext* aStyleContext,
3448                                      const FrameConstructionDataByTag* aDataPtr,
3449                                      uint32_t aDataLength, bool* aTagFound) {
3450   if (aTagFound) {
3451     *aTagFound = false;
3452   }
3453   for (const FrameConstructionDataByTag *curData = aDataPtr,
3454                                         *endData = aDataPtr + aDataLength;
3455        curData != endData; ++curData) {
3456     if (*curData->mTag == aTag) {
3457       if (aTagFound) {
3458         *aTagFound = true;
3459       }
3460       const FrameConstructionData* data = &curData->mData;
3461       if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3462         return data->mFunc.mDataGetter(aElement, aStyleContext);
3463       }
3464 
3465       return data;
3466     }
3467   }
3468 
3469   return nullptr;
3470 }
3471 
3472 #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nullptr)
3473 #define SIMPLE_INT_CREATE(_int, _func) \
3474   { _int, SIMPLE_FCDATA(_func) }
3475 #define SIMPLE_INT_CHAIN(_int, _func) \
3476   { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3477 #define COMPLEX_INT_CREATE(_int, _func) \
3478   { _int, FULL_CTOR_FCDATA(0, _func) }
3479 
3480 #define SIMPLE_TAG_CREATE(_tag, _func) \
3481   { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3482 #define SIMPLE_TAG_CHAIN(_tag, _func) \
3483   { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3484 #define COMPLEX_TAG_CREATE(_tag, _func) \
3485   { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3486 
IsFrameForFieldSet(nsIFrame * aFrame)3487 static bool IsFrameForFieldSet(nsIFrame* aFrame) {
3488   nsAtom* pseudo = aFrame->StyleContext()->GetPseudo();
3489   if (pseudo == nsCSSAnonBoxes::fieldsetContent ||
3490       pseudo == nsCSSAnonBoxes::scrolledContent ||
3491       pseudo == nsCSSAnonBoxes::columnContent) {
3492     return IsFrameForFieldSet(aFrame->GetParent());
3493   }
3494   return aFrame->IsFieldSetFrame();
3495 }
3496 
3497 /* static */
3498 const nsCSSFrameConstructor::FrameConstructionData*
FindHTMLData(Element * aElement,nsAtom * aTag,int32_t aNameSpaceID,nsIFrame * aParentFrame,nsStyleContext * aStyleContext)3499 nsCSSFrameConstructor::FindHTMLData(Element* aElement, nsAtom* aTag,
3500                                     int32_t aNameSpaceID,
3501                                     nsIFrame* aParentFrame,
3502                                     nsStyleContext* aStyleContext) {
3503   // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
3504   // a valid HTML namespace.  This check must match the one in
3505   // ShouldHaveFirstLineStyle.
3506   if (aNameSpaceID != kNameSpaceID_XHTML) {
3507     return nullptr;
3508   }
3509 
3510   NS_ASSERTION(!aParentFrame ||
3511                    aParentFrame->StyleContext()->GetPseudo() !=
3512                        nsCSSAnonBoxes::fieldsetContent ||
3513                    aParentFrame->GetParent()->IsFieldSetFrame(),
3514                "Unexpected parent for fieldset content anon box");
3515   if (aTag == nsGkAtoms::legend &&
3516       (!aParentFrame || !IsFrameForFieldSet(aParentFrame) ||
3517        aStyleContext->StyleDisplay()->IsFloatingStyle() ||
3518        aStyleContext->StyleDisplay()->IsAbsolutelyPositionedStyle())) {
3519     // <legend> is only special inside fieldset, we only check the frame tree
3520     // parent because the content tree parent may not be a <fieldset> due to
3521     // display:contents, Shadow DOM, or XBL. For floated or absolutely
3522     // positioned legends we want to construct by display type and
3523     // not do special legend stuff.
3524     return nullptr;
3525   }
3526 
3527   static const FrameConstructionDataByTag sHTMLData[] = {
3528       SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
3529       SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
3530                        nsCSSFrameConstructor::FindImgData),
3531       {&nsGkAtoms::br,
3532        FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
3533                    NS_NewBRFrame)},
3534       SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
3535       SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
3536       SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
3537       COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
3538       SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
3539       SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
3540       COMPLEX_TAG_CREATE(fieldset,
3541                          &nsCSSFrameConstructor::ConstructFieldSetFrame),
3542       {&nsGkAtoms::legend,
3543        FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
3544                    NS_NewLegendFrame)},
3545       SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
3546       SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
3547       {&nsGkAtoms::button,
3548        FCDATA_WITH_WRAPPING_BLOCK(
3549            FCDATA_ALLOW_BLOCK_STYLES | FCDATA_ALLOW_GRID_FLEX_COLUMNSET,
3550            NS_NewHTMLButtonControlFrame, nsCSSAnonBoxes::buttonContent)},
3551       SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
3552       SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
3553       SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
3554       SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
3555       SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
3556       COMPLEX_TAG_CREATE(details,
3557                          &nsCSSFrameConstructor::ConstructDetailsFrame)};
3558 
3559   bool tagFound;
3560   const FrameConstructionData* data =
3561       FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
3562                     ArrayLength(sHTMLData), &tagFound);
3563 
3564   // https://drafts.csswg.org/css-display/#unbox-html
3565   if (tagFound && MOZ_UNLIKELY(aStyleContext->StyleDisplay()->mDisplay ==
3566                                StyleDisplay::Contents)) {
3567     // <button>, <legend>, <details> and <fieldset> don’t have any special
3568     // behavior; display: contents simply removes their principal box, and their
3569     // contents render as normal.
3570     if (aTag != nsGkAtoms::button && aTag != nsGkAtoms::legend &&
3571         aTag != nsGkAtoms::details && aTag != nsGkAtoms::fieldset) {
3572       // On the rest of unusual HTML elements, display: contents creates no box.
3573       static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
3574       return &sSuppressData;
3575     }
3576   }
3577 
3578   return data;
3579 }
3580 
3581 /* static */
3582 const nsCSSFrameConstructor::FrameConstructionData*
FindImgData(Element * aElement,nsStyleContext * aStyleContext)3583 nsCSSFrameConstructor::FindImgData(Element* aElement,
3584                                    nsStyleContext* aStyleContext) {
3585   if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
3586     return nullptr;
3587   }
3588 
3589   static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
3590   return &sImgData;
3591 }
3592 
3593 /* static */
3594 const nsCSSFrameConstructor::FrameConstructionData*
FindImgControlData(Element * aElement,nsStyleContext * aStyleContext)3595 nsCSSFrameConstructor::FindImgControlData(Element* aElement,
3596                                           nsStyleContext* aStyleContext) {
3597   if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
3598     return nullptr;
3599   }
3600 
3601   static const FrameConstructionData sImgControlData =
3602       SIMPLE_FCDATA(NS_NewImageControlFrame);
3603   return &sImgControlData;
3604 }
3605 
3606 /* static */
3607 const nsCSSFrameConstructor::FrameConstructionData*
FindInputData(Element * aElement,nsStyleContext * aStyleContext)3608 nsCSSFrameConstructor::FindInputData(Element* aElement,
3609                                      nsStyleContext* aStyleContext) {
3610   static const FrameConstructionDataByInt sInputData[] = {
3611       SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewCheckboxRadioFrame),
3612       SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewCheckboxRadioFrame),
3613       SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
3614       SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
3615                        nsCSSFrameConstructor::FindImgControlData),
3616       SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame),
3617       SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame),
3618       SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
3619       SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame),
3620       SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame),
3621       SIMPLE_INT_CREATE(NS_FORM_INPUT_RANGE, NS_NewRangeFrame),
3622       SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
3623       {NS_FORM_INPUT_COLOR,
3624        FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewColorControlFrame,
3625                                   nsCSSAnonBoxes::buttonContent)},
3626       // TODO: this is temporary until a frame is written: bug 635240.
3627       SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
3628       SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewDateTimeControlFrame),
3629       SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewDateTimeControlFrame),
3630       // TODO: this is temporary until a frame is written: bug 888320
3631       SIMPLE_INT_CREATE(NS_FORM_INPUT_MONTH, NS_NewTextControlFrame),
3632       // TODO: this is temporary until a frame is written: bug 888320
3633       SIMPLE_INT_CREATE(NS_FORM_INPUT_WEEK, NS_NewTextControlFrame),
3634       // TODO: this is temporary until a frame is written: bug 888320
3635       SIMPLE_INT_CREATE(NS_FORM_INPUT_DATETIME_LOCAL, NS_NewTextControlFrame),
3636       {NS_FORM_INPUT_SUBMIT,
3637        FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3638                                   nsCSSAnonBoxes::buttonContent)},
3639       {NS_FORM_INPUT_RESET,
3640        FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3641                                   nsCSSAnonBoxes::buttonContent)},
3642       {NS_FORM_INPUT_BUTTON,
3643        FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3644                                   nsCSSAnonBoxes::buttonContent)}
3645       // Keeping hidden inputs out of here on purpose for so they get frames by
3646       // display (in practice, none).
3647   };
3648 
3649   nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
3650   NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
3651 
3652   auto controlType = control->ControlType();
3653 
3654   // radio and checkbox inputs with appearance:none should be constructed
3655   // by display type.  (Note that we're not checking that appearance is
3656   // not (respectively) NS_THEME_RADIO and NS_THEME_CHECKBOX.)
3657   if ((controlType == NS_FORM_INPUT_CHECKBOX ||
3658        controlType == NS_FORM_INPUT_RADIO) &&
3659       aStyleContext->StyleDisplay()->mAppearance == NS_THEME_NONE) {
3660     return nullptr;
3661   }
3662 
3663   return FindDataByInt(controlType, aElement, aStyleContext, sInputData,
3664                        ArrayLength(sInputData));
3665 }
3666 
3667 /* static */
3668 const nsCSSFrameConstructor::FrameConstructionData*
FindObjectData(Element * aElement,nsStyleContext * aStyleContext)3669 nsCSSFrameConstructor::FindObjectData(Element* aElement,
3670                                       nsStyleContext* aStyleContext) {
3671   // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3672   // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3673   // we want to treat those cases as TYPE_NULL
3674   uint32_t type;
3675   if (aElement->State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
3676                                               NS_EVENT_STATE_USERDISABLED |
3677                                               NS_EVENT_STATE_SUPPRESSED)) {
3678     type = nsIObjectLoadingContent::TYPE_NULL;
3679   } else {
3680     nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement));
3681     NS_ASSERTION(objContent,
3682                  "embed and object must implement "
3683                  "nsIObjectLoadingContent!");
3684 
3685     objContent->GetDisplayedType(&type);
3686   }
3687 
3688   static const FrameConstructionDataByInt sObjectData[] = {
3689       SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
3690                         NS_NewEmptyFrame),
3691       SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
3692                         NS_NewObjectFrame),
3693       SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE, NS_NewImageFrame),
3694       SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
3695                         NS_NewSubDocumentFrame),
3696       // Fake plugin handlers load as documents
3697       SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_FAKE_PLUGIN,
3698                         NS_NewSubDocumentFrame)
3699       // Nothing for TYPE_NULL so we'll construct frames by display there
3700   };
3701 
3702   return FindDataByInt((int32_t)type, aElement, aStyleContext, sObjectData,
3703                        ArrayLength(sObjectData));
3704 }
3705 
3706 /* static */
3707 const nsCSSFrameConstructor::FrameConstructionData*
FindCanvasData(Element * aElement,nsStyleContext * aStyleContext)3708 nsCSSFrameConstructor::FindCanvasData(Element* aElement,
3709                                       nsStyleContext* aStyleContext) {
3710   // We want to check whether script is enabled on the document that
3711   // could be painting to the canvas.  That's the owner document of
3712   // the canvas, except when the owner document is a static document,
3713   // in which case it's the original document it was cloned from.
3714   nsIDocument* doc = aElement->OwnerDoc();
3715   if (doc->IsStaticDocument()) {
3716     doc = doc->GetOriginalDocument();
3717   }
3718   if (!doc->IsScriptEnabled()) {
3719     return nullptr;
3720   }
3721 
3722   static const FrameConstructionData sCanvasData = FCDATA_WITH_WRAPPING_BLOCK(
3723       0, NS_NewHTMLCanvasFrame, nsCSSAnonBoxes::htmlCanvasContent);
3724   return &sCanvasData;
3725 }
3726 
ConstructFrameFromItemInternal(FrameConstructionItem & aItem,nsFrameConstructorState & aState,nsContainerFrame * aParentFrame,nsFrameItems & aFrameItems)3727 void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
3728     FrameConstructionItem& aItem, nsFrameConstructorState& aState,
3729     nsContainerFrame* aParentFrame, nsFrameItems& aFrameItems) {
3730   const FrameConstructionData* data = aItem.mFCData;
3731   NS_ASSERTION(data, "Must have frame construction data");
3732 
3733   uint32_t bits = data->mBits;
3734 
3735   NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
3736                "Should have dealt with this inside the data finder");
3737 
3738   // Some sets of bits are not compatible with each other
3739 #define CHECK_ONLY_ONE_BIT(_bit1, _bit2)           \
3740   NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
3741                "Only one of these bits should be set")
3742   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3743                      FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
3744   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
3745   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
3746   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
3747   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
3748   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3749                      FCDATA_DISALLOW_GENERATED_CONTENT);
3750   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
3751   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3752                      FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3753   CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
3754                      FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3755 #undef CHECK_ONLY_ONE_BIT
3756   NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
3757                    ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
3758                     data->mFullConstructor ==
3759                         &nsCSSFrameConstructor::ConstructNonScrollableBlock),
3760                "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
3761   MOZ_ASSERT(
3762       !(bits & FCDATA_IS_WRAPPER_ANON_BOX) || (bits & FCDATA_USE_CHILD_ITEMS),
3763       "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS");
3764 
3765   // Don't create a subdocument frame for iframes if we're creating extra frames
3766   if (aState.mCreatingExtraFrames &&
3767       aItem.mContent->IsHTMLElement(nsGkAtoms::iframe)) {
3768     return;
3769   }
3770 
3771   nsIContent* const content = aItem.mContent;
3772   nsIContent* parent = content->GetParent();
3773 
3774   // Push display:contents ancestors.
3775   Maybe<AutoDisplayContentsAncestorPusher> adcp;
3776   if (aState.mTreeMatchContext) {
3777     adcp.emplace(*aState.mTreeMatchContext, aState.mPresContext, parent);
3778   } else {
3779     MOZ_ASSERT(content->IsStyledByServo());
3780   }
3781 
3782   // Get the parent of the content and check if it is a XBL children element.
3783   // Push the children element as an ancestor here because it does
3784   // not have a frame and would not otherwise be pushed as an ancestor. It is
3785   // necessary to do so in order to correctly handle style resolution on
3786   // descendants.  (If !adcp.IsEmpty() then it was already pushed by
3787   // AutoDisplayContentsAncestorPusher above.)
3788   TreeMatchContext::AutoAncestorPusher insertionPointPusher(
3789       aState.mTreeMatchContext);
3790   if (adcp.isSome() && adcp->IsEmpty() && parent &&
3791       parent->IsActiveChildrenElement()) {
3792     if (aState.HasAncestorFilter()) {
3793       insertionPointPusher.PushAncestorAndStyleScope(parent);
3794     } else {
3795       insertionPointPusher.PushStyleScope(parent);
3796     }
3797   }
3798 
3799   // Push the content as a style ancestor now, so we don't have to do
3800   // it in our various full-constructor functions.  In particular,
3801   // since a number of full-constructor functions don't actually call
3802   // ProcessChildren in some cases (e.g. for CSS anonymous table boxes
3803   // or for situations where only anonymouse children are having
3804   // frames constructed), this is the best place to bottleneck the
3805   // pushing of the content instead of having to do it in multiple
3806   // places.
3807   TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
3808   if (aState.HasAncestorFilter()) {
3809     ancestorPusher.PushAncestorAndStyleScope(content);
3810   } else {
3811     ancestorPusher.PushStyleScope(content);
3812   }
3813 
3814   nsIFrame* newFrame;
3815   nsIFrame* primaryFrame;
3816   nsStyleContext* const styleContext = aItem.mStyleContext;
3817   const nsStyleDisplay* display = styleContext->StyleDisplay();
3818   if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
3819     newFrame = (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
3820                                                  display, aFrameItems);
3821     MOZ_ASSERT(newFrame, "Full constructor failed");
3822     primaryFrame = newFrame;
3823   } else {
3824     newFrame = (*data->mFunc.mCreationFunc)(mPresShell, styleContext);
3825 
3826     bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
3827     bool isPopup = aItem.mIsPopup;
3828     NS_ASSERTION(
3829         !isPopup || (aState.mPopupItems.containingBlock &&
3830                      aState.mPopupItems.containingBlock->IsPopupSetFrame()),
3831         "Should have a containing block here!");
3832 
3833     nsContainerFrame* geometricParent =
3834         isPopup
3835             ? aState.mPopupItems.containingBlock
3836             : (allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame)
3837                               : aParentFrame);
3838 
3839     // Must init frameToAddToList to null, since it's inout
3840     nsIFrame* frameToAddToList = nullptr;
3841     if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
3842         display->IsScrollableOverflow()) {
3843       nsContainerFrame* scrollframe = nullptr;
3844       BuildScrollFrame(aState, content, styleContext, newFrame, geometricParent,
3845                        scrollframe);
3846       frameToAddToList = scrollframe;
3847     } else {
3848       InitAndRestoreFrame(aState, content, geometricParent, newFrame);
3849       frameToAddToList = newFrame;
3850     }
3851 
3852     // Use frameToAddToList as the primary frame.  In the non-scrollframe case
3853     // they're equal, but in the scrollframe case newFrame is the scrolled
3854     // frame, while frameToAddToList is the scrollframe (and should be the
3855     // primary frame).
3856     primaryFrame = frameToAddToList;
3857 
3858     // If we need to create a block formatting context to wrap our
3859     // kids, do it now.
3860     const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display;
3861     nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
3862     nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3863     nsIFrame* possiblyLeafFrame = newFrame;
3864     if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
3865       RefPtr<nsStyleContext> outerSC =
3866           mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3867               *data->mAnonBoxPseudo, styleContext);
3868 #ifdef DEBUG
3869       nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
3870       MOZ_ASSERT(containerFrame);
3871 #endif
3872       nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
3873       nsContainerFrame* outerFrame;
3874       nsContainerFrame* innerFrame;
3875       if (bits & FCDATA_ALLOW_GRID_FLEX_COLUMNSET) {
3876         switch (display->mDisplay) {
3877           case StyleDisplay::Flex:
3878           case StyleDisplay::InlineFlex:
3879             outerFrame = NS_NewFlexContainerFrame(mPresShell, outerSC);
3880             InitAndRestoreFrame(aState, content, container, outerFrame);
3881             innerFrame = outerFrame;
3882             break;
3883           case StyleDisplay::Grid:
3884           case StyleDisplay::InlineGrid:
3885             outerFrame = NS_NewGridContainerFrame(mPresShell, outerSC);
3886             InitAndRestoreFrame(aState, content, container, outerFrame);
3887             innerFrame = outerFrame;
3888             break;
3889           default: {
3890             nsContainerFrame* columnSetFrame = nullptr;
3891             RefPtr<nsStyleContext> innerSC = outerSC;
3892             const nsStyleColumn* columns = outerSC->StyleColumn();
3893             if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
3894                 columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
3895               columnSetFrame = NS_NewColumnSetFrame(
3896                   mPresShell, outerSC, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
3897               InitAndRestoreFrame(aState, content, container, columnSetFrame);
3898               innerSC =
3899                   mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3900                       nsCSSAnonBoxes::columnContent, outerSC);
3901             }
3902             innerFrame = NS_NewBlockFormattingContext(mPresShell, innerSC);
3903             if (columnSetFrame) {
3904               InitAndRestoreFrame(aState, content, columnSetFrame, innerFrame);
3905               SetInitialSingleChild(columnSetFrame, innerFrame);
3906               outerFrame = columnSetFrame;
3907             } else {
3908               InitAndRestoreFrame(aState, content, container, innerFrame);
3909               outerFrame = innerFrame;
3910             }
3911             break;
3912           }
3913         }
3914       } else {
3915         innerFrame = NS_NewBlockFormattingContext(mPresShell, outerSC);
3916         InitAndRestoreFrame(aState, content, container, innerFrame);
3917         outerFrame = innerFrame;
3918       }
3919 
3920       SetInitialSingleChild(container, outerFrame);
3921 
3922       container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3923 
3924       // Now figure out whether newFrame or outerFrame should be the
3925       // absolute container.
3926       auto outerDisplay = outerSC->StyleDisplay();
3927       if (outerDisplay->IsAbsPosContainingBlock(outerFrame)) {
3928         maybeAbsoluteContainingBlockDisplay = outerDisplay;
3929         maybeAbsoluteContainingBlock = outerFrame;
3930         maybeAbsoluteContainingBlockStyleFrame = outerFrame;
3931         innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3932       }
3933 
3934       // Our kids should go into the innerFrame.
3935       newFrame = innerFrame;
3936     }
3937 
3938     aState.AddChild(frameToAddToList, aFrameItems, content, aParentFrame,
3939                     allowOutOfFlow, allowOutOfFlow, isPopup);
3940 
3941     nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
3942     if (newFrameAsContainer) {
3943 #ifdef MOZ_XUL
3944       // Icky XUL stuff, sadly
3945 
3946       if (aItem.mIsRootPopupgroup) {
3947         NS_ASSERTION(
3948             nsIRootBox::GetRootBox(mPresShell) &&
3949                 nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
3950                     newFrame,
3951             "Unexpected PopupSetFrame");
3952         aState.mPopupItems.containingBlock = newFrameAsContainer;
3953         aState.mHavePendingPopupgroup = false;
3954       }
3955 #endif /* MOZ_XUL */
3956 
3957       // Process the child content if requested
3958       nsFrameItems childItems;
3959       nsFrameConstructorSaveState absoluteSaveState;
3960 
3961       if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
3962         aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
3963       } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
3964         maybeAbsoluteContainingBlock->AddStateBits(
3965             NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3966         // This check is identical to nsStyleDisplay::IsAbsPosContainingBlock
3967         // except without the assertion that the style display and frame match.
3968         // When constructing scroll frames we intentionally use the style
3969         // display for the outer, but make the inner the containing block.
3970         if ((maybeAbsoluteContainingBlockDisplay
3971                  ->IsAbsolutelyPositionedStyle() ||
3972              maybeAbsoluteContainingBlockDisplay
3973                  ->IsRelativelyPositionedStyle() ||
3974              maybeAbsoluteContainingBlockDisplay->IsFixedPosContainingBlock(
3975                  maybeAbsoluteContainingBlockStyleFrame)) &&
3976             !nsSVGUtils::IsInSVGTextSubtree(
3977                 maybeAbsoluteContainingBlockStyleFrame)) {
3978           nsContainerFrame* cf =
3979               static_cast<nsContainerFrame*>(maybeAbsoluteContainingBlock);
3980           aState.PushAbsoluteContainingBlock(cf, cf, absoluteSaveState);
3981         }
3982       }
3983 
3984       if (!aItem.mAnonChildren.IsEmpty()) {
3985         NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS),
3986                      "We should not have both anonymous and non-anonymous "
3987                      "children in a given FrameConstructorItem");
3988         AddFCItemsForAnonymousContent(aState, newFrameAsContainer,
3989                                       aItem.mAnonChildren, aItem.mChildItems);
3990         bits |= FCDATA_USE_CHILD_ITEMS;
3991       }
3992 
3993       if (bits & FCDATA_USE_CHILD_ITEMS) {
3994         nsFrameConstructorSaveState floatSaveState;
3995 
3996         if (ShouldSuppressFloatingOfDescendants(newFrame)) {
3997           aState.PushFloatContainingBlock(nullptr, floatSaveState);
3998         } else if (newFrame->IsFloatContainingBlock()) {
3999           aState.PushFloatContainingBlock(newFrameAsContainer, floatSaveState);
4000         }
4001         ConstructFramesFromItemList(
4002             aState, aItem.mChildItems, newFrameAsContainer,
4003             bits & FCDATA_IS_WRAPPER_ANON_BOX, childItems);
4004       } else {
4005         // Process the child frames.
4006         ProcessChildren(aState, content, styleContext, newFrameAsContainer,
4007                         !(bits & FCDATA_DISALLOW_GENERATED_CONTENT), childItems,
4008                         (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
4009                         aItem.mPendingBinding, possiblyLeafFrame);
4010       }
4011 
4012       if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) {
4013         nsFrameItems newItems;
4014         nsFrameItems currentBlockItems;
4015         nsIFrame* f;
4016         while ((f = childItems.FirstChild()) != nullptr) {
4017           bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
4018           if (!wrapFrame) {
4019             FlushAccumulatedBlock(aState, content, newFrameAsContainer,
4020                                   currentBlockItems, newItems);
4021           }
4022 
4023           childItems.RemoveFrame(f);
4024           if (wrapFrame) {
4025             currentBlockItems.AddChild(f);
4026           } else {
4027             newItems.AddChild(f);
4028           }
4029         }
4030         FlushAccumulatedBlock(aState, content, newFrameAsContainer,
4031                               currentBlockItems, newItems);
4032 
4033         if (childItems.NotEmpty()) {
4034           // an error must have occurred, delete unprocessed frames
4035           childItems.DestroyFrames();
4036         }
4037 
4038         childItems = newItems;
4039       }
4040 
4041       // Set the frame's initial child list
4042       // Note that MathML depends on this being called even if
4043       // childItems is empty!
4044       newFrameAsContainer->SetInitialChildList(kPrincipalList, childItems);
4045     }
4046   }
4047 
4048   NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
4049                    ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
4050                "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
4051 
4052   if (aItem.mIsAnonymousContentCreatorContent) {
4053     primaryFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
4054   }
4055 
4056   // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
4057   // generated content that doesn't have one yet.  Note that we have to examine
4058   // the frame bit, because by this point mIsGeneratedContent has been cleared
4059   // on aItem.
4060   if ((!aState.mCreatingExtraFrames ||
4061        (primaryFrame->HasAnyStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT |
4062                                       NS_FRAME_GENERATED_CONTENT) &&
4063         !aItem.mContent->GetPrimaryFrame())) &&
4064       !(bits & FCDATA_SKIP_FRAMESET)) {
4065     aItem.mContent->SetPrimaryFrame(primaryFrame);
4066     ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
4067   }
4068 }
4069 
SetFlagsOnSubtree(nsIContent * aNode,uintptr_t aFlagsToSet)4070 static void SetFlagsOnSubtree(nsIContent* aNode, uintptr_t aFlagsToSet) {
4071 #ifdef DEBUG
4072   // Make sure that the node passed to us doesn't have any XBL children
4073   {
4074     FlattenedChildIterator iter(aNode);
4075     NS_ASSERTION(!iter.XBLInvolved() || !iter.GetNextChild(),
4076                  "The node should not have any XBL children");
4077   }
4078 #endif
4079 
4080   // Set the flag on the node itself
4081   aNode->SetFlags(aFlagsToSet);
4082 
4083   // Set the flag on all of its children recursively
4084   for (nsIContent* child = aNode->GetFirstChild(); child;
4085        child = child->GetNextSibling()) {
4086     SetFlagsOnSubtree(child, aFlagsToSet);
4087   }
4088 }
4089 
4090 /**
4091  * This function takes a tree of nsIAnonymousContentCreator::ContentInfo
4092  * objects where the nsIContent nodes have just been created, and appends the
4093  * nsIContent children in the tree to their parent. The leaf nsIContent objects
4094  * are appended first to minimize the number of notifications that are sent
4095  * out (i.e. by appending as many descendants as posible while their parent is
4096  * not yet in the document tree).
4097  *
4098  * This function is used simply as a convenience so that implementations of
4099  * nsIAnonymousContentCreator::CreateAnonymousContent don't all have to have
4100  * their own code to connect the elements that they create.
4101  */
ConnectAnonymousTreeDescendants(nsIContent * aParent,nsTArray<nsIAnonymousContentCreator::ContentInfo> & aContent)4102 static void ConnectAnonymousTreeDescendants(
4103     nsIContent* aParent,
4104     nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) {
4105   uint32_t count = aContent.Length();
4106   for (uint32_t i = 0; i < count; i++) {
4107     nsIContent* content = aContent[i].mContent;
4108     NS_ASSERTION(content, "null anonymous content?");
4109 
4110     ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
4111 
4112     aParent->AppendChildTo(content, false);
4113   }
4114 }
4115 
SetNativeAnonymousBitOnDescendants(nsIContent * aRoot)4116 static void SetNativeAnonymousBitOnDescendants(nsIContent* aRoot) {
4117   for (nsIContent* curr = aRoot; curr; curr = curr->GetNextNode(aRoot)) {
4118     curr->SetFlags(NODE_IS_NATIVE_ANONYMOUS);
4119   }
4120 }
4121 
GetAnonymousContent(nsIContent * aParent,nsIFrame * aParentFrame,nsTArray<nsIAnonymousContentCreator::ContentInfo> & aContent)4122 nsresult nsCSSFrameConstructor::GetAnonymousContent(
4123     nsIContent* aParent, nsIFrame* aParentFrame,
4124     nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) {
4125   nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
4126   if (!creator) return NS_OK;
4127 
4128   nsresult rv = creator->CreateAnonymousContent(aContent);
4129   if (NS_FAILED(rv)) {
4130     // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
4131     return rv;
4132   }
4133 
4134   uint32_t count = aContent.Length();
4135   for (uint32_t i = 0; i < count; i++) {
4136     // get our child's content and set its parent to our content
4137     nsIContent* content = aContent[i].mContent;
4138     NS_ASSERTION(content, "null anonymous content?");
4139 
4140     ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
4141 
4142     LayoutFrameType parentFrameType = aParentFrame->Type();
4143     if (parentFrameType == LayoutFrameType::SVGUse) {
4144       // least-surprise CSS binding until we do the SVG specified
4145       // cascading rules for <svg:use> - bug 265894
4146       content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
4147     } else {
4148       content->SetIsNativeAnonymousRoot();
4149       // Don't mark descendants of the custom content container
4150       // as native anonymous.  When canvas custom content is initially
4151       // created and appended to the custom content container, in
4152       // nsIDocument::InsertAnonymousContent, it is not considered native
4153       // anonymous content.  But if we end up reframing the root element,
4154       // we will re-create the nsCanvasFrame, and we would end up in here,
4155       // marking it as NAC.  Existing uses of canvas custom content would
4156       // break if it becomes NAC (since each element starts inheriting
4157       // styles from its closest non-NAC ancestor, rather than from its
4158       // parent).
4159       if (!(parentFrameType == LayoutFrameType::Canvas &&
4160             content == static_cast<nsCanvasFrame*>(aParentFrame)
4161                            ->GetCustomContentContainer())) {
4162         SetNativeAnonymousBitOnDescendants(content);
4163       }
4164     }
4165 
4166     bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
4167 
4168     // If the parent is in a shadow tree, make sure we don't
4169     // bind with a document because shadow roots and its descendants
4170     // are not in document.
4171     nsIDocument* bindDocument =
4172         aParent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
4173     rv = content->BindToTree(bindDocument, aParent, aParent, true);
4174     // If the anonymous content creator requested that the content should be
4175     // editable, honor its request.
4176     // We need to set the flag on the whole subtree, because existing
4177     // children's flags have already been set as part of the BindToTree
4178     // operation.
4179     if (anonContentIsEditable) {
4180       NS_ASSERTION(aParentFrame->IsTextInputFrame(),
4181                    "We only expect this for anonymous content under a text "
4182                    "control frame");
4183       SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
4184     }
4185     if (NS_FAILED(rv)) {
4186       content->UnbindFromTree();
4187       return rv;
4188     }
4189   }
4190 
4191   if (ServoStyleSet* styleSet = mPresShell->StyleSet()->GetAsServo()) {
4192     // Eagerly compute styles for the anonymous content tree.
4193     for (auto& info : aContent) {
4194       if (info.mContent->IsElement()) {
4195         styleSet->StyleNewSubtree(info.mContent->AsElement());
4196       }
4197     }
4198   }
4199 
4200   return NS_OK;
4201 }
4202 
IsXULDisplayType(const nsStyleDisplay * aDisplay)4203 static bool IsXULDisplayType(const nsStyleDisplay* aDisplay) {
4204   // -moz-{inline-}box is XUL, unless we're emulating it with flexbox.
4205   if (!StylePrefs::sEmulateMozBoxWithFlex &&
4206       (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
4207        aDisplay->mDisplay == StyleDisplay::MozBox)) {
4208     return true;
4209   }
4210 
4211 #ifdef MOZ_XUL
4212   return (aDisplay->mDisplay == StyleDisplay::MozInlineGrid ||
4213           aDisplay->mDisplay == StyleDisplay::MozInlineStack ||
4214           aDisplay->mDisplay == StyleDisplay::MozGrid ||
4215           aDisplay->mDisplay == StyleDisplay::MozStack ||
4216           aDisplay->mDisplay == StyleDisplay::MozGridGroup ||
4217           aDisplay->mDisplay == StyleDisplay::MozGridLine ||
4218           aDisplay->mDisplay == StyleDisplay::MozDeck ||
4219           aDisplay->mDisplay == StyleDisplay::MozPopup ||
4220           aDisplay->mDisplay == StyleDisplay::MozGroupbox);
4221 #else
4222   return false;
4223 #endif
4224 }
4225 
4226 // XUL frames are not allowed to be out of flow.
4227 #define SIMPLE_XUL_FCDATA(_func) \
4228   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, _func)
4229 #define SCROLLABLE_XUL_FCDATA(_func)                                  \
4230   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
4231                   FCDATA_MAY_NEED_SCROLLFRAME,                        \
4232               _func)
4233 // .. but we allow some XUL frames to be _containers_ for out-of-flow content
4234 // (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
4235 #define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) \
4236   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_MAY_NEED_SCROLLFRAME, _func)
4237 
4238 #define SIMPLE_XUL_CREATE(_tag, _func) \
4239   { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
4240 #define SCROLLABLE_XUL_CREATE(_tag, _func) \
4241   { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
4242 #define SIMPLE_XUL_DISPLAY_CREATE(_display, _func) \
4243   FCDATA_FOR_DISPLAY(_display, SIMPLE_XUL_FCDATA(_func))
4244 #define SCROLLABLE_XUL_DISPLAY_CREATE(_display, _func) \
4245   FCDATA_FOR_DISPLAY(_display, SCROLLABLE_XUL_FCDATA(_func))
4246 #define SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(_display, _func) \
4247   FCDATA_FOR_DISPLAY(_display, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func))
4248 
NS_NewGridBoxFrame(nsIPresShell * aPresShell,nsStyleContext * aStyleContext)4249 static nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
4250                                     nsStyleContext* aStyleContext) {
4251   nsCOMPtr<nsBoxLayout> layout;
4252   NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
4253   return NS_NewBoxFrame(aPresShell, aStyleContext, false, layout);
4254 }
4255 
4256 /* static */
4257 const nsCSSFrameConstructor::FrameConstructionData*
FindXULTagData(Element * aElement,nsAtom * aTag,int32_t aNameSpaceID,nsStyleContext * aStyleContext)4258 nsCSSFrameConstructor::FindXULTagData(Element* aElement, nsAtom* aTag,
4259                                       int32_t aNameSpaceID,
4260                                       nsStyleContext* aStyleContext) {
4261   if (aNameSpaceID != kNameSpaceID_XUL) {
4262     return nullptr;
4263   }
4264 
4265   static const FrameConstructionDataByTag sXULTagData[] = {
4266 #ifdef MOZ_XUL
4267       SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
4268       SCROLLABLE_XUL_CREATE(thumb, NS_NewButtonBoxFrame),
4269       SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
4270       SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
4271       SCROLLABLE_XUL_CREATE(autorepeatbutton, NS_NewAutoRepeatBoxFrame),
4272       SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
4273       SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
4274       SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
4275       SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
4276       SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
4277       SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
4278       SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
4279       SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
4280       SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
4281       SIMPLE_TAG_CHAIN(description,
4282                        nsCSSFrameConstructor::FindXULDescriptionData),
4283       SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
4284       SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
4285       SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
4286 #ifdef XP_MACOSX
4287       SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
4288 #else
4289       SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
4290 #endif /* XP_MACOSX */
4291       SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData),
4292       SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
4293       SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
4294       SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame),
4295       SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame),
4296       SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame),
4297       SIMPLE_TAG_CHAIN(listboxbody,
4298                        nsCSSFrameConstructor::FindXULListBoxBodyData),
4299       SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData),
4300 #endif /* MOZ_XUL */
4301       SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
4302       SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
4303       SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)};
4304 
4305   bool tagFound;
4306   const FrameConstructionData* data =
4307       FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
4308                     ArrayLength(sXULTagData), &tagFound);
4309 
4310   // There's no spec that says what display: contents means for special XUL
4311   // elements, but we do the same as for HTML "Unusual Elements", i.e. treat it
4312   // as display:none.
4313   if (tagFound && MOZ_UNLIKELY(aStyleContext->StyleDisplay()->mDisplay ==
4314                                StyleDisplay::Contents)) {
4315     static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4316     return &sSuppressData;
4317   }
4318 
4319   return data;
4320 }
4321 
4322 #ifdef MOZ_XUL
4323 /* static */
4324 const nsCSSFrameConstructor::FrameConstructionData*
FindPopupGroupData(Element * aElement,nsStyleContext *)4325 nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
4326                                           nsStyleContext* /* unused */) {
4327   if (!aElement->IsRootOfNativeAnonymousSubtree()) {
4328     return nullptr;
4329   }
4330 
4331   static const FrameConstructionData sPopupSetData =
4332       SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
4333   return &sPopupSetData;
4334 }
4335 
4336 /* static */
4337 const nsCSSFrameConstructor::FrameConstructionData
4338     nsCSSFrameConstructor::sXULTextBoxData =
4339         SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
4340 
4341 /* static */
4342 const nsCSSFrameConstructor::FrameConstructionData*
FindXULLabelData(Element * aElement,nsStyleContext *)4343 nsCSSFrameConstructor::FindXULLabelData(Element* aElement,
4344                                         nsStyleContext* /* unused */) {
4345   if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4346     return &sXULTextBoxData;
4347   }
4348 
4349   static const FrameConstructionData sLabelData =
4350       SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
4351   return &sLabelData;
4352 }
4353 
NS_NewXULDescriptionFrame(nsIPresShell * aPresShell,nsStyleContext * aContext)4354 static nsIFrame* NS_NewXULDescriptionFrame(nsIPresShell* aPresShell,
4355                                            nsStyleContext* aContext) {
4356   // XXXbz do we really need to set up the block formatting context root? If the
4357   // parent is not a block we'll get it anyway, and if it is, do we want it?
4358   return NS_NewBlockFormattingContext(aPresShell, aContext);
4359 }
4360 
4361 /* static */
4362 const nsCSSFrameConstructor::FrameConstructionData*
FindXULDescriptionData(Element * aElement,nsStyleContext *)4363 nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement,
4364                                               nsStyleContext* /* unused */) {
4365   if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4366     return &sXULTextBoxData;
4367   }
4368 
4369   static const FrameConstructionData sDescriptionData =
4370       SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame);
4371   return &sDescriptionData;
4372 }
4373 
4374 #ifdef XP_MACOSX
4375 /* static */
4376 const nsCSSFrameConstructor::FrameConstructionData*
FindXULMenubarData(Element * aElement,nsStyleContext * aStyleContext)4377 nsCSSFrameConstructor::FindXULMenubarData(Element* aElement,
4378                                           nsStyleContext* aStyleContext) {
4379   nsCOMPtr<nsIDocShell> treeItem = aStyleContext->PresContext()->GetDocShell();
4380   if (treeItem && nsIDocShellTreeItem::typeChrome == treeItem->ItemType()) {
4381     nsCOMPtr<nsIDocShellTreeItem> parent;
4382     treeItem->GetParent(getter_AddRefs(parent));
4383     if (!parent) {
4384       // This is the root.  Suppress the menubar, since on Mac
4385       // window menus are not attached to the window.
4386       static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4387       return &sSuppressData;
4388     }
4389   }
4390 
4391   static const FrameConstructionData sMenubarData =
4392       SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
4393   return &sMenubarData;
4394 }
4395 #endif /* XP_MACOSX */
4396 
4397 /* static */
4398 const nsCSSFrameConstructor::FrameConstructionData*
FindXULListBoxBodyData(Element * aElement,nsStyleContext * aStyleContext)4399 nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
4400                                               nsStyleContext* aStyleContext) {
4401   if (aStyleContext->StyleDisplay()->mDisplay != StyleDisplay::MozGridGroup) {
4402     return nullptr;
4403   }
4404 
4405   static const FrameConstructionData sListBoxBodyData =
4406       SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame);
4407   return &sListBoxBodyData;
4408 }
4409 
4410 /* static */
4411 const nsCSSFrameConstructor::FrameConstructionData*
FindXULListItemData(Element * aElement,nsStyleContext * aStyleContext)4412 nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
4413                                            nsStyleContext* aStyleContext) {
4414   if (aStyleContext->StyleDisplay()->mDisplay != StyleDisplay::MozGridLine) {
4415     return nullptr;
4416   }
4417 
4418   static const FrameConstructionData sListItemData =
4419       SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame);
4420   return &sListItemData;
4421 }
4422 
4423 #endif /* MOZ_XUL */
4424 
4425 /* static */
4426 const nsCSSFrameConstructor::FrameConstructionData*
FindXULDisplayData(const nsStyleDisplay * aDisplay,Element * aElement,nsStyleContext * aStyleContext)4427 nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
4428                                           Element* aElement,
4429                                           nsStyleContext* aStyleContext) {
4430   static const FrameConstructionDataByDisplay sXULDisplayData[] = {
4431       SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozBox,
4432                                                      NS_NewBoxFrame),
4433       SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineBox,
4434                                                      NS_NewBoxFrame),
4435 #ifdef MOZ_XUL
4436       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGrid, NS_NewGridBoxFrame),
4437       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineGrid,
4438                                     NS_NewGridBoxFrame),
4439       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridGroup,
4440                                     NS_NewGridRowGroupFrame),
4441       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridLine,
4442                                     NS_NewGridRowLeafFrame),
4443       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozStack, NS_NewStackFrame),
4444       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineStack,
4445                                     NS_NewStackFrame),
4446       SIMPLE_XUL_DISPLAY_CREATE(StyleDisplay::MozDeck, NS_NewDeckFrame),
4447       SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGroupbox,
4448                                     NS_NewGroupBoxFrame),
4449       FCDATA_FOR_DISPLAY(
4450           StyleDisplay::MozPopup,
4451           FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
4452                           FCDATA_SKIP_ABSPOS_PUSH,
4453                       NS_NewMenuPopupFrame))
4454 #endif /* MOZ_XUL */
4455   };
4456 
4457   if (aDisplay->mDisplay < StyleDisplay::MozBox) {
4458     return nullptr;
4459   }
4460 
4461   // If we're emulating -moz-box with flexbox, then treat it as non-XUL and
4462   // return null (except for scrollcorners which have to be XUL becuase their
4463   // parent reflows them with BoxReflow() which means they have to get
4464   // actual-XUL frames).
4465   if (StylePrefs::sEmulateMozBoxWithFlex && aElement &&
4466       !aElement->IsXULElement(nsGkAtoms::scrollcorner) &&
4467       (aDisplay->mDisplay == StyleDisplay::MozBox ||
4468        aDisplay->mDisplay == StyleDisplay::MozInlineBox)) {
4469     return nullptr;
4470   }
4471 
4472   MOZ_ASSERT(aDisplay->mDisplay <= StyleDisplay::MozPopup,
4473              "Someone added a new display value?");
4474 
4475   const FrameConstructionDataByDisplay& data =
4476       sXULDisplayData[size_t(aDisplay->mDisplay) -
4477                       size_t(StyleDisplay::MozBox)];
4478   MOZ_ASSERT(aDisplay->mDisplay == data.mDisplay,
4479              "Did someone mess with the order?");
4480 
4481   return &data.mData;
4482 }
4483 
4484 already_AddRefed<nsStyleContext>
BeginBuildingScrollFrame(nsFrameConstructorState & aState,nsIContent * aContent,nsStyleContext * aContentStyle,nsContainerFrame * aParentFrame,nsAtom * aScrolledPseudo,bool aIsRoot,nsContainerFrame * & aNewFrame)4485 nsCSSFrameConstructor::BeginBuildingScrollFrame(
4486     nsFrameConstructorState& aState, nsIContent* aContent,
4487     nsStyleContext* aContentStyle, nsContainerFrame* aParentFrame,
4488     nsAtom* aScrolledPseudo, bool aIsRoot, nsContainerFrame*& aNewFrame) {
4489   nsContainerFrame* gfxScrollFrame = aNewFrame;
4490 
4491   nsFrameItems anonymousItems;
4492 
4493   RefPtr<nsStyleContext> contentStyle = aContentStyle;
4494 
4495   if (!gfxScrollFrame) {
4496     // Build a XULScrollFrame when the child is a box, otherwise an
4497     // HTMLScrollFrame
4498     // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4499     // I wonder whether we can eliminate that somehow.
4500     const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay();
4501     if (IsXULDisplayType(displayStyle)) {
4502       gfxScrollFrame = NS_NewXULScrollFrame(
4503           mPresShell, contentStyle, aIsRoot,
4504           displayStyle->mDisplay == StyleDisplay::MozStack ||
4505               displayStyle->mDisplay == StyleDisplay::MozInlineStack);
4506     } else {
4507       gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
4508     }
4509 
4510     InitAndRestoreFrame(aState, aContent, aParentFrame, gfxScrollFrame);
4511   }
4512 
4513   // if there are any anonymous children for the scroll frame, create
4514   // frames for them.
4515   //
4516   // We can't take the normal ProcessChildren path, because the NAC needs to
4517   // be parented to the scrollframe, and everything else needs to be parented
4518   // to the scrolledframe.
4519   AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4520   DebugOnly<nsresult> rv =
4521       GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC);
4522   MOZ_ASSERT(NS_SUCCEEDED(rv));
4523   if (scrollNAC.Length() > 0) {
4524     TreeMatchContext::AutoAncestorPusher ancestorPusher(
4525         aState.mTreeMatchContext);
4526     if (aState.HasAncestorFilter()) {
4527       ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
4528     } else {
4529       ancestorPusher.PushStyleScope(aContent->AsElement());
4530     }
4531 
4532     AutoFrameConstructionItemList items(this);
4533     AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
4534     ConstructFramesFromItemList(aState, items, gfxScrollFrame,
4535                                 /* aParentIsWrapperAnonBox = */ false,
4536                                 anonymousItems);
4537   }
4538 
4539   aNewFrame = gfxScrollFrame;
4540   gfxScrollFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4541 
4542   // we used the style that was passed in. So resolve another one.
4543   StyleSetHandle styleSet = mPresShell->StyleSet();
4544   RefPtr<nsStyleContext> scrolledChildStyle =
4545       styleSet->ResolveInheritingAnonymousBoxStyle(aScrolledPseudo,
4546                                                    contentStyle);
4547 
4548   if (gfxScrollFrame) {
4549     gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems);
4550   }
4551 
4552   return scrolledChildStyle.forget();
4553 }
4554 
FinishBuildingScrollFrame(nsContainerFrame * aScrollFrame,nsIFrame * aScrolledFrame)4555 void nsCSSFrameConstructor::FinishBuildingScrollFrame(
4556     nsContainerFrame* aScrollFrame, nsIFrame* aScrolledFrame) {
4557   nsFrameList scrolled(aScrolledFrame, aScrolledFrame);
4558   aScrollFrame->AppendFrames(kPrincipalList, scrolled);
4559 }
4560 
4561 /**
4562  * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like
4563  *this
4564  *
4565  * ------- for gfx scrollbars ------
4566  *
4567  *
4568  *            ScrollFrame
4569  *                 ^
4570  *                 |
4571  *               Frame (scrolled frame you passed in)
4572  *
4573  *
4574  *-----------------------------------
4575  * LEGEND:
4576  *
4577  * ScrollFrame: This is a frame that manages gfx cross platform frame based
4578  *scrollbars.
4579  *
4580  * @param aContent the content node of the child to wrap.
4581  * @param aScrolledFrame The frame of the content to wrap. This should not be
4582  *                    Initialized. This method will initialize it with a
4583  *scrolled pseudo and no nsIContent. The content will be attached to the
4584  *scrollframe returned.
4585  * @param aContentStyle the style context that has already been resolved for the
4586  *content being passed in.
4587  *
4588  * @param aParentFrame The parent to attach the scroll frame to
4589  *
4590  * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It
4591  *will contain the scrolled frame you passed in. (returned) If this is not null,
4592  *we'll just use it
4593  * @param aScrolledContentStyle the style that was resolved for the scrolled
4594  *frame. (returned)
4595  */
BuildScrollFrame(nsFrameConstructorState & aState,nsIContent * aContent,nsStyleContext * aContentStyle,nsIFrame * aScrolledFrame,nsContainerFrame * aParentFrame,nsContainerFrame * & aNewFrame)4596 void nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
4597                                              nsIContent* aContent,
4598                                              nsStyleContext* aContentStyle,
4599                                              nsIFrame* aScrolledFrame,
4600                                              nsContainerFrame* aParentFrame,
4601                                              nsContainerFrame*& aNewFrame) {
4602   RefPtr<nsStyleContext> scrolledContentStyle = BeginBuildingScrollFrame(
4603       aState, aContent, aContentStyle, aParentFrame,
4604       nsCSSAnonBoxes::scrolledContent, false, aNewFrame);
4605 
4606   aScrolledFrame->SetStyleContextWithoutNotification(scrolledContentStyle);
4607   InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4608 
4609   FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
4610 }
4611 
4612 const nsCSSFrameConstructor::FrameConstructionData*
FindDisplayData(const nsStyleDisplay * aDisplay,Element * aElement,nsStyleContext * aStyleContext)4613 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
4614                                        Element* aElement,
4615                                        nsStyleContext* aStyleContext) {
4616   static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)),
4617                 "Check eParentTypeCount should not overflow");
4618 
4619   // The style system ensures that floated and positioned frames are
4620   // block-level.
4621   NS_ASSERTION(!(aDisplay->IsFloatingStyle() ||
4622                  aDisplay->IsAbsolutelyPositionedStyle()) ||
4623                    aDisplay->IsBlockOutsideStyle() ||
4624                    aDisplay->mDisplay == StyleDisplay::Contents,
4625                "Style system did not apply CSS2.1 section 9.7 fixups");
4626 
4627   // If this is "body", try propagating its scroll style to the viewport
4628   // Note that we need to do this even if the body is NOT scrollable;
4629   // it might have dynamically changed from scrollable to not scrollable,
4630   // and that might need to be propagated.
4631   // XXXbz is this the right place to do this?  If this code moves,
4632   // make this function static.
4633   bool propagatedScrollToViewport = false;
4634   if (aElement->IsHTMLElement(nsGkAtoms::body)) {
4635     if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4636       propagatedScrollToViewport =
4637           presContext->UpdateViewportScrollbarStylesOverride() == aElement;
4638     }
4639   }
4640 
4641   NS_ASSERTION(!propagatedScrollToViewport ||
4642                    !mPresShell->GetPresContext()->IsPaginated(),
4643                "Shouldn't propagate scroll in paginated contexts");
4644 
4645   if (aDisplay->IsBlockInsideStyle()) {
4646     // If the frame is a block-level frame and is scrollable, then wrap it in a
4647     // scroll frame.  Except we don't want to do that for paginated contexts for
4648     // frames that are block-outside and aren't frames for native anonymous
4649     // stuff.
4650     // XXX Ignore tables for the time being (except caption)
4651     const uint32_t kCaptionCtorFlags =
4652         FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable);
4653     bool caption = aDisplay->mDisplay == StyleDisplay::TableCaption;
4654     bool suppressScrollFrame = false;
4655     bool needScrollFrame =
4656         aDisplay->IsScrollableOverflow() && !propagatedScrollToViewport;
4657     if (needScrollFrame) {
4658       suppressScrollFrame = mPresShell->GetPresContext()->IsPaginated() &&
4659                             aDisplay->IsBlockOutsideStyle() &&
4660                             !aElement->IsInNativeAnonymousSubtree();
4661       if (!suppressScrollFrame) {
4662         static const FrameConstructionData sScrollableBlockData[2] = {
4663             FULL_CTOR_FCDATA(0,
4664                              &nsCSSFrameConstructor::ConstructScrollableBlock),
4665             FULL_CTOR_FCDATA(kCaptionCtorFlags,
4666                              &nsCSSFrameConstructor::ConstructScrollableBlock)};
4667         return &sScrollableBlockData[caption];
4668       }
4669 
4670       // If the scrollable frame would have propagated its scrolling to the
4671       // viewport, we still want to construct a regular block rather than a
4672       // scrollframe so that it paginates correctly, but we don't want to set
4673       // the bit on the block that tells it to clip at paint time.
4674       if (mPresShell->GetPresContext()->ElementWouldPropagateScrollbarStyles(
4675               aElement)) {
4676         suppressScrollFrame = false;
4677       }
4678     }
4679 
4680     // Handle various non-scrollable blocks.
4681     static const FrameConstructionData sNonScrollableBlockData[2][2] = {
4682         {FULL_CTOR_FCDATA(0,
4683                           &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4684          FULL_CTOR_FCDATA(kCaptionCtorFlags,
4685                           &nsCSSFrameConstructor::ConstructNonScrollableBlock)},
4686         {FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
4687                           &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4688          FULL_CTOR_FCDATA(
4689              FCDATA_FORCED_NON_SCROLLABLE_BLOCK | kCaptionCtorFlags,
4690              &nsCSSFrameConstructor::ConstructNonScrollableBlock)}};
4691     return &sNonScrollableBlockData[suppressScrollFrame][caption];
4692   }
4693 
4694   // If this is for a <body> node and we've propagated the scroll-frame to the
4695   // viewport, we need to make sure not to add another layer of scrollbars, so
4696   // we use a different FCData struct without FCDATA_MAY_NEED_SCROLLFRAME.
4697   if (propagatedScrollToViewport && aDisplay->IsScrollableOverflow()) {
4698     if (aDisplay->mDisplay == StyleDisplay::Flex ||
4699         aDisplay->mDisplay == StyleDisplay::WebkitBox ||
4700         (StylePrefs::sEmulateMozBoxWithFlex &&
4701          aDisplay->mDisplay == StyleDisplay::MozBox)) {
4702       static const FrameConstructionData sNonScrollableFlexData =
4703           FCDATA_DECL(0, NS_NewFlexContainerFrame);
4704       return &sNonScrollableFlexData;
4705     }
4706     if (aDisplay->mDisplay == StyleDisplay::Grid) {
4707       static const FrameConstructionData sNonScrollableGridData =
4708           FCDATA_DECL(0, NS_NewGridContainerFrame);
4709       return &sNonScrollableGridData;
4710     }
4711   }
4712 
4713   // NOTE: Make sure to keep this up to date with the StyleDisplay definition!
4714   static const FrameConstructionDataByDisplay sDisplayData[] = {
4715       FCDATA_FOR_DISPLAY(StyleDisplay::None, UNREACHABLE_FCDATA()),
4716       FCDATA_FOR_DISPLAY(StyleDisplay::Block, UNREACHABLE_FCDATA()),
4717       FCDATA_FOR_DISPLAY(StyleDisplay::FlowRoot, UNREACHABLE_FCDATA()),
4718       // To keep the hash table small don't add inline frames (they're
4719       // typically things like FONT and B), because we can quickly
4720       // find them if we need to.
4721       // XXXbz the "quickly" part is a bald-faced lie!
4722       FCDATA_FOR_DISPLAY(
4723           StyleDisplay::Inline,
4724           FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
4725                            &nsCSSFrameConstructor::ConstructInline)),
4726       FCDATA_FOR_DISPLAY(StyleDisplay::InlineBlock, UNREACHABLE_FCDATA()),
4727       FCDATA_FOR_DISPLAY(StyleDisplay::ListItem, UNREACHABLE_FCDATA()),
4728       FCDATA_FOR_DISPLAY(
4729           StyleDisplay::Table,
4730           FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4731       FCDATA_FOR_DISPLAY(
4732           StyleDisplay::InlineTable,
4733           FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4734       // NOTE: In the unlikely event that we add another table-part here that
4735       // has a desired-parent-type (& hence triggers table fixup), we'll need to
4736       // also update the flexbox chunk in nsStyleContext::ApplyStyleFixups().
4737       FCDATA_FOR_DISPLAY(
4738           StyleDisplay::TableRowGroup,
4739           FULL_CTOR_FCDATA(
4740               FCDATA_IS_TABLE_PART |
4741                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4742               &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4743       FCDATA_FOR_DISPLAY(
4744           StyleDisplay::TableColumn,
4745           FULL_CTOR_FCDATA(
4746               FCDATA_IS_TABLE_PART |
4747                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup),
4748               &nsCSSFrameConstructor::ConstructTableCol)),
4749       FCDATA_FOR_DISPLAY(
4750           StyleDisplay::TableColumnGroup,
4751           FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4752                           FCDATA_SKIP_ABSPOS_PUSH |
4753                           FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4754                       NS_NewTableColGroupFrame)),
4755       FCDATA_FOR_DISPLAY(
4756           StyleDisplay::TableHeaderGroup,
4757           FULL_CTOR_FCDATA(
4758               FCDATA_IS_TABLE_PART |
4759                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4760               &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4761       FCDATA_FOR_DISPLAY(
4762           StyleDisplay::TableFooterGroup,
4763           FULL_CTOR_FCDATA(
4764               FCDATA_IS_TABLE_PART |
4765                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4766               &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4767       FCDATA_FOR_DISPLAY(
4768           StyleDisplay::TableRow,
4769           FULL_CTOR_FCDATA(
4770               FCDATA_IS_TABLE_PART |
4771                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
4772               &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4773       FCDATA_FOR_DISPLAY(
4774           StyleDisplay::TableCell,
4775           FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4776                                FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
4777                            &nsCSSFrameConstructor::ConstructTableCell)),
4778       FCDATA_FOR_DISPLAY(StyleDisplay::TableCaption, UNREACHABLE_FCDATA()),
4779       FCDATA_FOR_DISPLAY(
4780           StyleDisplay::Flex,
4781           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4782       FCDATA_FOR_DISPLAY(
4783           StyleDisplay::InlineFlex,
4784           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4785       FCDATA_FOR_DISPLAY(
4786           StyleDisplay::Grid,
4787           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4788       FCDATA_FOR_DISPLAY(
4789           StyleDisplay::InlineGrid,
4790           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4791       FCDATA_FOR_DISPLAY(
4792           StyleDisplay::Ruby,
4793           FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewRubyFrame)),
4794       FCDATA_FOR_DISPLAY(StyleDisplay::RubyBase,
4795                          FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4796                                          FCDATA_DESIRED_PARENT_TYPE_TO_BITS(
4797                                              eTypeRubyBaseContainer),
4798                                      NS_NewRubyBaseFrame)),
4799       FCDATA_FOR_DISPLAY(
4800           StyleDisplay::RubyBaseContainer,
4801           FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4802                           FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4803                       NS_NewRubyBaseContainerFrame)),
4804       FCDATA_FOR_DISPLAY(StyleDisplay::RubyText,
4805                          FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4806                                          FCDATA_DESIRED_PARENT_TYPE_TO_BITS(
4807                                              eTypeRubyTextContainer),
4808                                      NS_NewRubyTextFrame)),
4809       FCDATA_FOR_DISPLAY(
4810           StyleDisplay::RubyTextContainer,
4811           FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4812                       NS_NewRubyTextContainerFrame)),
4813       FCDATA_FOR_DISPLAY(StyleDisplay::Contents, UNREACHABLE_FCDATA()),
4814       FCDATA_FOR_DISPLAY(
4815           StyleDisplay::WebkitBox,
4816           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4817       FCDATA_FOR_DISPLAY(
4818           StyleDisplay::WebkitInlineBox,
4819           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4820       FCDATA_FOR_DISPLAY(
4821           StyleDisplay::MozBox,
4822           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4823       FCDATA_FOR_DISPLAY(
4824           StyleDisplay::MozInlineBox,
4825           FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4826   };
4827   static_assert(
4828       ArrayLength(sDisplayData) == size_t(StyleDisplay::MozInlineBox) + 1,
4829       "Be sure to update sDisplayData if you touch StyleDisplay");
4830   MOZ_ASSERT(StylePrefs::sEmulateMozBoxWithFlex ||
4831                  (aDisplay->mDisplay != StyleDisplay::MozBox &&
4832                   aDisplay->mDisplay != StyleDisplay::MozInlineBox),
4833              "-moz-{inline-}box as XUL should have already been handled");
4834   MOZ_ASSERT(size_t(aDisplay->mDisplay) < ArrayLength(sDisplayData),
4835              "XUL display data should have already been handled");
4836 
4837   // See the mDisplay fixup code in nsRuleNode::ComputeDisplayData.
4838   MOZ_ASSERT(aDisplay->mDisplay != StyleDisplay::Contents ||
4839                  !aElement->IsRootOfNativeAnonymousSubtree(),
4840              "display:contents on anonymous content is unsupported");
4841 
4842   const FrameConstructionDataByDisplay& data =
4843       sDisplayData[size_t(aDisplay->mDisplay)];
4844 
4845   MOZ_ASSERT(data.mDisplay == aDisplay->mDisplay,
4846              "Someone messed up the order in the display values");
4847 
4848   return &data.mData;
4849 }
4850 
ConstructScrollableBlock(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)4851 nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
4852     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4853     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4854     nsFrameItems& aFrameItems) {
4855   return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
4856                                                  aDisplay, aFrameItems,
4857                                                  NS_NewBlockFormattingContext);
4858 }
4859 
ConstructScrollableBlockWithConstructor(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems,BlockFrameCreationFunc aConstructor)4860 nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlockWithConstructor(
4861     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4862     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4863     nsFrameItems& aFrameItems, BlockFrameCreationFunc aConstructor) {
4864   nsIContent* const content = aItem.mContent;
4865   nsStyleContext* const styleContext = aItem.mStyleContext;
4866 
4867   nsContainerFrame* newFrame = nullptr;
4868   RefPtr<nsStyleContext> scrolledContentStyle = BeginBuildingScrollFrame(
4869       aState, content, styleContext,
4870       aState.GetGeometricParent(aDisplay, aParentFrame),
4871       nsCSSAnonBoxes::scrolledContent, false, newFrame);
4872 
4873   // Create our block frame
4874   // pass a temporary stylecontext, the correct one will be set later
4875   nsContainerFrame* scrolledFrame = aConstructor(mPresShell, styleContext);
4876 
4877   // Make sure to AddChild before we call ConstructBlock so that we
4878   // end up before our descendants in fixed-pos lists as needed.
4879   aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
4880 
4881   nsFrameItems blockItem;
4882   ConstructBlock(
4883       aState, content, newFrame, newFrame, scrolledContentStyle, &scrolledFrame,
4884       blockItem,
4885       aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
4886       aItem.mPendingBinding);
4887 
4888   MOZ_ASSERT(blockItem.OnlyChild() == scrolledFrame,
4889              "Scrollframe's frameItems should be exactly the scrolled frame!");
4890   FinishBuildingScrollFrame(newFrame, scrolledFrame);
4891 
4892   return newFrame;
4893 }
4894 
ConstructNonScrollableBlock(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)4895 nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
4896     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4897     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4898     nsFrameItems& aFrameItems) {
4899   return ConstructNonScrollableBlockWithConstructor(
4900       aState, aItem, aParentFrame, aDisplay, aFrameItems, NS_NewBlockFrame);
4901 }
4902 
ConstructNonScrollableBlockWithConstructor(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems,BlockFrameCreationFunc aConstructor)4903 nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlockWithConstructor(
4904     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4905     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4906     nsFrameItems& aFrameItems, BlockFrameCreationFunc aConstructor) {
4907   nsStyleContext* const styleContext = aItem.mStyleContext;
4908 
4909   // We want a block formatting context root in paginated contexts for
4910   // every block that would be scrollable in a non-paginated context.
4911   // We mark our blocks with a bit here if this condition is true, so
4912   // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
4913   bool clipPaginatedOverflow =
4914       (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
4915   nsFrameState flags = nsFrameState(0);
4916   if ((aDisplay->IsAbsolutelyPositionedStyle() || aDisplay->IsFloatingStyle() ||
4917        StyleDisplay::InlineBlock == aDisplay->mDisplay ||
4918        clipPaginatedOverflow) &&
4919       !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
4920     flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS;
4921     if (clipPaginatedOverflow) {
4922       flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
4923     }
4924   }
4925 
4926   nsContainerFrame* newFrame = aConstructor(mPresShell, styleContext);
4927   newFrame->AddStateBits(flags);
4928   ConstructBlock(
4929       aState, aItem.mContent, aState.GetGeometricParent(aDisplay, aParentFrame),
4930       aParentFrame, styleContext, &newFrame, aFrameItems,
4931       aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
4932       aItem.mPendingBinding);
4933   return newFrame;
4934 }
4935 
InitAndRestoreFrame(const nsFrameConstructorState & aState,nsIContent * aContent,nsContainerFrame * aParentFrame,nsIFrame * aNewFrame,bool aAllowCounters)4936 void nsCSSFrameConstructor::InitAndRestoreFrame(
4937     const nsFrameConstructorState& aState, nsIContent* aContent,
4938     nsContainerFrame* aParentFrame, nsIFrame* aNewFrame, bool aAllowCounters) {
4939   MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized");
4940 
4941   // Initialize the frame
4942   aNewFrame->Init(aContent, aParentFrame, nullptr);
4943   aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4944 
4945   if (aState.mFrameState) {
4946     // Restore frame state for just the newly created frame.
4947     RestoreFrameStateFor(aNewFrame, aState.mFrameState);
4948   }
4949 
4950   if (aAllowCounters &&
4951       mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
4952     CountersDirty();
4953   }
4954 }
4955 
ResolveStyleContext(nsIFrame * aParentFrame,nsIContent * aContainer,nsIContent * aChild,nsFrameConstructorState * aState)4956 already_AddRefed<nsStyleContext> nsCSSFrameConstructor::ResolveStyleContext(
4957     nsIFrame* aParentFrame, nsIContent* aContainer, nsIContent* aChild,
4958     nsFrameConstructorState* aState) {
4959   MOZ_ASSERT(aContainer, "Must have parent here");
4960   // XXX uncomment when bug 1089223 is fixed:
4961   // MOZ_ASSERT(aContainer == aChild->GetFlattenedTreeParent());
4962   nsStyleContext* parentStyleContext = GetDisplayContentsStyleFor(aContainer);
4963   if (MOZ_LIKELY(!parentStyleContext)) {
4964     aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nullptr);
4965     if (aParentFrame) {
4966       MOZ_ASSERT(aParentFrame->GetContent() == aContainer);
4967       // Resolve the style context based on the content object and the parent
4968       // style context
4969       parentStyleContext = aParentFrame->StyleContext();
4970     } else {
4971       // Perhaps aParentFrame is a canvasFrame and we're replicating
4972       // fixed-pos frames.
4973       // XXX should we create a way to tell ConstructFrame which style
4974       // context to use, and pass it the style context for the
4975       // previous page's fixed-pos frame?
4976     }
4977   }
4978 
4979   return ResolveStyleContext(parentStyleContext, aChild, aState);
4980 }
4981 
ResolveStyleContext(nsIFrame * aParentFrame,nsIContent * aChild,nsFrameConstructorState * aState)4982 already_AddRefed<nsStyleContext> nsCSSFrameConstructor::ResolveStyleContext(
4983     nsIFrame* aParentFrame, nsIContent* aChild,
4984     nsFrameConstructorState* aState) {
4985   return ResolveStyleContext(aParentFrame, aChild->GetFlattenedTreeParent(),
4986                              aChild, aState);
4987 }
4988 
ResolveStyleContext(const InsertionPoint & aInsertion,nsIContent * aChild,nsFrameConstructorState * aState)4989 already_AddRefed<nsStyleContext> nsCSSFrameConstructor::ResolveStyleContext(
4990     const InsertionPoint& aInsertion, nsIContent* aChild,
4991     nsFrameConstructorState* aState) {
4992   return ResolveStyleContext(aInsertion.mParentFrame, aInsertion.mContainer,
4993                              aChild, aState);
4994 }
4995 
ResolveStyleContext(nsStyleContext * aParentStyleContext,nsIContent * aContent,nsFrameConstructorState * aState,Element * aOriginatingElementOrNull)4996 already_AddRefed<nsStyleContext> nsCSSFrameConstructor::ResolveStyleContext(
4997     nsStyleContext* aParentStyleContext, nsIContent* aContent,
4998     nsFrameConstructorState* aState, Element* aOriginatingElementOrNull) {
4999   StyleSetHandle styleSet = mPresShell->StyleSet();
5000 
5001   RefPtr<nsStyleContext> result;
5002   if (aContent->IsElement()) {
5003     auto pseudoType = aContent->AsElement()->GetPseudoElementType();
5004     if (pseudoType == CSSPseudoElementType::NotPseudo) {
5005       MOZ_ASSERT(!aOriginatingElementOrNull);
5006       if (aState) {
5007         result = styleSet->ResolveStyleFor(
5008             aContent->AsElement(), aParentStyleContext,
5009             LazyComputeBehavior::Assert, aState->mTreeMatchContext);
5010       } else {
5011         result = styleSet->ResolveStyleFor(aContent->AsElement(),
5012                                            aParentStyleContext,
5013                                            LazyComputeBehavior::Assert);
5014       }
5015     } else {
5016       MOZ_ASSERT(aContent->IsInNativeAnonymousSubtree());
5017       if (!aOriginatingElementOrNull) {
5018         // For pseudo-implementing NAC created by JS using the ChromeOnly
5019         // document.createElement(..., { pseudo: ... }) API, we find the
5020         // originating element by lookup the tree until we find a non-NAC
5021         // ancestor.  (These are the correct semantics for C++-generated pseudo-
5022         // implementing NAC as well, but for those cases we already have a
5023         // correct originating element passed in.)
5024         MOZ_ASSERT(
5025             nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType));
5026         aOriginatingElementOrNull =
5027             nsContentUtils::GetClosestNonNativeAnonymousAncestor(
5028                 aContent->AsElement());
5029       }
5030       MOZ_ASSERT(aOriginatingElementOrNull);
5031       result = styleSet->ResolvePseudoElementStyle(
5032           aOriginatingElementOrNull, pseudoType, aParentStyleContext,
5033           aContent->AsElement());
5034     }
5035   } else {
5036     MOZ_ASSERT(!aOriginatingElementOrNull);
5037     NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
5038                  "shouldn't waste time creating style contexts for "
5039                  "comments and processing instructions");
5040     result = styleSet->ResolveStyleForText(aContent, aParentStyleContext);
5041   }
5042 
5043   // ServoRestyleManager does not handle transitions yet, and when it does
5044   // it probably won't need to track reframed style contexts to start
5045   // transitions correctly.
5046   if (RestyleManager()->IsGecko()) {
5047 #ifdef MOZ_OLD_STYLE
5048     mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->AsGecko();
5049     GeckoRestyleManager::ReframingStyleContexts* rsc =
5050         geckoRM->GetReframingStyleContexts();
5051     if (rsc) {
5052       GeckoStyleContext* oldStyleContext =
5053           rsc->Get(aContent, CSSPseudoElementType::NotPseudo);
5054       nsPresContext* presContext = mPresShell->GetPresContext();
5055       if (oldStyleContext) {
5056         RefPtr<GeckoStyleContext> newContext =
5057             GeckoStyleContext::TakeRef(result.forget());
5058         GeckoRestyleManager::TryInitiatingTransition(
5059             presContext, aContent, oldStyleContext, &newContext);
5060         result = newContext.forget();
5061       } else if (aContent->IsElement()) {
5062         presContext->TransitionManager()->PruneCompletedTransitions(
5063             aContent->AsElement(), CSSPseudoElementType::NotPseudo,
5064             result->AsGecko());
5065       }
5066     }
5067 #else
5068     MOZ_CRASH("old style system disabled");
5069 #endif
5070   }
5071 
5072   return result.forget();
5073 }
5074 
5075 // MathML Mod - RBS
FlushAccumulatedBlock(nsFrameConstructorState & aState,nsIContent * aContent,nsContainerFrame * aParentFrame,nsFrameItems & aBlockItems,nsFrameItems & aNewItems)5076 void nsCSSFrameConstructor::FlushAccumulatedBlock(
5077     nsFrameConstructorState& aState, nsIContent* aContent,
5078     nsContainerFrame* aParentFrame, nsFrameItems& aBlockItems,
5079     nsFrameItems& aNewItems) {
5080   if (aBlockItems.IsEmpty()) {
5081     // Nothing to do
5082     return;
5083   }
5084 
5085   nsAtom* anonPseudo = nsCSSAnonBoxes::mozMathMLAnonymousBlock;
5086 
5087   nsStyleContext* parentContext =
5088       nsFrame::CorrectStyleParentFrame(aParentFrame, anonPseudo)
5089           ->StyleContext();
5090   StyleSetHandle styleSet = mPresShell->StyleSet();
5091   RefPtr<nsStyleContext> blockContext;
5092   blockContext =
5093       styleSet->ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
5094 
5095   // then, create a block frame that will wrap the child frames. Make it a
5096   // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
5097   // is not a suitable block.
5098   nsContainerFrame* blockFrame =
5099       NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
5100 
5101   InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
5102   ReparentFrames(this, blockFrame, aBlockItems, false);
5103   // We have to walk over aBlockItems before we hand it over to blockFrame.
5104   for (nsIFrame* f : aBlockItems) {
5105     f->SetParentIsWrapperAnonBox();
5106   }
5107   // abs-pos and floats are disabled in MathML children so we don't have to
5108   // worry about messing up those.
5109   blockFrame->SetInitialChildList(kPrincipalList, aBlockItems);
5110   NS_ASSERTION(aBlockItems.IsEmpty(), "What happened?");
5111   aBlockItems.Clear();
5112   aNewItems.AddChild(blockFrame);
5113 }
5114 
5115 // Only <math> elements can be floated or positioned.  All other MathML
5116 // should be in-flow.
5117 #define SIMPLE_MATHML_CREATE(_tag, _func)                                  \
5118   {                                                                        \
5119     &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |            \
5120                                       FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
5121                                       FCDATA_WRAP_KIDS_IN_BLOCKS,          \
5122                                   _func)                                   \
5123   }
5124 
5125 /* static */
5126 const nsCSSFrameConstructor::FrameConstructionData*
FindMathMLData(Element * aElement,nsAtom * aTag,int32_t aNameSpaceID,nsStyleContext * aStyleContext)5127 nsCSSFrameConstructor::FindMathMLData(Element* aElement, nsAtom* aTag,
5128                                       int32_t aNameSpaceID,
5129                                       nsStyleContext* aStyleContext) {
5130   // Make sure that we remain confined in the MathML world
5131   if (aNameSpaceID != kNameSpaceID_MathML) return nullptr;
5132 
5133   // Handle <math> specially, because it sometimes produces inlines
5134   if (aTag == nsGkAtoms::math) {
5135     // This needs to match the test in EnsureBlockDisplay in
5136     // nsRuleNode.cpp.  Though the behavior here for the display:table
5137     // case is pretty weird...
5138     if (aStyleContext->StyleDisplay()->IsBlockOutsideStyle()) {
5139       static const FrameConstructionData sBlockMathData = FCDATA_DECL(
5140           FCDATA_FORCE_NULL_ABSPOS_CONTAINER | FCDATA_WRAP_KIDS_IN_BLOCKS,
5141           NS_NewMathMLmathBlockFrame);
5142       return &sBlockMathData;
5143     }
5144 
5145     static const FrameConstructionData sInlineMathData =
5146         FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
5147                         FCDATA_IS_LINE_PARTICIPANT | FCDATA_WRAP_KIDS_IN_BLOCKS,
5148                     NS_NewMathMLmathInlineFrame);
5149     return &sInlineMathData;
5150   }
5151 
5152   static const FrameConstructionDataByTag sMathMLData[] = {
5153       SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame),
5154       SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame),
5155       SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
5156       SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
5157       SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
5158       SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
5159       SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
5160       SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
5161       SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame),
5162       SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame),
5163       SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame),
5164       SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
5165       SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
5166       SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
5167       SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmrowFrame),
5168       SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
5169       SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
5170       SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
5171       SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
5172       SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame),
5173       SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame),
5174       SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmrowFrame),
5175       SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame),
5176       SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame),
5177       SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame),
5178       SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame),
5179       SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame),
5180       SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame),
5181       SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)};
5182 
5183   return FindDataByTag(aTag, aElement, aStyleContext, sMathMLData,
5184                        ArrayLength(sMathMLData));
5185 }
5186 
ConstructFrameWithAnonymousChild(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,nsFrameItems & aFrameItems,ContainerFrameCreationFunc aConstructor,ContainerFrameCreationFunc aInnerConstructor,nsICSSAnonBoxPseudo * aInnerPseudo,bool aCandidateRootFrame)5187 nsContainerFrame* nsCSSFrameConstructor::ConstructFrameWithAnonymousChild(
5188     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
5189     nsContainerFrame* aParentFrame, nsFrameItems& aFrameItems,
5190     ContainerFrameCreationFunc aConstructor,
5191     ContainerFrameCreationFunc aInnerConstructor,
5192     nsICSSAnonBoxPseudo* aInnerPseudo, bool aCandidateRootFrame) {
5193   nsIContent* const content = aItem.mContent;
5194   nsStyleContext* const styleContext = aItem.mStyleContext;
5195 
5196   // Create the outer frame:
5197   nsContainerFrame* newFrame = aConstructor(mPresShell, styleContext);
5198 
5199   InitAndRestoreFrame(aState, content,
5200                       aCandidateRootFrame
5201                           ? aState.GetGeometricParent(
5202                                 styleContext->StyleDisplay(), aParentFrame)
5203                           : aParentFrame,
5204                       newFrame);
5205   newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
5206 
5207   // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
5208   RefPtr<nsStyleContext> scForAnon;
5209   scForAnon = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
5210       aInnerPseudo, styleContext);
5211 
5212   // Create the anonymous inner wrapper frame
5213   nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
5214 
5215   InitAndRestoreFrame(aState, content, newFrame, innerFrame);
5216 
5217   // Put the newly created frames into the right child list
5218   SetInitialSingleChild(newFrame, innerFrame);
5219 
5220   aState.AddChild(newFrame, aFrameItems, content, aParentFrame,
5221                   aCandidateRootFrame, aCandidateRootFrame);
5222 
5223   if (!mRootElementFrame && aCandidateRootFrame) {
5224     // The frame we're constructing will be the root element frame.
5225     // Set mRootElementFrame before processing children.
5226     mRootElementFrame = newFrame;
5227   }
5228 
5229   nsFrameItems childItems;
5230 
5231   // Process children
5232   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
5233                "nsIAnonymousContentCreator::CreateAnonymousContent should not "
5234                "be implemented for frames for which we explicitly create an "
5235                "anonymous child to wrap its child frames");
5236   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
5237     ConstructFramesFromItemList(
5238         aState, aItem.mChildItems, innerFrame,
5239         aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX, childItems);
5240   } else {
5241     ProcessChildren(aState, content, styleContext, innerFrame, true, childItems,
5242                     false, aItem.mPendingBinding);
5243   }
5244 
5245   // Set the inner wrapper frame's initial primary list
5246   innerFrame->SetInitialChildList(kPrincipalList, childItems);
5247 
5248   return newFrame;
5249 }
5250 
ConstructOuterSVG(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)5251 nsIFrame* nsCSSFrameConstructor::ConstructOuterSVG(
5252     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
5253     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
5254     nsFrameItems& aFrameItems) {
5255   return ConstructFrameWithAnonymousChild(
5256       aState, aItem, aParentFrame, aFrameItems, NS_NewSVGOuterSVGFrame,
5257       NS_NewSVGOuterSVGAnonChildFrame, nsCSSAnonBoxes::mozSVGOuterSVGAnonChild,
5258       true);
5259 }
5260 
ConstructMarker(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)5261 nsIFrame* nsCSSFrameConstructor::ConstructMarker(
5262     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
5263     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
5264     nsFrameItems& aFrameItems) {
5265   return ConstructFrameWithAnonymousChild(
5266       aState, aItem, aParentFrame, aFrameItems, NS_NewSVGMarkerFrame,
5267       NS_NewSVGMarkerAnonChildFrame, nsCSSAnonBoxes::mozSVGMarkerAnonChild,
5268       false);
5269 }
5270 
5271 // Only outer <svg> elements can be floated or positioned.  All other SVG
5272 // should be in-flow.
5273 #define SIMPLE_SVG_FCDATA(_func)                                      \
5274   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
5275                   FCDATA_DISALLOW_GENERATED_CONTENT,                  \
5276               _func)
5277 #define SIMPLE_SVG_CREATE(_tag, _func) \
5278   { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
5279 
IsFilterPrimitiveChildTag(const nsAtom * aTag)5280 static bool IsFilterPrimitiveChildTag(const nsAtom* aTag) {
5281   return aTag == nsGkAtoms::feDistantLight || aTag == nsGkAtoms::fePointLight ||
5282          aTag == nsGkAtoms::feSpotLight || aTag == nsGkAtoms::feFuncR ||
5283          aTag == nsGkAtoms::feFuncG || aTag == nsGkAtoms::feFuncB ||
5284          aTag == nsGkAtoms::feFuncA || aTag == nsGkAtoms::feMergeNode;
5285 }
5286 
5287 /* static */
5288 const nsCSSFrameConstructor::FrameConstructionData*
FindSVGData(Element * aElement,nsAtom * aTag,int32_t aNameSpaceID,nsIFrame * aParentFrame,bool aIsWithinSVGText,bool aAllowsTextPathChild,nsStyleContext * aStyleContext)5289 nsCSSFrameConstructor::FindSVGData(Element* aElement, nsAtom* aTag,
5290                                    int32_t aNameSpaceID, nsIFrame* aParentFrame,
5291                                    bool aIsWithinSVGText,
5292                                    bool aAllowsTextPathChild,
5293                                    nsStyleContext* aStyleContext) {
5294   if (aNameSpaceID != kNameSpaceID_SVG) {
5295     return nullptr;
5296   }
5297 
5298   static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
5299   static const FrameConstructionData sContainerData =
5300       SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
5301 
5302   bool parentIsSVG = aIsWithinSVGText;
5303   nsIContent* parentContent =
5304       aParentFrame ? aParentFrame->GetContent() : nullptr;
5305   // XXXbz should this really be based on the XBL-resolved tag of the parent
5306   // frame's content?  Should it not be based on the type of the parent frame
5307   // (e.g. whether it's an SVG frame)?
5308   if (parentContent) {
5309     int32_t parentNSID;
5310     nsAtom* parentTag = parentContent->OwnerDoc()->BindingManager()->ResolveTag(
5311         parentContent, &parentNSID);
5312 
5313     // It's not clear whether the SVG spec intends to allow any SVG
5314     // content within svg:foreignObject at all (SVG 1.1, section
5315     // 23.2), but if it does, it better be svg:svg.  So given that
5316     // we're allowing it, treat it as a non-SVG parent.
5317     parentIsSVG =
5318         parentNSID == kNameSpaceID_SVG && parentTag != nsGkAtoms::foreignObject;
5319   }
5320 
5321   if ((aTag != nsGkAtoms::svg && !parentIsSVG) ||
5322       (aTag == nsGkAtoms::desc || aTag == nsGkAtoms::title ||
5323        aTag == nsGkAtoms::metadata)) {
5324     // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
5325     // svg:svg not contained within svg:svg are incorrect, although they
5326     // don't seem to specify error handling.  Ignore them, since many of
5327     // our frame classes can't deal.  It *may* be that the document
5328     // should at that point be considered in error according to F.2, but
5329     // it's hard to tell.
5330     //
5331     // Style mutation can't change this situation, so don't bother
5332     // adding to the undisplayed content map.
5333     //
5334     // We don't currently handle any UI for desc/title/metadata
5335     return &sSuppressData;
5336   }
5337 
5338   // We don't need frames for animation elements
5339   if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
5340     return &sSuppressData;
5341   }
5342 
5343   // https://drafts.csswg.org/css-display/#unbox-svg
5344   if (aStyleContext->StyleDisplay()->mDisplay == StyleDisplay::Contents) {
5345     // For root <svg> elements, display: contents behaves as display: none.
5346     if (aTag == nsGkAtoms::svg && !parentIsSVG) {
5347       return &sSuppressData;
5348     }
5349 
5350     // For nested <svg>, <g>, <use> and <tspan> behave normally, but any other
5351     // element behaves as display: none as well.
5352     if (aTag != nsGkAtoms::g && aTag != nsGkAtoms::use &&
5353         aTag != nsGkAtoms::svg && aTag != nsGkAtoms::tspan) {
5354       return &sSuppressData;
5355     }
5356   }
5357 
5358   if (aTag == nsGkAtoms::svg && !parentIsSVG) {
5359     // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
5360     // of whether they fail conditional processing attributes, since various
5361     // SVG frames assume that one exists.  We handle the non-rendering
5362     // of failing outer <svg> element contents like <switch> statements,
5363     // and do the PassesConditionalProcessingTests call in
5364     // nsSVGOuterSVGFrame::Init.
5365     static const FrameConstructionData sOuterSVGData =
5366         FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
5367     return &sOuterSVGData;
5368   }
5369 
5370   if (aTag == nsGkAtoms::marker) {
5371     static const FrameConstructionData sMarkerSVGData =
5372         FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructMarker);
5373     return &sMarkerSVGData;
5374   }
5375 
5376   nsCOMPtr<SVGTests> tests(do_QueryInterface(aElement));
5377   if (tests && !tests->PassesConditionalProcessingTests()) {
5378     // Elements with failing conditional processing attributes never get
5379     // rendered.  Note that this is not where we select which frame in a
5380     // <switch> to render!  That happens in nsSVGSwitchFrame::PaintSVG.
5381     if (aIsWithinSVGText) {
5382       // SVGTextFrame doesn't handle conditional processing attributes,
5383       // so don't create frames for descendants of <text> with failing
5384       // attributes.  We need frames not to be created so that text layout
5385       // is correct.
5386       return &sSuppressData;
5387     }
5388     // If we're not inside <text>, create an nsSVGContainerFrame (which is a
5389     // frame that doesn't render) so that paint servers can still be referenced,
5390     // even if they live inside an element with failing conditional processing
5391     // attributes.
5392     return &sContainerData;
5393   }
5394 
5395   // Ensure that a stop frame is a child of a gradient and that gradients
5396   // can only have stop children.
5397   bool parentIsGradient =
5398       aParentFrame && (aParentFrame->IsSVGLinearGradientFrame() ||
5399                        aParentFrame->IsSVGRadialGradientFrame());
5400   bool stop = (aTag == nsGkAtoms::stop);
5401   if ((parentIsGradient && !stop) || (!parentIsGradient && stop)) {
5402     return &sSuppressData;
5403   }
5404 
5405   // Prevent bad frame types being children of filters or parents of filter
5406   // primitives.  If aParentFrame is null, we know that the frame that will
5407   // be created will be an nsInlineFrame, so it can never be a filter.
5408   bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
5409   bool filterPrimitive = aElement->IsNodeOfType(nsINode::eFILTER);
5410   if ((parentIsFilter && !filterPrimitive) ||
5411       (!parentIsFilter && filterPrimitive)) {
5412     return &sSuppressData;
5413   }
5414 
5415   // Prevent bad frame types being children of filter primitives or parents of
5416   // filter primitive children.  If aParentFrame is null, we know that the frame
5417   // that will be created will be an nsInlineFrame, so it can never be a filter
5418   // primitive.
5419   bool parentIsFEContainerFrame =
5420       aParentFrame && aParentFrame->IsSVGFEContainerFrame();
5421   if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(aTag)) ||
5422       (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(aTag))) {
5423     return &sSuppressData;
5424   }
5425 
5426   // Special cases for text/tspan/textPath, because the kind of frame
5427   // they get depends on the parent frame.  We ignore 'a' elements when
5428   // determining the parent, however.
5429   if (aIsWithinSVGText) {
5430     // If aIsWithinSVGText is true, then we know that the "SVG text uses
5431     // CSS frames" pref was true when this SVG fragment was first constructed.
5432 
5433     // We don't use ConstructInline because we want different behavior
5434     // for generated content.
5435     static const FrameConstructionData sTSpanData = FCDATA_DECL(
5436         FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
5437             FCDATA_DISALLOW_GENERATED_CONTENT | FCDATA_IS_LINE_PARTICIPANT |
5438             FCDATA_IS_INLINE | FCDATA_USE_CHILD_ITEMS,
5439         NS_NewInlineFrame);
5440     if (aTag == nsGkAtoms::textPath) {
5441       if (aAllowsTextPathChild) {
5442         return &sTSpanData;
5443       }
5444     } else if (aTag == nsGkAtoms::tspan || aTag == nsGkAtoms::a) {
5445       return &sTSpanData;
5446     }
5447     return &sSuppressData;
5448   } else if (aTag == nsGkAtoms::tspan || aTag == nsGkAtoms::textPath) {
5449     return &sSuppressData;
5450   }
5451 
5452   static const FrameConstructionDataByTag sSVGData[] = {
5453       SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
5454       SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
5455       SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
5456       SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame),
5457       SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame),
5458       SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame),
5459       SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame),
5460       SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame),
5461       SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame),
5462       SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame),
5463       SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame),
5464       SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
5465       SIMPLE_SVG_CREATE(generic_, NS_NewSVGGenericContainerFrame),
5466       {&nsGkAtoms::text,
5467        FCDATA_WITH_WRAPPING_BLOCK(
5468            FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_ALLOW_BLOCK_STYLES,
5469            NS_NewSVGTextFrame, nsCSSAnonBoxes::mozSVGText)},
5470       {&nsGkAtoms::foreignObject,
5471        FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW,
5472                                   NS_NewSVGForeignObjectFrame,
5473                                   nsCSSAnonBoxes::mozSVGForeignContent)},
5474       SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
5475       SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
5476       SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
5477       SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
5478       SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
5479       SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame),
5480       SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
5481       SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
5482       SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
5483       SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
5484       SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
5485       SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
5486       SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
5487       SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
5488       SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
5489       SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
5490       SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
5491       SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
5492       SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
5493       SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
5494       SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
5495       SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
5496       SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
5497       SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
5498       SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
5499       SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
5500       SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
5501       SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
5502       SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
5503       SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
5504       SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
5505       SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
5506       SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
5507       SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
5508       SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
5509       SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)};
5510 
5511   const FrameConstructionData* data = FindDataByTag(
5512       aTag, aElement, aStyleContext, sSVGData, ArrayLength(sSVGData));
5513 
5514   if (!data) {
5515     data = &sContainerData;
5516   }
5517 
5518   return data;
5519 }
5520 
AddPageBreakItem(nsIContent * aContent,FrameConstructionItemList & aItems)5521 void nsCSSFrameConstructor::AddPageBreakItem(
5522     nsIContent* aContent, FrameConstructionItemList& aItems) {
5523   RefPtr<nsStyleContext> pseudoStyle =
5524       mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
5525           nsCSSAnonBoxes::pageBreak);
5526 
5527   MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,
5528              "Unexpected display");
5529 
5530   static const FrameConstructionData sPageBreakData =
5531       FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
5532 
5533   // Lie about the tag and namespace so we don't trigger anything
5534   // interesting during frame construction.
5535   aItems.AppendItem(this, &sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
5536                     kNameSpaceID_None, nullptr, pseudoStyle.forget(), true,
5537                     nullptr);
5538 }
5539 
ShouldCreateItemsForChild(nsFrameConstructorState & aState,nsIContent * aContent,nsContainerFrame * aParentFrame)5540 bool nsCSSFrameConstructor::ShouldCreateItemsForChild(
5541     nsFrameConstructorState& aState, nsIContent* aContent,
5542     nsContainerFrame* aParentFrame) {
5543   aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
5544   if (aContent->IsElement() && !aContent->IsStyledByServo()) {
5545     // We can't just remove our pending restyle flags, since we may
5546     // have restyle-later-siblings set on us.  But we _can_ remove the
5547     // "is possible restyle root" flags, and need to.  Otherwise we can
5548     // end up with stale such flags (e.g. if we used to have a
5549     // display:none parent when our last restyle was posted and
5550     // processed and now no longer do).
5551     aContent->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS &
5552                          ~ELEMENT_PENDING_RESTYLE_FLAGS);
5553   }
5554 
5555   // XXX the GetContent() != aContent check is needed due to bug 135040.
5556   // Remove it once that's fixed.
5557   if (aContent->GetPrimaryFrame() &&
5558       aContent->GetPrimaryFrame()->GetContent() == aContent &&
5559       !aState.mCreatingExtraFrames) {
5560     NS_ERROR(
5561         "asked to create frame construction item for a node that already "
5562         "has a frame");
5563     return false;
5564   }
5565 
5566   // don't create a whitespace frame if aParent doesn't want it
5567   if (!NeedFrameFor(aState, aParentFrame, aContent)) {
5568     return false;
5569   }
5570 
5571   // never create frames for comments or PIs
5572   if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
5573       aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
5574     return false;
5575   }
5576 
5577   return true;
5578 }
5579 
DoAddFrameConstructionItems(nsFrameConstructorState & aState,nsIContent * aContent,nsStyleContext * aStyleContext,bool aSuppressWhiteSpaceOptimizations,nsContainerFrame * aParentFrame,nsTArray<nsIAnonymousContentCreator::ContentInfo> * aAnonChildren,FrameConstructionItemList & aItems)5580 void nsCSSFrameConstructor::DoAddFrameConstructionItems(
5581     nsFrameConstructorState& aState, nsIContent* aContent,
5582     nsStyleContext* aStyleContext, bool aSuppressWhiteSpaceOptimizations,
5583     nsContainerFrame* aParentFrame,
5584     nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
5585     FrameConstructionItemList& aItems) {
5586   uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
5587   if (aParentFrame) {
5588     if (nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
5589       flags |= ITEM_IS_WITHIN_SVG_TEXT;
5590     }
5591     if (aParentFrame->IsBlockFrame() && aParentFrame->GetParent() &&
5592         aParentFrame->GetParent()->IsSVGTextFrame()) {
5593       flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
5594     }
5595   }
5596   AddFrameConstructionItemsInternal(
5597       aState, aContent, aParentFrame, aContent->NodeInfo()->NameAtom(),
5598       aContent->GetNameSpaceID(), aSuppressWhiteSpaceOptimizations,
5599       aStyleContext, flags, aAnonChildren, aItems);
5600 }
5601 
AddFrameConstructionItems(nsFrameConstructorState & aState,nsIContent * aContent,bool aSuppressWhiteSpaceOptimizations,const InsertionPoint & aInsertion,FrameConstructionItemList & aItems)5602 void nsCSSFrameConstructor::AddFrameConstructionItems(
5603     nsFrameConstructorState& aState, nsIContent* aContent,
5604     bool aSuppressWhiteSpaceOptimizations, const InsertionPoint& aInsertion,
5605     FrameConstructionItemList& aItems) {
5606   nsContainerFrame* parentFrame = aInsertion.mParentFrame;
5607   if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
5608     return;
5609   }
5610   RefPtr<nsStyleContext> styleContext =
5611       ResolveStyleContext(aInsertion, aContent, &aState);
5612   DoAddFrameConstructionItems(aState, aContent, styleContext,
5613                               aSuppressWhiteSpaceOptimizations, parentFrame,
5614                               nullptr, aItems);
5615 }
5616 
SetAsUndisplayedContent(nsFrameConstructorState & aState,FrameConstructionItemList & aList,nsIContent * aContent,nsStyleContext * aStyleContext,bool aIsGeneratedContent)5617 void nsCSSFrameConstructor::SetAsUndisplayedContent(
5618     nsFrameConstructorState& aState, FrameConstructionItemList& aList,
5619     nsIContent* aContent, nsStyleContext* aStyleContext,
5620     bool aIsGeneratedContent) {
5621   if (aStyleContext->GetPseudo()) {
5622     if (aIsGeneratedContent) {
5623       aContent->UnbindFromTree();
5624     }
5625     return;
5626   }
5627   NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
5628 
5629   if (aState.mCreatingExtraFrames) {
5630     MOZ_ASSERT(GetDisplayNoneStyleFor(aContent),
5631                "should have called RegisterDisplayNoneStyleFor earlier");
5632     return;
5633   }
5634   aList.AppendUndisplayedItem(aContent, aStyleContext);
5635 }
5636 
AddFrameConstructionItemsInternal(nsFrameConstructorState & aState,nsIContent * aContent,nsContainerFrame * aParentFrame,nsAtom * aTag,int32_t aNameSpaceID,bool aSuppressWhiteSpaceOptimizations,nsStyleContext * aStyleContext,uint32_t aFlags,nsTArray<nsIAnonymousContentCreator::ContentInfo> * aAnonChildren,FrameConstructionItemList & aItems)5637 void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
5638     nsFrameConstructorState& aState, nsIContent* aContent,
5639     nsContainerFrame* aParentFrame, nsAtom* aTag, int32_t aNameSpaceID,
5640     bool aSuppressWhiteSpaceOptimizations, nsStyleContext* aStyleContext,
5641     uint32_t aFlags,
5642     nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
5643     FrameConstructionItemList& aItems) {
5644   NS_PRECONDITION(
5645       aContent->IsNodeOfType(nsINode::eTEXT) || aContent->IsElement(),
5646       "Shouldn't get anything else here!");
5647   MOZ_ASSERT(aContent->IsInComposedDoc());
5648   MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
5649              aContent->NodeInfo()->NameAtom() == nsGkAtoms::area);
5650 
5651   // The following code allows the user to specify the base tag
5652   // of an element using XBL.  XUL and HTML objects (like boxes, menus, etc.)
5653   // can then be extended arbitrarily.
5654   const nsStyleDisplay* display = aStyleContext->StyleDisplay();
5655   RefPtr<nsStyleContext> styleContext(aStyleContext);
5656   PendingBinding* pendingBinding = nullptr;
5657   if (aFlags & ITEM_ALLOW_XBL_BASE) {
5658     if (display->mBinding) {
5659       // Ensure that our XBL bindings are installed.
5660 
5661       nsXBLService* xblService = nsXBLService::GetInstance();
5662       if (!xblService) return;
5663 
5664       bool resolveStyle;
5665 
5666       nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
5667 
5668       nsresult rv = xblService->LoadBindings(
5669           aContent->AsElement(), display->mBinding->GetURI(),
5670           display->mBinding->mExtraData->GetPrincipal(),
5671           getter_AddRefs(newPendingBinding->mBinding), &resolveStyle);
5672       if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) return;
5673 
5674       if (newPendingBinding->mBinding) {
5675         pendingBinding = newPendingBinding;
5676         // aState takes over owning newPendingBinding
5677         aState.AddPendingBinding(newPendingBinding.forget());
5678       }
5679 
5680       if (resolveStyle) {
5681         // Need to take a different path (Servo directly grabs the style from
5682         // the element, Gecko needs to actually re-resolve it using the parent
5683         // style context).
5684         if (styleContext->IsServo()) {
5685           styleContext = mPresShell->StyleSet()->AsServo()->ResolveServoStyle(
5686               aContent->AsElement());
5687         } else {
5688 #ifdef MOZ_OLD_STYLE
5689           styleContext = ResolveStyleContext(
5690               styleContext->AsGecko()->GetParent(), aContent, &aState);
5691 #else
5692           MOZ_CRASH("old style system disabled");
5693 #endif
5694         }
5695       }
5696 
5697       display = styleContext->StyleDisplay();
5698       aStyleContext = styleContext;
5699       aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID);
5700     }
5701   }
5702 
5703   const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
5704 
5705   // Pre-check for display "none" - if we find that, don't create
5706   // any frame at all
5707   if (StyleDisplay::None == display->mDisplay) {
5708     SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
5709                             isGeneratedContent);
5710     return;
5711   }
5712 
5713   bool isText = !aContent->IsElement();
5714 
5715   // never create frames for non-option/optgroup kids of <select> and
5716   // non-option kids of <optgroup> inside a <select>.
5717   // XXXbz it's not clear how this should best work with XBL.
5718   nsIContent* parent = aContent->GetParent();
5719   if (parent) {
5720     // Check tag first, since that check will usually fail
5721     if (parent->IsAnyOfHTMLElements(nsGkAtoms::select, nsGkAtoms::optgroup) &&
5722         // <option> is ok no matter what
5723         !aContent->IsHTMLElement(nsGkAtoms::option) &&
5724         // <optgroup> is OK in <select> but not in <optgroup>
5725         (!aContent->IsHTMLElement(nsGkAtoms::optgroup) ||
5726          !parent->IsHTMLElement(nsGkAtoms::select)) &&
5727         // Allow native anonymous content no matter what
5728         !aContent->IsRootOfNativeAnonymousSubtree()) {
5729       // No frame for aContent
5730       if (!isText) {
5731         SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
5732                                 isGeneratedContent);
5733       }
5734       return;
5735     }
5736   }
5737 
5738   // When constructing a child of a non-open <details>, create only the frame
5739   // for the main <summary> element, and skip other elements.  This only applies
5740   // to things that are not roots of native anonymous subtrees (except for
5741   // ::before and ::after); we always want to create "internal" anonymous
5742   // content.
5743   auto* details = HTMLDetailsElement::FromContentOrNull(parent);
5744   if (details && !details->Open() &&
5745       (!aContent->IsRootOfNativeAnonymousSubtree() ||
5746        aContent->IsGeneratedContentContainerForBefore() ||
5747        aContent->IsGeneratedContentContainerForAfter())) {
5748     auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
5749     if (!summary || !summary->IsMainSummary()) {
5750       SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
5751                               isGeneratedContent);
5752       return;
5753     }
5754   }
5755 
5756   bool isPopup = false;
5757   bool foundMathMLData = false;
5758   // Try to find frame construction data for this content
5759   const FrameConstructionData* data;
5760   if (isText) {
5761     data = FindTextData(aParentFrame);
5762     if (!data) {
5763       // Nothing to do here; suppressed text inside SVG
5764       return;
5765     }
5766   } else {
5767     Element* element = aContent->AsElement();
5768 
5769     // Don't create frames for non-SVG element children of SVG elements.
5770     if (aNameSpaceID != kNameSpaceID_SVG &&
5771         ((aParentFrame && IsFrameForSVG(aParentFrame) &&
5772           !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) ||
5773          (aFlags & ITEM_IS_WITHIN_SVG_TEXT))) {
5774       SetAsUndisplayedContent(aState, aItems, element, styleContext,
5775                               isGeneratedContent);
5776       return;
5777     }
5778 
5779     data =
5780         FindHTMLData(element, aTag, aNameSpaceID, aParentFrame, styleContext);
5781     if (!data) {
5782       data = FindXULTagData(element, aTag, aNameSpaceID, styleContext);
5783     }
5784     if (!data) {
5785       data = FindMathMLData(element, aTag, aNameSpaceID, styleContext);
5786       foundMathMLData = !!data;
5787     }
5788     if (!data) {
5789       data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
5790                          aFlags & ITEM_IS_WITHIN_SVG_TEXT,
5791                          aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD, styleContext);
5792     }
5793 
5794     // Now check for XUL display types
5795     if (!data) {
5796       data = FindXULDisplayData(display, element, styleContext);
5797     }
5798 
5799     // And general display types
5800     if (!data) {
5801       data = FindDisplayData(display, element, styleContext);
5802     }
5803 
5804     NS_ASSERTION(data, "Should have frame construction data now");
5805 
5806     if (data->mBits & FCDATA_SUPPRESS_FRAME) {
5807       SetAsUndisplayedContent(aState, aItems, element, styleContext,
5808                               isGeneratedContent);
5809       return;
5810     }
5811 
5812 #ifdef MOZ_XUL
5813     if ((data->mBits & FCDATA_IS_POPUP) &&
5814         (!aParentFrame ||  // Parent is inline
5815          !aParentFrame->IsMenuFrame())) {
5816       if (!aState.mPopupItems.containingBlock &&
5817           !aState.mHavePendingPopupgroup) {
5818         SetAsUndisplayedContent(aState, aItems, element, styleContext,
5819                                 isGeneratedContent);
5820         return;
5821       }
5822 
5823       isPopup = true;
5824     }
5825 #endif /* MOZ_XUL */
5826   }
5827 
5828   uint32_t bits = data->mBits;
5829 
5830   // Inside colgroups, suppress everything except columns.
5831   if (aParentFrame && aParentFrame->IsTableColGroupFrame() &&
5832       (!(bits & FCDATA_IS_TABLE_PART) ||
5833        display->mDisplay != StyleDisplay::TableColumn)) {
5834     SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
5835                             isGeneratedContent);
5836     return;
5837   }
5838 
5839   bool canHavePageBreak =
5840       (aFlags & ITEM_ALLOW_PAGE_BREAK) && aState.mPresContext->IsPaginated() &&
5841       !display->IsAbsolutelyPositionedStyle() &&
5842       !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
5843       !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
5844 
5845   if (canHavePageBreak && display->mBreakBefore) {
5846     AddPageBreakItem(aContent, aItems);
5847   }
5848 
5849   // FIXME(emilio, https://github.com/w3c/csswg-drafts/issues/2167):
5850   //
5851   // Figure out what should happen for display: contents in MathML.
5852   if (display->mDisplay == StyleDisplay::Contents && !foundMathMLData) {
5853     if (!GetDisplayContentsStyleFor(aContent)) {
5854       MOZ_ASSERT(styleContext->GetPseudo() || !isGeneratedContent,
5855                  "Should have had pseudo type");
5856       aState.mFrameManager->RegisterDisplayContentsStyleFor(aContent,
5857                                                             styleContext);
5858     } else {
5859       aState.mFrameManager->ChangeRegisteredDisplayContentsStyleFor(
5860           aContent, styleContext);
5861     }
5862 
5863     TreeMatchContext::AutoAncestorPusher ancestorPusher(
5864         aState.mTreeMatchContext);
5865     if (aState.HasAncestorFilter()) {
5866       ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
5867     } else {
5868       ancestorPusher.PushStyleScope(aContent->AsElement());
5869     }
5870 
5871     if (aParentFrame) {
5872       aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
5873     }
5874     CreateGeneratedContentItem(aState, aParentFrame, aContent->AsElement(),
5875                                styleContext, CSSPseudoElementType::before,
5876                                aItems);
5877 
5878     FlattenedChildIterator iter(aContent);
5879     for (nsIContent* child = iter.GetNextChild(); child;
5880          child = iter.GetNextChild()) {
5881       if (!ShouldCreateItemsForChild(aState, child, aParentFrame)) {
5882         continue;
5883       }
5884 
5885       // Get the parent of the content and check if it is a XBL children element
5886       // (if the content is a children element then parent != aContent because
5887       // the FlattenedChildIterator will transitively iterate through
5888       // <xbl:children> for default content). Push the children element as an
5889       // ancestor here because it does not have a frame and would not otherwise
5890       // be pushed as an ancestor.
5891       nsIContent* parent = child->GetParent();
5892       MOZ_ASSERT(parent,
5893                  "Parent must be non-null because we are iterating children.");
5894       TreeMatchContext::AutoAncestorPusher ancestorPusher(
5895           aState.mTreeMatchContext);
5896       if (parent != aContent && parent->IsElement()) {
5897         if (aState.HasAncestorFilter()) {
5898           ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
5899         } else {
5900           ancestorPusher.PushStyleScope(parent->AsElement());
5901         }
5902       }
5903 
5904       RefPtr<nsStyleContext> childContext =
5905           ResolveStyleContext(styleContext, child, &aState);
5906       DoAddFrameConstructionItems(aState, child, childContext,
5907                                   aSuppressWhiteSpaceOptimizations,
5908                                   aParentFrame, aAnonChildren, aItems);
5909     }
5910     aItems.SetParentHasNoXBLChildren(!iter.XBLInvolved());
5911 
5912     CreateGeneratedContentItem(aState, aParentFrame, aContent->AsElement(),
5913                                styleContext, CSSPseudoElementType::after,
5914                                aItems);
5915     if (canHavePageBreak && display->mBreakAfter) {
5916       AddPageBreakItem(aContent, aItems);
5917     }
5918     return;
5919   }
5920 
5921   FrameConstructionItem* item = nullptr;
5922   if (details && details->Open()) {
5923     auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
5924     if (summary && summary->IsMainSummary()) {
5925       // If details is open, the main summary needs to be rendered as if it is
5926       // the first child, so add the item to the front of the item list.
5927       item =
5928           aItems.PrependItem(this, data, aContent, aTag, aNameSpaceID,
5929                              pendingBinding, styleContext.forget(),
5930                              aSuppressWhiteSpaceOptimizations, aAnonChildren);
5931     }
5932   }
5933 
5934   if (!item) {
5935     item = aItems.AppendItem(this, data, aContent, aTag, aNameSpaceID,
5936                              pendingBinding, styleContext.forget(),
5937                              aSuppressWhiteSpaceOptimizations, aAnonChildren);
5938   }
5939   item->mIsText = isText;
5940   item->mIsGeneratedContent = isGeneratedContent;
5941   item->mIsAnonymousContentCreatorContent =
5942       aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
5943   if (isGeneratedContent) {
5944     // We need to keep this alive until the frame takes ownership.
5945     // This corresponds to the Release in ConstructFramesFromItem.
5946     item->mContent->AddRef();
5947   }
5948   item->mIsRootPopupgroup = aNameSpaceID == kNameSpaceID_XUL &&
5949                             aTag == nsGkAtoms::popupgroup &&
5950                             aContent->IsRootOfNativeAnonymousSubtree();
5951   if (item->mIsRootPopupgroup) {
5952     aState.mHavePendingPopupgroup = true;
5953   }
5954   item->mIsPopup = isPopup;
5955   item->mIsForSVGAElement =
5956       aNameSpaceID == kNameSpaceID_SVG && aTag == nsGkAtoms::a;
5957 
5958   if (canHavePageBreak && display->mBreakAfter) {
5959     AddPageBreakItem(aContent, aItems);
5960   }
5961 
5962   if (bits & FCDATA_IS_INLINE) {
5963     // To correctly set item->mIsAllInline we need to build up our child items
5964     // right now.
5965     BuildInlineChildItems(aState, *item, aFlags & ITEM_IS_WITHIN_SVG_TEXT,
5966                           aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD);
5967     item->mHasInlineEnds = true;
5968     item->mIsBlock = false;
5969   } else {
5970     // Compute a boolean isInline which is guaranteed to be false for blocks
5971     // (but may also be false for some inlines).
5972     bool isInline =
5973         // Table-internal things are inline-outside if and only if they're kids
5974         // of inlines, since they'll trigger construction of inline-table
5975         // pseudos.
5976         ((bits & FCDATA_IS_TABLE_PART) &&
5977          (!aParentFrame ||  // No aParentFrame means inline
5978           aParentFrame->StyleDisplay()->mDisplay == StyleDisplay::Inline)) ||
5979         // Things that are inline-outside but aren't inline frames are inline
5980         display->IsInlineOutsideStyle() ||
5981         // Popups that are certainly out of flow.
5982         isPopup;
5983 
5984     // Set mIsAllInline conservatively.  It just might be that even an inline
5985     // that has mIsAllInline false doesn't need an {ib} split.  So this is just
5986     // an optimization to keep from doing too much work in cases when we can
5987     // show that mIsAllInline is true..
5988     item->mIsAllInline = item->mHasInlineEnds =
5989         isInline ||
5990         // Figure out whether we're guaranteed this item will be out of flow.
5991         // This is not a precise test, since one of our ancestor inlines might
5992         // add an absolute containing block (if it's relatively positioned) when
5993         // there wasn't such a containing block before.  But it's conservative
5994         // in the sense that anything that will really end up as an in-flow
5995         // non-inline will test false here.  In other words, if this test is
5996         // true we're guaranteed to be inline; if it's false we don't know what
5997         // we'll end up as.
5998         //
5999         // If we make this test precise, we can remove some of the code dealing
6000         // with the imprecision in ConstructInline and adjust the comments on
6001         // mIsAllInline and mIsBlock in the header.  And probably remove
6002         // mIsBlock altogether, since then it will always be equal to
6003         // !mHasInlineEnds.
6004         (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
6005          aState.GetGeometricParent(display, nullptr));
6006 
6007     // Set mIsBlock conservatively.  It's OK to set it false for some real
6008     // blocks, but not OK to set it true for things that aren't blocks.  Since
6009     // isOutOfFlow might be false even in cases when the frame will end up
6010     // out-of-flow, we can't use it here.  But we _can_ say that the frame will
6011     // for sure end up in-flow if it's not floated or absolutely positioned.
6012     item->mIsBlock = !isInline && !display->IsAbsolutelyPositionedStyle() &&
6013                      !display->IsFloatingStyle() &&
6014                      !(bits & FCDATA_IS_SVG_TEXT);
6015   }
6016 
6017   if (item->mIsAllInline) {
6018     aItems.InlineItemAdded();
6019   } else if (item->mIsBlock) {
6020     aItems.BlockItemAdded();
6021   }
6022 
6023   // Our item should be treated as a line participant if we have the relevant
6024   // bit and are going to be in-flow.  Note that this really only matters if
6025   // our ancestor is a box or some such, so the fact that we might have an
6026   // inline ancestor that might become a containing block is not relevant here.
6027   if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
6028       ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
6029        !aState.GetGeometricParent(display, nullptr))) {
6030     item->mIsLineParticipant = true;
6031     aItems.LineParticipantItemAdded();
6032   }
6033 }
6034 
6035 /**
6036  * Return true if the frame construction item pointed to by aIter will
6037  * create a frame adjacent to a line boundary in the frame tree, and that
6038  * line boundary is induced by a content node adjacent to the frame's
6039  * content node in the content tree. The latter condition is necessary so
6040  * that ContentAppended/ContentInserted/ContentRemoved can easily find any
6041  * text nodes that were suppressed here.
6042  */
AtLineBoundary(FCItemIterator & aIter)6043 bool nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter) {
6044   if (aIter.item().mSuppressWhiteSpaceOptimizations) {
6045     return false;
6046   }
6047 
6048   if (aIter.AtStart()) {
6049     if (aIter.List()->HasLineBoundaryAtStart() &&
6050         !aIter.item().mContent->GetPreviousSibling())
6051       return true;
6052   } else {
6053     FCItemIterator prev = aIter;
6054     prev.Prev();
6055     if (prev.item().IsLineBoundary() &&
6056         !prev.item().mSuppressWhiteSpaceOptimizations &&
6057         aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
6058       return true;
6059   }
6060 
6061   FCItemIterator next = aIter;
6062   next.Next();
6063   if (next.IsDone()) {
6064     if (aIter.List()->HasLineBoundaryAtEnd() &&
6065         !aIter.item().mContent->GetNextSibling())
6066       return true;
6067   } else {
6068     if (next.item().IsLineBoundary() &&
6069         !next.item().mSuppressWhiteSpaceOptimizations &&
6070         aIter.item().mContent->GetNextSibling() == next.item().mContent)
6071       return true;
6072   }
6073 
6074   return false;
6075 }
6076 
ConstructFramesFromItem(nsFrameConstructorState & aState,FCItemIterator & aIter,nsContainerFrame * aParentFrame,nsFrameItems & aFrameItems)6077 void nsCSSFrameConstructor::ConstructFramesFromItem(
6078     nsFrameConstructorState& aState, FCItemIterator& aIter,
6079     nsContainerFrame* aParentFrame, nsFrameItems& aFrameItems) {
6080   nsContainerFrame* adjParentFrame = aParentFrame;
6081   FrameConstructionItem& item = aIter.item();
6082   nsStyleContext* styleContext = item.mStyleContext;
6083   AdjustParentFrame(&adjParentFrame, item.mFCData, styleContext);
6084 
6085   if (item.mIsText) {
6086     // If this is collapsible whitespace next to a line boundary,
6087     // don't create a frame. item.IsWhitespace() also sets the
6088     // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
6089     // end up creating a frame, nsTextFrame::Init will clear the flag.)
6090     // We don't do this for generated content, because some generated
6091     // text content is empty text nodes that are about to be initialized.
6092     // (We check mAdditionalStateBits because only the generated content
6093     // container's frame construction item is marked with
6094     // mIsGeneratedContent, and we might not have an aParentFrame.)
6095     // We don't do it for content that may have XBL anonymous siblings,
6096     // because they make it difficult to correctly create the frame
6097     // due to dynamic changes.
6098     // We don't do it for SVG text, since we might need to position and
6099     // measure the white space glyphs due to x/y/dx/dy attributes.
6100     if (AtLineBoundary(aIter) &&
6101         !styleContext->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
6102         aIter.List()->ParentHasNoXBLChildren() &&
6103         !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
6104         (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
6105         !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
6106         !mAlwaysCreateFramesForIgnorableWhitespace && item.IsWhitespace(aState))
6107       return;
6108 
6109     ConstructTextFrame(item.mFCData, aState, item.mContent, adjParentFrame,
6110                        styleContext, aFrameItems);
6111     return;
6112   }
6113 
6114   // Start background loads during frame construction so that we're
6115   // guaranteed that they will be started before onload fires.
6116   styleContext->StartBackgroundImageLoads();
6117 
6118   nsFrameState savedStateBits = aState.mAdditionalStateBits;
6119   if (item.mIsGeneratedContent) {
6120     // Ensure that frames created here are all tagged with
6121     // NS_FRAME_GENERATED_CONTENT.
6122     aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
6123   }
6124 
6125   // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
6126   ConstructFrameFromItemInternal(item, aState, adjParentFrame, aFrameItems);
6127 
6128   if (item.mIsGeneratedContent) {
6129     // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
6130     // The frame owns the generated content now.
6131     item.mContent->Release();
6132 
6133     // Now that we've passed ownership of item.mContent to the frame, unset
6134     // our generated content flag so we don't release or unbind it ourselves.
6135     item.mIsGeneratedContent = false;
6136   }
6137 
6138   aState.mAdditionalStateBits = savedStateBits;
6139 }
6140 
IsRootBoxFrame(nsIFrame * aFrame)6141 inline bool IsRootBoxFrame(nsIFrame* aFrame) { return (aFrame->IsRootFrame()); }
6142 
ReconstructDocElementHierarchy(InsertionKind aInsertionKind)6143 void nsCSSFrameConstructor::ReconstructDocElementHierarchy(
6144     InsertionKind aInsertionKind) {
6145   Element* rootElement = mDocument->GetRootElement();
6146   if (!rootElement) {
6147     /* nothing to do */
6148     return;
6149   }
6150   RecreateFramesForContent(rootElement, aInsertionKind);
6151 }
6152 
GetAbsoluteContainingBlock(nsIFrame * aFrame,ContainingBlockType aType)6153 nsContainerFrame* nsCSSFrameConstructor::GetAbsoluteContainingBlock(
6154     nsIFrame* aFrame, ContainingBlockType aType) {
6155   // Starting with aFrame, look for a frame that is absolutely positioned or
6156   // relatively positioned (and transformed, if aType is FIXED)
6157   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
6158     if (frame->IsFrameOfType(nsIFrame::eMathML)) {
6159       // If it's mathml, bail out -- no absolute positioning out from inside
6160       // mathml frames.  Note that we don't make this part of the loop
6161       // condition because of the stuff at the end of this method...
6162       return nullptr;
6163     }
6164 
6165     // Look for the ICB.
6166     if (aType == FIXED_POS) {
6167       LayoutFrameType t = frame->Type();
6168       if (t == LayoutFrameType::Viewport || t == LayoutFrameType::PageContent) {
6169         return static_cast<nsContainerFrame*>(frame);
6170       }
6171     }
6172 
6173     // If the frame is positioned, we will probably return it as the containing
6174     // block (see the exceptions below).  Otherwise, we'll start looking at the
6175     // parent frame, unless we're dealing with a scrollframe.
6176     // Scrollframes are special since they're not positioned, but their
6177     // scrolledframe might be.  So, we need to check this special case to return
6178     // the correct containing block (the scrolledframe) in that case.
6179     // If we're looking for a fixed-pos containing block and the frame is
6180     // not transformed, skip it.
6181     if (!frame->IsAbsPosContainingBlock() ||
6182         (aType == FIXED_POS && !frame->IsFixedPosContainingBlock())) {
6183       continue;
6184     }
6185     nsIFrame* absPosCBCandidate = frame;
6186     LayoutFrameType type = absPosCBCandidate->Type();
6187     if (type == LayoutFrameType::FieldSet) {
6188       absPosCBCandidate =
6189           static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
6190       if (!absPosCBCandidate) {
6191         continue;
6192       }
6193       type = absPosCBCandidate->Type();
6194     }
6195     if (type == LayoutFrameType::Scroll) {
6196       nsIScrollableFrame* scrollFrame = do_QueryFrame(absPosCBCandidate);
6197       absPosCBCandidate = scrollFrame->GetScrolledFrame();
6198       if (!absPosCBCandidate) {
6199         continue;
6200       }
6201       type = absPosCBCandidate->Type();
6202     }
6203     // Only first continuations can be containing blocks.
6204     absPosCBCandidate = absPosCBCandidate->FirstContinuation();
6205     // Is the frame really an absolute container?
6206     if (!absPosCBCandidate->IsAbsoluteContainer()) {
6207       continue;
6208     }
6209 
6210     // For tables, skip the inner frame and consider the table wrapper frame.
6211     if (type == LayoutFrameType::Table) {
6212       continue;
6213     }
6214     // For table wrapper frames, we can just return absPosCBCandidate.
6215     MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(absPosCBCandidate),
6216                "abs.pos. containing block must be nsContainerFrame sub-class");
6217     return static_cast<nsContainerFrame*>(absPosCBCandidate);
6218   }
6219 
6220   MOZ_ASSERT(aType != FIXED_POS, "no ICB in this frame tree?");
6221 
6222   // It is possible for the search for the containing block to fail, because
6223   // no absolute container can be found in the parent chain.  In those cases,
6224   // we fall back to the document element's containing block.
6225   return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr;
6226 }
6227 
GetFloatContainingBlock(nsIFrame * aFrame)6228 nsContainerFrame* nsCSSFrameConstructor::GetFloatContainingBlock(
6229     nsIFrame* aFrame) {
6230   // Starting with aFrame, look for a frame that is a float containing block.
6231   // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
6232   // frames, because they don't seem to be able to deal.
6233   // The logic here needs to match the logic in ProcessChildren()
6234   for (nsIFrame* containingBlock = aFrame;
6235        containingBlock && !ShouldSuppressFloatingOfDescendants(containingBlock);
6236        containingBlock = containingBlock->GetParent()) {
6237     if (containingBlock->IsFloatContainingBlock()) {
6238       MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(containingBlock),
6239                  "float containing block must be nsContainerFrame sub-class");
6240       return static_cast<nsContainerFrame*>(containingBlock);
6241     }
6242   }
6243 
6244   // If we didn't find a containing block, then there just isn't
6245   // one.... return null
6246   return nullptr;
6247 }
6248 
6249 /**
6250  * This function will get the previous sibling to use for an append operation.
6251  *
6252  * It takes a parent frame (must not be null) and the next insertion sibling, if
6253  * the parent content is display: contents or has ::after content (may be null).
6254  */
FindAppendPrevSibling(nsIFrame * aParentFrame,nsIFrame * aNextSibling)6255 static nsIFrame* FindAppendPrevSibling(nsIFrame* aParentFrame,
6256                                        nsIFrame* aNextSibling) {
6257   aParentFrame->DrainSelfOverflowList();
6258 
6259   if (aNextSibling) {
6260     MOZ_ASSERT(aNextSibling->GetParent() == aParentFrame, "Wrong parent");
6261     return aNextSibling->GetPrevSibling();
6262   }
6263 
6264   return aParentFrame->GetChildList(kPrincipalList).LastChild();
6265 }
6266 
6267 /**
6268  * Finds the right parent frame to append content to aParentFrame.
6269  *
6270  * Cannot return or receive null.
6271  */
ContinuationToAppendTo(nsContainerFrame * aParentFrame)6272 static nsContainerFrame* ContinuationToAppendTo(
6273     nsContainerFrame* aParentFrame) {
6274   MOZ_ASSERT(aParentFrame);
6275 
6276   if (IsFramePartOfIBSplit(aParentFrame)) {
6277     // If the frame we are manipulating is a ib-split frame (that is, one that's
6278     // been created as a result of a block-in-inline situation) then we need to
6279     // append to the last ib-split sibling, not to the frame itself.
6280     //
6281     // Always make sure to look at the last continuation of the frame for the
6282     // {ib} case, even if that continuation is empty.
6283     //
6284     // We don't do this for the non-ib-split-frame case, since in the other
6285     // cases appending to the last nonempty continuation is fine and in fact not
6286     // doing that can confuse code that doesn't know to pull kids from
6287     // continuations other than its next one.
6288     return static_cast<nsContainerFrame*>(
6289         GetLastIBSplitSibling(aParentFrame)->LastContinuation());
6290   }
6291 
6292   return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
6293 }
6294 
6295 /**
6296  * This function will get the next sibling for a frame insert operation given
6297  * the parent and previous sibling.  aPrevSibling may be null.
6298  */
GetInsertNextSibling(nsIFrame * aParentFrame,nsIFrame * aPrevSibling)6299 static nsIFrame* GetInsertNextSibling(nsIFrame* aParentFrame,
6300                                       nsIFrame* aPrevSibling) {
6301   if (aPrevSibling) {
6302     return aPrevSibling->GetNextSibling();
6303   }
6304 
6305   return aParentFrame->PrincipalChildList().FirstChild();
6306 }
6307 
6308 /**
6309  * This function is called by ContentAppended() and ContentInserted() when
6310  * appending flowed frames to a parent's principal child list. It handles the
6311  * case where the parent is the trailing inline of an {ib} split.
6312  */
AppendFramesToParent(nsFrameConstructorState & aState,nsContainerFrame * aParentFrame,nsFrameItems & aFrameList,nsIFrame * aPrevSibling,bool aIsRecursiveCall)6313 void nsCSSFrameConstructor::AppendFramesToParent(
6314     nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
6315     nsFrameItems& aFrameList, nsIFrame* aPrevSibling, bool aIsRecursiveCall) {
6316   NS_PRECONDITION(
6317       !IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) ||
6318           !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild(),
6319       "aParentFrame has a ib-split sibling with kids?");
6320   NS_PRECONDITION(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
6321                   "Parent and prevsibling don't match");
6322 
6323   nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
6324 
6325   NS_ASSERTION(nextSibling || !aParentFrame->GetNextContinuation() ||
6326                    !aParentFrame->GetNextContinuation()
6327                         ->PrincipalChildList()
6328                         .FirstChild() ||
6329                    aIsRecursiveCall,
6330                "aParentFrame has later continuations with kids?");
6331   NS_ASSERTION(
6332       nextSibling || !IsFramePartOfIBSplit(aParentFrame) ||
6333           (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) &&
6334            !aParentFrame->GetNextContinuation()) ||
6335           aIsRecursiveCall,
6336       "aParentFrame is not last?");
6337 
6338   // If we're inserting a list of frames at the end of the trailing inline
6339   // of an {ib} split, we may need to create additional {ib} siblings to parent
6340   // them.
6341   if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
6342     // When we get here, our frame list might start with a block.  If it does
6343     // so, and aParentFrame is an inline, and it and all its previous
6344     // continuations have no siblings, then put the initial blocks from the
6345     // frame list into the previous block of the {ib} split.  Note that we
6346     // didn't want to stop at the block part of the split when figuring out
6347     // initial parent, because that could screw up float parenting; it's easier
6348     // to do this little fixup here instead.
6349     if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) {
6350       // See whether our trailing inline is empty
6351       nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
6352       if (firstContinuation->PrincipalChildList().IsEmpty()) {
6353         // Our trailing inline is empty.  Collect our starting blocks from
6354         // aFrameList, get the right parent frame for them, and put them in.
6355         nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator =
6356             FindFirstNonBlock(aFrameList);
6357         nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator);
6358         NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
6359 
6360         nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
6361         prevBlock =
6362             static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
6363         NS_ASSERTION(prevBlock, "Should have previous block here");
6364 
6365         MoveChildrenTo(aParentFrame, prevBlock, blockKids);
6366       }
6367     }
6368 
6369     // We want to put some of the frames into this inline frame.
6370     nsFrameList::FrameLinkEnumerator firstBlockEnumerator(aFrameList);
6371     FindFirstBlock(firstBlockEnumerator);
6372 
6373     nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
6374     if (!inlineKids.IsEmpty()) {
6375       AppendFrames(aParentFrame, kPrincipalList, inlineKids);
6376     }
6377 
6378     if (!aFrameList.IsEmpty()) {
6379       bool positioned = aParentFrame->IsRelativelyPositioned();
6380       nsFrameItems ibSiblings;
6381       CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
6382                        ibSiblings);
6383 
6384       // Make sure to trigger reflow of the inline that used to be our
6385       // last one and now isn't anymore, since its GetSkipSides() has
6386       // changed.
6387       mPresShell->FrameNeedsReflow(aParentFrame, nsIPresShell::eTreeChange,
6388                                    NS_FRAME_HAS_DIRTY_CHILDREN);
6389 
6390       // Recurse so we create new ib siblings as needed for aParentFrame's
6391       // parent
6392       return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
6393                                   aParentFrame, true);
6394     }
6395     return;
6396   }
6397 
6398   // Insert the frames after our aPrevSibling
6399   InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
6400 }
6401 
6402 #define UNSET_DISPLAY static_cast<StyleDisplay>(255)
6403 
6404 // This gets called to see if the frames corresponding to aSibling and aContent
6405 // should be siblings in the frame tree. Although (1) rows and cols, (2) row
6406 // groups and col groups, (3) row groups and captions, (4) legends and content
6407 // inside fieldsets, (5) popups and other kids of the menu are siblings from a
6408 // content perspective, they are not considered siblings in the frame tree.
IsValidSibling(nsIFrame * aSibling,nsIContent * aContent,StyleDisplay & aDisplay)6409 bool nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
6410                                            nsIContent* aContent,
6411                                            StyleDisplay& aDisplay) {
6412   nsIFrame* parentFrame = aSibling->GetParent();
6413   LayoutFrameType parentType = parentFrame->Type();
6414 
6415   StyleDisplay siblingDisplay = aSibling->GetDisplay();
6416   if (StyleDisplay::TableColumnGroup == siblingDisplay ||
6417       StyleDisplay::TableColumn == siblingDisplay ||
6418       StyleDisplay::TableCaption == siblingDisplay ||
6419       StyleDisplay::TableHeaderGroup == siblingDisplay ||
6420       StyleDisplay::TableRowGroup == siblingDisplay ||
6421       StyleDisplay::TableFooterGroup == siblingDisplay ||
6422       LayoutFrameType::Menu == parentType) {
6423     // if we haven't already, construct a style context to find the display type
6424     // of aContent
6425     if (UNSET_DISPLAY == aDisplay) {
6426       nsIFrame* styleParent;
6427       aSibling->GetParentStyleContext(&styleParent);
6428       if (!styleParent) {
6429         styleParent = aSibling->GetParent();
6430       }
6431       if (!styleParent) {
6432         NS_NOTREACHED("Shouldn't happen");
6433         return false;
6434       }
6435       if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
6436           aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
6437         // Comments and processing instructions never have frames, so we
6438         // should not try to generate style contexts for them.
6439         return false;
6440       }
6441       // XXXbz when this code is killed, the state argument to
6442       // ResolveStyleContext can be made non-optional.
6443       RefPtr<nsStyleContext> styleContext =
6444           ResolveStyleContext(styleParent, aContent, nullptr);
6445       const nsStyleDisplay* display = styleContext->StyleDisplay();
6446       aDisplay = display->mDisplay;
6447     }
6448     if (LayoutFrameType::Menu == parentType) {
6449       return (StyleDisplay::MozPopup == aDisplay) ==
6450              (StyleDisplay::MozPopup == siblingDisplay);
6451     }
6452     // To have decent performance we want to return false in cases in which
6453     // reordering the two siblings has no effect on display.  To ensure
6454     // correctness, we MUST return false in cases where the two siblings have
6455     // the same desired parent type and live on different display lists.
6456     // Specificaly, columns and column groups should only consider columns and
6457     // column groups as valid siblings.  Captions should only consider other
6458     // captions.  All other things should consider each other as valid
6459     // siblings.  The restriction in the |if| above on siblingDisplay is ok,
6460     // because for correctness the only part that really needs to happen is to
6461     // not consider captions, column groups, and row/header/footer groups
6462     // siblings of each other.  Treating a column or colgroup as a valid
6463     // sibling of a non-table-related frame will just mean we end up reframing.
6464     if ((siblingDisplay == StyleDisplay::TableCaption) !=
6465         (aDisplay == StyleDisplay::TableCaption)) {
6466       // One's a caption and the other is not.  Not valid siblings.
6467       return false;
6468     }
6469 
6470     if ((siblingDisplay == StyleDisplay::TableColumnGroup ||
6471          siblingDisplay == StyleDisplay::TableColumn) !=
6472         (aDisplay == StyleDisplay::TableColumnGroup ||
6473          aDisplay == StyleDisplay::TableColumn)) {
6474       // One's a column or column group and the other is not.  Not valid
6475       // siblings.
6476       return false;
6477     }
6478     // Fall through; it's possible that the display type was overridden and
6479     // a different sort of frame was constructed, so we may need to return false
6480     // below.
6481   }
6482 
6483   if (IsFrameForFieldSet(parentFrame)) {
6484     // Legends can be sibling of legends but not of other content in the
6485     // fieldset
6486     if (nsContainerFrame* cif = aSibling->GetContentInsertionFrame()) {
6487       aSibling = cif;
6488     }
6489     LayoutFrameType sibType = aSibling->Type();
6490     bool legendContent = aContent->IsHTMLElement(nsGkAtoms::legend);
6491 
6492     if ((legendContent && (LayoutFrameType::Legend != sibType)) ||
6493         (!legendContent && (LayoutFrameType::Legend == sibType)))
6494       return false;
6495   }
6496 
6497   return true;
6498 }
6499 
6500 // FIXME(emilio): If we ever kill IsValidSibling() we can simplify this quite a
6501 // bit (no need to pass aTargetContent or aTargetContentDisplay, and the
6502 // adjust() calls can be responsibility of the caller).
6503 template <nsCSSFrameConstructor::SiblingDirection aDirection>
FindSiblingInternal(FlattenedChildIterator & aIter,nsIContent * aTargetContent,StyleDisplay & aTargetContentDisplay)6504 nsIFrame* nsCSSFrameConstructor::FindSiblingInternal(
6505     FlattenedChildIterator& aIter, nsIContent* aTargetContent,
6506     StyleDisplay& aTargetContentDisplay) {
6507   auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* {
6508     return AdjustSiblingFrame(aPotentialSiblingFrame, aTargetContent,
6509                               aTargetContentDisplay, aDirection);
6510   };
6511 
6512   auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
6513     return aDirection == SiblingDirection::Forward ? aIter.GetNextChild()
6514                                                    : aIter.GetPreviousChild();
6515   };
6516 
6517   auto getNearPseudo = [](const nsIContent* aContent) -> nsIFrame* {
6518     return aDirection == SiblingDirection::Forward
6519                ? nsLayoutUtils::GetBeforeFrame(aContent)
6520                : nsLayoutUtils::GetAfterFrame(aContent);
6521   };
6522 
6523   auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* {
6524     return aDirection == SiblingDirection::Forward
6525                ? nsLayoutUtils::GetAfterFrame(aContent)
6526                : nsLayoutUtils::GetBeforeFrame(aContent);
6527   };
6528 
6529   while (nsIContent* sibling = nextDomSibling(aIter)) {
6530     if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
6531       // XXX the GetContent() == sibling check is needed due to bug 135040.
6532       // Remove it once that's fixed.
6533       if (primaryFrame->GetContent() == sibling) {
6534         if (nsIFrame* frame = adjust(primaryFrame)) {
6535           return frame;
6536         }
6537       }
6538     }
6539 
6540     if (GetDisplayContentsStyleFor(sibling)) {
6541       if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
6542         return frame;
6543       }
6544 
6545       const bool startFromBeginning = aDirection == SiblingDirection::Forward;
6546       FlattenedChildIterator iter(sibling, startFromBeginning);
6547       nsIFrame* sibling = FindSiblingInternal<aDirection>(
6548           iter, aTargetContent, aTargetContentDisplay);
6549       if (sibling) {
6550         return sibling;
6551       }
6552     }
6553   }
6554 
6555   return adjust(getFarPseudo(aIter.Parent()));
6556 }
6557 
AdjustSiblingFrame(nsIFrame * aSibling,nsIContent * aTargetContent,mozilla::StyleDisplay & aTargetContentDisplay,SiblingDirection aDirection)6558 nsIFrame* nsCSSFrameConstructor::AdjustSiblingFrame(
6559     nsIFrame* aSibling, nsIContent* aTargetContent,
6560     mozilla::StyleDisplay& aTargetContentDisplay, SiblingDirection aDirection) {
6561   if (!aSibling) {
6562     return nullptr;
6563   }
6564 
6565   if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
6566     aSibling = aSibling->GetPlaceholderFrame();
6567     MOZ_ASSERT(aSibling);
6568   }
6569 
6570   MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
6571   if (aDirection == SiblingDirection::Backward) {
6572     // The frame may be a ib-split frame (a split inline frame that contains a
6573     // block).  Get the last part of that split.
6574     if (IsFramePartOfIBSplit(aSibling)) {
6575       aSibling = GetLastIBSplitSibling(aSibling);
6576     }
6577 
6578     // The frame may have a continuation. If so, we want the last
6579     // non-overflow-container continuation as our previous sibling.
6580     aSibling = aSibling->GetTailContinuation();
6581   }
6582 
6583   if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
6584     return nullptr;
6585   }
6586 
6587   return aSibling;
6588 }
6589 
FindPreviousSibling(const FlattenedChildIterator & aIter,StyleDisplay & aTargetContentDisplay)6590 nsIFrame* nsCSSFrameConstructor::FindPreviousSibling(
6591     const FlattenedChildIterator& aIter, StyleDisplay& aTargetContentDisplay) {
6592   return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay);
6593 }
6594 
FindNextSibling(const FlattenedChildIterator & aIter,StyleDisplay & aTargetContentDisplay)6595 nsIFrame* nsCSSFrameConstructor::FindNextSibling(
6596     const FlattenedChildIterator& aIter, StyleDisplay& aTargetContentDisplay) {
6597   return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay);
6598 }
6599 
6600 template <nsCSSFrameConstructor::SiblingDirection aDirection>
FindSibling(const FlattenedChildIterator & aIter,StyleDisplay & aTargetContentDisplay)6601 nsIFrame* nsCSSFrameConstructor::FindSibling(
6602     const FlattenedChildIterator& aIter, StyleDisplay& aTargetContentDisplay) {
6603   nsIContent* targetContent = aIter.Get();
6604   FlattenedChildIterator siblingIter = aIter;
6605   nsIFrame* sibling = FindSiblingInternal<aDirection>(
6606       siblingIter, targetContent, aTargetContentDisplay);
6607   if (sibling) {
6608     return sibling;
6609   }
6610 
6611   // Our siblings (if any) do not have a frame to guide us. The frame for the
6612   // target content should be inserted whereever a frame for the container would
6613   // be inserted. This is needed when inserting into display: contents nodes.
6614   const nsIContent* current = aIter.Parent();
6615   while (GetDisplayContentsStyleFor(current)) {
6616     const nsIContent* parent = current->GetFlattenedTreeParent();
6617     MOZ_ASSERT(parent, "No display: contents on the root");
6618 
6619     FlattenedChildIterator iter(parent);
6620     iter.Seek(current);
6621     sibling = FindSiblingInternal<aDirection>(iter, targetContent,
6622                                               aTargetContentDisplay);
6623     if (sibling) {
6624       return sibling;
6625     }
6626 
6627     current = parent;
6628   }
6629 
6630   return nullptr;
6631 }
6632 
6633 // For fieldsets, returns the area frame, if the child is not a legend.
GetAdjustedParentFrame(nsContainerFrame * aParentFrame,nsIContent * aChildContent)6634 static nsContainerFrame* GetAdjustedParentFrame(nsContainerFrame* aParentFrame,
6635                                                 nsIContent* aChildContent) {
6636   NS_PRECONDITION(!aParentFrame->IsTableWrapperFrame(),
6637                   "Shouldn't be happening!");
6638 
6639   nsContainerFrame* newParent = nullptr;
6640 
6641   if (aParentFrame->IsFieldSetFrame()) {
6642     // If the parent is a fieldSet, use the fieldSet's area frame as the
6643     // parent unless the new content is a legend.
6644     if (!aChildContent->IsHTMLElement(nsGkAtoms::legend)) {
6645       newParent = GetFieldSetBlockFrame(aParentFrame);
6646     }
6647   }
6648   return newParent ? newParent : aParentFrame;
6649 }
6650 
GetInsertionPrevSibling(InsertionPoint * aInsertion,nsIContent * aChild,bool * aIsAppend,bool * aIsRangeInsertSafe,nsIContent * aStartSkipChild,nsIContent * aEndSkipChild)6651 nsIFrame* nsCSSFrameConstructor::GetInsertionPrevSibling(
6652     InsertionPoint* aInsertion, nsIContent* aChild, bool* aIsAppend,
6653     bool* aIsRangeInsertSafe, nsIContent* aStartSkipChild,
6654     nsIContent* aEndSkipChild) {
6655   NS_PRECONDITION(aInsertion->mParentFrame,
6656                   "Must have parent frame to start with");
6657 
6658   *aIsAppend = false;
6659 
6660   // Find the frame that precedes the insertion point. Walk backwards
6661   // from the parent frame to get the parent content, because if an
6662   // XBL insertion point is involved, we'll need to use _that_ to find
6663   // the preceding frame.
6664   FlattenedChildIterator iter(aInsertion->mContainer);
6665   bool xblCase = iter.XBLInvolved() || aInsertion->mParentFrame->GetContent() !=
6666                                            aInsertion->mContainer;
6667   if (xblCase || !aChild->IsRootOfAnonymousSubtree()) {
6668     // The check for IsRootOfAnonymousSubtree() is because editor is
6669     // severely broken and calls us directly for native anonymous
6670     // nodes that it creates.
6671     if (aStartSkipChild) {
6672       iter.Seek(aStartSkipChild);
6673     } else {
6674       iter.Seek(aChild);
6675     }
6676   } else {
6677     // Prime the iterator for the call to FindPreviousSibling.
6678     iter.GetNextChild();
6679     MOZ_ASSERT(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
6680                "Someone passed native anonymous content directly into frame "
6681                "construction.  Stop doing that!");
6682   }
6683 
6684   // Note that FindPreviousSibling is passed the iterator by value, so that
6685   // the later usage of the iterator starts from the same place.
6686   StyleDisplay childDisplay = UNSET_DISPLAY;
6687   nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
6688 
6689   // Now, find the geometric parent so that we can handle
6690   // continuations properly. Use the prev sibling if we have it;
6691   // otherwise use the next sibling.
6692   if (prevSibling) {
6693     aInsertion->mParentFrame =
6694         prevSibling->GetParent()->GetContentInsertionFrame();
6695   } else {
6696     // If there is no previous sibling, then find the frame that follows
6697     //
6698     // FIXME(emilio): This is really complex and probably shouldn't be.
6699     if (aEndSkipChild) {
6700       iter.Seek(aEndSkipChild);
6701       iter.GetPreviousChild();
6702     }
6703     if (nsIFrame* nextSibling = FindNextSibling(iter, childDisplay)) {
6704       aInsertion->mParentFrame =
6705           nextSibling->GetParent()->GetContentInsertionFrame();
6706     } else {
6707       // No previous or next sibling, so treat this like an appended frame.
6708       *aIsAppend = true;
6709       aInsertion->mParentFrame =
6710           ::ContinuationToAppendTo(aInsertion->mParentFrame);
6711 
6712       // Deal with fieldsets.
6713       aInsertion->mParentFrame =
6714           ::GetAdjustedParentFrame(aInsertion->mParentFrame, aChild);
6715       prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr);
6716     }
6717   }
6718 
6719   *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
6720   return prevSibling;
6721 }
6722 
GetContentInsertionFrameFor(nsIContent * aContent)6723 nsContainerFrame* nsCSSFrameConstructor::GetContentInsertionFrameFor(
6724     nsIContent* aContent) {
6725   nsIFrame* frame;
6726   while (!(frame = aContent->GetPrimaryFrame())) {
6727     if (!GetDisplayContentsStyleFor(aContent)) {
6728       return nullptr;
6729     }
6730 
6731     aContent = aContent->GetFlattenedTreeParent();
6732     if (!aContent) {
6733       return nullptr;
6734     }
6735   }
6736 
6737   // If the content of the frame is not the desired content then this is not
6738   // really a frame for the desired content.
6739   // XXX This check is needed due to bug 135040. Remove it once that's fixed.
6740   if (frame->GetContent() != aContent) {
6741     return nullptr;
6742   }
6743 
6744   nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
6745 
6746   NS_ASSERTION(!insertionFrame || insertionFrame == frame || !frame->IsLeaf(),
6747                "The insertion frame is the primary frame or the primary frame "
6748                "isn't a leaf");
6749 
6750   return insertionFrame;
6751 }
6752 
IsSpecialFramesetChild(nsIContent * aContent)6753 static bool IsSpecialFramesetChild(nsIContent* aContent) {
6754   // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
6755   return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
6756 }
6757 
6758 static void InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
6759 
6760 #ifdef MOZ_XUL
6761 
IsXULListBox(nsIContent * aContainer)6762 static bool IsXULListBox(nsIContent* aContainer) {
6763   return (aContainer->IsXULElement(nsGkAtoms::listbox));
6764 }
6765 
MaybeGetListBoxBodyFrame(nsIContent * aContainer,nsIContent * aChild)6766 static nsListBoxBodyFrame* MaybeGetListBoxBodyFrame(nsIContent* aContainer,
6767                                                     nsIContent* aChild) {
6768   if (!aContainer) return nullptr;
6769 
6770   if (IsXULListBox(aContainer) && aChild->IsXULElement(nsGkAtoms::listitem)) {
6771     RefPtr<nsXULElement> xulElement = nsXULElement::FromContent(aContainer);
6772     nsCOMPtr<nsIBoxObject> boxObject = xulElement->GetBoxObject(IgnoreErrors());
6773     nsCOMPtr<nsPIListBoxObject> listBoxObject = do_QueryInterface(boxObject);
6774     if (listBoxObject) {
6775       return listBoxObject->GetListBoxBody(false);
6776     }
6777   }
6778 
6779   return nullptr;
6780 }
6781 #endif  // MOZ_XUL
6782 
AddTextItemIfNeeded(nsFrameConstructorState & aState,const InsertionPoint & aInsertion,nsIContent * aPossibleTextContent,FrameConstructionItemList & aItems)6783 void nsCSSFrameConstructor::AddTextItemIfNeeded(
6784     nsFrameConstructorState& aState, const InsertionPoint& aInsertion,
6785     nsIContent* aPossibleTextContent, FrameConstructionItemList& aItems) {
6786   NS_PRECONDITION(aPossibleTextContent, "Must have node");
6787   if (!aPossibleTextContent->IsNodeOfType(nsINode::eTEXT) ||
6788       !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
6789       aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
6790     // Not text, or not suppressed due to being all-whitespace (if it were being
6791     // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
6792     // going to be reframed anyway.
6793     return;
6794   }
6795   MOZ_ASSERT(!aPossibleTextContent->GetPrimaryFrame(),
6796              "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6797   AddFrameConstructionItems(aState, aPossibleTextContent, false, aInsertion,
6798                             aItems);
6799 }
6800 
ReframeTextIfNeeded(nsIContent * aParentContent,nsIContent * aContent)6801 void nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent,
6802                                                 nsIContent* aContent) {
6803   if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
6804       !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
6805       aContent->HasFlag(NODE_NEEDS_FRAME)) {
6806     // Not text, or not suppressed due to being all-whitespace (if it were being
6807     // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
6808     // going to be reframed anyway.
6809     return;
6810   }
6811   MOZ_ASSERT(!aContent->GetPrimaryFrame(),
6812              "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6813   ContentInserted(aParentContent, aContent, nullptr, InsertionKind::Async);
6814 }
6815 
6816 #ifdef DEBUG
CheckBitsForLazyFrameConstruction(nsIContent * aParent)6817 void nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(
6818     nsIContent* aParent) {
6819   // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
6820   // we want to assert, but leaf frames that process their own children and may
6821   // ignore anonymous children (eg framesets) make this complicated. So we set
6822   // these two booleans if we encounter these situations and unset them if we
6823   // hit a node with a leaf frame.
6824   //
6825   // It's fine if one of node without primary frame is in a display:none
6826   // subtree.
6827   //
6828   // Also, it's fine if one of the nodes without primary frame is a display:
6829   // contents node.
6830   bool noPrimaryFrame = false;
6831   bool needsFrameBitSet = false;
6832   nsIContent* content = aParent;
6833   while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6834     if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
6835       noPrimaryFrame = needsFrameBitSet = false;
6836     }
6837     if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
6838       nsStyleContext* sc = GetDisplayNoneStyleFor(content);
6839       noPrimaryFrame = !GetDisplayContentsStyleFor(content) &&
6840                        (sc && !sc->IsInDisplayNoneSubtree());
6841     }
6842     if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
6843       needsFrameBitSet = true;
6844     }
6845 
6846     content = content->GetFlattenedTreeParent();
6847   }
6848   if (content && content->GetPrimaryFrame() &&
6849       content->GetPrimaryFrame()->IsLeaf()) {
6850     noPrimaryFrame = needsFrameBitSet = false;
6851   }
6852   NS_ASSERTION(!noPrimaryFrame,
6853                "Ancestors of nodes with frames to be "
6854                "constructed lazily should have frames");
6855   NS_ASSERTION(!needsFrameBitSet,
6856                "Ancestors of nodes with frames to be "
6857                "constructed lazily should not have NEEDS_FRAME bit set");
6858 }
6859 #endif
6860 
6861 // For inserts aChild should be valid, for appends it should be null.
6862 // Returns true if this operation can be lazy, false if not.
6863 //
6864 // FIXME(emilio, bug 1410020): This function assumes that the flattened tree
6865 // parent of all the appended children is the same, which, afaict, is not
6866 // necessarily true.
6867 //
6868 // But we disable lazy frame construction for shadow trees... We should fix
6869 // that, too.
6870 //
6871 // NOTE(emilio): The IsXULElement check is pretty unfortunate, but there's tons
6872 // of browser chrome code that rely on XBL bindings getting synchronously loaded
6873 // as soon as the elements get inserted in the DOM.
MaybeConstructLazily(Operation aOperation,nsIContent * aContainer,nsIContent * aChild)6874 bool nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
6875                                                  nsIContent* aContainer,
6876                                                  nsIContent* aChild) {
6877   if (!aContainer || aContainer->IsInNativeAnonymousSubtree() ||
6878       aContainer->IsXULElement()) {
6879     return false;
6880   }
6881 
6882   if (aOperation == CONTENTINSERT) {
6883     if (aChild->IsRootOfAnonymousSubtree() || aChild->IsXULElement()) {
6884       return false;
6885     }
6886   } else {  // CONTENTAPPEND
6887     NS_ASSERTION(aOperation == CONTENTAPPEND,
6888                  "operation should be either insert or append");
6889     for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6890       NS_ASSERTION(!child->IsRootOfAnonymousSubtree(),
6891                    "Should be coming through the CONTENTINSERT case");
6892       if (child->IsXULElement()) {
6893         return false;
6894       }
6895     }
6896   }
6897 
6898   // We can construct lazily; just need to set suitable bits in the content
6899   // tree.
6900   nsIContent* parent = aChild->GetFlattenedTreeParent();
6901   if (!parent) {
6902     // Not part of the flat tree, nothing to do.
6903     return true;
6904   }
6905 
6906   // Set NODE_NEEDS_FRAME on the new nodes.
6907   if (aOperation == CONTENTINSERT) {
6908     NS_ASSERTION(!aChild->GetPrimaryFrame() ||
6909                      aChild->GetPrimaryFrame()->GetContent() != aChild,
6910                  // XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
6911                  // check is needed due to bug 135040. Remove it once that's
6912                  // fixed.
6913                  "setting NEEDS_FRAME on a node that already has a frame?");
6914     aChild->SetFlags(NODE_NEEDS_FRAME);
6915   } else {  // CONTENTAPPEND
6916     for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6917       NS_ASSERTION(!child->GetPrimaryFrame() ||
6918                        child->GetPrimaryFrame()->GetContent() != child,
6919                    // XXX the child->GetPrimaryFrame()->GetContent() != child
6920                    // check is needed due to bug 135040. Remove it once that's
6921                    // fixed.
6922                    "setting NEEDS_FRAME on a node that already has a frame?");
6923       child->SetFlags(NODE_NEEDS_FRAME);
6924     }
6925   }
6926 
6927   // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
6928   // We need different handling for servo given the scoped restyle roots.
6929   CheckBitsForLazyFrameConstruction(parent);
6930 
6931   if (RestyleManager()->IsGecko()) {
6932 #ifdef MOZ_OLD_STYLE
6933     mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->AsGecko();
6934     while (parent && !parent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6935       parent->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
6936       parent = parent->GetFlattenedTreeParent();
6937     }
6938     geckoRM->PostRestyleEventForLazyConstruction();
6939 #else
6940     MOZ_CRASH("old style system disabled");
6941 #endif
6942   } else {
6943     parent->AsElement()->NoteDescendantsNeedFramesForServo();
6944   }
6945 
6946   return true;
6947 }
6948 
6949 #ifdef MOZ_OLD_STYLE
CreateNeededFrames(nsIContent * aContent,TreeMatchContext & aTreeMatchContext)6950 void nsCSSFrameConstructor::CreateNeededFrames(
6951     nsIContent* aContent, TreeMatchContext& aTreeMatchContext) {
6952   MOZ_ASSERT(!aContent->IsStyledByServo());
6953   NS_ASSERTION(
6954       !aContent->HasFlag(NODE_NEEDS_FRAME),
6955       "shouldn't get here with a content node that has needs frame bit set");
6956   NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
6957                "should only get here with a content node that has descendants "
6958                "needing frames");
6959   MOZ_ASSERT(aTreeMatchContext.mAncestorFilter.HasFilter(),
6960              "The whole point of having the tree match context is optimizing "
6961              "the ancestor filter usage!");
6962 
6963   aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
6964 
6965   // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
6966   // set) or issue content notifications for our kids first. In absence of
6967   // anything definitive either way we'll go with the latter.
6968 
6969   // It might be better to use GetChildArray and scan it completely first and
6970   // then issue all notifications. (We have to scan it completely first because
6971   // constructing frames can set attributes, which can change the storage of
6972   // child lists).
6973 
6974   // Scan the children of aContent to see what operations (if any) we need to
6975   // perform.
6976   bool inRun = false;
6977   nsIContent* firstChildInRun = nullptr;
6978   for (nsIContent* child = aContent->GetFirstChild(); child;
6979        child = child->GetNextSibling()) {
6980     if (child->HasFlag(NODE_NEEDS_FRAME)) {
6981       NS_ASSERTION(!child->GetPrimaryFrame() ||
6982                        child->GetPrimaryFrame()->GetContent() != child,
6983                    // XXX the child->GetPrimaryFrame()->GetContent() != child
6984                    // check is needed due to bug 135040. Remove it once that's
6985                    // fixed.
6986                    "NEEDS_FRAME set on a node that already has a frame?");
6987       if (!inRun) {
6988         inRun = true;
6989         firstChildInRun = child;
6990       }
6991     } else {
6992       if (inRun) {
6993         inRun = false;
6994         // generate a ContentRangeInserted for [startOfRun,i)
6995         ContentRangeInserted(aContent, firstChildInRun, child, nullptr,
6996                              InsertionKind::Sync, &aTreeMatchContext);
6997       }
6998     }
6999   }
7000 
7001   if (inRun) {
7002     ContentAppended(aContent, firstChildInRun, InsertionKind::Sync,
7003                     &aTreeMatchContext);
7004   }
7005 
7006   // Now descend.
7007   FlattenedChildIterator iter(aContent);
7008   for (nsIContent* child = iter.GetNextChild(); child;
7009        child = iter.GetNextChild()) {
7010     if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
7011       TreeMatchContext::AutoAncestorPusher insertionPointPusher(
7012           &aTreeMatchContext);
7013 
7014       // Handle stuff like xbl:children.
7015       if (child->GetParent() != aContent && child->GetParent()->IsElement()) {
7016         insertionPointPusher.PushAncestorAndStyleScope(
7017             child->GetParent()->AsElement());
7018       }
7019 
7020       TreeMatchContext::AutoAncestorPusher pusher(&aTreeMatchContext);
7021       pusher.PushAncestorAndStyleScope(child);
7022 
7023       CreateNeededFrames(child, aTreeMatchContext);
7024     }
7025   }
7026 }
7027 
CreateNeededFrames()7028 void nsCSSFrameConstructor::CreateNeededFrames() {
7029   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
7030                "Someone forgot a script blocker");
7031 
7032   Element* rootElement = mDocument->GetRootElement();
7033   NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME),
7034                "root element should not have frame created lazily");
7035   if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
7036     TreeMatchContext treeMatchContext(mDocument,
7037                                       TreeMatchContext::ForFrameConstruction);
7038     treeMatchContext.InitAncestors(rootElement);
7039     CreateNeededFrames(rootElement, treeMatchContext);
7040   }
7041 }
7042 #endif
7043 
IssueSingleInsertNofications(nsIContent * aContainer,nsIContent * aStartChild,nsIContent * aEndChild)7044 void nsCSSFrameConstructor::IssueSingleInsertNofications(
7045     nsIContent* aContainer, nsIContent* aStartChild, nsIContent* aEndChild) {
7046   for (nsIContent* child = aStartChild; child != aEndChild;
7047        child = child->GetNextSibling()) {
7048     // listboxes suck.
7049     MOZ_ASSERT(MaybeGetListBoxBodyFrame(aContainer, child) ||
7050                (!child->GetPrimaryFrame() && !GetDisplayNoneStyleFor(child) &&
7051                 !GetDisplayContentsStyleFor(child)));
7052 
7053     // Call ContentRangeInserted with this node.
7054     ContentRangeInserted(aContainer, child, child->GetNextSibling(),
7055                          mTempFrameTreeState, InsertionKind::Sync, nullptr);
7056   }
7057 }
7058 
IsMultiple() const7059 bool nsCSSFrameConstructor::InsertionPoint::IsMultiple() const {
7060   if (!mParentFrame) {
7061     return false;
7062   }
7063 
7064   // Fieldset frames have multiple normal flow child frame lists so handle it
7065   // the same as if it had multiple content insertion points.
7066   if (mParentFrame->IsFieldSetFrame()) {
7067     return true;
7068   }
7069 
7070   // A details frame moves the first summary frame to be its first child, so we
7071   // treat it as if it has multiple content insertion points.
7072   if (mParentFrame->IsDetailsFrame()) {
7073     return true;
7074   }
7075 
7076   return false;
7077 }
7078 
7079 nsCSSFrameConstructor::InsertionPoint
GetRangeInsertionPoint(nsIContent * aContainer,nsIContent * aStartChild,nsIContent * aEndChild)7080 nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aContainer,
7081                                               nsIContent* aStartChild,
7082                                               nsIContent* aEndChild) {
7083   MOZ_ASSERT(aStartChild);
7084 
7085   // If the children of the container may be distributed to different insertion
7086   // points, insert them separately and bail out, letting ContentInserted handle
7087   // the mess.
7088   if (aContainer->GetShadowRoot() || aContainer->GetXBLBinding()) {
7089     IssueSingleInsertNofications(aContainer, aStartChild, aEndChild);
7090     return {};
7091   }
7092 
7093 #ifdef DEBUG
7094   {
7095     nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
7096     for (nsIContent* child = aStartChild->GetNextSibling(); child;
7097          child = child->GetNextSibling()) {
7098       MOZ_ASSERT(child->GetFlattenedTreeParent() == expectedParent);
7099     }
7100   }
7101 #endif
7102 
7103   // Now the flattened tree parent of all the siblings is the same, just use the
7104   // same insertion point and take the fast path, unless it's a multiple
7105   // insertion point.
7106   InsertionPoint ip = GetInsertionPoint(aStartChild);
7107   if (ip.IsMultiple()) {
7108     IssueSingleInsertNofications(aContainer, aStartChild, aEndChild);
7109     return {};
7110   }
7111 
7112   return ip;
7113 }
7114 
MaybeRecreateForFrameset(nsIFrame * aParentFrame,nsIContent * aStartChild,nsIContent * aEndChild)7115 bool nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
7116                                                      nsIContent* aStartChild,
7117                                                      nsIContent* aEndChild) {
7118   if (aParentFrame->IsFrameSetFrame()) {
7119     // Check whether we have any kids we care about.
7120     for (nsIContent* cur = aStartChild; cur != aEndChild;
7121          cur = cur->GetNextSibling()) {
7122       if (IsSpecialFramesetChild(cur)) {
7123         // Just reframe the parent, since framesets are weird like that.
7124         RecreateFramesForContent(aParentFrame->GetContent(),
7125                                  InsertionKind::Async);
7126         return true;
7127       }
7128     }
7129   }
7130   return false;
7131 }
7132 
LazilyStyleNewChildRange(nsIContent * aStartChild,nsIContent * aEndChild)7133 void nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
7134                                                      nsIContent* aEndChild) {
7135   for (nsIContent* child = aStartChild; child != aEndChild;
7136        child = child->GetNextSibling()) {
7137     if (child->IsElement()) {
7138       child->AsElement()->NoteDirtyForServo();
7139     }
7140   }
7141 }
7142 
7143 #ifdef DEBUG
IsFlattenedTreeChild(nsIContent * aParent,nsIContent * aChild)7144 static bool IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild) {
7145   FlattenedChildIterator iter(aParent);
7146   for (nsIContent* node = iter.GetNextChild(); node;
7147        node = iter.GetNextChild()) {
7148     if (node == aChild) {
7149       return true;
7150     }
7151   }
7152   return false;
7153 }
7154 #endif
7155 
StyleNewChildRange(nsIContent * aStartChild,nsIContent * aEndChild)7156 void nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
7157                                                nsIContent* aEndChild) {
7158   ServoStyleSet* styleSet = mPresShell->StyleSet()->AsServo();
7159 
7160   for (nsIContent* child = aStartChild; child != aEndChild;
7161        child = child->GetNextSibling()) {
7162     if (child->IsElement() && !child->AsElement()->HasServoData()) {
7163       Element* parent = child->AsElement()->GetFlattenedTreeParentElement();
7164       // NB: Parent may be null if the content is appended to a shadow root, and
7165       // isn't assigned to any insertion point.
7166       if (MOZ_LIKELY(parent) && parent->HasServoData()) {
7167         MOZ_ASSERT(
7168             IsFlattenedTreeChild(parent, child),
7169             "GetFlattenedTreeParent and ChildIterator don't agree, fix this!");
7170         styleSet->StyleNewSubtree(child->AsElement());
7171       }
7172     }
7173   }
7174 }
7175 
ContentAppended(nsIContent * aContainer,nsIContent * aFirstNewContent,InsertionKind aInsertionKind,TreeMatchContext * aProvidedTreeMatchContext)7176 void nsCSSFrameConstructor::ContentAppended(
7177     nsIContent* aContainer, nsIContent* aFirstNewContent,
7178     InsertionKind aInsertionKind, TreeMatchContext* aProvidedTreeMatchContext) {
7179   MOZ_ASSERT(!aProvidedTreeMatchContext ||
7180              aInsertionKind == InsertionKind::Sync);
7181   MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
7182              !RestyleManager()->IsInStyleRefresh());
7183 
7184   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7185 
7186 #ifdef DEBUG
7187   if (gNoisyContentUpdates) {
7188     printf(
7189         "nsCSSFrameConstructor::ContentAppended container=%p "
7190         "first-child=%p lazy=%d\n",
7191         static_cast<void*>(aContainer), aFirstNewContent,
7192         aInsertionKind == InsertionKind::Async);
7193     if (gReallyNoisyContentUpdates && aContainer) {
7194       aContainer->List(stdout, 0);
7195     }
7196   }
7197 #endif
7198 
7199 #ifdef DEBUG
7200   for (nsIContent* child = aFirstNewContent; child;
7201        child = child->GetNextSibling()) {
7202     // XXX the GetContent() != child check is needed due to bug 135040.
7203     // Remove it once that's fixed.
7204     NS_ASSERTION(
7205         !child->GetPrimaryFrame() ||
7206             child->GetPrimaryFrame()->GetContent() != child,
7207         "asked to construct a frame for a node that already has a frame");
7208   }
7209 #endif
7210 
7211 #ifdef MOZ_XUL
7212   if (aContainer) {
7213     int32_t namespaceID;
7214     nsAtom* tag =
7215         mDocument->BindingManager()->ResolveTag(aContainer, &namespaceID);
7216 
7217     // Just ignore tree tags, anyway we don't create any frames for them.
7218     if (tag == nsGkAtoms::treechildren || tag == nsGkAtoms::treeitem ||
7219         tag == nsGkAtoms::treerow)
7220       return;
7221   }
7222 #endif  // MOZ_XUL
7223 
7224   // See comment in ContentRangeInserted for why this is necessary.
7225   if (!GetContentInsertionFrameFor(aContainer) &&
7226       !aContainer->IsActiveChildrenElement()) {
7227     // We're punting on frame construction because there's no container frame.
7228     // The Servo-backed style system handles this case like the lazy frame
7229     // construction case, except when we're already constructing frames, in
7230     // which case we shouldn't need to do anything else.
7231     if (aContainer->IsStyledByServo() &&
7232         aInsertionKind == InsertionKind::Async) {
7233       LazilyStyleNewChildRange(aFirstNewContent, nullptr);
7234     }
7235     return;
7236   }
7237 
7238   if (aInsertionKind == InsertionKind::Async &&
7239       MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
7240     if (aContainer->IsStyledByServo()) {
7241       LazilyStyleNewChildRange(aFirstNewContent, nullptr);
7242     }
7243     return;
7244   }
7245 
7246   // We couldn't construct lazily. Make Servo eagerly traverse the new content
7247   // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
7248   // styles are up-to-date already).
7249   if (aInsertionKind == InsertionKind::Async && aContainer->IsStyledByServo()) {
7250     StyleNewChildRange(aFirstNewContent, nullptr);
7251   }
7252 
7253   LAYOUT_PHASE_TEMP_EXIT();
7254   InsertionPoint insertion =
7255       GetRangeInsertionPoint(aContainer, aFirstNewContent, nullptr);
7256   nsContainerFrame*& parentFrame = insertion.mParentFrame;
7257   LAYOUT_PHASE_TEMP_REENTER();
7258   if (!parentFrame) {
7259     return;
7260   }
7261 
7262   LAYOUT_PHASE_TEMP_EXIT();
7263   if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
7264     LAYOUT_PHASE_TEMP_REENTER();
7265     return;
7266   }
7267   LAYOUT_PHASE_TEMP_REENTER();
7268 
7269   if (parentFrame->IsLeaf()) {
7270     // Nothing to do here; we shouldn't be constructing kids of leaves
7271     // Clear lazy bits so we don't try to construct again.
7272     ClearLazyBits(aFirstNewContent, nullptr);
7273     return;
7274   }
7275 
7276   if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7277     LAYOUT_PHASE_TEMP_EXIT();
7278     RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
7279     LAYOUT_PHASE_TEMP_REENTER();
7280     return;
7281   }
7282 
7283 #ifdef DEBUG
7284   if (gNoisyContentUpdates && IsFramePartOfIBSplit(parentFrame)) {
7285     printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
7286     nsFrame::ListTag(stdout, parentFrame);
7287     printf(" is ib-split\n");
7288   }
7289 #endif
7290 
7291   // We should never get here with fieldsets or details, since they have
7292   // multiple insertion points.
7293   MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
7294              "Parent frame should not be fieldset or details!");
7295 
7296   // Deal with possible :after generated content on the parent, or display:
7297   // contents.
7298   nsIFrame* nextSibling = nullptr;
7299   if (GetDisplayContentsStyleFor(insertion.mContainer) ||
7300       nsLayoutUtils::GetAfterFrame(insertion.mContainer)) {
7301     FlattenedChildIterator iter(insertion.mContainer);
7302     iter.Seek(insertion.mContainer->GetLastChild());
7303     StyleDisplay unused = UNSET_DISPLAY;
7304     nextSibling = FindNextSibling(iter, unused);
7305   }
7306 
7307   if (nextSibling) {
7308     parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7309   } else {
7310     parentFrame = ::ContinuationToAppendTo(parentFrame);
7311   }
7312 
7313   nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
7314 
7315   // See if the containing block has :first-letter style applied.
7316   const bool haveFirstLetterStyle =
7317       containingBlock && HasFirstLetterStyle(containingBlock);
7318 
7319   const bool haveFirstLineStyle =
7320       containingBlock &&
7321       ShouldHaveFirstLineStyle(containingBlock->GetContent(),
7322                                containingBlock->StyleContext());
7323 
7324   if (haveFirstLetterStyle) {
7325     AutoWeakFrame wf(nextSibling);
7326 
7327     // Before we get going, remove the current letter frames
7328     RemoveLetterFrames(mPresShell, containingBlock);
7329 
7330     // Reget nextSibling, since we may have killed it.
7331     //
7332     // FIXME(emilio): This kinda sucks! :(
7333     if (nextSibling && !wf) {
7334       FlattenedChildIterator iter(insertion.mContainer);
7335       iter.Seek(insertion.mContainer->GetLastChild());
7336       StyleDisplay unused = UNSET_DISPLAY;
7337       nextSibling = FindNextSibling(iter, unused);
7338       if (nextSibling) {
7339         parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7340         containingBlock = GetFloatContainingBlock(parentFrame);
7341       }
7342     }
7343   }
7344 
7345   // Create some new frames
7346   //
7347   // We use the provided tree match context, or create a new one on the fly
7348   // otherwise.
7349   Maybe<TreeMatchContext> matchContext;
7350   if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
7351     // We use GetParentElementCrossingShadowRoot to handle the case where
7352     // aContainer is a ShadowRoot.
7353     matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
7354     matchContext->InitAncestors(
7355         aFirstNewContent->GetParentElementCrossingShadowRoot());
7356   }
7357   nsFrameConstructorState state(
7358       mPresShell, matchContext.ptrOr(aProvidedTreeMatchContext),
7359       GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
7360       GetAbsoluteContainingBlock(parentFrame, ABS_POS), containingBlock);
7361 
7362   LayoutFrameType frameType = parentFrame->Type();
7363 
7364   FlattenedChildIterator iter(aContainer);
7365   const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
7366 
7367   AutoFrameConstructionItemList items(this);
7368   if (aFirstNewContent->GetPreviousSibling() &&
7369       GetParentType(frameType) == eTypeBlock && haveNoXBLChildren) {
7370     // If there's a text node in the normal content list just before the new
7371     // items, and it has no frame, make a frame construction item for it. If it
7372     // doesn't need a frame, ConstructFramesFromItemList below won't give it
7373     // one.  No need to do all this if our parent type is not block, though,
7374     // since WipeContainingBlock already handles that situation.
7375     //
7376     // Because we're appending, we don't need to worry about any text
7377     // after the appended content; there can only be XBL anonymous content
7378     // (text in an XBL binding is not suppressed) or generated content
7379     // (and bare text nodes are not generated). Native anonymous content
7380     // generated by frames never participates in inline layout.
7381     AddTextItemIfNeeded(state, insertion,
7382                         aFirstNewContent->GetPreviousSibling(), items);
7383   }
7384   for (nsIContent* child = aFirstNewContent; child;
7385        child = child->GetNextSibling()) {
7386     AddFrameConstructionItems(state, child, false, insertion, items);
7387   }
7388 
7389   nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, nextSibling);
7390 
7391   // Perform special check for diddling around with the frames in
7392   // a ib-split inline frame.
7393   // If we're appending before :after content, then we're not really
7394   // appending, so let WipeContainingBlock know that.
7395   LAYOUT_PHASE_TEMP_EXIT();
7396   if (WipeContainingBlock(state, containingBlock, parentFrame, items, true,
7397                           prevSibling)) {
7398     LAYOUT_PHASE_TEMP_REENTER();
7399     return;
7400   }
7401   LAYOUT_PHASE_TEMP_REENTER();
7402 
7403   // If the parent is a block frame, and we're not in a special case
7404   // where frames can be moved around, determine if the list is for the
7405   // start or end of the block.
7406   if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
7407       !haveFirstLineStyle && !IsFramePartOfIBSplit(parentFrame)) {
7408     items.SetLineBoundaryAtStart(!prevSibling ||
7409                                  !prevSibling->IsInlineOutside() ||
7410                                  prevSibling->IsBrFrame());
7411     // :after content can't be <br> so no need to check it
7412     //
7413     // FIXME(emilio): A display: contents sibling could! Write a test-case and
7414     // fix.
7415     items.SetLineBoundaryAtEnd(!nextSibling || !nextSibling->IsInlineOutside());
7416   }
7417   // To suppress whitespace-only text frames, we have to verify that
7418   // our container's DOM child list matches its flattened tree child list.
7419   items.SetParentHasNoXBLChildren(haveNoXBLChildren);
7420 
7421   nsFrameItems frameItems;
7422   ConstructFramesFromItemList(state, items, parentFrame,
7423                               ParentIsWrapperAnonBox(parentFrame), frameItems);
7424 
7425   for (nsIContent* child = aFirstNewContent; child;
7426        child = child->GetNextSibling()) {
7427     // Invalidate now instead of before the WipeContainingBlock call, just in
7428     // case we do wipe; in that case we don't need to do this walk at all.
7429     // XXXbz does that matter?  Would it make more sense to save some virtual
7430     // GetChildAt_Deprecated calls instead and do this during construction of
7431     // our FrameConstructionItemList?
7432     InvalidateCanvasIfNeeded(mPresShell, child);
7433   }
7434 
7435   // If the container is a table and a caption was appended, it needs to be put
7436   // in the table wrapper frame's additional child list.
7437   nsFrameItems captionItems;
7438   if (LayoutFrameType::Table == frameType) {
7439     // Pull out the captions.  Note that we don't want to do that as we go,
7440     // because processing a single caption can add a whole bunch of things to
7441     // the frame items due to pseudoframe processing.  So we'd have to pull
7442     // captions from a list anyway; might as well do that here.
7443     // XXXbz this is no longer true; we could pull captions directly out of the
7444     // FrameConstructionItemList now.
7445     PullOutCaptionFrames(frameItems, captionItems);
7446   }
7447 
7448   if (haveFirstLineStyle && parentFrame == containingBlock) {
7449     // It's possible that some of the new frames go into a
7450     // first-line frame. Look at them and see...
7451     AppendFirstLineFrames(state, containingBlock->GetContent(), containingBlock,
7452                           frameItems);
7453     // That moved things into line frames as needed, reparenting their
7454     // styles.  Nothing else needs to be done.
7455   } else if (parentFrame->StyleContext()->HasPseudoElementData()) {
7456     // parentFrame might be inside a ::first-line frame.  Check whether it is,
7457     // and if so fix up our styles.
7458     CheckForFirstLineInsertion(parentFrame, frameItems);
7459     CheckForFirstLineInsertion(parentFrame, captionItems);
7460   }
7461 
7462   // Notify the parent frame passing it the list of new frames
7463   // Append the flowed frames to the principal child list; captions
7464   // need special treatment
7465   if (captionItems.NotEmpty()) {  // append the caption to the table wrapper
7466     NS_ASSERTION(LayoutFrameType::Table == frameType, "how did that happen?");
7467     nsContainerFrame* outerTable = parentFrame->GetParent();
7468     AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7469   }
7470 
7471   if (frameItems.NotEmpty()) {  // append the in-flow kids
7472     AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
7473   }
7474 
7475   // Recover first-letter frames
7476   if (haveFirstLetterStyle) {
7477     RecoverLetterFrames(containingBlock);
7478   }
7479 
7480 #ifdef DEBUG
7481   if (gReallyNoisyContentUpdates) {
7482     printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
7483     parentFrame->List(stdout, 0);
7484   }
7485 #endif
7486 
7487 #ifdef ACCESSIBILITY
7488   if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7489     accService->ContentRangeInserted(mPresShell, aContainer, aFirstNewContent,
7490                                      nullptr);
7491   }
7492 #endif
7493 }
7494 
7495 #ifdef MOZ_XUL
7496 
7497 enum content_operation { CONTENT_INSERTED, CONTENT_REMOVED };
7498 
7499 // Helper function to lookup the listbox body frame and send a notification
7500 // for insertion or removal of content
NotifyListBoxBody(nsPresContext * aPresContext,nsIContent * aContainer,nsIContent * aChild,nsIContent * aOldNextSibling,nsIFrame * aChildFrame,content_operation aOperation)7501 static bool NotifyListBoxBody(nsPresContext* aPresContext,
7502                               nsIContent* aContainer, nsIContent* aChild,
7503                               // Only used for the removed notification
7504                               nsIContent* aOldNextSibling,
7505                               nsIFrame* aChildFrame,
7506                               content_operation aOperation) {
7507   nsListBoxBodyFrame* listBoxBodyFrame =
7508       MaybeGetListBoxBodyFrame(aContainer, aChild);
7509   if (listBoxBodyFrame) {
7510     if (aOperation == CONTENT_REMOVED) {
7511       // Except if we have an aChildFrame and its parent is not the right
7512       // thing, then we don't do this.  Pseudo frames are so much fun....
7513       if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) {
7514         listBoxBodyFrame->OnContentRemoved(aPresContext, aContainer,
7515                                            aChildFrame, aOldNextSibling);
7516         return true;
7517       }
7518     } else {
7519       listBoxBodyFrame->OnContentInserted(aChild);
7520       return true;
7521     }
7522   }
7523 
7524   return false;
7525 }
7526 #endif  // MOZ_XUL
7527 
ContentInserted(nsIContent * aContainer,nsIContent * aChild,nsILayoutHistoryState * aFrameState,InsertionKind aInsertionKind)7528 void nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
7529                                             nsIContent* aChild,
7530                                             nsILayoutHistoryState* aFrameState,
7531                                             InsertionKind aInsertionKind) {
7532   ContentRangeInserted(aContainer, aChild, aChild->GetNextSibling(),
7533                        aFrameState, aInsertionKind);
7534 }
7535 
7536 // ContentRangeInserted handles creating frames for a range of nodes that
7537 // aren't at the end of their childlist. ContentRangeInserted isn't a real
7538 // content notification, but rather it handles regular ContentInserted calls
7539 // for a single node as well as the lazy construction of frames for a range of
7540 // nodes when called from CreateNeededFrames. For a range of nodes to be
7541 // suitable to have its frames constructed all at once they must meet the same
7542 // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
7543 // these), plus more. Namely when finding the insertion prevsibling we must not
7544 // need to consult something specific to any one node in the range, so that the
7545 // insertion prevsibling would be the same for each node in the range. So we
7546 // pass the first node in the range to GetInsertionPrevSibling, and if
7547 // IsValidSibling (the only place GetInsertionPrevSibling might look at the
7548 // passed in node itself) needs to resolve style on the node we record this and
7549 // return that this range needs to be split up and inserted separately. Table
7550 // captions need extra attention as we need to determine where to insert them
7551 // in the caption list, while skipping any nodes in the range being inserted
7552 // (because when we treat the caption frames the other nodes have had their
7553 // frames constructed but not yet inserted into the frame tree).
ContentRangeInserted(nsIContent * aContainer,nsIContent * aStartChild,nsIContent * aEndChild,nsILayoutHistoryState * aFrameState,InsertionKind aInsertionKind,TreeMatchContext * aProvidedTreeMatchContext)7554 void nsCSSFrameConstructor::ContentRangeInserted(
7555     nsIContent* aContainer, nsIContent* aStartChild, nsIContent* aEndChild,
7556     nsILayoutHistoryState* aFrameState, InsertionKind aInsertionKind,
7557     TreeMatchContext* aProvidedTreeMatchContext) {
7558   MOZ_ASSERT(!aProvidedTreeMatchContext ||
7559              aInsertionKind == InsertionKind::Sync);
7560   MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
7561              !RestyleManager()->IsInStyleRefresh());
7562 
7563   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7564 
7565   NS_PRECONDITION(aStartChild, "must always pass a child");
7566 
7567 #ifdef DEBUG
7568   if (gNoisyContentUpdates) {
7569     printf(
7570         "nsCSSFrameConstructor::ContentRangeInserted container=%p "
7571         "start-child=%p end-child=%p lazy=%d\n",
7572         static_cast<void*>(aContainer), static_cast<void*>(aStartChild),
7573         static_cast<void*>(aEndChild), aInsertionKind == InsertionKind::Async);
7574     if (gReallyNoisyContentUpdates) {
7575       if (aContainer) {
7576         aContainer->List(stdout, 0);
7577       } else {
7578         aStartChild->List(stdout, 0);
7579       }
7580     }
7581   }
7582 
7583   for (nsIContent* child = aStartChild; child != aEndChild;
7584        child = child->GetNextSibling()) {
7585     // XXX the GetContent() != child check is needed due to bug 135040.
7586     // Remove it once that's fixed.
7587     NS_ASSERTION(
7588         !child->GetPrimaryFrame() ||
7589             child->GetPrimaryFrame()->GetContent() != child,
7590         "asked to construct a frame for a node that already has a frame");
7591   }
7592 #endif
7593 
7594   auto styleNewChildRangeEagerly = [this, aInsertionKind, aContainer,
7595                                     aStartChild, aEndChild]() {
7596     // When aInsertionKind == InsertionKind::Sync, we know that the
7597     // styles are up-to-date already.
7598     if (aInsertionKind == InsertionKind::Async &&
7599         aContainer->IsStyledByServo()) {
7600       StyleNewChildRange(aStartChild, aEndChild);
7601     }
7602   };
7603 
7604   bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
7605   NS_ASSERTION(isSingleInsert || aInsertionKind == InsertionKind::Sync,
7606                "range insert shouldn't be lazy");
7607   NS_ASSERTION(isSingleInsert || aEndChild,
7608                "range should not include all nodes after aStartChild");
7609 
7610 #ifdef MOZ_XUL
7611   if (aContainer && IsXULListBox(aContainer)) {
7612     // For XUL list box, we need to style the new children eagerly.
7613     styleNewChildRangeEagerly();
7614     if (isSingleInsert) {
7615       if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer,
7616                             // The insert case in NotifyListBoxBody
7617                             // doesn't use "old next sibling".
7618                             aStartChild, nullptr, nullptr, CONTENT_INSERTED)) {
7619         return;
7620       }
7621     } else {
7622       // We don't handle a range insert to a listbox parent, issue single
7623       // ContertInserted calls for each node inserted.
7624       LAYOUT_PHASE_TEMP_EXIT();
7625       IssueSingleInsertNofications(aContainer, aStartChild, aEndChild);
7626       LAYOUT_PHASE_TEMP_REENTER();
7627       return;
7628     }
7629   }
7630 #endif  // MOZ_XUL
7631 
7632   // If we have a null parent, then this must be the document element being
7633   // inserted, or some other child of the document in the DOM (might be a PI,
7634   // say).
7635   if (!aContainer) {
7636     NS_ASSERTION(isSingleInsert,
7637                  "root node insertion should be a single insertion");
7638     Element* docElement = mDocument->GetRootElement();
7639 
7640     if (aStartChild != docElement) {
7641       // Not the root element; just bail out
7642       return;
7643     }
7644 
7645     NS_PRECONDITION(!mRootElementFrame, "root element frame already created");
7646 
7647     // Create frames for the document element and its child elements
7648     if (ConstructDocElementFrame(docElement, aFrameState)) {
7649       InvalidateCanvasIfNeeded(mPresShell, aStartChild);
7650 #ifdef DEBUG
7651       if (gReallyNoisyContentUpdates) {
7652         printf(
7653             "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
7654             "model:\n");
7655         mRootElementFrame->List(stdout, 0);
7656       }
7657 #endif
7658     }
7659 
7660     if (aFrameState) {
7661       // Restore frame state for the root scroll frame if there is one
7662       if (nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame()) {
7663         RestoreFrameStateFor(rootScrollFrame, aFrameState);
7664       }
7665     }
7666 
7667 #ifdef ACCESSIBILITY
7668     if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7669       accService->ContentRangeInserted(mPresShell, aContainer, aStartChild,
7670                                        aEndChild);
7671     }
7672 #endif
7673 
7674     return;
7675   }
7676 
7677   nsContainerFrame* parentFrame = GetContentInsertionFrameFor(aContainer);
7678   // The xbl:children element won't have a frame, but default content can have
7679   // the children as a parent. While its uncommon to change the structure of the
7680   // default content itself, a label, for example, can be reframed by having its
7681   // value attribute set or removed.
7682   if (!parentFrame &&
7683       !(aContainer->IsActiveChildrenElement() || aContainer->IsShadowRoot())) {
7684     // We're punting on frame construction because there's no container frame.
7685     // The Servo-backed style system handles this case like the lazy frame
7686     // construction case, except when we're already constructing frames, in
7687     // which case we shouldn't need to do anything else.
7688     if (aContainer->IsStyledByServo() &&
7689         aInsertionKind == InsertionKind::Async) {
7690       LazilyStyleNewChildRange(aStartChild, aEndChild);
7691     }
7692     return;
7693   }
7694 
7695   MOZ_ASSERT_IF(aContainer->IsShadowRoot(), !parentFrame);
7696 
7697   // Otherwise, we've got parent content. Find its frame.
7698   NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer ||
7699                    GetDisplayContentsStyleFor(aContainer),
7700                "New XBL code is possibly wrong!");
7701 
7702   if (aInsertionKind == InsertionKind::Async &&
7703       MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
7704     if (aContainer->IsStyledByServo()) {
7705       LazilyStyleNewChildRange(aStartChild, aEndChild);
7706     }
7707     return;
7708   }
7709 
7710   // We couldn't construct lazily. Make Servo eagerly traverse the new content
7711   // if needed.
7712   styleNewChildRangeEagerly();
7713 
7714   InsertionPoint insertion;
7715   if (isSingleInsert) {
7716     // See if we have an XBL insertion point. If so, then that's our
7717     // real parent frame; if not, then the frame hasn't been built yet
7718     // and we just bail.
7719     insertion = GetInsertionPoint(aStartChild);
7720   } else {
7721     // Get our insertion point. If we need to issue single ContentInserted's
7722     // GetRangeInsertionPoint will take care of that for us.
7723     LAYOUT_PHASE_TEMP_EXIT();
7724     insertion = GetRangeInsertionPoint(aContainer, aStartChild, aEndChild);
7725     LAYOUT_PHASE_TEMP_REENTER();
7726   }
7727 
7728   if (!insertion.mParentFrame) {
7729     return;
7730   }
7731 
7732   bool isAppend, isRangeInsertSafe;
7733   nsIFrame* prevSibling = GetInsertionPrevSibling(
7734       &insertion, aStartChild, &isAppend, &isRangeInsertSafe);
7735 
7736   // check if range insert is safe
7737   if (!isSingleInsert && !isRangeInsertSafe) {
7738     // must fall back to a single ContertInserted for each child in the range
7739     LAYOUT_PHASE_TEMP_EXIT();
7740     IssueSingleInsertNofications(aContainer, aStartChild, aEndChild);
7741     LAYOUT_PHASE_TEMP_REENTER();
7742     return;
7743   }
7744 
7745   LayoutFrameType frameType = insertion.mParentFrame->Type();
7746   LAYOUT_PHASE_TEMP_EXIT();
7747   if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild,
7748                                aEndChild)) {
7749     LAYOUT_PHASE_TEMP_REENTER();
7750     return;
7751   }
7752   LAYOUT_PHASE_TEMP_REENTER();
7753 
7754   // We should only get here with fieldsets when doing a single insert, because
7755   // fieldsets have multiple insertion points.
7756   NS_ASSERTION(isSingleInsert || frameType != LayoutFrameType::FieldSet,
7757                "Unexpected parent");
7758   if (IsFrameForFieldSet(insertion.mParentFrame) &&
7759       aStartChild->NodeInfo()->NameAtom() == nsGkAtoms::legend) {
7760     // Just reframe the parent, since figuring out whether this
7761     // should be the new legend and then handling it is too complex.
7762     // We could do a little better here --- check if the fieldset already
7763     // has a legend which occurs earlier in its child list than this node,
7764     // and if so, proceed. But we'd have to extend nsFieldSetFrame
7765     // to locate this legend in the inserted frames and extract it.
7766     LAYOUT_PHASE_TEMP_EXIT();
7767     RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7768                              InsertionKind::Async);
7769     LAYOUT_PHASE_TEMP_REENTER();
7770     return;
7771   }
7772 
7773   // We should only get here with details when doing a single insertion because
7774   // we treat details frame as if it has multiple insertion points.
7775   MOZ_ASSERT(isSingleInsert || frameType != LayoutFrameType::Details);
7776   if (frameType == LayoutFrameType::Details) {
7777     // When inserting an element into <details>, just reframe the details frame
7778     // and let it figure out where the element should be laid out. It might seem
7779     // expensive to recreate the entire details frame, but it's the simplest way
7780     // to handle the insertion.
7781     LAYOUT_PHASE_TEMP_EXIT();
7782     RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7783                              InsertionKind::Async);
7784     LAYOUT_PHASE_TEMP_REENTER();
7785     return;
7786   }
7787 
7788   // Don't construct kids of leaves
7789   if (insertion.mParentFrame->IsLeaf()) {
7790     // Clear lazy bits so we don't try to construct again.
7791     ClearLazyBits(aStartChild, aEndChild);
7792     return;
7793   }
7794 
7795   // FIXME(emilio): This looks terribly inefficient if you insert elements deep
7796   // in a MathML subtree.
7797   if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7798     LAYOUT_PHASE_TEMP_EXIT();
7799     RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7800                              InsertionKind::Async);
7801     LAYOUT_PHASE_TEMP_REENTER();
7802     return;
7803   }
7804 
7805   Maybe<TreeMatchContext> matchContext;
7806   if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
7807     // We use GetParentElementCrossingShadowRoot to handle the case where
7808     // aContainer is a ShadowRoot.
7809     matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
7810     matchContext->InitAncestors(
7811         aStartChild->GetParentElementCrossingShadowRoot());
7812   }
7813   nsFrameConstructorState state(
7814       mPresShell, matchContext.ptrOr(aProvidedTreeMatchContext),
7815       GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
7816       GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
7817       GetFloatContainingBlock(insertion.mParentFrame), do_AddRef(aFrameState));
7818 
7819   // Recover state for the containing block - we need to know if
7820   // it has :first-letter or :first-line style applied to it. The
7821   // reason we care is that the internal structure in these cases
7822   // is not the normal structure and requires custom updating
7823   // logic.
7824   nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
7825   bool haveFirstLetterStyle = false;
7826   bool haveFirstLineStyle = false;
7827 
7828   // In order to shave off some cycles, we only dig up the
7829   // containing block haveFirst* flags if the parent frame where
7830   // the insertion/append is occurring is an inline or block
7831   // container. For other types of containers this isn't relevant.
7832   StyleDisplay parentDisplay = insertion.mParentFrame->GetDisplay();
7833 
7834   // Examine the insertion.mParentFrame where the insertion is taking
7835   // place. If it's a certain kind of container then some special
7836   // processing is done.
7837   if ((StyleDisplay::Block == parentDisplay) ||
7838       (StyleDisplay::ListItem == parentDisplay) ||
7839       (StyleDisplay::Inline == parentDisplay) ||
7840       (StyleDisplay::InlineBlock == parentDisplay)) {
7841     // Recover the special style flags for the containing block
7842     if (containingBlock) {
7843       haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
7844       haveFirstLineStyle = ShouldHaveFirstLineStyle(
7845           containingBlock->GetContent(), containingBlock->StyleContext());
7846     }
7847 
7848     if (haveFirstLetterStyle) {
7849       // If our current insertion.mParentFrame is a Letter frame, use its parent
7850       // as our new parent hint
7851       if (insertion.mParentFrame->IsLetterFrame()) {
7852         // If insertion.mParentFrame is out of flow, then we actually want the
7853         // parent of the placeholder frame.
7854         if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7855           nsPlaceholderFrame* placeholderFrame =
7856               insertion.mParentFrame->GetPlaceholderFrame();
7857           NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
7858           insertion.mParentFrame = placeholderFrame->GetParent();
7859         } else {
7860           insertion.mParentFrame = insertion.mParentFrame->GetParent();
7861         }
7862       }
7863 
7864       // Remove the old letter frames before doing the insertion
7865       RemoveLetterFrames(mPresShell, state.mFloatedItems.containingBlock);
7866 
7867       // Removing the letterframes messes around with the frame tree, removing
7868       // and creating frames.  We need to reget our prevsibling, parent frame,
7869       // etc.
7870       prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend,
7871                                             &isRangeInsertSafe);
7872 
7873       // Need check whether a range insert is still safe.
7874       if (!isSingleInsert && !isRangeInsertSafe) {
7875         // Need to recover the letter frames first.
7876         RecoverLetterFrames(state.mFloatedItems.containingBlock);
7877 
7878         // must fall back to a single ContertInserted for each child in the
7879         // range
7880         LAYOUT_PHASE_TEMP_EXIT();
7881         IssueSingleInsertNofications(aContainer, aStartChild, aEndChild);
7882         LAYOUT_PHASE_TEMP_REENTER();
7883         return;
7884       }
7885 
7886       frameType = insertion.mParentFrame->Type();
7887     }
7888   }
7889 
7890   AutoFrameConstructionItemList items(this);
7891   ParentType parentType = GetParentType(frameType);
7892   FlattenedChildIterator iter(aContainer);
7893   bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
7894   if (aStartChild->GetPreviousSibling() && parentType == eTypeBlock &&
7895       haveNoXBLChildren) {
7896     // If there's a text node in the normal content list just before the
7897     // new nodes, and it has no frame, make a frame construction item for
7898     // it, because it might need a frame now.  No need to do this if our
7899     // parent type is not block, though, since WipeContainingBlock
7900     // already handles that sitation.
7901     AddTextItemIfNeeded(state, insertion, aStartChild->GetPreviousSibling(),
7902                         items);
7903   }
7904 
7905   if (isSingleInsert) {
7906     AddFrameConstructionItems(state, aStartChild,
7907                               aStartChild->IsRootOfAnonymousSubtree(),
7908                               insertion, items);
7909   } else {
7910     for (nsIContent* child = aStartChild; child != aEndChild;
7911          child = child->GetNextSibling()) {
7912       AddFrameConstructionItems(state, child, false, insertion, items);
7913     }
7914   }
7915 
7916   if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) {
7917     // If there's a text node in the normal content list just after the
7918     // new nodes, and it has no frame, make a frame construction item for
7919     // it, because it might need a frame now.  No need to do this if our
7920     // parent type is not block, though, since WipeContainingBlock
7921     // already handles that sitation.
7922     AddTextItemIfNeeded(state, insertion, aEndChild, items);
7923   }
7924 
7925   // Perform special check for diddling around with the frames in
7926   // a special inline frame.
7927   // If we're appending before :after content, then we're not really
7928   // appending, so let WipeContainingBlock know that.
7929   LAYOUT_PHASE_TEMP_EXIT();
7930   if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
7931                           isAppend, prevSibling)) {
7932     LAYOUT_PHASE_TEMP_REENTER();
7933     return;
7934   }
7935   LAYOUT_PHASE_TEMP_REENTER();
7936 
7937   // If the container is a table and a caption will be appended, it needs to be
7938   // put in the table wrapper frame's additional child list.
7939   // We make no attempt here to set flags to indicate whether the list
7940   // will be at the start or end of a block. It doesn't seem worthwhile.
7941   nsFrameItems frameItems, captionItems;
7942   ConstructFramesFromItemList(state, items, insertion.mParentFrame,
7943                               ParentIsWrapperAnonBox(insertion.mParentFrame),
7944                               frameItems);
7945 
7946   if (frameItems.NotEmpty()) {
7947     for (nsIContent* child = aStartChild; child != aEndChild;
7948          child = child->GetNextSibling()) {
7949       InvalidateCanvasIfNeeded(mPresShell, child);
7950     }
7951 
7952     if (LayoutFrameType::Table == frameType ||
7953         LayoutFrameType::TableWrapper == frameType) {
7954       PullOutCaptionFrames(frameItems, captionItems);
7955     }
7956   }
7957 
7958   if (haveFirstLineStyle && insertion.mParentFrame == containingBlock &&
7959       isAppend) {
7960     // It's possible that the new frame goes into a first-line
7961     // frame. Look at it and see...
7962     AppendFirstLineFrames(state, containingBlock->GetContent(), containingBlock,
7963                           frameItems);
7964   } else if (insertion.mParentFrame->StyleContext()->HasPseudoElementData()) {
7965     CheckForFirstLineInsertion(insertion.mParentFrame, frameItems);
7966     CheckForFirstLineInsertion(insertion.mParentFrame, captionItems);
7967   }
7968 
7969   // We might have captions; put them into the caption list of the
7970   // table wrapper frame.
7971   if (captionItems.NotEmpty()) {
7972     NS_ASSERTION(LayoutFrameType::Table == frameType ||
7973                      LayoutFrameType::TableWrapper == frameType,
7974                  "parent for caption is not table?");
7975     // We need to determine where to put the caption items; start with the
7976     // the parent frame that has already been determined and get the insertion
7977     // prevsibling of the first caption item.
7978     bool captionIsAppend;
7979     nsIFrame* captionPrevSibling = nullptr;
7980 
7981     // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
7982     bool ignored;
7983     InsertionPoint captionInsertion(insertion.mParentFrame,
7984                                     insertion.mContainer);
7985     if (isSingleInsert) {
7986       captionPrevSibling = GetInsertionPrevSibling(
7987           &captionInsertion, aStartChild, &captionIsAppend, &ignored);
7988     } else {
7989       nsIContent* firstCaption = captionItems.FirstChild()->GetContent();
7990       // It is very important here that we skip the children in
7991       // [aStartChild,aEndChild) when looking for a
7992       // prevsibling.
7993       captionPrevSibling = GetInsertionPrevSibling(
7994           &captionInsertion, firstCaption, &captionIsAppend, &ignored,
7995           aStartChild, aEndChild);
7996     }
7997 
7998     nsContainerFrame* outerTable = nullptr;
7999     if (GetCaptionAdjustedParent(captionInsertion.mParentFrame,
8000                                  captionItems.FirstChild(), &outerTable)) {
8001       // If the parent is not a table wrapper frame we will try to add frames
8002       // to a named child list that the parent does not honor and the frames
8003       // will get lost.
8004       NS_ASSERTION(outerTable->IsTableWrapperFrame(),
8005                    "Pseudo frame construction failure; "
8006                    "a caption can be only a child of a table wrapper frame");
8007 
8008       // If the parent of our current prevSibling is different from the frame
8009       // we'll actually use as the parent, then the calculated insertion
8010       // point is now invalid (bug 341382).
8011       if (captionPrevSibling && captionPrevSibling->GetParent() != outerTable) {
8012         captionPrevSibling = nullptr;
8013       }
8014       if (captionIsAppend) {
8015         AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
8016       } else {
8017         InsertFrames(outerTable, nsIFrame::kCaptionList, captionPrevSibling,
8018                      captionItems);
8019       }
8020     }
8021   }
8022 
8023   if (frameItems.NotEmpty()) {
8024     // Notify the parent frame
8025     if (isAppend) {
8026       AppendFramesToParent(state, insertion.mParentFrame, frameItems,
8027                            prevSibling);
8028     } else {
8029       InsertFrames(insertion.mParentFrame, kPrincipalList, prevSibling,
8030                    frameItems);
8031     }
8032   }
8033 
8034   if (haveFirstLetterStyle) {
8035     // Recover the letter frames for the containing block when
8036     // it has first-letter style.
8037     RecoverLetterFrames(state.mFloatedItems.containingBlock);
8038   }
8039 
8040 #ifdef DEBUG
8041   if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
8042     printf(
8043         "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
8044         "model:\n");
8045     insertion.mParentFrame->List(stdout, 0);
8046   }
8047 #endif
8048 
8049 #ifdef ACCESSIBILITY
8050   if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
8051     accService->ContentRangeInserted(mPresShell, aContainer, aStartChild,
8052                                      aEndChild);
8053   }
8054 #endif
8055 }
8056 
ContentRemoved(nsIContent * aContainer,nsIContent * aChild,nsIContent * aOldNextSibling,RemoveFlags aFlags)8057 bool nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
8058                                            nsIContent* aChild,
8059                                            nsIContent* aOldNextSibling,
8060                                            RemoveFlags aFlags) {
8061   MOZ_ASSERT(aChild);
8062   MOZ_ASSERT(!aChild->IsRootOfAnonymousSubtree() || !aOldNextSibling,
8063              "Anonymous roots don't have siblings");
8064   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
8065   nsPresContext* presContext = mPresShell->GetPresContext();
8066   MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
8067 
8068   // We want to detect when the viewport override element stored in the
8069   // prescontext is in the subtree being removed.  Except in fullscreen cases
8070   // (which are handled in Element::UnbindFromTree and do not get stored on the
8071   // prescontext), the override element is always either the root element or a
8072   // <body> child of the root element.  So we can only be removing the stored
8073   // override element if the thing being removed is either the override element
8074   // itself or the root element (which can be a parent of the override element).
8075   if (aChild == presContext->GetViewportScrollbarStylesOverrideElement() ||
8076       (!aContainer && aChild->IsElement())) {
8077     // We might be removing the element that we propagated viewport scrollbar
8078     // styles from.  Recompute those. (This clause covers two of the three
8079     // possible scrollbar-propagation sources: the <body> [as aChild or a
8080     // descendant] and the root node. The other possible scrollbar-propagation
8081     // source is a fullscreen element, and we have code elsewhere to update
8082     // scrollbars after fullscreen elements are removed -- specifically, it's
8083     // part of the fullscreen cleanup code called by Element::UnbindFromTree.
8084     // We don't handle the fullscreen case here, because it doesn't change the
8085     // scrollbar styles override element stored on the prescontext.)
8086     Element* newOverrideElement =
8087         presContext->UpdateViewportScrollbarStylesOverride();
8088 
8089     // If aChild is the root (i.e. aContainer is null), then we don't
8090     // need to do any reframing of newOverrideElement, because we're
8091     // about to tear down the whole frame tree anyway.  And we need to
8092     // make sure we don't do any such reframing, because reframing the
8093     // <body> can trigger a reframe of the <html> and then reenter
8094     // here.
8095     //
8096     // But if aChild is not the root, and if newOverrideElement is not
8097     // the root and isn't aChild (which it could be if all we're doing
8098     // here is reframing the current override element), it needs
8099     // reframing.  In particular, it used to have a scrollframe
8100     // (because its overflow was not "visible"), but now it will
8101     // propagate its overflow to the viewport, so it should not need a
8102     // scrollframe anymore.
8103     if (aContainer && newOverrideElement && newOverrideElement->GetParent() &&
8104         newOverrideElement != aChild) {
8105       LAYOUT_PHASE_TEMP_EXIT();
8106       RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
8107       LAYOUT_PHASE_TEMP_REENTER();
8108     }
8109   }
8110 
8111 #ifdef DEBUG
8112   if (gNoisyContentUpdates) {
8113     printf(
8114         "nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
8115         "old-next-sibling=%p\n",
8116         static_cast<void*>(aContainer), static_cast<void*>(aChild),
8117         static_cast<void*>(aOldNextSibling));
8118     if (gReallyNoisyContentUpdates) {
8119       aContainer->List(stdout, 0);
8120     }
8121   }
8122 #endif
8123 
8124   nsIFrame* childFrame = aChild->GetPrimaryFrame();
8125   if (!childFrame || childFrame->GetContent() != aChild) {
8126     // XXXbz the GetContent() != aChild check is needed due to bug 135040.
8127     // Remove it once that's fixed.
8128     childFrame = nullptr;
8129     UnregisterDisplayNoneStyleFor(aChild, aContainer);
8130   }
8131   MOZ_ASSERT(!childFrame || !GetDisplayContentsStyleFor(aChild),
8132              "display:contents nodes shouldn't have a frame");
8133   if (!childFrame && GetDisplayContentsStyleFor(aChild)) {
8134     // NOTE(emilio): We may iterate through ::before and ::after here and they
8135     // may be gone after the respective ContentRemoved call. Right now
8136     // StyleChildrenIterator handles that properly, so it's not an issue.
8137     StyleChildrenIterator iter(aChild);
8138     for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
8139       if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
8140         LAYOUT_PHASE_TEMP_EXIT();
8141         bool didReconstruct =
8142             ContentRemoved(aChild, c, nullptr, REMOVE_FOR_RECONSTRUCTION);
8143         LAYOUT_PHASE_TEMP_REENTER();
8144         if (didReconstruct) {
8145           return true;
8146         }
8147       }
8148     }
8149     UnregisterDisplayContentsStyleFor(aChild, aContainer);
8150     return false;
8151   }
8152 
8153 #ifdef MOZ_XUL
8154   if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
8155                         childFrame, CONTENT_REMOVED)) {
8156     return false;
8157   }
8158 #endif  // MOZ_XUL
8159 
8160   // If we're removing the root, then make sure to remove things starting at
8161   // the viewport's child instead of the primary frame (which might even be
8162   // null if the root had an XBL binding or display:none, even though the
8163   // frames above it got created).  We do the adjustment after the childFrame
8164   // check above, because we do want to clear any undisplayed content we might
8165   // have for the root.  Detecting removal of a root is a little exciting; in
8166   // particular, having a null aContainer is necessary but NOT sufficient.  Due
8167   // to how we process reframes, the content node might not even be in our
8168   // document by now.  So explicitly check whether the viewport's first kid's
8169   // content node is aChild.
8170   bool isRoot = false;
8171   if (!aContainer) {
8172     nsIFrame* viewport = GetRootFrame();
8173     if (viewport) {
8174       nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
8175       if (firstChild && firstChild->GetContent() == aChild) {
8176         isRoot = true;
8177         childFrame = firstChild;
8178         NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
8179       }
8180     }
8181   }
8182 
8183   if (childFrame) {
8184     InvalidateCanvasIfNeeded(mPresShell, aChild);
8185 
8186     // See whether we need to remove more than just childFrame
8187     LAYOUT_PHASE_TEMP_EXIT();
8188     if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
8189       LAYOUT_PHASE_TEMP_REENTER();
8190       return true;
8191     }
8192     LAYOUT_PHASE_TEMP_REENTER();
8193 
8194     // Get the childFrame's parent frame
8195     nsIFrame* parentFrame = childFrame->GetParent();
8196     LayoutFrameType parentType = parentFrame->Type();
8197 
8198     if (parentType == LayoutFrameType::FrameSet &&
8199         IsSpecialFramesetChild(aChild)) {
8200       // Just reframe the parent, since framesets are weird like that.
8201       LAYOUT_PHASE_TEMP_EXIT();
8202       RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
8203       LAYOUT_PHASE_TEMP_REENTER();
8204       return true;
8205     }
8206 
8207     // If we're a child of MathML, then we should reframe the MathML content.
8208     // If we're non-MathML, then we would be wrapped in a block so we need to
8209     // check our grandparent in that case.
8210     nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
8211                                            ? parentFrame->GetParent()
8212                                            : parentFrame;
8213     if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
8214       LAYOUT_PHASE_TEMP_EXIT();
8215       RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
8216       LAYOUT_PHASE_TEMP_REENTER();
8217       return true;
8218     }
8219 
8220     // Undo XUL wrapping if it's no longer needed.
8221     // (If we're in the XUL block-wrapping situation, parentFrame is the
8222     // wrapper frame.)
8223     nsIFrame* grandparentFrame = parentFrame->GetParent();
8224     if (grandparentFrame && grandparentFrame->IsXULBoxFrame() &&
8225         (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
8226         // check if this frame is the only one needing wrapping
8227         aChild == AnyKidsNeedBlockParent(
8228                       parentFrame->PrincipalChildList().FirstChild()) &&
8229         !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
8230       LAYOUT_PHASE_TEMP_EXIT();
8231       RecreateFramesForContent(grandparentFrame->GetContent(),
8232                                InsertionKind::Async);
8233       LAYOUT_PHASE_TEMP_REENTER();
8234       return true;
8235     }
8236 
8237 #ifdef ACCESSIBILITY
8238     if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
8239       accService->ContentRemoved(mPresShell, aChild);
8240     }
8241 #endif
8242 
8243     // Examine the containing-block for the removed content and see if
8244     // :first-letter style applies.
8245     nsIFrame* inflowChild = childFrame;
8246     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8247       inflowChild = childFrame->GetPlaceholderFrame();
8248       NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
8249     }
8250     nsContainerFrame* containingBlock =
8251         GetFloatContainingBlock(inflowChild->GetParent());
8252     bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
8253     if (haveFLS) {
8254     // Trap out to special routine that handles adjusting a blocks
8255     // frame tree when first-letter style is present.
8256 #ifdef NOISY_FIRST_LETTER
8257       printf("ContentRemoved: containingBlock=");
8258       nsFrame::ListTag(stdout, containingBlock);
8259       printf(" parentFrame=");
8260       nsFrame::ListTag(stdout, parentFrame);
8261       printf(" childFrame=");
8262       nsFrame::ListTag(stdout, childFrame);
8263       printf("\n");
8264 #endif
8265 
8266       // First update the containing blocks structure by removing the
8267       // existing letter frames. This makes the subsequent logic
8268       // simpler.
8269       RemoveLetterFrames(mPresShell, containingBlock);
8270 
8271       // Recover childFrame and parentFrame
8272       childFrame = aChild->GetPrimaryFrame();
8273       if (!childFrame || childFrame->GetContent() != aChild) {
8274         // XXXbz the GetContent() != aChild check is needed due to bug 135040.
8275         // Remove it once that's fixed.
8276         UnregisterDisplayNoneStyleFor(aChild, aContainer);
8277         return false;
8278       }
8279       parentFrame = childFrame->GetParent();
8280       parentType = parentFrame->Type();
8281 
8282 #ifdef NOISY_FIRST_LETTER
8283       printf("  ==> revised parentFrame=");
8284       nsFrame::ListTag(stdout, parentFrame);
8285       printf(" childFrame=");
8286       nsFrame::ListTag(stdout, childFrame);
8287       printf("\n");
8288 #endif
8289     }
8290 
8291 #ifdef DEBUG
8292     if (gReallyNoisyContentUpdates) {
8293       printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
8294       nsFrame::ListTag(stdout, childFrame);
8295       putchar('\n');
8296       parentFrame->List(stdout, 0);
8297     }
8298 #endif
8299 
8300     // Notify the parent frame that it should delete the frame
8301     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8302       childFrame = childFrame->GetPlaceholderFrame();
8303       NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
8304       parentFrame = childFrame->GetParent();
8305     }
8306 
8307     RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
8308 
8309     // NOTE(emilio): aChild could be dead here already if it is a ::before or
8310     // ::after pseudo-element (since in that case it was owned by childFrame,
8311     // which we just destroyed).
8312 
8313     if (isRoot) {
8314       mRootElementFrame = nullptr;
8315       mRootElementStyleFrame = nullptr;
8316       mDocElementContainingBlock = nullptr;
8317       mPageSequenceFrame = nullptr;
8318       mHasRootAbsPosContainingBlock = false;
8319     }
8320 
8321     if (haveFLS && mRootElementFrame) {
8322       RecoverLetterFrames(containingBlock);
8323     }
8324 
8325     // If we're just reconstructing frames for the element, then the
8326     // following ContentInserted notification on the element will
8327     // take care of fixing up any adjacent text nodes.  We don't need
8328     // to do this if the table parent type of our parent type is not
8329     // eTypeBlock, though, because in that case the whitespace isn't
8330     // being suppressed due to us anyway.
8331     if (aContainer && aOldNextSibling && aFlags == REMOVE_CONTENT &&
8332         GetParentType(parentType) == eTypeBlock) {
8333       // Adjacent whitespace-only text nodes might have been suppressed if
8334       // this node does not have inline ends. Create frames for them now
8335       // if necessary.
8336       // Reframe any text node just before the node being removed, if there is
8337       // one, and if it's not the last child or the first child. If a whitespace
8338       // textframe was being suppressed and it's now the last child or first
8339       // child then it can stay suppressed since the parent must be a block
8340       // and hence it's adjacent to a block end.
8341       // If aOldNextSibling is null, then the text node before the node being
8342       // removed is the last node, and we don't need to worry about it.
8343       //
8344       // FIXME(emilio): This should probably use the lazy frame construction
8345       // bits if possible instead of reframing it in place.
8346       nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
8347       if (prevSibling && prevSibling->GetPreviousSibling()) {
8348         LAYOUT_PHASE_TEMP_EXIT();
8349         ReframeTextIfNeeded(aContainer, prevSibling);
8350         LAYOUT_PHASE_TEMP_REENTER();
8351       }
8352       // Reframe any text node just after the node being removed, if there is
8353       // one, and if it's not the last child or the first child.
8354       if (aOldNextSibling->GetNextSibling() &&
8355           aOldNextSibling->GetPreviousSibling()) {
8356         LAYOUT_PHASE_TEMP_EXIT();
8357         ReframeTextIfNeeded(aContainer, aOldNextSibling);
8358         LAYOUT_PHASE_TEMP_REENTER();
8359       }
8360     }
8361 
8362 #ifdef DEBUG
8363     if (gReallyNoisyContentUpdates && parentFrame) {
8364       printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
8365       parentFrame->List(stdout, 0);
8366     }
8367 #endif
8368   }
8369 
8370   return false;
8371 }
8372 
8373 /**
8374  * This method invalidates the canvas when frames are removed or added for a
8375  * node that might have its background propagated to the canvas, i.e., a
8376  * document root node or an HTML BODY which is a child of the root node.
8377  *
8378  * @param aFrame a frame for a content node about to be removed or a frame that
8379  *               was just created for a content node that was inserted.
8380  */
InvalidateCanvasIfNeeded(nsIPresShell * presShell,nsIContent * node)8381 static void InvalidateCanvasIfNeeded(nsIPresShell* presShell,
8382                                      nsIContent* node) {
8383   NS_PRECONDITION(presShell->GetRootFrame(), "What happened here?");
8384   NS_PRECONDITION(presShell->GetPresContext(), "Say what?");
8385 
8386   //  Note that both in ContentRemoved and ContentInserted the content node
8387   //  will still have the right parent pointer, so looking at that is ok.
8388 
8389   nsIContent* parent = node->GetParent();
8390   if (parent) {
8391     // Has a parent; might not be what we want
8392     nsIContent* grandParent = parent->GetParent();
8393     if (grandParent) {
8394       // Has a grandparent, so not what we want
8395       return;
8396     }
8397 
8398     // Check whether it's an HTML body
8399     if (!node->IsHTMLElement(nsGkAtoms::body)) {
8400       return;
8401     }
8402   }
8403 
8404   // At this point the node has no parent or it's an HTML <body> child of the
8405   // root.  We might not need to invalidate in this case (eg we might be in
8406   // XHTML or something), but chances are we want to.  Play it safe.
8407   // Invalidate the viewport.
8408 
8409   nsIFrame* rootFrame = presShell->GetRootFrame();
8410   rootFrame->InvalidateFrameSubtree();
8411 }
8412 
EnsureFrameForTextNodeIsCreatedAfterFlush(nsGenericDOMDataNode * aContent)8413 bool nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
8414     nsGenericDOMDataNode* aContent) {
8415   if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
8416     return false;
8417   }
8418 
8419   if (mAlwaysCreateFramesForIgnorableWhitespace) {
8420     return false;
8421   }
8422 
8423   // Text frame may have been suppressed. Disable suppression and signal that a
8424   // flush should be performed. We do this on a document-wide basis so that
8425   // pages that repeatedly query metrics for collapsed-whitespace text nodes
8426   // don't trigger pathological behavior.
8427   mAlwaysCreateFramesForIgnorableWhitespace = true;
8428   Element* root = mDocument->GetRootElement();
8429   if (!root) {
8430     return false;
8431   }
8432 
8433   RestyleManager()->PostRestyleEvent(root, nsRestyleHint(0),
8434                                      nsChangeHint_ReconstructFrame);
8435   return true;
8436 }
8437 
CharacterDataChanged(nsIContent * aContent,const CharacterDataChangeInfo & aInfo)8438 void nsCSSFrameConstructor::CharacterDataChanged(
8439     nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
8440   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
8441 
8442   if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
8443        !aContent->TextIsOnlyWhitespace()) ||
8444       (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
8445        aContent->TextIsOnlyWhitespace())) {
8446 #ifdef DEBUG
8447     nsIFrame* frame = aContent->GetPrimaryFrame();
8448     NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
8449                  "Bit should never be set on generated content");
8450 #endif
8451     LAYOUT_PHASE_TEMP_EXIT();
8452     RecreateFramesForContent(aContent, InsertionKind::Async);
8453     LAYOUT_PHASE_TEMP_REENTER();
8454     return;
8455   }
8456 
8457   // It's possible the frame whose content changed isn't inserted into the
8458   // frame hierarchy yet, or that there is no frame that maps the content
8459   if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
8460 #if 0
8461     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
8462        ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
8463         aContent, ContentTag(aContent, 0),
8464         aSubContent, frame));
8465 #endif
8466 
8467     // Special check for text content that is a child of a letter frame.  If
8468     // this happens, we should remove the letter frame, do whatever we're
8469     // planning to do with this notification, then put the letter frame back.
8470     // Note that this is basically what RecreateFramesForContent ends up doing;
8471     // the reason we dont' want to call that here is that our text content
8472     // could be native anonymous, in which case RecreateFramesForContent would
8473     // completely barf on it.  And recreating the non-anonymous ancestor would
8474     // just lead us to come back into this notification (e.g. if quotes or
8475     // counters are involved), leading to a loop.
8476     nsContainerFrame* block = GetFloatContainingBlock(frame);
8477     bool haveFirstLetterStyle = false;
8478     if (block) {
8479       // See if the block has first-letter style applied to it.
8480       haveFirstLetterStyle = HasFirstLetterStyle(block);
8481       if (haveFirstLetterStyle) {
8482         RemoveLetterFrames(mPresShell, block);
8483         // Reget |frame|, since we might have killed it.
8484         // Do we really need to call CharacterDataChanged in this case, though?
8485         frame = aContent->GetPrimaryFrame();
8486         NS_ASSERTION(frame, "Should have frame here!");
8487       }
8488     }
8489 
8490     // Notify the first frame that maps the content. It will generate a reflow
8491     // command
8492     frame->CharacterDataChanged(aInfo);
8493 
8494     if (haveFirstLetterStyle) {
8495       RecoverLetterFrames(block);
8496     }
8497   }
8498 }
8499 
RecalcQuotesAndCounters()8500 void nsCSSFrameConstructor::RecalcQuotesAndCounters() {
8501   nsAutoScriptBlocker scriptBlocker;
8502 
8503   if (mQuotesDirty) {
8504     mQuotesDirty = false;
8505     mQuoteList.RecalcAll();
8506   }
8507 
8508   if (mCountersDirty) {
8509     mCountersDirty = false;
8510     mCounterManager.RecalcAll();
8511   }
8512 
8513   NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
8514   NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
8515 }
8516 
NotifyCounterStylesAreDirty()8517 void nsCSSFrameConstructor::NotifyCounterStylesAreDirty() {
8518   mCounterManager.SetAllDirty();
8519   CountersDirty();
8520 }
8521 
WillDestroyFrameTree()8522 void nsCSSFrameConstructor::WillDestroyFrameTree() {
8523 #if defined(DEBUG_dbaron_off)
8524   mCounterManager.Dump();
8525 #endif
8526 
8527   mIsDestroyingFrameTree = true;
8528 
8529   // Prevent frame tree destruction from being O(N^2)
8530   mQuoteList.Clear();
8531   mCounterManager.Clear();
8532 
8533   // Remove our presshell as a style flush observer.  But leave
8534   // RestyleManager::mObservingRefreshDriver true so we don't readd to
8535   // it even if someone tries to post restyle events on us from this
8536   // point on for some reason.
8537   mPresShell->GetPresContext()->RefreshDriver()->RemoveStyleFlushObserver(
8538       mPresShell);
8539 
8540   nsFrameManager::Destroy();
8541 }
8542 
8543 // STATIC
8544 
8545 // XXXbz I'd really like this method to go away. Once we have inline-block and
8546 // I can just use that for sized broken images, that can happen, maybe.
GetAlternateTextFor(Element * aElement,nsAtom * aTag,nsAString & aAltText)8547 void nsCSSFrameConstructor::GetAlternateTextFor(Element* aElement, nsAtom* aTag,
8548                                                 nsAString& aAltText) {
8549   // The "alt" attribute specifies alternate text that is rendered
8550   // when the image can not be displayed.
8551   if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText)) {
8552     return;
8553   }
8554 
8555   if (nsGkAtoms::input == aTag) {
8556     // If there's no "alt" attribute, and aContent is an input element, then use
8557     // the value of the "value" attribute
8558     if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
8559       return;
8560     }
8561 
8562     // If there's no "value" attribute either, then use the localized string for
8563     // "Submit" as the alternate text.
8564     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
8565                                        "Submit", aAltText);
8566   }
8567 }
8568 
CreateContinuingOuterTableFrame(nsIPresShell * aPresShell,nsPresContext * aPresContext,nsIFrame * aFrame,nsContainerFrame * aParentFrame,nsIContent * aContent,nsStyleContext * aStyleContext)8569 nsIFrame* nsCSSFrameConstructor::CreateContinuingOuterTableFrame(
8570     nsIPresShell* aPresShell, nsPresContext* aPresContext, nsIFrame* aFrame,
8571     nsContainerFrame* aParentFrame, nsIContent* aContent,
8572     nsStyleContext* aStyleContext) {
8573   nsTableWrapperFrame* newFrame =
8574       NS_NewTableWrapperFrame(aPresShell, aStyleContext);
8575 
8576   newFrame->Init(aContent, aParentFrame, aFrame);
8577 
8578   // Create a continuing inner table frame, and if there's a caption then
8579   // replicate the caption
8580   nsFrameItems newChildFrames;
8581 
8582   nsIFrame* childFrame = aFrame->PrincipalChildList().FirstChild();
8583   if (childFrame) {
8584     nsIFrame* continuingTableFrame =
8585         CreateContinuingFrame(aPresContext, childFrame, newFrame);
8586     newChildFrames.AddChild(continuingTableFrame);
8587 
8588     NS_ASSERTION(!childFrame->GetNextSibling(),
8589                  "there can be only one inner table frame");
8590   }
8591 
8592   // Set the table wrapper's initial child list
8593   newFrame->SetInitialChildList(kPrincipalList, newChildFrames);
8594 
8595   return newFrame;
8596 }
8597 
CreateContinuingTableFrame(nsIPresShell * aPresShell,nsIFrame * aFrame,nsContainerFrame * aParentFrame,nsIContent * aContent,nsStyleContext * aStyleContext)8598 nsIFrame* nsCSSFrameConstructor::CreateContinuingTableFrame(
8599     nsIPresShell* aPresShell, nsIFrame* aFrame, nsContainerFrame* aParentFrame,
8600     nsIContent* aContent, nsStyleContext* aStyleContext) {
8601   nsTableFrame* newFrame = NS_NewTableFrame(aPresShell, aStyleContext);
8602 
8603   newFrame->Init(aContent, aParentFrame, aFrame);
8604 
8605   // Replicate any header/footer frames
8606   nsFrameItems childFrames;
8607   for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
8608     // See if it's a header/footer, possibly wrapped in a scroll frame.
8609     nsTableRowGroupFrame* rowGroupFrame =
8610         static_cast<nsTableRowGroupFrame*>(childFrame);
8611     // If the row group was continued, then don't replicate it.
8612     nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
8613     if (rgNextInFlow) {
8614       rowGroupFrame->SetRepeatable(false);
8615     } else if (rowGroupFrame->IsRepeatable()) {
8616       // Replicate the header/footer frame.
8617       nsTableRowGroupFrame* headerFooterFrame;
8618       nsFrameItems childItems;
8619 
8620       TreeMatchContextHolder matchContext(mDocument);
8621       nsFrameConstructorState state(
8622           mPresShell, matchContext,
8623           GetAbsoluteContainingBlock(newFrame, FIXED_POS),
8624           GetAbsoluteContainingBlock(newFrame, ABS_POS), nullptr);
8625       state.mCreatingExtraFrames = true;
8626 
8627       nsStyleContext* const headerFooterStyleContext =
8628           rowGroupFrame->StyleContext();
8629       headerFooterFrame = static_cast<nsTableRowGroupFrame*>(
8630           NS_NewTableRowGroupFrame(aPresShell, headerFooterStyleContext));
8631 
8632       nsIContent* headerFooter = rowGroupFrame->GetContent();
8633       headerFooterFrame->Init(headerFooter, newFrame, nullptr);
8634 
8635       nsFrameConstructorSaveState absoluteSaveState;
8636       MakeTablePartAbsoluteContainingBlockIfNeeded(
8637           state, headerFooterStyleContext->StyleDisplay(), absoluteSaveState,
8638           headerFooterFrame);
8639 
8640       ProcessChildren(state, headerFooter, rowGroupFrame->StyleContext(),
8641                       headerFooterFrame, true, childItems, false, nullptr);
8642       NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
8643       headerFooterFrame->SetInitialChildList(kPrincipalList, childItems);
8644       headerFooterFrame->SetRepeatable(true);
8645 
8646       // Table specific initialization
8647       headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
8648 
8649       // XXX Deal with absolute and fixed frames...
8650       childFrames.AddChild(headerFooterFrame);
8651     }
8652   }
8653 
8654   // Set the table frame's initial child list
8655   newFrame->SetInitialChildList(kPrincipalList, childFrames);
8656 
8657   return newFrame;
8658 }
8659 
CreateContinuingFrame(nsPresContext * aPresContext,nsIFrame * aFrame,nsContainerFrame * aParentFrame,bool aIsFluid)8660 nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
8661     nsPresContext* aPresContext, nsIFrame* aFrame,
8662     nsContainerFrame* aParentFrame, bool aIsFluid) {
8663   nsIPresShell* shell = aPresContext->PresShell();
8664   nsStyleContext* styleContext = aFrame->StyleContext();
8665   nsIFrame* newFrame = nullptr;
8666   nsIFrame* nextContinuation = aFrame->GetNextContinuation();
8667   nsIFrame* nextInFlow = aFrame->GetNextInFlow();
8668 
8669   // Use the frame type to determine what type of frame to create
8670   LayoutFrameType frameType = aFrame->Type();
8671   nsIContent* content = aFrame->GetContent();
8672 
8673   NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE,
8674                "why CreateContinuingFrame for a non-splittable frame?");
8675 
8676   if (LayoutFrameType::Text == frameType) {
8677     newFrame = NS_NewContinuingTextFrame(shell, styleContext);
8678     newFrame->Init(content, aParentFrame, aFrame);
8679   } else if (LayoutFrameType::Inline == frameType) {
8680     newFrame = NS_NewInlineFrame(shell, styleContext);
8681     newFrame->Init(content, aParentFrame, aFrame);
8682   } else if (LayoutFrameType::Block == frameType) {
8683     MOZ_ASSERT(!aFrame->IsTableCaption(),
8684                "no support for fragmenting table captions yet");
8685     newFrame = NS_NewBlockFrame(shell, styleContext);
8686     newFrame->Init(content, aParentFrame, aFrame);
8687 #ifdef MOZ_XUL
8688   } else if (LayoutFrameType::XULLabel == frameType) {
8689     newFrame = NS_NewXULLabelFrame(shell, styleContext);
8690     newFrame->Init(content, aParentFrame, aFrame);
8691 #endif
8692   } else if (LayoutFrameType::ColumnSet == frameType) {
8693     MOZ_ASSERT(!aFrame->IsTableCaption(),
8694                "no support for fragmenting table captions yet");
8695     newFrame = NS_NewColumnSetFrame(shell, styleContext, nsFrameState(0));
8696     newFrame->Init(content, aParentFrame, aFrame);
8697   } else if (LayoutFrameType::Page == frameType) {
8698     nsContainerFrame* canvasFrame;
8699     newFrame = ConstructPageFrame(shell, aParentFrame, aFrame, canvasFrame);
8700   } else if (LayoutFrameType::TableWrapper == frameType) {
8701     newFrame = CreateContinuingOuterTableFrame(
8702         shell, aPresContext, aFrame, aParentFrame, content, styleContext);
8703 
8704   } else if (LayoutFrameType::Table == frameType) {
8705     newFrame = CreateContinuingTableFrame(shell, aFrame, aParentFrame, content,
8706                                           styleContext);
8707 
8708   } else if (LayoutFrameType::TableRowGroup == frameType) {
8709     newFrame = NS_NewTableRowGroupFrame(shell, styleContext);
8710     newFrame->Init(content, aParentFrame, aFrame);
8711     if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8712       nsTableFrame::RegisterPositionedTablePart(newFrame);
8713     }
8714   } else if (LayoutFrameType::TableRow == frameType) {
8715     nsTableRowFrame* rowFrame = NS_NewTableRowFrame(shell, styleContext);
8716 
8717     rowFrame->Init(content, aParentFrame, aFrame);
8718     if (rowFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8719       nsTableFrame::RegisterPositionedTablePart(rowFrame);
8720     }
8721 
8722     // Create a continuing frame for each table cell frame
8723     nsFrameItems newChildList;
8724     nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
8725     while (cellFrame) {
8726       // See if it's a table cell frame
8727       if (IS_TABLE_CELL(cellFrame->Type())) {
8728         nsIFrame* continuingCellFrame =
8729             CreateContinuingFrame(aPresContext, cellFrame, rowFrame);
8730         newChildList.AddChild(continuingCellFrame);
8731       }
8732       cellFrame = cellFrame->GetNextSibling();
8733     }
8734 
8735     rowFrame->SetInitialChildList(kPrincipalList, newChildList);
8736     newFrame = rowFrame;
8737 
8738   } else if (IS_TABLE_CELL(frameType)) {
8739     // Warning: If you change this and add a wrapper frame around table cell
8740     // frames, make sure Bug 368554 doesn't regress!
8741     // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
8742     nsTableFrame* tableFrame =
8743         static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
8744     nsTableCellFrame* cellFrame =
8745         NS_NewTableCellFrame(shell, styleContext, tableFrame);
8746 
8747     cellFrame->Init(content, aParentFrame, aFrame);
8748     if (cellFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8749       nsTableFrame::RegisterPositionedTablePart(cellFrame);
8750     }
8751 
8752     // Create a continuing area frame
8753     nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
8754     nsIFrame* continuingBlockFrame = CreateContinuingFrame(
8755         aPresContext, blockFrame, static_cast<nsContainerFrame*>(cellFrame));
8756 
8757     SetInitialSingleChild(cellFrame, continuingBlockFrame);
8758     newFrame = cellFrame;
8759   } else if (LayoutFrameType::Line == frameType) {
8760     newFrame = NS_NewFirstLineFrame(shell, styleContext);
8761     newFrame->Init(content, aParentFrame, aFrame);
8762   } else if (LayoutFrameType::Letter == frameType) {
8763     newFrame = NS_NewFirstLetterFrame(shell, styleContext);
8764     newFrame->Init(content, aParentFrame, aFrame);
8765   } else if (LayoutFrameType::Image == frameType) {
8766     newFrame = NS_NewImageFrame(shell, styleContext);
8767     newFrame->Init(content, aParentFrame, aFrame);
8768   } else if (LayoutFrameType::ImageControl == frameType) {
8769     newFrame = NS_NewImageControlFrame(shell, styleContext);
8770     newFrame->Init(content, aParentFrame, aFrame);
8771   } else if (LayoutFrameType::Placeholder == frameType) {
8772     // create a continuing out of flow frame
8773     nsIFrame* oofFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
8774     nsIFrame* oofContFrame =
8775         CreateContinuingFrame(aPresContext, oofFrame, aParentFrame);
8776     newFrame = CreatePlaceholderFrameFor(
8777         shell, content, oofContFrame, aParentFrame, aFrame,
8778         aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK);
8779   } else if (LayoutFrameType::FieldSet == frameType) {
8780     nsContainerFrame* fieldset = NS_NewFieldSetFrame(shell, styleContext);
8781 
8782     fieldset->Init(content, aParentFrame, aFrame);
8783 
8784     // Create a continuing area frame
8785     // XXXbz we really shouldn't have to do this by hand!
8786     nsContainerFrame* blockFrame = GetFieldSetBlockFrame(aFrame);
8787     if (blockFrame) {
8788       nsIFrame* continuingBlockFrame =
8789           CreateContinuingFrame(aPresContext, blockFrame, fieldset);
8790       // Set the fieldset's initial child list
8791       SetInitialSingleChild(fieldset, continuingBlockFrame);
8792     } else {
8793       MOZ_ASSERT(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
8794                  "FieldSet block may only be null for overflow containers");
8795     }
8796     newFrame = fieldset;
8797   } else if (LayoutFrameType::Legend == frameType) {
8798     newFrame = NS_NewLegendFrame(shell, styleContext);
8799     newFrame->Init(content, aParentFrame, aFrame);
8800   } else if (LayoutFrameType::FlexContainer == frameType) {
8801     newFrame = NS_NewFlexContainerFrame(shell, styleContext);
8802     newFrame->Init(content, aParentFrame, aFrame);
8803   } else if (LayoutFrameType::GridContainer == frameType) {
8804     newFrame = NS_NewGridContainerFrame(shell, styleContext);
8805     newFrame->Init(content, aParentFrame, aFrame);
8806   } else if (LayoutFrameType::Ruby == frameType) {
8807     newFrame = NS_NewRubyFrame(shell, styleContext);
8808     newFrame->Init(content, aParentFrame, aFrame);
8809   } else if (LayoutFrameType::RubyBaseContainer == frameType) {
8810     newFrame = NS_NewRubyBaseContainerFrame(shell, styleContext);
8811     newFrame->Init(content, aParentFrame, aFrame);
8812   } else if (LayoutFrameType::RubyTextContainer == frameType) {
8813     newFrame = NS_NewRubyTextContainerFrame(shell, styleContext);
8814     newFrame->Init(content, aParentFrame, aFrame);
8815   } else if (LayoutFrameType::Details == frameType) {
8816     newFrame = NS_NewDetailsFrame(shell, styleContext);
8817     newFrame->Init(content, aParentFrame, aFrame);
8818   } else {
8819     MOZ_CRASH("unexpected frame type");
8820   }
8821 
8822   // Init() set newFrame to be a fluid continuation of aFrame.
8823   // If we want a non-fluid continuation, we need to call SetPrevContinuation()
8824   // to reset NS_FRAME_IS_FLUID_CONTINUATION.
8825   if (!aIsFluid) {
8826     newFrame->SetPrevContinuation(aFrame);
8827   }
8828 
8829   // A continuation of generated content is also generated content
8830   if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
8831     newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
8832   }
8833 
8834   // A continuation of nsIAnonymousContentCreator content is also
8835   // nsIAnonymousContentCreator created content
8836   if (aFrame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
8837     newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
8838   }
8839 
8840   // A continuation of an out-of-flow is also an out-of-flow
8841   if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8842     newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
8843   }
8844 
8845   if (nextInFlow) {
8846     nextInFlow->SetPrevInFlow(newFrame);
8847     newFrame->SetNextInFlow(nextInFlow);
8848   } else if (nextContinuation) {
8849     nextContinuation->SetPrevContinuation(newFrame);
8850     newFrame->SetNextContinuation(nextContinuation);
8851   }
8852 
8853   MOZ_ASSERT(!newFrame->GetNextSibling(), "unexpected sibling");
8854   return newFrame;
8855 }
8856 
ReplicateFixedFrames(nsPageContentFrame * aParentFrame)8857 nsresult nsCSSFrameConstructor::ReplicateFixedFrames(
8858     nsPageContentFrame* aParentFrame) {
8859   // Now deal with fixed-pos things....  They should appear on all pages,
8860   // so we want to move over the placeholders when processing the child
8861   // of the pageContentFrame.
8862 
8863   nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
8864   if (!prevPageContentFrame) {
8865     return NS_OK;
8866   }
8867   nsContainerFrame* canvasFrame =
8868       do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
8869   nsIFrame* prevCanvasFrame =
8870       prevPageContentFrame->PrincipalChildList().FirstChild();
8871   if (!canvasFrame || !prevCanvasFrame) {
8872     // document's root element frame missing
8873     return NS_ERROR_UNEXPECTED;
8874   }
8875 
8876   nsFrameItems fixedPlaceholders;
8877   nsIFrame* firstFixed =
8878       prevPageContentFrame->GetChildList(nsIFrame::kFixedList).FirstChild();
8879   if (!firstFixed) {
8880     return NS_OK;
8881   }
8882 
8883   // Don't allow abs-pos descendants of the fixed content to escape the content.
8884   // This should not normally be possible (because fixed-pos elements should
8885   // be absolute containers) but fixed-pos tables currently aren't abs-pos
8886   // containers.
8887   TreeMatchContextHolder matchContext(mDocument);
8888   nsFrameConstructorState state(mPresShell, matchContext, aParentFrame, nullptr,
8889                                 mRootElementFrame);
8890   state.mCreatingExtraFrames = true;
8891 
8892   // We can't use an ancestor filter here, because we're not going to
8893   // be usefully recurring down the tree.  This means that other
8894   // places in frame construction can't assume a filter is
8895   // initialized!
8896 
8897   // Iterate across fixed frames and replicate each whose placeholder is a
8898   // descendant of aFrame. (We don't want to explicitly copy placeholders that
8899   // are within fixed frames, because that would cause duplicates on the new
8900   // page - bug 389619)
8901   for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
8902     nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
8903     if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(
8904                                prevCanvasFrame, prevPlaceholder)) {
8905       // We want to use the same style as the primary style frame for
8906       // our content
8907       nsIContent* content = fixed->GetContent();
8908       nsStyleContext* styleContext =
8909           nsLayoutUtils::GetStyleFrame(content)->StyleContext();
8910       AutoFrameConstructionItemList items(this);
8911       AddFrameConstructionItemsInternal(
8912           state, content, canvasFrame, content->NodeInfo()->NameAtom(),
8913           content->GetNameSpaceID(), true, styleContext,
8914           ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK, nullptr, items);
8915       ConstructFramesFromItemList(state, items, canvasFrame,
8916                                   /* aParentIsWrapperAnonBox = */ false,
8917                                   fixedPlaceholders);
8918     }
8919   }
8920 
8921   // Add the placeholders to our primary child list.
8922   // XXXbz this is a little screwed up, since the fixed frames will have
8923   // broken auto-positioning. Oh, well.
8924   NS_ASSERTION(!canvasFrame->PrincipalChildList().FirstChild(),
8925                "leaking frames; doc root continuation must be empty");
8926   canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders);
8927   return NS_OK;
8928 }
8929 
GetInsertionPoint(nsIContent * aChild)8930 nsCSSFrameConstructor::InsertionPoint nsCSSFrameConstructor::GetInsertionPoint(
8931     nsIContent* aChild) {
8932   MOZ_ASSERT(aChild);
8933   nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
8934   if (!insertionElement) {
8935     // The element doesn't belong in the flattened tree, and thus we don't want
8936     // to render it.
8937     return {};
8938   }
8939 
8940   return {GetContentInsertionFrameFor(insertionElement), insertionElement};
8941 }
8942 
8943 // Capture state for the frame tree rooted at the frame associated with the
8944 // content object, aContent
CaptureStateForFramesOf(nsIContent * aContent,nsILayoutHistoryState * aHistoryState)8945 void nsCSSFrameConstructor::CaptureStateForFramesOf(
8946     nsIContent* aContent, nsILayoutHistoryState* aHistoryState) {
8947   if (!aHistoryState) {
8948     return;
8949   }
8950   nsIFrame* frame = aContent->GetPrimaryFrame();
8951   if (frame == mRootElementFrame) {
8952     frame = mRootElementFrame
8953                 ? GetAbsoluteContainingBlock(mRootElementFrame, FIXED_POS)
8954                 : GetRootFrame();
8955   }
8956   for (; frame;
8957        frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
8958     CaptureFrameState(frame, aHistoryState);
8959   }
8960 }
8961 
8962 #ifdef MOZ_OLD_STYLE
DefinitelyEqualURIsAndPrincipal(mozilla::css::URLValue * aURI1,mozilla::css::URLValue * aURI2)8963 static bool DefinitelyEqualURIsAndPrincipal(mozilla::css::URLValue* aURI1,
8964                                             mozilla::css::URLValue* aURI2) {
8965   return aURI1 == aURI2 ||
8966          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIsAndPrincipal(*aURI2));
8967 }
8968 
MaybeRecreateFramesForElement(Element * aElement)8969 nsStyleContext* nsCSSFrameConstructor::MaybeRecreateFramesForElement(
8970     Element* aElement) {
8971   RefPtr<nsStyleContext> oldContext = GetDisplayNoneStyleFor(aElement);
8972   StyleDisplay oldDisplay = StyleDisplay::None;
8973   if (!oldContext) {
8974     oldContext = GetDisplayContentsStyleFor(aElement);
8975     if (!oldContext) {
8976       return nullptr;
8977     }
8978     oldDisplay = StyleDisplay::Contents;
8979   }
8980 
8981   // The parent has a frame, so try resolving a new context.
8982   RefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->ResolveStyleFor(
8983       aElement, oldContext->AsGecko()->GetParent(),
8984       LazyComputeBehavior::Assert);
8985 
8986   if (oldDisplay == StyleDisplay::None) {
8987     ChangeRegisteredDisplayNoneStyleFor(aElement, newContext);
8988   } else {
8989     ChangeRegisteredDisplayContentsStyleFor(aElement, newContext);
8990   }
8991 
8992   const nsStyleDisplay* disp = newContext->StyleDisplay();
8993   if (oldDisplay == disp->mDisplay) {
8994     // We can skip trying to recreate frames here, but only if our style
8995     // context does not have a binding URI that differs from our old one.
8996     // Otherwise, we should try to recreate, because we may want to apply the
8997     // new binding
8998     if (!disp->mBinding) {
8999       return newContext;
9000     }
9001     const nsStyleDisplay* oldDisp = oldContext->PeekStyleDisplay();
9002     if (oldDisp &&
9003         DefinitelyEqualURIsAndPrincipal(disp->mBinding, oldDisp->mBinding)) {
9004       return newContext;
9005     }
9006   }
9007 
9008   RecreateFramesForContent(aElement, InsertionKind::Sync);
9009   return nullptr;
9010 }
9011 #endif
9012 
IsWhitespaceFrame(nsIFrame * aFrame)9013 static bool IsWhitespaceFrame(nsIFrame* aFrame) {
9014   MOZ_ASSERT(aFrame, "invalid argument");
9015   return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
9016 }
9017 
FindFirstNonWhitespaceChild(nsIFrame * aParentFrame)9018 static nsIFrame* FindFirstNonWhitespaceChild(nsIFrame* aParentFrame) {
9019   nsIFrame* f = aParentFrame->PrincipalChildList().FirstChild();
9020   while (f && IsWhitespaceFrame(f)) {
9021     f = f->GetNextSibling();
9022   }
9023   return f;
9024 }
9025 
FindNextNonWhitespaceSibling(nsIFrame * aFrame)9026 static nsIFrame* FindNextNonWhitespaceSibling(nsIFrame* aFrame) {
9027   nsIFrame* f = aFrame;
9028   do {
9029     f = f->GetNextSibling();
9030   } while (f && IsWhitespaceFrame(f));
9031   return f;
9032 }
9033 
FindPreviousNonWhitespaceSibling(nsIFrame * aFrame)9034 static nsIFrame* FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) {
9035   nsIFrame* f = aFrame;
9036   do {
9037     f = f->GetPrevSibling();
9038   } while (f && IsWhitespaceFrame(f));
9039   return f;
9040 }
9041 
MaybeRecreateContainerForFrameRemoval(nsIFrame * aFrame)9042 bool nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
9043     nsIFrame* aFrame) {
9044   NS_PRECONDITION(aFrame, "Must have a frame");
9045   NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
9046   NS_PRECONDITION(aFrame == aFrame->FirstContinuation(),
9047                   "aFrame not the result of GetPrimaryFrame()?");
9048 
9049   if (IsFramePartOfIBSplit(aFrame)) {
9050   // The removal functions can't handle removal of an {ib} split directly; we
9051   // need to rebuild the containing block.
9052 #ifdef DEBUG
9053     if (gNoisyContentUpdates) {
9054       printf(
9055           "nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9056           "frame=");
9057       nsFrame::ListTag(stdout, aFrame);
9058       printf(" is ib-split\n");
9059     }
9060 #endif
9061 
9062     ReframeContainingBlock(aFrame);
9063     return true;
9064   }
9065 
9066   nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
9067   if (insertionFrame && insertionFrame->IsLegendFrame() &&
9068       aFrame->GetParent()->IsFieldSetFrame()) {
9069     RecreateFramesForContent(aFrame->GetParent()->GetContent(),
9070                              InsertionKind::Async);
9071     return true;
9072   }
9073 
9074   nsIFrame* inFlowFrame = (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
9075                               ? aFrame->GetPlaceholderFrame()
9076                               : aFrame;
9077   MOZ_ASSERT(inFlowFrame, "How did that happen?");
9078   MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
9079              "placeholder for primary frame has previous continuations?");
9080   nsIFrame* parent = inFlowFrame->GetParent();
9081 
9082   if (parent && parent->IsDetailsFrame()) {
9083     HTMLSummaryElement* summary =
9084         HTMLSummaryElement::FromContent(aFrame->GetContent());
9085     DetailsFrame* detailsFrame = static_cast<DetailsFrame*>(parent);
9086 
9087     // Unlike adding summary element cases, we need to check children of the
9088     // parent details frame since at this moment the summary element has been
9089     // already removed from the parent details element's child list.
9090     if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) {
9091       // When removing a summary, we should reframe the parent details frame to
9092       // ensure that another summary is used or the default summary is
9093       // generated.
9094       RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9095       return true;
9096     }
9097   }
9098 
9099   // Now check for possibly needing to reconstruct due to a pseudo parent
9100   // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
9101   // need to be checked here, since all other types of parent will be catched
9102   // by "Check ruby containers" section below.
9103   if (IsTableOrRubyPseudo(parent)) {
9104     if (FindFirstNonWhitespaceChild(parent) == inFlowFrame ||
9105         !FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()) ||
9106         // If it is a whitespace, and is the only child of the parent, the
9107         // pseudo parent was created for the space, and should now be removed.
9108         (IsWhitespaceFrame(aFrame) &&
9109          parent->PrincipalChildList().OnlyChild()) ||
9110         // If we're a table-column-group, then the OnlyChild check above is
9111         // not going to catch cases when we're the first child.
9112         (inFlowFrame->IsTableColGroupFrame() &&
9113          parent->GetChildList(nsIFrame::kColGroupList).FirstChild() ==
9114              inFlowFrame) ||
9115         // Similar if we're a table-caption.
9116         (inFlowFrame->IsTableCaption() &&
9117          parent->GetChildList(nsIFrame::kCaptionList).FirstChild() ==
9118              inFlowFrame)) {
9119       RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9120       return true;
9121     }
9122   }
9123 
9124   // Might need to reconstruct things if this frame's nextSibling is a table
9125   // or ruby pseudo, since removal of this frame might mean that this pseudo
9126   // needs to get merged with the frame's prevSibling if that's also a table
9127   // or ruby pseudo.
9128   nsIFrame* nextSibling =
9129       FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
9130   NS_ASSERTION(!IsTableOrRubyPseudo(inFlowFrame), "Shouldn't happen here");
9131   // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
9132   // need to be checked here, since all other types of such frames will have
9133   // a ruby container parent, and be catched by "Check ruby containers" below.
9134   if (nextSibling && IsTableOrRubyPseudo(nextSibling)) {
9135     nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
9136     if (prevSibling && IsTableOrRubyPseudo(prevSibling)) {
9137 #ifdef DEBUG
9138       if (gNoisyContentUpdates) {
9139         printf(
9140             "nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9141             "frame=");
9142         nsFrame::ListTag(stdout, aFrame);
9143         printf(
9144             " has a table pseudo next sibling of different type and a "
9145             "table pseudo prevsibling\n");
9146       }
9147 #endif
9148       // Good enough to recreate frames for aFrame's parent's content; even if
9149       // aFrame's parent is a pseudo, that'll be the right content node.
9150       RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9151       return true;
9152     }
9153   }
9154 
9155   // Check ruby containers
9156   LayoutFrameType parentType = parent->Type();
9157   if (parentType == LayoutFrameType::Ruby ||
9158       RubyUtils::IsRubyContainerBox(parentType)) {
9159     // In ruby containers, pseudo frames may be created from
9160     // whitespaces or even nothing. There are two cases we actually
9161     // need to handle here, but hard to check exactly:
9162     // 1. Status of spaces beside the frame may vary, and related
9163     //    frames may be constructed or destroyed accordingly.
9164     // 2. The type of the first child of a ruby frame determines
9165     //    whether a pseudo ruby base container should exist.
9166     RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9167     return true;
9168   }
9169 
9170   // Might need to reconstruct things if the removed frame's nextSibling is an
9171   // anonymous flex item.  The removed frame might've been what divided two
9172   // runs of inline content into two anonymous flex items, which would now
9173   // need to be merged.
9174   // NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
9175   // we're only interested in anonymous flex items here, and those can never
9176   // be adjacent to whitespace, since they absorb contiguous runs of inline
9177   // non-replaced content (including whitespace).
9178   if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
9179     AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
9180 #ifdef DEBUG
9181     if (gNoisyContentUpdates) {
9182       printf(
9183           "nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9184           "frame=");
9185       nsFrame::ListTag(stdout, aFrame);
9186       printf(" has an anonymous flex item as its next sibling\n");
9187     }
9188 #endif  // DEBUG
9189     // Recreate frames for the flex container (the removed frame's parent)
9190     RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9191     return true;
9192   }
9193 
9194   // Might need to reconstruct things if the removed frame's nextSibling is
9195   // null and its parent is an anonymous flex item. (This might be the last
9196   // remaining child of that anonymous flex item, which can then go away.)
9197   if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
9198     AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
9199 #ifdef DEBUG
9200     if (gNoisyContentUpdates) {
9201       printf(
9202           "nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9203           "frame=");
9204       nsFrame::ListTag(stdout, aFrame);
9205       printf(" has an anonymous flex item as its parent\n");
9206     }
9207 #endif  // DEBUG
9208     // Recreate frames for the flex container (the removed frame's grandparent)
9209     RecreateFramesForContent(parent->GetParent()->GetContent(),
9210                              InsertionKind::Async);
9211     return true;
9212   }
9213 
9214 #ifdef MOZ_XUL
9215   if (aFrame->IsPopupSetFrame()) {
9216     nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
9217     if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
9218       ReconstructDocElementHierarchy(InsertionKind::Async);
9219       return true;
9220     }
9221   }
9222 #endif
9223 
9224   // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
9225   // a non-fluid continuation, i.e. it was split by bidi resolution
9226   if (!inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
9227       ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
9228        (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
9229     RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9230     return true;
9231   }
9232 
9233   // We might still need to reconstruct things if the parent of inFlowFrame is
9234   // ib-split, since in that case the removal of aFrame might affect the
9235   // splitting of its parent.
9236   if (!IsFramePartOfIBSplit(parent)) {
9237     return false;
9238   }
9239 
9240   // If inFlowFrame is not the only in-flow child of |parent|, then removing
9241   // it will change nothing about the {ib} split.
9242   if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
9243       inFlowFrame->LastContinuation()->GetNextSibling()) {
9244     return false;
9245   }
9246 
9247   // If the parent is the first or last part of the {ib} split, then
9248   // removing one of its kids will have no effect on the splitting.
9249   // Get the first continuation up front so we don't have to do it twice.
9250   nsIFrame* parentFirstContinuation = parent->FirstContinuation();
9251   if (!GetIBSplitSibling(parentFirstContinuation) ||
9252       !GetIBSplitPrevSibling(parentFirstContinuation)) {
9253     return false;
9254   }
9255 
9256 #ifdef DEBUG
9257   if (gNoisyContentUpdates) {
9258     printf(
9259         "nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9260         "frame=");
9261     nsFrame::ListTag(stdout, parent);
9262     printf(" is ib-split\n");
9263   }
9264 #endif
9265 
9266   ReframeContainingBlock(parent);
9267   return true;
9268 }
9269 
UpdateTableCellSpans(nsIContent * aContent)9270 void nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent) {
9271   nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
9272 
9273   // It's possible that this warning could fire if some other style change
9274   // simultaneously changes the 'display' of the element and makes it no
9275   // longer be a table cell.
9276   NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!");
9277 
9278   if (cellFrame) {
9279     cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
9280   }
9281 }
9282 
RecreateFramesForContent(nsIContent * aContent,InsertionKind aInsertionKind)9283 void nsCSSFrameConstructor::RecreateFramesForContent(
9284     nsIContent* aContent, InsertionKind aInsertionKind) {
9285   MOZ_ASSERT(aContent);
9286 
9287   // If there is no document, we don't want to recreate frames for it.  (You
9288   // shouldn't generally be giving this method content without a document
9289   // anyway).
9290   // Rebuilding the frame tree can have bad effects, especially if it's the
9291   // frame tree for chrome (see bug 157322).
9292   if (NS_WARN_IF(!aContent->GetComposedDoc())) {
9293     return;
9294   }
9295 
9296   // Is the frame ib-split? If so, we need to reframe the containing
9297   // block *here*, rather than trying to remove and re-insert the
9298   // content (which would otherwise result in *two* nested reframe
9299   // containing block from ContentRemoved() and ContentInserted(),
9300   // below!).  We'd really like to optimize away one of those
9301   // containing block reframes, hence the code here.
9302 
9303   nsIFrame* frame = aContent->GetPrimaryFrame();
9304   if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
9305     // Reframe the topmost MathML element to prevent exponential blowup
9306     // (see bug 397518)
9307     while (true) {
9308       nsIContent* parentContent = aContent->GetParent();
9309       nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame();
9310       if (!parentContentFrame ||
9311           !parentContentFrame->IsFrameOfType(nsIFrame::eMathML))
9312         break;
9313       aContent = parentContent;
9314       frame = parentContentFrame;
9315     }
9316   }
9317 
9318   if (frame) {
9319     nsIFrame* nonGeneratedAncestor =
9320         nsLayoutUtils::GetNonGeneratedAncestor(frame);
9321     if (nonGeneratedAncestor->GetContent() != aContent) {
9322       return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
9323                                       InsertionKind::Async);
9324     }
9325 
9326     if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
9327       // Recreate the frames for the entire nsIAnonymousContentCreator tree
9328       // since |frame| or one of its descendants may need an nsStyleContext
9329       // that associates it to a CSS pseudo-element, and only the
9330       // nsIAnonymousContentCreator that created this content knows how to make
9331       // that happen.
9332       nsIAnonymousContentCreator* acc = nullptr;
9333       nsIFrame* ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
9334       while (!(acc = do_QueryFrame(ancestor))) {
9335         ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(ancestor);
9336       }
9337       NS_ASSERTION(acc,
9338                    "Where is the nsIAnonymousContentCreator? We may fail "
9339                    "to recreate its content correctly");
9340       // nsSVGUseFrame is special, and we know this is unnecessary for it.
9341       if (!ancestor->IsSVGUseFrame()) {
9342         NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
9343                      "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
9344         return RecreateFramesForContent(ancestor->GetContent(),
9345                                         InsertionKind::Async);
9346       }
9347     }
9348 
9349     nsIFrame* parent = frame->GetParent();
9350     nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
9351     // If the parent frame is a leaf then the subsequent insert will fail to
9352     // create a frame, so we need to recreate the parent content. This happens
9353     // with native anonymous content from the editor.
9354     if (parent && parent->IsLeaf() && parentContent &&
9355         parentContent != aContent) {
9356       return RecreateFramesForContent(parentContent, InsertionKind::Async);
9357     }
9358   }
9359 
9360   if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
9361     return;
9362   }
9363 
9364   nsINode* containerNode = aContent->GetParentNode();
9365   // XXXbz how can containerNode be null here?
9366   if (containerNode) {
9367     // Before removing the frames associated with the content object,
9368     // ask them to save their state onto a temporary state object.
9369     CaptureStateForFramesOf(aContent, mTempFrameTreeState);
9370 
9371     // Need the nsIContent parent, which might be null here, since we need to
9372     // pass it to ContentInserted and ContentRemoved.
9373     nsIContent* container = aContent->GetParent();
9374 
9375     // Remove the frames associated with the content object.
9376     nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree()
9377                                   ? nullptr
9378                                   : aContent->GetNextSibling();
9379     bool didReconstruct = ContentRemoved(container, aContent, nextSibling,
9380                                          REMOVE_FOR_RECONSTRUCTION);
9381 
9382     if (!didReconstruct) {
9383       if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
9384         // FIXME(emilio, bug 1397239): There's nothing removing the frame state
9385         // for elements that go away before we come back to the frame
9386         // constructor.
9387         //
9388         // Also, it'd be nice to just use the `ContentRangeInserted` path for
9389         // both elements and non-elements, but we need to make lazy frame
9390         // construction to apply to all elements first.
9391         RestyleManager()->PostRestyleEvent(aContent->AsElement(),
9392                                            nsRestyleHint(0),
9393                                            nsChangeHint_ReconstructFrame);
9394       } else {
9395         // Now, recreate the frames associated with this content object. If
9396         // ContentRemoved triggered reconstruction, then we don't need to do
9397         // this because the frames will already have been built.
9398         ContentRangeInserted(container, aContent, aContent->GetNextSibling(),
9399                              mTempFrameTreeState, aInsertionKind, nullptr);
9400       }
9401     }
9402   }
9403 }
9404 
DestroyFramesFor(Element * aElement)9405 bool nsCSSFrameConstructor::DestroyFramesFor(Element* aElement) {
9406   MOZ_ASSERT(aElement && aElement->GetParentNode());
9407 
9408   nsIContent* nextSibling = aElement->IsRootOfAnonymousSubtree()
9409                                 ? nullptr
9410                                 : aElement->GetNextSibling();
9411 
9412   CaptureStateForFramesOf(aElement, mTempFrameTreeState);
9413   return ContentRemoved(aElement->GetParent(), aElement, nextSibling,
9414                         REMOVE_FOR_RECONSTRUCTION);
9415 }
9416 
9417 //////////////////////////////////////////////////////////////////////
9418 
9419 // Block frame construction code
9420 
GetFirstLetterStyle(nsIContent * aContent,nsStyleContext * aStyleContext)9421 already_AddRefed<nsStyleContext> nsCSSFrameConstructor::GetFirstLetterStyle(
9422     nsIContent* aContent, nsStyleContext* aStyleContext) {
9423   if (aContent) {
9424     return mPresShell->StyleSet()->ResolvePseudoElementStyle(
9425         aContent->AsElement(), CSSPseudoElementType::firstLetter, aStyleContext,
9426         nullptr);
9427   }
9428   return nullptr;
9429 }
9430 
GetFirstLineStyle(nsIContent * aContent,nsStyleContext * aStyleContext)9431 already_AddRefed<nsStyleContext> nsCSSFrameConstructor::GetFirstLineStyle(
9432     nsIContent* aContent, nsStyleContext* aStyleContext) {
9433   if (aContent) {
9434     return mPresShell->StyleSet()->ResolvePseudoElementStyle(
9435         aContent->AsElement(), CSSPseudoElementType::firstLine, aStyleContext,
9436         nullptr);
9437   }
9438   return nullptr;
9439 }
9440 
9441 // Predicate to see if a given content (block element) has
9442 // first-letter style applied to it.
ShouldHaveFirstLetterStyle(nsIContent * aContent,nsStyleContext * aStyleContext)9443 bool nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(
9444     nsIContent* aContent, nsStyleContext* aStyleContext) {
9445   return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
9446                                        CSSPseudoElementType::firstLetter,
9447                                        mPresShell->GetPresContext());
9448 }
9449 
HasFirstLetterStyle(nsIFrame * aBlockFrame)9450 bool nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame) {
9451   NS_PRECONDITION(aBlockFrame, "Need a frame");
9452   NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame), "Not a block frame?");
9453 
9454   return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0;
9455 }
9456 
ShouldHaveFirstLineStyle(nsIContent * aContent,nsStyleContext * aStyleContext)9457 bool nsCSSFrameConstructor::ShouldHaveFirstLineStyle(
9458     nsIContent* aContent, nsStyleContext* aStyleContext) {
9459   bool hasFirstLine = nsLayoutUtils::HasPseudoStyle(
9460       aContent, aStyleContext, CSSPseudoElementType::firstLine,
9461       mPresShell->GetPresContext());
9462   if (hasFirstLine) {
9463     // But disable for fieldsets
9464     int32_t namespaceID;
9465     nsAtom* tag =
9466         mDocument->BindingManager()->ResolveTag(aContent, &namespaceID);
9467     // This check must match the one in FindHTMLData.
9468     hasFirstLine =
9469         tag != nsGkAtoms::fieldset || namespaceID != kNameSpaceID_XHTML;
9470   }
9471 
9472   return hasFirstLine;
9473 }
9474 
ShouldHaveSpecialBlockStyle(nsIContent * aContent,nsStyleContext * aStyleContext,bool * aHaveFirstLetterStyle,bool * aHaveFirstLineStyle)9475 void nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(
9476     nsIContent* aContent, nsStyleContext* aStyleContext,
9477     bool* aHaveFirstLetterStyle, bool* aHaveFirstLineStyle) {
9478   *aHaveFirstLetterStyle = ShouldHaveFirstLetterStyle(aContent, aStyleContext);
9479   *aHaveFirstLineStyle = ShouldHaveFirstLineStyle(aContent, aStyleContext);
9480 }
9481 
9482 /* static */
9483 const nsCSSFrameConstructor::PseudoParentData
9484     nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
9485         {// Cell
9486          FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9487                               FCDATA_USE_CHILD_ITEMS |
9488                               FCDATA_IS_WRAPPER_ANON_BOX |
9489                               FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
9490                           &nsCSSFrameConstructor::ConstructTableCell),
9491          &nsCSSAnonBoxes::tableCell},
9492         {// Row
9493          FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9494                               FCDATA_USE_CHILD_ITEMS |
9495                               FCDATA_IS_WRAPPER_ANON_BOX |
9496                               FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
9497                           &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
9498          &nsCSSAnonBoxes::tableRow},
9499         {// Row group
9500          FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9501                               FCDATA_USE_CHILD_ITEMS |
9502                               FCDATA_IS_WRAPPER_ANON_BOX |
9503                               FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9504                           &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
9505          &nsCSSAnonBoxes::tableRowGroup},
9506         {// Column group
9507          FCDATA_DECL(
9508              FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9509                  FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
9510                  FCDATA_SKIP_ABSPOS_PUSH |
9511                  // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
9512                  // restyle these: they have non-inheriting style contexts.
9513                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9514              NS_NewTableColGroupFrame),
9515          &nsCSSAnonBoxes::tableColGroup},
9516         {// Table
9517          FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
9518                               FCDATA_IS_WRAPPER_ANON_BOX,
9519                           &nsCSSFrameConstructor::ConstructTable),
9520          &nsCSSAnonBoxes::table},
9521         {// Ruby
9522          FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_USE_CHILD_ITEMS |
9523                          FCDATA_IS_WRAPPER_ANON_BOX | FCDATA_SKIP_FRAMESET,
9524                      NS_NewRubyFrame),
9525          &nsCSSAnonBoxes::ruby},
9526         {// Ruby Base
9527          FCDATA_DECL(
9528              FCDATA_USE_CHILD_ITEMS | FCDATA_IS_LINE_PARTICIPANT |
9529                  FCDATA_IS_WRAPPER_ANON_BOX |
9530                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
9531                  FCDATA_SKIP_FRAMESET,
9532              NS_NewRubyBaseFrame),
9533          &nsCSSAnonBoxes::rubyBase},
9534         {// Ruby Base Container
9535          FCDATA_DECL(FCDATA_USE_CHILD_ITEMS | FCDATA_IS_LINE_PARTICIPANT |
9536                          FCDATA_IS_WRAPPER_ANON_BOX |
9537                          FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
9538                          FCDATA_SKIP_FRAMESET,
9539                      NS_NewRubyBaseContainerFrame),
9540          &nsCSSAnonBoxes::rubyBaseContainer},
9541         {// Ruby Text
9542          FCDATA_DECL(
9543              FCDATA_USE_CHILD_ITEMS | FCDATA_IS_LINE_PARTICIPANT |
9544                  FCDATA_IS_WRAPPER_ANON_BOX |
9545                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
9546                  FCDATA_SKIP_FRAMESET,
9547              NS_NewRubyTextFrame),
9548          &nsCSSAnonBoxes::rubyText},
9549         {// Ruby Text Container
9550          FCDATA_DECL(FCDATA_USE_CHILD_ITEMS | FCDATA_IS_WRAPPER_ANON_BOX |
9551                          FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
9552                          FCDATA_SKIP_FRAMESET,
9553                      NS_NewRubyTextContainerFrame),
9554          &nsCSSAnonBoxes::rubyTextContainer}};
9555 
CreateNeededAnonFlexOrGridItems(nsFrameConstructorState & aState,FrameConstructionItemList & aItems,nsIFrame * aParentFrame)9556 void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
9557     nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
9558     nsIFrame* aParentFrame) {
9559   if (aItems.IsEmpty() || !::IsFlexOrGridContainer(aParentFrame)) {
9560     return;
9561   }
9562 
9563   const bool isLegacyBox = IsFlexContainerForLegacyBox(aParentFrame);
9564   FCItemIterator iter(aItems);
9565   do {
9566     // Advance iter past children that don't want to be wrapped
9567     if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
9568       // Hit the end of the items without finding any remaining children that
9569       // need to be wrapped. We're finished!
9570       return;
9571     }
9572 
9573     // If our next potentially-wrappable child is whitespace, then see if
9574     // there's anything wrappable immediately after it. If not, we just drop
9575     // the whitespace and move on. (We're not supposed to create any anonymous
9576     // flex/grid items that _only_ contain whitespace).
9577     // (BUT if this is generated content, then we don't give whitespace nodes
9578     // any special treatment, because they're probably not really whitespace --
9579     // they're just temporarily empty, waiting for their generated text.)
9580     // XXXdholbert If this node's generated text will *actually end up being
9581     // entirely whitespace*, then we technically should still skip over it, per
9582     // the CSS grid & flexbox specs. I'm not bothering with that at this point,
9583     // since it's a pretty extreme edge case.
9584     if (!aParentFrame->IsGeneratedContentFrame() &&
9585         iter.item().IsWhitespace(aState)) {
9586       FCItemIterator afterWhitespaceIter(iter);
9587       bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
9588       bool nextChildNeedsAnonItem =
9589           !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(
9590                          aState, isLegacyBox);
9591 
9592       if (!nextChildNeedsAnonItem) {
9593         // There's nothing after the whitespace that we need to wrap, so we
9594         // just drop this run of whitespace.
9595         iter.DeleteItemsTo(this, afterWhitespaceIter);
9596         if (hitEnd) {
9597           // Nothing left to do -- we're finished!
9598           return;
9599         }
9600         // else, we have a next child and it does not want to be wrapped.  So,
9601         // we jump back to the beginning of the loop to skip over that child
9602         // (and anything else non-wrappable after it)
9603         MOZ_ASSERT(!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem(
9604                                          aState, isLegacyBox),
9605                    "hitEnd and/or nextChildNeedsAnonItem lied");
9606         continue;
9607       }
9608     }
9609 
9610     // Now |iter| points to the first child that needs to be wrapped in an
9611     // anonymous flex/grid item. Now we see how many children after it also want
9612     // to be wrapped in an anonymous flex/grid item.
9613     FCItemIterator endIter(iter);  // iterator to find the end of the group
9614     endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox);
9615 
9616     NS_ASSERTION(iter != endIter,
9617                  "Should've had at least one wrappable child to seek past");
9618 
9619     // Now, we create the anonymous flex or grid item to contain the children
9620     // between |iter| and |endIter|.
9621     nsAtom* pseudoType = (aParentFrame->IsFlexContainerFrame())
9622                              ? nsCSSAnonBoxes::anonymousFlexItem
9623                              : nsCSSAnonBoxes::anonymousGridItem;
9624     nsStyleContext* parentStyle = aParentFrame->StyleContext();
9625     nsIContent* parentContent = aParentFrame->GetContent();
9626     already_AddRefed<nsStyleContext> wrapperStyle =
9627         mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
9628                                                                    parentStyle);
9629 
9630     static const FrameConstructionData sBlockFormattingContextFCData =
9631         FCDATA_DECL(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
9632                         FCDATA_IS_WRAPPER_ANON_BOX,
9633                     NS_NewBlockFormattingContext);
9634 
9635     FrameConstructionItem* newItem = new (this)
9636         FrameConstructionItem(&sBlockFormattingContextFCData,
9637                               // Use the content of our parent frame
9638                               parentContent,
9639                               // Lie about the tag; it doesn't matter anyway
9640                               pseudoType, iter.item().mNameSpaceID,
9641                               // no pending binding
9642                               nullptr, wrapperStyle, true, nullptr);
9643 
9644     newItem->mIsAllInline = newItem->mHasInlineEnds =
9645         newItem->mStyleContext->StyleDisplay()->IsInlineOutsideStyle();
9646     newItem->mIsBlock = !newItem->mIsAllInline;
9647 
9648     MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,
9649                "expecting anonymous flex/grid items to be block-level "
9650                "(this will make a difference when we encounter "
9651                "'align-items: baseline')");
9652 
9653     // Anonymous flex and grid items induce line boundaries around their
9654     // contents.
9655     newItem->mChildItems.SetLineBoundaryAtStart(true);
9656     newItem->mChildItems.SetLineBoundaryAtEnd(true);
9657     // The parent of the items in aItems is also the parent of the items
9658     // in mChildItems
9659     newItem->mChildItems.SetParentHasNoXBLChildren(
9660         aItems.ParentHasNoXBLChildren());
9661 
9662     // Eat up all items between |iter| and |endIter| and put them in our
9663     // wrapper. This advances |iter| to point to |endIter|.
9664     iter.AppendItemsToList(this, endIter, newItem->mChildItems);
9665 
9666     iter.InsertItem(newItem);
9667   } while (!iter.IsDone());
9668 }
9669 
9670 /* static */ nsCSSFrameConstructor::RubyWhitespaceType
ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,StyleDisplay aNextDisplay)9671 nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
9672                                                  StyleDisplay aNextDisplay) {
9673   MOZ_ASSERT(nsStyleDisplay::IsRubyDisplayType(aPrevDisplay) &&
9674              nsStyleDisplay::IsRubyDisplayType(aNextDisplay));
9675   if (aPrevDisplay == aNextDisplay &&
9676       (aPrevDisplay == StyleDisplay::RubyBase ||
9677        aPrevDisplay == StyleDisplay::RubyText)) {
9678     return eRubyInterLeafWhitespace;
9679   }
9680   if (aNextDisplay == StyleDisplay::RubyText ||
9681       aNextDisplay == StyleDisplay::RubyTextContainer) {
9682     return eRubyInterLevelWhitespace;
9683   }
9684   return eRubyInterSegmentWhitespace;
9685 }
9686 
9687 /**
9688  * This function checks the content from |aStartIter| to |aEndIter|,
9689  * determines whether it contains only whitespace, and if yes,
9690  * interprets the type of whitespace. This method does not change
9691  * any of the iters.
9692  */
9693 /* static */ nsCSSFrameConstructor::RubyWhitespaceType
InterpretRubyWhitespace(nsFrameConstructorState & aState,const FCItemIterator & aStartIter,const FCItemIterator & aEndIter)9694 nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
9695                                                const FCItemIterator& aStartIter,
9696                                                const FCItemIterator& aEndIter) {
9697   if (!aStartIter.item().IsWhitespace(aState)) {
9698     return eRubyNotWhitespace;
9699   }
9700 
9701   FCItemIterator spaceEndIter(aStartIter);
9702   spaceEndIter.SkipWhitespace(aState);
9703   if (spaceEndIter != aEndIter) {
9704     return eRubyNotWhitespace;
9705   }
9706 
9707   // Any leading or trailing whitespace in non-pseudo ruby box
9708   // should have been trimmed, hence there should not be any
9709   // whitespace at the start or the end.
9710   MOZ_ASSERT(!aStartIter.AtStart() && !aEndIter.IsDone());
9711   FCItemIterator prevIter(aStartIter);
9712   prevIter.Prev();
9713   return ComputeRubyWhitespaceType(
9714       prevIter.item().mStyleContext->StyleDisplay()->mDisplay,
9715       aEndIter.item().mStyleContext->StyleDisplay()->mDisplay);
9716 }
9717 
9718 /**
9719  * This function eats up consecutive items which do not want the current
9720  * parent into either a ruby base box or a ruby text box.  When it
9721  * returns, |aIter| points to the first item it doesn't wrap.
9722  */
WrapItemsInPseudoRubyLeafBox(FCItemIterator & aIter,nsStyleContext * aParentStyle,nsIContent * aParentContent)9723 void nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
9724     FCItemIterator& aIter, nsStyleContext* aParentStyle,
9725     nsIContent* aParentContent) {
9726   StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
9727   ParentType parentType, wrapperType;
9728   if (parentDisplay == StyleDisplay::RubyTextContainer) {
9729     parentType = eTypeRubyTextContainer;
9730     wrapperType = eTypeRubyText;
9731   } else {
9732     MOZ_ASSERT(parentDisplay == StyleDisplay::RubyBaseContainer);
9733     parentType = eTypeRubyBaseContainer;
9734     wrapperType = eTypeRubyBase;
9735   }
9736 
9737   MOZ_ASSERT(aIter.item().DesiredParentType() != parentType,
9738              "Should point to something needs to be wrapped.");
9739 
9740   FCItemIterator endIter(aIter);
9741   endIter.SkipItemsNotWantingParentType(parentType);
9742 
9743   WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
9744                           endIter);
9745 }
9746 
9747 /**
9748  * This function eats up consecutive items into a ruby level container.
9749  * It may create zero or one level container. When it returns, |aIter|
9750  * points to the first item it doesn't wrap.
9751  */
WrapItemsInPseudoRubyLevelContainer(nsFrameConstructorState & aState,FCItemIterator & aIter,nsStyleContext * aParentStyle,nsIContent * aParentContent)9752 void nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
9753     nsFrameConstructorState& aState, FCItemIterator& aIter,
9754     nsStyleContext* aParentStyle, nsIContent* aParentContent) {
9755   MOZ_ASSERT(aIter.item().DesiredParentType() != eTypeRuby,
9756              "Pointing to a level container?");
9757 
9758   FrameConstructionItem& firstItem = aIter.item();
9759   ParentType wrapperType = firstItem.DesiredParentType();
9760   if (wrapperType != eTypeRubyTextContainer) {
9761     // If the first item is not ruby text,
9762     // it should be in a base container.
9763     wrapperType = eTypeRubyBaseContainer;
9764   }
9765 
9766   FCItemIterator endIter(aIter);
9767   do {
9768     if (endIter.SkipItemsWantingParentType(wrapperType) ||
9769         // If the skipping above stops at some item which wants a
9770         // different ruby parent, then we have finished.
9771         IsRubyParentType(endIter.item().DesiredParentType())) {
9772       // No more items need to be wrapped in this level container.
9773       break;
9774     }
9775 
9776     FCItemIterator contentEndIter(endIter);
9777     contentEndIter.SkipItemsNotWantingRubyParent();
9778     // endIter must be on something doesn't want a ruby parent.
9779     MOZ_ASSERT(contentEndIter != endIter);
9780 
9781     // InterpretRubyWhitespace depends on the fact that any leading or
9782     // trailing whitespace described in the spec have been trimmed at
9783     // this point. With this precondition, it is safe not to check
9784     // whether contentEndIter has been done.
9785     RubyWhitespaceType whitespaceType =
9786         InterpretRubyWhitespace(aState, endIter, contentEndIter);
9787     if (whitespaceType == eRubyInterLevelWhitespace) {
9788       // Remove inter-level whitespace.
9789       bool atStart = (aIter == endIter);
9790       endIter.DeleteItemsTo(this, contentEndIter);
9791       if (atStart) {
9792         aIter = endIter;
9793       }
9794     } else if (whitespaceType == eRubyInterSegmentWhitespace) {
9795       // If this level container starts with inter-segment whitespaces,
9796       // wrap them. Break at contentEndIter. Otherwise, leave it here.
9797       // Break at endIter. They will be wrapped when we are here again.
9798       if (aIter == endIter) {
9799         MOZ_ASSERT(wrapperType == eTypeRubyBaseContainer,
9800                    "Inter-segment whitespace should be wrapped in rbc");
9801         endIter = contentEndIter;
9802       }
9803       break;
9804     } else if (wrapperType == eTypeRubyTextContainer &&
9805                whitespaceType != eRubyInterLeafWhitespace) {
9806       // Misparented inline content that's not inter-annotation
9807       // whitespace doesn't belong in a pseudo ruby text container.
9808       // Break at endIter.
9809       break;
9810     } else {
9811       endIter = contentEndIter;
9812     }
9813   } while (!endIter.IsDone());
9814 
9815   // It is possible that everything our parent wants us to wrap is
9816   // simply an inter-level whitespace, which has been trimmed, or
9817   // an inter-segment whitespace, which will be wrapped later.
9818   // In those cases, don't create anything.
9819   if (aIter != endIter) {
9820     WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
9821                             endIter);
9822   }
9823 }
9824 
9825 /**
9826  * This function trims leading and trailing whitespaces
9827  * in the given item list.
9828  */
TrimLeadingAndTrailingWhitespaces(nsFrameConstructorState & aState,FrameConstructionItemList & aItems)9829 void nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
9830     nsFrameConstructorState& aState, FrameConstructionItemList& aItems) {
9831   FCItemIterator iter(aItems);
9832   if (!iter.IsDone() && iter.item().IsWhitespace(aState)) {
9833     FCItemIterator spaceEndIter(iter);
9834     spaceEndIter.SkipWhitespace(aState);
9835     iter.DeleteItemsTo(this, spaceEndIter);
9836   }
9837 
9838   iter.SetToEnd();
9839   if (!iter.AtStart()) {
9840     FCItemIterator spaceEndIter(iter);
9841     do {
9842       iter.Prev();
9843       if (iter.AtStart()) {
9844         // It's fine to not check the first item, because we
9845         // should have trimmed leading whitespaces above.
9846         break;
9847       }
9848     } while (iter.item().IsWhitespace(aState));
9849     iter.Next();
9850     if (iter != spaceEndIter) {
9851       iter.DeleteItemsTo(this, spaceEndIter);
9852     }
9853   }
9854 }
9855 
9856 /**
9857  * This function walks through the child list (aItems) and creates
9858  * needed pseudo ruby boxes to wrap misparented children.
9859  */
CreateNeededPseudoInternalRubyBoxes(nsFrameConstructorState & aState,FrameConstructionItemList & aItems,nsIFrame * aParentFrame)9860 void nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
9861     nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
9862     nsIFrame* aParentFrame) {
9863   const ParentType ourParentType = GetParentType(aParentFrame);
9864   if (!IsRubyParentType(ourParentType) ||
9865       aItems.AllWantParentType(ourParentType)) {
9866     return;
9867   }
9868 
9869   if (!IsRubyPseudo(aParentFrame)) {
9870     // Normally, ruby pseudo frames start from and end at some elements,
9871     // which means they don't have leading and trailing whitespaces at
9872     // all.  But there are two cases where they do actually have leading
9873     // or trailing whitespaces:
9874     // 1. It is an inter-segment whitespace which in an individual ruby
9875     //    base container.
9876     // 2. The pseudo frame starts from or ends at consecutive inline
9877     //    content, which is not pure whitespace, but includes some.
9878     // In either case, the whitespaces are not the leading or trailing
9879     // whitespaces defined in the spec, and thus should not be trimmed.
9880     TrimLeadingAndTrailingWhitespaces(aState, aItems);
9881   }
9882 
9883   FCItemIterator iter(aItems);
9884   nsIContent* parentContent = aParentFrame->GetContent();
9885   nsStyleContext* parentStyle = aParentFrame->StyleContext();
9886   while (!iter.IsDone()) {
9887     if (!iter.SkipItemsWantingParentType(ourParentType)) {
9888       if (ourParentType == eTypeRuby) {
9889         WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
9890                                             parentContent);
9891       } else {
9892         WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
9893       }
9894     }
9895   }
9896 }
9897 
9898 /*
9899  * This function works as follows: we walk through the child list (aItems) and
9900  * find items that cannot have aParentFrame as their parent.  We wrap
9901  * continuous runs of such items into a FrameConstructionItem for a frame that
9902  * gets them closer to their desired parents.  For example, a run of non-row
9903  * children of a row-group will get wrapped in a row.  When we later construct
9904  * the frame for this wrapper (in this case for the row), it'll be the correct
9905  * parent for the cells in the set of items we wrapped or we'll wrap cells
9906  * around everything else.  At the end of this method, aItems is guaranteed to
9907  * contain only items for frames that can be direct kids of aParentFrame.
9908  */
CreateNeededPseudoContainers(nsFrameConstructorState & aState,FrameConstructionItemList & aItems,nsIFrame * aParentFrame)9909 void nsCSSFrameConstructor::CreateNeededPseudoContainers(
9910     nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
9911     nsIFrame* aParentFrame) {
9912   ParentType ourParentType = GetParentType(aParentFrame);
9913   if (IsRubyParentType(ourParentType) ||
9914       aItems.AllWantParentType(ourParentType)) {
9915     // Nothing to do here
9916     return;
9917   }
9918 
9919   FCItemIterator iter(aItems);
9920   do {
9921     if (iter.SkipItemsWantingParentType(ourParentType)) {
9922       // Nothing else to do here; we're finished
9923       return;
9924     }
9925 
9926     // Now we're pointing to the first child that wants a different parent
9927     // type.
9928 
9929     // Now try to figure out what kids we can group together.  We can generally
9930     // group everything that has a different desired parent type from us.  Two
9931     // exceptions to this:
9932     // 1) If our parent type is table, we can't group columns with anything
9933     //    else other than whitespace.
9934     // 2) Whitespace that lies between two things we can group which both want
9935     //    a non-block parent should be dropped, even if we can't group them
9936     //    with each other and even if the whitespace wants a parent of
9937     //    ourParentType.  Ends of the list count as things that don't want a
9938     //    block parent (so that for example we'll drop a whitespace-only list).
9939 
9940     FCItemIterator endIter(iter); /* iterator to find the end of the group */
9941     ParentType groupingParentType = endIter.item().DesiredParentType();
9942     if (aItems.AllWantParentType(groupingParentType) &&
9943         groupingParentType != eTypeBlock) {
9944       // Just group them all and be done with it.  We need the check for
9945       // eTypeBlock here to catch the "all the items are whitespace" case
9946       // described above.
9947       endIter.SetToEnd();
9948     } else {
9949       // Locate the end of the group.
9950 
9951       // Keep track of the type the previous item wanted, in case we have to
9952       // deal with whitespace.  Start it off with ourParentType, since that's
9953       // the last thing |iter| would have skipped over.
9954       ParentType prevParentType = ourParentType;
9955       do {
9956         // Walk an iterator past any whitespace that we might be able to drop
9957         // from the list
9958         FCItemIterator spaceEndIter(endIter);
9959         if (prevParentType != eTypeBlock &&
9960             !aParentFrame->IsGeneratedContentFrame() &&
9961             spaceEndIter.item().IsWhitespace(aState)) {
9962           bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
9963 
9964           // We drop the whitespace in the following cases:
9965           // 1) If these are not trailing spaces and the next item wants a table
9966           //    or table-part parent
9967           // 2) If these are trailing spaces and aParentFrame is a
9968           //    tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
9969           //    (Being a tabular container pretty much means ourParentType is
9970           //    not eTypeBlock besides the eTypeColGroup case, which won't
9971           //    reach here.)
9972           if ((!trailingSpaces &&
9973                IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
9974               (trailingSpaces && ourParentType != eTypeBlock)) {
9975             bool updateStart = (iter == endIter);
9976             endIter.DeleteItemsTo(this, spaceEndIter);
9977             NS_ASSERTION(trailingSpaces == endIter.IsDone(),
9978                          "These should match");
9979 
9980             if (updateStart) {
9981               iter = endIter;
9982             }
9983 
9984             if (trailingSpaces) {
9985               break; /* Found group end */
9986             }
9987 
9988             if (updateStart) {
9989               // Update groupingParentType, since it might have been eTypeBlock
9990               // just because of the whitespace.
9991               groupingParentType = iter.item().DesiredParentType();
9992             }
9993           }
9994         }
9995 
9996         // Now endIter points to a non-whitespace item or a non-droppable
9997         // whitespace item. In the latter case, if this is the end of the group
9998         // we'll traverse this whitespace again.  But it'll all just be quick
9999         // DesiredParentType() checks which will match ourParentType (that's
10000         // what it means that this is the group end), so it's OK.
10001         // However, when we are grouping a ruby parent, and endIter points to
10002         // a non-droppable whitespace, if the next non-whitespace item also
10003         // wants a ruby parent, the whitespace should also be included into
10004         // the current ruby container.
10005         prevParentType = endIter.item().DesiredParentType();
10006         if (prevParentType == ourParentType &&
10007             (endIter == spaceEndIter || spaceEndIter.IsDone() ||
10008              !IsRubyParentType(groupingParentType) ||
10009              !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
10010           // End the group at endIter.
10011           break;
10012         }
10013 
10014         if (ourParentType == eTypeTable &&
10015             (prevParentType == eTypeColGroup) !=
10016                 (groupingParentType == eTypeColGroup)) {
10017           // Either we started with columns and now found something else, or
10018           // vice versa.  In any case, end the grouping.
10019           break;
10020         }
10021 
10022         // If we have some whitespace that we were not able to drop and there is
10023         // an item after the whitespace that is already properly parented, then
10024         // make sure to include the spaces in our group but stop the group after
10025         // that.
10026         if (spaceEndIter != endIter && !spaceEndIter.IsDone() &&
10027             ourParentType == spaceEndIter.item().DesiredParentType()) {
10028           endIter = spaceEndIter;
10029           break;
10030         }
10031 
10032         // Include the whitespace we didn't drop (if any) in the group.
10033         endIter = spaceEndIter;
10034         prevParentType = endIter.item().DesiredParentType();
10035 
10036         endIter.Next();
10037       } while (!endIter.IsDone());
10038     }
10039 
10040     if (iter == endIter) {
10041       // Nothing to wrap here; just skipped some whitespace
10042       continue;
10043     }
10044 
10045     // Now group together all the items between iter and endIter.  The right
10046     // parent type to use depends on ourParentType.
10047     ParentType wrapperType;
10048     switch (ourParentType) {
10049       case eTypeRow:
10050         // The parent type for a cell is eTypeBlock, since that's what a cell
10051         // looks like to its kids.
10052         wrapperType = eTypeBlock;
10053         break;
10054       case eTypeRowGroup:
10055         wrapperType = eTypeRow;
10056         break;
10057       case eTypeTable:
10058         // Either colgroup or rowgroup, depending on what we're grouping.
10059         wrapperType =
10060             groupingParentType == eTypeColGroup ? eTypeColGroup : eTypeRowGroup;
10061         break;
10062       case eTypeColGroup:
10063         MOZ_CRASH("Colgroups should be suppresing non-col child items");
10064       default:
10065         NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type");
10066         if (IsRubyParentType(groupingParentType)) {
10067           wrapperType = eTypeRuby;
10068         } else {
10069           NS_ASSERTION(IsTableParentType(groupingParentType),
10070                        "groupingParentType should be either Ruby or table");
10071           wrapperType = eTypeTable;
10072         }
10073     }
10074 
10075     nsStyleContext* parentStyle = aParentFrame->StyleContext();
10076     WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
10077                             wrapperType, iter, endIter);
10078 
10079     // Now |iter| points to the item that was the first one we didn't wrap;
10080     // loop and see whether we need to skip it or wrap it in something
10081     // different.
10082   } while (!iter.IsDone());
10083 }
10084 
10085 /**
10086  * This method wraps frame construction item from |aIter| to
10087  * |aEndIter|. After it returns, aIter points to the first item
10088  * after the wrapper.
10089  */
WrapItemsInPseudoParent(nsIContent * aParentContent,nsStyleContext * aParentStyle,ParentType aWrapperType,FCItemIterator & aIter,const FCItemIterator & aEndIter)10090 void nsCSSFrameConstructor::WrapItemsInPseudoParent(
10091     nsIContent* aParentContent, nsStyleContext* aParentStyle,
10092     ParentType aWrapperType, FCItemIterator& aIter,
10093     const FCItemIterator& aEndIter) {
10094   const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
10095   nsAtom* pseudoType = *pseudoData.mPseudoType;
10096   StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
10097 
10098   if (pseudoType == nsCSSAnonBoxes::table &&
10099       (parentDisplay == StyleDisplay::Inline ||
10100        parentDisplay == StyleDisplay::RubyBase ||
10101        parentDisplay == StyleDisplay::RubyText)) {
10102     pseudoType = nsCSSAnonBoxes::inlineTable;
10103   }
10104 
10105   already_AddRefed<nsStyleContext> wrapperStyle;
10106   if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX) {
10107     wrapperStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10108         pseudoType, aParentStyle);
10109   } else {
10110     wrapperStyle =
10111         mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
10112             pseudoType);
10113   }
10114 
10115   FrameConstructionItem* newItem = new (this)
10116       FrameConstructionItem(&pseudoData.mFCData,
10117                             // Use the content of our parent frame
10118                             aParentContent,
10119                             // Lie about the tag; it doesn't matter anyway
10120                             pseudoType,
10121                             // The namespace does matter, however; it needs
10122                             // to match that of our first child item to
10123                             // match the old behavior
10124                             aIter.item().mNameSpaceID,
10125                             // no pending binding
10126                             nullptr, wrapperStyle, true, nullptr);
10127 
10128   const nsStyleDisplay* disp = newItem->mStyleContext->StyleDisplay();
10129   // Here we're cheating a tad... technically, table-internal items should be
10130   // inline if aParentFrame is inline, but they'll get wrapped in an
10131   // inline-table in the end, so it'll all work out.  In any case, arguably
10132   // we don't need to maintain this state at this point... but it's better
10133   // to, I guess.
10134   newItem->mIsAllInline = newItem->mHasInlineEnds =
10135       disp->IsInlineOutsideStyle();
10136 
10137   bool isRuby = disp->IsRubyDisplayType();
10138   // All types of ruby frames need a block frame to provide line layout,
10139   // hence they are always line participant.
10140   newItem->mIsLineParticipant = isRuby;
10141 
10142   if (!isRuby) {
10143     // Table pseudo frames always induce line boundaries around their
10144     // contents.
10145     newItem->mChildItems.SetLineBoundaryAtStart(true);
10146     newItem->mChildItems.SetLineBoundaryAtEnd(true);
10147   }
10148   // The parent of the items in aItems is also the parent of the items
10149   // in mChildItems
10150   newItem->mChildItems.SetParentHasNoXBLChildren(
10151       aIter.List()->ParentHasNoXBLChildren());
10152 
10153   // Eat up all items between |aIter| and |aEndIter| and put them in our
10154   // wrapper Advances |aIter| to point to |aEndIter|.
10155   aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
10156 
10157   aIter.InsertItem(newItem);
10158 }
10159 
CreateNeededPseudoSiblings(nsFrameConstructorState & aState,FrameConstructionItemList & aItems,nsIFrame * aParentFrame)10160 void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
10161     nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
10162     nsIFrame* aParentFrame) {
10163   if (aItems.IsEmpty() || GetParentType(aParentFrame) != eTypeRuby) {
10164     return;
10165   }
10166 
10167   FCItemIterator iter(aItems);
10168   StyleDisplay firstDisplay =
10169       iter.item().mStyleContext->StyleDisplay()->mDisplay;
10170   if (firstDisplay == StyleDisplay::RubyBaseContainer) {
10171     return;
10172   }
10173   NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,
10174                "Child of ruby frame should either a rbc or a rtc");
10175 
10176   const PseudoParentData& pseudoData =
10177       sPseudoParentData[eTypeRubyBaseContainer];
10178   already_AddRefed<nsStyleContext> pseudoStyle =
10179       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10180           *pseudoData.mPseudoType, aParentFrame->StyleContext());
10181   FrameConstructionItem* newItem =
10182       new (this) FrameConstructionItem(&pseudoData.mFCData,
10183                                        // Use the content of the parent frame
10184                                        aParentFrame->GetContent(),
10185                                        // Tag type
10186                                        *pseudoData.mPseudoType,
10187                                        // Use the namespace of the rtc frame
10188                                        iter.item().mNameSpaceID,
10189                                        // no pending binding
10190                                        nullptr, pseudoStyle, true, nullptr);
10191   newItem->mIsAllInline = true;
10192   newItem->mChildItems.SetParentHasNoXBLChildren(true);
10193   iter.InsertItem(newItem);
10194 }
10195 
10196 #ifdef DEBUG
10197 /**
10198  * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
10199  * rather than being a direct child of aContainerFrame.
10200  *
10201  * NOTE: aContainerFrame must be a flex or grid container - this function is
10202  * purely for sanity-checking the children of these container types.
10203  * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
10204  * logic (which operates a bit earlier, on FCData instead of frames).
10205  */
FrameWantsToBeInAnonymousItem(const nsIFrame * aContainerFrame,const nsIFrame * aFrame)10206 static bool FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
10207                                           const nsIFrame* aFrame) {
10208   MOZ_ASSERT(::IsFlexOrGridContainer(aContainerFrame));
10209 
10210   // Any line-participant frames (e.g. text) definitely want to be wrapped in
10211   // an anonymous flex/grid item.
10212   if (aFrame->IsFrameOfType(nsIFrame::eLineParticipant)) {
10213     return true;
10214   }
10215 
10216   // If the container is a -webkit-{inline-}box or -moz-{inline-}box container,
10217   // then placeholders also need to be wrapped, for compatibility.
10218   if (IsFlexContainerForLegacyBox(aContainerFrame) &&
10219       aFrame->IsPlaceholderFrame()) {
10220     return true;
10221   }
10222 
10223   return false;
10224 }
10225 #endif
10226 
VerifyGridFlexContainerChildren(nsIFrame * aParentFrame,const nsFrameList & aChildren)10227 static void VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
10228                                             const nsFrameList& aChildren) {
10229 #ifdef DEBUG
10230   if (!::IsFlexOrGridContainer(aParentFrame)) {
10231     return;
10232   }
10233 
10234   bool prevChildWasAnonItem = false;
10235   for (const nsIFrame* child : aChildren) {
10236     MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(aParentFrame, child),
10237                "frame wants to be inside an anonymous item, but it isn't");
10238     if (IsAnonymousFlexOrGridItem(child)) {
10239       AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
10240       MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row");
10241       nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
10242       MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty");
10243       prevChildWasAnonItem = true;
10244     } else {
10245       prevChildWasAnonItem = false;
10246     }
10247   }
10248 #endif
10249 }
10250 
ConstructFramesFromItemList(nsFrameConstructorState & aState,FrameConstructionItemList & aItems,nsContainerFrame * aParentFrame,bool aParentIsWrapperAnonBox,nsFrameItems & aFrameItems)10251 inline void nsCSSFrameConstructor::ConstructFramesFromItemList(
10252     nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
10253     nsContainerFrame* aParentFrame, bool aParentIsWrapperAnonBox,
10254     nsFrameItems& aFrameItems) {
10255   // Ensure aParentIsWrapperAnonBox is correct.  We _could_ compute it directly,
10256   // but it would be a bit slow, which is why we pass it from callers, who have
10257   // that information offhand in many cases.
10258   MOZ_ASSERT(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox);
10259 
10260   CreateNeededPseudoContainers(aState, aItems, aParentFrame);
10261   CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
10262   CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
10263   CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
10264 
10265   aItems.SetTriedConstructingFrames();
10266   for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
10267     NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
10268                  "Needed pseudos didn't get created; expect bad things");
10269     ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
10270   }
10271 
10272   VerifyGridFlexContainerChildren(aParentFrame, aFrameItems);
10273   NS_ASSERTION(!aState.mHavePendingPopupgroup,
10274                "Should have proccessed it by now");
10275 
10276   if (aParentIsWrapperAnonBox) {
10277     for (nsIFrame* f : aFrameItems) {
10278       f->SetParentIsWrapperAnonBox();
10279     }
10280   }
10281 }
10282 
AddFCItemsForAnonymousContent(nsFrameConstructorState & aState,nsContainerFrame * aFrame,nsTArray<nsIAnonymousContentCreator::ContentInfo> & aAnonymousItems,FrameConstructionItemList & aItemsToConstruct,uint32_t aExtraFlags)10283 void nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
10284     nsFrameConstructorState& aState, nsContainerFrame* aFrame,
10285     nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
10286     FrameConstructionItemList& aItemsToConstruct, uint32_t aExtraFlags) {
10287   for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) {
10288     nsIContent* content = aAnonymousItems[i].mContent;
10289     // Gecko-styled nodes should have no pending restyle flags.
10290     MOZ_ASSERT(content->IsStyledByServo() || !content->IsElement() ||
10291                !(content->GetFlags() & ELEMENT_ALL_RESTYLE_FLAGS));
10292     // Assert some things about this content
10293     MOZ_ASSERT(!(content->GetFlags() &
10294                  (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
10295                "Should not be marked as needing frames");
10296     MOZ_ASSERT(!content->GetPrimaryFrame(), "Should have no existing frame");
10297     MOZ_ASSERT(!content->IsNodeOfType(nsINode::eCOMMENT) &&
10298                    !content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION),
10299                "Why is someone creating garbage anonymous content");
10300 
10301     RefPtr<nsStyleContext> styleContext;
10302     Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
10303         parentDisplayBasedStyleFixupSkipper;
10304     MOZ_ASSERT(aState.mTreeMatchContext || content->IsStyledByServo());
10305     if (aState.mTreeMatchContext) {
10306       parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
10307     }
10308 
10309     // Make sure we eagerly performed the servo cascade when the anonymous
10310     // nodes were created.
10311     MOZ_ASSERT(!content->IsStyledByServo() || !content->IsElement() ||
10312                content->AsElement()->HasServoData());
10313 
10314     // Determine whether this NAC is pseudo-implementing.
10315     nsAtom* pseudo = nullptr;
10316     if (content->IsElement()) {
10317       auto pseudoType = content->AsElement()->GetPseudoElementType();
10318       if (pseudoType != CSSPseudoElementType::NotPseudo) {
10319         pseudo = nsCSSPseudoElements::GetPseudoAtom(pseudoType);
10320       }
10321     }
10322 
10323     // Determine the appropriate parent style for this NAC, and if the NAC
10324     // implements a pseudo-element, the appropriate originating element
10325     // (that is to say, the element to the left of the ::pseudo-element in
10326     // the selector). This is all rather tricky, and merits some discussion.
10327     //
10328     // First, it's important to note that author stylesheets generally do not
10329     // apply to elements in native-anonymous subtrees. The exceptions to
10330     // this are web-exposed pseudo-elements, where authors can style the
10331     // pseudo-implementing NAC if the originating element is not itself in a NAC
10332     // subtree.
10333     //
10334     // For this reason, it's very important that we avoid using a style parent
10335     // that is inside a NAC subtree together with an originating element that
10336     // is not inside a NAC subtree, since that would allow authors to
10337     // explicitly inherit styles from internal elements, potentially making
10338     // the NAC hierarchy observable. To ensure this, and generally simplify
10339     // things, we always set the originating element to the style parent.
10340     //
10341     // As a consequence of the above, all web-exposed pseudo-elements (which,
10342     // by definition, must have a content-accessible originating element) must
10343     // also inherit style from that same content-accessible element. To avoid
10344     // unintuitive behavior differences between NAC elements that do and don't
10345     // correspond to web-exposed pseudo-elements, we follow this protocol for
10346     // all NAC, pseudo-implementing or not.
10347     //
10348     // However, things get tricky with the <video> element, where we have a
10349     // bunch of XBL-generated anonymous content descending from a native-
10350     // anonymous XULElement. The XBL elements inherit style from their
10351     // flattened tree parent, because that's how XBL works. But then we need
10352     // to figure out what to do when one of those anonymous XBL elements
10353     // (like an <input> element) generates its own (possibly pseudo-element-
10354     // implementing) NAC.
10355     //
10356     // In this case, we inherit style from the XBL-generated NAC-creating
10357     // element, rather than the <video> element. There are a number of good
10358     // reasons for this. First, inheriting from the great-grandparent while
10359     // the parent inherits from the grandparent would be bizarre at best.
10360     // Second, exposing pseudo-elements from elements within our particular
10361     // XBL implementation would allow content styles to (un)intentionally
10362     // alter the video controls, which would be very bad. Third, our UA
10363     // stylesheets have selectors like:
10364     //
10365     // input[type=range][orient=horizontal]::-moz-range-track
10366     //
10367     // and we need to make sure that the originating element is the <input>,
10368     // not the <video>, because that's where the |orient| attribute lives.
10369     //
10370     // The upshot of all of this is that, to find the style parent (and
10371     // originating element, if applicable), we walk up our parent chain to the
10372     // first element that is not itself NAC (distinct from whether it happens
10373     // to be in a NAC subtree).
10374     //
10375     // The one exception to all of this is scrollbar content, which we parent
10376     // directly to the scrollframe. This is because the special-snowflake
10377     // construction of scroll frames doesn't result in the placeholder frame
10378     // being constructed until later, which means that GetInFlowParent() doesn't
10379     // work right in the case of out-of-flow scrollframes.
10380     //
10381     // To implement all this, we need to pass the correct parent style context
10382     // here because SetPrimaryFrame() may not have been called on the content
10383     // yet and thus ResolveStyleContext can't find it otherwise.
10384     //
10385     // We don't need to worry about display:contents here, because such
10386     // elements don't get a frame and thus can't generate NAC. But we do need
10387     // to worry about anonymous boxes, which CorrectStyleParentFrame handles
10388     // for us.
10389     nsIFrame* inheritFrame = aFrame;
10390     if (!content->IsNativeScrollbarContent()) {
10391       while (inheritFrame->GetContent()->IsNativeAnonymous()) {
10392         inheritFrame = inheritFrame->GetInFlowParent();
10393       }
10394     }
10395 
10396     nsIFrame* styleParentFrame =
10397         nsFrame::CorrectStyleParentFrame(inheritFrame, pseudo);
10398     // The only way we can not have a style parent now is if inheritFrame is the
10399     // canvas frame and we're the NAC parent for all the things added via
10400     // nsIDocument::InsertAnonymousContent.
10401     MOZ_ASSERT(styleParentFrame || inheritFrame->IsCanvasFrame());
10402     // And that anonymous div has no pseudo.
10403     MOZ_ASSERT(styleParentFrame || !pseudo);
10404 
10405     Element* originating =
10406         pseudo ? styleParentFrame->GetContent()->AsElement() : nullptr;
10407     nsStyleContext* parentStyle =
10408         styleParentFrame ? styleParentFrame->StyleContext() : nullptr;
10409     styleContext =
10410         ResolveStyleContext(parentStyle, content, &aState, originating);
10411 
10412     nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
10413     if (!aAnonymousItems[i].mChildren.IsEmpty()) {
10414       anonChildren = &aAnonymousItems[i].mChildren;
10415     }
10416 
10417     uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK |
10418                      ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags;
10419 
10420     AddFrameConstructionItemsInternal(
10421         aState, content, aFrame, content->NodeInfo()->NameAtom(),
10422         content->GetNameSpaceID(), true, styleContext, flags, anonChildren,
10423         aItemsToConstruct);
10424   }
10425 }
10426 
ProcessChildren(nsFrameConstructorState & aState,nsIContent * aContent,nsStyleContext * aStyleContext,nsContainerFrame * aFrame,const bool aCanHaveGeneratedContent,nsFrameItems & aFrameItems,const bool aAllowBlockStyles,PendingBinding * aPendingBinding,nsIFrame * aPossiblyLeafFrame)10427 void nsCSSFrameConstructor::ProcessChildren(
10428     nsFrameConstructorState& aState, nsIContent* aContent,
10429     nsStyleContext* aStyleContext, nsContainerFrame* aFrame,
10430     const bool aCanHaveGeneratedContent, nsFrameItems& aFrameItems,
10431     const bool aAllowBlockStyles, PendingBinding* aPendingBinding,
10432     nsIFrame* aPossiblyLeafFrame) {
10433   NS_PRECONDITION(aFrame, "Must have parent frame here");
10434   NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
10435                   "Parent frame in ProcessChildren should be its own "
10436                   "content insertion frame");
10437   const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
10438   static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
10439   AutoRestore<uint16_t> savedDepth(mCurrentDepth);
10440   if (mCurrentDepth != UINT16_MAX) {
10441     ++mCurrentDepth;
10442   }
10443 
10444   if (!aPossiblyLeafFrame) {
10445     aPossiblyLeafFrame = aFrame;
10446   }
10447 
10448   // XXXbz ideally, this would do all the pushing of various
10449   // containing blocks as needed, so callers don't have to do it...
10450 
10451   // Check that our parent frame is a block before allowing ::first-letter/line.
10452   // E.g. <button style="display:grid"> should not allow it.
10453   const bool allowFirstPseudos =
10454       aAllowBlockStyles && nsLayoutUtils::GetAsBlock(aFrame);
10455   bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
10456   if (allowFirstPseudos) {
10457     ShouldHaveSpecialBlockStyle(aContent, aStyleContext, &haveFirstLetterStyle,
10458                                 &haveFirstLineStyle);
10459   }
10460 
10461   const bool isFlexOrGridContainer = ::IsFlexOrGridContainer(aFrame);
10462   // The logic here needs to match the logic in GetFloatContainingBlock()
10463   // (Since we already have isFlexOrGridContainer, we check that eagerly instead
10464   // of letting ShouldSuppressFloatingOfDescendants look it up redundantly.)
10465   nsFrameConstructorSaveState floatSaveState;
10466   if (isFlexOrGridContainer || ShouldSuppressFloatingOfDescendants(aFrame)) {
10467     aState.PushFloatContainingBlock(nullptr, floatSaveState);
10468   } else if (aFrame->IsFloatContainingBlock()) {
10469     aState.PushFloatContainingBlock(aFrame, floatSaveState);
10470   }
10471 
10472   nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
10473                                                            aPendingBinding);
10474 
10475   AutoFrameConstructionItemList itemsToConstruct(this);
10476 
10477   // If we have first-letter or first-line style then frames can get
10478   // moved around so don't set these flags.
10479   if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
10480     itemsToConstruct.SetLineBoundaryAtStart(true);
10481     itemsToConstruct.SetLineBoundaryAtEnd(true);
10482   }
10483 
10484   // Create any anonymous frames we need here.  This must happen before the
10485   // non-anonymous children are processed to ensure that popups are never
10486   // constructed before the popupset.
10487   AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
10488   GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
10489 #ifdef DEBUG
10490   for (uint32_t i = 0; i < anonymousItems.Length(); ++i) {
10491     MOZ_ASSERT(anonymousItems[i].mContent->IsRootOfAnonymousSubtree(),
10492                "Content should know it's an anonymous subtree");
10493   }
10494 #endif
10495   AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
10496                                 itemsToConstruct);
10497 
10498   if (!aPossiblyLeafFrame->IsLeaf()) {
10499     // :before/:after content should have the same style context parent
10500     // as normal kids.
10501     // Note that we don't use this style context for looking up things like
10502     // special block styles because in some cases involving table pseudo-frames
10503     // it has nothing to do with the parent frame's desired behavior.
10504     nsStyleContext* styleContext;
10505 
10506     if (aCanHaveGeneratedContent) {
10507       aFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
10508       styleContext =
10509           nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->StyleContext();
10510       // Probe for generated content before
10511       CreateGeneratedContentItem(aState, aFrame, aContent->AsElement(),
10512                                  styleContext, CSSPseudoElementType::before,
10513                                  itemsToConstruct);
10514     }
10515 
10516     const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
10517     if (!addChildItems) {
10518       NS_WARNING("ProcessChildren max depth exceeded");
10519     }
10520 
10521     // Don't blockify 'display' in ApplyStyleFixups unless aFrame really is
10522     // a flex/grid container frame, not just has display:flex/grid.
10523     Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
10524         parentDisplayBasedStyleFixupSkipper;
10525     MOZ_ASSERT(aState.mTreeMatchContext || aContent->IsStyledByServo());
10526     if (!isFlexOrGridContainer && aState.mTreeMatchContext) {
10527       parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
10528     }
10529 
10530     InsertionPoint insertion(aFrame, nullptr);
10531     FlattenedChildIterator iter(aContent);
10532     for (nsIContent* child = iter.GetNextChild(); child;
10533          child = iter.GetNextChild()) {
10534       // Get the parent of the content and check if it is a XBL children element
10535       // (if the content is a children element then parent != aContent because
10536       // the FlattenedChildIterator will transitively iterate through
10537       // <xbl:children> for default content). Push the children element as an
10538       // ancestor here because it does not have a frame and would not otherwise
10539       // be pushed as an ancestor.
10540       insertion.mContainer = aContent;
10541       nsIContent* parent = child->GetParent();
10542       MOZ_ASSERT(parent,
10543                  "Parent must be non-null because we are iterating children.");
10544       TreeMatchContext::AutoAncestorPusher ancestorPusher(
10545           aState.mTreeMatchContext);
10546       if (parent != aContent && parent->IsElement()) {
10547         insertion.mContainer = child->GetFlattenedTreeParent();
10548         MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(child).mContainer);
10549         if (aState.HasAncestorFilter()) {
10550           ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
10551         } else {
10552           ancestorPusher.PushStyleScope(parent->AsElement());
10553         }
10554       }
10555 
10556       // Frame construction item construction should not post
10557       // restyles, so removing restyle flags here is safe.
10558       child->UnsetRestyleFlagsIfGecko();
10559       if (addChildItems) {
10560         AddFrameConstructionItems(aState, child, iter.XBLInvolved(), insertion,
10561                                   itemsToConstruct);
10562       } else {
10563         ClearLazyBits(child, child->GetNextSibling());
10564       }
10565     }
10566     itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
10567 
10568     if (aCanHaveGeneratedContent) {
10569       // Probe for generated content after
10570       CreateGeneratedContentItem(aState, aFrame, aContent->AsElement(),
10571                                  styleContext, CSSPseudoElementType::after,
10572                                  itemsToConstruct);
10573     }
10574   } else {
10575     ClearLazyBits(aContent->GetFirstChild(), nullptr);
10576   }
10577 
10578   ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
10579                               /* aParentIsWrapperAnonBox = */ false,
10580                               aFrameItems);
10581 
10582   NS_ASSERTION(!allowFirstPseudos || !aFrame->IsXULBoxFrame(),
10583                "can't be both block and box");
10584 
10585   if (haveFirstLetterStyle) {
10586     WrapFramesInFirstLetterFrame(aFrame, aFrameItems);
10587   }
10588   if (haveFirstLineStyle) {
10589     WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr, aFrameItems);
10590   }
10591 
10592   // We might end up with first-line frames that change
10593   // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
10594   // should never happen for cases whan aFrame->IsXULBoxFrame().
10595   NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsXULBoxFrame(),
10596                "Shouldn't have first-line style if we're a box");
10597   NS_ASSERTION(
10598       !aFrame->IsXULBoxFrame() ||
10599           itemsToConstruct.AnyItemsNeedBlockParent() ==
10600               (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr),
10601       "Something went awry in our block parent calculations");
10602 
10603   if (aFrame->IsXULBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
10604     // XXXbz we could do this on the FrameConstructionItemList level,
10605     // no?  And if we cared we could look through the item list
10606     // instead of groveling through the framelist here..
10607     nsStyleContext* frameStyleContext = aFrame->StyleContext();
10608     // Report a warning for non-GC frames, for chrome:
10609     if (!aFrame->IsGeneratedContentFrame() &&
10610         mPresShell->GetPresContext()->IsChrome()) {
10611       nsIContent* badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild());
10612       nsDependentAtomString parentTag(aContent->NodeInfo()->NameAtom()),
10613           kidTag(badKid->NodeInfo()->NameAtom());
10614       const char16_t* params[] = {parentTag.get(), kidTag.get()};
10615       const nsStyleDisplay* display = frameStyleContext->StyleDisplay();
10616       const char* message = (display->mDisplay == StyleDisplay::MozInlineBox)
10617                                 ? "NeededToWrapXULInlineBox"
10618                                 : "NeededToWrapXUL";
10619       nsContentUtils::ReportToConsole(
10620           nsIScriptError::warningFlag,
10621           NS_LITERAL_CSTRING("Layout: FrameConstructor"), mDocument,
10622           nsContentUtils::eXUL_PROPERTIES, message, params,
10623           ArrayLength(params));
10624     }
10625 
10626     RefPtr<nsStyleContext> blockSC =
10627         mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10628             nsCSSAnonBoxes::mozXULAnonymousBlock, frameStyleContext);
10629     nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10630     // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
10631     // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
10632     // a real block placed here wouldn't get those set on it.
10633 
10634     InitAndRestoreFrame(aState, aContent, aFrame, blockFrame, false);
10635 
10636     NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
10637     ReparentFrames(this, blockFrame, aFrameItems, false);
10638 
10639     blockFrame->SetInitialChildList(kPrincipalList, aFrameItems);
10640     NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?");
10641     aFrameItems.Clear();
10642     aFrameItems.AddChild(blockFrame);
10643 
10644     aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
10645     MOZ_ASSERT(!aFrame->IsLeaf(), "Why do we have an nsLeafBoxFrame here?");
10646     aFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
10647   }
10648 }
10649 
10650 //----------------------------------------------------------------------
10651 
10652 // Support for :first-line style
10653 
10654 // Special routine to handle placing a list of frames into a block
10655 // frame that has first-line style. The routine ensures that the first
10656 // collection of inline frames end up in a first-line frame.
10657 // NOTE: aState may have containing block information related to a
10658 // different part of the frame tree than where the first line occurs.
10659 // In particular aState may be set up for where ContentInserted or
10660 // ContentAppended is inserting content, which may be some
10661 // non-first-in-flow continuation of the block to which the first-line
10662 // belongs. So this function needs to be careful about how it uses
10663 // aState.
WrapFramesInFirstLineFrame(nsFrameConstructorState & aState,nsIContent * aBlockContent,nsContainerFrame * aBlockFrame,nsFirstLineFrame * aLineFrame,nsFrameItems & aFrameItems)10664 void nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
10665     nsFrameConstructorState& aState, nsIContent* aBlockContent,
10666     nsContainerFrame* aBlockFrame, nsFirstLineFrame* aLineFrame,
10667     nsFrameItems& aFrameItems) {
10668   // Find the part of aFrameItems that we want to put in the first-line
10669   nsFrameList::FrameLinkEnumerator link(aFrameItems);
10670   while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) {
10671     link.Next();
10672   }
10673 
10674   nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
10675 
10676   if (firstLineChildren.IsEmpty()) {
10677     // Nothing is supposed to go into the first-line; nothing to do
10678     return;
10679   }
10680 
10681   if (!aLineFrame) {
10682     // Create line frame
10683     nsStyleContext* parentStyle =
10684         nsFrame::CorrectStyleParentFrame(aBlockFrame,
10685                                          nsCSSPseudoElements::firstLine)
10686             ->StyleContext();
10687     RefPtr<nsStyleContext> firstLineStyle =
10688         GetFirstLineStyle(aBlockContent, parentStyle);
10689 
10690     aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
10691 
10692     // Initialize the line frame
10693     InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
10694 
10695     // The lineFrame will be the block's first child; the rest of the
10696     // frame list (after lastInlineFrame) will be the second and
10697     // subsequent children; insert lineFrame into aFrameItems.
10698     aFrameItems.InsertFrame(nullptr, nullptr, aLineFrame);
10699 
10700     NS_ASSERTION(aLineFrame->StyleContext() == firstLineStyle,
10701                  "Bogus style context on line frame");
10702   }
10703 
10704   // Give the inline frames to the lineFrame <b>after</b> reparenting them
10705   ReparentFrames(this, aLineFrame, firstLineChildren, true);
10706   if (aLineFrame->PrincipalChildList().IsEmpty() &&
10707       (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
10708     aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren);
10709   } else {
10710     AppendFrames(aLineFrame, kPrincipalList, firstLineChildren);
10711   }
10712 }
10713 
10714 // Special routine to handle appending a new frame to a block frame's
10715 // child list. Takes care of placing the new frame into the right
10716 // place when first-line style is present.
AppendFirstLineFrames(nsFrameConstructorState & aState,nsIContent * aBlockContent,nsContainerFrame * aBlockFrame,nsFrameItems & aFrameItems)10717 void nsCSSFrameConstructor::AppendFirstLineFrames(
10718     nsFrameConstructorState& aState, nsIContent* aBlockContent,
10719     nsContainerFrame* aBlockFrame, nsFrameItems& aFrameItems) {
10720   // It's possible that aBlockFrame needs to have a first-line frame
10721   // created because it doesn't currently have any children.
10722   const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
10723   if (blockKids.IsEmpty()) {
10724     WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, nullptr,
10725                                aFrameItems);
10726     return;
10727   }
10728 
10729   // Examine the last block child - if it's a first-line frame then
10730   // appended frames need special treatment.
10731   nsIFrame* lastBlockKid = blockKids.LastChild();
10732   if (!lastBlockKid->IsLineFrame()) {
10733     // No first-line frame at the end of the list, therefore there is
10734     // an intervening block between any first-line frame the frames
10735     // we are appending. Therefore, we don't need any special
10736     // treatment of the appended frames.
10737     return;
10738   }
10739 
10740   nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
10741   WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, lineFrame,
10742                              aFrameItems);
10743 }
10744 
CheckForFirstLineInsertion(nsIFrame * aParentFrame,nsFrameItems & aFrameItems)10745 void nsCSSFrameConstructor::CheckForFirstLineInsertion(
10746     nsIFrame* aParentFrame, nsFrameItems& aFrameItems) {
10747   MOZ_ASSERT(aParentFrame->StyleContext()->HasPseudoElementData(),
10748              "Why were we called?");
10749 
10750   if (aFrameItems.IsEmpty()) {
10751     // Happens often enough, with the caption stuff.  No need to do the ancestor
10752     // walk here.
10753     return;
10754   }
10755 
10756   class RestyleManager* restyleManager = RestyleManager();
10757   if (!restyleManager->IsServo()) {
10758     // Gecko's style resolution is frame-based, so already has the right styles
10759     // even in the ::first-line case.
10760     return;
10761   }
10762 
10763   // Check whether there's a ::first-line on the path up from aParentFrame.
10764   // Note that we can't stop until we've run out of ancestors with
10765   // pseudo-element data, because the first-letter might be somewhere way up the
10766   // tree; in particular it might be past our containing block.
10767   nsIFrame* ancestor = aParentFrame;
10768   while (ancestor) {
10769     if (!ancestor->StyleContext()->HasPseudoElementData()) {
10770       // We know we won't find a ::first-line now.
10771       return;
10772     }
10773 
10774     if (!ancestor->IsLineFrame()) {
10775       ancestor = ancestor->GetParent();
10776       continue;
10777     }
10778 
10779     if (!ancestor->StyleContext()->IsPseudoElement()) {
10780       // This is a continuation lineframe, not the first line; no need to do
10781       // anything to the styles.
10782       return;
10783     }
10784 
10785     // Fix up the styles of aFrameItems for ::first-line.
10786     for (nsIFrame* f : aFrameItems) {
10787       restyleManager->ReparentStyleContext(f);
10788     }
10789     return;
10790   }
10791 }
10792 
10793 //----------------------------------------------------------------------
10794 
10795 // First-letter support
10796 
10797 // Determine how many characters in the text fragment apply to the
10798 // first letter
FirstLetterCount(const nsTextFragment * aFragment)10799 static int32_t FirstLetterCount(const nsTextFragment* aFragment) {
10800   int32_t count = 0;
10801   int32_t firstLetterLength = 0;
10802 
10803   int32_t i, n = aFragment->GetLength();
10804   for (i = 0; i < n; i++) {
10805     char16_t ch = aFragment->CharAt(i);
10806     // FIXME: take content language into account when deciding whitespace.
10807     if (dom::IsSpaceCharacter(ch)) {
10808       if (firstLetterLength) {
10809         break;
10810       }
10811       count++;
10812       continue;
10813     }
10814     // XXX I18n
10815     if ((ch == '\'') || (ch == '\"')) {
10816       if (firstLetterLength) {
10817         break;
10818       }
10819       // keep looping
10820       firstLetterLength = 1;
10821     } else {
10822       count++;
10823       break;
10824     }
10825   }
10826 
10827   return count;
10828 }
10829 
NeedFirstLetterContinuation(nsIContent * aContent)10830 static bool NeedFirstLetterContinuation(nsIContent* aContent) {
10831   NS_PRECONDITION(aContent, "null ptr");
10832 
10833   bool result = false;
10834   if (aContent) {
10835     const nsTextFragment* frag = aContent->GetText();
10836     if (frag) {
10837       int32_t flc = FirstLetterCount(frag);
10838       int32_t tl = frag->GetLength();
10839       if (flc < tl) {
10840         result = true;
10841       }
10842     }
10843   }
10844   return result;
10845 }
10846 
IsFirstLetterContent(nsIContent * aContent)10847 static bool IsFirstLetterContent(nsIContent* aContent) {
10848   return aContent->TextLength() && !aContent->TextIsOnlyWhitespace();
10849 }
10850 
10851 /**
10852  * Create a letter frame, only make it a floating frame.
10853  */
CreateFloatingLetterFrame(nsFrameConstructorState & aState,nsIContent * aTextContent,nsIFrame * aTextFrame,nsContainerFrame * aParentFrame,nsStyleContext * aParentStyleContext,nsStyleContext * aStyleContext,nsFrameItems & aResult)10854 nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
10855     nsFrameConstructorState& aState, nsIContent* aTextContent,
10856     nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
10857     nsStyleContext* aParentStyleContext, nsStyleContext* aStyleContext,
10858     nsFrameItems& aResult) {
10859   MOZ_ASSERT(aParentStyleContext);
10860 
10861   nsFirstLetterFrame* letterFrame =
10862       NS_NewFirstLetterFrame(mPresShell, aStyleContext);
10863   // We don't want to use a text content for a non-text frame (because we want
10864   // its primary frame to be a text frame).
10865   nsIContent* letterContent = aParentFrame->GetContent();
10866   nsContainerFrame* containingBlock =
10867       aState.GetGeometricParent(aStyleContext->StyleDisplay(), aParentFrame);
10868   InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
10869 
10870   // Init the text frame to refer to the letter frame. Make sure we
10871   // get a proper style context for it (the one passed in is for the
10872   // letter frame and will have the float property set on it; the text
10873   // frame shouldn't have that set).
10874   StyleSetHandle styleSet = mPresShell->StyleSet();
10875   RefPtr<nsStyleContext> textSC =
10876       styleSet->ResolveStyleForText(aTextContent, aStyleContext);
10877   aTextFrame->SetStyleContextWithoutNotification(textSC);
10878   InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
10879 
10880   // And then give the text frame to the letter frame
10881   SetInitialSingleChild(letterFrame, aTextFrame);
10882 
10883   // See if we will need to continue the text frame (does it contain
10884   // more than just the first-letter text or not?) If it does, then we
10885   // create (in advance) a continuation frame for it.
10886   nsIFrame* nextTextFrame = nullptr;
10887   if (NeedFirstLetterContinuation(aTextContent)) {
10888     // Create continuation
10889     nextTextFrame =
10890         CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame);
10891     RefPtr<nsStyleContext> newSC =
10892         styleSet->ResolveStyleForText(aTextContent, aParentStyleContext);
10893     nextTextFrame->SetStyleContext(newSC);
10894   }
10895 
10896   NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
10897   // Put the new float before any of the floats in the block we're doing
10898   // first-letter for, that is, before any floats whose parent is
10899   // containingBlock.
10900   nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
10901   while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) {
10902     link.Next();
10903   }
10904 
10905   aState.AddChild(letterFrame, aResult, letterContent, aParentFrame, false,
10906                   true, false, true, link.PrevFrame());
10907 
10908   if (nextTextFrame) {
10909     aResult.AddChild(nextTextFrame);
10910   }
10911 
10912   return letterFrame;
10913 }
10914 
10915 /**
10916  * Create a new letter frame for aTextFrame. The letter frame will be
10917  * a child of aParentFrame.
10918  */
CreateLetterFrame(nsContainerFrame * aBlockFrame,nsContainerFrame * aBlockContinuation,nsIContent * aTextContent,nsContainerFrame * aParentFrame,nsFrameItems & aResult)10919 void nsCSSFrameConstructor::CreateLetterFrame(
10920     nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
10921     nsIContent* aTextContent, nsContainerFrame* aParentFrame,
10922     nsFrameItems& aResult) {
10923   NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT),
10924                   "aTextContent isn't text");
10925   NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame), "Not a block frame?");
10926 
10927   // Get style context for the first-letter-frame.  Keep this in sync with
10928   // nsBlockFrame::UpdatePseudoElementStyles.
10929   nsIFrame* parentFrame = nsFrame::CorrectStyleParentFrame(
10930       aParentFrame, nsCSSPseudoElements::firstLetter);
10931 
10932   nsStyleContext* parentStyleContext = parentFrame->StyleContext();
10933 
10934   // Use content from containing block so that we can actually
10935   // find a matching style rule.
10936   nsIContent* blockContent = aBlockFrame->GetContent();
10937 
10938   // Create first-letter style rule
10939   RefPtr<nsStyleContext> sc =
10940       GetFirstLetterStyle(blockContent, parentStyleContext);
10941 
10942   if (sc) {
10943     if (sc->IsServo() && parentFrame->IsLineFrame()) {
10944       nsIFrame* parentIgnoringFirstLine = nsFrame::CorrectStyleParentFrame(
10945           aBlockFrame, nsCSSPseudoElements::firstLetter);
10946 
10947       sc = mPresShell->StyleSet()->AsServo()->ReparentStyleContext(
10948           sc->AsServo(), parentStyleContext->AsServo(),
10949           parentIgnoringFirstLine->StyleContext()->AsServo(),
10950           parentStyleContext->AsServo(), blockContent->AsElement());
10951     }
10952 
10953     RefPtr<nsStyleContext> textSC =
10954         mPresShell->StyleSet()->ResolveStyleForText(aTextContent, sc);
10955 
10956     // Create a new text frame (the original one will be discarded)
10957     // pass a temporary stylecontext, the correct one will be set
10958     // later.  Start off by unsetting the primary frame for
10959     // aTextContent, so it's no longer pointing to the to-be-destroyed
10960     // frame.
10961     // XXXbz it would be really nice to destroy the old frame _first_,
10962     // then create the new one, so we could avoid this hack.
10963     aTextContent->SetPrimaryFrame(nullptr);
10964     nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
10965 
10966     NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
10967                  "Containing block is confused");
10968     TreeMatchContextHolder matchContext(mDocument);
10969     nsFrameConstructorState state(
10970         mPresShell, matchContext,
10971         GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
10972         GetAbsoluteContainingBlock(aParentFrame, ABS_POS), aBlockContinuation);
10973 
10974     // Create the right type of first-letter frame
10975     const nsStyleDisplay* display = sc->StyleDisplay();
10976     nsFirstLetterFrame* letterFrame;
10977     if (display->IsFloatingStyle() &&
10978         !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
10979       // Make a floating first-letter frame
10980       letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
10981                                               aParentFrame, parentStyleContext,
10982                                               sc, aResult);
10983     } else {
10984       // Make an inflow first-letter frame
10985       letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
10986 
10987       // Initialize the first-letter-frame.  We don't want to use a text
10988       // content for a non-text frame (because we want its primary frame to
10989       // be a text frame).
10990       nsIContent* letterContent = aParentFrame->GetContent();
10991       letterFrame->Init(letterContent, aParentFrame, nullptr);
10992 
10993       InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
10994 
10995       SetInitialSingleChild(letterFrame, textFrame);
10996       aResult.Clear();
10997       aResult.AddChild(letterFrame);
10998       NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
10999                    "should have the first continuation here");
11000       aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
11001     }
11002     MOZ_ASSERT(
11003         !aBlockFrame->GetPrevContinuation(),
11004         "Setting up a first-letter frame on a non-first block continuation?");
11005     auto parent =
11006         static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
11007     parent->SetHasFirstLetterChild();
11008     aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
11009                              letterFrame);
11010     aTextContent->SetPrimaryFrame(textFrame);
11011   }
11012 }
11013 
WrapFramesInFirstLetterFrame(nsContainerFrame * aBlockFrame,nsFrameItems & aBlockFrames)11014 void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
11015     nsContainerFrame* aBlockFrame, nsFrameItems& aBlockFrames) {
11016   aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
11017 
11018   nsContainerFrame* parentFrame = nullptr;
11019   nsIFrame* textFrame = nullptr;
11020   nsIFrame* prevFrame = nullptr;
11021   nsFrameItems letterFrames;
11022   bool stopLooking = false;
11023   WrapFramesInFirstLetterFrame(
11024       aBlockFrame, aBlockFrame, aBlockFrame, aBlockFrames.FirstChild(),
11025       &parentFrame, &textFrame, &prevFrame, letterFrames, &stopLooking);
11026   if (parentFrame) {
11027     if (parentFrame == aBlockFrame) {
11028       // Take textFrame out of the block's frame list and substitute the
11029       // letter frame(s) instead.
11030       aBlockFrames.DestroyFrame(textFrame);
11031       aBlockFrames.InsertFrames(nullptr, prevFrame, letterFrames);
11032     } else {
11033       // Take the old textFrame out of the inline parent's child list
11034       RemoveFrame(kPrincipalList, textFrame);
11035 
11036       // Insert in the letter frame(s)
11037       parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
11038     }
11039   }
11040 }
11041 
WrapFramesInFirstLetterFrame(nsContainerFrame * aBlockFrame,nsContainerFrame * aBlockContinuation,nsContainerFrame * aParentFrame,nsIFrame * aParentFrameList,nsContainerFrame ** aModifiedParent,nsIFrame ** aTextFrame,nsIFrame ** aPrevFrame,nsFrameItems & aLetterFrames,bool * aStopLooking)11042 void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
11043     nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
11044     nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
11045     nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
11046     nsIFrame** aPrevFrame, nsFrameItems& aLetterFrames, bool* aStopLooking) {
11047   nsIFrame* prevFrame = nullptr;
11048   nsIFrame* frame = aParentFrameList;
11049 
11050   while (frame) {
11051     nsIFrame* nextFrame = frame->GetNextSibling();
11052 
11053     LayoutFrameType frameType = frame->Type();
11054     if (LayoutFrameType::Text == frameType) {
11055       // Wrap up first-letter content in a letter frame
11056       nsIContent* textContent = frame->GetContent();
11057       if (IsFirstLetterContent(textContent)) {
11058         // Create letter frame to wrap up the text
11059         CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
11060                           aParentFrame, aLetterFrames);
11061 
11062         // Provide adjustment information for parent
11063         *aModifiedParent = aParentFrame;
11064         *aTextFrame = frame;
11065         *aPrevFrame = prevFrame;
11066         *aStopLooking = true;
11067         return;
11068       }
11069     } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
11070       nsIFrame* kids = frame->PrincipalChildList().FirstChild();
11071       WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
11072                                    static_cast<nsContainerFrame*>(frame), kids,
11073                                    aModifiedParent, aTextFrame, aPrevFrame,
11074                                    aLetterFrames, aStopLooking);
11075       if (*aStopLooking) {
11076         return;
11077       }
11078     } else {
11079       // This will stop us looking to create more letter frames. For
11080       // example, maybe the frame-type is "letterFrame" or
11081       // "placeholderFrame". This keeps us from creating extra letter
11082       // frames, and also prevents us from creating letter frames when
11083       // the first real content child of a block is not text (e.g. an
11084       // image, hr, etc.)
11085       *aStopLooking = true;
11086       break;
11087     }
11088 
11089     prevFrame = frame;
11090     frame = nextFrame;
11091   }
11092 }
11093 
FindFirstLetterFrame(nsIFrame * aFrame,nsIFrame::ChildListID aListID)11094 static nsIFrame* FindFirstLetterFrame(nsIFrame* aFrame,
11095                                       nsIFrame::ChildListID aListID) {
11096   nsFrameList list = aFrame->GetChildList(aListID);
11097   for (nsFrameList::Enumerator e(list); !e.AtEnd(); e.Next()) {
11098     if (e.get()->IsLetterFrame()) {
11099       return e.get();
11100     }
11101   }
11102   return nullptr;
11103 }
11104 
RemoveFloatingFirstLetterFrames(nsIPresShell * aPresShell,nsIFrame * aBlockFrame)11105 void nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
11106     nsIPresShell* aPresShell, nsIFrame* aBlockFrame) {
11107   // Look for the first letter frame on the kFloatList, then kPushedFloatsList.
11108   nsIFrame* floatFrame =
11109       ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kFloatList);
11110   if (!floatFrame) {
11111     floatFrame =
11112         ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList);
11113     if (!floatFrame) {
11114       return;
11115     }
11116   }
11117 
11118   // Take the text frame away from the letter frame (so it isn't
11119   // destroyed when we destroy the letter frame).
11120   nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
11121   if (!textFrame) {
11122     return;
11123   }
11124 
11125   // Discover the placeholder frame for the letter frame
11126   nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
11127   if (!placeholderFrame) {
11128     // Somethings really wrong
11129     return;
11130   }
11131   nsContainerFrame* parentFrame = placeholderFrame->GetParent();
11132   if (!parentFrame) {
11133     // Somethings really wrong
11134     return;
11135   }
11136   static_cast<nsContainerFrame*>(parentFrame->FirstContinuation())
11137       ->ClearHasFirstLetterChild();
11138 
11139   // Create a new text frame with the right style context that maps
11140   // all of the content that was previously part of the letter frame
11141   // (and probably continued elsewhere).
11142   nsStyleContext* parentSC = parentFrame->StyleContext();
11143   nsIContent* textContent = textFrame->GetContent();
11144   if (!textContent) {
11145     return;
11146   }
11147   RefPtr<nsStyleContext> newSC =
11148       aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
11149   nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
11150   newTextFrame->Init(textContent, parentFrame, nullptr);
11151 
11152   // Destroy the old text frame's continuations (the old text frame
11153   // will be destroyed when its letter frame is destroyed).
11154   nsIFrame* frameToDelete = textFrame->LastContinuation();
11155   while (frameToDelete != textFrame) {
11156     nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
11157     RemoveFrame(kPrincipalList, frameToDelete);
11158     frameToDelete = nextFrameToDelete;
11159   }
11160 
11161   nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
11162 
11163   // Now that everything is set...
11164 #ifdef NOISY_FIRST_LETTER
11165   printf(
11166       "RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p "
11167       "newTextFrame=%p\n",
11168       textContent.get(), textFrame, newTextFrame);
11169 #endif
11170 
11171   // Remove placeholder frame and the float
11172   RemoveFrame(kPrincipalList, placeholderFrame);
11173 
11174   // Now that the old frames are gone, we can start pointing to our
11175   // new primary frame.
11176   textContent->SetPrimaryFrame(newTextFrame);
11177 
11178   // Wallpaper bug 822910.
11179   bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
11180   if (offsetsNeedFixing) {
11181     prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
11182   }
11183 
11184   // Insert text frame in its place
11185   nsFrameList textList(newTextFrame, newTextFrame);
11186   InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
11187 
11188   if (offsetsNeedFixing) {
11189     prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
11190   }
11191 }
11192 
RemoveFirstLetterFrames(nsIPresShell * aPresShell,nsContainerFrame * aFrame,nsContainerFrame * aBlockFrame,bool * aStopLooking)11193 void nsCSSFrameConstructor::RemoveFirstLetterFrames(
11194     nsIPresShell* aPresShell, nsContainerFrame* aFrame,
11195     nsContainerFrame* aBlockFrame, bool* aStopLooking) {
11196   nsIFrame* prevSibling = nullptr;
11197   nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
11198 
11199   while (kid) {
11200     if (kid->IsLetterFrame()) {
11201       // Bingo. Found it. First steal away the text frame.
11202       static_cast<nsContainerFrame*>(aFrame->FirstContinuation())
11203           ->ClearHasFirstLetterChild();
11204       nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
11205       if (!textFrame) {
11206         break;
11207       }
11208 
11209       // Create a new textframe
11210       nsStyleContext* parentSC = aFrame->StyleContext();
11211       if (!parentSC) {
11212         break;
11213       }
11214       nsIContent* textContent = textFrame->GetContent();
11215       if (!textContent) {
11216         break;
11217       }
11218       RefPtr<nsStyleContext> newSC =
11219           aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
11220       textFrame = NS_NewTextFrame(aPresShell, newSC);
11221       textFrame->Init(textContent, aFrame, nullptr);
11222 
11223       // Next rip out the kid and replace it with the text frame
11224       RemoveFrame(kPrincipalList, kid);
11225 
11226       // Now that the old frames are gone, we can start pointing to our
11227       // new primary frame.
11228       textContent->SetPrimaryFrame(textFrame);
11229 
11230       // Wallpaper bug 822910.
11231       bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
11232       if (offsetsNeedFixing) {
11233         prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
11234       }
11235 
11236       // Insert text frame in its place
11237       nsFrameList textList(textFrame, textFrame);
11238       InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
11239 
11240       if (offsetsNeedFixing) {
11241         prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
11242       }
11243 
11244       *aStopLooking = true;
11245       NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
11246                    "should have the first continuation here");
11247       aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
11248       break;
11249     } else if (IsInlineFrame(kid)) {
11250       nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
11251       if (kidAsContainerFrame) {
11252         // Look inside child inline frame for the letter frame.
11253         RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame, aBlockFrame,
11254                                 aStopLooking);
11255         if (*aStopLooking) {
11256           break;
11257         }
11258       }
11259     }
11260     prevSibling = kid;
11261     kid = kid->GetNextSibling();
11262   }
11263 }
11264 
RemoveLetterFrames(nsIPresShell * aPresShell,nsContainerFrame * aBlockFrame)11265 void nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
11266                                                nsContainerFrame* aBlockFrame) {
11267   aBlockFrame =
11268       static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
11269   aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
11270   nsContainerFrame* continuation = aBlockFrame;
11271 
11272   bool stopLooking = false;
11273   do {
11274     RemoveFloatingFirstLetterFrames(aPresShell, continuation);
11275     RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
11276                             &stopLooking);
11277     if (stopLooking) {
11278       break;
11279     }
11280     continuation =
11281         static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
11282   } while (continuation);
11283 }
11284 
11285 // Fixup the letter frame situation for the given block
RecoverLetterFrames(nsContainerFrame * aBlockFrame)11286 void nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame) {
11287   aBlockFrame =
11288       static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
11289   nsContainerFrame* continuation = aBlockFrame;
11290 
11291   nsContainerFrame* parentFrame = nullptr;
11292   nsIFrame* textFrame = nullptr;
11293   nsIFrame* prevFrame = nullptr;
11294   nsFrameItems letterFrames;
11295   bool stopLooking = false;
11296   do {
11297     // XXX shouldn't this bit be set already (bug 408493), assert instead?
11298     continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
11299     WrapFramesInFirstLetterFrame(
11300         aBlockFrame, continuation, continuation,
11301         continuation->PrincipalChildList().FirstChild(), &parentFrame,
11302         &textFrame, &prevFrame, letterFrames, &stopLooking);
11303     if (stopLooking) {
11304       break;
11305     }
11306     continuation =
11307         static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
11308   } while (continuation);
11309 
11310   if (parentFrame) {
11311     // Take the old textFrame out of the parent's child list
11312     RemoveFrame(kPrincipalList, textFrame);
11313 
11314     // Insert in the letter frame(s)
11315     parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
11316   }
11317 }
11318 
11319 //----------------------------------------------------------------------
11320 
11321 // listbox Widget Routines
11322 
CreateListBoxContent(nsContainerFrame * aParentFrame,nsIFrame * aPrevFrame,nsIContent * aChild,nsIFrame ** aNewFrame,bool aIsAppend)11323 void nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
11324                                                  nsIFrame* aPrevFrame,
11325                                                  nsIContent* aChild,
11326                                                  nsIFrame** aNewFrame,
11327                                                  bool aIsAppend) {
11328 #ifdef MOZ_XUL
11329   // Construct a new frame
11330   if (nullptr != aParentFrame) {
11331     nsFrameItems frameItems;
11332     TreeMatchContextHolder matchContext(mDocument);
11333     nsFrameConstructorState state(
11334         mPresShell, matchContext,
11335         GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
11336         GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
11337         GetFloatContainingBlock(aParentFrame), do_AddRef(mTempFrameTreeState));
11338 
11339     // If we ever initialize the ancestor filter on |state|, make sure
11340     // to push the right parent!
11341 
11342     RefPtr<nsStyleContext> styleContext;
11343     styleContext = ResolveStyleContext(aParentFrame, aChild, &state);
11344 
11345     // Pre-check for display "none" - only if we find that, do we create
11346     // any frame at all
11347     const nsStyleDisplay* display = styleContext->StyleDisplay();
11348 
11349     if (StyleDisplay::None == display->mDisplay) {
11350       *aNewFrame = nullptr;
11351       return;
11352     }
11353 
11354     AutoFrameConstructionItemList items(this);
11355     AddFrameConstructionItemsInternal(
11356         state, aChild, aParentFrame, aChild->NodeInfo()->NameAtom(),
11357         aChild->GetNameSpaceID(), true, styleContext, ITEM_ALLOW_XBL_BASE,
11358         nullptr, items);
11359     ConstructFramesFromItemList(state, items, aParentFrame,
11360                                 /* aParentIsWrapperAnonBox = */ false,
11361                                 frameItems);
11362 
11363     nsIFrame* newFrame = frameItems.FirstChild();
11364     *aNewFrame = newFrame;
11365 
11366     if (newFrame) {
11367       // Notify the parent frame
11368       if (aIsAppend)
11369         ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
11370       else
11371         ((nsListBoxBodyFrame*)aParentFrame)
11372             ->ListBoxInsertFrames(aPrevFrame, frameItems);
11373     }
11374 
11375 #ifdef ACCESSIBILITY
11376     if (newFrame) {
11377       nsAccessibilityService* accService = nsIPresShell::AccService();
11378       if (accService) {
11379         accService->ContentRangeInserted(mPresShell, aChild->GetParent(),
11380                                          aChild, aChild->GetNextSibling());
11381       }
11382     }
11383 #endif
11384   }
11385 #endif
11386 }
11387 
11388 //----------------------------------------
11389 
ConstructBlock(nsFrameConstructorState & aState,nsIContent * aContent,nsContainerFrame * aParentFrame,nsContainerFrame * aContentParentFrame,nsStyleContext * aStyleContext,nsContainerFrame ** aNewFrame,nsFrameItems & aFrameItems,nsIFrame * aPositionedFrameForAbsPosContainer,PendingBinding * aPendingBinding)11390 void nsCSSFrameConstructor::ConstructBlock(
11391     nsFrameConstructorState& aState, nsIContent* aContent,
11392     nsContainerFrame* aParentFrame, nsContainerFrame* aContentParentFrame,
11393     nsStyleContext* aStyleContext, nsContainerFrame** aNewFrame,
11394     nsFrameItems& aFrameItems, nsIFrame* aPositionedFrameForAbsPosContainer,
11395     PendingBinding* aPendingBinding) {
11396   // Create column wrapper if necessary
11397   nsContainerFrame* blockFrame = *aNewFrame;
11398   NS_ASSERTION((blockFrame->IsBlockFrame() || blockFrame->IsDetailsFrame()),
11399                "not a block frame nor a details frame?");
11400   nsContainerFrame* parent = aParentFrame;
11401   RefPtr<nsStyleContext> blockStyle = aStyleContext;
11402   const nsStyleColumn* columns = aStyleContext->StyleColumn();
11403 
11404   if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
11405       columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
11406     nsContainerFrame* columnSetFrame = NS_NewColumnSetFrame(
11407         mPresShell, aStyleContext, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
11408 
11409     InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
11410     blockStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
11411         nsCSSAnonBoxes::columnContent, aStyleContext);
11412     parent = columnSetFrame;
11413     *aNewFrame = columnSetFrame;
11414     if (aPositionedFrameForAbsPosContainer == blockFrame) {
11415       aPositionedFrameForAbsPosContainer = columnSetFrame;
11416     }
11417 
11418     SetInitialSingleChild(columnSetFrame, blockFrame);
11419   }
11420 
11421   blockFrame->SetStyleContextWithoutNotification(blockStyle);
11422   InitAndRestoreFrame(aState, aContent, parent, blockFrame);
11423 
11424   aState.AddChild(*aNewFrame, aFrameItems, aContent,
11425                   aContentParentFrame ? aContentParentFrame : aParentFrame);
11426   if (!mRootElementFrame) {
11427     // The frame we're constructing will be the root element frame.
11428     // Set mRootElementFrame before processing children.
11429     mRootElementFrame = *aNewFrame;
11430   }
11431 
11432   // We should make the outer frame be the absolute containing block,
11433   // if one is required. We have to do this because absolute
11434   // positioning must be computed with respect to the CSS dimensions
11435   // of the element, which are the dimensions of the outer block. But
11436   // we can't really do that because only blocks can have absolute
11437   // children. So use the block and try to compensate with hacks
11438   // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
11439   nsFrameConstructorSaveState absoluteSaveState;
11440   (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11441   if (aPositionedFrameForAbsPosContainer) {
11442     //    NS_ASSERTION(aRelPos, "should have made area frame for this");
11443     aState.PushAbsoluteContainingBlock(
11444         *aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
11445   }
11446 
11447   // Process the child content
11448   nsFrameItems childItems;
11449   ProcessChildren(aState, aContent, aStyleContext, blockFrame, true, childItems,
11450                   true, aPendingBinding);
11451 
11452   // Set the frame's initial child list
11453   blockFrame->SetInitialChildList(kPrincipalList, childItems);
11454 }
11455 
ConstructInline(nsFrameConstructorState & aState,FrameConstructionItem & aItem,nsContainerFrame * aParentFrame,const nsStyleDisplay * aDisplay,nsFrameItems & aFrameItems)11456 nsIFrame* nsCSSFrameConstructor::ConstructInline(
11457     nsFrameConstructorState& aState, FrameConstructionItem& aItem,
11458     nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
11459     nsFrameItems& aFrameItems) {
11460   // If an inline frame has non-inline kids, then we chop up the child list
11461   // into runs of blocks and runs of inlines, create anonymous block frames to
11462   // contain the runs of blocks, inline frames with our style context for the
11463   // runs of inlines, and put all these frames, in order, into aFrameItems.  We
11464   // return the the first one.  The whole setup is called an {ib}
11465   // split; in what follows "frames in the split" refers to the anonymous blocks
11466   // and inlines that contain our children.
11467   //
11468   // {ib} splits maintain the following invariants:
11469   // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
11470   //    set.
11471   // 2) Each frame in the split has the nsIFrame::IBSplitSibling
11472   //    property pointing to the next frame in the split, except for the last
11473   //    one, which does not have it set.
11474   // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
11475   //    property pointing to the previous frame in the split, except for the
11476   //    first one, which does not have it set.
11477   // 4) The first and last frame in the split are always inlines.
11478   //
11479   // An invariant that is NOT maintained is that the wrappers are actually
11480   // linked via GetNextSibling linkage.  A simple example is an inline
11481   // containing an inline that contains a block.  The three parts of the inner
11482   // inline end up with three different parents.
11483   //
11484   // For example, this HTML:
11485   // <span>
11486   //   <div>a</div>
11487   //   <span>
11488   //     b
11489   //     <div>c</div>
11490   //   </span>
11491   //   d
11492   //   <div>e</div>
11493   //   f
11494   //  </span>
11495   // Gives the following frame tree:
11496   //
11497   // Inline (outer span)
11498   // Block (anonymous, outer span)
11499   //   Block (div)
11500   //     Text("a")
11501   // Inline (outer span)
11502   //   Inline (inner span)
11503   //     Text("b")
11504   // Block (anonymous, outer span)
11505   //   Block (anonymous, inner span)
11506   //     Block (div)
11507   //       Text("c")
11508   // Inline (outer span)
11509   //   Inline (inner span)
11510   //   Text("d")
11511   // Block (anonymous, outer span)
11512   //   Block (div)
11513   //     Text("e")
11514   // Inline (outer span)
11515   //   Text("f")
11516 
11517   nsIContent* const content = aItem.mContent;
11518   nsStyleContext* const styleContext = aItem.mStyleContext;
11519 
11520   bool positioned = StyleDisplay::Inline == aDisplay->mDisplay &&
11521                     aDisplay->IsRelativelyPositionedStyle() &&
11522                     !nsSVGUtils::IsInSVGTextSubtree(aParentFrame);
11523 
11524   nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext);
11525 
11526   // Initialize the frame
11527   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
11528 
11529   // Inline frames can always have generated content
11530   newFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
11531 
11532   nsFrameConstructorSaveState
11533       absoluteSaveState;  // definition cannot be inside next block
11534                           // because the object's destructor is significant
11535                           // this is part of the fix for bug 42372
11536 
11537   newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11538   if (positioned) {
11539     // Relatively positioned frames becomes a container for child
11540     // frames that are positioned
11541     aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
11542   }
11543 
11544   // Process the child content
11545   nsFrameItems childItems;
11546   ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
11547                               /* aParentIsWrapperAnonBox = */ false,
11548                               childItems);
11549 
11550   nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
11551   if (!aItem.mIsAllInline) {
11552     FindFirstBlock(firstBlockEnumerator);
11553   }
11554 
11555   if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) {
11556     // This part is easy.  We either already know we have no non-inline kids,
11557     // or haven't found any when constructing actual frames (the latter can
11558     // happen only if out-of-flows that we thought had no containing block
11559     // acquired one when ancestor inline frames and {ib} splits got
11560     // constructed).  Just put all the kids into the single inline frame and
11561     // bail.
11562     newFrame->SetInitialChildList(kPrincipalList, childItems);
11563     aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
11564     return newFrame;
11565   }
11566 
11567   // This inline frame contains several types of children. Therefore this frame
11568   // has to be chopped into several pieces, as described above.
11569 
11570   // Grab the first inline's kids
11571   nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
11572   newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
11573 
11574   aFrameItems.AddChild(newFrame);
11575 
11576   newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
11577   CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
11578 
11579   return newFrame;
11580 }
11581 
CreateIBSiblings(nsFrameConstructorState & aState,nsContainerFrame * aInitialInline,bool aIsPositioned,nsFrameItems & aChildItems,nsFrameItems & aSiblings)11582 void nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
11583                                              nsContainerFrame* aInitialInline,
11584                                              bool aIsPositioned,
11585                                              nsFrameItems& aChildItems,
11586                                              nsFrameItems& aSiblings) {
11587   nsIContent* content = aInitialInline->GetContent();
11588   nsStyleContext* styleContext = aInitialInline->StyleContext();
11589   nsContainerFrame* parentFrame = aInitialInline->GetParent();
11590 
11591   // Resolve the right style context for our anonymous blocks.
11592   // The distinction in styles is needed because of CSS 2.1, section
11593   // 9.2.1.1, which says:
11594   //   When such an inline box is affected by relative positioning, any
11595   //   resulting translation also affects the block-level box contained
11596   //   in the inline box.
11597   RefPtr<nsStyleContext> blockSC =
11598       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
11599           nsCSSAnonBoxes::mozBlockInsideInlineWrapper, styleContext);
11600 
11601   nsContainerFrame* lastNewInline =
11602       static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
11603   do {
11604     // On entry to this loop aChildItems is not empty and the first frame in it
11605     // is block-level.
11606     NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items");
11607     NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(),
11608                     "Must have list starting with block");
11609 
11610     // The initial run of blocks belongs to an anonymous block that we create
11611     // right now. The anonymous block will be the parent of these block
11612     // children of the inline.
11613     nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
11614     InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
11615 
11616     // Find the first non-block child which defines the end of our block kids
11617     // and the start of our next inline's kids
11618     nsFrameList::FrameLinkEnumerator firstNonBlock =
11619         FindFirstNonBlock(aChildItems);
11620     nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock);
11621 
11622     MoveChildrenTo(aInitialInline, blockFrame, blockKids);
11623 
11624     SetFrameIsIBSplit(lastNewInline, blockFrame);
11625     aSiblings.AddChild(blockFrame);
11626 
11627     // Now grab the initial inlines in aChildItems and put them into an inline
11628     // frame.
11629     nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, styleContext);
11630     InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
11631     inlineFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
11632                               NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11633     if (aIsPositioned) {
11634       inlineFrame->MarkAsAbsoluteContainingBlock();
11635     }
11636 
11637     if (aChildItems.NotEmpty()) {
11638       nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
11639       FindFirstBlock(firstBlock);
11640       nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
11641 
11642       MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
11643     }
11644 
11645     SetFrameIsIBSplit(blockFrame, inlineFrame);
11646     aSiblings.AddChild(inlineFrame);
11647     lastNewInline = inlineFrame;
11648   } while (aChildItems.NotEmpty());
11649 
11650   SetFrameIsIBSplit(lastNewInline, nullptr);
11651 }
11652 
BuildInlineChildItems(nsFrameConstructorState & aState,FrameConstructionItem & aParentItem,bool aItemIsWithinSVGText,bool aItemAllowsTextPathChild)11653 void nsCSSFrameConstructor::BuildInlineChildItems(
11654     nsFrameConstructorState& aState, FrameConstructionItem& aParentItem,
11655     bool aItemIsWithinSVGText, bool aItemAllowsTextPathChild) {
11656   // XXXbz should we preallocate aParentItem.mChildItems to some sane
11657   // length?  Maybe even to parentContent->GetChildCount()?
11658   nsFrameConstructorState::PendingBindingAutoPusher pusher(
11659       aState, aParentItem.mPendingBinding);
11660 
11661   nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
11662   nsIContent* const parentContent = aParentItem.mContent;
11663 
11664   TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
11665   if (aState.HasAncestorFilter()) {
11666     ancestorPusher.PushAncestorAndStyleScope(parentContent->AsElement());
11667   } else {
11668     ancestorPusher.PushStyleScope(parentContent->AsElement());
11669   }
11670 
11671   if (!aItemIsWithinSVGText) {
11672     // Probe for generated content before
11673     CreateGeneratedContentItem(aState, nullptr, parentContent->AsElement(),
11674                                parentStyleContext, CSSPseudoElementType::before,
11675                                aParentItem.mChildItems);
11676   }
11677 
11678   uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
11679   if (aItemIsWithinSVGText) {
11680     flags |= ITEM_IS_WITHIN_SVG_TEXT;
11681   }
11682   if (aItemAllowsTextPathChild && aParentItem.mIsForSVGAElement) {
11683     flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
11684   }
11685 
11686   if (!aParentItem.mAnonChildren.IsEmpty()) {
11687     // Use the anon-children list instead of the content tree child list so
11688     // that we use any special style context that should be associated with
11689     // the children, and so that we won't try to construct grandchildren frame
11690     // constructor items before the frame is available for their parent.
11691     AddFCItemsForAnonymousContent(aState, nullptr, aParentItem.mAnonChildren,
11692                                   aParentItem.mChildItems, flags);
11693   } else {
11694     // Use the content tree child list:
11695     FlattenedChildIterator iter(parentContent);
11696     for (nsIContent* content = iter.GetNextChild(); content;
11697          content = iter.GetNextChild()) {
11698       // Get the parent of the content and check if it is a XBL children element
11699       // (if the content is a children element then contentParent !=
11700       // parentContent because the FlattenedChildIterator will transitively
11701       // iterate through <xbl:children> for default content). Push the children
11702       // element as an ancestor here because it does not have a frame and would
11703       // not otherwise be pushed as an ancestor.
11704       nsIContent* contentParent = content->GetParent();
11705       MOZ_ASSERT(contentParent,
11706                  "Parent must be non-null because we are iterating children.");
11707       TreeMatchContext::AutoAncestorPusher insertionPointPusher(
11708           aState.mTreeMatchContext);
11709       if (contentParent != parentContent && contentParent->IsElement()) {
11710         if (aState.HasAncestorFilter()) {
11711           insertionPointPusher.PushAncestorAndStyleScope(
11712               contentParent->AsElement());
11713         } else {
11714           insertionPointPusher.PushStyleScope(contentParent->AsElement());
11715         }
11716       }
11717 
11718       // Manually check for comments/PIs, since we don't have a frame to pass to
11719       // AddFrameConstructionItems.  We know our parent is a non-replaced
11720       // inline, so there is no need to do the NeedFrameFor check.
11721       content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
11722       if (content->IsNodeOfType(nsINode::eCOMMENT) ||
11723           content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
11724         continue;
11725       }
11726 
11727       // See comment explaining why we need to remove the "is possible
11728       // restyle root" flags in AddFrameConstructionItems.  But note
11729       // that we can remove all restyle flags, just like in
11730       // ProcessChildren and for the same reason.
11731       content->UnsetRestyleFlagsIfGecko();
11732 
11733       RefPtr<nsStyleContext> childContext =
11734           ResolveStyleContext(parentStyleContext, content, &aState);
11735 
11736       AddFrameConstructionItemsInternal(
11737           aState, content, nullptr, content->NodeInfo()->NameAtom(),
11738           content->GetNameSpaceID(), iter.XBLInvolved(), childContext, flags,
11739           nullptr, aParentItem.mChildItems);
11740     }
11741   }
11742 
11743   if (!aItemIsWithinSVGText) {
11744     // Probe for generated content after
11745     CreateGeneratedContentItem(aState, nullptr, parentContent->AsElement(),
11746                                parentStyleContext, CSSPseudoElementType::after,
11747                                aParentItem.mChildItems);
11748   }
11749 
11750   aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
11751 }
11752 
11753 // return whether it's ok to append (in the AppendFrames sense) to
11754 // aParentFrame if our nextSibling is aNextSibling.  aParentFrame must
11755 // be an ib-split inline.
IsSafeToAppendToIBSplitInline(nsIFrame * aParentFrame,nsIFrame * aNextSibling)11756 static bool IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame,
11757                                           nsIFrame* aNextSibling) {
11758   NS_PRECONDITION(IsInlineFrame(aParentFrame),
11759                   "Must have an inline parent here");
11760   do {
11761     NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),
11762                  "How is this not part of an ib-split?");
11763     if (aNextSibling || aParentFrame->GetNextContinuation() ||
11764         GetIBSplitSibling(aParentFrame)) {
11765       return false;
11766     }
11767 
11768     aNextSibling = aParentFrame->GetNextSibling();
11769     aParentFrame = aParentFrame->GetParent();
11770   } while (IsInlineFrame(aParentFrame));
11771 
11772   return true;
11773 }
11774 
WipeContainingBlock(nsFrameConstructorState & aState,nsIFrame * aContainingBlock,nsIFrame * aFrame,FrameConstructionItemList & aItems,bool aIsAppend,nsIFrame * aPrevSibling)11775 bool nsCSSFrameConstructor::WipeContainingBlock(
11776     nsFrameConstructorState& aState, nsIFrame* aContainingBlock,
11777     nsIFrame* aFrame, FrameConstructionItemList& aItems, bool aIsAppend,
11778     nsIFrame* aPrevSibling) {
11779   if (aItems.IsEmpty()) {
11780     return false;
11781   }
11782 
11783   // Before we go and append the frames, we must check for several
11784   // special situations.
11785 
11786   // Situation #1 is a XUL frame that contains frames that are required
11787   // to be wrapped in blocks.
11788   if (aFrame->IsXULBoxFrame() &&
11789       !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
11790       aItems.AnyItemsNeedBlockParent()) {
11791     RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11792     return true;
11793   }
11794 
11795   nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
11796 
11797   // Situation #2 is a flex or grid container frame into which we're inserting
11798   // new inline non-replaced children, adjacent to an existing anonymous
11799   // flex or grid item.
11800   LayoutFrameType frameType = aFrame->Type();
11801   if (frameType == LayoutFrameType::FlexContainer ||
11802       frameType == LayoutFrameType::GridContainer) {
11803     FCItemIterator iter(aItems);
11804 
11805     // Check if we're adding to-be-wrapped content right *after* an existing
11806     // anonymous flex or grid item (which would need to absorb this content).
11807     const bool isLegacyBox = IsFlexContainerForLegacyBox(aFrame);
11808     if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
11809         iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
11810       RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11811       return true;
11812     }
11813 
11814     // Check if we're adding to-be-wrapped content right *before* an existing
11815     // anonymous flex or grid item (which would need to absorb this content).
11816     if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
11817       // Jump to the last entry in the list
11818       iter.SetToEnd();
11819       iter.Prev();
11820       if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
11821         RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11822         return true;
11823       }
11824     }
11825   }
11826 
11827   // Situation #3 is an anonymous flex or grid item that's getting new children
11828   // who don't want to be wrapped.
11829   if (IsAnonymousFlexOrGridItem(aFrame)) {
11830     AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
11831 
11832     // We need to push a null float containing block to be sure that
11833     // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
11834     // inserted content. (In particular, this is necessary in order for
11835     // its "GetGeometricParent" call to return the correct result.)
11836     // We're not honoring floats on this content because it has the
11837     // _flex/grid container_ as its parent in the content tree.
11838     nsFrameConstructorSaveState floatSaveState;
11839     aState.PushFloatContainingBlock(nullptr, floatSaveState);
11840 
11841     FCItemIterator iter(aItems);
11842     // Skip over things that _do_ need an anonymous flex item, because
11843     // they're perfectly happy to go here -- they won't cause a reframe.
11844     nsIFrame* containerFrame = aFrame->GetParent();
11845     const bool isLegacyBox = IsFlexContainerForLegacyBox(containerFrame);
11846     if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
11847       // We hit something that _doesn't_ need an anonymous flex item!
11848       // Rebuild the flex container to bust it out.
11849       RecreateFramesForContent(containerFrame->GetContent(),
11850                                InsertionKind::Async);
11851       return true;
11852     }
11853 
11854     // If we get here, then everything in |aItems| needs to be wrapped in
11855     // an anonymous flex or grid item.  That's where it's already going - good!
11856   }
11857 
11858   // Situation #4 is a ruby-related frame that's getting new children.
11859   // The situation for ruby is complex, especially when interacting with
11860   // spaces. It containes these two special cases apart from tables:
11861   // 1) There are effectively three types of white spaces in ruby frames
11862   //    we handle differently: leading/tailing/inter-level space,
11863   //    inter-base/inter-annotation space, and inter-segment space.
11864   //    These three types of spaces can be converted to each other when
11865   //    their sibling changes.
11866   // 2) The first effective child of a ruby frame must always be a ruby
11867   //    base container. It should be created or destroyed accordingly.
11868   if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
11869       RubyUtils::IsRubyContainerBox(frameType)) {
11870     // We want to optimize it better, and avoid reframing as much as
11871     // possible. But given the cases above, and the fact that a ruby
11872     // usually won't be very large, it should be fine to reframe it.
11873     RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11874     return true;
11875   }
11876 
11877   // Situation #5 is a case when table pseudo-frames don't work out right
11878   ParentType parentType = GetParentType(aFrame);
11879   // If all the kids want a parent of the type that aFrame is, then we're all
11880   // set to go.  Indeed, there won't be any table pseudo-frames created between
11881   // aFrame and the kids, so those won't need to be merged with any table
11882   // pseudo-frames that might already be kids of aFrame.  If aFrame itself is a
11883   // table pseudo-frame, then all the kids in this list would have wanted a
11884   // frame of that type wrapping them anyway, so putting them inside it is ok.
11885   if (!aItems.AllWantParentType(parentType)) {
11886     // Don't give up yet.  If parentType is not eTypeBlock and the parent is
11887     // not a generated content frame, then try filtering whitespace out of the
11888     // list.
11889     if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
11890       // For leading whitespace followed by a kid that wants our parent type,
11891       // there are four cases:
11892       // 1) We have a previous sibling which is not a table pseudo.  That means
11893       //    that previous sibling wanted a (non-block) parent of the type we're
11894       //    looking at.  Then the whitespace comes between two table-internal
11895       //    elements, so should be collapsed out.
11896       // 2) We have a previous sibling which is a table pseudo.  It might have
11897       //    kids who want this whitespace, so we need to reframe.
11898       // 3) We have no previous sibling and our parent frame is not a table
11899       //    pseudo.  That means that we'll be at the beginning of our actual
11900       //    non-block-type parent, and the whitespace is OK to collapse out.
11901       //    If something is ever inserted before us, it'll find our own parent
11902       //    as its parent and if it's something that would care about the
11903       //    whitespace it'll want a block parent, so it'll trigger a reframe at
11904       //    that point.
11905       // 4) We have no previous sibling and our parent frame is a table pseudo.
11906       //    Need to reframe.
11907       // All that is predicated on finding the correct previous sibling.  We
11908       // might have to walk backwards along continuations from aFrame to do so.
11909       //
11910       // It's always OK to drop whitespace between any two items that want a
11911       // parent of type parentType.
11912       //
11913       // For trailing whitespace preceded by a kid that wants our parent type,
11914       // there are four cases:
11915       // 1) We have a next sibling which is not a table pseudo.  That means
11916       //    that next sibling wanted a (non-block) parent of the type we're
11917       //    looking at.  Then the whitespace comes between two table-internal
11918       //    elements, so should be collapsed out.
11919       // 2) We have a next sibling which is a table pseudo.  It might have
11920       //    kids who want this whitespace, so we need to reframe.
11921       // 3) We have no next sibling and our parent frame is not a table
11922       //    pseudo.  That means that we'll be at the end of our actual
11923       //    non-block-type parent, and the whitespace is OK to collapse out.
11924       //    If something is ever inserted after us, it'll find our own parent
11925       //    as its parent and if it's something that would care about the
11926       //    whitespace it'll want a block parent, so it'll trigger a reframe at
11927       //    that point.
11928       // 4) We have no next sibling and our parent frame is a table pseudo.
11929       //    Need to reframe.
11930       // All that is predicated on finding the correct next sibling.  We might
11931       // have to walk forward along continuations from aFrame to do so.  That
11932       // said, in the case when nextSibling is null at this point and aIsAppend
11933       // is true, we know we're in case 3.  Furthermore, in that case we don't
11934       // even have to worry about the table pseudo situation; we know our
11935       // parent is not a table pseudo there.
11936       FCItemIterator iter(aItems);
11937       FCItemIterator start(iter);
11938       do {
11939         if (iter.SkipItemsWantingParentType(parentType)) {
11940           break;
11941         }
11942 
11943         // iter points to an item that wants a different parent.  If it's not
11944         // whitespace, we're done; no more point scanning the list.
11945         if (!iter.item().IsWhitespace(aState)) {
11946           break;
11947         }
11948 
11949         if (iter == start) {
11950           // Leading whitespace.  How to handle this depends on our
11951           // previous sibling and aFrame.  See the long comment above.
11952           nsIFrame* prevSibling = aPrevSibling;
11953           if (!prevSibling) {
11954             // Try to find one after all
11955             nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
11956             while (parentPrevCont) {
11957               prevSibling =
11958                   parentPrevCont->GetChildList(kPrincipalList).LastChild();
11959               if (prevSibling) {
11960                 break;
11961               }
11962               parentPrevCont = parentPrevCont->GetPrevContinuation();
11963             }
11964           };
11965           if (prevSibling) {
11966             if (IsTablePseudo(prevSibling)) {
11967               // need to reframe
11968               break;
11969             }
11970           } else if (IsTablePseudo(aFrame)) {
11971             // need to reframe
11972             break;
11973           }
11974         }
11975 
11976         FCItemIterator spaceEndIter(iter);
11977         // Advance spaceEndIter past any whitespace
11978         bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
11979 
11980         bool okToDrop;
11981         if (trailingSpaces) {
11982           // Trailing whitespace.  How to handle this depeds on aIsAppend, our
11983           // next sibling and aFrame.  See the long comment above.
11984           okToDrop = aIsAppend && !nextSibling;
11985           if (!okToDrop) {
11986             if (!nextSibling) {
11987               // Try to find one after all
11988               nsIFrame* parentNextCont = aFrame->GetNextContinuation();
11989               while (parentNextCont) {
11990                 nextSibling = parentNextCont->PrincipalChildList().FirstChild();
11991                 if (nextSibling) {
11992                   break;
11993                 }
11994                 parentNextCont = parentNextCont->GetNextContinuation();
11995               }
11996             }
11997 
11998             okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
11999                        (!nextSibling && !IsTablePseudo(aFrame));
12000           }
12001 #ifdef DEBUG
12002           else {
12003             NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
12004           }
12005 #endif
12006         } else {
12007           okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
12008         }
12009 
12010         if (okToDrop) {
12011           iter.DeleteItemsTo(this, spaceEndIter);
12012         } else {
12013           // We're done: we don't want to drop the whitespace, and it has the
12014           // wrong parent type.
12015           break;
12016         }
12017 
12018         // Now loop, since |iter| points to item right after the whitespace we
12019         // removed.
12020       } while (!iter.IsDone());
12021     }
12022 
12023     // We might be able to figure out some sort of optimizations here, but they
12024     // would have to depend on having a correct aPrevSibling and a correct next
12025     // sibling.  For example, we can probably avoid reframing if none of
12026     // aFrame, aPrevSibling, and next sibling are table pseudo-frames.  But it
12027     // doesn't seem worth it to worry about that for now, especially since we
12028     // in fact do not have a reliable aPrevSibling, nor any next sibling, in
12029     // this method.
12030 
12031     // aItems might have changed, so recheck the parent type thing.  In fact,
12032     // it might be empty, so recheck that too.
12033     if (aItems.IsEmpty()) {
12034       return false;
12035     }
12036 
12037     if (!aItems.AllWantParentType(parentType)) {
12038       // Reframing aFrame->GetContent() is good enough, since the content of
12039       // table pseudo-frames is the ancestor content.
12040       RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
12041       return true;
12042     }
12043   }
12044 
12045   // Now we have several cases involving {ib} splits.  Put them all in a
12046   // do/while with breaks to take us to the "go and reconstruct" code.
12047   do {
12048     if (IsInlineFrame(aFrame)) {
12049       if (aItems.AreAllItemsInline()) {
12050         // We can just put the kids in.
12051         return false;
12052       }
12053 
12054       if (!IsFramePartOfIBSplit(aFrame)) {
12055         // Need to go ahead and reconstruct.
12056         break;
12057       }
12058 
12059       // Now we're adding kids including some blocks to an inline part of an
12060       // {ib} split.  If we plan to call AppendFrames, and don't have a next
12061       // sibling for the new frames, and our parent is the last continuation of
12062       // the last part of the {ib} split, and the same is true of all our
12063       // ancestor inlines (they have no following continuations and they're the
12064       // last part of their {ib} splits and we'd be adding to the end for all
12065       // of them), then AppendFrames will handle things for us.  Bail out in
12066       // that case.
12067       if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
12068         return false;
12069       }
12070 
12071       // Need to reconstruct.
12072       break;
12073     }
12074 
12075     // Now we know we have a block parent.  If it's not part of an
12076     // ib-split, we're all set.
12077     if (!IsFramePartOfIBSplit(aFrame)) {
12078       return false;
12079     }
12080 
12081     // We're adding some kids to a block part of an {ib} split.  If all the
12082     // kids are blocks, we don't need to reconstruct.
12083     if (aItems.AreAllItemsBlock()) {
12084       return false;
12085     }
12086 
12087     // We might have some inline kids for this block.  Just fall out of the
12088     // loop and reconstruct.
12089   } while (0);
12090 
12091   // If we don't have a containing block, start with aFrame and look for one.
12092   if (!aContainingBlock) {
12093     aContainingBlock = aFrame;
12094   }
12095 
12096   // To find the right block to reframe, just walk up the tree until we find a
12097   // frame that is:
12098   // 1)  Not part of an IB split
12099   // 2)  Not a pseudo-frame
12100   // 3)  Not an inline frame
12101   // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
12102   // enforces that the root is display:none, display:table, or display:block.
12103   // Note that walking up "too far" is OK in terms of correctness, even if it
12104   // might be a little inefficient.  This is why we walk out of all
12105   // pseudo-frames -- telling which ones are or are not OK to walk out of is
12106   // too hard (and I suspect that we do in fact need to walk out of all of
12107   // them).
12108   while (IsFramePartOfIBSplit(aContainingBlock) ||
12109          aContainingBlock->IsInlineOutside() ||
12110          aContainingBlock->StyleContext()->GetPseudo()) {
12111     aContainingBlock = aContainingBlock->GetParent();
12112     NS_ASSERTION(aContainingBlock,
12113                  "Must have non-inline, non-ib-split, non-pseudo frame as "
12114                  "root (or child of root, for a table root)!");
12115   }
12116 
12117   // Tell parent of the containing block to reformulate the
12118   // entire block. This is painful and definitely not optimal
12119   // but it will *always* get the right answer.
12120 
12121   nsIContent* blockContent = aContainingBlock->GetContent();
12122 #ifdef DEBUG
12123   if (gNoisyContentUpdates) {
12124     printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
12125            static_cast<void*>(blockContent));
12126   }
12127 #endif
12128   RecreateFramesForContent(blockContent, InsertionKind::Async);
12129   return true;
12130 }
12131 
ReframeContainingBlock(nsIFrame * aFrame)12132 void nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) {
12133 #ifdef DEBUG
12134   // ReframeContainingBlock is a NASTY routine, it causes terrible performance
12135   // problems so I want to see when it is happening!  Unfortunately, it is
12136   // happening way to often because so much content on the web causes
12137   // block-in-inline frame situations and we handle them very poorly
12138   if (gNoisyContentUpdates) {
12139     printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
12140            static_cast<void*>(aFrame));
12141   }
12142 #endif
12143 
12144   // XXXbz how exactly would we get here while isReflowing anyway?  Should this
12145   // whole test be ifdef DEBUG?
12146   if (mPresShell->IsReflowLocked()) {
12147     // don't ReframeContainingBlock, this will result in a crash
12148     // if we remove a tree that's in reflow - see bug 121368 for testcase
12149     NS_ERROR(
12150         "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
12151         "Reflow!!!");
12152     return;
12153   }
12154 
12155   // Get the first "normal" ancestor of the target frame.
12156   nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
12157   if (containingBlock) {
12158     // From here we look for the containing block in case the target
12159     // frame is already a block (which can happen when an inline frame
12160     // wraps some of its content in an anonymous block; see
12161     // ConstructInline)
12162 
12163     // NOTE: We used to get the FloatContainingBlock here, but it was often
12164     // wrong. GetIBContainingBlock works much better and provides the correct
12165     // container in all cases so GetFloatContainingBlock(aFrame) has been
12166     // removed
12167 
12168     // And get the containingBlock's content
12169     if (nsIContent* blockContent = containingBlock->GetContent()) {
12170 #ifdef DEBUG
12171       if (gNoisyContentUpdates) {
12172         printf("  ==> blockContent=%p\n", static_cast<void*>(blockContent));
12173       }
12174 #endif
12175       RecreateFramesForContent(blockContent->AsElement(), InsertionKind::Async);
12176       return;
12177     }
12178   }
12179 
12180   // If we get here, we're screwed!
12181   RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
12182                            InsertionKind::Async);
12183 }
12184 
GenerateChildFrames(nsContainerFrame * aFrame)12185 void nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame) {
12186   {
12187     nsAutoScriptBlocker scriptBlocker;
12188     nsFrameItems childItems;
12189     TreeMatchContextHolder matchContext(mDocument);
12190     nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr,
12191                                   nullptr);
12192     // We don't have a parent frame with a pending binding constructor here,
12193     // so no need to worry about ordering of the kids' constructors with it.
12194     // Pass null for the PendingBinding.
12195     ProcessChildren(state, aFrame->GetContent(), aFrame->StyleContext(), aFrame,
12196                     false, childItems, false, nullptr);
12197 
12198     aFrame->SetInitialChildList(kPrincipalList, childItems);
12199   }
12200 
12201 #ifdef ACCESSIBILITY
12202   nsAccessibilityService* accService = nsIPresShell::AccService();
12203   if (accService) {
12204     nsIContent* container = aFrame->GetContent();
12205     nsIContent* child = container->GetFirstChild();
12206     if (child) {
12207       accService->ContentRangeInserted(mPresShell, container, child, nullptr);
12208     }
12209   }
12210 #endif
12211 
12212   // call XBL constructors after the frames are created
12213   mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
12214 }
12215 
12216 //////////////////////////////////////////////////////////
12217 // nsCSSFrameConstructor::FrameConstructionItem methods //
12218 //////////////////////////////////////////////////////////
IsWhitespace(nsFrameConstructorState & aState) const12219 bool nsCSSFrameConstructor::FrameConstructionItem::IsWhitespace(
12220     nsFrameConstructorState& aState) const {
12221   NS_PRECONDITION(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame(),
12222                   "How did that happen?");
12223   if (!mIsText) {
12224     return false;
12225   }
12226   mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
12227                      NS_REFRAME_IF_WHITESPACE);
12228   return mContent->TextIsOnlyWhitespace();
12229 }
12230 
12231 //////////////////////////////////////////////////////////////
12232 // nsCSSFrameConstructor::FrameConstructionItemList methods //
12233 //////////////////////////////////////////////////////////////
AdjustCountsForItem(FrameConstructionItem * aItem,int32_t aDelta)12234 void nsCSSFrameConstructor::FrameConstructionItemList::AdjustCountsForItem(
12235     FrameConstructionItem* aItem, int32_t aDelta) {
12236   NS_PRECONDITION(aDelta == 1 || aDelta == -1, "Unexpected delta");
12237   mItemCount += aDelta;
12238   if (aItem->mIsAllInline) {
12239     mInlineCount += aDelta;
12240   }
12241   if (aItem->mIsBlock) {
12242     mBlockCount += aDelta;
12243   }
12244   if (aItem->mIsLineParticipant) {
12245     mLineParticipantCount += aDelta;
12246   }
12247   mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
12248 }
12249 
12250 ////////////////////////////////////////////////////////////////////////
12251 // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
12252 ////////////////////////////////////////////////////////////////////////
12253 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
SkipItemsWantingParentType(ParentType aParentType)12254     SkipItemsWantingParentType(ParentType aParentType) {
12255   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
12256   while (item().DesiredParentType() == aParentType) {
12257     Next();
12258     if (IsDone()) {
12259       return true;
12260     }
12261   }
12262   return false;
12263 }
12264 
12265 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
SkipItemsNotWantingParentType(ParentType aParentType)12266     SkipItemsNotWantingParentType(ParentType aParentType) {
12267   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
12268   while (item().DesiredParentType() != aParentType) {
12269     Next();
12270     if (IsDone()) {
12271       return true;
12272     }
12273   }
12274   return false;
12275 }
12276 
12277 // Note: we implement -webkit-{inline-}box (and optionally -moz-{inline-}box)
12278 // using nsFlexContainerFrame, but we use different rules for what gets wrapped
12279 // in an anonymous flex item.
NeedsAnonFlexOrGridItem(const nsFrameConstructorState & aState,bool aIsLegacyBox)12280 bool nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem(
12281     const nsFrameConstructorState& aState, bool aIsLegacyBox) {
12282   if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
12283     // This will be an inline non-replaced box.
12284     return true;
12285   }
12286 
12287   if (aIsLegacyBox) {
12288     if (mStyleContext->StyleDisplay()->IsInlineOutsideStyle()) {
12289       // In an emulated legacy box, all inline-level content gets wrapped in an
12290       // anonymous flex item.
12291       return true;
12292     }
12293     if (mIsPopup ||
12294         (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
12295          aState.GetGeometricParent(mStyleContext->StyleDisplay(), nullptr))) {
12296       // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
12297       // placeholder which (because our container is an emulated legacy box)
12298       // we'll need to wrap in an anonymous flex item.  So, we just treat
12299       // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
12300       // and then when we spawn the placeholder, it'll end up in the right
12301       // spot.
12302       return true;
12303     }
12304   }
12305 
12306   return false;
12307 }
12308 
12309 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
SkipItemsThatNeedAnonFlexOrGridItem(const nsFrameConstructorState & aState,bool aIsLegacyBox)12310     SkipItemsThatNeedAnonFlexOrGridItem(const nsFrameConstructorState& aState,
12311                                         bool aIsLegacyBox) {
12312   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
12313   while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyBox)) {
12314     Next();
12315     if (IsDone()) {
12316       return true;
12317     }
12318   }
12319   return false;
12320 }
12321 
12322 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
SkipItemsThatDontNeedAnonFlexOrGridItem(const nsFrameConstructorState & aState,bool aIsLegacyBox)12323     SkipItemsThatDontNeedAnonFlexOrGridItem(
12324         const nsFrameConstructorState& aState, bool aIsLegacyBox) {
12325   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
12326   while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyBox))) {
12327     Next();
12328     if (IsDone()) {
12329       return true;
12330     }
12331   }
12332   return false;
12333 }
12334 
12335 inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
SkipItemsNotWantingRubyParent()12336     SkipItemsNotWantingRubyParent() {
12337   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
12338   while (!IsRubyParentType(item().DesiredParentType())) {
12339     Next();
12340     if (IsDone()) {
12341       return true;
12342     }
12343   }
12344   return false;
12345 }
12346 
12347 inline bool
SkipWhitespace(nsFrameConstructorState & aState)12348 nsCSSFrameConstructor::FrameConstructionItemList::Iterator::SkipWhitespace(
12349     nsFrameConstructorState& aState) {
12350   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
12351   NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?");
12352   do {
12353     Next();
12354     if (IsDone()) {
12355       return true;
12356     }
12357   } while (item().IsWhitespace(aState));
12358 
12359   return false;
12360 }
12361 
12362 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
AppendItemToList(FrameConstructionItemList & aTargetList)12363     AppendItemToList(FrameConstructionItemList& aTargetList) {
12364   NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
12365   NS_PRECONDITION(!IsDone(), "should not be done");
12366 
12367   FrameConstructionItem* item = mCurrent;
12368   Next();
12369   item->remove();
12370   aTargetList.mItems.insertBack(item);
12371 
12372   mList.AdjustCountsForItem(item, -1);
12373   aTargetList.AdjustCountsForItem(item, 1);
12374 }
12375 
12376 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
AppendItemsToList(nsCSSFrameConstructor * aFCtor,const Iterator & aEnd,FrameConstructionItemList & aTargetList)12377     AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
12378                       FrameConstructionItemList& aTargetList) {
12379   NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
12380   NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
12381 
12382   // We can't just move our guts to the other list if it already has
12383   // some information or if we're not moving our entire list.
12384   if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() ||
12385       !aTargetList.mUndisplayedItems.IsEmpty()) {
12386     do {
12387       AppendItemToList(aTargetList);
12388     } while (*this != aEnd);
12389     return;
12390   }
12391 
12392   // Move our entire list of items into the empty target list.
12393   aTargetList.mItems = Move(mList.mItems);
12394 
12395   // Copy over the various counters
12396   aTargetList.mInlineCount = mList.mInlineCount;
12397   aTargetList.mBlockCount = mList.mBlockCount;
12398   aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
12399   aTargetList.mItemCount = mList.mItemCount;
12400   memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
12401          sizeof(aTargetList.mDesiredParentCounts));
12402 
12403   // Swap out undisplayed item arrays, before we nuke the array on our end
12404   aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
12405 
12406   // reset mList
12407   mList.Reset(aFCtor);
12408 
12409   // Point ourselves to aEnd, as advertised
12410   SetToEnd();
12411   MOZ_ASSERT(*this == aEnd, "How did that happen?");
12412 }
12413 
InsertItem(FrameConstructionItem * aItem)12414 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::InsertItem(
12415     FrameConstructionItem* aItem) {
12416   if (IsDone()) {
12417     mList.mItems.insertBack(aItem);
12418   } else {
12419     // Just insert the item before us.  There's no magic here.
12420     mCurrent->setPrevious(aItem);
12421   }
12422   mList.AdjustCountsForItem(aItem, 1);
12423 
12424   MOZ_ASSERT(aItem->getNext() == mCurrent, "How did that happen?");
12425 }
12426 
DeleteItemsTo(nsCSSFrameConstructor * aFCtor,const Iterator & aEnd)12427 void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::DeleteItemsTo(
12428     nsCSSFrameConstructor* aFCtor, const Iterator& aEnd) {
12429   NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
12430   NS_PRECONDITION(*this != aEnd, "Shouldn't be at aEnd yet");
12431 
12432   do {
12433     NS_ASSERTION(!IsDone(), "Ran off end of list?");
12434     FrameConstructionItem* item = mCurrent;
12435     Next();
12436     item->remove();
12437     mList.AdjustCountsForItem(item, -1);
12438     item->Delete(aFCtor);
12439   } while (*this != aEnd);
12440 }
12441 
QuotesDirty()12442 void nsCSSFrameConstructor::QuotesDirty() {
12443   mQuotesDirty = true;
12444   mPresShell->SetNeedLayoutFlush();
12445 }
12446 
CountersDirty()12447 void nsCSSFrameConstructor::CountersDirty() {
12448   mCountersDirty = true;
12449   mPresShell->SetNeedLayoutFlush();
12450 }
12451 
AllocateFCItem()12452 void* nsCSSFrameConstructor::AllocateFCItem() {
12453   void* item;
12454   if (mFirstFreeFCItem) {
12455     item = mFirstFreeFCItem;
12456     mFirstFreeFCItem = mFirstFreeFCItem->mNext;
12457   } else {
12458     item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
12459   }
12460   ++mFCItemsInUse;
12461   return item;
12462 }
12463 
FreeFCItem(FrameConstructionItem * aItem)12464 void nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem) {
12465   MOZ_ASSERT(mFCItemsInUse != 0);
12466   if (--mFCItemsInUse == 0) {
12467     // The arena is now unused - clear it but retain one chunk.
12468     mFirstFreeFCItem = nullptr;
12469     mFCItemPool.Clear();
12470   } else {
12471     // Prepend it to the list of free items.
12472     FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
12473     item->mNext = mFirstFreeFCItem;
12474     mFirstFreeFCItem = item;
12475   }
12476 }
12477 
AddSizeOfIncludingThis(nsWindowSizes & aSizes) const12478 void nsCSSFrameConstructor::AddSizeOfIncludingThis(
12479     nsWindowSizes& aSizes) const {
12480   if (nsIFrame* rootFrame = GetRootFrame()) {
12481     rootFrame->AddSizeOfExcludingThisForTree(aSizes);
12482   }
12483 
12484   // This must be done after measuring from the frame tree, since frame
12485   // manager will measure sizes of staled computed values and style
12486   // structs, which only make sense after we know what are being used.
12487   nsFrameManager::AddSizeOfIncludingThis(aSizes);
12488 
12489   // Measurement of the following members may be added later if DMD finds it
12490   // is worthwhile:
12491   // - mFCItemPool
12492   // - mQuoteList
12493   // - mCounterManager
12494 }
12495