Backed out changeset 2960ea3e50ca (bug 1881157) for causing crashtest assertion failu...
[gecko.git] / layout / base / nsCSSFrameConstructor.h
blobee6b3a5e14ebe4a002ab752c272ba7290e0c9db6
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);
301 * Sets the page name when a page break is being generated due to a change
302 * in page name.
304 * Should only be used during paginated reflow, to signal what page value
305 * the next page content frame should have.
307 * It is an error to set this if a new page name has already been set, either
308 * through SetNextPageContentFramePageName or
309 * MaybeSetNextPageContentFramePageName.
311 void SetNextPageContentFramePageName(const nsAtom* aPageName) {
312 MOZ_ASSERT(aPageName, "New page name should never be null");
313 MOZ_ASSERT(!mNextPageContentFramePageName,
314 "PageContentFrame page name was already set");
315 mNextPageContentFramePageName = aPageName;
319 * If a new page name has not been set for the next page, sets the value
320 * using the given frame.
322 * |aFrame| should be a frame to be placed on the new page.
324 * This function handles the work of resolving an atom for the frame, and
325 * avoids doing this extra work when not necessary.
327 * This is used during block reflow when a page break has occurred but it was
328 * not caused by a change in page name. It should only be used during
329 * paginated reflow.
331 void MaybeSetNextPageContentFramePageName(const nsIFrame* aFrame);
333 // Copy over fixed frames from aParentFrame's prev-in-flow
334 nsresult ReplicateFixedFrames(nsPageContentFrame* aParentFrame);
337 * Get the insertion point for aChild.
339 InsertionPoint GetInsertionPoint(nsIContent* aChild);
342 * Return the insertion frame of the primary frame of aContent, or its nearest
343 * ancestor that isn't display:contents.
345 nsContainerFrame* GetContentInsertionFrameFor(nsIContent* aContent);
347 // GetInitialContainingBlock() is deprecated in favor of
348 // GetRootElementFrame(); nsIFrame* GetInitialContainingBlock() { return
349 // mRootElementFrame; } This returns the outermost frame for the root element
350 nsContainerFrame* GetRootElementFrame() { return mRootElementFrame; }
351 // This returns the frame for the root element that does not
352 // have a psuedo-element style
353 nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; }
354 nsPageSequenceFrame* GetPageSequenceFrame() { return mPageSequenceFrame; }
355 // Returns the outermost canvas frame. There's usually one per document, but
356 // if but if we're in printing / paginated mode we might have multiple: one
357 // per page plus the background one.
358 nsCanvasFrame* GetCanvasFrame() { return mCanvasFrame; }
359 // Get the frame that is the parent of the root element's frame.
360 nsCanvasFrame* GetDocElementContainingBlock() {
361 return mDocElementContainingBlock;
364 void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
366 #if defined(ACCESSIBILITY) || defined(MOZ_LAYOUT_DEBUGGER)
367 // Exposed only for nsLayoutUtils::GetMarkerSpokenText and
368 // nsLayoutDebuggingTools to use.
369 mozilla::ContainStyleScopeManager& GetContainStyleScopeManager() {
370 return mContainStyleScopeManager;
372 #endif
374 private:
375 struct FrameConstructionItem;
376 class FrameConstructionItemList;
378 mozilla::PrintedSheetFrame* ConstructPrintedSheetFrame(
379 PresShell* aPresShell, nsContainerFrame* aParentFrame,
380 nsIFrame* aPrevSheetFrame);
382 nsContainerFrame* ConstructPageFrame(PresShell* aPresShell,
383 nsContainerFrame* aParentFrame,
384 nsIFrame* aPrevPageFrame,
385 nsCanvasFrame*& aCanvasFrame);
387 void InitAndRestoreFrame(const nsFrameConstructorState& aState,
388 nsIContent* aContent, nsContainerFrame* aParentFrame,
389 nsIFrame* aNewFrame, bool aAllowCounters = true);
391 already_AddRefed<ComputedStyle> ResolveComputedStyle(nsIContent* aContent);
393 enum class ItemFlag : uint8_t {
394 // Allow page-break before and after items to be created if the
395 // style asks for them.
396 AllowPageBreak,
397 IsGeneratedContent,
398 IsWithinSVGText,
399 // The item allows items to be created for SVG <textPath> children.
400 AllowTextPathChild,
401 // The item is content created by an nsIAnonymousContentCreator frame.
402 IsAnonymousContentCreatorContent,
403 // The item will be the rendered legend of a <fieldset>.
404 IsForRenderedLegend,
405 // This will be an outside ::marker.
406 IsForOutsideMarker,
409 using ItemFlags = mozilla::EnumSet<ItemFlag>;
411 // Add the frame construction items for the given aContent and aParentFrame
412 // to the list. This might add more than one item in some rare cases.
413 // If aSuppressWhiteSpaceOptimizations is true, optimizations that
414 // may suppress the construction of white-space-only text frames
415 // must be skipped for these items and items around them.
416 void AddFrameConstructionItems(nsFrameConstructorState& aState,
417 nsIContent* aContent,
418 bool aSuppressWhiteSpaceOptimizations,
419 const ComputedStyle& aParentStyle,
420 const InsertionPoint& aInsertion,
421 FrameConstructionItemList& aItems,
422 ItemFlags = {});
424 // Helper method for AddFrameConstructionItems etc.
425 // Unsets the need-frame/restyle bits on aContent.
426 // return true iff we should attempt to create frames for aContent.
427 bool ShouldCreateItemsForChild(nsFrameConstructorState& aState,
428 nsIContent* aContent,
429 nsContainerFrame* aParentFrame);
431 // Construct the frames for the document element. This can return null if the
432 // document element is display:none, or if it's an SVG element that's not
433 // <svg>, etc.
434 nsIFrame* ConstructDocElementFrame(Element* aDocElement);
436 // Set up our mDocElementContainingBlock correctly for the given root
437 // content.
438 void SetUpDocElementContainingBlock(nsIContent* aDocElement);
441 * CreateAttributeContent creates a single content/frame combination for an
442 * |attr(foo)| generated content.
444 * @param aParentContent the parent content for the generated content (that
445 * is, the originating element).
446 * @param aParentFrame the parent frame for the generated frame
447 * @param aAttrNamespace the namespace of the attribute in question
448 * @param aAttrName the localname of the attribute
449 * @param aComputedStyle the style to use
450 * @param aGeneratedContent the array of generated content to append the
451 * created content to.
452 * @param [out] aNewContent the content node we create
453 * @param [out] aNewFrame the new frame we create
455 void CreateAttributeContent(const Element& aParentContent,
456 nsIFrame* aParentFrame, int32_t aAttrNamespace,
457 nsAtom* aAttrName, ComputedStyle* aComputedStyle,
458 nsCOMArray<nsIContent>& aGeneratedContent,
459 nsIContent** aNewContent, nsIFrame** aNewFrame);
462 * Create a text node containing the given string. If aText is non-null
463 * then we also set aText to the returned node.
465 already_AddRefed<nsIContent> CreateGenConTextNode(
466 nsFrameConstructorState& aState, const nsAString& aString,
467 mozilla::UniquePtr<nsGenConInitializer> aInitializer);
470 * Create a content node for the given generated content style.
471 * The caller takes care of making it SetIsNativeAnonymousRoot, binding it
472 * to the document, and creating frames for it.
473 * @param aOriginatingElement is the node that has the before/after style.
474 * @param aComputedStyle is the 'before' or 'after' pseudo-element style.
475 * @param aContentIndex is the index of the content item to create.
476 * @param aAddChild callback to be called for each generated content child.
478 void CreateGeneratedContent(
479 nsFrameConstructorState& aState, Element& aOriginatingElement,
480 ComputedStyle& aPseudoStyle, uint32_t aContentIndex,
481 const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
484 * Create child content nodes for a ::marker from its 'list-style-*' values.
486 void CreateGeneratedContentFromListStyle(
487 nsFrameConstructorState& aState, Element& aOriginatingElement,
488 const ComputedStyle& aPseudoStyle,
489 const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
491 * Create child content nodes for a ::marker from its 'list-style-type'.
493 void CreateGeneratedContentFromListStyleType(
494 nsFrameConstructorState& aState, Element& aOriginatingElement,
495 const ComputedStyle& aPseudoStyle,
496 const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
498 // aParentFrame may be null; this method doesn't use it directly in any case.
499 void CreateGeneratedContentItem(nsFrameConstructorState& aState,
500 nsContainerFrame* aParentFrame,
501 Element& aOriginatingElement, ComputedStyle&,
502 PseudoStyleType aPseudoElement,
503 FrameConstructionItemList& aItems,
504 ItemFlags aExtraFlags = {});
506 // This method is called by ContentAppended() and ContentRangeInserted() when
507 // appending flowed frames to a parent's principal child list. It handles the
508 // case where the parent is the trailing inline of an ib-split or is the last
509 // continuation of a ::-moz-column-content in an nsColumnSetFrame.
511 // This method can change aFrameList: it can chop off the beginning and put it
512 // in aParentFrame while either putting the remainder into an ib-split sibling
513 // of aParentFrame or creating aParentFrame's column-span siblings for the
514 // remainder.
516 // aPrevSibling must be the frame after which aFrameList is to be placed on
517 // aParentFrame's principal child list. It may be null if aFrameList is being
518 // added at the beginning of the child list.
519 void AppendFramesToParent(nsFrameConstructorState& aState,
520 nsContainerFrame* aParentFrame,
521 nsFrameList& aFrameList, nsIFrame* aPrevSibling,
522 bool aIsRecursiveCall = false);
524 // BEGIN TABLE SECTION
526 * Construct a table wrapper frame. This is the FrameConstructionData
527 * callback used for the job.
529 nsIFrame* ConstructTable(nsFrameConstructorState& aState,
530 FrameConstructionItem& aItem,
531 nsContainerFrame* aParentFrame,
532 const nsStyleDisplay* aDisplay,
533 nsFrameList& aFrameList);
536 * FrameConstructionData callback for constructing table rows and row groups.
538 nsIFrame* ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
539 FrameConstructionItem& aItem,
540 nsContainerFrame* aParentFrame,
541 const nsStyleDisplay* aStyleDisplay,
542 nsFrameList& aFrameList);
545 * FrameConstructionData callback used for constructing table columns.
547 nsIFrame* ConstructTableCol(nsFrameConstructorState& aState,
548 FrameConstructionItem& aItem,
549 nsContainerFrame* aParentFrame,
550 const nsStyleDisplay* aStyleDisplay,
551 nsFrameList& aFrameList);
554 * FrameConstructionData callback used for constructing table cells.
556 nsIFrame* ConstructTableCell(nsFrameConstructorState& aState,
557 FrameConstructionItem& aItem,
558 nsContainerFrame* aParentFrame,
559 const nsStyleDisplay* aStyleDisplay,
560 nsFrameList& aFrameList);
562 private:
563 /* An enum of possible parent types for anonymous table or ruby object
564 construction */
565 enum ParentType {
566 eTypeBlock = 0, /* This includes all non-table-related frames */
567 eTypeRow,
568 eTypeRowGroup,
569 eTypeColGroup,
570 eTypeTable,
571 eTypeRuby,
572 eTypeRubyBase,
573 eTypeRubyBaseContainer,
574 eTypeRubyText,
575 eTypeRubyTextContainer,
576 eParentTypeCount
579 /* 4 bits is enough to handle our ParentType values */
580 #define FCDATA_PARENT_TYPE_OFFSET 28
581 /* Macro to get the desired parent type out of an mBits member of
582 FrameConstructionData */
583 #define FCDATA_DESIRED_PARENT_TYPE(_bits) \
584 ParentType((_bits) >> FCDATA_PARENT_TYPE_OFFSET)
585 /* Macro to create FrameConstructionData bits out of a desired parent type */
586 #define FCDATA_DESIRED_PARENT_TYPE_TO_BITS(_type) \
587 (((uint32_t)(_type)) << FCDATA_PARENT_TYPE_OFFSET)
589 /* Get the parent type that aParentFrame has. */
590 static ParentType GetParentType(nsIFrame* aParentFrame) {
591 return GetParentType(aParentFrame->Type());
594 /* Get the parent type for the given LayoutFrameType */
595 static ParentType GetParentType(mozilla::LayoutFrameType aFrameType);
597 static bool IsRubyParentType(ParentType aParentType) {
598 return (aParentType == eTypeRuby || aParentType == eTypeRubyBase ||
599 aParentType == eTypeRubyBaseContainer ||
600 aParentType == eTypeRubyText ||
601 aParentType == eTypeRubyTextContainer);
604 static bool IsTableParentType(ParentType aParentType) {
605 return (aParentType == eTypeTable || aParentType == eTypeRow ||
606 aParentType == eTypeRowGroup || aParentType == eTypeColGroup);
609 /* A constructor function that just creates an nsIFrame object. The caller
610 is responsible for initializing the object, adding it to frame lists,
611 constructing frames for the children, etc.
613 @param PresShell the presshell whose arena should be used to allocate
614 the frame.
615 @param ComputedStyle the style to use for the frame. */
616 using FrameCreationFunc = nsIFrame* (*)(PresShell*, ComputedStyle*);
617 using ContainerFrameCreationFunc = nsContainerFrame* (*)(PresShell*,
618 ComputedStyle*);
619 using BlockFrameCreationFunc = nsBlockFrame* (*)(PresShell*, ComputedStyle*);
621 /* A function that can be used to get a FrameConstructionData. Such
622 a function is allowed to return null.
624 @param nsIContent the node for which the frame is being constructed.
625 @param ComputedStyle the style to be used for the frame.
627 struct FrameConstructionData;
628 using FrameConstructionDataGetter =
629 const FrameConstructionData* (*)(const Element&, ComputedStyle&);
631 /* A constructor function that's used for complicated construction tasks.
632 This is expected to create the new frame, initialize it, add whatever
633 needs to be added to aFrameList (XXXbz is that really necessary? Could
634 caller add? Might there be cases when the returned frame or its
635 placeholder is not the thing that ends up in aFrameList? If not, would
636 it be safe to do the add into the frame construction state after
637 processing kids? Look into this as a followup!), process children as
638 needed, etc. It is NOT expected to deal with setting the frame on the
639 content.
641 @param aState the frame construction state to use.
642 @param aItem the frame construction item to use
643 @param aParentFrame the frame to set as the parent of the
644 newly-constructed frame.
645 @param aStyleDisplay the display struct from aItem's mComputedStyle
646 @param aFrameList the frame list to add the new frame (or its
647 placeholder) to.
648 @return the frame that was constructed. This frame is what the caller
649 will set as the frame on the content. Guaranteed non-null.
651 using FrameFullConstructor =
652 nsIFrame* (nsCSSFrameConstructor::*)(nsFrameConstructorState& aState,
653 FrameConstructionItem& aItem,
654 nsContainerFrame* aParentFrame,
655 const nsStyleDisplay* aStyleDisplay,
656 nsFrameList& aFrameList);
658 /* Bits that modify the way a FrameConstructionData is handled */
660 /* If the FCDATA_SKIP_FRAMESET bit is set, then the frame created should not
661 be set as the primary frame on the content node. This should only be used
662 in very rare cases when we create more than one frame for a given content
663 node. */
664 #define FCDATA_SKIP_FRAMESET 0x1
665 /* If the FCDATA_FUNC_IS_DATA_GETTER bit is set, then the mFunc of the
666 FrameConstructionData is a getter function that can be used to get the
667 actual FrameConstructionData to use. */
668 #define FCDATA_FUNC_IS_DATA_GETTER 0x2
669 /* If the FCDATA_FUNC_IS_FULL_CTOR bit is set, then the FrameConstructionData
670 has an mFullConstructor. In this case, there is no relevant mData or
671 mFunc */
672 #define FCDATA_FUNC_IS_FULL_CTOR 0x4
673 /* If FCDATA_DISALLOW_OUT_OF_FLOW is set, do not allow the frame to
674 float or be absolutely positioned. This can also be used with
675 FCDATA_FUNC_IS_FULL_CTOR to indicate what the full-constructor
676 function will do. */
677 #define FCDATA_DISALLOW_OUT_OF_FLOW 0x8
678 /* If FCDATA_FORCE_NULL_ABSPOS_CONTAINER is set, make sure to push a
679 null absolute containing block before processing children for this
680 frame. If this is not set, the frame will be pushed as the
681 absolute containing block as needed, based on its style */
682 #define FCDATA_FORCE_NULL_ABSPOS_CONTAINER 0x10
683 /* If FCDATA_WRAP_KIDS_IN_BLOCKS is set, the inline kids of the frame
684 will be wrapped in blocks. This is only usable for MathML at the
685 moment. */
686 #define FCDATA_WRAP_KIDS_IN_BLOCKS 0x20
687 /* If FCDATA_SUPPRESS_FRAME is set, no frame should be created for the
688 content. If this bit is set, nothing else in the struct needs to be
689 set. */
690 #define FCDATA_SUPPRESS_FRAME 0x40
691 /* If FCDATA_MAY_NEED_SCROLLFRAME is set, the new frame should be wrapped in
692 a scrollframe if its overflow type so requires. */
693 #define FCDATA_MAY_NEED_SCROLLFRAME 0x80
694 /* If FCDATA_IS_POPUP is set, the new frame is a XUL popup frame. These need
695 some really weird special handling. */
696 #define FCDATA_IS_POPUP 0x100
697 /* If FCDATA_SKIP_ABSPOS_PUSH is set, don't push this frame as an
698 absolute containing block, no matter what its style says. */
699 #define FCDATA_SKIP_ABSPOS_PUSH 0x200
700 /* If FCDATA_DISALLOW_GENERATED_CONTENT is set, then don't allow generated
701 content when processing kids of this frame. This should not be used with
702 FCDATA_FUNC_IS_FULL_CTOR */
703 #define FCDATA_DISALLOW_GENERATED_CONTENT 0x400
704 /* If FCDATA_IS_TABLE_PART is set, then the frame is some sort of
705 table-related thing and we should not attempt to fetch a table-cell parent
706 for it if it's inside another table-related frame. */
707 #define FCDATA_IS_TABLE_PART 0x800
708 /* If FCDATA_IS_INLINE is set, then the frame is a non-replaced CSS
709 inline box. */
710 #define FCDATA_IS_INLINE 0x1000
711 /* If FCDATA_IS_LINE_PARTICIPANT is set, the frame is something that will
712 return true for IsLineParticipant() */
713 #define FCDATA_IS_LINE_PARTICIPANT 0x2000
714 /* If FCDATA_IS_LINE_BREAK is set, the frame is something that will
715 induce a line break boundary before and after itself. */
716 #define FCDATA_IS_LINE_BREAK 0x4000
717 /* If FCDATA_ALLOW_BLOCK_STYLES is set, allow block styles when processing
718 children of a block (i.e. allow ::first-letter/line).
719 This should not be used with FCDATA_FUNC_IS_FULL_CTOR. */
720 #define FCDATA_ALLOW_BLOCK_STYLES 0x8000
721 /* If FCDATA_USE_CHILD_ITEMS is set, then use the mChildItems in the relevant
722 FrameConstructionItem instead of trying to process the content's children.
723 This can be used with or without FCDATA_FUNC_IS_FULL_CTOR.
724 The child items might still need table pseudo processing. */
725 #define FCDATA_USE_CHILD_ITEMS 0x10000
726 /* If FCDATA_FORCED_NON_SCROLLABLE_BLOCK is set, then this block
727 would have been scrollable but has been forced to be
728 non-scrollable due to being in a paginated context. */
729 #define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000
730 /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a
731 block formatting context wrapper around the kids of this frame
732 using the FrameConstructionData's mPseudoAtom for its anonymous
733 box type. */
734 #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000
735 /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of
736 an SVG text frame. */
737 #define FCDATA_IS_SVG_TEXT 0x80000
739 * If FCDATA_ALLOW_GRID_FLEX_COLUMN is set, then we should create a
740 * grid/flex/column container instead of a block wrapper when the styles says
741 * so. This bit is meaningful only if FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS
742 * is also set.
744 #define FCDATA_ALLOW_GRID_FLEX_COLUMN 0x200000
746 * Whether the kids of this FrameConstructionData should be flagged as having
747 * a wrapper anon box parent. This should only be set if
748 * FCDATA_USE_CHILD_ITEMS is set.
750 #define FCDATA_IS_WRAPPER_ANON_BOX 0x400000
752 /* Structure representing information about how a frame should be
753 constructed. */
754 struct FrameConstructionData {
755 // We have exactly one of three types of functions, so use a union for
756 // better cache locality.
757 union Func {
758 FrameCreationFunc mCreationFunc;
759 FrameConstructionDataGetter mDataGetter;
760 FrameFullConstructor mFullConstructor;
762 explicit constexpr Func(FrameCreationFunc aFunc) : mCreationFunc(aFunc) {}
763 explicit constexpr Func(FrameConstructionDataGetter aDataGetter)
764 : mDataGetter(aDataGetter) {}
765 explicit constexpr Func(FrameFullConstructor aCtor)
766 : mFullConstructor(aCtor) {}
767 } mFunc;
768 // Flag bits that can modify the way the construction happens
769 const uint32_t mBits = 0;
770 // For cases when FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, the
771 // anonymous box type to use for that wrapper.
772 PseudoStyleType const mAnonBoxPseudo = PseudoStyleType::NotPseudo;
774 constexpr FrameConstructionData() : FrameConstructionData(nullptr) {}
776 MOZ_IMPLICIT constexpr FrameConstructionData(std::nullptr_t,
777 uint32_t aBits = 0)
778 : mFunc(static_cast<FrameCreationFunc>(nullptr)), mBits(aBits) {}
780 MOZ_IMPLICIT constexpr FrameConstructionData(
781 FrameCreationFunc aCreationFunc, uint32_t aBits = 0)
782 : mFunc(aCreationFunc), mBits(aBits) {}
783 constexpr FrameConstructionData(FrameCreationFunc aCreationFunc,
784 uint32_t aBits,
785 PseudoStyleType aAnonBoxPseudo)
786 : mFunc(aCreationFunc),
787 mBits(aBits | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS),
788 mAnonBoxPseudo(aAnonBoxPseudo) {}
789 MOZ_IMPLICIT constexpr FrameConstructionData(
790 FrameConstructionDataGetter aDataGetter, uint32_t aBits = 0)
791 : mFunc(aDataGetter),
792 mBits(aBits | FCDATA_FUNC_IS_DATA_GETTER),
793 mAnonBoxPseudo(PseudoStyleType::NotPseudo) {}
794 MOZ_IMPLICIT constexpr FrameConstructionData(FrameFullConstructor aCtor,
795 uint32_t aBits = 0)
796 : mFunc(aCtor),
797 mBits(aBits | FCDATA_FUNC_IS_FULL_CTOR),
798 mAnonBoxPseudo(PseudoStyleType::NotPseudo) {}
801 /* Structure representing a mapping of an atom to a FrameConstructionData.
802 This can be used with non-static atoms, assuming that the nsAtom* is
803 stored somewhere that this struct can point to (that is, a static
804 nsAtom*) and that it's allocated before the struct is ever used. */
805 struct FrameConstructionDataByTag {
806 const nsStaticAtom* const mTag;
807 const FrameConstructionData mData;
810 /* Structure representing a mapping of an integer to a
811 FrameConstructionData. There are no magic integer values here. */
812 struct FrameConstructionDataByInt {
813 /* Could be used for display or whatever else */
814 const int32_t mInt;
815 const FrameConstructionData mData;
818 struct FrameConstructionDataByDisplay {
819 #ifdef DEBUG
820 const mozilla::StyleDisplay mDisplay;
821 #endif
822 const FrameConstructionData mData;
825 /* Structure that has a FrameConstructionData and style pseudo-type
826 for a table pseudo-frame */
827 struct PseudoParentData {
828 const FrameConstructionData mFCData;
829 mozilla::PseudoStyleType const mPseudoType;
831 /* Array of such structures that we use to properly construct table
832 pseudo-frames as needed */
833 static const PseudoParentData sPseudoParentData[eParentTypeCount];
835 const FrameConstructionData* FindDataForContent(nsIContent&, ComputedStyle&,
836 nsIFrame* aParentFrame,
837 ItemFlags aFlags);
839 // aParentFrame might be null. If it is, that means it was an inline frame.
840 static const FrameConstructionData* FindTextData(const Text&,
841 nsIFrame* aParentFrame);
842 const FrameConstructionData* FindElementData(const Element&, ComputedStyle&,
843 nsIFrame* aParentFrame,
844 ItemFlags aFlags);
845 const FrameConstructionData* FindElementTagData(const Element&,
846 ComputedStyle&,
847 nsIFrame* aParentFrame,
848 ItemFlags aFlags);
850 /* A function that takes an integer, content, style, and array of
851 FrameConstructionDataByInts and finds the appropriate frame construction
852 data to use and returns it. This can return null if none of the integers
853 match or if the matching integer has a FrameConstructionDataGetter that
854 returns null. */
855 static const FrameConstructionData* FindDataByInt(
856 int32_t aInt, const Element&, ComputedStyle&,
857 const FrameConstructionDataByInt* aDataPtr, uint32_t aDataLength);
860 * A function that takes a tag, content, style, and array of
861 * FrameConstructionDataByTags and finds the appropriate frame construction
862 * data to use and returns it.
864 * This can return null if none of the tags match or if the matching tag has a
865 * FrameConstructionDataGetter that returns null. In the case that the tags
866 * actually match, aTagFound will be true, even if the return value is null.
868 static const FrameConstructionData* FindDataByTag(
869 const Element& aElement, ComputedStyle& aComputedStyle,
870 const FrameConstructionDataByTag* aDataPtr, uint32_t aDataLength);
872 /* A class representing a list of FrameConstructionItems. Instances of this
873 class are only created as AutoFrameConstructionItemList, or as a member
874 of FrameConstructionItem. */
875 class FrameConstructionItemList {
876 public:
877 void Reset(nsCSSFrameConstructor* aFCtor) {
878 Destroy(aFCtor);
879 this->~FrameConstructionItemList();
880 new (this) FrameConstructionItemList();
883 void SetLineBoundaryAtStart(bool aBoundary) {
884 mLineBoundaryAtStart = aBoundary;
886 void SetLineBoundaryAtEnd(bool aBoundary) {
887 mLineBoundaryAtEnd = aBoundary;
889 void SetParentHasNoShadowDOM(bool aValue) {
890 mParentHasNoShadowDOM = aValue;
892 bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
893 bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
894 bool ParentHasNoShadowDOM() { return mParentHasNoShadowDOM; }
895 bool IsEmpty() const { return mItems.isEmpty(); }
896 bool AreAllItemsInline() const { return mInlineCount == mItemCount; }
897 bool AreAllItemsBlock() const { return mBlockCount == mItemCount; }
898 bool AllWantParentType(ParentType aDesiredParentType) const {
899 return mDesiredParentCounts[aDesiredParentType] == mItemCount;
902 // aSuppressWhiteSpaceOptimizations is true if optimizations that
903 // skip constructing whitespace frames for this item or items
904 // around it cannot be performed.
905 // Also, the return value is always non-null, thanks to infallible 'new'.
906 FrameConstructionItem* AppendItem(
907 nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
908 nsIContent* aContent, already_AddRefed<ComputedStyle>&& aComputedStyle,
909 bool aSuppressWhiteSpaceOptimizations) {
910 FrameConstructionItem* item = new (aFCtor)
911 FrameConstructionItem(aFCData, aContent, std::move(aComputedStyle),
912 aSuppressWhiteSpaceOptimizations);
913 mItems.insertBack(item);
914 ++mItemCount;
915 ++mDesiredParentCounts[item->DesiredParentType()];
916 return item;
919 // Arguments are the same as AppendItem().
920 FrameConstructionItem* PrependItem(
921 nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
922 nsIContent* aContent, already_AddRefed<ComputedStyle>&& aComputedStyle,
923 bool aSuppressWhiteSpaceOptimizations) {
924 FrameConstructionItem* item = new (aFCtor)
925 FrameConstructionItem(aFCData, aContent, std::move(aComputedStyle),
926 aSuppressWhiteSpaceOptimizations);
927 mItems.insertFront(item);
928 ++mItemCount;
929 ++mDesiredParentCounts[item->DesiredParentType()];
930 return item;
933 void InlineItemAdded() { ++mInlineCount; }
934 void BlockItemAdded() { ++mBlockCount; }
936 class Iterator {
937 public:
938 explicit Iterator(FrameConstructionItemList& aList)
939 : mCurrent(aList.mItems.getFirst()), mList(aList) {}
940 Iterator(const Iterator& aOther) = default;
942 bool operator==(const Iterator& aOther) const {
943 MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
944 return mCurrent == aOther.mCurrent;
946 bool operator!=(const Iterator& aOther) const {
947 return !(*this == aOther);
949 Iterator& operator=(const Iterator& aOther) {
950 MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
951 mCurrent = aOther.mCurrent;
952 return *this;
955 FrameConstructionItemList* List() { return &mList; }
957 FrameConstructionItem& item() {
958 MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
959 return *mCurrent;
962 const FrameConstructionItem& item() const {
963 MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
964 return *mCurrent;
967 bool IsDone() const { return mCurrent == nullptr; }
968 bool AtStart() const { return mCurrent == mList.mItems.getFirst(); }
969 void Next() {
970 NS_ASSERTION(!IsDone(), "Should have checked IsDone()!");
971 mCurrent = mCurrent->getNext();
973 void Prev() {
974 NS_ASSERTION(!AtStart(), "Should have checked AtStart()!");
975 mCurrent = mCurrent ? mCurrent->getPrevious() : mList.mItems.getLast();
977 void SetToEnd() { mCurrent = nullptr; }
979 // Skip over all items that want the given parent type. Return whether
980 // the iterator is done after doing that. The iterator must not be done
981 // when this is called.
982 inline bool SkipItemsWantingParentType(ParentType aParentType);
984 // Skip over all items that want a parent type different from the given
985 // one. Return whether the iterator is done after doing that. The
986 // iterator must not be done when this is called.
987 inline bool SkipItemsNotWantingParentType(ParentType aParentType);
989 // Skip over non-replaced inline frames and positioned frames.
990 // Return whether the iterator is done after doing that.
991 // The iterator must not be done when this is called.
992 inline bool SkipItemsThatNeedAnonFlexOrGridItem(
993 const nsFrameConstructorState& aState, bool aIsWebkitBox);
995 // Skip to the first frame that is a non-replaced inline or is
996 // positioned. Return whether the iterator is done after doing that.
997 // The iterator must not be done when this is called.
998 inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
999 const nsFrameConstructorState& aState, bool aIsWebkitBox);
1001 // Skip over all items that do not want a ruby parent. Return whether
1002 // the iterator is done after doing that. The iterator must not be done
1003 // when this is called.
1004 inline bool SkipItemsNotWantingRubyParent();
1006 // Skip over whitespace. Return whether the iterator is done after doing
1007 // that. The iterator must not be done, and must be pointing to a
1008 // whitespace item when this is called.
1009 inline bool SkipWhitespace(nsFrameConstructorState& aState);
1011 // Remove the item pointed to by this iterator from its current list and
1012 // Append it to aTargetList. This iterator is advanced to point to the
1013 // next item in its list. aIter must not be done. aTargetList must not
1014 // be the list this iterator is iterating over..
1015 void AppendItemToList(FrameConstructionItemList& aTargetList);
1017 // As above, but moves all items starting with this iterator until we
1018 // get to aEnd; the item pointed to by aEnd is not stolen. This method
1019 // might have optimizations over just looping and doing StealItem for
1020 // some special cases. After this method returns, this iterator will
1021 // point to the item aEnd points to now; aEnd is not modified.
1022 // aTargetList must not be the list this iterator is iterating over.
1023 void AppendItemsToList(nsCSSFrameConstructor* aFCtor,
1024 const Iterator& aEnd,
1025 FrameConstructionItemList& aTargetList);
1027 // Insert aItem in this iterator's list right before the item pointed to
1028 // by this iterator. After the insertion, this iterator will continue to
1029 // point to the item it now points to (the one just after the
1030 // newly-inserted item). This iterator is allowed to be done; in that
1031 // case this call just appends the given item to the list.
1032 void InsertItem(FrameConstructionItem* aItem);
1034 // Delete the items between this iterator and aEnd, including the item
1035 // this iterator currently points to but not including the item pointed
1036 // to by aEnd. When this returns, this iterator will point to the same
1037 // item as aEnd. This iterator must not equal aEnd when this method is
1038 // called.
1039 void DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd);
1041 private:
1042 FrameConstructionItem* mCurrent;
1043 FrameConstructionItemList& mList;
1046 protected:
1047 FrameConstructionItemList()
1048 : mInlineCount(0),
1049 mBlockCount(0),
1050 mItemCount(0),
1051 mLineBoundaryAtStart(false),
1052 mLineBoundaryAtEnd(false),
1053 mParentHasNoShadowDOM(false) {
1054 MOZ_COUNT_CTOR(FrameConstructionItemList);
1055 memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
1058 void Destroy(nsCSSFrameConstructor* aFCtor) {
1059 while (FrameConstructionItem* item = mItems.popFirst()) {
1060 item->Delete(aFCtor);
1064 // Prevent stack instances (except as AutoFrameConstructionItemList).
1065 friend struct FrameConstructionItem;
1066 ~FrameConstructionItemList() {
1067 MOZ_COUNT_DTOR(FrameConstructionItemList);
1068 MOZ_ASSERT(mItems.isEmpty(), "leaking");
1071 private:
1072 // Not allocated from the heap!
1073 void* operator new(size_t) = delete;
1074 void* operator new[](size_t) = delete;
1075 #ifdef _MSC_VER /* Visual Studio */
1076 void operator delete(void*) { MOZ_CRASH("FrameConstructionItemList::del"); }
1077 #else
1078 void operator delete(void*) = delete;
1079 #endif
1080 void operator delete[](void*) = delete;
1081 // Placement new is used by Reset().
1082 void* operator new(size_t, void* aPtr) { return aPtr; }
1084 struct UndisplayedItem {
1085 UndisplayedItem(nsIContent* aContent, ComputedStyle* aComputedStyle)
1086 : mContent(aContent), mComputedStyle(aComputedStyle) {}
1088 nsIContent* const mContent;
1089 RefPtr<ComputedStyle> mComputedStyle;
1092 // Adjust our various counts for aItem being added or removed. aDelta
1093 // should be either +1 or -1 depending on which is happening.
1094 void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta);
1096 mozilla::LinkedList<FrameConstructionItem> mItems;
1097 uint32_t mInlineCount;
1098 uint32_t mBlockCount;
1099 uint32_t mItemCount;
1100 uint32_t mDesiredParentCounts[eParentTypeCount];
1101 // True if there is guaranteed to be a line boundary before the
1102 // frames created by these items
1103 bool mLineBoundaryAtStart;
1104 // True if there is guaranteed to be a line boundary after the
1105 // frames created by these items
1106 bool mLineBoundaryAtEnd;
1107 // True if the parent is guaranteed to have no shadow tree.
1108 bool mParentHasNoShadowDOM;
1111 /* A struct representing a list of FrameConstructionItems on the stack. */
1112 struct MOZ_RAII AutoFrameConstructionItemList final
1113 : public FrameConstructionItemList {
1114 template <typename... Args>
1115 explicit AutoFrameConstructionItemList(nsCSSFrameConstructor* aFCtor,
1116 Args&&... args)
1117 : FrameConstructionItemList(std::forward<Args>(args)...),
1118 mFCtor(aFCtor) {
1119 MOZ_ASSERT(mFCtor);
1121 ~AutoFrameConstructionItemList() { Destroy(mFCtor); }
1123 private:
1124 nsCSSFrameConstructor* const mFCtor;
1127 typedef FrameConstructionItemList::Iterator FCItemIterator;
1129 /* A struct representing an item for which frames might need to be
1130 * constructed. This contains all the information needed to construct the
1131 * frame other than the parent frame and whatever would be stored in the
1132 * frame constructor state. You probably want to use
1133 * AutoFrameConstructionItem instead of this struct. */
1134 struct FrameConstructionItem final
1135 : public mozilla::LinkedListElement<FrameConstructionItem> {
1136 FrameConstructionItem(const FrameConstructionData* aFCData,
1137 nsIContent* aContent,
1138 already_AddRefed<ComputedStyle>&& aComputedStyle,
1139 bool aSuppressWhiteSpaceOptimizations)
1140 : mFCData(aFCData),
1141 mContent(aContent),
1142 mComputedStyle(std::move(aComputedStyle)),
1143 mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations),
1144 mIsText(false),
1145 mIsGeneratedContent(false),
1146 mIsAllInline(false),
1147 mIsBlock(false),
1148 mIsPopup(false),
1149 mIsLineParticipant(false),
1150 mIsRenderedLegend(false) {
1151 MOZ_COUNT_CTOR(FrameConstructionItem);
1154 void* operator new(size_t, nsCSSFrameConstructor* aFCtor) {
1155 return aFCtor->AllocateFCItem();
1158 void Delete(nsCSSFrameConstructor* aFCtor) {
1159 mChildItems.Destroy(aFCtor);
1160 if (mIsGeneratedContent) {
1161 mContent->UnbindFromTree();
1162 NS_RELEASE(mContent);
1164 this->~FrameConstructionItem();
1165 aFCtor->FreeFCItem(this);
1168 ParentType DesiredParentType() {
1169 return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
1172 // Indicates whether (when in a flex or grid container) this item needs
1173 // to be wrapped in an anonymous block. (Note that we implement
1174 // -webkit-box/-webkit-inline-box using our standard flexbox frame class,
1175 // but we use different rules for what gets wrapped. The aIsWebkitBox
1176 // parameter here tells us whether to use those different rules.)
1177 bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
1178 bool aIsWebkitBox);
1180 // Don't call this unless the frametree really depends on the answer!
1181 // Especially so for generated content, where we don't want to reframe
1182 // things.
1183 bool IsWhitespace(nsFrameConstructorState& aState) const;
1185 bool IsLineBoundary() const {
1186 return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK);
1189 // Child frame construction items.
1190 FrameConstructionItemList mChildItems;
1192 // The FrameConstructionData to use.
1193 const FrameConstructionData* mFCData;
1194 // The nsIContent node to use when initializing the new frame.
1195 nsIContent* mContent;
1196 // The style to use for creating the new frame.
1197 RefPtr<ComputedStyle> mComputedStyle;
1198 // Whether optimizations to skip constructing textframes around
1199 // this content need to be suppressed.
1200 bool mSuppressWhiteSpaceOptimizations : 1;
1201 // Whether this is a text content item.
1202 bool mIsText : 1;
1203 // Whether this is a generated content container.
1204 // If it is, mContent is a strong pointer.
1205 bool mIsGeneratedContent : 1;
1206 // Whether construction from this item will create only frames that are
1207 // IsInlineOutside() in the principal child list. This is not precise, but
1208 // conservative: if true the frames will really be inline, whereas if false
1209 // they might still all be inline.
1210 bool mIsAllInline : 1;
1211 // Whether construction from this item will create only frames that are
1212 // IsBlockOutside() in the principal child list. This is not precise, but
1213 // conservative: if true the frames will really be blocks, whereas if false
1214 // they might still be blocks (and in particular, out-of-flows that didn't
1215 // find a containing block).
1216 bool mIsBlock : 1;
1217 // Whether construction from this item will create a popup that needs to
1218 // go into the global popup items.
1219 bool mIsPopup : 1;
1220 // Whether this item should be treated as a line participant
1221 bool mIsLineParticipant : 1;
1222 // Whether this item is the rendered legend of a <fieldset>
1223 bool mIsRenderedLegend : 1;
1225 private:
1226 // Not allocated from the general heap - instead, use the new/Delete APIs
1227 // that take a nsCSSFrameConstructor* (which manages our arena allocation).
1228 void* operator new(size_t) = delete;
1229 void* operator new[](size_t) = delete;
1230 #ifdef _MSC_VER /* Visual Studio */
1231 void operator delete(void*) { MOZ_CRASH("FrameConstructionItem::delete"); }
1232 #else
1233 void operator delete(void*) = delete;
1234 #endif
1235 void operator delete[](void*) = delete;
1236 FrameConstructionItem(const FrameConstructionItem& aOther) = delete;
1237 // Not allocated from the stack!
1238 ~FrameConstructionItem() {
1239 MOZ_COUNT_DTOR(FrameConstructionItem);
1240 MOZ_ASSERT(mChildItems.IsEmpty(), "leaking");
1245 * Convenience struct to assist in managing a temporary FrameConstructionItem
1246 * using a local variable. Castable to FrameConstructionItem so that it can
1247 * be passed transparently to functions that expect that type.
1248 * (This struct exists because FrameConstructionItem is arena-allocated, and
1249 * it's nice to abstract away its allocation/deallocation.)
1251 struct MOZ_RAII AutoFrameConstructionItem final {
1252 template <typename... Args>
1253 explicit AutoFrameConstructionItem(nsCSSFrameConstructor* aFCtor,
1254 Args&&... args)
1255 : mFCtor(aFCtor),
1256 mItem(new(aFCtor)
1257 FrameConstructionItem(std::forward<Args>(args)...)) {
1258 MOZ_ASSERT(mFCtor);
1260 ~AutoFrameConstructionItem() { mItem->Delete(mFCtor); }
1261 operator FrameConstructionItem&() { return *mItem; }
1263 private:
1264 nsCSSFrameConstructor* const mFCtor;
1265 FrameConstructionItem* const mItem;
1269 * Updates the nsFrameConstructorState auto page-name value, and restores the
1270 * previous value on destruction.
1271 * See https://drafts.csswg.org/css-page-3/#using-named-pages
1273 * To track this, this will automatically add PageValuesProperty to
1274 * the frame.
1276 * Note that this does not add PageValuesProperty to the frame when not in a
1277 * paginated context.
1279 class MOZ_RAII AutoFrameConstructionPageName final {
1280 nsFrameConstructorState& mState;
1281 const nsAtom* mNameToRestore;
1283 public:
1284 AutoFrameConstructionPageName(const AutoFrameConstructionPageName&) =
1285 delete;
1286 AutoFrameConstructionPageName(AutoFrameConstructionPageName&&) = delete;
1287 AutoFrameConstructionPageName(nsFrameConstructorState& aState,
1288 nsIFrame* const aFrame);
1289 ~AutoFrameConstructionPageName();
1293 * Function to create the anonymous flex or grid items that we need.
1294 * If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
1295 * this method is a NOP.
1296 * @param aItems the child frame construction items before pseudo creation
1297 * @param aParentFrame the parent frame
1299 void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
1300 FrameConstructionItemList& aItems,
1301 nsIFrame* aParentFrame);
1303 enum RubyWhitespaceType {
1304 eRubyNotWhitespace,
1305 eRubyInterLevelWhitespace,
1306 // Includes inter-base and inter-annotation whitespace
1307 eRubyInterLeafWhitespace,
1308 eRubyInterSegmentWhitespace
1312 * Function to compute the whitespace type according to the display
1313 * values of the previous and the next elements.
1315 static inline RubyWhitespaceType ComputeRubyWhitespaceType(
1316 mozilla::StyleDisplay aPrevDisplay, mozilla::StyleDisplay aNextDisplay);
1319 * Function to interpret the type of whitespace between
1320 * |aStartIter| and |aEndIter|.
1322 static inline RubyWhitespaceType InterpretRubyWhitespace(
1323 nsFrameConstructorState& aState, const FCItemIterator& aStartIter,
1324 const FCItemIterator& aEndIter);
1327 * Function to wrap consecutive misparented inline content into
1328 * a ruby base box or a ruby text box.
1330 void WrapItemsInPseudoRubyLeafBox(FCItemIterator& aIter,
1331 ComputedStyle* aParentStyle,
1332 nsIContent* aParentContent);
1335 * Function to wrap consecutive misparented items
1336 * into a ruby level container.
1338 inline void WrapItemsInPseudoRubyLevelContainer(
1339 nsFrameConstructorState& aState, FCItemIterator& aIter,
1340 ComputedStyle* aParentStyle, nsIContent* aParentContent);
1343 * Function to trim leading and trailing whitespaces.
1345 inline void TrimLeadingAndTrailingWhitespaces(
1346 nsFrameConstructorState& aState, FrameConstructionItemList& aItems);
1349 * Function to create internal ruby boxes.
1351 inline void CreateNeededPseudoInternalRubyBoxes(
1352 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
1353 nsIFrame* aParentFrame);
1356 * Function to create the pseudo intermediate containers we need.
1357 * @param aItems the child frame construction items before pseudo creation
1358 * @param aParentFrame the parent frame we're creating pseudos for
1360 inline void CreateNeededPseudoContainers(nsFrameConstructorState& aState,
1361 FrameConstructionItemList& aItems,
1362 nsIFrame* aParentFrame);
1365 * Function to wrap consecutive items into a pseudo parent.
1367 inline void WrapItemsInPseudoParent(nsIContent* aParentContent,
1368 ComputedStyle* aParentStyle,
1369 ParentType aWrapperType,
1370 FCItemIterator& aIter,
1371 const FCItemIterator& aEndIter);
1374 * Function to create the pseudo siblings we need.
1376 inline void CreateNeededPseudoSiblings(nsFrameConstructorState& aState,
1377 FrameConstructionItemList& aItems,
1378 nsIFrame* aParentFrame);
1380 // END TABLE SECTION
1382 protected:
1383 static nsIFrame* CreatePlaceholderFrameFor(PresShell* aPresShell,
1384 nsIContent* aContent,
1385 nsIFrame* aFrame,
1386 nsContainerFrame* aParentFrame,
1387 nsIFrame* aPrevInFlow,
1388 nsFrameState aTypeBit);
1390 private:
1391 // ConstructFieldSetFrame puts the new frame in aFrameList and
1392 // handles the kids of the fieldset
1393 nsIFrame* ConstructFieldSetFrame(nsFrameConstructorState& aState,
1394 FrameConstructionItem& aItem,
1395 nsContainerFrame* aParentFrame,
1396 const nsStyleDisplay* aStyleDisplay,
1397 nsFrameList& aFrameList);
1399 nsIFrame* ConstructListBoxSelectFrame(nsFrameConstructorState& aState,
1400 FrameConstructionItem& aItem,
1401 nsContainerFrame* aParentFrame,
1402 const nsStyleDisplay* aStyleDisplay,
1403 nsFrameList& aFrameList);
1405 // Creates a block frame wrapping an anonymous ruby frame.
1406 nsIFrame* ConstructBlockRubyFrame(nsFrameConstructorState& aState,
1407 FrameConstructionItem& aItem,
1408 nsContainerFrame* aParentFrame,
1409 const nsStyleDisplay* aStyleDisplay,
1410 nsFrameList& aFrameList);
1412 void ConstructTextFrame(const FrameConstructionData* aData,
1413 nsFrameConstructorState& aState, nsIContent* aContent,
1414 nsContainerFrame* aParentFrame,
1415 ComputedStyle* aComputedStyle,
1416 nsFrameList& aFrameList);
1418 // If aPossibleTextContent is a text node and doesn't have a frame, append a
1419 // frame construction item for it to aItems.
1420 void AddTextItemIfNeeded(nsFrameConstructorState& aState,
1421 const ComputedStyle& aParentStyle,
1422 const InsertionPoint& aInsertion,
1423 nsIContent* aPossibleTextContent,
1424 FrameConstructionItemList& aItems);
1426 // If aContent is a text node and doesn't have a frame, try to create a frame
1427 // for it.
1428 void ReframeTextIfNeeded(nsIContent* aContent);
1430 enum InsertPageBreakLocation { eBefore, eAfter };
1431 inline void AppendPageBreakItem(nsIContent* aContent,
1432 FrameConstructionItemList& aItems) {
1433 InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eAfter);
1435 inline void PrependPageBreakItem(nsIContent* aContent,
1436 FrameConstructionItemList& aItems) {
1437 InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eBefore);
1439 void InsertPageBreakItem(nsIContent* aContent,
1440 FrameConstructionItemList& aItems,
1441 InsertPageBreakLocation location);
1443 // Function to find FrameConstructionData for aElement. Will return
1444 // null if aElement is not HTML.
1445 // aParentFrame might be null. If it is, that means it was an
1446 // inline frame.
1447 static const FrameConstructionData* FindHTMLData(const Element&,
1448 nsIFrame* aParentFrame,
1449 ComputedStyle&);
1450 // HTML data-finding helper functions
1451 static const FrameConstructionData* FindSelectData(const Element&,
1452 ComputedStyle&);
1453 static const FrameConstructionData* FindImgData(const Element&,
1454 ComputedStyle&);
1455 static const FrameConstructionData* FindGeneratedImageData(const Element&,
1456 ComputedStyle&);
1457 static const FrameConstructionData* FindImgControlData(const Element&,
1458 ComputedStyle&);
1459 static const FrameConstructionData* FindSearchControlData(const Element&,
1460 ComputedStyle&);
1461 static const FrameConstructionData* FindInputData(const Element&,
1462 ComputedStyle&);
1463 static const FrameConstructionData* FindObjectData(const Element&,
1464 ComputedStyle&);
1465 static const FrameConstructionData* FindCanvasData(const Element&,
1466 ComputedStyle&);
1467 // <details> always creates a block per spec.
1468 static const FrameConstructionData* FindDetailsData(const Element&,
1469 ComputedStyle&);
1471 /* Construct a frame from the given FrameConstructionItem. This function
1472 will handle adding the frame to frame lists, processing children, setting
1473 the frame as the primary frame for the item's content, and so forth.
1475 @param aItem the FrameConstructionItem to use.
1476 @param aState the frame construction state to use.
1477 @param aParentFrame the frame to set as the parent of the
1478 newly-constructed frame.
1479 @param aFrameList the frame list to add the new frame (or its
1480 placeholder) to.
1482 void ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
1483 nsFrameConstructorState& aState,
1484 nsContainerFrame* aParentFrame,
1485 nsFrameList& aFrameList);
1487 // The guts of AddFrameConstructionItems
1488 // aParentFrame might be null. If it is, that means it was an
1489 // inline frame.
1490 void AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
1491 nsIContent* aContent,
1492 nsContainerFrame* aParentFrame,
1493 bool aSuppressWhiteSpaceOptimizations,
1494 ComputedStyle*, ItemFlags,
1495 FrameConstructionItemList& aItems);
1498 * Construct frames for the given item list and parent frame, and put the
1499 * resulting frames in aFrameList.
1501 void ConstructFramesFromItemList(nsFrameConstructorState& aState,
1502 FrameConstructionItemList& aItems,
1503 nsContainerFrame* aParentFrame,
1504 bool aParentIsWrapperAnonBox,
1505 nsFrameList& aFrameList);
1506 void ConstructFramesFromItem(nsFrameConstructorState& aState,
1507 FCItemIterator& aItem,
1508 nsContainerFrame* aParentFrame,
1509 nsFrameList& aFrameList);
1510 static bool AtLineBoundary(FCItemIterator& aIter);
1512 nsresult GetAnonymousContent(
1513 nsIContent* aParent, nsIFrame* aParentFrame,
1514 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonContent);
1516 // MathML Mod - RBS
1518 * Takes the frames in aBlockList and wraps them in a new anonymous block
1519 * frame whose content is aContent and whose parent will be aParentFrame.
1520 * The anonymous block is added to aNewList and aBlockList is cleared.
1522 void FlushAccumulatedBlock(nsFrameConstructorState& aState,
1523 nsIContent* aContent,
1524 nsContainerFrame* aParentFrame,
1525 nsFrameList& aBlockList, nsFrameList& aNewList);
1527 // Function to find FrameConstructionData for an element. Will return
1528 // null if the element is not MathML.
1529 static const FrameConstructionData* FindMathMLData(const Element&,
1530 ComputedStyle&);
1532 // Function to find FrameConstructionData for an element. Will return
1533 // null if the element is not XUL.
1534 static const FrameConstructionData* FindXULTagData(const Element&,
1535 ComputedStyle&);
1536 // XUL data-finding helper functions and structures
1537 static const FrameConstructionData* FindPopupGroupData(const Element&,
1538 ComputedStyle&);
1539 static const FrameConstructionData* FindXULButtonData(const Element&,
1540 ComputedStyle&);
1541 static const FrameConstructionData* FindXULLabelOrDescriptionData(
1542 const Element&, ComputedStyle&);
1543 #ifdef XP_MACOSX
1544 static const FrameConstructionData* FindXULMenubarData(const Element&,
1545 ComputedStyle&);
1546 #endif /* XP_MACOSX */
1549 * Constructs an outer frame, an anonymous child that wraps its real
1550 * children, and its descendant frames. This is used by both
1551 * ConstructOuterSVG and ConstructMarker, which both want an anonymous block
1552 * child for their children to go in to.
1554 nsContainerFrame* ConstructFrameWithAnonymousChild(
1555 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
1556 nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
1557 ContainerFrameCreationFunc aConstructor,
1558 ContainerFrameCreationFunc aInnerConstructor,
1559 mozilla::PseudoStyleType aInnerPseudo, bool aCandidateRootFrame);
1562 * Construct an SVGOuterSVGFrame.
1564 nsIFrame* ConstructOuterSVG(nsFrameConstructorState& aState,
1565 FrameConstructionItem& aItem,
1566 nsContainerFrame* aParentFrame,
1567 const nsStyleDisplay* aDisplay,
1568 nsFrameList& aFrameList);
1571 * Construct an SVGMarkerFrame.
1573 nsIFrame* ConstructMarker(nsFrameConstructorState& aState,
1574 FrameConstructionItem& aItem,
1575 nsContainerFrame* aParentFrame,
1576 const nsStyleDisplay* aDisplay,
1577 nsFrameList& aFrameList);
1579 static const FrameConstructionData* FindSVGData(const Element&,
1580 nsIFrame* aParentFrame,
1581 bool aIsWithinSVGText,
1582 bool aAllowsTextPathChild,
1583 ComputedStyle&);
1585 // Not static because it does PropagateScrollToViewport. If this
1586 // changes, make this static.
1587 const FrameConstructionData* FindDisplayData(const nsStyleDisplay&,
1588 const Element&);
1591 * Construct a scrollable block frame
1593 nsIFrame* ConstructScrollableBlock(nsFrameConstructorState& aState,
1594 FrameConstructionItem& aItem,
1595 nsContainerFrame* aParentFrame,
1596 const nsStyleDisplay* aDisplay,
1597 nsFrameList& aFrameList);
1600 * Construct a non-scrollable block frame
1602 nsIFrame* ConstructNonScrollableBlock(nsFrameConstructorState& aState,
1603 FrameConstructionItem& aItem,
1604 nsContainerFrame* aParentFrame,
1605 const nsStyleDisplay* aDisplay,
1606 nsFrameList& aFrameList);
1609 * This adds FrameConstructionItem objects to aItemsToConstruct for the
1610 * anonymous content returned by an nsIAnonymousContentCreator::
1611 * CreateAnonymousContent implementation.
1612 * This includes an AutoFrameConstructionPageName argument as it is always
1613 * the caller's responsibility to handle page-name tracking before calling
1614 * this function.
1616 void AddFCItemsForAnonymousContent(
1617 nsFrameConstructorState& aState, nsContainerFrame* aFrame,
1618 const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
1619 FrameConstructionItemList& aItemsToConstruct,
1620 const AutoFrameConstructionPageName& aUnusedPageNameTracker);
1623 * Construct the frames for the children of aContent. "children" is defined
1624 * as "whatever FlattenedChildIterator returns for aContent". This means
1625 * we're basically operating on children in the "flattened tree":
1627 * https://drafts.csswg.org/css-scoping/#flat-tree
1629 * This method will also handle constructing ::before, ::after,
1630 * ::first-letter, and ::first-line frames, as needed and if allowed.
1632 * If the parent is a float containing block, this method will handle pushing
1633 * it as the float containing block in aState (so there's no need for callers
1634 * to push it themselves).
1636 * @param aState the frame construction state
1637 * @param aContent the content node whose children need frames
1638 * @param aComputedStyle the style for aContent
1639 * @param aParentFrame the frame to use as the parent frame for the new
1640 * in-flow kids. Note that this must be its own content insertion frame, but
1641 * need not be be the primary frame for aContent. This frame will be
1642 * pushed as the float containing block, as needed. aFrame is also
1643 * used to find the parent style for the kids' style
1644 * (not necessary aFrame's style).
1645 * @param aCanHaveGeneratedContent Whether to allow :before and
1646 * :after styles on the parent.
1647 * @param aFrameList the list in which we should place the in-flow children
1648 * @param aAllowBlockStyles Whether to allow first-letter and first-line
1649 * styles on the parent.
1650 * @param aPossiblyLeafFrame if non-null, this should be used for the isLeaf
1651 * test and the anonymous content creation. If null, aFrame will be
1652 * used.
1654 void ProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent,
1655 ComputedStyle* aComputedStyle,
1656 nsContainerFrame* aParentFrame,
1657 const bool aCanHaveGeneratedContent,
1658 nsFrameList& aFrameList, const bool aAllowBlockStyles,
1659 nsIFrame* aPossiblyLeafFrame = nullptr);
1662 * These two functions are used when we start frame creation from a non-root
1663 * element. They should recreate the same state that we would have
1664 * arrived at if we had built frames from the root frame to aFrame.
1665 * Therefore, any calls to PushFloatContainingBlock and
1666 * PushAbsoluteContainingBlock during frame construction should get
1667 * corresponding logic in these functions.
1669 public:
1670 enum ContainingBlockType { ABS_POS, FIXED_POS };
1671 nsContainerFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame,
1672 ContainingBlockType aType);
1673 nsContainerFrame* GetFloatContainingBlock(nsIFrame* aFrame);
1675 private:
1676 // Build a scroll frame:
1677 // Calls BeginBuildingScrollFrame, InitAndRestoreFrame, and then
1678 // FinishBuildingScrollFrame.
1679 // @param aNewFrame the created scrollframe --- output only
1680 // @param aParentFrame the geometric parent that the scrollframe will have.
1681 void BuildScrollFrame(nsFrameConstructorState& aState, nsIContent* aContent,
1682 ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
1683 nsContainerFrame* aParentFrame,
1684 nsContainerFrame*& aNewFrame);
1686 // Builds the initial ScrollFrame
1687 already_AddRefed<ComputedStyle> BeginBuildingScrollFrame(
1688 nsFrameConstructorState& aState, nsIContent* aContent,
1689 ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame,
1690 mozilla::PseudoStyleType aScrolledPseudo, bool aIsRoot,
1691 nsContainerFrame*& aNewFrame);
1693 // Completes the building of the scrollframe:
1694 // Creates a view for the scrolledframe and makes it the child of the
1695 // scrollframe.
1696 void FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
1697 nsIFrame* aScrolledFrame);
1699 void InitializeListboxSelect(nsFrameConstructorState& aState,
1700 nsContainerFrame* aScrollFrame,
1701 nsContainerFrame* aScrolledFrame,
1702 nsIContent* aContent,
1703 nsContainerFrame* aParentFrame,
1704 ComputedStyle* aComputedStyle,
1705 nsFrameList& aFrameList);
1708 * Recreate frames for aContent.
1709 * @param aContent the content to recreate frames for
1710 * @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
1712 void RecreateFramesForContent(nsIContent* aContent,
1713 InsertionKind aInsertionKind);
1716 * Handles change of rowspan and colspan attributes on table cells.
1718 void UpdateTableCellSpans(nsIContent* aContent);
1720 // If removal of aFrame from the frame tree requires reconstruction of some
1721 // containing block (either of aFrame or of its parent) due to {ib} splits or
1722 // table pseudo-frames, recreate the relevant frame subtree. The return value
1723 // indicates whether this happened. aFrame must be the result of a
1724 // GetPrimaryFrame() call on a content node (which means its parent is also
1725 // not null).
1726 bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame);
1728 nsIFrame* CreateContinuingOuterTableFrame(nsIFrame* aFrame,
1729 nsContainerFrame* aParentFrame,
1730 nsIContent* aContent,
1731 ComputedStyle* aComputedStyle);
1733 nsIFrame* CreateContinuingTableFrame(nsIFrame* aFrame,
1734 nsContainerFrame* aParentFrame,
1735 nsIContent* aContent,
1736 ComputedStyle* aComputedStyle);
1738 //----------------------------------------
1740 // Methods support creating block frames and their children
1742 already_AddRefed<ComputedStyle> GetFirstLetterStyle(
1743 nsIContent* aContent, ComputedStyle* aComputedStyle);
1745 already_AddRefed<ComputedStyle> GetFirstLineStyle(
1746 nsIContent* aContent, ComputedStyle* aComputedStyle);
1748 bool ShouldHaveFirstLetterStyle(nsIContent* aContent,
1749 ComputedStyle* aComputedStyle);
1751 // Check whether a given block has first-letter style. Make sure to
1752 // only pass in blocks! And don't pass in null either.
1753 bool HasFirstLetterStyle(nsIFrame* aBlockFrame);
1755 bool ShouldHaveFirstLineStyle(nsIContent* aContent,
1756 ComputedStyle* aComputedStyle);
1758 void ShouldHaveSpecialBlockStyle(nsIContent* aContent,
1759 ComputedStyle* aComputedStyle,
1760 bool* aHaveFirstLetterStyle,
1761 bool* aHaveFirstLineStyle);
1763 // |aContentParentFrame| should be null if it's really the same as
1764 // |aParentFrame|.
1765 // @param aFrameList where we want to put the block in case it's in-flow.
1766 // @param aNewFrame an in/out parameter. On input it is the block to be
1767 // constructed. On output it is reset to the outermost
1768 // frame constructed (e.g. if we need to wrap the block in an
1769 // nsColumnSetFrame.
1770 // @param aParentFrame is the desired parent for the (possibly wrapped)
1771 // block
1772 // @param aContentParent is the parent the block would have if it
1773 // were in-flow
1774 // @param aPositionedFrameForAbsPosContainer if non-null, then the new
1775 // block should be an abs-pos container and aPositionedFrameForAbsPosContainer
1776 // is the frame whose style is making this block an abs-pos container.
1777 void ConstructBlock(nsFrameConstructorState& aState, nsIContent* aContent,
1778 nsContainerFrame* aParentFrame,
1779 nsContainerFrame* aContentParentFrame,
1780 ComputedStyle* aComputedStyle,
1781 nsContainerFrame** aNewFrame, nsFrameList& aFrameList,
1782 nsIFrame* aPositionedFrameForAbsPosContainer);
1784 // Build the initial column hierarchy around aColumnContent. This function
1785 // should be called before constructing aColumnContent's children.
1787 // Before calling FinishBuildingColumns(), we need to create column-span
1788 // siblings for aColumnContent's children. Caller can use helpers
1789 // MayNeedToCreateColumnSpanSiblings() and CreateColumnSpanSiblings() to
1790 // check whether column-span siblings might need to be created and to do
1791 // the actual work of creating them if they're needed.
1793 // @param aColumnContent the block that we're wrapping in a ColumnSet. On
1794 // entry to this function it has aComputedStyle as its style. After
1795 // this function returns, aColumnContent has a ::-moz-column-content
1796 // anonymous box style.
1797 // @param aParentFrame the parent frame we want to use for the
1798 // ColumnSetWrapperFrame (which would have been the parent of
1799 // aColumnContent if we were not creating a column hierarchy).
1800 // @param aContent is the content of the aColumnContent.
1801 // @return the outermost ColumnSetWrapperFrame.
1802 nsBlockFrame* BeginBuildingColumns(nsFrameConstructorState& aState,
1803 nsIContent* aContent,
1804 nsContainerFrame* aParentFrame,
1805 nsContainerFrame* aColumnContent,
1806 ComputedStyle* aComputedStyle);
1808 // Complete building the column hierarchy by first wrapping each
1809 // non-column-span child in aChildList in a ColumnSetFrame (skipping
1810 // column-span children), and reparenting them to have aColumnSetWrapper
1811 // as their parent.
1813 // @param aColumnSetWrapper is the frame returned by
1814 // BeginBuildingColumns(), and is the grandparent of aColumnContent.
1815 // @param aColumnContent is the block frame passed into
1816 // BeginBuildingColumns()
1817 // @param aColumnContentSiblings contains the aColumnContent's siblings, which
1818 // are the column spanners and aColumnContent's continuations returned
1819 // by CreateColumnSpanSiblings(). It'll become empty after this call.
1820 void FinishBuildingColumns(nsFrameConstructorState& aState,
1821 nsContainerFrame* aColumnSetWrapper,
1822 nsContainerFrame* aColumnContent,
1823 nsFrameList& aColumnContentSiblings);
1825 // Return whether aBlockFrame's children in aChildList, which might
1826 // contain column-span, may need to be wrapped in
1827 // ::moz-column-span-wrapper and promoted as aBlockFrame's siblings.
1829 // @param aBlockFrame is the parent of the frames in aChildList.
1831 // Note: This a check without actually looking into each frame in the
1832 // child list, so it may return false positive.
1833 bool MayNeedToCreateColumnSpanSiblings(nsContainerFrame* aBlockFrame,
1834 const nsFrameList& aChildList);
1836 // Wrap consecutive runs of column-span kids and runs of non-column-span
1837 // kids in blocks for aInitialBlock's children.
1839 // @param aInitialBlock is the parent of those frames in aChildList.
1840 // @param aChildList must begin with a column-span kid. It becomes empty
1841 // after this call.
1842 // @param aPositionedFrame if non-null, it's the frame whose style is making
1843 // aInitialBlock an abs-pos container.
1845 // Return those wrapping blocks in nsFrameList.
1846 nsFrameList CreateColumnSpanSiblings(nsFrameConstructorState& aState,
1847 nsContainerFrame* aInitialBlock,
1848 nsFrameList& aChildList,
1849 nsIFrame* aPositionedFrame);
1851 // Reconstruct the multi-column containing block of aParentFrame when we want
1852 // to insert aFrameList into aParentFrame immediately after aPrevSibling but
1853 // cannot fix the frame tree because aFrameList contains some column-spans.
1855 // Note: This method is intended to be called as a helper in ContentAppended()
1856 // and ContentRangeInserted(). It assumes aState was set up locally and wasn't
1857 // used to construct any ancestors of aParentFrame in aFrameList.
1859 // @param aParentFrame the to-be parent frame for aFrameList.
1860 // @param aFrameList the frames to be inserted. It will be cleared if we need
1861 // reconstruction.
1862 // @param aPrevSibling the position where the frames in aFrameList are going
1863 // to be inserted. Nullptr means aFrameList is being inserted at
1864 // the beginning.
1865 // @return true if the multi-column containing block of aParentFrame is
1866 // reconstructed; false otherwise.
1867 bool MaybeRecreateForColumnSpan(nsFrameConstructorState& aState,
1868 nsContainerFrame* aParentFrame,
1869 nsFrameList& aFrameList,
1870 nsIFrame* aPrevSibling);
1872 nsIFrame* ConstructInline(nsFrameConstructorState& aState,
1873 FrameConstructionItem& aItem,
1874 nsContainerFrame* aParentFrame,
1875 const nsStyleDisplay* aDisplay,
1876 nsFrameList& aFrameList);
1879 * Create any additional {ib} siblings needed to contain aChildList and put
1880 * them in aSiblings.
1882 * @param aState the frame constructor state
1883 * @param aInitialInline is an already-existing inline frame that will be
1884 * part of this {ib} split and come before everything
1885 * in aSiblings.
1886 * @param aIsPositioned true if aInitialInline is positioned.
1887 * @param aChildList is a child list starting with a block; this method
1888 * assumes that the inline has already taken all the
1889 * children it wants. When the method returns aChildList
1890 * will be empty.
1891 * @param aSiblings the nsFrameList to put the newly-created siblings into.
1893 * This method is responsible for making any SetFrameIsIBSplit calls that are
1894 * needed.
1896 void CreateIBSiblings(nsFrameConstructorState& aState,
1897 nsContainerFrame* aInitialInline, bool aIsPositioned,
1898 nsFrameList& aChildList, nsFrameList& aSiblings);
1901 * For an inline aParentItem, construct its list of child
1902 * FrameConstructionItems and set its mIsAllInline flag appropriately.
1904 void BuildInlineChildItems(nsFrameConstructorState& aState,
1905 FrameConstructionItem& aParentItem,
1906 bool aItemIsWithinSVGText,
1907 bool aItemAllowsTextPathChild);
1909 // Determine whether we need to wipe out aFrame (the insertion parent) and
1910 // rebuild the entire subtree when we insert or append new content under
1911 // aFrame.
1913 // This is similar to WipeContainingBlock(), but is called before constructing
1914 // any frame construction items. Any container frames which need reframing
1915 // regardless of the content inserted or appended can add a check in this
1916 // method.
1918 // @return true if we reconstructed the insertion parent frame; false
1919 // otherwise
1920 bool WipeInsertionParent(nsContainerFrame* aFrame);
1922 // Determine whether we need to wipe out what we just did and start over
1923 // because we're doing something like adding block kids to an inline frame
1924 // (and therefore need an {ib} split). aPrevSibling must be correct, even in
1925 // aIsAppend cases. Passing aIsAppend false even when an append is happening
1926 // is ok in terms of correctness, but can lead to unnecessary reframing. If
1927 // aIsAppend is true, then the caller MUST call
1928 // nsCSSFrameConstructor::AppendFramesToParent (as opposed to
1929 // nsFrameManager::InsertFrames directly) to add the new frames.
1930 // @return true if we reconstructed the containing block, false
1931 // otherwise
1932 bool WipeContainingBlock(nsFrameConstructorState& aState,
1933 nsIFrame* aContainingBlock, nsIFrame* aFrame,
1934 FrameConstructionItemList& aItems, bool aIsAppend,
1935 nsIFrame* aPrevSibling);
1937 void ReframeContainingBlock(nsIFrame* aFrame);
1939 //----------------------------------------
1941 // Methods support :first-letter style
1943 nsFirstLetterFrame* CreateFloatingLetterFrame(
1944 nsFrameConstructorState& aState, mozilla::dom::Text* aTextContent,
1945 nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
1946 ComputedStyle* aParentStyle, ComputedStyle* aComputedStyle,
1947 nsFrameList& aResult);
1949 void CreateLetterFrame(nsContainerFrame* aBlockFrame,
1950 nsContainerFrame* aBlockContinuation,
1951 mozilla::dom::Text* aTextContent,
1952 nsContainerFrame* aParentFrame, nsFrameList& aResult);
1954 void WrapFramesInFirstLetterFrame(nsContainerFrame* aBlockFrame,
1955 nsFrameList& aBlockFrames);
1958 * Looks in the block aBlockFrame for a text frame that contains the
1959 * first-letter of the block and creates the necessary first-letter frames
1960 * and returns them in aLetterFrames.
1962 * @param aBlockFrame the (first-continuation of) the block we are creating a
1963 * first-letter frame for
1964 * @param aBlockContinuation the current continuation of the block that we
1965 * are looking in for a textframe with suitable
1966 * contents for first-letter
1967 * @param aParentFrame the current frame whose children we are looking at for
1968 * a suitable first-letter textframe
1969 * @param aParentFrameList the first child of aParentFrame
1970 * @param aModifiedParent returns the parent of the textframe that contains
1971 * the first-letter
1972 * @param aTextFrame returns the textframe that had the first-letter
1973 * @param aPrevFrame returns the previous sibling of aTextFrame
1974 * @param aLetterFrames returns the frames that were created
1976 void WrapFramesInFirstLetterFrame(
1977 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
1978 nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
1979 nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
1980 nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking);
1982 void RecoverLetterFrames(nsContainerFrame* aBlockFrame);
1984 void RemoveLetterFrames(PresShell* aPresShell, nsContainerFrame* aBlockFrame);
1986 // Recursive helper for RemoveLetterFrames
1987 void RemoveFirstLetterFrames(PresShell* aPresShell, nsContainerFrame* aFrame,
1988 nsContainerFrame* aBlockFrame,
1989 bool* aStopLooking);
1991 // Special remove method for those pesky floating first-letter frames
1992 void RemoveFloatingFirstLetterFrames(PresShell* aPresShell,
1993 nsIFrame* aBlockFrame);
1995 // Capture state for the frame tree rooted at the frame associated with the
1996 // content object, aContent
1997 void CaptureStateForFramesOf(nsIContent* aContent,
1998 nsILayoutHistoryState* aHistoryState);
2000 //----------------------------------------
2002 // Methods support :first-line style
2004 // This method chops the initial inline-outside frames out of aFrameList.
2005 // If aLineFrame is non-null, it appends them to that frame. Otherwise, it
2006 // creates a new line frame, sets the inline frames as its initial child
2007 // list, and inserts that line frame at the front of what's left of
2008 // aFrameList. In both cases, the kids are reparented to the line frame.
2009 // After this call, aFrameList holds the frames that need to become kids of
2010 // the block (possibly including line frames).
2011 void WrapFramesInFirstLineFrame(nsFrameConstructorState& aState,
2012 nsIContent* aBlockContent,
2013 nsContainerFrame* aBlockFrame,
2014 nsFirstLineFrame* aLineFrame,
2015 nsFrameList& aFrameList);
2017 // Handle the case when a block with first-line style is appended to (by
2018 // possibly calling WrapFramesInFirstLineFrame as needed).
2019 void AppendFirstLineFrames(nsFrameConstructorState& aState,
2020 nsIContent* aContent,
2021 nsContainerFrame* aBlockFrame,
2022 nsFrameList& aFrameList);
2025 * When aFrameList is being inserted into aParentFrame, and aParentFrame has
2026 * pseudo-element-affected styles, it's possible that we're inserting under a
2027 * ::first-line frame. In that case, with servo's style system, the styles we
2028 * resolved for aFrameList are wrong (they don't take ::first-line into
2029 * account), and we should fix them up, which is what this method does.
2031 * This method does not mutate aFrameList.
2033 void CheckForFirstLineInsertion(nsIFrame* aParentFrame,
2034 nsFrameList& aFrameList);
2037 * Find the next frame for appending to a given insertion point.
2039 * We're appending, so this is almost always null, except for a few edge
2040 * cases.
2042 nsIFrame* FindNextSiblingForAppend(const InsertionPoint&);
2044 // The direction in which we should look for siblings.
2045 enum class SiblingDirection {
2046 Forward,
2047 Backward,
2051 * Find the frame for the content immediately next to the one aIter points to,
2052 * in the direction SiblingDirection indicates, following continuations if
2053 * necessary.
2055 * aIter is passed by const reference on purpose, so as not to modify the
2056 * caller's iterator.
2058 * @param aIter should be positioned such that aIter.GetPreviousChild()
2059 * is the first content to search for frames
2060 * @param aTargetContentDisplay the CSS display enum for the content aIter
2061 * points to if already known. It will be filled in if needed.
2063 template <SiblingDirection>
2064 nsIFrame* FindSibling(
2065 const mozilla::dom::FlattenedChildIterator& aIter,
2066 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2068 // Helper for the implementation of FindSibling.
2070 // Beware that this function does mutate the iterator.
2071 template <SiblingDirection>
2072 nsIFrame* FindSiblingInternal(
2073 mozilla::dom::FlattenedChildIterator&, nsIContent* aTargetContent,
2074 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2076 // An alias of FindSibling<SiblingDirection::Forward>.
2077 nsIFrame* FindNextSibling(
2078 const mozilla::dom::FlattenedChildIterator& aIter,
2079 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2080 // An alias of FindSibling<SiblingDirection::Backwards>.
2081 nsIFrame* FindPreviousSibling(
2082 const mozilla::dom::FlattenedChildIterator& aIter,
2083 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2085 // Given a potential first-continuation sibling frame for aTargetContent,
2086 // verify that it is an actual valid sibling for it, and return the
2087 // appropriate continuation the new frame for aTargetContent should be
2088 // inserted next to.
2089 nsIFrame* AdjustSiblingFrame(
2090 nsIFrame* aSibling, nsIContent* aTargetContent,
2091 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay,
2092 SiblingDirection aDirection);
2094 // Find the right previous sibling for an insertion. This also updates the
2095 // parent frame to point to the correct continuation of the parent frame to
2096 // use, and returns whether this insertion is to be treated as an append.
2097 // aChild is the child being inserted.
2098 // aIsRangeInsertSafe returns whether it is safe to do a range insert with
2099 // aChild being the first child in the range. It is the callers'
2100 // responsibility to check whether a range insert is safe with regards to
2101 // fieldsets.
2102 // The skip parameters are used to ignore a range of children when looking
2103 // for a sibling. All nodes starting from aStartSkipChild and up to but not
2104 // including aEndSkipChild will be skipped over when looking for sibling
2105 // frames. Skipping a range can deal with shadow DOM, but not when there are
2106 // multiple insertion points.
2107 nsIFrame* GetInsertionPrevSibling(InsertionPoint* aInsertion, // inout
2108 nsIContent* aChild, bool* aIsAppend,
2109 bool* aIsRangeInsertSafe,
2110 nsIContent* aStartSkipChild = nullptr,
2111 nsIContent* aEndSkipChild = nullptr);
2113 // see if aContent and aSibling are legitimate siblings due to restrictions
2114 // imposed by table columns
2115 // XXXbz this code is generally wrong, since the frame for aContent
2116 // may be constructed based on tag, not based on aDisplay!
2117 bool IsValidSibling(nsIFrame* aSibling, nsIContent* aContent,
2118 mozilla::Maybe<mozilla::StyleDisplay>& aDisplay);
2120 void QuotesDirty();
2121 void CountersDirty();
2123 void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
2124 nsContainerFrame* aFrame,
2125 nsIContent* aDocElement,
2126 nsFrameList&);
2128 public:
2129 friend class nsFrameConstructorState;
2131 private:
2132 // For allocating FrameConstructionItems from the mFCItemPool arena.
2133 friend struct FrameConstructionItem;
2134 void* AllocateFCItem();
2135 void FreeFCItem(FrameConstructionItem*);
2137 mozilla::dom::Document* mDocument; // Weak ref
2139 // See the comment at the start of ConstructRootFrame for more details
2140 // about the following frames.
2142 // This is just the outermost frame for the root element.
2143 nsContainerFrame* mRootElementFrame = nullptr;
2144 // This is the frame for the root element that has no pseudo-element style.
2145 nsIFrame* mRootElementStyleFrame = nullptr;
2146 // This is the containing block that contains the root element ---
2147 // the real "initial containing block" according to CSS 2.1.
2148 nsCanvasFrame* mDocElementContainingBlock = nullptr;
2149 // This is usually mDocElementContainingBlock, except when printing, where it
2150 // is the canvas frame that is under all the printed pages.
2151 nsCanvasFrame* mCanvasFrame = nullptr;
2152 nsPageSequenceFrame* mPageSequenceFrame = nullptr;
2154 // FrameConstructionItem arena + list of freed items available for re-use.
2155 mozilla::ArenaAllocator<4096, 8> mFCItemPool;
2157 // This indicates what page name to use for the next nsPageContentFrame.
2158 // Set when CSS named pages cause a breakpoint.
2159 // This does not apply to the first page content frame, which has its name
2160 // set by nsPageContentFrame::EnsurePageName() during first reflow.
2161 RefPtr<const nsAtom> mNextPageContentFramePageName;
2163 struct FreeFCItemLink {
2164 FreeFCItemLink* mNext;
2166 FreeFCItemLink* mFirstFreeFCItem;
2167 size_t mFCItemsInUse;
2169 mozilla::ContainStyleScopeManager mContainStyleScopeManager;
2171 // Current ProcessChildren depth.
2172 uint16_t mCurrentDepth;
2173 bool mQuotesDirty : 1;
2174 bool mCountersDirty : 1;
2175 bool mAlwaysCreateFramesForIgnorableWhitespace : 1;
2177 // The layout state from our history entry (to restore scroll positions and
2178 // such from history), or a new one if there was none (so we can store scroll
2179 // positions and such during reframe).
2181 // FIXME(bug 1397239): This can leak some state sometimes for the lifetime of
2182 // the frame constructor, which is not great.
2183 nsCOMPtr<nsILayoutHistoryState> mFrameTreeState;
2186 #endif /* nsCSSFrameConstructor_h___ */