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 #ifndef nsCSSFrameConstructor_h___
13 #define nsCSSFrameConstructor_h___
14 
15 #include "mozilla/ArenaAllocator.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/LinkedList.h"
18 #include "mozilla/RestyleManager.h"
19 
20 #include "nsCOMPtr.h"
21 #include "nsILayoutHistoryState.h"
22 #include "nsQuoteList.h"
23 #include "nsCounterManager.h"
24 #include "nsIAnonymousContentCreator.h"
25 #include "nsFrameManager.h"
26 #include "ScrollbarStyles.h"
27 
28 struct nsFrameItems;
29 class nsStyleContext;
30 struct nsStyleDisplay;
31 struct nsGenConInitializer;
32 
33 class nsContainerFrame;
34 class nsFirstLineFrame;
35 class nsFirstLetterFrame;
36 class nsICSSAnonBoxPseudo;
37 class nsIDocument;
38 class nsPageContentFrame;
39 struct PendingBinding;
40 class nsGenericDOMDataNode;
41 
42 class nsFrameConstructorState;
43 
44 namespace mozilla {
45 
46 namespace dom {
47 
48 class FlattenedChildIterator;
49 
50 }  // namespace dom
51 }  // namespace mozilla
52 
53 class nsCSSFrameConstructor final : public nsFrameManager {
54  public:
55   typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
56   typedef mozilla::dom::Element Element;
57 
58   friend class mozilla::RestyleManager;
59   friend class mozilla::GeckoRestyleManager;
60   friend class mozilla::ServoRestyleManager;
61 
62   nsCSSFrameConstructor(nsIDocument* aDocument, nsIPresShell* aPresShell);
~nsCSSFrameConstructor()63   ~nsCSSFrameConstructor() { MOZ_ASSERT(mFCItemsInUse == 0); }
64 
65   // get the alternate text for a content node
66   static void GetAlternateTextFor(mozilla::dom::Element* aContent,
67                                   nsAtom* aTag,  // content object's tag
68                                   nsAString& aAltText);
69 
70  private:
71   nsCSSFrameConstructor(const nsCSSFrameConstructor& aCopy) = delete;
72   nsCSSFrameConstructor& operator=(const nsCSSFrameConstructor& aCopy) = delete;
73 
74  public:
75   /**
76    * Whether insertion should be done synchronously or asynchronously.
77    *
78    * Generally, insertion is synchronous if we're entering frame construction
79    * from restyle processing, and async if we're removing stuff, or need to
80    * reconstruct some ancestor.
81    *
82    * Note that constructing async from frame construction will post a restyle
83    * event, but won't need another whole refresh driver tick to go in. Instead
84    * change hint processing will keep going as long as there are changes in the
85    * queue.
86    */
87   enum class InsertionKind {
88     Sync,
89     Async,
90   };
91 
RestyleManager()92   mozilla::RestyleManager* RestyleManager() const {
93     return mPresShell->GetPresContext()->RestyleManager();
94   }
95 
96   nsIFrame* ConstructRootFrame();
97 
98   void ReconstructDocElementHierarchy(InsertionKind);
99 
100 #ifdef MOZ_OLD_STYLE
101   // Create frames for content nodes that are marked as needing frames. This
102   // should be called before ProcessPendingRestyles.
103   // Note: It's the caller's responsibility to make sure to wrap a
104   // CreateNeededFrames call in a view update batch and a script blocker.
105   void CreateNeededFrames();
106 #endif
107 
108  private:
109 #ifdef MOZ_OLD_STYLE
110   void CreateNeededFrames(nsIContent* aContent,
111                           TreeMatchContext& aTreeMatchContext);
112 #endif
113 
114   enum Operation { CONTENTAPPEND, CONTENTINSERT };
115 
116   // aChild is the child being inserted for inserts, and the first
117   // child being appended for appends.
118   bool MaybeConstructLazily(Operation aOperation, nsIContent* aContainer,
119                             nsIContent* aChild);
120 
121 #ifdef DEBUG
122   void CheckBitsForLazyFrameConstruction(nsIContent* aParent);
123 #else
CheckBitsForLazyFrameConstruction(nsIContent *)124   void CheckBitsForLazyFrameConstruction(nsIContent*) {}
125 #endif
126 
127   // Issues a single ContentInserted for each child of aContainer in the range
128   // [aStartChild, aEndChild).
129   void IssueSingleInsertNofications(nsIContent* aContainer,
130                                     nsIContent* aStartChild,
131                                     nsIContent* aEndChild);
132 
133   /**
134    * Data that represents an insertion point for some child content.
135    */
136   struct InsertionPoint {
InsertionPointInsertionPoint137     InsertionPoint() : mParentFrame(nullptr), mContainer(nullptr) {}
138 
InsertionPointInsertionPoint139     InsertionPoint(nsContainerFrame* aParentFrame, nsIContent* aContainer)
140         : mParentFrame(aParentFrame), mContainer(aContainer) {}
141 
142     /**
143      * The parent frame to use if the inserted children needs to create
144      * frame(s).  May be null, which signals that  we shouldn't try to
145      * create frames for the inserted children; either because there are
146      * no parent frame or because there are multiple insertion points and
147      * we will call IssueSingleInsertNofications for each child instead.
148      * mContainer should not be used when mParentFrame is null.
149      */
150     nsContainerFrame* mParentFrame;
151     /**
152      * The flattened tree parent for the inserted children.
153      * It's undefined if mParentFrame is null.
154      */
155     nsIContent* mContainer;
156 
157     /**
158      * Whether it is required to insert children one-by-one instead of as a
159      * range.
160      */
161     bool IsMultiple() const;
162   };
163 
164   /**
165    * Checks if the children of aContainer in the range [aStartChild, aEndChild)
166    * can be inserted/appended to one insertion point together. If so, returns
167    * that insertion point. If not, returns with InsertionPoint.mFrame == nullptr
168    * and issues single ContentInserted calls for each child.
169    * aEndChild = nullptr indicates that we are dealing with an append.
170    */
171   InsertionPoint GetRangeInsertionPoint(nsIContent* aContainer,
172                                         nsIContent* aStartChild,
173                                         nsIContent* aEndChild);
174 
175   // Returns true if parent was recreated due to frameset child, false
176   // otherwise.
177   bool MaybeRecreateForFrameset(nsIFrame* aParentFrame, nsIContent* aStartChild,
178                                 nsIContent* aEndChild);
179 
180   /**
181    * For each child in the aStartChild/aEndChild range, calls
182    * NoteDirtyDescendantsForServo on their flattened tree parents.  This is
183    * used when content is inserted into the document and we decide that
184    * we can do lazy frame construction.  It handles children being rebound to
185    * different insertion points by calling NoteDirtyDescendantsForServo on each
186    * child's flattened tree parent.  Only used when we are styled by Servo.
187    */
188   void LazilyStyleNewChildRange(nsIContent* aStartChild, nsIContent* aEndChild);
189 
190   /**
191    * For each child in the aStartChild/aEndChild range, calls StyleNewChildren
192    * on their flattened tree parents.  This is used when content is inserted
193    * into the document and we decide that we cannot do lazy frame construction.
194    * It handles children being rebound to different insertion points by calling
195    * StyleNewChildren on each child's flattened tree parent.  Only used when we
196    * are styled by Servo.
197    */
198   void StyleNewChildRange(nsIContent* aStartChild, nsIContent* aEndChild);
199 
200  public:
201   /**
202    * Lazy frame construction is controlled by the InsertionKind parameter of
203    * nsCSSFrameConstructor::ContentAppended/Inserted. It is true for all
204    * inserts/appends as passed from the presshell, except for the insert of the
205    * root element, which is always non-lazy.
206    *
207    * Even if the aInsertionKind passed to ContentAppended/Inserted is
208    * Async we still may not be able to construct lazily, so we call
209    * MaybeConstructLazily.  MaybeConstructLazily does not allow lazy
210    * construction if any of the following are true:
211    *  -we are in chrome
212    *  -the container is in a native anonymous subtree
213    *  -the container is XUL
214    *  -is any of the appended/inserted nodes are XUL or editable
215    *  -(for inserts) the child is anonymous.  In the append case this function
216    *   must not be called with anonymous children.
217    * The XUL and chrome checks are because XBL bindings only get applied at
218    * frame construction time and some things depend on the bindings getting
219    * attached synchronously.
220    *
221    * If MaybeConstructLazily returns false we construct as usual, but if it
222    * returns true then it adds NODE_NEEDS_FRAME bits to the newly
223    * inserted/appended nodes and adds NODE_DESCENDANTS_NEED_FRAMES bits to the
224    * container and up along the parent chain until it hits the root or another
225    * node with that bit set. Then it posts a restyle event to ensure that a
226    * flush happens to construct those frames.
227    *
228    * When the flush happens the presshell calls
229    * nsCSSFrameConstructor::CreateNeededFrames. CreateNeededFrames follows any
230    * nodes with NODE_DESCENDANTS_NEED_FRAMES set down the content tree looking
231    * for nodes with NODE_NEEDS_FRAME set. It calls ContentAppended for any runs
232    * of nodes with NODE_NEEDS_FRAME set that are at the end of their childlist,
233    * and ContentRangeInserted for any other runs that aren't.
234    *
235    * If a node is removed from the document then we don't bother unsetting any
236    * of the lazy bits that might be set on it, its descendants, or any of its
237    * ancestor nodes because that is a slow operation, the work might be wasted
238    * if another node gets inserted in its place, and we can clear the bits
239    * quicker by processing the content tree from top down the next time we call
240    * CreateNeededFrames. (We do clear the bits when BindToTree is called on any
241    * nsIContent; so any nodes added to the document will not have any lazy bits
242    * set.)
243    */
244 
245   // If aInsertionKind is Async then frame construction of the new children can
246   // be done lazily.
247   //
248   // When constructing frames lazily, we can keep the tree match context in a
249   // much easier way than nsFrameConstructorState, and thus, we're allowed to
250   // provide a TreeMatchContext to avoid calling InitAncestors repeatedly deep
251   // in the DOM.
252   void ContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent,
253                        InsertionKind aInsertionKind,
254                        TreeMatchContext* aProvidedTreeMatchContext = nullptr);
255 
256   // If aInsertionkind is Async then frame construction of the new child
257   // can be done lazily.
258   void ContentInserted(nsIContent* aContainer, nsIContent* aChild,
259                        nsILayoutHistoryState* aFrameState,
260                        InsertionKind aInsertionKind);
261 
262   // Like ContentInserted but handles inserting the children of aContainer in
263   // the range [aStartChild, aEndChild).  aStartChild must be non-null.
264   // aEndChild may be null to indicate the range includes all kids after
265   // aStartChild.
266   //
267   // If aInsertionKind is Async then frame construction of the new children can
268   // be done lazily. It is only allowed to be Async when inserting a single
269   // node.
270   //
271   // See ContentAppended to see why we allow passing an already initialized
272   // TreeMatchContext.
273   void ContentRangeInserted(
274       nsIContent* aContainer, nsIContent* aStartChild, nsIContent* aEndChild,
275       nsILayoutHistoryState* aFrameState, InsertionKind aInsertionKind,
276       TreeMatchContext* aProvidedTreeMatchContext = nullptr);
277 
278   enum RemoveFlags {
279     REMOVE_CONTENT,
280     REMOVE_FOR_RECONSTRUCTION,
281   };
282 
283   /**
284    * Recreate or destroy frames for aChild in aContainer.
285    *
286    * aFlags == REMOVE_CONTENT means aChild has been removed from the document.
287    * aFlags == REMOVE_FOR_RECONSTRUCTION means the caller will reconstruct the
288    * frames later.
289    *
290    * In both the above cases, this method will in some cases try to reconstruct
291    * frames on some ancestor of aChild.  This can happen regardless of the value
292    * of aFlags.
293    *
294    * The return value indicates whether this "reconstruct an ancestor" action
295    * took place.  If true is returned, that means that the frame subtree rooted
296    * at some ancestor of aChild's frame was destroyed and will be reconstructed
297    * async.
298    */
299   bool ContentRemoved(nsIContent* aContainer, nsIContent* aChild,
300                       nsIContent* aOldNextSibling, RemoveFlags aFlags);
301 
302   void CharacterDataChanged(nsIContent* aContent,
303                             const CharacterDataChangeInfo& aInfo);
304 
305   // If aContent is a text node that has been optimized away due to being
306   // whitespace next to a block boundary (or for some other reason), ensure that
307   // a frame for it is created the next time frames are flushed, if it can
308   // possibly have a frame at all.
309   //
310   // Returns whether there are chances for the frame to be unsuppressed.
311   bool EnsureFrameForTextNodeIsCreatedAfterFlush(
312       nsGenericDOMDataNode* aContent);
313 
314   // Generate the child frames and process bindings
315   void GenerateChildFrames(nsContainerFrame* aFrame);
316 
317   // Should be called when a frame is going to be destroyed and
318   // WillDestroyFrameTree hasn't been called yet.
319   void NotifyDestroyingFrame(nsIFrame* aFrame);
320 
321   void RecalcQuotesAndCounters();
322 
323   // Called when any counter style is changed.
324   void NotifyCounterStylesAreDirty();
325 
326   // Gets called when the presshell is destroying itself and also
327   // when we tear down our frame tree to reconstruct it
328   void WillDestroyFrameTree();
329 
330   /**
331    * Destroy the frames for aContent.  Note that this may destroy frames
332    * for an ancestor instead.
333    *
334    * Returns whether a reconstruct was posted for any ancestor.
335    */
336   bool DestroyFramesFor(mozilla::dom::Element* aElement);
337 
338   // Request to create a continuing frame.  This method never returns null.
339   nsIFrame* CreateContinuingFrame(nsPresContext* aPresContext, nsIFrame* aFrame,
340                                   nsContainerFrame* aParentFrame,
341                                   bool aIsFluid = true);
342 
343   // Copy over fixed frames from aParentFrame's prev-in-flow
344   nsresult ReplicateFixedFrames(nsPageContentFrame* aParentFrame);
345 
346   /**
347    * Get the insertion point for aChild.
348    */
349   InsertionPoint GetInsertionPoint(nsIContent* aChild);
350 
351   /**
352    * Return the insertion frame of the primary frame of aContent, or its nearest
353    * ancestor that isn't display:contents.
354    */
355   nsContainerFrame* GetContentInsertionFrameFor(nsIContent* aContent);
356 
357   void CreateListBoxContent(nsContainerFrame* aParentFrame,
358                             nsIFrame* aPrevFrame, nsIContent* aChild,
359                             nsIFrame** aResult, bool aIsAppend);
360 
361   // GetInitialContainingBlock() is deprecated in favor of
362   // GetRootElementFrame(); nsIFrame* GetInitialContainingBlock() { return
363   // mRootElementFrame; } This returns the outermost frame for the root element
GetRootElementFrame()364   nsContainerFrame* GetRootElementFrame() { return mRootElementFrame; }
365   // This returns the frame for the root element that does not
366   // have a psuedo-element style
GetRootElementStyleFrame()367   nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; }
GetPageSequenceFrame()368   nsIFrame* GetPageSequenceFrame() { return mPageSequenceFrame; }
369 
370   // Get the frame that is the parent of the root element.
GetDocElementContainingBlock()371   nsContainerFrame* GetDocElementContainingBlock() {
372     return mDocElementContainingBlock;
373   }
374 
375   void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
376 
377  private:
378   struct FrameConstructionItem;
379   class FrameConstructionItemList;
380 
381   nsContainerFrame* ConstructPageFrame(nsIPresShell* aPresShell,
382                                        nsContainerFrame* aParentFrame,
383                                        nsIFrame* aPrevPageFrame,
384                                        nsContainerFrame*& aCanvasFrame);
385 
386   void InitAndRestoreFrame(const nsFrameConstructorState& aState,
387                            nsIContent* aContent, nsContainerFrame* aParentFrame,
388                            nsIFrame* aNewFrame, bool aAllowCounters = true);
389 
390   // aState can be null if not available; it's used as an optimization.
391   // XXXbz IsValidSibling is the only caller that doesn't pass a state here!
392   already_AddRefed<nsStyleContext> ResolveStyleContext(
393       nsIFrame* aParentFrame, nsIContent* aContainer, nsIContent* aChild,
394       nsFrameConstructorState* aState);
395   already_AddRefed<nsStyleContext> ResolveStyleContext(
396       nsIFrame* aParentFrame, nsIContent* aChild,
397       nsFrameConstructorState* aState);
398   already_AddRefed<nsStyleContext> ResolveStyleContext(
399       const InsertionPoint& aInsertion, nsIContent* aChild,
400       nsFrameConstructorState* aState);
401   already_AddRefed<nsStyleContext> ResolveStyleContext(
402       nsStyleContext* aParentStyleContext, nsIContent* aContent,
403       nsFrameConstructorState* aState,
404       Element* aOriginatingElementOrNull = nullptr);
405 
406   // Add the frame construction items for the given aContent and aParentFrame
407   // to the list.  This might add more than one item in some rare cases.
408   // If aSuppressWhiteSpaceOptimizations is true, optimizations that
409   // may suppress the construction of white-space-only text frames
410   // must be skipped for these items and items around them.
411   void AddFrameConstructionItems(nsFrameConstructorState& aState,
412                                  nsIContent* aContent,
413                                  bool aSuppressWhiteSpaceOptimizations,
414                                  const InsertionPoint& aInsertion,
415                                  FrameConstructionItemList& aItems);
416 
417   // Helper method for AddFrameConstructionItems etc.
418   // Unsets the need-frame/restyle bits on aContent.
419   // return true iff we should attempt to create frames for aContent.
420   bool ShouldCreateItemsForChild(nsFrameConstructorState& aState,
421                                  nsIContent* aContent,
422                                  nsContainerFrame* aParentFrame);
423 
424   // Helper method for AddFrameConstructionItems etc.
425   // Make sure ShouldCreateItemsForChild() returned true before calling this.
426   void DoAddFrameConstructionItems(
427       nsFrameConstructorState& aState, nsIContent* aContent,
428       nsStyleContext* aStyleContext, bool aSuppressWhiteSpaceOptimizations,
429       nsContainerFrame* aParentFrame,
430       nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
431       FrameConstructionItemList& aItems);
432 
433   // Construct the frames for the document element.  This can return null if the
434   // document element is display:none, or if the document element has a
435   // not-yet-loaded XBL binding, or if it's an SVG element that's not <svg>.
436   nsIFrame* ConstructDocElementFrame(Element* aDocElement,
437                                      nsILayoutHistoryState* aFrameState);
438 
439   // Set up our mDocElementContainingBlock correctly for the given root
440   // content.
441   void SetUpDocElementContainingBlock(nsIContent* aDocElement);
442 
443   /**
444    * CreateAttributeContent creates a single content/frame combination for an
445    * |attr(foo)| generated content.
446    *
447    * @param aParentContent the parent content for the generated content
448    * @param aParentFrame the parent frame for the generated frame
449    * @param aAttrNamespace the namespace of the attribute in question
450    * @param aAttrName the localname of the attribute
451    * @param aStyleContext the style context to use
452    * @param aGeneratedContent the array of generated content to append the
453    *                          created content to.
454    * @param [out] aNewContent the content node we create
455    * @param [out] aNewFrame the new frame we create
456    */
457   void CreateAttributeContent(mozilla::dom::Element* aParentContent,
458                               nsIFrame* aParentFrame, int32_t aAttrNamespace,
459                               nsAtom* aAttrName, nsStyleContext* aStyleContext,
460                               nsCOMArray<nsIContent>& aGeneratedContent,
461                               nsIContent** aNewContent, nsIFrame** aNewFrame);
462 
463   /**
464    * Create a text node containing the given string. If aText is non-null
465    * then we also set aText to the returned node.
466    */
467   already_AddRefed<nsIContent> CreateGenConTextNode(
468       nsFrameConstructorState& aState, const nsString& aString,
469       RefPtr<nsTextNode>* aText, nsGenConInitializer* aInitializer);
470 
471   /**
472    * Create a content node for the given generated content style.
473    * The caller takes care of making it SetIsNativeAnonymousRoot, binding it
474    * to the document, and creating frames for it.
475    * @param aParentContent is the node that has the before/after style
476    * @param aStyleContext is the 'before' or 'after' pseudo-element
477    * style context
478    * @param aContentIndex is the index of the content item to create
479    */
480   already_AddRefed<nsIContent> CreateGeneratedContent(
481       nsFrameConstructorState& aState, mozilla::dom::Element* aParentContent,
482       nsStyleContext* aStyleContext, uint32_t aContentIndex);
483 
484   // aFrame may be null; this method doesn't use it directly in any case.
485   void CreateGeneratedContentItem(nsFrameConstructorState& aState,
486                                   nsContainerFrame* aFrame,
487                                   mozilla::dom::Element* aContent,
488                                   nsStyleContext* aStyleContext,
489                                   CSSPseudoElementType aPseudoElement,
490                                   FrameConstructionItemList& aItems);
491 
492   // This method can change aFrameList: it can chop off the beginning and put
493   // it in aParentFrame while putting the remainder into a ib-split sibling of
494   // aParentFrame.  aPrevSibling must be the frame after which aFrameList is to
495   // be placed on aParentFrame's principal child list.  It may be null if
496   // aFrameList is being added at the beginning of the child list.
497   void AppendFramesToParent(nsFrameConstructorState& aState,
498                             nsContainerFrame* aParentFrame,
499                             nsFrameItems& aFrameList, nsIFrame* aPrevSibling,
500                             bool aIsRecursiveCall = false);
501 
502   // BEGIN TABLE SECTION
503   /**
504    * Construct a table wrapper frame. This is the FrameConstructionData
505    * callback used for the job.
506    */
507   nsIFrame* ConstructTable(nsFrameConstructorState& aState,
508                            FrameConstructionItem& aItem,
509                            nsContainerFrame* aParentFrame,
510                            const nsStyleDisplay* aDisplay,
511                            nsFrameItems& aFrameItems);
512 
513   /**
514    * FrameConstructionData callback for constructing table rows and row groups.
515    */
516   nsIFrame* ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
517                                         FrameConstructionItem& aItem,
518                                         nsContainerFrame* aParentFrame,
519                                         const nsStyleDisplay* aStyleDisplay,
520                                         nsFrameItems& aFrameItems);
521 
522   /**
523    * FrameConstructionData callback used for constructing table columns.
524    */
525   nsIFrame* ConstructTableCol(nsFrameConstructorState& aState,
526                               FrameConstructionItem& aItem,
527                               nsContainerFrame* aParentFrame,
528                               const nsStyleDisplay* aStyleDisplay,
529                               nsFrameItems& aFrameItems);
530 
531   /**
532    * FrameConstructionData callback used for constructing table cells.
533    */
534   nsIFrame* ConstructTableCell(nsFrameConstructorState& aState,
535                                FrameConstructionItem& aItem,
536                                nsContainerFrame* aParentFrame,
537                                const nsStyleDisplay* aStyleDisplay,
538                                nsFrameItems& aFrameItems);
539 
540  private:
541   /* An enum of possible parent types for anonymous table or ruby object
542      construction */
543   enum ParentType {
544     eTypeBlock = 0, /* This includes all non-table-related frames */
545     eTypeRow,
546     eTypeRowGroup,
547     eTypeColGroup,
548     eTypeTable,
549     eTypeRuby,
550     eTypeRubyBase,
551     eTypeRubyBaseContainer,
552     eTypeRubyText,
553     eTypeRubyTextContainer,
554     eParentTypeCount
555   };
556 
557   /* 4 bits is enough to handle our ParentType values */
558 #define FCDATA_PARENT_TYPE_OFFSET 28
559   /* Macro to get the desired parent type out of an mBits member of
560      FrameConstructionData */
561 #define FCDATA_DESIRED_PARENT_TYPE(_bits) \
562   ParentType((_bits) >> FCDATA_PARENT_TYPE_OFFSET)
563   /* Macro to create FrameConstructionData bits out of a desired parent type */
564 #define FCDATA_DESIRED_PARENT_TYPE_TO_BITS(_type) \
565   (((uint32_t)(_type)) << FCDATA_PARENT_TYPE_OFFSET)
566 
567   /* Get the parent type that aParentFrame has. */
GetParentType(nsIFrame * aParentFrame)568   static ParentType GetParentType(nsIFrame* aParentFrame) {
569     return GetParentType(aParentFrame->Type());
570   }
571 
572   /* Get the parent type for the given LayoutFrameType */
573   static ParentType GetParentType(mozilla::LayoutFrameType aFrameType);
574 
IsRubyParentType(ParentType aParentType)575   static bool IsRubyParentType(ParentType aParentType) {
576     return (aParentType == eTypeRuby || aParentType == eTypeRubyBase ||
577             aParentType == eTypeRubyBaseContainer ||
578             aParentType == eTypeRubyText ||
579             aParentType == eTypeRubyTextContainer);
580   }
581 
IsTableParentType(ParentType aParentType)582   static bool IsTableParentType(ParentType aParentType) {
583     return (aParentType == eTypeTable || aParentType == eTypeRow ||
584             aParentType == eTypeRowGroup || aParentType == eTypeColGroup);
585   }
586 
587   /* A constructor function that just creates an nsIFrame object.  The caller
588      is responsible for initializing the object, adding it to frame lists,
589      constructing frames for the children, etc.
590 
591      @param nsIPresShell the presshell whose arena should be used to allocate
592                          the frame.
593      @param nsStyleContext the style context to use for the frame. */
594   typedef nsIFrame* (*FrameCreationFunc)(nsIPresShell*, nsStyleContext*);
595   typedef nsContainerFrame* (*ContainerFrameCreationFunc)(nsIPresShell*,
596                                                           nsStyleContext*);
597   typedef nsBlockFrame* (*BlockFrameCreationFunc)(nsIPresShell*,
598                                                   nsStyleContext*);
599 
600   /* A function that can be used to get a FrameConstructionData.  Such
601      a function is allowed to return null.
602 
603      @param nsIContent the node for which the frame is being constructed.
604      @param nsStyleContext the style context to be used for the frame.
605   */
606   struct FrameConstructionData;
607   typedef const FrameConstructionData* (*FrameConstructionDataGetter)(
608       Element*, nsStyleContext*);
609 
610   /* A constructor function that's used for complicated construction tasks.
611      This is expected to create the new frame, initialize it, add whatever
612      needs to be added to aFrameItems (XXXbz is that really necessary?  Could
613      caller add?  Might there be cases when the returned frame or its
614      placeholder is not the thing that ends up in aFrameItems?  If not, would
615      it be safe to do the add into the frame construction state after
616      processing kids?  Look into this as a followup!), process children as
617      needed, etc.  It is NOT expected to deal with setting the frame on the
618      content.
619 
620      @param aState the frame construction state to use.
621      @param aItem the frame construction item to use
622      @param aParentFrame the frame to set as the parent of the
623                          newly-constructed frame.
624      @param aStyleDisplay the display struct from aItem's mStyleContext
625      @param aFrameItems the frame list to add the new frame (or its
626                         placeholder) to.
627      @return the frame that was constructed.  This frame is what the caller
628              will set as the frame on the content.  Guaranteed non-null.
629   */
630   typedef nsIFrame* (nsCSSFrameConstructor::*FrameFullConstructor)(
631       nsFrameConstructorState& aState, FrameConstructionItem& aItem,
632       nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
633       nsFrameItems& aFrameItems);
634 
635   /* Bits that modify the way a FrameConstructionData is handled */
636 
637   /* If the FCDATA_SKIP_FRAMESET bit is set, then the frame created should not
638      be set as the primary frame on the content node.  This should only be used
639      in very rare cases when we create more than one frame for a given content
640      node. */
641 #define FCDATA_SKIP_FRAMESET 0x1
642   /* If the FCDATA_FUNC_IS_DATA_GETTER bit is set, then the mFunc of the
643      FrameConstructionData is a getter function that can be used to get the
644      actual FrameConstructionData to use. */
645 #define FCDATA_FUNC_IS_DATA_GETTER 0x2
646   /* If the FCDATA_FUNC_IS_FULL_CTOR bit is set, then the FrameConstructionData
647      has an mFullConstructor.  In this case, there is no relevant mData or
648      mFunc */
649 #define FCDATA_FUNC_IS_FULL_CTOR 0x4
650   /* If FCDATA_DISALLOW_OUT_OF_FLOW is set, do not allow the frame to
651      float or be absolutely positioned.  This can also be used with
652      FCDATA_FUNC_IS_FULL_CTOR to indicate what the full-constructor
653      function will do. */
654 #define FCDATA_DISALLOW_OUT_OF_FLOW 0x8
655   /* If FCDATA_FORCE_NULL_ABSPOS_CONTAINER is set, make sure to push a
656      null absolute containing block before processing children for this
657      frame.  If this is not set, the frame will be pushed as the
658      absolute containing block as needed, based on its style */
659 #define FCDATA_FORCE_NULL_ABSPOS_CONTAINER 0x10
660   /* If FCDATA_WRAP_KIDS_IN_BLOCKS is set, the inline kids of the frame
661      will be wrapped in blocks.  This is only usable for MathML at the
662      moment. */
663 #define FCDATA_WRAP_KIDS_IN_BLOCKS 0x20
664   /* If FCDATA_SUPPRESS_FRAME is set, no frame should be created for the
665      content.  If this bit is set, nothing else in the struct needs to be
666      set. */
667 #define FCDATA_SUPPRESS_FRAME 0x40
668   /* If FCDATA_MAY_NEED_SCROLLFRAME is set, the new frame should be wrapped in
669      a scrollframe if its overflow type so requires. */
670 #define FCDATA_MAY_NEED_SCROLLFRAME 0x80
671 #ifdef MOZ_XUL
672   /* If FCDATA_IS_POPUP is set, the new frame is a XUL popup frame.  These need
673      some really weird special handling.  */
674 #define FCDATA_IS_POPUP 0x100
675 #endif /* MOZ_XUL */
676   /* If FCDATA_SKIP_ABSPOS_PUSH is set, don't push this frame as an
677      absolute containing block, no matter what its style says. */
678 #define FCDATA_SKIP_ABSPOS_PUSH 0x200
679   /* If FCDATA_DISALLOW_GENERATED_CONTENT is set, then don't allow generated
680      content when processing kids of this frame.  This should not be used with
681      FCDATA_FUNC_IS_FULL_CTOR */
682 #define FCDATA_DISALLOW_GENERATED_CONTENT 0x400
683   /* If FCDATA_IS_TABLE_PART is set, then the frame is some sort of
684      table-related thing and we should not attempt to fetch a table-cell parent
685      for it if it's inside another table-related frame. */
686 #define FCDATA_IS_TABLE_PART 0x800
687   /* If FCDATA_IS_INLINE is set, then the frame is a non-replaced CSS
688      inline box. */
689 #define FCDATA_IS_INLINE 0x1000
690   /* If FCDATA_IS_LINE_PARTICIPANT is set, the frame is something that will
691      return true for IsFrameOfType(nsIFrame::eLineParticipant) */
692 #define FCDATA_IS_LINE_PARTICIPANT 0x2000
693   /* If FCDATA_IS_LINE_BREAK is set, the frame is something that will
694      induce a line break boundary before and after itself. */
695 #define FCDATA_IS_LINE_BREAK 0x4000
696   /* If FCDATA_ALLOW_BLOCK_STYLES is set, allow block styles when processing
697      children of a block (i.e. allow ::first-letter/line).
698      This should not be used with FCDATA_FUNC_IS_FULL_CTOR. */
699 #define FCDATA_ALLOW_BLOCK_STYLES 0x8000
700   /* If FCDATA_USE_CHILD_ITEMS is set, then use the mChildItems in the relevant
701      FrameConstructionItem instead of trying to process the content's children.
702      This can be used with or without FCDATA_FUNC_IS_FULL_CTOR.
703      The child items might still need table pseudo processing. */
704 #define FCDATA_USE_CHILD_ITEMS 0x10000
705   /* If FCDATA_FORCED_NON_SCROLLABLE_BLOCK is set, then this block
706      would have been scrollable but has been forced to be
707      non-scrollable due to being in a paginated context. */
708 #define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000
709   /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a
710      block formatting context wrapper around the kids of this frame
711      using the FrameConstructionData's mPseudoAtom for its anonymous
712      box type. */
713 #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000
714   /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of
715      an SVG text frame. */
716 #define FCDATA_IS_SVG_TEXT 0x80000
717   /**
718    * When FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, this bit says
719    * if we should create a grid/flex/columnset container instead of
720    * a block wrapper when the styles says so.
721    */
722 #define FCDATA_ALLOW_GRID_FLEX_COLUMNSET 0x200000
723   /**
724    * Whether the kids of this FrameConstructionData should be flagged as having
725    * a wrapper anon box parent.  This should only be set if
726    * FCDATA_USE_CHILD_ITEMS is set.
727    */
728 #define FCDATA_IS_WRAPPER_ANON_BOX 0x400000
729 
730   /* Structure representing information about how a frame should be
731      constructed.  */
732   struct FrameConstructionData {
733     // Flag bits that can modify the way the construction happens
734     uint32_t mBits;
735     // We have exactly one of three types of functions, so use a union for
736     // better cache locality for the ones that aren't pointer-to-member.  That
737     // one needs to be separate, because we can't cast between it and the
738     // others and hence wouldn't be able to initialize the union without a
739     // constructor and all the resulting generated code.  See documentation
740     // above for FrameCreationFunc, FrameConstructionDataGetter, and
741     // FrameFullConstructor to see what the functions would do.
742     union Func {
743       FrameCreationFunc mCreationFunc;
744       FrameConstructionDataGetter mDataGetter;
745     } mFunc;
746     FrameFullConstructor mFullConstructor;
747     // For cases when FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, the
748     // anonymous box type to use for that wrapper.
749     nsICSSAnonBoxPseudo* const* const mAnonBoxPseudo;
750   };
751 
752   /* Structure representing a mapping of an atom to a FrameConstructionData.
753      This can be used with non-static atoms, assuming that the nsAtom* is
754      stored somewhere that this struct can point to (that is, a static
755      nsAtom*) and that it's allocated before the struct is ever used. */
756   struct FrameConstructionDataByTag {
757     // Pointer to nsStaticAtom* is used because we want to initialize this
758     // statically, so before our atom tables are set up.
759     const nsStaticAtom* const* const mTag;
760     const FrameConstructionData mData;
761   };
762 
763   /* Structure representing a mapping of an integer to a
764      FrameConstructionData. There are no magic integer values here. */
765   struct FrameConstructionDataByInt {
766     /* Could be used for display or whatever else */
767     const int32_t mInt;
768     const FrameConstructionData mData;
769   };
770 
771   struct FrameConstructionDataByDisplay {
772 #ifdef DEBUG
773     const mozilla::StyleDisplay mDisplay;
774 #endif
775     const FrameConstructionData mData;
776   };
777 
778 #ifdef DEBUG
779 #define FCDATA_FOR_DISPLAY(_display, _fcdata) \
780   { _display, _fcdata }
781 #else
782 #define FCDATA_FOR_DISPLAY(_display, _fcdata) \
783   { _fcdata }
784 #endif
785 
786   /* Structure that has a FrameConstructionData and style context pseudo-type
787      for a table pseudo-frame */
788   struct PseudoParentData {
789     const FrameConstructionData mFCData;
790     nsICSSAnonBoxPseudo* const* const mPseudoType;
791   };
792   /* Array of such structures that we use to properly construct table
793      pseudo-frames as needed */
794   static const PseudoParentData sPseudoParentData[eParentTypeCount];
795 
796   /* A function that takes an integer, content, style context, and array of
797      FrameConstructionDataByInts and finds the appropriate frame construction
798      data to use and returns it.  This can return null if none of the integers
799      match or if the matching integer has a FrameConstructionDataGetter that
800      returns null. */
801   static const FrameConstructionData* FindDataByInt(
802       int32_t aInt, Element* aElement, nsStyleContext* aStyleContext,
803       const FrameConstructionDataByInt* aDataPtr, uint32_t aDataLength);
804 
805   /**
806    * A function that takes a tag, content, style context, and array of
807    * FrameConstructionDataByTags and finds the appropriate frame construction
808    * data to use and returns it.
809    *
810    * This can return null if none of the tags match or if the matching tag has a
811    * FrameConstructionDataGetter that returns null. In the case that the tags
812    * actually match, aTagFound will be true, even if the return value is null.
813    */
814   static const FrameConstructionData* FindDataByTag(
815       nsAtom* aTag, Element* aElement, nsStyleContext* aStyleContext,
816       const FrameConstructionDataByTag* aDataPtr, uint32_t aDataLength,
817       bool* aTagFound = nullptr);
818 
819   /* A class representing a list of FrameConstructionItems.  Instances of this
820      class are only created as AutoFrameConstructionItemList, or as a member
821      of FrameConstructionItem. */
822   class FrameConstructionItemList {
823    public:
Reset(nsCSSFrameConstructor * aFCtor)824     void Reset(nsCSSFrameConstructor* aFCtor) {
825       Destroy(aFCtor);
826       this->~FrameConstructionItemList();
827       new (this) FrameConstructionItemList();
828     }
829 
SetLineBoundaryAtStart(bool aBoundary)830     void SetLineBoundaryAtStart(bool aBoundary) {
831       mLineBoundaryAtStart = aBoundary;
832     }
SetLineBoundaryAtEnd(bool aBoundary)833     void SetLineBoundaryAtEnd(bool aBoundary) {
834       mLineBoundaryAtEnd = aBoundary;
835     }
SetParentHasNoXBLChildren(bool aHasNoXBLChildren)836     void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) {
837       mParentHasNoXBLChildren = aHasNoXBLChildren;
838     }
SetTriedConstructingFrames()839     void SetTriedConstructingFrames() { mTriedConstructingFrames = true; }
HasLineBoundaryAtStart()840     bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
HasLineBoundaryAtEnd()841     bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
ParentHasNoXBLChildren()842     bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; }
IsEmpty()843     bool IsEmpty() const { return mItems.isEmpty(); }
AnyItemsNeedBlockParent()844     bool AnyItemsNeedBlockParent() const { return mLineParticipantCount != 0; }
AreAllItemsInline()845     bool AreAllItemsInline() const { return mInlineCount == mItemCount; }
AreAllItemsBlock()846     bool AreAllItemsBlock() const { return mBlockCount == mItemCount; }
AllWantParentType(ParentType aDesiredParentType)847     bool AllWantParentType(ParentType aDesiredParentType) const {
848       return mDesiredParentCounts[aDesiredParentType] == mItemCount;
849     }
850 
851     // aSuppressWhiteSpaceOptimizations is true if optimizations that
852     // skip constructing whitespace frames for this item or items
853     // around it cannot be performed.
854     // Also, the return value is always non-null, thanks to infallible 'new'.
AppendItem(nsCSSFrameConstructor * aFCtor,const FrameConstructionData * aFCData,nsIContent * aContent,nsAtom * aTag,int32_t aNameSpaceID,PendingBinding * aPendingBinding,already_AddRefed<nsStyleContext> && aStyleContext,bool aSuppressWhiteSpaceOptimizations,nsTArray<nsIAnonymousContentCreator::ContentInfo> * aAnonChildren)855     FrameConstructionItem* AppendItem(
856         nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
857         nsIContent* aContent, nsAtom* aTag, int32_t aNameSpaceID,
858         PendingBinding* aPendingBinding,
859         already_AddRefed<nsStyleContext>&& aStyleContext,
860         bool aSuppressWhiteSpaceOptimizations,
861         nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren) {
862       FrameConstructionItem* item = new (aFCtor) FrameConstructionItem(
863           aFCData, aContent, aTag, aNameSpaceID, aPendingBinding, aStyleContext,
864           aSuppressWhiteSpaceOptimizations, aAnonChildren);
865       mItems.insertBack(item);
866       ++mItemCount;
867       ++mDesiredParentCounts[item->DesiredParentType()];
868       return item;
869     }
870 
871     // Arguments are the same as AppendItem().
PrependItem(nsCSSFrameConstructor * aFCtor,const FrameConstructionData * aFCData,nsIContent * aContent,nsAtom * aTag,int32_t aNameSpaceID,PendingBinding * aPendingBinding,already_AddRefed<nsStyleContext> && aStyleContext,bool aSuppressWhiteSpaceOptimizations,nsTArray<nsIAnonymousContentCreator::ContentInfo> * aAnonChildren)872     FrameConstructionItem* PrependItem(
873         nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
874         nsIContent* aContent, nsAtom* aTag, int32_t aNameSpaceID,
875         PendingBinding* aPendingBinding,
876         already_AddRefed<nsStyleContext>&& aStyleContext,
877         bool aSuppressWhiteSpaceOptimizations,
878         nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren) {
879       FrameConstructionItem* item = new (aFCtor) FrameConstructionItem(
880           aFCData, aContent, aTag, aNameSpaceID, aPendingBinding, aStyleContext,
881           aSuppressWhiteSpaceOptimizations, aAnonChildren);
882       mItems.insertFront(item);
883       ++mItemCount;
884       ++mDesiredParentCounts[item->DesiredParentType()];
885       return item;
886     }
887 
AppendUndisplayedItem(nsIContent * aContent,nsStyleContext * aStyleContext)888     void AppendUndisplayedItem(nsIContent* aContent,
889                                nsStyleContext* aStyleContext) {
890       mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aStyleContext));
891     }
892 
InlineItemAdded()893     void InlineItemAdded() { ++mInlineCount; }
BlockItemAdded()894     void BlockItemAdded() { ++mBlockCount; }
LineParticipantItemAdded()895     void LineParticipantItemAdded() { ++mLineParticipantCount; }
896 
897     class Iterator {
898      public:
Iterator(FrameConstructionItemList & aList)899       explicit Iterator(FrameConstructionItemList& aList)
900           : mCurrent(aList.mItems.getFirst()), mList(aList) {}
Iterator(const Iterator & aOther)901       Iterator(const Iterator& aOther)
902           : mCurrent(aOther.mCurrent), mList(aOther.mList) {}
903 
904       bool operator==(const Iterator& aOther) const {
905         MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
906         return mCurrent == aOther.mCurrent;
907       }
908       bool operator!=(const Iterator& aOther) const {
909         return !(*this == aOther);
910       }
911       Iterator& operator=(const Iterator& aOther) {
912         MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
913         mCurrent = aOther.mCurrent;
914         return *this;
915       }
916 
List()917       FrameConstructionItemList* List() { return &mList; }
918 
item()919       FrameConstructionItem& item() {
920         MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
921         return *mCurrent;
922       }
923 
item()924       const FrameConstructionItem& item() const {
925         MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
926         return *mCurrent;
927       }
928 
IsDone()929       bool IsDone() const { return mCurrent == nullptr; }
AtStart()930       bool AtStart() const { return mCurrent == mList.mItems.getFirst(); }
Next()931       void Next() {
932         NS_ASSERTION(!IsDone(), "Should have checked IsDone()!");
933         mCurrent = mCurrent->getNext();
934       }
Prev()935       void Prev() {
936         NS_ASSERTION(!AtStart(), "Should have checked AtStart()!");
937         mCurrent = mCurrent ? mCurrent->getPrevious() : mList.mItems.getLast();
938       }
SetToEnd()939       void SetToEnd() { mCurrent = nullptr; }
940 
941       // Skip over all items that want the given parent type. Return whether
942       // the iterator is done after doing that.  The iterator must not be done
943       // when this is called.
944       inline bool SkipItemsWantingParentType(ParentType aParentType);
945 
946       // Skip over all items that want a parent type different from the given
947       // one.  Return whether the iterator is done after doing that.  The
948       // iterator must not be done when this is called.
949       inline bool SkipItemsNotWantingParentType(ParentType aParentType);
950 
951       // Skip over non-replaced inline frames and positioned frames.
952       // Return whether the iterator is done after doing that.
953       // The iterator must not be done when this is called.
954       inline bool SkipItemsThatNeedAnonFlexOrGridItem(
955           const nsFrameConstructorState& aState, bool aIsWebkitBox);
956 
957       // Skip to the first frame that is a non-replaced inline or is
958       // positioned.  Return whether the iterator is done after doing that.
959       // The iterator must not be done when this is called.
960       inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
961           const nsFrameConstructorState& aState, bool aIsWebkitBox);
962 
963       // Skip over all items that do not want a ruby parent.  Return whether
964       // the iterator is done after doing that.  The iterator must not be done
965       // when this is called.
966       inline bool SkipItemsNotWantingRubyParent();
967 
968       // Skip over whitespace.  Return whether the iterator is done after doing
969       // that.  The iterator must not be done, and must be pointing to a
970       // whitespace item when this is called.
971       inline bool SkipWhitespace(nsFrameConstructorState& aState);
972 
973       // Remove the item pointed to by this iterator from its current list and
974       // Append it to aTargetList.  This iterator is advanced to point to the
975       // next item in its list.  aIter must not be done.  aTargetList must not
976       // be the list this iterator is iterating over..
977       void AppendItemToList(FrameConstructionItemList& aTargetList);
978 
979       // As above, but moves all items starting with this iterator until we
980       // get to aEnd; the item pointed to by aEnd is not stolen.  This method
981       // might have optimizations over just looping and doing StealItem for
982       // some special cases.  After this method returns, this iterator will
983       // point to the item aEnd points to now; aEnd is not modified.
984       // aTargetList must not be the list this iterator is iterating over.
985       void AppendItemsToList(nsCSSFrameConstructor* aFCtor,
986                              const Iterator& aEnd,
987                              FrameConstructionItemList& aTargetList);
988 
989       // Insert aItem in this iterator's list right before the item pointed to
990       // by this iterator.  After the insertion, this iterator will continue to
991       // point to the item it now points to (the one just after the
992       // newly-inserted item).  This iterator is allowed to be done; in that
993       // case this call just appends the given item to the list.
994       void InsertItem(FrameConstructionItem* aItem);
995 
996       // Delete the items between this iterator and aEnd, including the item
997       // this iterator currently points to but not including the item pointed
998       // to by aEnd.  When this returns, this iterator will point to the same
999       // item as aEnd.  This iterator must not equal aEnd when this method is
1000       // called.
1001       void DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd);
1002 
1003      private:
1004       FrameConstructionItem* mCurrent;
1005       FrameConstructionItemList& mList;
1006     };
1007 
1008    protected:
FrameConstructionItemList()1009     FrameConstructionItemList()
1010         : mInlineCount(0),
1011           mBlockCount(0),
1012           mLineParticipantCount(0),
1013           mItemCount(0),
1014           mLineBoundaryAtStart(false),
1015           mLineBoundaryAtEnd(false),
1016           mParentHasNoXBLChildren(false),
1017           mTriedConstructingFrames(false) {
1018       MOZ_COUNT_CTOR(FrameConstructionItemList);
1019       memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
1020     }
1021 
Destroy(nsCSSFrameConstructor * aFCtor)1022     void Destroy(nsCSSFrameConstructor* aFCtor) {
1023       while (FrameConstructionItem* item = mItems.popFirst()) {
1024         item->Delete(aFCtor);
1025       }
1026 
1027       // Create the undisplayed entries for our mUndisplayedItems, if any, but
1028       // only if we have tried constructing frames for this item list.  If we
1029       // haven't, then we're just throwing it away and will probably try again.
1030       if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) {
1031         for (uint32_t i = 0; i < mUndisplayedItems.Length(); ++i) {
1032           UndisplayedItem& item = mUndisplayedItems[i];
1033           aFCtor->RegisterDisplayNoneStyleFor(item.mContent,
1034                                               item.mStyleContext);
1035         }
1036       }
1037     }
1038 
1039     // Prevent stack instances (except as AutoFrameConstructionItemList).
1040     friend struct FrameConstructionItem;
~FrameConstructionItemList()1041     ~FrameConstructionItemList() {
1042       MOZ_COUNT_DTOR(FrameConstructionItemList);
1043       MOZ_ASSERT(mItems.isEmpty(), "leaking");
1044     }
1045 
1046    private:
1047     // Not allocated from the heap!
1048     void* operator new(size_t) = delete;
1049     void* operator new[](size_t) = delete;
1050 #ifdef _MSC_VER /* Visual Studio */
delete(void *)1051     void operator delete(void*) { MOZ_CRASH("FrameConstructionItemList::del"); }
1052 #else
1053     void operator delete(void*) = delete;
1054 #endif
1055     void operator delete[](void*) = delete;
1056     // Placement new is used by Reset().
new(size_t,void * aPtr)1057     void* operator new(size_t, void* aPtr) { return aPtr; }
1058 
1059     struct UndisplayedItem {
UndisplayedItemUndisplayedItem1060       UndisplayedItem(nsIContent* aContent, nsStyleContext* aStyleContext)
1061           : mContent(aContent), mStyleContext(aStyleContext) {}
1062 
1063       nsIContent* const mContent;
1064       RefPtr<nsStyleContext> mStyleContext;
1065     };
1066 
1067     // Adjust our various counts for aItem being added or removed.  aDelta
1068     // should be either +1 or -1 depending on which is happening.
1069     void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta);
1070 
1071     nsTArray<UndisplayedItem> mUndisplayedItems;
1072     mozilla::LinkedList<FrameConstructionItem> mItems;
1073     uint32_t mInlineCount;
1074     uint32_t mBlockCount;
1075     uint32_t mLineParticipantCount;
1076     uint32_t mItemCount;
1077     uint32_t mDesiredParentCounts[eParentTypeCount];
1078     // True if there is guaranteed to be a line boundary before the
1079     // frames created by these items
1080     bool mLineBoundaryAtStart;
1081     // True if there is guaranteed to be a line boundary after the
1082     // frames created by these items
1083     bool mLineBoundaryAtEnd;
1084     // True if the parent is guaranteed to have no XBL anonymous children
1085     bool mParentHasNoXBLChildren;
1086     // True if we have tried constructing frames from this list
1087     bool mTriedConstructingFrames;
1088   };
1089 
1090   /* A struct representing a list of FrameConstructionItems on the stack. */
1091   struct MOZ_RAII AutoFrameConstructionItemList final
1092       : public FrameConstructionItemList {
1093     template <typename... Args>
AutoFrameConstructionItemListfinal1094     explicit AutoFrameConstructionItemList(nsCSSFrameConstructor* aFCtor,
1095                                            Args&&... args)
1096         : FrameConstructionItemList(std::forward<Args>(args)...),
1097           mFCtor(aFCtor) {
1098       MOZ_ASSERT(mFCtor);
1099     }
~AutoFrameConstructionItemListfinal1100     ~AutoFrameConstructionItemList() { Destroy(mFCtor); }
1101 
1102    private:
1103     nsCSSFrameConstructor* const mFCtor;
1104   };
1105 
1106   typedef FrameConstructionItemList::Iterator FCItemIterator;
1107 
1108   /* A struct representing an item for which frames might need to be
1109    * constructed.  This contains all the information needed to construct the
1110    * frame other than the parent frame and whatever would be stored in the
1111    * frame constructor state.  You probably want to use
1112    * AutoFrameConstructionItem instead of this struct. */
1113   struct FrameConstructionItem final
1114       : public mozilla::LinkedListElement<FrameConstructionItem> {
FrameConstructionItemfinal1115     FrameConstructionItem(
1116         const FrameConstructionData* aFCData, nsIContent* aContent,
1117         nsAtom* aTag, int32_t aNameSpaceID, PendingBinding* aPendingBinding,
1118         already_AddRefed<nsStyleContext>& aStyleContext,
1119         bool aSuppressWhiteSpaceOptimizations,
1120         nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren)
1121         : mFCData(aFCData),
1122           mContent(aContent),
1123           mTag(aTag),
1124           mPendingBinding(aPendingBinding),
1125           mStyleContext(aStyleContext),
1126           mNameSpaceID(aNameSpaceID),
1127           mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations),
1128           mIsText(false),
1129           mIsGeneratedContent(false),
1130           mIsAnonymousContentCreatorContent(false),
1131           mIsRootPopupgroup(false),
1132           mIsAllInline(false),
1133           mIsBlock(false),
1134           mHasInlineEnds(false),
1135           mIsPopup(false),
1136           mIsLineParticipant(false),
1137           mIsForSVGAElement(false) {
1138       MOZ_COUNT_CTOR(FrameConstructionItem);
1139       if (aAnonChildren) {
1140         NS_ASSERTION(!(mFCData->mBits & FCDATA_FUNC_IS_FULL_CTOR) ||
1141                          mFCData->mFullConstructor ==
1142                              &nsCSSFrameConstructor::ConstructInline,
1143                      "This is going to fail");
1144         NS_ASSERTION(!(mFCData->mBits & FCDATA_USE_CHILD_ITEMS),
1145                      "nsIAnonymousContentCreator::CreateAnonymousContent "
1146                      "implementations should not output a list where the "
1147                      "items have children in this case");
1148         mAnonChildren.SwapElements(*aAnonChildren);
1149       }
1150     }
1151 
newfinal1152     void* operator new(size_t, nsCSSFrameConstructor* aFCtor) {
1153       return aFCtor->AllocateFCItem();
1154     }
1155 
Deletefinal1156     void Delete(nsCSSFrameConstructor* aFCtor) {
1157       mChildItems.Destroy(aFCtor);
1158       if (mIsGeneratedContent) {
1159         mContent->UnbindFromTree();
1160         NS_RELEASE(mContent);
1161       }
1162       this->~FrameConstructionItem();
1163       aFCtor->FreeFCItem(this);
1164     }
1165 
DesiredParentTypefinal1166     ParentType DesiredParentType() {
1167       return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
1168     }
1169 
1170     // Indicates whether (when in a flex or grid container) this item needs
1171     // to be wrapped in an anonymous block.  (Note that we implement
1172     // -webkit-box/-webkit-inline-box using our standard flexbox frame class,
1173     // but we use different rules for what gets wrapped. The aIsWebkitBox
1174     // parameter here tells us whether to use those different rules.)
1175     bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
1176                                  bool aIsWebkitBox);
1177 
1178     // Don't call this unless the frametree really depends on the answer!
1179     // Especially so for generated content, where we don't want to reframe
1180     // things.
1181     bool IsWhitespace(nsFrameConstructorState& aState) const;
1182 
IsLineBoundaryfinal1183     bool IsLineBoundary() const {
1184       return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK);
1185     }
1186 
1187     // Child frame construction items.
1188     FrameConstructionItemList mChildItems;
1189 
1190     // ContentInfo list for children that have yet to have
1191     // FrameConstructionItem objects created for them. This exists because
1192     // AddFrameConstructionItemsInternal needs a valid frame, but in the case
1193     // that nsIAnonymousContentCreator::CreateAnonymousContent returns items
1194     // that have their own children (so we have a tree of ContentInfo objects
1195     // rather than a flat list) we don't yet have a frame to provide to
1196     // AddFrameConstructionItemsInternal in order to create the items for the
1197     // grandchildren. That prevents FrameConstructionItems from being created
1198     // for these grandchildren (and any descendants that they may have),
1199     // otherwise they could have been added to the mChildItems member of their
1200     // parent FrameConstructionItem. As it is, the grandchildren ContentInfo
1201     // list has to be stored in this mAnonChildren member in order to delay
1202     // construction of the FrameConstructionItems for the grandchildren until
1203     // a frame has been created for their parent item.
1204     nsTArray<nsIAnonymousContentCreator::ContentInfo> mAnonChildren;
1205 
1206     // The FrameConstructionData to use.
1207     const FrameConstructionData* mFCData;
1208     // The nsIContent node to use when initializing the new frame.
1209     nsIContent* mContent;
1210     // The XBL-resolved tag name to use for frame construction.
1211     nsAtom* mTag;
1212     // The PendingBinding for this frame construction item, if any.  May be
1213     // null.  We maintain a list of PendingBindings in the frame construction
1214     // state in the order in which AddToAttachedQueue should be called on them:
1215     // depth-first, post-order traversal order.  Since we actually traverse the
1216     // DOM in a mix of breadth-first and depth-first, it is the responsibility
1217     // of whoever constructs FrameConstructionItem kids of a given
1218     // FrameConstructionItem to push its mPendingBinding as the current
1219     // insertion point before doing so and pop it afterward.
1220     PendingBinding* mPendingBinding;
1221     // The style context to use for creating the new frame.
1222     RefPtr<nsStyleContext> mStyleContext;
1223     // The XBL-resolved namespace to use for frame construction.
1224     int32_t mNameSpaceID;
1225     // Whether optimizations to skip constructing textframes around
1226     // this content need to be suppressed.
1227     bool mSuppressWhiteSpaceOptimizations : 1;
1228     // Whether this is a text content item.
1229     bool mIsText : 1;
1230     // Whether this is a generated content container.
1231     // If it is, mContent is a strong pointer.
1232     bool mIsGeneratedContent : 1;
1233     // Whether this is an item for nsIAnonymousContentCreator content.
1234     bool mIsAnonymousContentCreatorContent : 1;
1235     // Whether this is an item for the root popupgroup.
1236     bool mIsRootPopupgroup : 1;
1237     // Whether construction from this item will create only frames that are
1238     // IsInlineOutside() in the principal child list.  This is not precise, but
1239     // conservative: if true the frames will really be inline, whereas if false
1240     // they might still all be inline.
1241     bool mIsAllInline : 1;
1242     // Whether construction from this item will create only frames that are
1243     // IsBlockOutside() in the principal child list.  This is not precise, but
1244     // conservative: if true the frames will really be blocks, whereas if false
1245     // they might still be blocks (and in particular, out-of-flows that didn't
1246     // find a containing block).
1247     bool mIsBlock : 1;
1248     // Whether construction from this item will give leading and trailing
1249     // inline frames.  This is equal to mIsAllInline, except for inline frame
1250     // items, where it's always true, whereas mIsAllInline might be false due
1251     // to {ib} splits.
1252     bool mHasInlineEnds : 1;
1253     // Whether construction from this item will create a popup that needs to
1254     // go into the global popup items.
1255     bool mIsPopup : 1;
1256     // Whether this item should be treated as a line participant
1257     bool mIsLineParticipant : 1;
1258     // Whether this item is for an SVG <a> element
1259     bool mIsForSVGAElement : 1;
1260 
1261    private:
1262     // Not allocated from the general heap - instead, use the new/Delete APIs
1263     // that take a nsCSSFrameConstructor* (which manages our arena allocation).
1264     void* operator new(size_t) = delete;
1265     void* operator new[](size_t) = delete;
1266 #ifdef _MSC_VER /* Visual Studio */
deletefinal1267     void operator delete(void*) { MOZ_CRASH("FrameConstructionItem::delete"); }
1268 #else
1269     void operator delete(void*) = delete;
1270 #endif
1271     void operator delete[](void*) = delete;
1272     FrameConstructionItem(const FrameConstructionItem& aOther) =
1273         delete; /* not implemented */
1274     // Not allocated from the stack!
~FrameConstructionItemfinal1275     ~FrameConstructionItem() {
1276       MOZ_COUNT_DTOR(FrameConstructionItem);
1277       MOZ_ASSERT(mChildItems.IsEmpty(), "leaking");
1278     }
1279   };
1280 
1281   /**
1282    * Convenience struct to assist in managing a temporary FrameConstructionItem
1283    * using a local variable. Castable to FrameConstructionItem so that it can
1284    * be passed transparently to functions that expect that type.
1285    * (This struct exists because FrameConstructionItem is arena-allocated, and
1286    * it's nice to abstract away its allocation/deallocation.)
1287    */
1288   struct MOZ_RAII AutoFrameConstructionItem final {
1289     template <typename... Args>
AutoFrameConstructionItemfinal1290     explicit AutoFrameConstructionItem(nsCSSFrameConstructor* aFCtor,
1291                                        Args&&... args)
1292         : mFCtor(aFCtor),
1293           mItem(new (aFCtor)
1294                     FrameConstructionItem(std::forward<Args>(args)...)) {
1295       MOZ_ASSERT(mFCtor);
1296     }
~AutoFrameConstructionItemfinal1297     ~AutoFrameConstructionItem() { mItem->Delete(mFCtor); }
1298     operator FrameConstructionItem&() { return *mItem; }
1299 
1300    private:
1301     nsCSSFrameConstructor* const mFCtor;
1302     FrameConstructionItem* const mItem;
1303   };
1304 
1305   /**
1306    * Function to create the anonymous flex or grid items that we need.
1307    * If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
1308    * this method is a NOP.
1309    * @param aItems the child frame construction items before pseudo creation
1310    * @param aParentFrame the parent frame
1311    */
1312   void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
1313                                        FrameConstructionItemList& aItems,
1314                                        nsIFrame* aParentFrame);
1315 
1316   enum RubyWhitespaceType {
1317     eRubyNotWhitespace,
1318     eRubyInterLevelWhitespace,
1319     // Includes inter-base and inter-annotation whitespace
1320     eRubyInterLeafWhitespace,
1321     eRubyInterSegmentWhitespace
1322   };
1323 
1324   /**
1325    * Function to compute the whitespace type according to the display
1326    * values of the previous and the next elements.
1327    */
1328   static inline RubyWhitespaceType ComputeRubyWhitespaceType(
1329       mozilla::StyleDisplay aPrevDisplay, mozilla::StyleDisplay aNextDisplay);
1330 
1331   /**
1332    * Function to interpret the type of whitespace between
1333    * |aStartIter| and |aEndIter|.
1334    */
1335   static inline RubyWhitespaceType InterpretRubyWhitespace(
1336       nsFrameConstructorState& aState, const FCItemIterator& aStartIter,
1337       const FCItemIterator& aEndIter);
1338 
1339   /**
1340    * Function to wrap consecutive misparented inline content into
1341    * a ruby base box or a ruby text box.
1342    */
1343   void WrapItemsInPseudoRubyLeafBox(FCItemIterator& aIter,
1344                                     nsStyleContext* aParentStyle,
1345                                     nsIContent* aParentContent);
1346 
1347   /**
1348    * Function to wrap consecutive misparented items
1349    * into a ruby level container.
1350    */
1351   inline void WrapItemsInPseudoRubyLevelContainer(
1352       nsFrameConstructorState& aState, FCItemIterator& aIter,
1353       nsStyleContext* aParentStyle, nsIContent* aParentContent);
1354 
1355   /**
1356    * Function to trim leading and trailing whitespaces.
1357    */
1358   inline void TrimLeadingAndTrailingWhitespaces(
1359       nsFrameConstructorState& aState, FrameConstructionItemList& aItems);
1360 
1361   /**
1362    * Function to create internal ruby boxes.
1363    */
1364   inline void CreateNeededPseudoInternalRubyBoxes(
1365       nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
1366       nsIFrame* aParentFrame);
1367 
1368   /**
1369    * Function to create the pseudo intermediate containers we need.
1370    * @param aItems the child frame construction items before pseudo creation
1371    * @param aParentFrame the parent frame we're creating pseudos for
1372    */
1373   inline void CreateNeededPseudoContainers(nsFrameConstructorState& aState,
1374                                            FrameConstructionItemList& aItems,
1375                                            nsIFrame* aParentFrame);
1376 
1377   /**
1378    * Function to wrap consecutive items into a pseudo parent.
1379    */
1380   inline void WrapItemsInPseudoParent(nsIContent* aParentContent,
1381                                       nsStyleContext* aParentStyle,
1382                                       ParentType aWrapperType,
1383                                       FCItemIterator& aIter,
1384                                       const FCItemIterator& aEndIter);
1385 
1386   /**
1387    * Function to create the pseudo siblings we need.
1388    */
1389   inline void CreateNeededPseudoSiblings(nsFrameConstructorState& aState,
1390                                          FrameConstructionItemList& aItems,
1391                                          nsIFrame* aParentFrame);
1392 
1393   /**
1394    * Function to adjust aParentFrame to deal with captions.
1395    * @param aParentFrame the frame we think should be the parent.  This will be
1396    *        adjusted to point to the right parent frame.
1397    * @param aFCData the FrameConstructionData that would be used for frame
1398    *        construction.
1399    * @param aStyleContext the style context for aChildContent
1400    */
1401   // XXXbz this function should really go away once we rework pseudo-frame
1402   // handling to be better. This should simply be part of the job of
1403   // GetGeometricParent, and stuff like the frameitems and parent frame should
1404   // be kept track of in the state...
1405   void AdjustParentFrame(nsContainerFrame** aParentFrame,
1406                          const FrameConstructionData* aFCData,
1407                          nsStyleContext* aStyleContext);
1408 
1409   // END TABLE SECTION
1410 
1411  protected:
1412   static nsIFrame* CreatePlaceholderFrameFor(nsIPresShell* aPresShell,
1413                                              nsIContent* aContent,
1414                                              nsIFrame* aFrame,
1415                                              nsContainerFrame* aParentFrame,
1416                                              nsIFrame* aPrevInFlow,
1417                                              nsFrameState aTypeBit);
1418 
1419   static nsIFrame* CreateBackdropFrameFor(nsIPresShell* aPresShell,
1420                                           nsIContent* aContent,
1421                                           nsIFrame* aFrame,
1422                                           nsContainerFrame* aParentFrame);
1423 
1424  private:
1425   // ConstructSelectFrame puts the new frame in aFrameItems and
1426   // handles the kids of the select.
1427   nsIFrame* ConstructSelectFrame(nsFrameConstructorState& aState,
1428                                  FrameConstructionItem& aItem,
1429                                  nsContainerFrame* aParentFrame,
1430                                  const nsStyleDisplay* aStyleDisplay,
1431                                  nsFrameItems& aFrameItems);
1432 
1433   // ConstructFieldSetFrame puts the new frame in aFrameItems and
1434   // handles the kids of the fieldset
1435   nsIFrame* ConstructFieldSetFrame(nsFrameConstructorState& aState,
1436                                    FrameConstructionItem& aItem,
1437                                    nsContainerFrame* aParentFrame,
1438                                    const nsStyleDisplay* aStyleDisplay,
1439                                    nsFrameItems& aFrameItems);
1440 
1441   // ConstructDetailsFrame puts the new frame in aFrameItems and
1442   // handles the kids of the details.
1443   nsIFrame* ConstructDetailsFrame(nsFrameConstructorState& aState,
1444                                   FrameConstructionItem& aItem,
1445                                   nsContainerFrame* aParentFrame,
1446                                   const nsStyleDisplay* aStyleDisplay,
1447                                   nsFrameItems& aFrameItems);
1448 
1449   // aParentFrame might be null.  If it is, that means it was an
1450   // inline frame.
1451   static const FrameConstructionData* FindTextData(nsIFrame* aParentFrame);
1452 
1453   void ConstructTextFrame(const FrameConstructionData* aData,
1454                           nsFrameConstructorState& aState, nsIContent* aContent,
1455                           nsContainerFrame* aParentFrame,
1456                           nsStyleContext* aStyleContext,
1457                           nsFrameItems& aFrameItems);
1458 
1459   // If aPossibleTextContent is a text node and doesn't have a frame, append a
1460   // frame construction item for it to aItems.
1461   void AddTextItemIfNeeded(nsFrameConstructorState& aState,
1462                            const InsertionPoint& aInsertion,
1463                            nsIContent* aPossibleTextContent,
1464                            FrameConstructionItemList& aItems);
1465 
1466   // If aParentContent's child aContent is a text node and
1467   // doesn't have a frame, try to create a frame for it.
1468   void ReframeTextIfNeeded(nsIContent* aParentContent, nsIContent* aContent);
1469 
1470   void AddPageBreakItem(nsIContent* aContent,
1471                         FrameConstructionItemList& aItems);
1472 
1473   // Function to find FrameConstructionData for aElement.  Will return
1474   // null if aElement is not HTML.
1475   // aParentFrame might be null.  If it is, that means it was an
1476   // inline frame.
1477   static const FrameConstructionData* FindHTMLData(
1478       Element* aContent, nsAtom* aTag, int32_t aNameSpaceID,
1479       nsIFrame* aParentFrame, nsStyleContext* aStyleContext);
1480   // HTML data-finding helper functions
1481   static const FrameConstructionData* FindImgData(
1482       Element* aElement, nsStyleContext* aStyleContext);
1483   static const FrameConstructionData* FindImgControlData(
1484       Element* aElement, nsStyleContext* aStyleContext);
1485   static const FrameConstructionData* FindInputData(
1486       Element* aElement, nsStyleContext* aStyleContext);
1487   static const FrameConstructionData* FindObjectData(
1488       Element* aElement, nsStyleContext* aStyleContext);
1489   static const FrameConstructionData* FindCanvasData(
1490       Element* aElement, nsStyleContext* aStyleContext);
1491 
1492   /* Construct a frame from the given FrameConstructionItem.  This function
1493      will handle adding the frame to frame lists, processing children, setting
1494      the frame as the primary frame for the item's content, and so forth.
1495 
1496      @param aItem the FrameConstructionItem to use.
1497      @param aState the frame construction state to use.
1498      @param aParentFrame the frame to set as the parent of the
1499                          newly-constructed frame.
1500      @param aFrameItems the frame list to add the new frame (or its
1501                         placeholder) to.
1502   */
1503   void ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
1504                                       nsFrameConstructorState& aState,
1505                                       nsContainerFrame* aParentFrame,
1506                                       nsFrameItems& aFrameItems);
1507 
1508   // possible flags for AddFrameConstructionItemInternal's aFlags argument
1509   /* Allow xbl:base to affect the tag/namespace used. */
1510 #define ITEM_ALLOW_XBL_BASE 0x1
1511   /* Allow page-break before and after items to be created if the
1512      style asks for them. */
1513 #define ITEM_ALLOW_PAGE_BREAK 0x2
1514   /* The item is a generated content item. */
1515 #define ITEM_IS_GENERATED_CONTENT 0x4
1516   /* The item is within an SVG text block frame. */
1517 #define ITEM_IS_WITHIN_SVG_TEXT 0x8
1518   /* The item allows items to be created for SVG <textPath> children. */
1519 #define ITEM_ALLOWS_TEXT_PATH_CHILD 0x10
1520   /* The item is content created by an nsIAnonymousContentCreator frame */
1521 #define ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT 0x20
1522   // The guts of AddFrameConstructionItems
1523   // aParentFrame might be null.  If it is, that means it was an
1524   // inline frame.
1525   void AddFrameConstructionItemsInternal(
1526       nsFrameConstructorState& aState, nsIContent* aContent,
1527       nsContainerFrame* aParentFrame, nsAtom* aTag, int32_t aNameSpaceID,
1528       bool aSuppressWhiteSpaceOptimizations, nsStyleContext* aStyleContext,
1529       uint32_t aFlags,
1530       nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
1531       FrameConstructionItemList& aItems);
1532 
1533   /**
1534    * Construct frames for the given item list and parent frame, and put the
1535    * resulting frames in aFrameItems.
1536    */
1537   void ConstructFramesFromItemList(nsFrameConstructorState& aState,
1538                                    FrameConstructionItemList& aItems,
1539                                    nsContainerFrame* aParentFrame,
1540                                    bool aParentIsWrapperAnonBox,
1541                                    nsFrameItems& aFrameItems);
1542   void ConstructFramesFromItem(nsFrameConstructorState& aState,
1543                                FCItemIterator& aItem,
1544                                nsContainerFrame* aParentFrame,
1545                                nsFrameItems& aFrameItems);
1546   static bool AtLineBoundary(FCItemIterator& aIter);
1547 
1548   nsresult GetAnonymousContent(
1549       nsIContent* aParent, nsIFrame* aParentFrame,
1550       nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonContent);
1551 
1552   // MathML Mod - RBS
1553   /**
1554    * Takes the frames in aBlockItems and wraps them in a new anonymous block
1555    * frame whose content is aContent and whose parent will be aParentFrame.
1556    * The anonymous block is added to aNewItems and aBlockItems is cleared.
1557    */
1558   void FlushAccumulatedBlock(nsFrameConstructorState& aState,
1559                              nsIContent* aContent,
1560                              nsContainerFrame* aParentFrame,
1561                              nsFrameItems& aBlockItems,
1562                              nsFrameItems& aNewItems);
1563 
1564   // Function to find FrameConstructionData for aContent.  Will return
1565   // null if aContent is not MathML.
1566   static const FrameConstructionData* FindMathMLData(
1567       Element* aElement, nsAtom* aTag, int32_t aNameSpaceID,
1568       nsStyleContext* aStyleContext);
1569 
1570   // Function to find FrameConstructionData for aContent.  Will return
1571   // null if aContent is not XUL.
1572   static const FrameConstructionData* FindXULTagData(
1573       Element* aElement, nsAtom* aTag, int32_t aNameSpaceID,
1574       nsStyleContext* aStyleContext);
1575   // XUL data-finding helper functions and structures
1576 #ifdef MOZ_XUL
1577   static const FrameConstructionData* FindPopupGroupData(
1578       Element* aElement, nsStyleContext* aStyleContext);
1579   // sXULTextBoxData used for both labels and descriptions
1580   static const FrameConstructionData sXULTextBoxData;
1581   static const FrameConstructionData* FindXULLabelData(
1582       Element* aElement, nsStyleContext* aStyleContext);
1583   static const FrameConstructionData* FindXULDescriptionData(
1584       Element* aElement, nsStyleContext* aStyleContext);
1585 #ifdef XP_MACOSX
1586   static const FrameConstructionData* FindXULMenubarData(
1587       Element* aElement, nsStyleContext* aStyleContext);
1588 #endif /* XP_MACOSX */
1589   static const FrameConstructionData* FindXULListBoxBodyData(
1590       Element* aElement, nsStyleContext* aStyleContext);
1591   static const FrameConstructionData* FindXULListItemData(
1592       Element* aElement, nsStyleContext* aStyleContext);
1593 #endif /* MOZ_XUL */
1594 
1595   // Function to find FrameConstructionData for aContent using one of the XUL
1596   // display types.  Will return null if aDisplay doesn't have a XUL display
1597   // type.  This function performs no other checks, so should only be called if
1598   // we know for sure that the content is not something that should get a frame
1599   // constructed by tag.
1600   static const FrameConstructionData* FindXULDisplayData(
1601       const nsStyleDisplay* aDisplay, Element* aElement,
1602       nsStyleContext* aStyleContext);
1603 
1604   /**
1605    * Constructs an outer frame, an anonymous child that wraps its real
1606    * children, and its descendant frames.  This is used by both
1607    * ConstructOuterSVG and ConstructMarker, which both want an anonymous block
1608    * child for their children to go in to.
1609    */
1610   nsContainerFrame* ConstructFrameWithAnonymousChild(
1611       nsFrameConstructorState& aState, FrameConstructionItem& aItem,
1612       nsContainerFrame* aParentFrame, nsFrameItems& aFrameItems,
1613       ContainerFrameCreationFunc aConstructor,
1614       ContainerFrameCreationFunc aInnerConstructor,
1615       nsICSSAnonBoxPseudo* aInnerPseudo, bool aCandidateRootFrame);
1616 
1617   /**
1618    * Construct an nsSVGOuterSVGFrame.
1619    */
1620   nsIFrame* ConstructOuterSVG(nsFrameConstructorState& aState,
1621                               FrameConstructionItem& aItem,
1622                               nsContainerFrame* aParentFrame,
1623                               const nsStyleDisplay* aDisplay,
1624                               nsFrameItems& aFrameItems);
1625 
1626   /**
1627    * Construct an nsSVGMarkerFrame.
1628    */
1629   nsIFrame* ConstructMarker(nsFrameConstructorState& aState,
1630                             FrameConstructionItem& aItem,
1631                             nsContainerFrame* aParentFrame,
1632                             const nsStyleDisplay* aDisplay,
1633                             nsFrameItems& aFrameItems);
1634 
1635   static const FrameConstructionData* FindSVGData(
1636       Element* aElement, nsAtom* aTag, int32_t aNameSpaceID,
1637       nsIFrame* aParentFrame, bool aIsWithinSVGText, bool aAllowsTextPathChild,
1638       nsStyleContext* aStyleContext);
1639 
1640   /* Not static because it does PropagateScrollToViewport.  If this
1641      changes, make this static */
1642   const FrameConstructionData* FindDisplayData(const nsStyleDisplay* aDisplay,
1643                                                Element* aElement,
1644                                                nsStyleContext* aStyleContext);
1645 
1646   /**
1647    * Construct a scrollable block frame
1648    */
1649   nsIFrame* ConstructScrollableBlock(nsFrameConstructorState& aState,
1650                                      FrameConstructionItem& aItem,
1651                                      nsContainerFrame* aParentFrame,
1652                                      const nsStyleDisplay* aDisplay,
1653                                      nsFrameItems& aFrameItems);
1654 
1655   /**
1656    * Construct a scrollable block frame using the given block frame creation
1657    * function.
1658    */
1659   nsIFrame* ConstructScrollableBlockWithConstructor(
1660       nsFrameConstructorState& aState, FrameConstructionItem& aItem,
1661       nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
1662       nsFrameItems& aFrameItems, BlockFrameCreationFunc aConstructor);
1663 
1664   /**
1665    * Construct a non-scrollable block frame
1666    */
1667   nsIFrame* ConstructNonScrollableBlock(nsFrameConstructorState& aState,
1668                                         FrameConstructionItem& aItem,
1669                                         nsContainerFrame* aParentFrame,
1670                                         const nsStyleDisplay* aDisplay,
1671                                         nsFrameItems& aFrameItems);
1672 
1673   /**
1674    * Construct a non-scrollable block frame using the given block frame creation
1675    * function.
1676    */
1677   nsIFrame* ConstructNonScrollableBlockWithConstructor(
1678       nsFrameConstructorState& aState, FrameConstructionItem& aItem,
1679       nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
1680       nsFrameItems& aFrameItems, BlockFrameCreationFunc aConstructor);
1681 
1682   /**
1683    * This adds FrameConstructionItem objects to aItemsToConstruct for the
1684    * anonymous content returned by an nsIAnonymousContentCreator::
1685    * CreateAnonymousContent implementation.
1686    */
1687   void AddFCItemsForAnonymousContent(
1688       nsFrameConstructorState& aState, nsContainerFrame* aFrame,
1689       nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
1690       FrameConstructionItemList& aItemsToConstruct, uint32_t aExtraFlags = 0);
1691 
1692   /**
1693    * Construct the frames for the children of aContent.  "children" is defined
1694    * as "whatever FlattenedChildIterator returns for aContent".  This means
1695    * we're basically operating on children in the "flattened tree" per
1696    * sXBL/XBL2. This method will also handle constructing ::before, ::after,
1697    * ::first-letter, and ::first-line frames, as needed and if allowed.
1698    *
1699    * If the parent is a float containing block, this method will handle pushing
1700    * it as the float containing block in aState (so there's no need for callers
1701    * to push it themselves).
1702    *
1703    * @param aState the frame construction state
1704    * @param aContent the content node whose children need frames
1705    * @param aStyleContext the style context for aContent
1706    * @param aParentFrame the frame to use as the parent frame for the new
1707    * in-flow kids. Note that this must be its own content insertion frame, but
1708    *        need not be be the primary frame for aContent.  This frame will be
1709    *        pushed as the float containing block, as needed.  aFrame is also
1710    *        used to find the parent style context for the kids' style contexts
1711    *        (not necessary aFrame's style context).
1712    * @param aCanHaveGeneratedContent Whether to allow :before and
1713    *        :after styles on the parent.
1714    * @param aFrameItems the list in which we should place the in-flow children
1715    * @param aAllowBlockStyles Whether to allow first-letter and first-line
1716    *        styles on the parent.
1717    * @param aPendingBinding Make sure to push this into aState before doing any
1718    *        child item construction.
1719    * @param aPossiblyLeafFrame if non-null, this should be used for the isLeaf
1720    *        test and the anonymous content creation.  If null, aFrame will be
1721    *        used.
1722    */
1723   void ProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent,
1724                        nsStyleContext* aStyleContext,
1725                        nsContainerFrame* aParentFrame,
1726                        const bool aCanHaveGeneratedContent,
1727                        nsFrameItems& aFrameItems, const bool aAllowBlockStyles,
1728                        PendingBinding* aPendingBinding,
1729                        nsIFrame* aPossiblyLeafFrame = nullptr);
1730 
1731   /**
1732    * These two functions are used when we start frame creation from a non-root
1733    * element. They should recreate the same state that we would have
1734    * arrived at if we had built frames from the root frame to aFrame.
1735    * Therefore, any calls to PushFloatContainingBlock and
1736    * PushAbsoluteContainingBlock during frame construction should get
1737    * corresponding logic in these functions.
1738    */
1739  public:
1740   enum ContainingBlockType { ABS_POS, FIXED_POS };
1741   nsContainerFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame,
1742                                                ContainingBlockType aType);
1743   nsContainerFrame* GetFloatContainingBlock(nsIFrame* aFrame);
1744 
1745  private:
1746   // Build a scroll frame:
1747   //  Calls BeginBuildingScrollFrame, InitAndRestoreFrame, and then
1748   //  FinishBuildingScrollFrame.
1749   // @param aNewFrame the created scrollframe --- output only
1750   // @param aParentFrame the geometric parent that the scrollframe will have.
1751   void BuildScrollFrame(nsFrameConstructorState& aState, nsIContent* aContent,
1752                         nsStyleContext* aContentStyle, nsIFrame* aScrolledFrame,
1753                         nsContainerFrame* aParentFrame,
1754                         nsContainerFrame*& aNewFrame);
1755 
1756   // Builds the initial ScrollFrame
1757   already_AddRefed<nsStyleContext> BeginBuildingScrollFrame(
1758       nsFrameConstructorState& aState, nsIContent* aContent,
1759       nsStyleContext* aContentStyle, nsContainerFrame* aParentFrame,
1760       nsAtom* aScrolledPseudo, bool aIsRoot, nsContainerFrame*& aNewFrame);
1761 
1762   // Completes the building of the scrollframe:
1763   // Creates a view for the scrolledframe and makes it the child of the
1764   // scrollframe.
1765   void FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
1766                                  nsIFrame* aScrolledFrame);
1767 
1768   // InitializeSelectFrame puts scrollFrame in aFrameItems if aBuildCombobox is
1769   // false aBuildCombobox indicates if we are building a combobox that has a
1770   // dropdown popup widget or not.
1771   void InitializeSelectFrame(nsFrameConstructorState& aState,
1772                              nsContainerFrame* aScrollFrame,
1773                              nsContainerFrame* aScrolledFrame,
1774                              nsIContent* aContent,
1775                              nsContainerFrame* aParentFrame,
1776                              nsStyleContext* aStyleContext, bool aBuildCombobox,
1777                              PendingBinding* aPendingBinding,
1778                              nsFrameItems& aFrameItems);
1779 
1780 #ifdef MOZ_OLD_STYLE
1781   /**
1782    * ReResolve style for aElement then recreate frames if required.
1783    * Do nothing for other types of style changes, except for undisplayed nodes
1784    * (display:none/contents) which will have their style context updated in the
1785    * frame manager undisplayed maps.
1786    * @return null if frames were recreated, the new style context otherwise
1787    */
1788   nsStyleContext* MaybeRecreateFramesForElement(Element* aElement);
1789 #endif
1790 
1791   /**
1792    * Recreate frames for aContent.
1793    * @param aContent the content to recreate frames for
1794    * @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
1795    */
1796   void RecreateFramesForContent(nsIContent* aContent,
1797                                 InsertionKind aInsertionKind);
1798 
1799   /**
1800    *  Handles change of rowspan and colspan attributes on table cells.
1801    */
1802   void UpdateTableCellSpans(nsIContent* aContent);
1803 
1804   // If removal of aFrame from the frame tree requires reconstruction of some
1805   // containing block (either of aFrame or of its parent) due to {ib} splits or
1806   // table pseudo-frames, recreate the relevant frame subtree.  The return value
1807   // indicates whether this happened.  aFrame must be the result of a
1808   // GetPrimaryFrame() call on a content node (which means its parent is also
1809   // not null).
1810   bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame);
1811 
1812   nsIFrame* CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
1813                                             nsPresContext* aPresContext,
1814                                             nsIFrame* aFrame,
1815                                             nsContainerFrame* aParentFrame,
1816                                             nsIContent* aContent,
1817                                             nsStyleContext* aStyleContext);
1818 
1819   nsIFrame* CreateContinuingTableFrame(nsIPresShell* aPresShell,
1820                                        nsIFrame* aFrame,
1821                                        nsContainerFrame* aParentFrame,
1822                                        nsIContent* aContent,
1823                                        nsStyleContext* aStyleContext);
1824 
1825   //----------------------------------------
1826 
1827   // Methods support creating block frames and their children
1828 
1829   already_AddRefed<nsStyleContext> GetFirstLetterStyle(
1830       nsIContent* aContent, nsStyleContext* aStyleContext);
1831 
1832   already_AddRefed<nsStyleContext> GetFirstLineStyle(
1833       nsIContent* aContent, nsStyleContext* aStyleContext);
1834 
1835   bool ShouldHaveFirstLetterStyle(nsIContent* aContent,
1836                                   nsStyleContext* aStyleContext);
1837 
1838   // Check whether a given block has first-letter style.  Make sure to
1839   // only pass in blocks!  And don't pass in null either.
1840   bool HasFirstLetterStyle(nsIFrame* aBlockFrame);
1841 
1842   bool ShouldHaveFirstLineStyle(nsIContent* aContent,
1843                                 nsStyleContext* aStyleContext);
1844 
1845   void ShouldHaveSpecialBlockStyle(nsIContent* aContent,
1846                                    nsStyleContext* aStyleContext,
1847                                    bool* aHaveFirstLetterStyle,
1848                                    bool* aHaveFirstLineStyle);
1849 
1850   // |aContentParentFrame| should be null if it's really the same as
1851   // |aParentFrame|.
1852   // @param aFrameItems where we want to put the block in case it's in-flow.
1853   // @param aNewFrame an in/out parameter. On input it is the block to be
1854   // constructed. On output it is reset to the outermost
1855   // frame constructed (e.g. if we need to wrap the block in an
1856   // nsColumnSetFrame.
1857   // @param aParentFrame is the desired parent for the (possibly wrapped)
1858   // block
1859   // @param aContentParent is the parent the block would have if it
1860   // were in-flow
1861   // @param aPositionedFrameForAbsPosContainer if non-null, then the new
1862   // block should be an abs-pos container and aPositionedFrameForAbsPosContainer
1863   // is the frame whose style is making this block an abs-pos container.
1864   // @param aPendingBinding the pending binding  from this block's frame
1865   // construction item.
1866   void ConstructBlock(nsFrameConstructorState& aState, nsIContent* aContent,
1867                       nsContainerFrame* aParentFrame,
1868                       nsContainerFrame* aContentParentFrame,
1869                       nsStyleContext* aStyleContext,
1870                       nsContainerFrame** aNewFrame, nsFrameItems& aFrameItems,
1871                       nsIFrame* aPositionedFrameForAbsPosContainer,
1872                       PendingBinding* aPendingBinding);
1873 
1874   nsIFrame* ConstructInline(nsFrameConstructorState& aState,
1875                             FrameConstructionItem& aItem,
1876                             nsContainerFrame* aParentFrame,
1877                             const nsStyleDisplay* aDisplay,
1878                             nsFrameItems& aFrameItems);
1879 
1880   /**
1881    * Create any additional {ib} siblings needed to contain aChildItems and put
1882    * them in aSiblings.
1883    *
1884    * @param aState the frame constructor state
1885    * @param aInitialInline is an already-existing inline frame that will be
1886    *                       part of this {ib} split and come before everything
1887    *                       in aSiblings.
1888    * @param aIsPositioned true if aInitialInline is positioned.
1889    * @param aChildItems is a child list starting with a block; this method
1890    *                    assumes that the inline has already taken all the
1891    *                    children it wants.  When the method returns aChildItems
1892    *                    will be empty.
1893    * @param aSiblings the nsFrameItems to put the newly-created siblings into.
1894    *
1895    * This method is responsible for making any SetFrameIsIBSplit calls that are
1896    * needed.
1897    */
1898   void CreateIBSiblings(nsFrameConstructorState& aState,
1899                         nsContainerFrame* aInitialInline, bool aIsPositioned,
1900                         nsFrameItems& aChildItems, nsFrameItems& aSiblings);
1901 
1902   /**
1903    * For an inline aParentItem, construct its list of child
1904    * FrameConstructionItems and set its mIsAllInline flag appropriately.
1905    */
1906   void BuildInlineChildItems(nsFrameConstructorState& aState,
1907                              FrameConstructionItem& aParentItem,
1908                              bool aItemIsWithinSVGText,
1909                              bool aItemAllowsTextPathChild);
1910 
1911   // Determine whether we need to wipe out what we just did and start over
1912   // because we're doing something like adding block kids to an inline frame
1913   // (and therefore need an {ib} split).  aPrevSibling must be correct, even in
1914   // aIsAppend cases.  Passing aIsAppend false even when an append is happening
1915   // is ok in terms of correctness, but can lead to unnecessary reframing.  If
1916   // aIsAppend is true, then the caller MUST call
1917   // nsCSSFrameConstructor::AppendFramesToParent (as opposed to
1918   // nsFrameManager::InsertFrames directly) to add the new frames.
1919   // @return true if we reconstructed the containing block, false
1920   // otherwise
1921   bool WipeContainingBlock(nsFrameConstructorState& aState,
1922                            nsIFrame* aContainingBlock, nsIFrame* aFrame,
1923                            FrameConstructionItemList& aItems, bool aIsAppend,
1924                            nsIFrame* aPrevSibling);
1925 
1926   void ReframeContainingBlock(nsIFrame* aFrame);
1927 
1928   //----------------------------------------
1929 
1930   // Methods support :first-letter style
1931 
1932   nsFirstLetterFrame* CreateFloatingLetterFrame(
1933       nsFrameConstructorState& aState, nsIContent* aTextContent,
1934       nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
1935       nsStyleContext* aParentStyleContext, nsStyleContext* aStyleContext,
1936       nsFrameItems& aResult);
1937 
1938   void CreateLetterFrame(nsContainerFrame* aBlockFrame,
1939                          nsContainerFrame* aBlockContinuation,
1940                          nsIContent* aTextContent,
1941                          nsContainerFrame* aParentFrame, nsFrameItems& aResult);
1942 
1943   void WrapFramesInFirstLetterFrame(nsContainerFrame* aBlockFrame,
1944                                     nsFrameItems& aBlockFrames);
1945 
1946   /**
1947    * Looks in the block aBlockFrame for a text frame that contains the
1948    * first-letter of the block and creates the necessary first-letter frames
1949    * and returns them in aLetterFrames.
1950    *
1951    * @param aBlockFrame the (first-continuation of) the block we are creating a
1952    *                    first-letter frame for
1953    * @param aBlockContinuation the current continuation of the block that we
1954    *                           are looking in for a textframe with suitable
1955    *                           contents for first-letter
1956    * @param aParentFrame the current frame whose children we are looking at for
1957    *                     a suitable first-letter textframe
1958    * @param aParentFrameList the first child of aParentFrame
1959    * @param aModifiedParent returns the parent of the textframe that contains
1960    *                        the first-letter
1961    * @param aTextFrame returns the textframe that had the first-letter
1962    * @param aPrevFrame returns the previous sibling of aTextFrame
1963    * @param aLetterFrames returns the frames that were created
1964    */
1965   void WrapFramesInFirstLetterFrame(
1966       nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
1967       nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
1968       nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
1969       nsIFrame** aPrevFrame, nsFrameItems& aLetterFrames, bool* aStopLooking);
1970 
1971   void RecoverLetterFrames(nsContainerFrame* aBlockFrame);
1972 
1973   //
1974   void RemoveLetterFrames(nsIPresShell* aPresShell,
1975                           nsContainerFrame* aBlockFrame);
1976 
1977   // Recursive helper for RemoveLetterFrames
1978   void RemoveFirstLetterFrames(nsIPresShell* aPresShell,
1979                                nsContainerFrame* aFrame,
1980                                nsContainerFrame* aBlockFrame,
1981                                bool* aStopLooking);
1982 
1983   // Special remove method for those pesky floating first-letter frames
1984   void RemoveFloatingFirstLetterFrames(nsIPresShell* aPresShell,
1985                                        nsIFrame* aBlockFrame);
1986 
1987   // Capture state for the frame tree rooted at the frame associated with the
1988   // content object, aContent
1989   void CaptureStateForFramesOf(nsIContent* aContent,
1990                                nsILayoutHistoryState* aHistoryState);
1991 
1992   //----------------------------------------
1993 
1994   // Methods support :first-line style
1995 
1996   // This method chops the initial inline-outside frames out of aFrameItems.
1997   // If aLineFrame is non-null, it appends them to that frame.  Otherwise, it
1998   // creates a new line frame, sets the inline frames as its initial child
1999   // list, and inserts that line frame at the front of what's left of
2000   // aFrameItems.  In both cases, the kids are reparented to the line frame.
2001   // After this call, aFrameItems holds the frames that need to become kids of
2002   // the block (possibly including line frames).
2003   void WrapFramesInFirstLineFrame(nsFrameConstructorState& aState,
2004                                   nsIContent* aBlockContent,
2005                                   nsContainerFrame* aBlockFrame,
2006                                   nsFirstLineFrame* aLineFrame,
2007                                   nsFrameItems& aFrameItems);
2008 
2009   // Handle the case when a block with first-line style is appended to (by
2010   // possibly calling WrapFramesInFirstLineFrame as needed).
2011   void AppendFirstLineFrames(nsFrameConstructorState& aState,
2012                              nsIContent* aContent,
2013                              nsContainerFrame* aBlockFrame,
2014                              nsFrameItems& aFrameItems);
2015 
2016   /**
2017    * When aFrameItems is being inserted into aParentFrame, and aParentFrame has
2018    * pseudo-element-affected styles, it's possible that we're inserting under a
2019    * ::first-line frame.  In that case, with servo's style system, the styles we
2020    * resolved for aFrameItems are wrong (they don't take ::first-line into
2021    * account), and we should fix them up, which is what this method does.
2022    *
2023    * This method does not mutate aFrameItems.
2024    */
2025   void CheckForFirstLineInsertion(nsIFrame* aParentFrame,
2026                                   nsFrameItems& aFrameItems);
2027 
2028   // The direction in which we should look for siblings.
2029   enum class SiblingDirection {
2030     Forward,
2031     Backward,
2032   };
2033 
2034   /**
2035    * Find the frame for the content immediately next to the one aIter points to,
2036    * in the direction SiblingDirection indicates, following continuations if
2037    * necessary.
2038    *
2039    * aIter is passed by const reference on purpose, so as not to modify the
2040    * caller's iterator.
2041    *
2042    * @param aIter should be positioned such that aIter.GetPreviousChild()
2043    *          is the first content to search for frames
2044    * @param aTargetContentDisplay the CSS display enum for the content aIter
2045    *          points to if already known, UNSET_DISPLAY otherwise. It will be
2046    *          filled in if needed.
2047    */
2048   template <SiblingDirection>
2049   nsIFrame* FindSibling(const mozilla::dom::FlattenedChildIterator& aIter,
2050                         mozilla::StyleDisplay& aTargetContentDisplay);
2051 
2052   // Helper for the implementation of FindSibling.
2053   //
2054   // Beware that this function does mutate the iterator.
2055   template <SiblingDirection>
2056   nsIFrame* FindSiblingInternal(mozilla::dom::FlattenedChildIterator&,
2057                                 nsIContent* aTargetContent,
2058                                 mozilla::StyleDisplay& aTargetContentDisplay);
2059 
2060   // An alias of FindSibling<SiblingDirection::Forward>.
2061   nsIFrame* FindNextSibling(const mozilla::dom::FlattenedChildIterator& aIter,
2062                             mozilla::StyleDisplay& aTargetContentDisplay);
2063   // An alias of FindSibling<SiblingDirection::Backwards>.
2064   nsIFrame* FindPreviousSibling(
2065       const mozilla::dom::FlattenedChildIterator& aIter,
2066       mozilla::StyleDisplay& aTargetContentDisplay);
2067 
2068   // Given a potential first-continuation sibling frame for aTargetContent,
2069   // verify that it is an actual valid sibling for it, and return the
2070   // appropriate continuation the new frame for aTargetContent should be
2071   // inserted next to.
2072   nsIFrame* AdjustSiblingFrame(nsIFrame* aSibling, nsIContent* aTargetContent,
2073                                mozilla::StyleDisplay& aTargetContentDisplay,
2074                                SiblingDirection aDirection);
2075 
2076   // Find the right previous sibling for an insertion.  This also updates the
2077   // parent frame to point to the correct continuation of the parent frame to
2078   // use, and returns whether this insertion is to be treated as an append.
2079   // aChild is the child being inserted.
2080   // aIsRangeInsertSafe returns whether it is safe to do a range insert with
2081   // aChild being the first child in the range. It is the callers'
2082   // responsibility to check whether a range insert is safe with regards to
2083   // fieldsets.
2084   // The skip parameters are used to ignore a range of children when looking
2085   // for a sibling. All nodes starting from aStartSkipChild and up to but not
2086   // including aEndSkipChild will be skipped over when looking for sibling
2087   // frames. Skipping a range can deal with XBL but not when there are multiple
2088   // insertion points.
2089   nsIFrame* GetInsertionPrevSibling(InsertionPoint* aInsertion,  // inout
2090                                     nsIContent* aChild, bool* aIsAppend,
2091                                     bool* aIsRangeInsertSafe,
2092                                     nsIContent* aStartSkipChild = nullptr,
2093                                     nsIContent* aEndSkipChild = nullptr);
2094 
2095   // see if aContent and aSibling are legitimate siblings due to restrictions
2096   // imposed by table columns
2097   // XXXbz this code is generally wrong, since the frame for aContent
2098   // may be constructed based on tag, not based on aDisplay!
2099   bool IsValidSibling(nsIFrame* aSibling, nsIContent* aContent,
2100                       mozilla::StyleDisplay& aDisplay);
2101 
2102   void QuotesDirty();
2103   void CountersDirty();
2104 
2105   /**
2106    * Add the pair (aContent, aStyleContext) to the undisplayed items
2107    * in aList as needed.  This method enforces the invariant that all
2108    * style contexts in the undisplayed content map must be non-pseudo
2109    * contexts and also handles unbinding undisplayed generated content
2110    * as needed.
2111    */
2112   void SetAsUndisplayedContent(nsFrameConstructorState& aState,
2113                                FrameConstructionItemList& aList,
2114                                nsIContent* aContent,
2115                                nsStyleContext* aStyleContext,
2116                                bool aIsGeneratedContent);
2117   // Create touch caret frame.
2118   void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
2119                                           nsIFrame* aFrame,
2120                                           nsIContent* aDocElement);
2121 
2122  public:
2123   friend class nsFrameConstructorState;
2124 
2125  private:
2126   // For allocating FrameConstructionItems from the mFCItemPool arena.
2127   friend struct FrameConstructionItem;
2128   void* AllocateFCItem();
2129   void FreeFCItem(FrameConstructionItem*);
2130 
2131   nsIDocument* mDocument;  // Weak ref
2132 
2133   // See the comment at the start of ConstructRootFrame for more details
2134   // about the following frames.
2135 
2136   // This is just the outermost frame for the root element.
2137   nsContainerFrame* mRootElementFrame;
2138   // This is the frame for the root element that has no pseudo-element style.
2139   nsIFrame* mRootElementStyleFrame;
2140   // This is the containing block that contains the root element ---
2141   // the real "initial containing block" according to CSS 2.1.
2142   nsContainerFrame* mDocElementContainingBlock;
2143   nsIFrame* mPageSequenceFrame;
2144 
2145   // FrameConstructionItem arena + list of freed items available for re-use.
2146   mozilla::ArenaAllocator<4096, 8> mFCItemPool;
2147   struct FreeFCItemLink {
2148     FreeFCItemLink* mNext;
2149   };
2150   FreeFCItemLink* mFirstFreeFCItem;
2151   size_t mFCItemsInUse;
2152 
2153   nsQuoteList mQuoteList;
2154   nsCounterManager mCounterManager;
2155   // Current ProcessChildren depth.
2156   uint16_t mCurrentDepth;
2157   bool mQuotesDirty : 1;
2158   bool mCountersDirty : 1;
2159   bool mIsDestroyingFrameTree : 1;
2160   // This is true if mDocElementContainingBlock supports absolute positioning
2161   bool mHasRootAbsPosContainingBlock : 1;
2162   bool mAlwaysCreateFramesForIgnorableWhitespace : 1;
2163 
2164   nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
2165 };
2166 
2167 #endif /* nsCSSFrameConstructor_h___ */
2168