Bug 1856663 - Add more chunks for Android mochitest-plain. r=jmaher,taskgraph-reviewe...
[gecko.git] / layout / base / nsCSSFrameConstructor.h
blobd96fbb27a89d3690ba174dddb97c37e576be3871
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/. */
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
12 #ifndef nsCSSFrameConstructor_h___
13 #define nsCSSFrameConstructor_h___
15 #include "mozilla/ArenaAllocator.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/ContainStyleScopeManager.h"
18 #include "mozilla/FunctionRef.h"
19 #include "mozilla/LinkedList.h"
20 #include "mozilla/Maybe.h"
21 #include "mozilla/ScrollStyles.h"
22 #include "mozilla/UniquePtr.h"
23 #include "mozilla/PresShell.h"
25 #include "nsCOMPtr.h"
26 #include "nsILayoutHistoryState.h"
27 #include "nsIAnonymousContentCreator.h"
28 #include "nsFrameManager.h"
29 #include "nsIFrame.h"
31 struct nsStyleDisplay;
32 struct nsGenConInitializer;
34 class nsBlockFrame;
35 class nsContainerFrame;
36 class nsFirstLineFrame;
37 class nsFirstLetterFrame;
38 class nsCSSAnonBoxPseudoStaticAtom;
39 class nsPageSequenceFrame;
41 class nsPageContentFrame;
43 class nsFrameConstructorState;
45 namespace mozilla {
47 class ComputedStyle;
48 class PresShell;
49 class PrintedSheetFrame;
50 class RestyleManager;
52 namespace dom {
54 class CharacterData;
55 class Text;
56 class FlattenedChildIterator;
58 } // namespace dom
59 } // namespace mozilla
61 class nsCSSFrameConstructor final : public nsFrameManager {
62 public:
63 using ComputedStyle = mozilla::ComputedStyle;
64 using PseudoStyleType = mozilla::PseudoStyleType;
65 using PresShell = mozilla::PresShell;
66 using Element = mozilla::dom::Element;
67 using Text = mozilla::dom::Text;
69 // FIXME(emilio): Is this really needed?
70 friend class mozilla::RestyleManager;
72 nsCSSFrameConstructor(mozilla::dom::Document* aDocument,
73 PresShell* aPresShell);
74 ~nsCSSFrameConstructor() { MOZ_ASSERT(mFCItemsInUse == 0); }
76 static void GetAlternateTextFor(const Element&, nsAString& aAltText);
78 private:
79 nsCSSFrameConstructor(const nsCSSFrameConstructor& aCopy) = delete;
80 nsCSSFrameConstructor& operator=(const nsCSSFrameConstructor& aCopy) = delete;
82 public:
83 /**
84 * Whether insertion should be done synchronously or asynchronously.
86 * Generally, insertion is synchronous if we're entering frame construction
87 * from restyle processing, and async if we're removing stuff, or need to
88 * reconstruct some ancestor.
90 * Note that constructing async from frame construction will post a restyle
91 * event, but won't need another whole refresh driver tick to go in. Instead
92 * change hint processing will keep going as long as there are changes in the
93 * queue.
95 enum class InsertionKind {
96 Sync,
97 Async,
100 mozilla::RestyleManager* RestyleManager() const {
101 return mPresShell->GetPresContext()->RestyleManager();
104 nsIFrame* ConstructRootFrame();
106 private:
107 enum Operation { CONTENTAPPEND, CONTENTINSERT };
109 // aChild is the child being inserted for inserts, and the first
110 // child being appended for appends.
111 void ConstructLazily(Operation aOperation, nsIContent* aChild);
113 #ifdef DEBUG
114 void CheckBitsForLazyFrameConstruction(nsIContent* aParent);
115 #else
116 void CheckBitsForLazyFrameConstruction(nsIContent*) {}
117 #endif
119 // Issues a single ContentInserted for each child in the range
120 // [aStartChild, aEndChild).
121 void IssueSingleInsertNofications(nsIContent* aStartChild,
122 nsIContent* aEndChild, InsertionKind);
125 * Data that represents an insertion point for some child content.
127 struct InsertionPoint {
128 InsertionPoint() : mParentFrame(nullptr), mContainer(nullptr) {}
130 InsertionPoint(nsContainerFrame* aParentFrame, nsIContent* aContainer)
131 : mParentFrame(aParentFrame), mContainer(aContainer) {}
134 * The parent frame to use if the inserted children needs to create
135 * frame(s). May be null, which signals that we shouldn't try to
136 * create frames for the inserted children; either because there are
137 * no parent frame or because there are multiple insertion points and
138 * we will call IssueSingleInsertNofications for each child instead.
139 * mContainer should not be used when mParentFrame is null.
141 nsContainerFrame* mParentFrame;
143 * The flattened tree parent for the inserted children.
144 * It's undefined if mParentFrame is null.
146 nsIContent* mContainer;
149 * Whether it is required to insert children one-by-one instead of as a
150 * range.
152 bool IsMultiple() const;
156 * Checks if the children in the range [aStartChild, aEndChild) can be
157 * inserted/appended to one insertion point together.
159 * If so, returns that insertion point. If not, returns with
160 * InsertionPoint.mFrame == nullptr and issues single ContentInserted calls
161 * for each child.
163 * aEndChild = nullptr indicates that we are dealing with an append.
165 InsertionPoint GetRangeInsertionPoint(nsIContent* aStartChild,
166 nsIContent* aEndChild, InsertionKind);
168 // Returns true if parent was recreated due to frameset child, false
169 // otherwise.
170 bool MaybeRecreateForFrameset(nsIFrame* aParentFrame, nsIContent* aStartChild,
171 nsIContent* aEndChild);
174 * For each child in the aStartChild/aEndChild range, calls
175 * NoteDirtyDescendantsForServo on their flattened tree parents. This is
176 * used when content is inserted into the document and we decide that
177 * we can do lazy frame construction. It handles children being rebound to
178 * different insertion points by calling NoteDirtyDescendantsForServo on each
179 * child's flattened tree parent. Only used when we are styled by Servo.
181 void LazilyStyleNewChildRange(nsIContent* aStartChild, nsIContent* aEndChild);
184 * For each child in the aStartChild/aEndChild range, calls StyleNewChildren
185 * on their flattened tree parents. This is used when content is inserted
186 * into the document and we decide that we cannot do lazy frame construction.
187 * It handles children being rebound to different insertion points by calling
188 * StyleNewChildren on each child's flattened tree parent. Only used when we
189 * are styled by Servo.
191 void StyleNewChildRange(nsIContent* aStartChild, nsIContent* aEndChild);
193 public:
195 * Lazy frame construction is controlled by the InsertionKind parameter of
196 * nsCSSFrameConstructor::ContentAppended/Inserted. It is true for all
197 * inserts/appends as passed from the presshell, except for the insert of the
198 * root element, which is always non-lazy.
200 * If we construct lazily, then we add NODE_NEEDS_FRAME bits to the newly
201 * inserted/appended nodes and adds NODE_DESCENDANTS_NEED_FRAMES bits to the
202 * container and up along the parent chain until it hits the root or another
203 * node with that bit set. Then it posts a restyle event to ensure that a
204 * flush happens to construct those frames.
206 * When the flush happens the RestyleManager walks the dirty nodes during
207 * ProcessPostTraversal, and ends up calling Content{Appended,Inserted} with
208 * InsertionKind::Sync in ProcessRestyledFrames.
210 * If a node is removed from the document then we don't bother unsetting any
211 * of the lazy bits that might be set on it, its descendants, or any of its
212 * ancestor nodes because that is a slow operation, the work might be wasted
213 * if another node gets inserted in its place, and we can clear the bits
214 * quicker by processing the content tree from top down the next time we
215 * reconstruct frames. (We do clear the bits when BindToTree is called on any
216 * nsIContent; so any nodes added to the document will not have any lazy bits
217 * set.)
220 // If the insertion kind is Async then frame construction of the new children
221 // can be done lazily.
222 void ContentAppended(nsIContent* aFirstNewContent, InsertionKind);
224 // If the insertion kind is Async then frame construction of the new child
225 // can be done lazily.
226 void ContentInserted(nsIContent* aChild, InsertionKind);
228 // Like ContentInserted but handles inserting the children in the range
229 // [aStartChild, aEndChild). aStartChild must be non-null. aEndChild may be
230 // null to indicate the range includes all kids after aStartChild.
232 // If aInsertionKind is Async then frame construction of the new children can
233 // be done lazily. It is only allowed to be Async when inserting a single
234 // node.
235 void ContentRangeInserted(nsIContent* aStartChild, nsIContent* aEndChild,
236 InsertionKind aInsertionKind);
238 enum RemoveFlags {
239 REMOVE_CONTENT,
240 REMOVE_FOR_RECONSTRUCTION,
244 * Recreate or destroy frames for aChild.
246 * aFlags == REMOVE_CONTENT means aChild has been removed from the document.
247 * aFlags == REMOVE_FOR_RECONSTRUCTION means the caller will reconstruct the
248 * frames later.
250 * In both the above cases, this method will in some cases try to reconstruct
251 * frames on some ancestor of aChild. This can happen regardless of the value
252 * of aFlags.
254 * The return value indicates whether this "reconstruct an ancestor" action
255 * took place. If true is returned, that means that the frame subtree rooted
256 * at some ancestor of aChild's frame was destroyed and will be reconstructed
257 * async.
259 bool ContentRemoved(nsIContent* aChild, nsIContent* aOldNextSibling,
260 RemoveFlags aFlags);
262 void CharacterDataChanged(nsIContent* aContent,
263 const CharacterDataChangeInfo& aInfo);
265 // If aContent is a text node that has been optimized away due to being
266 // whitespace next to a block boundary (or for some other reason), ensure that
267 // a frame for it is created the next time frames are flushed, if it can
268 // possibly have a frame at all.
270 // Returns whether there are chances for the frame to be unsuppressed.
271 bool EnsureFrameForTextNodeIsCreatedAfterFlush(
272 mozilla::dom::CharacterData* aContent);
274 // Should be called when a frame is going to be destroyed and
275 // WillDestroyFrameTree hasn't been called yet.
276 void NotifyDestroyingFrame(nsIFrame* aFrame);
278 void RecalcQuotesAndCounters();
280 // Called when any counter style is changed.
281 void NotifyCounterStylesAreDirty();
283 // Gets called when the presshell is destroying itself and also
284 // when we tear down our frame tree to reconstruct it
285 void WillDestroyFrameTree();
288 * Destroy the frames for aContent. Note that this may destroy frames
289 * for an ancestor instead.
291 * Returns whether a reconstruct was posted for any ancestor.
293 bool DestroyFramesFor(nsIContent* aContent);
295 // Request to create a continuing frame. This method never returns null.
296 nsIFrame* CreateContinuingFrame(nsIFrame* aFrame,
297 nsContainerFrame* aParentFrame,
298 bool aIsFluid = true);
300 void SetNextPageContentFramePageName(const nsAtom* aAtom) {
301 MOZ_ASSERT(!mNextPageContentFramePageName,
302 "PageContentFrame page name was already set");
303 mNextPageContentFramePageName = aAtom;
306 // Copy over fixed frames from aParentFrame's prev-in-flow
307 nsresult ReplicateFixedFrames(nsPageContentFrame* aParentFrame);
310 * Get the insertion point for aChild.
312 InsertionPoint GetInsertionPoint(nsIContent* aChild);
315 * Return the insertion frame of the primary frame of aContent, or its nearest
316 * ancestor that isn't display:contents.
318 nsContainerFrame* GetContentInsertionFrameFor(nsIContent* aContent);
320 // GetInitialContainingBlock() is deprecated in favor of
321 // GetRootElementFrame(); nsIFrame* GetInitialContainingBlock() { return
322 // mRootElementFrame; } This returns the outermost frame for the root element
323 nsContainerFrame* GetRootElementFrame() { return mRootElementFrame; }
324 // This returns the frame for the root element that does not
325 // have a psuedo-element style
326 nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; }
327 nsPageSequenceFrame* GetPageSequenceFrame() { return mPageSequenceFrame; }
328 // Returns the outermost canvas frame. There's usually one per document, but
329 // if but if we're in printing / paginated mode we might have multiple: one
330 // per page plus the background one.
331 nsCanvasFrame* GetCanvasFrame() { return mCanvasFrame; }
332 // Get the frame that is the parent of the root element's frame.
333 nsCanvasFrame* GetDocElementContainingBlock() {
334 return mDocElementContainingBlock;
337 void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
339 #if defined(ACCESSIBILITY) || defined(MOZ_LAYOUT_DEBUGGER)
340 // Exposed only for nsLayoutUtils::GetMarkerSpokenText and
341 // nsLayoutDebuggingTools to use.
342 mozilla::ContainStyleScopeManager& GetContainStyleScopeManager() {
343 return mContainStyleScopeManager;
345 #endif
347 private:
348 struct FrameConstructionItem;
349 class FrameConstructionItemList;
351 mozilla::PrintedSheetFrame* ConstructPrintedSheetFrame(
352 PresShell* aPresShell, nsContainerFrame* aParentFrame,
353 nsIFrame* aPrevSheetFrame);
355 nsContainerFrame* ConstructPageFrame(PresShell* aPresShell,
356 nsContainerFrame* aParentFrame,
357 nsIFrame* aPrevPageFrame,
358 nsCanvasFrame*& aCanvasFrame);
360 void InitAndRestoreFrame(const nsFrameConstructorState& aState,
361 nsIContent* aContent, nsContainerFrame* aParentFrame,
362 nsIFrame* aNewFrame, bool aAllowCounters = true);
364 already_AddRefed<ComputedStyle> ResolveComputedStyle(nsIContent* aContent);
366 enum class ItemFlag : uint8_t {
367 // Allow page-break before and after items to be created if the
368 // style asks for them.
369 AllowPageBreak,
370 IsGeneratedContent,
371 IsWithinSVGText,
372 // The item allows items to be created for SVG <textPath> children.
373 AllowTextPathChild,
374 // The item is content created by an nsIAnonymousContentCreator frame.
375 IsAnonymousContentCreatorContent,
376 // The item will be the rendered legend of a <fieldset>.
377 IsForRenderedLegend,
378 // This will be an outside ::marker.
379 IsForOutsideMarker,
382 using ItemFlags = mozilla::EnumSet<ItemFlag>;
384 // Add the frame construction items for the given aContent and aParentFrame
385 // to the list. This might add more than one item in some rare cases.
386 // If aSuppressWhiteSpaceOptimizations is true, optimizations that
387 // may suppress the construction of white-space-only text frames
388 // must be skipped for these items and items around them.
389 void AddFrameConstructionItems(nsFrameConstructorState& aState,
390 nsIContent* aContent,
391 bool aSuppressWhiteSpaceOptimizations,
392 const ComputedStyle& aParentStyle,
393 const InsertionPoint& aInsertion,
394 FrameConstructionItemList& aItems,
395 ItemFlags = {});
397 // Helper method for AddFrameConstructionItems etc.
398 // Unsets the need-frame/restyle bits on aContent.
399 // return true iff we should attempt to create frames for aContent.
400 bool ShouldCreateItemsForChild(nsFrameConstructorState& aState,
401 nsIContent* aContent,
402 nsContainerFrame* aParentFrame);
404 // Construct the frames for the document element. This can return null if the
405 // document element is display:none, or if it's an SVG element that's not
406 // <svg>, etc.
407 nsIFrame* ConstructDocElementFrame(Element* aDocElement);
409 // Set up our mDocElementContainingBlock correctly for the given root
410 // content.
411 void SetUpDocElementContainingBlock(nsIContent* aDocElement);
414 * CreateAttributeContent creates a single content/frame combination for an
415 * |attr(foo)| generated content.
417 * @param aParentContent the parent content for the generated content (that
418 * is, the originating element).
419 * @param aParentFrame the parent frame for the generated frame
420 * @param aAttrNamespace the namespace of the attribute in question
421 * @param aAttrName the localname of the attribute
422 * @param aComputedStyle the style to use
423 * @param aGeneratedContent the array of generated content to append the
424 * created content to.
425 * @param [out] aNewContent the content node we create
426 * @param [out] aNewFrame the new frame we create
428 void CreateAttributeContent(const Element& aParentContent,
429 nsIFrame* aParentFrame, int32_t aAttrNamespace,
430 nsAtom* aAttrName, ComputedStyle* aComputedStyle,
431 nsCOMArray<nsIContent>& aGeneratedContent,
432 nsIContent** aNewContent, nsIFrame** aNewFrame);
435 * Create a text node containing the given string. If aText is non-null
436 * then we also set aText to the returned node.
438 already_AddRefed<nsIContent> CreateGenConTextNode(
439 nsFrameConstructorState& aState, const nsAString& aString,
440 mozilla::UniquePtr<nsGenConInitializer> aInitializer);
443 * Create a content node for the given generated content style.
444 * The caller takes care of making it SetIsNativeAnonymousRoot, binding it
445 * to the document, and creating frames for it.
446 * @param aOriginatingElement is the node that has the before/after style.
447 * @param aComputedStyle is the 'before' or 'after' pseudo-element style.
448 * @param aContentIndex is the index of the content item to create.
449 * @param aAddChild callback to be called for each generated content child.
451 void CreateGeneratedContent(
452 nsFrameConstructorState& aState, Element& aOriginatingElement,
453 ComputedStyle& aPseudoStyle, uint32_t aContentIndex,
454 const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
457 * Create child content nodes for a ::marker from its 'list-style-*' values.
459 void CreateGeneratedContentFromListStyle(
460 nsFrameConstructorState& aState, Element& aOriginatingElement,
461 const ComputedStyle& aPseudoStyle,
462 const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
464 * Create child content nodes for a ::marker from its 'list-style-type'.
466 void CreateGeneratedContentFromListStyleType(
467 nsFrameConstructorState& aState, Element& aOriginatingElement,
468 const ComputedStyle& aPseudoStyle,
469 const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
471 // aParentFrame may be null; this method doesn't use it directly in any case.
472 void CreateGeneratedContentItem(nsFrameConstructorState& aState,
473 nsContainerFrame* aParentFrame,
474 Element& aOriginatingElement, ComputedStyle&,
475 PseudoStyleType aPseudoElement,
476 FrameConstructionItemList& aItems,
477 ItemFlags aExtraFlags = {});
479 // This method is called by ContentAppended() and ContentRangeInserted() when
480 // appending flowed frames to a parent's principal child list. It handles the
481 // case where the parent is the trailing inline of an ib-split or is the last
482 // continuation of a ::-moz-column-content in an nsColumnSetFrame.
484 // This method can change aFrameList: it can chop off the beginning and put it
485 // in aParentFrame while either putting the remainder into an ib-split sibling
486 // of aParentFrame or creating aParentFrame's column-span siblings for the
487 // remainder.
489 // aPrevSibling must be the frame after which aFrameList is to be placed on
490 // aParentFrame's principal child list. It may be null if aFrameList is being
491 // added at the beginning of the child list.
492 void AppendFramesToParent(nsFrameConstructorState& aState,
493 nsContainerFrame* aParentFrame,
494 nsFrameList& aFrameList, nsIFrame* aPrevSibling,
495 bool aIsRecursiveCall = false);
497 // BEGIN TABLE SECTION
499 * Construct a table wrapper frame. This is the FrameConstructionData
500 * callback used for the job.
502 nsIFrame* ConstructTable(nsFrameConstructorState& aState,
503 FrameConstructionItem& aItem,
504 nsContainerFrame* aParentFrame,
505 const nsStyleDisplay* aDisplay,
506 nsFrameList& aFrameList);
509 * FrameConstructionData callback for constructing table rows and row groups.
511 nsIFrame* ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
512 FrameConstructionItem& aItem,
513 nsContainerFrame* aParentFrame,
514 const nsStyleDisplay* aStyleDisplay,
515 nsFrameList& aFrameList);
518 * FrameConstructionData callback used for constructing table columns.
520 nsIFrame* ConstructTableCol(nsFrameConstructorState& aState,
521 FrameConstructionItem& aItem,
522 nsContainerFrame* aParentFrame,
523 const nsStyleDisplay* aStyleDisplay,
524 nsFrameList& aFrameList);
527 * FrameConstructionData callback used for constructing table cells.
529 nsIFrame* ConstructTableCell(nsFrameConstructorState& aState,
530 FrameConstructionItem& aItem,
531 nsContainerFrame* aParentFrame,
532 const nsStyleDisplay* aStyleDisplay,
533 nsFrameList& aFrameList);
535 private:
536 /* An enum of possible parent types for anonymous table or ruby object
537 construction */
538 enum ParentType {
539 eTypeBlock = 0, /* This includes all non-table-related frames */
540 eTypeRow,
541 eTypeRowGroup,
542 eTypeColGroup,
543 eTypeTable,
544 eTypeRuby,
545 eTypeRubyBase,
546 eTypeRubyBaseContainer,
547 eTypeRubyText,
548 eTypeRubyTextContainer,
549 eParentTypeCount
552 /* 4 bits is enough to handle our ParentType values */
553 #define FCDATA_PARENT_TYPE_OFFSET 28
554 /* Macro to get the desired parent type out of an mBits member of
555 FrameConstructionData */
556 #define FCDATA_DESIRED_PARENT_TYPE(_bits) \
557 ParentType((_bits) >> FCDATA_PARENT_TYPE_OFFSET)
558 /* Macro to create FrameConstructionData bits out of a desired parent type */
559 #define FCDATA_DESIRED_PARENT_TYPE_TO_BITS(_type) \
560 (((uint32_t)(_type)) << FCDATA_PARENT_TYPE_OFFSET)
562 /* Get the parent type that aParentFrame has. */
563 static ParentType GetParentType(nsIFrame* aParentFrame) {
564 return GetParentType(aParentFrame->Type());
567 /* Get the parent type for the given LayoutFrameType */
568 static ParentType GetParentType(mozilla::LayoutFrameType aFrameType);
570 static bool IsRubyParentType(ParentType aParentType) {
571 return (aParentType == eTypeRuby || aParentType == eTypeRubyBase ||
572 aParentType == eTypeRubyBaseContainer ||
573 aParentType == eTypeRubyText ||
574 aParentType == eTypeRubyTextContainer);
577 static bool IsTableParentType(ParentType aParentType) {
578 return (aParentType == eTypeTable || aParentType == eTypeRow ||
579 aParentType == eTypeRowGroup || aParentType == eTypeColGroup);
582 /* A constructor function that just creates an nsIFrame object. The caller
583 is responsible for initializing the object, adding it to frame lists,
584 constructing frames for the children, etc.
586 @param PresShell the presshell whose arena should be used to allocate
587 the frame.
588 @param ComputedStyle the style to use for the frame. */
589 using FrameCreationFunc = nsIFrame* (*)(PresShell*, ComputedStyle*);
590 using ContainerFrameCreationFunc = nsContainerFrame* (*)(PresShell*,
591 ComputedStyle*);
592 using BlockFrameCreationFunc = nsBlockFrame* (*)(PresShell*, ComputedStyle*);
594 /* A function that can be used to get a FrameConstructionData. Such
595 a function is allowed to return null.
597 @param nsIContent the node for which the frame is being constructed.
598 @param ComputedStyle the style to be used for the frame.
600 struct FrameConstructionData;
601 using FrameConstructionDataGetter =
602 const FrameConstructionData* (*)(const Element&, ComputedStyle&);
604 /* A constructor function that's used for complicated construction tasks.
605 This is expected to create the new frame, initialize it, add whatever
606 needs to be added to aFrameList (XXXbz is that really necessary? Could
607 caller add? Might there be cases when the returned frame or its
608 placeholder is not the thing that ends up in aFrameList? If not, would
609 it be safe to do the add into the frame construction state after
610 processing kids? Look into this as a followup!), process children as
611 needed, etc. It is NOT expected to deal with setting the frame on the
612 content.
614 @param aState the frame construction state to use.
615 @param aItem the frame construction item to use
616 @param aParentFrame the frame to set as the parent of the
617 newly-constructed frame.
618 @param aStyleDisplay the display struct from aItem's mComputedStyle
619 @param aFrameList the frame list to add the new frame (or its
620 placeholder) to.
621 @return the frame that was constructed. This frame is what the caller
622 will set as the frame on the content. Guaranteed non-null.
624 using FrameFullConstructor =
625 nsIFrame* (nsCSSFrameConstructor::*)(nsFrameConstructorState& aState,
626 FrameConstructionItem& aItem,
627 nsContainerFrame* aParentFrame,
628 const nsStyleDisplay* aStyleDisplay,
629 nsFrameList& aFrameList);
631 /* Bits that modify the way a FrameConstructionData is handled */
633 /* If the FCDATA_SKIP_FRAMESET bit is set, then the frame created should not
634 be set as the primary frame on the content node. This should only be used
635 in very rare cases when we create more than one frame for a given content
636 node. */
637 #define FCDATA_SKIP_FRAMESET 0x1
638 /* If the FCDATA_FUNC_IS_DATA_GETTER bit is set, then the mFunc of the
639 FrameConstructionData is a getter function that can be used to get the
640 actual FrameConstructionData to use. */
641 #define FCDATA_FUNC_IS_DATA_GETTER 0x2
642 /* If the FCDATA_FUNC_IS_FULL_CTOR bit is set, then the FrameConstructionData
643 has an mFullConstructor. In this case, there is no relevant mData or
644 mFunc */
645 #define FCDATA_FUNC_IS_FULL_CTOR 0x4
646 /* If FCDATA_DISALLOW_OUT_OF_FLOW is set, do not allow the frame to
647 float or be absolutely positioned. This can also be used with
648 FCDATA_FUNC_IS_FULL_CTOR to indicate what the full-constructor
649 function will do. */
650 #define FCDATA_DISALLOW_OUT_OF_FLOW 0x8
651 /* If FCDATA_FORCE_NULL_ABSPOS_CONTAINER is set, make sure to push a
652 null absolute containing block before processing children for this
653 frame. If this is not set, the frame will be pushed as the
654 absolute containing block as needed, based on its style */
655 #define FCDATA_FORCE_NULL_ABSPOS_CONTAINER 0x10
656 /* If FCDATA_WRAP_KIDS_IN_BLOCKS is set, the inline kids of the frame
657 will be wrapped in blocks. This is only usable for MathML at the
658 moment. */
659 #define FCDATA_WRAP_KIDS_IN_BLOCKS 0x20
660 /* If FCDATA_SUPPRESS_FRAME is set, no frame should be created for the
661 content. If this bit is set, nothing else in the struct needs to be
662 set. */
663 #define FCDATA_SUPPRESS_FRAME 0x40
664 /* If FCDATA_MAY_NEED_SCROLLFRAME is set, the new frame should be wrapped in
665 a scrollframe if its overflow type so requires. */
666 #define FCDATA_MAY_NEED_SCROLLFRAME 0x80
667 /* If FCDATA_IS_POPUP is set, the new frame is a XUL popup frame. These need
668 some really weird special handling. */
669 #define FCDATA_IS_POPUP 0x100
670 /* If FCDATA_SKIP_ABSPOS_PUSH is set, don't push this frame as an
671 absolute containing block, no matter what its style says. */
672 #define FCDATA_SKIP_ABSPOS_PUSH 0x200
673 /* If FCDATA_DISALLOW_GENERATED_CONTENT is set, then don't allow generated
674 content when processing kids of this frame. This should not be used with
675 FCDATA_FUNC_IS_FULL_CTOR */
676 #define FCDATA_DISALLOW_GENERATED_CONTENT 0x400
677 /* If FCDATA_IS_TABLE_PART is set, then the frame is some sort of
678 table-related thing and we should not attempt to fetch a table-cell parent
679 for it if it's inside another table-related frame. */
680 #define FCDATA_IS_TABLE_PART 0x800
681 /* If FCDATA_IS_INLINE is set, then the frame is a non-replaced CSS
682 inline box. */
683 #define FCDATA_IS_INLINE 0x1000
684 /* If FCDATA_IS_LINE_PARTICIPANT is set, the frame is something that will
685 return true for IsFrameOfType(nsIFrame::eLineParticipant) */
686 #define FCDATA_IS_LINE_PARTICIPANT 0x2000
687 /* If FCDATA_IS_LINE_BREAK is set, the frame is something that will
688 induce a line break boundary before and after itself. */
689 #define FCDATA_IS_LINE_BREAK 0x4000
690 /* If FCDATA_ALLOW_BLOCK_STYLES is set, allow block styles when processing
691 children of a block (i.e. allow ::first-letter/line).
692 This should not be used with FCDATA_FUNC_IS_FULL_CTOR. */
693 #define FCDATA_ALLOW_BLOCK_STYLES 0x8000
694 /* If FCDATA_USE_CHILD_ITEMS is set, then use the mChildItems in the relevant
695 FrameConstructionItem instead of trying to process the content's children.
696 This can be used with or without FCDATA_FUNC_IS_FULL_CTOR.
697 The child items might still need table pseudo processing. */
698 #define FCDATA_USE_CHILD_ITEMS 0x10000
699 /* If FCDATA_FORCED_NON_SCROLLABLE_BLOCK is set, then this block
700 would have been scrollable but has been forced to be
701 non-scrollable due to being in a paginated context. */
702 #define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000
703 /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a
704 block formatting context wrapper around the kids of this frame
705 using the FrameConstructionData's mPseudoAtom for its anonymous
706 box type. */
707 #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000
708 /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of
709 an SVG text frame. */
710 #define FCDATA_IS_SVG_TEXT 0x80000
712 * If FCDATA_ALLOW_GRID_FLEX_COLUMN is set, then we should create a
713 * grid/flex/column container instead of a block wrapper when the styles says
714 * so. This bit is meaningful only if FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS
715 * is also set.
717 #define FCDATA_ALLOW_GRID_FLEX_COLUMN 0x200000
719 * Whether the kids of this FrameConstructionData should be flagged as having
720 * a wrapper anon box parent. This should only be set if
721 * FCDATA_USE_CHILD_ITEMS is set.
723 #define FCDATA_IS_WRAPPER_ANON_BOX 0x400000
725 /* Structure representing information about how a frame should be
726 constructed. */
727 struct FrameConstructionData {
728 // We have exactly one of three types of functions, so use a union for
729 // better cache locality.
730 union Func {
731 FrameCreationFunc mCreationFunc;
732 FrameConstructionDataGetter mDataGetter;
733 FrameFullConstructor mFullConstructor;
735 explicit constexpr Func(FrameCreationFunc aFunc) : mCreationFunc(aFunc) {}
736 explicit constexpr Func(FrameConstructionDataGetter aDataGetter)
737 : mDataGetter(aDataGetter) {}
738 explicit constexpr Func(FrameFullConstructor aCtor)
739 : mFullConstructor(aCtor) {}
740 } mFunc;
741 // Flag bits that can modify the way the construction happens
742 const uint32_t mBits = 0;
743 // For cases when FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, the
744 // anonymous box type to use for that wrapper.
745 PseudoStyleType const mAnonBoxPseudo = PseudoStyleType::NotPseudo;
747 constexpr FrameConstructionData() : FrameConstructionData(nullptr) {}
749 MOZ_IMPLICIT constexpr FrameConstructionData(std::nullptr_t,
750 uint32_t aBits = 0)
751 : mFunc(static_cast<FrameCreationFunc>(nullptr)), mBits(aBits) {}
753 MOZ_IMPLICIT constexpr FrameConstructionData(
754 FrameCreationFunc aCreationFunc, uint32_t aBits = 0)
755 : mFunc(aCreationFunc), mBits(aBits) {}
756 constexpr FrameConstructionData(FrameCreationFunc aCreationFunc,
757 uint32_t aBits,
758 PseudoStyleType aAnonBoxPseudo)
759 : mFunc(aCreationFunc),
760 mBits(aBits | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS),
761 mAnonBoxPseudo(aAnonBoxPseudo) {}
762 MOZ_IMPLICIT constexpr FrameConstructionData(
763 FrameConstructionDataGetter aDataGetter, uint32_t aBits = 0)
764 : mFunc(aDataGetter),
765 mBits(aBits | FCDATA_FUNC_IS_DATA_GETTER),
766 mAnonBoxPseudo(PseudoStyleType::NotPseudo) {}
767 MOZ_IMPLICIT constexpr FrameConstructionData(FrameFullConstructor aCtor,
768 uint32_t aBits = 0)
769 : mFunc(aCtor),
770 mBits(aBits | FCDATA_FUNC_IS_FULL_CTOR),
771 mAnonBoxPseudo(PseudoStyleType::NotPseudo) {}
774 /* Structure representing a mapping of an atom to a FrameConstructionData.
775 This can be used with non-static atoms, assuming that the nsAtom* is
776 stored somewhere that this struct can point to (that is, a static
777 nsAtom*) and that it's allocated before the struct is ever used. */
778 struct FrameConstructionDataByTag {
779 const nsStaticAtom* const mTag;
780 const FrameConstructionData mData;
783 /* Structure representing a mapping of an integer to a
784 FrameConstructionData. There are no magic integer values here. */
785 struct FrameConstructionDataByInt {
786 /* Could be used for display or whatever else */
787 const int32_t mInt;
788 const FrameConstructionData mData;
791 struct FrameConstructionDataByDisplay {
792 #ifdef DEBUG
793 const mozilla::StyleDisplay mDisplay;
794 #endif
795 const FrameConstructionData mData;
798 /* Structure that has a FrameConstructionData and style pseudo-type
799 for a table pseudo-frame */
800 struct PseudoParentData {
801 const FrameConstructionData mFCData;
802 mozilla::PseudoStyleType const mPseudoType;
804 /* Array of such structures that we use to properly construct table
805 pseudo-frames as needed */
806 static const PseudoParentData sPseudoParentData[eParentTypeCount];
808 const FrameConstructionData* FindDataForContent(nsIContent&, ComputedStyle&,
809 nsIFrame* aParentFrame,
810 ItemFlags aFlags);
812 // aParentFrame might be null. If it is, that means it was an inline frame.
813 static const FrameConstructionData* FindTextData(const Text&,
814 nsIFrame* aParentFrame);
815 const FrameConstructionData* FindElementData(const Element&, ComputedStyle&,
816 nsIFrame* aParentFrame,
817 ItemFlags aFlags);
818 const FrameConstructionData* FindElementTagData(const Element&,
819 ComputedStyle&,
820 nsIFrame* aParentFrame,
821 ItemFlags aFlags);
823 /* A function that takes an integer, content, style, and array of
824 FrameConstructionDataByInts and finds the appropriate frame construction
825 data to use and returns it. This can return null if none of the integers
826 match or if the matching integer has a FrameConstructionDataGetter that
827 returns null. */
828 static const FrameConstructionData* FindDataByInt(
829 int32_t aInt, const Element&, ComputedStyle&,
830 const FrameConstructionDataByInt* aDataPtr, uint32_t aDataLength);
833 * A function that takes a tag, content, style, and array of
834 * FrameConstructionDataByTags and finds the appropriate frame construction
835 * data to use and returns it.
837 * This can return null if none of the tags match or if the matching tag has a
838 * FrameConstructionDataGetter that returns null. In the case that the tags
839 * actually match, aTagFound will be true, even if the return value is null.
841 static const FrameConstructionData* FindDataByTag(
842 const Element& aElement, ComputedStyle& aComputedStyle,
843 const FrameConstructionDataByTag* aDataPtr, uint32_t aDataLength);
845 /* A class representing a list of FrameConstructionItems. Instances of this
846 class are only created as AutoFrameConstructionItemList, or as a member
847 of FrameConstructionItem. */
848 class FrameConstructionItemList {
849 public:
850 void Reset(nsCSSFrameConstructor* aFCtor) {
851 Destroy(aFCtor);
852 this->~FrameConstructionItemList();
853 new (this) FrameConstructionItemList();
856 void SetLineBoundaryAtStart(bool aBoundary) {
857 mLineBoundaryAtStart = aBoundary;
859 void SetLineBoundaryAtEnd(bool aBoundary) {
860 mLineBoundaryAtEnd = aBoundary;
862 void SetParentHasNoShadowDOM(bool aValue) {
863 mParentHasNoShadowDOM = aValue;
865 bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
866 bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
867 bool ParentHasNoShadowDOM() { return mParentHasNoShadowDOM; }
868 bool IsEmpty() const { return mItems.isEmpty(); }
869 bool AreAllItemsInline() const { return mInlineCount == mItemCount; }
870 bool AreAllItemsBlock() const { return mBlockCount == mItemCount; }
871 bool AllWantParentType(ParentType aDesiredParentType) const {
872 return mDesiredParentCounts[aDesiredParentType] == mItemCount;
875 // aSuppressWhiteSpaceOptimizations is true if optimizations that
876 // skip constructing whitespace frames for this item or items
877 // around it cannot be performed.
878 // Also, the return value is always non-null, thanks to infallible 'new'.
879 FrameConstructionItem* AppendItem(
880 nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
881 nsIContent* aContent, already_AddRefed<ComputedStyle>&& aComputedStyle,
882 bool aSuppressWhiteSpaceOptimizations) {
883 FrameConstructionItem* item = new (aFCtor)
884 FrameConstructionItem(aFCData, aContent, std::move(aComputedStyle),
885 aSuppressWhiteSpaceOptimizations);
886 mItems.insertBack(item);
887 ++mItemCount;
888 ++mDesiredParentCounts[item->DesiredParentType()];
889 return item;
892 // Arguments are the same as AppendItem().
893 FrameConstructionItem* PrependItem(
894 nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
895 nsIContent* aContent, already_AddRefed<ComputedStyle>&& aComputedStyle,
896 bool aSuppressWhiteSpaceOptimizations) {
897 FrameConstructionItem* item = new (aFCtor)
898 FrameConstructionItem(aFCData, aContent, std::move(aComputedStyle),
899 aSuppressWhiteSpaceOptimizations);
900 mItems.insertFront(item);
901 ++mItemCount;
902 ++mDesiredParentCounts[item->DesiredParentType()];
903 return item;
906 void InlineItemAdded() { ++mInlineCount; }
907 void BlockItemAdded() { ++mBlockCount; }
909 class Iterator {
910 public:
911 explicit Iterator(FrameConstructionItemList& aList)
912 : mCurrent(aList.mItems.getFirst()), mList(aList) {}
913 Iterator(const Iterator& aOther) = default;
915 bool operator==(const Iterator& aOther) const {
916 MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
917 return mCurrent == aOther.mCurrent;
919 bool operator!=(const Iterator& aOther) const {
920 return !(*this == aOther);
922 Iterator& operator=(const Iterator& aOther) {
923 MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
924 mCurrent = aOther.mCurrent;
925 return *this;
928 FrameConstructionItemList* List() { return &mList; }
930 FrameConstructionItem& item() {
931 MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
932 return *mCurrent;
935 const FrameConstructionItem& item() const {
936 MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
937 return *mCurrent;
940 bool IsDone() const { return mCurrent == nullptr; }
941 bool AtStart() const { return mCurrent == mList.mItems.getFirst(); }
942 void Next() {
943 NS_ASSERTION(!IsDone(), "Should have checked IsDone()!");
944 mCurrent = mCurrent->getNext();
946 void Prev() {
947 NS_ASSERTION(!AtStart(), "Should have checked AtStart()!");
948 mCurrent = mCurrent ? mCurrent->getPrevious() : mList.mItems.getLast();
950 void SetToEnd() { mCurrent = nullptr; }
952 // Skip over all items that want the given parent type. Return whether
953 // the iterator is done after doing that. The iterator must not be done
954 // when this is called.
955 inline bool SkipItemsWantingParentType(ParentType aParentType);
957 // Skip over all items that want a parent type different from the given
958 // one. Return whether the iterator is done after doing that. The
959 // iterator must not be done when this is called.
960 inline bool SkipItemsNotWantingParentType(ParentType aParentType);
962 // Skip over non-replaced inline frames and positioned frames.
963 // Return whether the iterator is done after doing that.
964 // The iterator must not be done when this is called.
965 inline bool SkipItemsThatNeedAnonFlexOrGridItem(
966 const nsFrameConstructorState& aState, bool aIsWebkitBox);
968 // Skip to the first frame that is a non-replaced inline or is
969 // positioned. Return whether the iterator is done after doing that.
970 // The iterator must not be done when this is called.
971 inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
972 const nsFrameConstructorState& aState, bool aIsWebkitBox);
974 // Skip over all items that do not want a ruby parent. Return whether
975 // the iterator is done after doing that. The iterator must not be done
976 // when this is called.
977 inline bool SkipItemsNotWantingRubyParent();
979 // Skip over whitespace. Return whether the iterator is done after doing
980 // that. The iterator must not be done, and must be pointing to a
981 // whitespace item when this is called.
982 inline bool SkipWhitespace(nsFrameConstructorState& aState);
984 // Remove the item pointed to by this iterator from its current list and
985 // Append it to aTargetList. This iterator is advanced to point to the
986 // next item in its list. aIter must not be done. aTargetList must not
987 // be the list this iterator is iterating over..
988 void AppendItemToList(FrameConstructionItemList& aTargetList);
990 // As above, but moves all items starting with this iterator until we
991 // get to aEnd; the item pointed to by aEnd is not stolen. This method
992 // might have optimizations over just looping and doing StealItem for
993 // some special cases. After this method returns, this iterator will
994 // point to the item aEnd points to now; aEnd is not modified.
995 // aTargetList must not be the list this iterator is iterating over.
996 void AppendItemsToList(nsCSSFrameConstructor* aFCtor,
997 const Iterator& aEnd,
998 FrameConstructionItemList& aTargetList);
1000 // Insert aItem in this iterator's list right before the item pointed to
1001 // by this iterator. After the insertion, this iterator will continue to
1002 // point to the item it now points to (the one just after the
1003 // newly-inserted item). This iterator is allowed to be done; in that
1004 // case this call just appends the given item to the list.
1005 void InsertItem(FrameConstructionItem* aItem);
1007 // Delete the items between this iterator and aEnd, including the item
1008 // this iterator currently points to but not including the item pointed
1009 // to by aEnd. When this returns, this iterator will point to the same
1010 // item as aEnd. This iterator must not equal aEnd when this method is
1011 // called.
1012 void DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd);
1014 private:
1015 FrameConstructionItem* mCurrent;
1016 FrameConstructionItemList& mList;
1019 protected:
1020 FrameConstructionItemList()
1021 : mInlineCount(0),
1022 mBlockCount(0),
1023 mItemCount(0),
1024 mLineBoundaryAtStart(false),
1025 mLineBoundaryAtEnd(false),
1026 mParentHasNoShadowDOM(false) {
1027 MOZ_COUNT_CTOR(FrameConstructionItemList);
1028 memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
1031 void Destroy(nsCSSFrameConstructor* aFCtor) {
1032 while (FrameConstructionItem* item = mItems.popFirst()) {
1033 item->Delete(aFCtor);
1037 // Prevent stack instances (except as AutoFrameConstructionItemList).
1038 friend struct FrameConstructionItem;
1039 ~FrameConstructionItemList() {
1040 MOZ_COUNT_DTOR(FrameConstructionItemList);
1041 MOZ_ASSERT(mItems.isEmpty(), "leaking");
1044 private:
1045 // Not allocated from the heap!
1046 void* operator new(size_t) = delete;
1047 void* operator new[](size_t) = delete;
1048 #ifdef _MSC_VER /* Visual Studio */
1049 void operator delete(void*) { MOZ_CRASH("FrameConstructionItemList::del"); }
1050 #else
1051 void operator delete(void*) = delete;
1052 #endif
1053 void operator delete[](void*) = delete;
1054 // Placement new is used by Reset().
1055 void* operator new(size_t, void* aPtr) { return aPtr; }
1057 struct UndisplayedItem {
1058 UndisplayedItem(nsIContent* aContent, ComputedStyle* aComputedStyle)
1059 : mContent(aContent), mComputedStyle(aComputedStyle) {}
1061 nsIContent* const mContent;
1062 RefPtr<ComputedStyle> mComputedStyle;
1065 // Adjust our various counts for aItem being added or removed. aDelta
1066 // should be either +1 or -1 depending on which is happening.
1067 void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta);
1069 mozilla::LinkedList<FrameConstructionItem> mItems;
1070 uint32_t mInlineCount;
1071 uint32_t mBlockCount;
1072 uint32_t mItemCount;
1073 uint32_t mDesiredParentCounts[eParentTypeCount];
1074 // True if there is guaranteed to be a line boundary before the
1075 // frames created by these items
1076 bool mLineBoundaryAtStart;
1077 // True if there is guaranteed to be a line boundary after the
1078 // frames created by these items
1079 bool mLineBoundaryAtEnd;
1080 // True if the parent is guaranteed to have no shadow tree.
1081 bool mParentHasNoShadowDOM;
1084 /* A struct representing a list of FrameConstructionItems on the stack. */
1085 struct MOZ_RAII AutoFrameConstructionItemList final
1086 : public FrameConstructionItemList {
1087 template <typename... Args>
1088 explicit AutoFrameConstructionItemList(nsCSSFrameConstructor* aFCtor,
1089 Args&&... args)
1090 : FrameConstructionItemList(std::forward<Args>(args)...),
1091 mFCtor(aFCtor) {
1092 MOZ_ASSERT(mFCtor);
1094 ~AutoFrameConstructionItemList() { Destroy(mFCtor); }
1096 private:
1097 nsCSSFrameConstructor* const mFCtor;
1100 typedef FrameConstructionItemList::Iterator FCItemIterator;
1102 /* A struct representing an item for which frames might need to be
1103 * constructed. This contains all the information needed to construct the
1104 * frame other than the parent frame and whatever would be stored in the
1105 * frame constructor state. You probably want to use
1106 * AutoFrameConstructionItem instead of this struct. */
1107 struct FrameConstructionItem final
1108 : public mozilla::LinkedListElement<FrameConstructionItem> {
1109 FrameConstructionItem(const FrameConstructionData* aFCData,
1110 nsIContent* aContent,
1111 already_AddRefed<ComputedStyle>&& aComputedStyle,
1112 bool aSuppressWhiteSpaceOptimizations)
1113 : mFCData(aFCData),
1114 mContent(aContent),
1115 mComputedStyle(std::move(aComputedStyle)),
1116 mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations),
1117 mIsText(false),
1118 mIsGeneratedContent(false),
1119 mIsAllInline(false),
1120 mIsBlock(false),
1121 mIsPopup(false),
1122 mIsLineParticipant(false),
1123 mIsRenderedLegend(false) {
1124 MOZ_COUNT_CTOR(FrameConstructionItem);
1127 void* operator new(size_t, nsCSSFrameConstructor* aFCtor) {
1128 return aFCtor->AllocateFCItem();
1131 void Delete(nsCSSFrameConstructor* aFCtor) {
1132 mChildItems.Destroy(aFCtor);
1133 if (mIsGeneratedContent) {
1134 mContent->UnbindFromTree();
1135 NS_RELEASE(mContent);
1137 this->~FrameConstructionItem();
1138 aFCtor->FreeFCItem(this);
1141 ParentType DesiredParentType() {
1142 return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
1145 // Indicates whether (when in a flex or grid container) this item needs
1146 // to be wrapped in an anonymous block. (Note that we implement
1147 // -webkit-box/-webkit-inline-box using our standard flexbox frame class,
1148 // but we use different rules for what gets wrapped. The aIsWebkitBox
1149 // parameter here tells us whether to use those different rules.)
1150 bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
1151 bool aIsWebkitBox);
1153 // Don't call this unless the frametree really depends on the answer!
1154 // Especially so for generated content, where we don't want to reframe
1155 // things.
1156 bool IsWhitespace(nsFrameConstructorState& aState) const;
1158 bool IsLineBoundary() const {
1159 return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK);
1162 // Child frame construction items.
1163 FrameConstructionItemList mChildItems;
1165 // The FrameConstructionData to use.
1166 const FrameConstructionData* mFCData;
1167 // The nsIContent node to use when initializing the new frame.
1168 nsIContent* mContent;
1169 // The style to use for creating the new frame.
1170 RefPtr<ComputedStyle> mComputedStyle;
1171 // Whether optimizations to skip constructing textframes around
1172 // this content need to be suppressed.
1173 bool mSuppressWhiteSpaceOptimizations : 1;
1174 // Whether this is a text content item.
1175 bool mIsText : 1;
1176 // Whether this is a generated content container.
1177 // If it is, mContent is a strong pointer.
1178 bool mIsGeneratedContent : 1;
1179 // Whether construction from this item will create only frames that are
1180 // IsInlineOutside() in the principal child list. This is not precise, but
1181 // conservative: if true the frames will really be inline, whereas if false
1182 // they might still all be inline.
1183 bool mIsAllInline : 1;
1184 // Whether construction from this item will create only frames that are
1185 // IsBlockOutside() in the principal child list. This is not precise, but
1186 // conservative: if true the frames will really be blocks, whereas if false
1187 // they might still be blocks (and in particular, out-of-flows that didn't
1188 // find a containing block).
1189 bool mIsBlock : 1;
1190 // Whether construction from this item will create a popup that needs to
1191 // go into the global popup items.
1192 bool mIsPopup : 1;
1193 // Whether this item should be treated as a line participant
1194 bool mIsLineParticipant : 1;
1195 // Whether this item is the rendered legend of a <fieldset>
1196 bool mIsRenderedLegend : 1;
1198 private:
1199 // Not allocated from the general heap - instead, use the new/Delete APIs
1200 // that take a nsCSSFrameConstructor* (which manages our arena allocation).
1201 void* operator new(size_t) = delete;
1202 void* operator new[](size_t) = delete;
1203 #ifdef _MSC_VER /* Visual Studio */
1204 void operator delete(void*) { MOZ_CRASH("FrameConstructionItem::delete"); }
1205 #else
1206 void operator delete(void*) = delete;
1207 #endif
1208 void operator delete[](void*) = delete;
1209 FrameConstructionItem(const FrameConstructionItem& aOther) = delete;
1210 // Not allocated from the stack!
1211 ~FrameConstructionItem() {
1212 MOZ_COUNT_DTOR(FrameConstructionItem);
1213 MOZ_ASSERT(mChildItems.IsEmpty(), "leaking");
1218 * Convenience struct to assist in managing a temporary FrameConstructionItem
1219 * using a local variable. Castable to FrameConstructionItem so that it can
1220 * be passed transparently to functions that expect that type.
1221 * (This struct exists because FrameConstructionItem is arena-allocated, and
1222 * it's nice to abstract away its allocation/deallocation.)
1224 struct MOZ_RAII AutoFrameConstructionItem final {
1225 template <typename... Args>
1226 explicit AutoFrameConstructionItem(nsCSSFrameConstructor* aFCtor,
1227 Args&&... args)
1228 : mFCtor(aFCtor),
1229 mItem(new(aFCtor)
1230 FrameConstructionItem(std::forward<Args>(args)...)) {
1231 MOZ_ASSERT(mFCtor);
1233 ~AutoFrameConstructionItem() { mItem->Delete(mFCtor); }
1234 operator FrameConstructionItem&() { return *mItem; }
1236 private:
1237 nsCSSFrameConstructor* const mFCtor;
1238 FrameConstructionItem* const mItem;
1242 * Updates the nsFrameConstructorState auto page-name value, and restores the
1243 * previous value on destruction.
1244 * See https://drafts.csswg.org/css-page-3/#using-named-pages
1246 * To track this, this will automatically add PageValuesProperty to
1247 * the frame.
1249 * Note that this does not add PageValuesProperty to the frame when not in a
1250 * paginated context, or if layout.css.named-pages.enabled is set to false.
1252 class MOZ_RAII AutoFrameConstructionPageName final {
1253 nsFrameConstructorState& mState;
1254 const nsAtom* mNameToRestore;
1256 public:
1257 AutoFrameConstructionPageName(const AutoFrameConstructionPageName&) =
1258 delete;
1259 AutoFrameConstructionPageName(AutoFrameConstructionPageName&&) = delete;
1260 AutoFrameConstructionPageName(nsFrameConstructorState& aState,
1261 nsIFrame* const aFrame);
1262 ~AutoFrameConstructionPageName();
1266 * Function to create the anonymous flex or grid items that we need.
1267 * If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
1268 * this method is a NOP.
1269 * @param aItems the child frame construction items before pseudo creation
1270 * @param aParentFrame the parent frame
1272 void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
1273 FrameConstructionItemList& aItems,
1274 nsIFrame* aParentFrame);
1276 enum RubyWhitespaceType {
1277 eRubyNotWhitespace,
1278 eRubyInterLevelWhitespace,
1279 // Includes inter-base and inter-annotation whitespace
1280 eRubyInterLeafWhitespace,
1281 eRubyInterSegmentWhitespace
1285 * Function to compute the whitespace type according to the display
1286 * values of the previous and the next elements.
1288 static inline RubyWhitespaceType ComputeRubyWhitespaceType(
1289 mozilla::StyleDisplay aPrevDisplay, mozilla::StyleDisplay aNextDisplay);
1292 * Function to interpret the type of whitespace between
1293 * |aStartIter| and |aEndIter|.
1295 static inline RubyWhitespaceType InterpretRubyWhitespace(
1296 nsFrameConstructorState& aState, const FCItemIterator& aStartIter,
1297 const FCItemIterator& aEndIter);
1300 * Function to wrap consecutive misparented inline content into
1301 * a ruby base box or a ruby text box.
1303 void WrapItemsInPseudoRubyLeafBox(FCItemIterator& aIter,
1304 ComputedStyle* aParentStyle,
1305 nsIContent* aParentContent);
1308 * Function to wrap consecutive misparented items
1309 * into a ruby level container.
1311 inline void WrapItemsInPseudoRubyLevelContainer(
1312 nsFrameConstructorState& aState, FCItemIterator& aIter,
1313 ComputedStyle* aParentStyle, nsIContent* aParentContent);
1316 * Function to trim leading and trailing whitespaces.
1318 inline void TrimLeadingAndTrailingWhitespaces(
1319 nsFrameConstructorState& aState, FrameConstructionItemList& aItems);
1322 * Function to create internal ruby boxes.
1324 inline void CreateNeededPseudoInternalRubyBoxes(
1325 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
1326 nsIFrame* aParentFrame);
1329 * Function to create the pseudo intermediate containers we need.
1330 * @param aItems the child frame construction items before pseudo creation
1331 * @param aParentFrame the parent frame we're creating pseudos for
1333 inline void CreateNeededPseudoContainers(nsFrameConstructorState& aState,
1334 FrameConstructionItemList& aItems,
1335 nsIFrame* aParentFrame);
1338 * Function to wrap consecutive items into a pseudo parent.
1340 inline void WrapItemsInPseudoParent(nsIContent* aParentContent,
1341 ComputedStyle* aParentStyle,
1342 ParentType aWrapperType,
1343 FCItemIterator& aIter,
1344 const FCItemIterator& aEndIter);
1347 * Function to create the pseudo siblings we need.
1349 inline void CreateNeededPseudoSiblings(nsFrameConstructorState& aState,
1350 FrameConstructionItemList& aItems,
1351 nsIFrame* aParentFrame);
1353 // END TABLE SECTION
1355 protected:
1356 static nsIFrame* CreatePlaceholderFrameFor(PresShell* aPresShell,
1357 nsIContent* aContent,
1358 nsIFrame* aFrame,
1359 nsContainerFrame* aParentFrame,
1360 nsIFrame* aPrevInFlow,
1361 nsFrameState aTypeBit);
1363 private:
1364 // ConstructSelectFrame puts the new frame in aFrameList and
1365 // handles the kids of the select.
1366 nsIFrame* ConstructSelectFrame(nsFrameConstructorState& aState,
1367 FrameConstructionItem& aItem,
1368 nsContainerFrame* aParentFrame,
1369 const nsStyleDisplay* aStyleDisplay,
1370 nsFrameList& aFrameList);
1372 // ConstructFieldSetFrame puts the new frame in aFrameList and
1373 // handles the kids of the fieldset
1374 nsIFrame* ConstructFieldSetFrame(nsFrameConstructorState& aState,
1375 FrameConstructionItem& aItem,
1376 nsContainerFrame* aParentFrame,
1377 const nsStyleDisplay* aStyleDisplay,
1378 nsFrameList& aFrameList);
1380 // <details> always creates a block per spec.
1381 nsIFrame* ConstructDetails(nsFrameConstructorState& aState,
1382 FrameConstructionItem& aItem,
1383 nsContainerFrame* aParentFrame,
1384 const nsStyleDisplay* aStyleDisplay,
1385 nsFrameList& aFrameList);
1387 // Creates a block frame wrapping an anonymous ruby frame.
1388 nsIFrame* ConstructBlockRubyFrame(nsFrameConstructorState& aState,
1389 FrameConstructionItem& aItem,
1390 nsContainerFrame* aParentFrame,
1391 const nsStyleDisplay* aStyleDisplay,
1392 nsFrameList& aFrameList);
1394 void ConstructTextFrame(const FrameConstructionData* aData,
1395 nsFrameConstructorState& aState, nsIContent* aContent,
1396 nsContainerFrame* aParentFrame,
1397 ComputedStyle* aComputedStyle,
1398 nsFrameList& aFrameList);
1400 // If aPossibleTextContent is a text node and doesn't have a frame, append a
1401 // frame construction item for it to aItems.
1402 void AddTextItemIfNeeded(nsFrameConstructorState& aState,
1403 const ComputedStyle& aParentStyle,
1404 const InsertionPoint& aInsertion,
1405 nsIContent* aPossibleTextContent,
1406 FrameConstructionItemList& aItems);
1408 // If aContent is a text node and doesn't have a frame, try to create a frame
1409 // for it.
1410 void ReframeTextIfNeeded(nsIContent* aContent);
1412 enum InsertPageBreakLocation { eBefore, eAfter };
1413 inline void AppendPageBreakItem(nsIContent* aContent,
1414 FrameConstructionItemList& aItems) {
1415 InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eAfter);
1417 inline void PrependPageBreakItem(nsIContent* aContent,
1418 FrameConstructionItemList& aItems) {
1419 InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eBefore);
1421 void InsertPageBreakItem(nsIContent* aContent,
1422 FrameConstructionItemList& aItems,
1423 InsertPageBreakLocation location);
1425 // Function to find FrameConstructionData for aElement. Will return
1426 // null if aElement is not HTML.
1427 // aParentFrame might be null. If it is, that means it was an
1428 // inline frame.
1429 static const FrameConstructionData* FindHTMLData(const Element&,
1430 nsIFrame* aParentFrame,
1431 ComputedStyle&);
1432 // HTML data-finding helper functions
1433 static const FrameConstructionData* FindImgData(const Element&,
1434 ComputedStyle&);
1435 static const FrameConstructionData* FindGeneratedImageData(const Element&,
1436 ComputedStyle&);
1437 static const FrameConstructionData* FindImgControlData(const Element&,
1438 ComputedStyle&);
1439 static const FrameConstructionData* FindSearchControlData(const Element&,
1440 ComputedStyle&);
1441 static const FrameConstructionData* FindInputData(const Element&,
1442 ComputedStyle&);
1443 static const FrameConstructionData* FindObjectData(const Element&,
1444 ComputedStyle&);
1445 static const FrameConstructionData* FindCanvasData(const Element&,
1446 ComputedStyle&);
1448 /* Construct a frame from the given FrameConstructionItem. This function
1449 will handle adding the frame to frame lists, processing children, setting
1450 the frame as the primary frame for the item's content, and so forth.
1452 @param aItem the FrameConstructionItem to use.
1453 @param aState the frame construction state to use.
1454 @param aParentFrame the frame to set as the parent of the
1455 newly-constructed frame.
1456 @param aFrameList the frame list to add the new frame (or its
1457 placeholder) to.
1459 void ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
1460 nsFrameConstructorState& aState,
1461 nsContainerFrame* aParentFrame,
1462 nsFrameList& aFrameList);
1464 // The guts of AddFrameConstructionItems
1465 // aParentFrame might be null. If it is, that means it was an
1466 // inline frame.
1467 void AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
1468 nsIContent* aContent,
1469 nsContainerFrame* aParentFrame,
1470 bool aSuppressWhiteSpaceOptimizations,
1471 ComputedStyle*, ItemFlags,
1472 FrameConstructionItemList& aItems);
1475 * Construct frames for the given item list and parent frame, and put the
1476 * resulting frames in aFrameList.
1478 void ConstructFramesFromItemList(nsFrameConstructorState& aState,
1479 FrameConstructionItemList& aItems,
1480 nsContainerFrame* aParentFrame,
1481 bool aParentIsWrapperAnonBox,
1482 nsFrameList& aFrameList);
1483 void ConstructFramesFromItem(nsFrameConstructorState& aState,
1484 FCItemIterator& aItem,
1485 nsContainerFrame* aParentFrame,
1486 nsFrameList& aFrameList);
1487 static bool AtLineBoundary(FCItemIterator& aIter);
1489 nsresult GetAnonymousContent(
1490 nsIContent* aParent, nsIFrame* aParentFrame,
1491 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonContent);
1493 // MathML Mod - RBS
1495 * Takes the frames in aBlockList and wraps them in a new anonymous block
1496 * frame whose content is aContent and whose parent will be aParentFrame.
1497 * The anonymous block is added to aNewList and aBlockList is cleared.
1499 void FlushAccumulatedBlock(nsFrameConstructorState& aState,
1500 nsIContent* aContent,
1501 nsContainerFrame* aParentFrame,
1502 nsFrameList& aBlockList, nsFrameList& aNewList);
1504 // Function to find FrameConstructionData for an element. Will return
1505 // null if the element is not MathML.
1506 static const FrameConstructionData* FindMathMLData(const Element&,
1507 ComputedStyle&);
1509 // Function to find FrameConstructionData for an element. Will return
1510 // null if the element is not XUL.
1511 static const FrameConstructionData* FindXULTagData(const Element&,
1512 ComputedStyle&);
1513 // XUL data-finding helper functions and structures
1514 static const FrameConstructionData* FindPopupGroupData(const Element&,
1515 ComputedStyle&);
1516 static const FrameConstructionData* FindXULButtonData(const Element&,
1517 ComputedStyle&);
1518 static const FrameConstructionData* FindXULLabelOrDescriptionData(
1519 const Element&, ComputedStyle&);
1520 #ifdef XP_MACOSX
1521 static const FrameConstructionData* FindXULMenubarData(const Element&,
1522 ComputedStyle&);
1523 #endif /* XP_MACOSX */
1526 * Constructs an outer frame, an anonymous child that wraps its real
1527 * children, and its descendant frames. This is used by both
1528 * ConstructOuterSVG and ConstructMarker, which both want an anonymous block
1529 * child for their children to go in to.
1531 nsContainerFrame* ConstructFrameWithAnonymousChild(
1532 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
1533 nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
1534 ContainerFrameCreationFunc aConstructor,
1535 ContainerFrameCreationFunc aInnerConstructor,
1536 mozilla::PseudoStyleType aInnerPseudo, bool aCandidateRootFrame);
1539 * Construct an SVGOuterSVGFrame.
1541 nsIFrame* ConstructOuterSVG(nsFrameConstructorState& aState,
1542 FrameConstructionItem& aItem,
1543 nsContainerFrame* aParentFrame,
1544 const nsStyleDisplay* aDisplay,
1545 nsFrameList& aFrameList);
1548 * Construct an SVGMarkerFrame.
1550 nsIFrame* ConstructMarker(nsFrameConstructorState& aState,
1551 FrameConstructionItem& aItem,
1552 nsContainerFrame* aParentFrame,
1553 const nsStyleDisplay* aDisplay,
1554 nsFrameList& aFrameList);
1556 static const FrameConstructionData* FindSVGData(const Element&,
1557 nsIFrame* aParentFrame,
1558 bool aIsWithinSVGText,
1559 bool aAllowsTextPathChild,
1560 ComputedStyle&);
1562 // Not static because it does PropagateScrollToViewport. If this
1563 // changes, make this static.
1564 const FrameConstructionData* FindDisplayData(const nsStyleDisplay&,
1565 const Element&);
1568 * Construct a scrollable block frame
1570 nsIFrame* ConstructScrollableBlock(nsFrameConstructorState& aState,
1571 FrameConstructionItem& aItem,
1572 nsContainerFrame* aParentFrame,
1573 const nsStyleDisplay* aDisplay,
1574 nsFrameList& aFrameList);
1577 * Construct a non-scrollable block frame
1579 nsIFrame* ConstructNonScrollableBlock(nsFrameConstructorState& aState,
1580 FrameConstructionItem& aItem,
1581 nsContainerFrame* aParentFrame,
1582 const nsStyleDisplay* aDisplay,
1583 nsFrameList& aFrameList);
1586 * This adds FrameConstructionItem objects to aItemsToConstruct for the
1587 * anonymous content returned by an nsIAnonymousContentCreator::
1588 * CreateAnonymousContent implementation.
1589 * This includes an AutoFrameConstructionPageName argument as it is always
1590 * the caller's responsibility to handle page-name tracking before calling
1591 * this function.
1593 void AddFCItemsForAnonymousContent(
1594 nsFrameConstructorState& aState, nsContainerFrame* aFrame,
1595 const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
1596 FrameConstructionItemList& aItemsToConstruct,
1597 const AutoFrameConstructionPageName& aUnusedPageNameTracker);
1600 * Construct the frames for the children of aContent. "children" is defined
1601 * as "whatever FlattenedChildIterator returns for aContent". This means
1602 * we're basically operating on children in the "flattened tree":
1604 * https://drafts.csswg.org/css-scoping/#flat-tree
1606 * This method will also handle constructing ::before, ::after,
1607 * ::first-letter, and ::first-line frames, as needed and if allowed.
1609 * If the parent is a float containing block, this method will handle pushing
1610 * it as the float containing block in aState (so there's no need for callers
1611 * to push it themselves).
1613 * @param aState the frame construction state
1614 * @param aContent the content node whose children need frames
1615 * @param aComputedStyle the style for aContent
1616 * @param aParentFrame the frame to use as the parent frame for the new
1617 * in-flow kids. Note that this must be its own content insertion frame, but
1618 * need not be be the primary frame for aContent. This frame will be
1619 * pushed as the float containing block, as needed. aFrame is also
1620 * used to find the parent style for the kids' style
1621 * (not necessary aFrame's style).
1622 * @param aCanHaveGeneratedContent Whether to allow :before and
1623 * :after styles on the parent.
1624 * @param aFrameList the list in which we should place the in-flow children
1625 * @param aAllowBlockStyles Whether to allow first-letter and first-line
1626 * styles on the parent.
1627 * @param aPossiblyLeafFrame if non-null, this should be used for the isLeaf
1628 * test and the anonymous content creation. If null, aFrame will be
1629 * used.
1631 void ProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent,
1632 ComputedStyle* aComputedStyle,
1633 nsContainerFrame* aParentFrame,
1634 const bool aCanHaveGeneratedContent,
1635 nsFrameList& aFrameList, const bool aAllowBlockStyles,
1636 nsIFrame* aPossiblyLeafFrame = nullptr);
1639 * These two functions are used when we start frame creation from a non-root
1640 * element. They should recreate the same state that we would have
1641 * arrived at if we had built frames from the root frame to aFrame.
1642 * Therefore, any calls to PushFloatContainingBlock and
1643 * PushAbsoluteContainingBlock during frame construction should get
1644 * corresponding logic in these functions.
1646 public:
1647 enum ContainingBlockType { ABS_POS, FIXED_POS };
1648 nsContainerFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame,
1649 ContainingBlockType aType);
1650 nsContainerFrame* GetFloatContainingBlock(nsIFrame* aFrame);
1652 private:
1653 // Build a scroll frame:
1654 // Calls BeginBuildingScrollFrame, InitAndRestoreFrame, and then
1655 // FinishBuildingScrollFrame.
1656 // @param aNewFrame the created scrollframe --- output only
1657 // @param aParentFrame the geometric parent that the scrollframe will have.
1658 void BuildScrollFrame(nsFrameConstructorState& aState, nsIContent* aContent,
1659 ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
1660 nsContainerFrame* aParentFrame,
1661 nsContainerFrame*& aNewFrame);
1663 // Builds the initial ScrollFrame
1664 already_AddRefed<ComputedStyle> BeginBuildingScrollFrame(
1665 nsFrameConstructorState& aState, nsIContent* aContent,
1666 ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame,
1667 mozilla::PseudoStyleType aScrolledPseudo, bool aIsRoot,
1668 nsContainerFrame*& aNewFrame);
1670 // Completes the building of the scrollframe:
1671 // Creates a view for the scrolledframe and makes it the child of the
1672 // scrollframe.
1673 void FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
1674 nsIFrame* aScrolledFrame);
1676 void InitializeListboxSelect(nsFrameConstructorState& aState,
1677 nsContainerFrame* aScrollFrame,
1678 nsContainerFrame* aScrolledFrame,
1679 nsIContent* aContent,
1680 nsContainerFrame* aParentFrame,
1681 ComputedStyle* aComputedStyle,
1682 nsFrameList& aFrameList);
1685 * Recreate frames for aContent.
1686 * @param aContent the content to recreate frames for
1687 * @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
1689 void RecreateFramesForContent(nsIContent* aContent,
1690 InsertionKind aInsertionKind);
1693 * Handles change of rowspan and colspan attributes on table cells.
1695 void UpdateTableCellSpans(nsIContent* aContent);
1697 // If removal of aFrame from the frame tree requires reconstruction of some
1698 // containing block (either of aFrame or of its parent) due to {ib} splits or
1699 // table pseudo-frames, recreate the relevant frame subtree. The return value
1700 // indicates whether this happened. aFrame must be the result of a
1701 // GetPrimaryFrame() call on a content node (which means its parent is also
1702 // not null).
1703 bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame);
1705 nsIFrame* CreateContinuingOuterTableFrame(nsIFrame* aFrame,
1706 nsContainerFrame* aParentFrame,
1707 nsIContent* aContent,
1708 ComputedStyle* aComputedStyle);
1710 nsIFrame* CreateContinuingTableFrame(nsIFrame* aFrame,
1711 nsContainerFrame* aParentFrame,
1712 nsIContent* aContent,
1713 ComputedStyle* aComputedStyle);
1715 //----------------------------------------
1717 // Methods support creating block frames and their children
1719 already_AddRefed<ComputedStyle> GetFirstLetterStyle(
1720 nsIContent* aContent, ComputedStyle* aComputedStyle);
1722 already_AddRefed<ComputedStyle> GetFirstLineStyle(
1723 nsIContent* aContent, ComputedStyle* aComputedStyle);
1725 bool ShouldHaveFirstLetterStyle(nsIContent* aContent,
1726 ComputedStyle* aComputedStyle);
1728 // Check whether a given block has first-letter style. Make sure to
1729 // only pass in blocks! And don't pass in null either.
1730 bool HasFirstLetterStyle(nsIFrame* aBlockFrame);
1732 bool ShouldHaveFirstLineStyle(nsIContent* aContent,
1733 ComputedStyle* aComputedStyle);
1735 void ShouldHaveSpecialBlockStyle(nsIContent* aContent,
1736 ComputedStyle* aComputedStyle,
1737 bool* aHaveFirstLetterStyle,
1738 bool* aHaveFirstLineStyle);
1740 // |aContentParentFrame| should be null if it's really the same as
1741 // |aParentFrame|.
1742 // @param aFrameList where we want to put the block in case it's in-flow.
1743 // @param aNewFrame an in/out parameter. On input it is the block to be
1744 // constructed. On output it is reset to the outermost
1745 // frame constructed (e.g. if we need to wrap the block in an
1746 // nsColumnSetFrame.
1747 // @param aParentFrame is the desired parent for the (possibly wrapped)
1748 // block
1749 // @param aContentParent is the parent the block would have if it
1750 // were in-flow
1751 // @param aPositionedFrameForAbsPosContainer if non-null, then the new
1752 // block should be an abs-pos container and aPositionedFrameForAbsPosContainer
1753 // is the frame whose style is making this block an abs-pos container.
1754 void ConstructBlock(nsFrameConstructorState& aState, nsIContent* aContent,
1755 nsContainerFrame* aParentFrame,
1756 nsContainerFrame* aContentParentFrame,
1757 ComputedStyle* aComputedStyle,
1758 nsContainerFrame** aNewFrame, nsFrameList& aFrameList,
1759 nsIFrame* aPositionedFrameForAbsPosContainer);
1761 // Build the initial column hierarchy around aColumnContent. This function
1762 // should be called before constructing aColumnContent's children.
1764 // Before calling FinishBuildingColumns(), we need to create column-span
1765 // siblings for aColumnContent's children. Caller can use helpers
1766 // MayNeedToCreateColumnSpanSiblings() and CreateColumnSpanSiblings() to
1767 // check whether column-span siblings might need to be created and to do
1768 // the actual work of creating them if they're needed.
1770 // @param aColumnContent the block that we're wrapping in a ColumnSet. On
1771 // entry to this function it has aComputedStyle as its style. After
1772 // this function returns, aColumnContent has a ::-moz-column-content
1773 // anonymous box style.
1774 // @param aParentFrame the parent frame we want to use for the
1775 // ColumnSetWrapperFrame (which would have been the parent of
1776 // aColumnContent if we were not creating a column hierarchy).
1777 // @param aContent is the content of the aColumnContent.
1778 // @return the outermost ColumnSetWrapperFrame.
1779 nsBlockFrame* BeginBuildingColumns(nsFrameConstructorState& aState,
1780 nsIContent* aContent,
1781 nsContainerFrame* aParentFrame,
1782 nsContainerFrame* aColumnContent,
1783 ComputedStyle* aComputedStyle);
1785 // Complete building the column hierarchy by first wrapping each
1786 // non-column-span child in aChildList in a ColumnSetFrame (skipping
1787 // column-span children), and reparenting them to have aColumnSetWrapper
1788 // as their parent.
1790 // @param aColumnSetWrapper is the frame returned by
1791 // BeginBuildingColumns(), and is the grandparent of aColumnContent.
1792 // @param aColumnContent is the block frame passed into
1793 // BeginBuildingColumns()
1794 // @param aColumnContentSiblings contains the aColumnContent's siblings, which
1795 // are the column spanners and aColumnContent's continuations returned
1796 // by CreateColumnSpanSiblings(). It'll become empty after this call.
1797 void FinishBuildingColumns(nsFrameConstructorState& aState,
1798 nsContainerFrame* aColumnSetWrapper,
1799 nsContainerFrame* aColumnContent,
1800 nsFrameList& aColumnContentSiblings);
1802 // Return whether aBlockFrame's children in aChildList, which might
1803 // contain column-span, may need to be wrapped in
1804 // ::moz-column-span-wrapper and promoted as aBlockFrame's siblings.
1806 // @param aBlockFrame is the parent of the frames in aChildList.
1808 // Note: This a check without actually looking into each frame in the
1809 // child list, so it may return false positive.
1810 bool MayNeedToCreateColumnSpanSiblings(nsContainerFrame* aBlockFrame,
1811 const nsFrameList& aChildList);
1813 // Wrap consecutive runs of column-span kids and runs of non-column-span
1814 // kids in blocks for aInitialBlock's children.
1816 // @param aInitialBlock is the parent of those frames in aChildList.
1817 // @param aChildList must begin with a column-span kid. It becomes empty
1818 // after this call.
1819 // @param aPositionedFrame if non-null, it's the frame whose style is making
1820 // aInitialBlock an abs-pos container.
1822 // Return those wrapping blocks in nsFrameList.
1823 nsFrameList CreateColumnSpanSiblings(nsFrameConstructorState& aState,
1824 nsContainerFrame* aInitialBlock,
1825 nsFrameList& aChildList,
1826 nsIFrame* aPositionedFrame);
1828 // Reconstruct the multi-column containing block of aParentFrame when we want
1829 // to insert aFrameList into aParentFrame immediately after aPrevSibling but
1830 // cannot fix the frame tree because aFrameList contains some column-spans.
1832 // Note: This method is intended to be called as a helper in ContentAppended()
1833 // and ContentRangeInserted(). It assumes aState was set up locally and wasn't
1834 // used to construct any ancestors of aParentFrame in aFrameList.
1836 // @param aParentFrame the to-be parent frame for aFrameList.
1837 // @param aFrameList the frames to be inserted. It will be cleared if we need
1838 // reconstruction.
1839 // @param aPrevSibling the position where the frames in aFrameList are going
1840 // to be inserted. Nullptr means aFrameList is being inserted at
1841 // the beginning.
1842 // @return true if the multi-column containing block of aParentFrame is
1843 // reconstructed; false otherwise.
1844 bool MaybeRecreateForColumnSpan(nsFrameConstructorState& aState,
1845 nsContainerFrame* aParentFrame,
1846 nsFrameList& aFrameList,
1847 nsIFrame* aPrevSibling);
1849 nsIFrame* ConstructInline(nsFrameConstructorState& aState,
1850 FrameConstructionItem& aItem,
1851 nsContainerFrame* aParentFrame,
1852 const nsStyleDisplay* aDisplay,
1853 nsFrameList& aFrameList);
1856 * Create any additional {ib} siblings needed to contain aChildList and put
1857 * them in aSiblings.
1859 * @param aState the frame constructor state
1860 * @param aInitialInline is an already-existing inline frame that will be
1861 * part of this {ib} split and come before everything
1862 * in aSiblings.
1863 * @param aIsPositioned true if aInitialInline is positioned.
1864 * @param aChildList is a child list starting with a block; this method
1865 * assumes that the inline has already taken all the
1866 * children it wants. When the method returns aChildList
1867 * will be empty.
1868 * @param aSiblings the nsFrameList to put the newly-created siblings into.
1870 * This method is responsible for making any SetFrameIsIBSplit calls that are
1871 * needed.
1873 void CreateIBSiblings(nsFrameConstructorState& aState,
1874 nsContainerFrame* aInitialInline, bool aIsPositioned,
1875 nsFrameList& aChildList, nsFrameList& aSiblings);
1878 * For an inline aParentItem, construct its list of child
1879 * FrameConstructionItems and set its mIsAllInline flag appropriately.
1881 void BuildInlineChildItems(nsFrameConstructorState& aState,
1882 FrameConstructionItem& aParentItem,
1883 bool aItemIsWithinSVGText,
1884 bool aItemAllowsTextPathChild);
1886 // Determine whether we need to wipe out aFrame (the insertion parent) and
1887 // rebuild the entire subtree when we insert or append new content under
1888 // aFrame.
1890 // This is similar to WipeContainingBlock(), but is called before constructing
1891 // any frame construction items. Any container frames which need reframing
1892 // regardless of the content inserted or appended can add a check in this
1893 // method.
1895 // @return true if we reconstructed the insertion parent frame; false
1896 // otherwise
1897 bool WipeInsertionParent(nsContainerFrame* aFrame);
1899 // Determine whether we need to wipe out what we just did and start over
1900 // because we're doing something like adding block kids to an inline frame
1901 // (and therefore need an {ib} split). aPrevSibling must be correct, even in
1902 // aIsAppend cases. Passing aIsAppend false even when an append is happening
1903 // is ok in terms of correctness, but can lead to unnecessary reframing. If
1904 // aIsAppend is true, then the caller MUST call
1905 // nsCSSFrameConstructor::AppendFramesToParent (as opposed to
1906 // nsFrameManager::InsertFrames directly) to add the new frames.
1907 // @return true if we reconstructed the containing block, false
1908 // otherwise
1909 bool WipeContainingBlock(nsFrameConstructorState& aState,
1910 nsIFrame* aContainingBlock, nsIFrame* aFrame,
1911 FrameConstructionItemList& aItems, bool aIsAppend,
1912 nsIFrame* aPrevSibling);
1914 void ReframeContainingBlock(nsIFrame* aFrame);
1916 //----------------------------------------
1918 // Methods support :first-letter style
1920 nsFirstLetterFrame* CreateFloatingLetterFrame(
1921 nsFrameConstructorState& aState, mozilla::dom::Text* aTextContent,
1922 nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
1923 ComputedStyle* aParentStyle, ComputedStyle* aComputedStyle,
1924 nsFrameList& aResult);
1926 void CreateLetterFrame(nsContainerFrame* aBlockFrame,
1927 nsContainerFrame* aBlockContinuation,
1928 mozilla::dom::Text* aTextContent,
1929 nsContainerFrame* aParentFrame, nsFrameList& aResult);
1931 void WrapFramesInFirstLetterFrame(nsContainerFrame* aBlockFrame,
1932 nsFrameList& aBlockFrames);
1935 * Looks in the block aBlockFrame for a text frame that contains the
1936 * first-letter of the block and creates the necessary first-letter frames
1937 * and returns them in aLetterFrames.
1939 * @param aBlockFrame the (first-continuation of) the block we are creating a
1940 * first-letter frame for
1941 * @param aBlockContinuation the current continuation of the block that we
1942 * are looking in for a textframe with suitable
1943 * contents for first-letter
1944 * @param aParentFrame the current frame whose children we are looking at for
1945 * a suitable first-letter textframe
1946 * @param aParentFrameList the first child of aParentFrame
1947 * @param aModifiedParent returns the parent of the textframe that contains
1948 * the first-letter
1949 * @param aTextFrame returns the textframe that had the first-letter
1950 * @param aPrevFrame returns the previous sibling of aTextFrame
1951 * @param aLetterFrames returns the frames that were created
1953 void WrapFramesInFirstLetterFrame(
1954 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
1955 nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
1956 nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
1957 nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking);
1959 void RecoverLetterFrames(nsContainerFrame* aBlockFrame);
1961 void RemoveLetterFrames(PresShell* aPresShell, nsContainerFrame* aBlockFrame);
1963 // Recursive helper for RemoveLetterFrames
1964 void RemoveFirstLetterFrames(PresShell* aPresShell, nsContainerFrame* aFrame,
1965 nsContainerFrame* aBlockFrame,
1966 bool* aStopLooking);
1968 // Special remove method for those pesky floating first-letter frames
1969 void RemoveFloatingFirstLetterFrames(PresShell* aPresShell,
1970 nsIFrame* aBlockFrame);
1972 // Capture state for the frame tree rooted at the frame associated with the
1973 // content object, aContent
1974 void CaptureStateForFramesOf(nsIContent* aContent,
1975 nsILayoutHistoryState* aHistoryState);
1977 //----------------------------------------
1979 // Methods support :first-line style
1981 // This method chops the initial inline-outside frames out of aFrameList.
1982 // If aLineFrame is non-null, it appends them to that frame. Otherwise, it
1983 // creates a new line frame, sets the inline frames as its initial child
1984 // list, and inserts that line frame at the front of what's left of
1985 // aFrameList. In both cases, the kids are reparented to the line frame.
1986 // After this call, aFrameList holds the frames that need to become kids of
1987 // the block (possibly including line frames).
1988 void WrapFramesInFirstLineFrame(nsFrameConstructorState& aState,
1989 nsIContent* aBlockContent,
1990 nsContainerFrame* aBlockFrame,
1991 nsFirstLineFrame* aLineFrame,
1992 nsFrameList& aFrameList);
1994 // Handle the case when a block with first-line style is appended to (by
1995 // possibly calling WrapFramesInFirstLineFrame as needed).
1996 void AppendFirstLineFrames(nsFrameConstructorState& aState,
1997 nsIContent* aContent,
1998 nsContainerFrame* aBlockFrame,
1999 nsFrameList& aFrameList);
2002 * When aFrameList is being inserted into aParentFrame, and aParentFrame has
2003 * pseudo-element-affected styles, it's possible that we're inserting under a
2004 * ::first-line frame. In that case, with servo's style system, the styles we
2005 * resolved for aFrameList are wrong (they don't take ::first-line into
2006 * account), and we should fix them up, which is what this method does.
2008 * This method does not mutate aFrameList.
2010 void CheckForFirstLineInsertion(nsIFrame* aParentFrame,
2011 nsFrameList& aFrameList);
2014 * Find the next frame for appending to a given insertion point.
2016 * We're appending, so this is almost always null, except for a few edge
2017 * cases.
2019 nsIFrame* FindNextSiblingForAppend(const InsertionPoint&);
2021 // The direction in which we should look for siblings.
2022 enum class SiblingDirection {
2023 Forward,
2024 Backward,
2028 * Find the frame for the content immediately next to the one aIter points to,
2029 * in the direction SiblingDirection indicates, following continuations if
2030 * necessary.
2032 * aIter is passed by const reference on purpose, so as not to modify the
2033 * caller's iterator.
2035 * @param aIter should be positioned such that aIter.GetPreviousChild()
2036 * is the first content to search for frames
2037 * @param aTargetContentDisplay the CSS display enum for the content aIter
2038 * points to if already known. It will be filled in if needed.
2040 template <SiblingDirection>
2041 nsIFrame* FindSibling(
2042 const mozilla::dom::FlattenedChildIterator& aIter,
2043 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2045 // Helper for the implementation of FindSibling.
2047 // Beware that this function does mutate the iterator.
2048 template <SiblingDirection>
2049 nsIFrame* FindSiblingInternal(
2050 mozilla::dom::FlattenedChildIterator&, nsIContent* aTargetContent,
2051 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2053 // An alias of FindSibling<SiblingDirection::Forward>.
2054 nsIFrame* FindNextSibling(
2055 const mozilla::dom::FlattenedChildIterator& aIter,
2056 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2057 // An alias of FindSibling<SiblingDirection::Backwards>.
2058 nsIFrame* FindPreviousSibling(
2059 const mozilla::dom::FlattenedChildIterator& aIter,
2060 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2062 // Given a potential first-continuation sibling frame for aTargetContent,
2063 // verify that it is an actual valid sibling for it, and return the
2064 // appropriate continuation the new frame for aTargetContent should be
2065 // inserted next to.
2066 nsIFrame* AdjustSiblingFrame(
2067 nsIFrame* aSibling, nsIContent* aTargetContent,
2068 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay,
2069 SiblingDirection aDirection);
2071 // Find the right previous sibling for an insertion. This also updates the
2072 // parent frame to point to the correct continuation of the parent frame to
2073 // use, and returns whether this insertion is to be treated as an append.
2074 // aChild is the child being inserted.
2075 // aIsRangeInsertSafe returns whether it is safe to do a range insert with
2076 // aChild being the first child in the range. It is the callers'
2077 // responsibility to check whether a range insert is safe with regards to
2078 // fieldsets.
2079 // The skip parameters are used to ignore a range of children when looking
2080 // for a sibling. All nodes starting from aStartSkipChild and up to but not
2081 // including aEndSkipChild will be skipped over when looking for sibling
2082 // frames. Skipping a range can deal with shadow DOM, but not when there are
2083 // multiple insertion points.
2084 nsIFrame* GetInsertionPrevSibling(InsertionPoint* aInsertion, // inout
2085 nsIContent* aChild, bool* aIsAppend,
2086 bool* aIsRangeInsertSafe,
2087 nsIContent* aStartSkipChild = nullptr,
2088 nsIContent* aEndSkipChild = nullptr);
2090 // see if aContent and aSibling are legitimate siblings due to restrictions
2091 // imposed by table columns
2092 // XXXbz this code is generally wrong, since the frame for aContent
2093 // may be constructed based on tag, not based on aDisplay!
2094 bool IsValidSibling(nsIFrame* aSibling, nsIContent* aContent,
2095 mozilla::Maybe<mozilla::StyleDisplay>& aDisplay);
2097 void QuotesDirty();
2098 void CountersDirty();
2100 void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
2101 nsContainerFrame* aFrame,
2102 nsIContent* aDocElement,
2103 nsFrameList&);
2105 public:
2106 friend class nsFrameConstructorState;
2108 private:
2109 // For allocating FrameConstructionItems from the mFCItemPool arena.
2110 friend struct FrameConstructionItem;
2111 void* AllocateFCItem();
2112 void FreeFCItem(FrameConstructionItem*);
2114 mozilla::dom::Document* mDocument; // Weak ref
2116 // See the comment at the start of ConstructRootFrame for more details
2117 // about the following frames.
2119 // This is just the outermost frame for the root element.
2120 nsContainerFrame* mRootElementFrame = nullptr;
2121 // This is the frame for the root element that has no pseudo-element style.
2122 nsIFrame* mRootElementStyleFrame = nullptr;
2123 // This is the containing block that contains the root element ---
2124 // the real "initial containing block" according to CSS 2.1.
2125 nsCanvasFrame* mDocElementContainingBlock = nullptr;
2126 // This is usually mDocElementContainingBlock, except when printing, where it
2127 // is the canvas frame that is under all the printed pages.
2128 nsCanvasFrame* mCanvasFrame = nullptr;
2129 nsPageSequenceFrame* mPageSequenceFrame = nullptr;
2131 // FrameConstructionItem arena + list of freed items available for re-use.
2132 mozilla::ArenaAllocator<4096, 8> mFCItemPool;
2134 // This indicates what page name to use for the next nsPageContentFrame.
2135 // Set when CSS named pages cause a breakpoint.
2136 // This does not apply to the first page content frame, which has its name
2137 // set by nsPageContentFrame::EnsurePageName() during first reflow.
2138 RefPtr<const nsAtom> mNextPageContentFramePageName;
2140 struct FreeFCItemLink {
2141 FreeFCItemLink* mNext;
2143 FreeFCItemLink* mFirstFreeFCItem;
2144 size_t mFCItemsInUse;
2146 mozilla::ContainStyleScopeManager mContainStyleScopeManager;
2148 // Current ProcessChildren depth.
2149 uint16_t mCurrentDepth;
2150 bool mQuotesDirty : 1;
2151 bool mCountersDirty : 1;
2152 bool mAlwaysCreateFramesForIgnorableWhitespace : 1;
2154 // The layout state from our history entry (to restore scroll positions and
2155 // such from history), or a new one if there was none (so we can store scroll
2156 // positions and such during reframe).
2158 // FIXME(bug 1397239): This can leak some state sometimes for the lifetime of
2159 // the frame constructor, which is not great.
2160 nsCOMPtr<nsILayoutHistoryState> mFrameTreeState;
2163 #endif /* nsCSSFrameConstructor_h___ */