Bug 1879449 [wpt PR 44489] - [wptrunner] Add `infrastructure/expected-fail/` test...
[gecko.git] / layout / base / nsCSSFrameConstructor.h
blob283d1385ce1b9f31b8fec547530ae4d62ff71216
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_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a
727 block formatting context wrapper around the kids of this frame
728 using the FrameConstructionData's mPseudoAtom for its anonymous
729 box type. */
730 #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000
731 /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of
732 an SVG text frame. */
733 #define FCDATA_IS_SVG_TEXT 0x80000
735 * If FCDATA_ALLOW_GRID_FLEX_COLUMN is set, then we should create a
736 * grid/flex/column container instead of a block wrapper when the styles says
737 * so. This bit is meaningful only if FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS
738 * is also set.
740 #define FCDATA_ALLOW_GRID_FLEX_COLUMN 0x200000
742 * Whether the kids of this FrameConstructionData should be flagged as having
743 * a wrapper anon box parent. This should only be set if
744 * FCDATA_USE_CHILD_ITEMS is set.
746 #define FCDATA_IS_WRAPPER_ANON_BOX 0x400000
748 /* Structure representing information about how a frame should be
749 constructed. */
750 struct FrameConstructionData {
751 // We have exactly one of three types of functions, so use a union for
752 // better cache locality.
753 union Func {
754 FrameCreationFunc mCreationFunc;
755 FrameConstructionDataGetter mDataGetter;
756 FrameFullConstructor mFullConstructor;
758 explicit constexpr Func(FrameCreationFunc aFunc) : mCreationFunc(aFunc) {}
759 explicit constexpr Func(FrameConstructionDataGetter aDataGetter)
760 : mDataGetter(aDataGetter) {}
761 explicit constexpr Func(FrameFullConstructor aCtor)
762 : mFullConstructor(aCtor) {}
763 } mFunc;
764 // Flag bits that can modify the way the construction happens
765 const uint32_t mBits = 0;
766 // For cases when FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, the
767 // anonymous box type to use for that wrapper.
768 PseudoStyleType const mAnonBoxPseudo = PseudoStyleType::NotPseudo;
770 constexpr FrameConstructionData() : FrameConstructionData(nullptr) {}
772 MOZ_IMPLICIT constexpr FrameConstructionData(std::nullptr_t,
773 uint32_t aBits = 0)
774 : mFunc(static_cast<FrameCreationFunc>(nullptr)), mBits(aBits) {}
776 MOZ_IMPLICIT constexpr FrameConstructionData(
777 FrameCreationFunc aCreationFunc, uint32_t aBits = 0)
778 : mFunc(aCreationFunc), mBits(aBits) {}
779 constexpr FrameConstructionData(FrameCreationFunc aCreationFunc,
780 uint32_t aBits,
781 PseudoStyleType aAnonBoxPseudo)
782 : mFunc(aCreationFunc),
783 mBits(aBits | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS),
784 mAnonBoxPseudo(aAnonBoxPseudo) {}
785 MOZ_IMPLICIT constexpr FrameConstructionData(
786 FrameConstructionDataGetter aDataGetter, uint32_t aBits = 0)
787 : mFunc(aDataGetter),
788 mBits(aBits | FCDATA_FUNC_IS_DATA_GETTER),
789 mAnonBoxPseudo(PseudoStyleType::NotPseudo) {}
790 MOZ_IMPLICIT constexpr FrameConstructionData(FrameFullConstructor aCtor,
791 uint32_t aBits = 0)
792 : mFunc(aCtor),
793 mBits(aBits | FCDATA_FUNC_IS_FULL_CTOR),
794 mAnonBoxPseudo(PseudoStyleType::NotPseudo) {}
797 /* Structure representing a mapping of an atom to a FrameConstructionData.
798 This can be used with non-static atoms, assuming that the nsAtom* is
799 stored somewhere that this struct can point to (that is, a static
800 nsAtom*) and that it's allocated before the struct is ever used. */
801 struct FrameConstructionDataByTag {
802 const nsStaticAtom* const mTag;
803 const FrameConstructionData mData;
806 /* Structure representing a mapping of an integer to a
807 FrameConstructionData. There are no magic integer values here. */
808 struct FrameConstructionDataByInt {
809 /* Could be used for display or whatever else */
810 const int32_t mInt;
811 const FrameConstructionData mData;
814 struct FrameConstructionDataByDisplay {
815 #ifdef DEBUG
816 const mozilla::StyleDisplay mDisplay;
817 #endif
818 const FrameConstructionData mData;
821 /* Structure that has a FrameConstructionData and style pseudo-type
822 for a table pseudo-frame */
823 struct PseudoParentData {
824 const FrameConstructionData mFCData;
825 mozilla::PseudoStyleType const mPseudoType;
827 /* Array of such structures that we use to properly construct table
828 pseudo-frames as needed */
829 static const PseudoParentData sPseudoParentData[eParentTypeCount];
831 const FrameConstructionData* FindDataForContent(nsIContent&, ComputedStyle&,
832 nsIFrame* aParentFrame,
833 ItemFlags aFlags);
835 // aParentFrame might be null. If it is, that means it was an inline frame.
836 static const FrameConstructionData* FindTextData(const Text&,
837 nsIFrame* aParentFrame);
838 const FrameConstructionData* FindElementData(const Element&, ComputedStyle&,
839 nsIFrame* aParentFrame,
840 ItemFlags aFlags);
841 const FrameConstructionData* FindElementTagData(const Element&,
842 ComputedStyle&,
843 nsIFrame* aParentFrame,
844 ItemFlags aFlags);
846 /* A function that takes an integer, content, style, and array of
847 FrameConstructionDataByInts and finds the appropriate frame construction
848 data to use and returns it. This can return null if none of the integers
849 match or if the matching integer has a FrameConstructionDataGetter that
850 returns null. */
851 static const FrameConstructionData* FindDataByInt(
852 int32_t aInt, const Element&, ComputedStyle&,
853 const FrameConstructionDataByInt* aDataPtr, uint32_t aDataLength);
856 * A function that takes a tag, content, style, and array of
857 * FrameConstructionDataByTags and finds the appropriate frame construction
858 * data to use and returns it.
860 * This can return null if none of the tags match or if the matching tag has a
861 * FrameConstructionDataGetter that returns null. In the case that the tags
862 * actually match, aTagFound will be true, even if the return value is null.
864 static const FrameConstructionData* FindDataByTag(
865 const Element& aElement, ComputedStyle& aComputedStyle,
866 const FrameConstructionDataByTag* aDataPtr, uint32_t aDataLength);
868 /* A class representing a list of FrameConstructionItems. Instances of this
869 class are only created as AutoFrameConstructionItemList, or as a member
870 of FrameConstructionItem. */
871 class FrameConstructionItemList {
872 public:
873 void Reset(nsCSSFrameConstructor* aFCtor) {
874 Destroy(aFCtor);
875 this->~FrameConstructionItemList();
876 new (this) FrameConstructionItemList();
879 void SetLineBoundaryAtStart(bool aBoundary) {
880 mLineBoundaryAtStart = aBoundary;
882 void SetLineBoundaryAtEnd(bool aBoundary) {
883 mLineBoundaryAtEnd = aBoundary;
885 void SetParentHasNoShadowDOM(bool aValue) {
886 mParentHasNoShadowDOM = aValue;
888 bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
889 bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
890 bool ParentHasNoShadowDOM() { return mParentHasNoShadowDOM; }
891 bool IsEmpty() const { return mItems.isEmpty(); }
892 bool AreAllItemsInline() const { return mInlineCount == mItemCount; }
893 bool AreAllItemsBlock() const { return mBlockCount == mItemCount; }
894 bool AllWantParentType(ParentType aDesiredParentType) const {
895 return mDesiredParentCounts[aDesiredParentType] == mItemCount;
898 // aSuppressWhiteSpaceOptimizations is true if optimizations that
899 // skip constructing whitespace frames for this item or items
900 // around it cannot be performed.
901 // Also, the return value is always non-null, thanks to infallible 'new'.
902 FrameConstructionItem* AppendItem(
903 nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
904 nsIContent* aContent, already_AddRefed<ComputedStyle>&& aComputedStyle,
905 bool aSuppressWhiteSpaceOptimizations) {
906 FrameConstructionItem* item = new (aFCtor)
907 FrameConstructionItem(aFCData, aContent, std::move(aComputedStyle),
908 aSuppressWhiteSpaceOptimizations);
909 mItems.insertBack(item);
910 ++mItemCount;
911 ++mDesiredParentCounts[item->DesiredParentType()];
912 return item;
915 // Arguments are the same as AppendItem().
916 FrameConstructionItem* PrependItem(
917 nsCSSFrameConstructor* aFCtor, const FrameConstructionData* aFCData,
918 nsIContent* aContent, already_AddRefed<ComputedStyle>&& aComputedStyle,
919 bool aSuppressWhiteSpaceOptimizations) {
920 FrameConstructionItem* item = new (aFCtor)
921 FrameConstructionItem(aFCData, aContent, std::move(aComputedStyle),
922 aSuppressWhiteSpaceOptimizations);
923 mItems.insertFront(item);
924 ++mItemCount;
925 ++mDesiredParentCounts[item->DesiredParentType()];
926 return item;
929 void InlineItemAdded() { ++mInlineCount; }
930 void BlockItemAdded() { ++mBlockCount; }
932 class Iterator {
933 public:
934 explicit Iterator(FrameConstructionItemList& aList)
935 : mCurrent(aList.mItems.getFirst()), mList(aList) {}
936 Iterator(const Iterator& aOther) = default;
938 bool operator==(const Iterator& aOther) const {
939 MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
940 return mCurrent == aOther.mCurrent;
942 bool operator!=(const Iterator& aOther) const {
943 return !(*this == aOther);
945 Iterator& operator=(const Iterator& aOther) {
946 MOZ_ASSERT(&mList == &aOther.mList, "Iterators for different lists?");
947 mCurrent = aOther.mCurrent;
948 return *this;
951 FrameConstructionItemList* List() { return &mList; }
953 FrameConstructionItem& item() {
954 MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
955 return *mCurrent;
958 const FrameConstructionItem& item() const {
959 MOZ_ASSERT(!IsDone(), "Should have checked IsDone()!");
960 return *mCurrent;
963 bool IsDone() const { return mCurrent == nullptr; }
964 bool AtStart() const { return mCurrent == mList.mItems.getFirst(); }
965 void Next() {
966 NS_ASSERTION(!IsDone(), "Should have checked IsDone()!");
967 mCurrent = mCurrent->getNext();
969 void Prev() {
970 NS_ASSERTION(!AtStart(), "Should have checked AtStart()!");
971 mCurrent = mCurrent ? mCurrent->getPrevious() : mList.mItems.getLast();
973 void SetToEnd() { mCurrent = nullptr; }
975 // Skip over all items that want the given parent type. Return whether
976 // the iterator is done after doing that. The iterator must not be done
977 // when this is called.
978 inline bool SkipItemsWantingParentType(ParentType aParentType);
980 // Skip over all items that want a parent type different from the given
981 // one. Return whether the iterator is done after doing that. The
982 // iterator must not be done when this is called.
983 inline bool SkipItemsNotWantingParentType(ParentType aParentType);
985 // Skip over non-replaced inline frames and positioned frames.
986 // Return whether the iterator is done after doing that.
987 // The iterator must not be done when this is called.
988 inline bool SkipItemsThatNeedAnonFlexOrGridItem(
989 const nsFrameConstructorState& aState, bool aIsWebkitBox);
991 // Skip to the first frame that is a non-replaced inline or is
992 // positioned. Return whether the iterator is done after doing that.
993 // The iterator must not be done when this is called.
994 inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
995 const nsFrameConstructorState& aState, bool aIsWebkitBox);
997 // Skip over all items that do not want a ruby parent. Return whether
998 // the iterator is done after doing that. The iterator must not be done
999 // when this is called.
1000 inline bool SkipItemsNotWantingRubyParent();
1002 // Skip over whitespace. Return whether the iterator is done after doing
1003 // that. The iterator must not be done, and must be pointing to a
1004 // whitespace item when this is called.
1005 inline bool SkipWhitespace(nsFrameConstructorState& aState);
1007 // Remove the item pointed to by this iterator from its current list and
1008 // Append it to aTargetList. This iterator is advanced to point to the
1009 // next item in its list. aIter must not be done. aTargetList must not
1010 // be the list this iterator is iterating over..
1011 void AppendItemToList(FrameConstructionItemList& aTargetList);
1013 // As above, but moves all items starting with this iterator until we
1014 // get to aEnd; the item pointed to by aEnd is not stolen. This method
1015 // might have optimizations over just looping and doing StealItem for
1016 // some special cases. After this method returns, this iterator will
1017 // point to the item aEnd points to now; aEnd is not modified.
1018 // aTargetList must not be the list this iterator is iterating over.
1019 void AppendItemsToList(nsCSSFrameConstructor* aFCtor,
1020 const Iterator& aEnd,
1021 FrameConstructionItemList& aTargetList);
1023 // Insert aItem in this iterator's list right before the item pointed to
1024 // by this iterator. After the insertion, this iterator will continue to
1025 // point to the item it now points to (the one just after the
1026 // newly-inserted item). This iterator is allowed to be done; in that
1027 // case this call just appends the given item to the list.
1028 void InsertItem(FrameConstructionItem* aItem);
1030 // Delete the items between this iterator and aEnd, including the item
1031 // this iterator currently points to but not including the item pointed
1032 // to by aEnd. When this returns, this iterator will point to the same
1033 // item as aEnd. This iterator must not equal aEnd when this method is
1034 // called.
1035 void DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd);
1037 private:
1038 FrameConstructionItem* mCurrent;
1039 FrameConstructionItemList& mList;
1042 protected:
1043 FrameConstructionItemList()
1044 : mInlineCount(0),
1045 mBlockCount(0),
1046 mItemCount(0),
1047 mLineBoundaryAtStart(false),
1048 mLineBoundaryAtEnd(false),
1049 mParentHasNoShadowDOM(false) {
1050 MOZ_COUNT_CTOR(FrameConstructionItemList);
1051 memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
1054 void Destroy(nsCSSFrameConstructor* aFCtor) {
1055 while (FrameConstructionItem* item = mItems.popFirst()) {
1056 item->Delete(aFCtor);
1060 // Prevent stack instances (except as AutoFrameConstructionItemList).
1061 friend struct FrameConstructionItem;
1062 ~FrameConstructionItemList() {
1063 MOZ_COUNT_DTOR(FrameConstructionItemList);
1064 MOZ_ASSERT(mItems.isEmpty(), "leaking");
1067 private:
1068 // Not allocated from the heap!
1069 void* operator new(size_t) = delete;
1070 void* operator new[](size_t) = delete;
1071 #ifdef _MSC_VER /* Visual Studio */
1072 void operator delete(void*) { MOZ_CRASH("FrameConstructionItemList::del"); }
1073 #else
1074 void operator delete(void*) = delete;
1075 #endif
1076 void operator delete[](void*) = delete;
1077 // Placement new is used by Reset().
1078 void* operator new(size_t, void* aPtr) { return aPtr; }
1080 struct UndisplayedItem {
1081 UndisplayedItem(nsIContent* aContent, ComputedStyle* aComputedStyle)
1082 : mContent(aContent), mComputedStyle(aComputedStyle) {}
1084 nsIContent* const mContent;
1085 RefPtr<ComputedStyle> mComputedStyle;
1088 // Adjust our various counts for aItem being added or removed. aDelta
1089 // should be either +1 or -1 depending on which is happening.
1090 void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta);
1092 mozilla::LinkedList<FrameConstructionItem> mItems;
1093 uint32_t mInlineCount;
1094 uint32_t mBlockCount;
1095 uint32_t mItemCount;
1096 uint32_t mDesiredParentCounts[eParentTypeCount];
1097 // True if there is guaranteed to be a line boundary before the
1098 // frames created by these items
1099 bool mLineBoundaryAtStart;
1100 // True if there is guaranteed to be a line boundary after the
1101 // frames created by these items
1102 bool mLineBoundaryAtEnd;
1103 // True if the parent is guaranteed to have no shadow tree.
1104 bool mParentHasNoShadowDOM;
1107 /* A struct representing a list of FrameConstructionItems on the stack. */
1108 struct MOZ_RAII AutoFrameConstructionItemList final
1109 : public FrameConstructionItemList {
1110 template <typename... Args>
1111 explicit AutoFrameConstructionItemList(nsCSSFrameConstructor* aFCtor,
1112 Args&&... args)
1113 : FrameConstructionItemList(std::forward<Args>(args)...),
1114 mFCtor(aFCtor) {
1115 MOZ_ASSERT(mFCtor);
1117 ~AutoFrameConstructionItemList() { Destroy(mFCtor); }
1119 private:
1120 nsCSSFrameConstructor* const mFCtor;
1123 typedef FrameConstructionItemList::Iterator FCItemIterator;
1125 /* A struct representing an item for which frames might need to be
1126 * constructed. This contains all the information needed to construct the
1127 * frame other than the parent frame and whatever would be stored in the
1128 * frame constructor state. You probably want to use
1129 * AutoFrameConstructionItem instead of this struct. */
1130 struct FrameConstructionItem final
1131 : public mozilla::LinkedListElement<FrameConstructionItem> {
1132 FrameConstructionItem(const FrameConstructionData* aFCData,
1133 nsIContent* aContent,
1134 already_AddRefed<ComputedStyle>&& aComputedStyle,
1135 bool aSuppressWhiteSpaceOptimizations)
1136 : mFCData(aFCData),
1137 mContent(aContent),
1138 mComputedStyle(std::move(aComputedStyle)),
1139 mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations),
1140 mIsText(false),
1141 mIsGeneratedContent(false),
1142 mIsAllInline(false),
1143 mIsBlock(false),
1144 mIsPopup(false),
1145 mIsLineParticipant(false),
1146 mIsRenderedLegend(false) {
1147 MOZ_COUNT_CTOR(FrameConstructionItem);
1150 void* operator new(size_t, nsCSSFrameConstructor* aFCtor) {
1151 return aFCtor->AllocateFCItem();
1154 void Delete(nsCSSFrameConstructor* aFCtor) {
1155 mChildItems.Destroy(aFCtor);
1156 if (mIsGeneratedContent) {
1157 mContent->UnbindFromTree();
1158 NS_RELEASE(mContent);
1160 this->~FrameConstructionItem();
1161 aFCtor->FreeFCItem(this);
1164 ParentType DesiredParentType() {
1165 return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
1168 // Indicates whether (when in a flex or grid container) this item needs
1169 // to be wrapped in an anonymous block. (Note that we implement
1170 // -webkit-box/-webkit-inline-box using our standard flexbox frame class,
1171 // but we use different rules for what gets wrapped. The aIsWebkitBox
1172 // parameter here tells us whether to use those different rules.)
1173 bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
1174 bool aIsWebkitBox);
1176 // Don't call this unless the frametree really depends on the answer!
1177 // Especially so for generated content, where we don't want to reframe
1178 // things.
1179 bool IsWhitespace(nsFrameConstructorState& aState) const;
1181 bool IsLineBoundary() const {
1182 return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK);
1185 // Child frame construction items.
1186 FrameConstructionItemList mChildItems;
1188 // The FrameConstructionData to use.
1189 const FrameConstructionData* mFCData;
1190 // The nsIContent node to use when initializing the new frame.
1191 nsIContent* mContent;
1192 // The style to use for creating the new frame.
1193 RefPtr<ComputedStyle> mComputedStyle;
1194 // Whether optimizations to skip constructing textframes around
1195 // this content need to be suppressed.
1196 bool mSuppressWhiteSpaceOptimizations : 1;
1197 // Whether this is a text content item.
1198 bool mIsText : 1;
1199 // Whether this is a generated content container.
1200 // If it is, mContent is a strong pointer.
1201 bool mIsGeneratedContent : 1;
1202 // Whether construction from this item will create only frames that are
1203 // IsInlineOutside() in the principal child list. This is not precise, but
1204 // conservative: if true the frames will really be inline, whereas if false
1205 // they might still all be inline.
1206 bool mIsAllInline : 1;
1207 // Whether construction from this item will create only frames that are
1208 // IsBlockOutside() in the principal child list. This is not precise, but
1209 // conservative: if true the frames will really be blocks, whereas if false
1210 // they might still be blocks (and in particular, out-of-flows that didn't
1211 // find a containing block).
1212 bool mIsBlock : 1;
1213 // Whether construction from this item will create a popup that needs to
1214 // go into the global popup items.
1215 bool mIsPopup : 1;
1216 // Whether this item should be treated as a line participant
1217 bool mIsLineParticipant : 1;
1218 // Whether this item is the rendered legend of a <fieldset>
1219 bool mIsRenderedLegend : 1;
1221 private:
1222 // Not allocated from the general heap - instead, use the new/Delete APIs
1223 // that take a nsCSSFrameConstructor* (which manages our arena allocation).
1224 void* operator new(size_t) = delete;
1225 void* operator new[](size_t) = delete;
1226 #ifdef _MSC_VER /* Visual Studio */
1227 void operator delete(void*) { MOZ_CRASH("FrameConstructionItem::delete"); }
1228 #else
1229 void operator delete(void*) = delete;
1230 #endif
1231 void operator delete[](void*) = delete;
1232 FrameConstructionItem(const FrameConstructionItem& aOther) = delete;
1233 // Not allocated from the stack!
1234 ~FrameConstructionItem() {
1235 MOZ_COUNT_DTOR(FrameConstructionItem);
1236 MOZ_ASSERT(mChildItems.IsEmpty(), "leaking");
1241 * Convenience struct to assist in managing a temporary FrameConstructionItem
1242 * using a local variable. Castable to FrameConstructionItem so that it can
1243 * be passed transparently to functions that expect that type.
1244 * (This struct exists because FrameConstructionItem is arena-allocated, and
1245 * it's nice to abstract away its allocation/deallocation.)
1247 struct MOZ_RAII AutoFrameConstructionItem final {
1248 template <typename... Args>
1249 explicit AutoFrameConstructionItem(nsCSSFrameConstructor* aFCtor,
1250 Args&&... args)
1251 : mFCtor(aFCtor),
1252 mItem(new(aFCtor)
1253 FrameConstructionItem(std::forward<Args>(args)...)) {
1254 MOZ_ASSERT(mFCtor);
1256 ~AutoFrameConstructionItem() { mItem->Delete(mFCtor); }
1257 operator FrameConstructionItem&() { return *mItem; }
1259 private:
1260 nsCSSFrameConstructor* const mFCtor;
1261 FrameConstructionItem* const mItem;
1265 * Updates the nsFrameConstructorState auto page-name value, and restores the
1266 * previous value on destruction.
1267 * See https://drafts.csswg.org/css-page-3/#using-named-pages
1269 * To track this, this will automatically add PageValuesProperty to
1270 * the frame.
1272 * Note that this does not add PageValuesProperty to the frame when not in a
1273 * paginated context.
1275 class MOZ_RAII AutoFrameConstructionPageName final {
1276 nsFrameConstructorState& mState;
1277 const nsAtom* mNameToRestore;
1279 public:
1280 AutoFrameConstructionPageName(const AutoFrameConstructionPageName&) =
1281 delete;
1282 AutoFrameConstructionPageName(AutoFrameConstructionPageName&&) = delete;
1283 AutoFrameConstructionPageName(nsFrameConstructorState& aState,
1284 nsIFrame* const aFrame);
1285 ~AutoFrameConstructionPageName();
1289 * Function to create the anonymous flex or grid items that we need.
1290 * If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
1291 * this method is a NOP.
1292 * @param aItems the child frame construction items before pseudo creation
1293 * @param aParentFrame the parent frame
1295 void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
1296 FrameConstructionItemList& aItems,
1297 nsIFrame* aParentFrame);
1299 enum RubyWhitespaceType {
1300 eRubyNotWhitespace,
1301 eRubyInterLevelWhitespace,
1302 // Includes inter-base and inter-annotation whitespace
1303 eRubyInterLeafWhitespace,
1304 eRubyInterSegmentWhitespace
1308 * Function to compute the whitespace type according to the display
1309 * values of the previous and the next elements.
1311 static inline RubyWhitespaceType ComputeRubyWhitespaceType(
1312 mozilla::StyleDisplay aPrevDisplay, mozilla::StyleDisplay aNextDisplay);
1315 * Function to interpret the type of whitespace between
1316 * |aStartIter| and |aEndIter|.
1318 static inline RubyWhitespaceType InterpretRubyWhitespace(
1319 nsFrameConstructorState& aState, const FCItemIterator& aStartIter,
1320 const FCItemIterator& aEndIter);
1323 * Function to wrap consecutive misparented inline content into
1324 * a ruby base box or a ruby text box.
1326 void WrapItemsInPseudoRubyLeafBox(FCItemIterator& aIter,
1327 ComputedStyle* aParentStyle,
1328 nsIContent* aParentContent);
1331 * Function to wrap consecutive misparented items
1332 * into a ruby level container.
1334 inline void WrapItemsInPseudoRubyLevelContainer(
1335 nsFrameConstructorState& aState, FCItemIterator& aIter,
1336 ComputedStyle* aParentStyle, nsIContent* aParentContent);
1339 * Function to trim leading and trailing whitespaces.
1341 inline void TrimLeadingAndTrailingWhitespaces(
1342 nsFrameConstructorState& aState, FrameConstructionItemList& aItems);
1345 * Function to create internal ruby boxes.
1347 inline void CreateNeededPseudoInternalRubyBoxes(
1348 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
1349 nsIFrame* aParentFrame);
1352 * Function to create the pseudo intermediate containers we need.
1353 * @param aItems the child frame construction items before pseudo creation
1354 * @param aParentFrame the parent frame we're creating pseudos for
1356 inline void CreateNeededPseudoContainers(nsFrameConstructorState& aState,
1357 FrameConstructionItemList& aItems,
1358 nsIFrame* aParentFrame);
1361 * Function to wrap consecutive items into a pseudo parent.
1363 inline void WrapItemsInPseudoParent(nsIContent* aParentContent,
1364 ComputedStyle* aParentStyle,
1365 ParentType aWrapperType,
1366 FCItemIterator& aIter,
1367 const FCItemIterator& aEndIter);
1370 * Function to create the pseudo siblings we need.
1372 inline void CreateNeededPseudoSiblings(nsFrameConstructorState& aState,
1373 FrameConstructionItemList& aItems,
1374 nsIFrame* aParentFrame);
1376 // END TABLE SECTION
1378 protected:
1379 static nsIFrame* CreatePlaceholderFrameFor(PresShell* aPresShell,
1380 nsIContent* aContent,
1381 nsIFrame* aFrame,
1382 nsContainerFrame* aParentFrame,
1383 nsIFrame* aPrevInFlow,
1384 nsFrameState aTypeBit);
1386 private:
1387 // ConstructFieldSetFrame puts the new frame in aFrameList and
1388 // handles the kids of the fieldset
1389 nsIFrame* ConstructFieldSetFrame(nsFrameConstructorState& aState,
1390 FrameConstructionItem& aItem,
1391 nsContainerFrame* aParentFrame,
1392 const nsStyleDisplay* aStyleDisplay,
1393 nsFrameList& aFrameList);
1395 nsIFrame* ConstructListBoxSelectFrame(nsFrameConstructorState& aState,
1396 FrameConstructionItem& aItem,
1397 nsContainerFrame* aParentFrame,
1398 const nsStyleDisplay* aStyleDisplay,
1399 nsFrameList& aFrameList);
1401 // Creates a block frame wrapping an anonymous ruby frame.
1402 nsIFrame* ConstructBlockRubyFrame(nsFrameConstructorState& aState,
1403 FrameConstructionItem& aItem,
1404 nsContainerFrame* aParentFrame,
1405 const nsStyleDisplay* aStyleDisplay,
1406 nsFrameList& aFrameList);
1408 void ConstructTextFrame(const FrameConstructionData* aData,
1409 nsFrameConstructorState& aState, nsIContent* aContent,
1410 nsContainerFrame* aParentFrame,
1411 ComputedStyle* aComputedStyle,
1412 nsFrameList& aFrameList);
1414 // If aPossibleTextContent is a text node and doesn't have a frame, append a
1415 // frame construction item for it to aItems.
1416 void AddTextItemIfNeeded(nsFrameConstructorState& aState,
1417 const ComputedStyle& aParentStyle,
1418 const InsertionPoint& aInsertion,
1419 nsIContent* aPossibleTextContent,
1420 FrameConstructionItemList& aItems);
1422 // If aContent is a text node and doesn't have a frame, try to create a frame
1423 // for it.
1424 void ReframeTextIfNeeded(nsIContent* aContent);
1426 enum InsertPageBreakLocation { eBefore, eAfter };
1427 inline void AppendPageBreakItem(nsIContent* aContent,
1428 FrameConstructionItemList& aItems) {
1429 InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eAfter);
1431 inline void PrependPageBreakItem(nsIContent* aContent,
1432 FrameConstructionItemList& aItems) {
1433 InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eBefore);
1435 void InsertPageBreakItem(nsIContent* aContent,
1436 FrameConstructionItemList& aItems,
1437 InsertPageBreakLocation location);
1439 // Function to find FrameConstructionData for aElement. Will return
1440 // null if aElement is not HTML.
1441 // aParentFrame might be null. If it is, that means it was an
1442 // inline frame.
1443 static const FrameConstructionData* FindHTMLData(const Element&,
1444 nsIFrame* aParentFrame,
1445 ComputedStyle&);
1446 // HTML data-finding helper functions
1447 static const FrameConstructionData* FindSelectData(const Element&,
1448 ComputedStyle&);
1449 static const FrameConstructionData* FindImgData(const Element&,
1450 ComputedStyle&);
1451 static const FrameConstructionData* FindGeneratedImageData(const Element&,
1452 ComputedStyle&);
1453 static const FrameConstructionData* FindImgControlData(const Element&,
1454 ComputedStyle&);
1455 static const FrameConstructionData* FindSearchControlData(const Element&,
1456 ComputedStyle&);
1457 static const FrameConstructionData* FindInputData(const Element&,
1458 ComputedStyle&);
1459 static const FrameConstructionData* FindObjectData(const Element&,
1460 ComputedStyle&);
1461 static const FrameConstructionData* FindCanvasData(const Element&,
1462 ComputedStyle&);
1463 // <details> always creates a block per spec.
1464 static const FrameConstructionData* FindDetailsData(const Element&,
1465 ComputedStyle&);
1467 /* Construct a frame from the given FrameConstructionItem. This function
1468 will handle adding the frame to frame lists, processing children, setting
1469 the frame as the primary frame for the item's content, and so forth.
1471 @param aItem the FrameConstructionItem to use.
1472 @param aState the frame construction state to use.
1473 @param aParentFrame the frame to set as the parent of the
1474 newly-constructed frame.
1475 @param aFrameList the frame list to add the new frame (or its
1476 placeholder) to.
1478 void ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
1479 nsFrameConstructorState& aState,
1480 nsContainerFrame* aParentFrame,
1481 nsFrameList& aFrameList);
1483 // The guts of AddFrameConstructionItems
1484 // aParentFrame might be null. If it is, that means it was an
1485 // inline frame.
1486 void AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
1487 nsIContent* aContent,
1488 nsContainerFrame* aParentFrame,
1489 bool aSuppressWhiteSpaceOptimizations,
1490 ComputedStyle*, ItemFlags,
1491 FrameConstructionItemList& aItems);
1494 * Construct frames for the given item list and parent frame, and put the
1495 * resulting frames in aFrameList.
1497 void ConstructFramesFromItemList(nsFrameConstructorState& aState,
1498 FrameConstructionItemList& aItems,
1499 nsContainerFrame* aParentFrame,
1500 bool aParentIsWrapperAnonBox,
1501 nsFrameList& aFrameList);
1502 void ConstructFramesFromItem(nsFrameConstructorState& aState,
1503 FCItemIterator& aItem,
1504 nsContainerFrame* aParentFrame,
1505 nsFrameList& aFrameList);
1506 static bool AtLineBoundary(FCItemIterator& aIter);
1508 nsresult GetAnonymousContent(
1509 nsIContent* aParent, nsIFrame* aParentFrame,
1510 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonContent);
1512 // MathML Mod - RBS
1514 * Takes the frames in aBlockList and wraps them in a new anonymous block
1515 * frame whose content is aContent and whose parent will be aParentFrame.
1516 * The anonymous block is added to aNewList and aBlockList is cleared.
1518 void FlushAccumulatedBlock(nsFrameConstructorState& aState,
1519 nsIContent* aContent,
1520 nsContainerFrame* aParentFrame,
1521 nsFrameList& aBlockList, nsFrameList& aNewList);
1523 // Function to find FrameConstructionData for an element. Will return
1524 // null if the element is not MathML.
1525 static const FrameConstructionData* FindMathMLData(const Element&,
1526 ComputedStyle&);
1528 // Function to find FrameConstructionData for an element. Will return
1529 // null if the element is not XUL.
1530 static const FrameConstructionData* FindXULTagData(const Element&,
1531 ComputedStyle&);
1532 // XUL data-finding helper functions and structures
1533 static const FrameConstructionData* FindPopupGroupData(const Element&,
1534 ComputedStyle&);
1535 static const FrameConstructionData* FindXULButtonData(const Element&,
1536 ComputedStyle&);
1537 static const FrameConstructionData* FindXULLabelOrDescriptionData(
1538 const Element&, ComputedStyle&);
1539 #ifdef XP_MACOSX
1540 static const FrameConstructionData* FindXULMenubarData(const Element&,
1541 ComputedStyle&);
1542 #endif /* XP_MACOSX */
1545 * Constructs an outer frame, an anonymous child that wraps its real
1546 * children, and its descendant frames. This is used by both
1547 * ConstructOuterSVG and ConstructMarker, which both want an anonymous block
1548 * child for their children to go in to.
1550 nsContainerFrame* ConstructFrameWithAnonymousChild(
1551 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
1552 nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
1553 ContainerFrameCreationFunc aConstructor,
1554 ContainerFrameCreationFunc aInnerConstructor,
1555 mozilla::PseudoStyleType aInnerPseudo, bool aCandidateRootFrame);
1558 * Construct an SVGOuterSVGFrame.
1560 nsIFrame* ConstructOuterSVG(nsFrameConstructorState& aState,
1561 FrameConstructionItem& aItem,
1562 nsContainerFrame* aParentFrame,
1563 const nsStyleDisplay* aDisplay,
1564 nsFrameList& aFrameList);
1567 * Construct an SVGMarkerFrame.
1569 nsIFrame* ConstructMarker(nsFrameConstructorState& aState,
1570 FrameConstructionItem& aItem,
1571 nsContainerFrame* aParentFrame,
1572 const nsStyleDisplay* aDisplay,
1573 nsFrameList& aFrameList);
1575 static const FrameConstructionData* FindSVGData(const Element&,
1576 nsIFrame* aParentFrame,
1577 bool aIsWithinSVGText,
1578 bool aAllowsTextPathChild,
1579 ComputedStyle&);
1581 // Not static because it does PropagateScrollToViewport. If this
1582 // changes, make this static.
1583 const FrameConstructionData* FindDisplayData(const nsStyleDisplay&,
1584 const Element&);
1587 * Construct a scrollable block frame
1589 nsIFrame* ConstructScrollableBlock(nsFrameConstructorState& aState,
1590 FrameConstructionItem& aItem,
1591 nsContainerFrame* aParentFrame,
1592 const nsStyleDisplay* aDisplay,
1593 nsFrameList& aFrameList);
1596 * Construct a non-scrollable block frame
1598 nsIFrame* ConstructNonScrollableBlock(nsFrameConstructorState& aState,
1599 FrameConstructionItem& aItem,
1600 nsContainerFrame* aParentFrame,
1601 const nsStyleDisplay* aDisplay,
1602 nsFrameList& aFrameList);
1605 * This adds FrameConstructionItem objects to aItemsToConstruct for the
1606 * anonymous content returned by an nsIAnonymousContentCreator::
1607 * CreateAnonymousContent implementation.
1608 * This includes an AutoFrameConstructionPageName argument as it is always
1609 * the caller's responsibility to handle page-name tracking before calling
1610 * this function.
1612 void AddFCItemsForAnonymousContent(
1613 nsFrameConstructorState& aState, nsContainerFrame* aFrame,
1614 const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
1615 FrameConstructionItemList& aItemsToConstruct,
1616 const AutoFrameConstructionPageName& aUnusedPageNameTracker);
1619 * Construct the frames for the children of aContent. "children" is defined
1620 * as "whatever FlattenedChildIterator returns for aContent". This means
1621 * we're basically operating on children in the "flattened tree":
1623 * https://drafts.csswg.org/css-scoping/#flat-tree
1625 * This method will also handle constructing ::before, ::after,
1626 * ::first-letter, and ::first-line frames, as needed and if allowed.
1628 * If the parent is a float containing block, this method will handle pushing
1629 * it as the float containing block in aState (so there's no need for callers
1630 * to push it themselves).
1632 * @param aState the frame construction state
1633 * @param aContent the content node whose children need frames
1634 * @param aComputedStyle the style for aContent
1635 * @param aParentFrame the frame to use as the parent frame for the new
1636 * in-flow kids. Note that this must be its own content insertion frame, but
1637 * need not be be the primary frame for aContent. This frame will be
1638 * pushed as the float containing block, as needed. aFrame is also
1639 * used to find the parent style for the kids' style
1640 * (not necessary aFrame's style).
1641 * @param aCanHaveGeneratedContent Whether to allow :before and
1642 * :after styles on the parent.
1643 * @param aFrameList the list in which we should place the in-flow children
1644 * @param aAllowBlockStyles Whether to allow first-letter and first-line
1645 * styles on the parent.
1646 * @param aPossiblyLeafFrame if non-null, this should be used for the isLeaf
1647 * test and the anonymous content creation. If null, aFrame will be
1648 * used.
1650 void ProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent,
1651 ComputedStyle* aComputedStyle,
1652 nsContainerFrame* aParentFrame,
1653 const bool aCanHaveGeneratedContent,
1654 nsFrameList& aFrameList, const bool aAllowBlockStyles,
1655 nsIFrame* aPossiblyLeafFrame = nullptr);
1658 * These two functions are used when we start frame creation from a non-root
1659 * element. They should recreate the same state that we would have
1660 * arrived at if we had built frames from the root frame to aFrame.
1661 * Therefore, any calls to PushFloatContainingBlock and
1662 * PushAbsoluteContainingBlock during frame construction should get
1663 * corresponding logic in these functions.
1665 public:
1666 enum ContainingBlockType { ABS_POS, FIXED_POS };
1667 nsContainerFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame,
1668 ContainingBlockType aType);
1669 nsContainerFrame* GetFloatContainingBlock(nsIFrame* aFrame);
1671 private:
1672 // Build a scroll frame:
1673 // Calls BeginBuildingScrollFrame, InitAndRestoreFrame, and then
1674 // FinishBuildingScrollFrame.
1675 // @param aNewFrame the created scrollframe --- output only
1676 // @param aParentFrame the geometric parent that the scrollframe will have.
1677 void BuildScrollFrame(nsFrameConstructorState& aState, nsIContent* aContent,
1678 ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
1679 nsContainerFrame* aParentFrame,
1680 nsContainerFrame*& aNewFrame);
1682 // Builds the initial ScrollFrame
1683 already_AddRefed<ComputedStyle> BeginBuildingScrollFrame(
1684 nsFrameConstructorState& aState, nsIContent* aContent,
1685 ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame,
1686 mozilla::PseudoStyleType aScrolledPseudo, bool aIsRoot,
1687 nsContainerFrame*& aNewFrame);
1689 // Completes the building of the scrollframe:
1690 // Creates a view for the scrolledframe and makes it the child of the
1691 // scrollframe.
1692 void FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
1693 nsIFrame* aScrolledFrame);
1695 void InitializeListboxSelect(nsFrameConstructorState& aState,
1696 nsContainerFrame* aScrollFrame,
1697 nsContainerFrame* aScrolledFrame,
1698 nsIContent* aContent,
1699 nsContainerFrame* aParentFrame,
1700 ComputedStyle* aComputedStyle,
1701 nsFrameList& aFrameList);
1704 * Recreate frames for aContent.
1705 * @param aContent the content to recreate frames for
1706 * @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
1708 void RecreateFramesForContent(nsIContent* aContent,
1709 InsertionKind aInsertionKind);
1712 * Handles change of rowspan and colspan attributes on table cells.
1714 void UpdateTableCellSpans(nsIContent* aContent);
1716 // If removal of aFrame from the frame tree requires reconstruction of some
1717 // containing block (either of aFrame or of its parent) due to {ib} splits or
1718 // table pseudo-frames, recreate the relevant frame subtree. The return value
1719 // indicates whether this happened. aFrame must be the result of a
1720 // GetPrimaryFrame() call on a content node (which means its parent is also
1721 // not null).
1722 bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame);
1724 nsIFrame* CreateContinuingOuterTableFrame(nsIFrame* aFrame,
1725 nsContainerFrame* aParentFrame,
1726 nsIContent* aContent,
1727 ComputedStyle* aComputedStyle);
1729 nsIFrame* CreateContinuingTableFrame(nsIFrame* aFrame,
1730 nsContainerFrame* aParentFrame,
1731 nsIContent* aContent,
1732 ComputedStyle* aComputedStyle);
1734 //----------------------------------------
1736 // Methods support creating block frames and their children
1738 already_AddRefed<ComputedStyle> GetFirstLetterStyle(
1739 nsIContent* aContent, ComputedStyle* aComputedStyle);
1741 already_AddRefed<ComputedStyle> GetFirstLineStyle(
1742 nsIContent* aContent, ComputedStyle* aComputedStyle);
1744 bool ShouldHaveFirstLetterStyle(nsIContent* aContent,
1745 ComputedStyle* aComputedStyle);
1747 // Check whether a given block has first-letter style. Make sure to
1748 // only pass in blocks! And don't pass in null either.
1749 bool HasFirstLetterStyle(nsIFrame* aBlockFrame);
1751 bool ShouldHaveFirstLineStyle(nsIContent* aContent,
1752 ComputedStyle* aComputedStyle);
1754 void ShouldHaveSpecialBlockStyle(nsIContent* aContent,
1755 ComputedStyle* aComputedStyle,
1756 bool* aHaveFirstLetterStyle,
1757 bool* aHaveFirstLineStyle);
1759 // |aContentParentFrame| should be null if it's really the same as
1760 // |aParentFrame|.
1761 // @param aFrameList where we want to put the block in case it's in-flow.
1762 // @param aNewFrame an in/out parameter. On input it is the block to be
1763 // constructed. On output it is reset to the outermost
1764 // frame constructed (e.g. if we need to wrap the block in an
1765 // nsColumnSetFrame.
1766 // @param aParentFrame is the desired parent for the (possibly wrapped)
1767 // block
1768 // @param aContentParent is the parent the block would have if it
1769 // were in-flow
1770 // @param aPositionedFrameForAbsPosContainer if non-null, then the new
1771 // block should be an abs-pos container and aPositionedFrameForAbsPosContainer
1772 // is the frame whose style is making this block an abs-pos container.
1773 void ConstructBlock(nsFrameConstructorState& aState, nsIContent* aContent,
1774 nsContainerFrame* aParentFrame,
1775 nsContainerFrame* aContentParentFrame,
1776 ComputedStyle* aComputedStyle,
1777 nsContainerFrame** aNewFrame, nsFrameList& aFrameList,
1778 nsIFrame* aPositionedFrameForAbsPosContainer);
1780 // Build the initial column hierarchy around aColumnContent. This function
1781 // should be called before constructing aColumnContent's children.
1783 // Before calling FinishBuildingColumns(), we need to create column-span
1784 // siblings for aColumnContent's children. Caller can use helpers
1785 // MayNeedToCreateColumnSpanSiblings() and CreateColumnSpanSiblings() to
1786 // check whether column-span siblings might need to be created and to do
1787 // the actual work of creating them if they're needed.
1789 // @param aColumnContent the block that we're wrapping in a ColumnSet. On
1790 // entry to this function it has aComputedStyle as its style. After
1791 // this function returns, aColumnContent has a ::-moz-column-content
1792 // anonymous box style.
1793 // @param aParentFrame the parent frame we want to use for the
1794 // ColumnSetWrapperFrame (which would have been the parent of
1795 // aColumnContent if we were not creating a column hierarchy).
1796 // @param aContent is the content of the aColumnContent.
1797 // @return the outermost ColumnSetWrapperFrame.
1798 nsBlockFrame* BeginBuildingColumns(nsFrameConstructorState& aState,
1799 nsIContent* aContent,
1800 nsContainerFrame* aParentFrame,
1801 nsContainerFrame* aColumnContent,
1802 ComputedStyle* aComputedStyle);
1804 // Complete building the column hierarchy by first wrapping each
1805 // non-column-span child in aChildList in a ColumnSetFrame (skipping
1806 // column-span children), and reparenting them to have aColumnSetWrapper
1807 // as their parent.
1809 // @param aColumnSetWrapper is the frame returned by
1810 // BeginBuildingColumns(), and is the grandparent of aColumnContent.
1811 // @param aColumnContent is the block frame passed into
1812 // BeginBuildingColumns()
1813 // @param aColumnContentSiblings contains the aColumnContent's siblings, which
1814 // are the column spanners and aColumnContent's continuations returned
1815 // by CreateColumnSpanSiblings(). It'll become empty after this call.
1816 void FinishBuildingColumns(nsFrameConstructorState& aState,
1817 nsContainerFrame* aColumnSetWrapper,
1818 nsContainerFrame* aColumnContent,
1819 nsFrameList& aColumnContentSiblings);
1821 // Return whether aBlockFrame's children in aChildList, which might
1822 // contain column-span, may need to be wrapped in
1823 // ::moz-column-span-wrapper and promoted as aBlockFrame's siblings.
1825 // @param aBlockFrame is the parent of the frames in aChildList.
1827 // Note: This a check without actually looking into each frame in the
1828 // child list, so it may return false positive.
1829 bool MayNeedToCreateColumnSpanSiblings(nsContainerFrame* aBlockFrame,
1830 const nsFrameList& aChildList);
1832 // Wrap consecutive runs of column-span kids and runs of non-column-span
1833 // kids in blocks for aInitialBlock's children.
1835 // @param aInitialBlock is the parent of those frames in aChildList.
1836 // @param aChildList must begin with a column-span kid. It becomes empty
1837 // after this call.
1838 // @param aPositionedFrame if non-null, it's the frame whose style is making
1839 // aInitialBlock an abs-pos container.
1841 // Return those wrapping blocks in nsFrameList.
1842 nsFrameList CreateColumnSpanSiblings(nsFrameConstructorState& aState,
1843 nsContainerFrame* aInitialBlock,
1844 nsFrameList& aChildList,
1845 nsIFrame* aPositionedFrame);
1847 // Reconstruct the multi-column containing block of aParentFrame when we want
1848 // to insert aFrameList into aParentFrame immediately after aPrevSibling but
1849 // cannot fix the frame tree because aFrameList contains some column-spans.
1851 // Note: This method is intended to be called as a helper in ContentAppended()
1852 // and ContentRangeInserted(). It assumes aState was set up locally and wasn't
1853 // used to construct any ancestors of aParentFrame in aFrameList.
1855 // @param aParentFrame the to-be parent frame for aFrameList.
1856 // @param aFrameList the frames to be inserted. It will be cleared if we need
1857 // reconstruction.
1858 // @param aPrevSibling the position where the frames in aFrameList are going
1859 // to be inserted. Nullptr means aFrameList is being inserted at
1860 // the beginning.
1861 // @return true if the multi-column containing block of aParentFrame is
1862 // reconstructed; false otherwise.
1863 bool MaybeRecreateForColumnSpan(nsFrameConstructorState& aState,
1864 nsContainerFrame* aParentFrame,
1865 nsFrameList& aFrameList,
1866 nsIFrame* aPrevSibling);
1868 nsIFrame* ConstructInline(nsFrameConstructorState& aState,
1869 FrameConstructionItem& aItem,
1870 nsContainerFrame* aParentFrame,
1871 const nsStyleDisplay* aDisplay,
1872 nsFrameList& aFrameList);
1875 * Create any additional {ib} siblings needed to contain aChildList and put
1876 * them in aSiblings.
1878 * @param aState the frame constructor state
1879 * @param aInitialInline is an already-existing inline frame that will be
1880 * part of this {ib} split and come before everything
1881 * in aSiblings.
1882 * @param aIsPositioned true if aInitialInline is positioned.
1883 * @param aChildList is a child list starting with a block; this method
1884 * assumes that the inline has already taken all the
1885 * children it wants. When the method returns aChildList
1886 * will be empty.
1887 * @param aSiblings the nsFrameList to put the newly-created siblings into.
1889 * This method is responsible for making any SetFrameIsIBSplit calls that are
1890 * needed.
1892 void CreateIBSiblings(nsFrameConstructorState& aState,
1893 nsContainerFrame* aInitialInline, bool aIsPositioned,
1894 nsFrameList& aChildList, nsFrameList& aSiblings);
1897 * For an inline aParentItem, construct its list of child
1898 * FrameConstructionItems and set its mIsAllInline flag appropriately.
1900 void BuildInlineChildItems(nsFrameConstructorState& aState,
1901 FrameConstructionItem& aParentItem,
1902 bool aItemIsWithinSVGText,
1903 bool aItemAllowsTextPathChild);
1905 // Determine whether we need to wipe out aFrame (the insertion parent) and
1906 // rebuild the entire subtree when we insert or append new content under
1907 // aFrame.
1909 // This is similar to WipeContainingBlock(), but is called before constructing
1910 // any frame construction items. Any container frames which need reframing
1911 // regardless of the content inserted or appended can add a check in this
1912 // method.
1914 // @return true if we reconstructed the insertion parent frame; false
1915 // otherwise
1916 bool WipeInsertionParent(nsContainerFrame* aFrame);
1918 // Determine whether we need to wipe out what we just did and start over
1919 // because we're doing something like adding block kids to an inline frame
1920 // (and therefore need an {ib} split). aPrevSibling must be correct, even in
1921 // aIsAppend cases. Passing aIsAppend false even when an append is happening
1922 // is ok in terms of correctness, but can lead to unnecessary reframing. If
1923 // aIsAppend is true, then the caller MUST call
1924 // nsCSSFrameConstructor::AppendFramesToParent (as opposed to
1925 // nsFrameManager::InsertFrames directly) to add the new frames.
1926 // @return true if we reconstructed the containing block, false
1927 // otherwise
1928 bool WipeContainingBlock(nsFrameConstructorState& aState,
1929 nsIFrame* aContainingBlock, nsIFrame* aFrame,
1930 FrameConstructionItemList& aItems, bool aIsAppend,
1931 nsIFrame* aPrevSibling);
1933 void ReframeContainingBlock(nsIFrame* aFrame);
1935 //----------------------------------------
1937 // Methods support :first-letter style
1939 nsFirstLetterFrame* CreateFloatingLetterFrame(
1940 nsFrameConstructorState& aState, mozilla::dom::Text* aTextContent,
1941 nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
1942 ComputedStyle* aParentStyle, ComputedStyle* aComputedStyle,
1943 nsFrameList& aResult);
1945 void CreateLetterFrame(nsContainerFrame* aBlockFrame,
1946 nsContainerFrame* aBlockContinuation,
1947 mozilla::dom::Text* aTextContent,
1948 nsContainerFrame* aParentFrame, nsFrameList& aResult);
1950 void WrapFramesInFirstLetterFrame(nsContainerFrame* aBlockFrame,
1951 nsFrameList& aBlockFrames);
1954 * Looks in the block aBlockFrame for a text frame that contains the
1955 * first-letter of the block and creates the necessary first-letter frames
1956 * and returns them in aLetterFrames.
1958 * @param aBlockFrame the (first-continuation of) the block we are creating a
1959 * first-letter frame for
1960 * @param aBlockContinuation the current continuation of the block that we
1961 * are looking in for a textframe with suitable
1962 * contents for first-letter
1963 * @param aParentFrame the current frame whose children we are looking at for
1964 * a suitable first-letter textframe
1965 * @param aParentFrameList the first child of aParentFrame
1966 * @param aModifiedParent returns the parent of the textframe that contains
1967 * the first-letter
1968 * @param aTextFrame returns the textframe that had the first-letter
1969 * @param aPrevFrame returns the previous sibling of aTextFrame
1970 * @param aLetterFrames returns the frames that were created
1972 void WrapFramesInFirstLetterFrame(
1973 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
1974 nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
1975 nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
1976 nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking);
1978 void RecoverLetterFrames(nsContainerFrame* aBlockFrame);
1980 void RemoveLetterFrames(PresShell* aPresShell, nsContainerFrame* aBlockFrame);
1982 // Recursive helper for RemoveLetterFrames
1983 void RemoveFirstLetterFrames(PresShell* aPresShell, nsContainerFrame* aFrame,
1984 nsContainerFrame* aBlockFrame,
1985 bool* aStopLooking);
1987 // Special remove method for those pesky floating first-letter frames
1988 void RemoveFloatingFirstLetterFrames(PresShell* aPresShell,
1989 nsIFrame* aBlockFrame);
1991 // Capture state for the frame tree rooted at the frame associated with the
1992 // content object, aContent
1993 void CaptureStateForFramesOf(nsIContent* aContent,
1994 nsILayoutHistoryState* aHistoryState);
1996 //----------------------------------------
1998 // Methods support :first-line style
2000 // This method chops the initial inline-outside frames out of aFrameList.
2001 // If aLineFrame is non-null, it appends them to that frame. Otherwise, it
2002 // creates a new line frame, sets the inline frames as its initial child
2003 // list, and inserts that line frame at the front of what's left of
2004 // aFrameList. In both cases, the kids are reparented to the line frame.
2005 // After this call, aFrameList holds the frames that need to become kids of
2006 // the block (possibly including line frames).
2007 void WrapFramesInFirstLineFrame(nsFrameConstructorState& aState,
2008 nsIContent* aBlockContent,
2009 nsContainerFrame* aBlockFrame,
2010 nsFirstLineFrame* aLineFrame,
2011 nsFrameList& aFrameList);
2013 // Handle the case when a block with first-line style is appended to (by
2014 // possibly calling WrapFramesInFirstLineFrame as needed).
2015 void AppendFirstLineFrames(nsFrameConstructorState& aState,
2016 nsIContent* aContent,
2017 nsContainerFrame* aBlockFrame,
2018 nsFrameList& aFrameList);
2021 * When aFrameList is being inserted into aParentFrame, and aParentFrame has
2022 * pseudo-element-affected styles, it's possible that we're inserting under a
2023 * ::first-line frame. In that case, with servo's style system, the styles we
2024 * resolved for aFrameList are wrong (they don't take ::first-line into
2025 * account), and we should fix them up, which is what this method does.
2027 * This method does not mutate aFrameList.
2029 void CheckForFirstLineInsertion(nsIFrame* aParentFrame,
2030 nsFrameList& aFrameList);
2033 * Find the next frame for appending to a given insertion point.
2035 * We're appending, so this is almost always null, except for a few edge
2036 * cases.
2038 nsIFrame* FindNextSiblingForAppend(const InsertionPoint&);
2040 // The direction in which we should look for siblings.
2041 enum class SiblingDirection {
2042 Forward,
2043 Backward,
2047 * Find the frame for the content immediately next to the one aIter points to,
2048 * in the direction SiblingDirection indicates, following continuations if
2049 * necessary.
2051 * aIter is passed by const reference on purpose, so as not to modify the
2052 * caller's iterator.
2054 * @param aIter should be positioned such that aIter.GetPreviousChild()
2055 * is the first content to search for frames
2056 * @param aTargetContentDisplay the CSS display enum for the content aIter
2057 * points to if already known. It will be filled in if needed.
2059 template <SiblingDirection>
2060 nsIFrame* FindSibling(
2061 const mozilla::dom::FlattenedChildIterator& aIter,
2062 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2064 // Helper for the implementation of FindSibling.
2066 // Beware that this function does mutate the iterator.
2067 template <SiblingDirection>
2068 nsIFrame* FindSiblingInternal(
2069 mozilla::dom::FlattenedChildIterator&, nsIContent* aTargetContent,
2070 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2072 // An alias of FindSibling<SiblingDirection::Forward>.
2073 nsIFrame* FindNextSibling(
2074 const mozilla::dom::FlattenedChildIterator& aIter,
2075 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2076 // An alias of FindSibling<SiblingDirection::Backwards>.
2077 nsIFrame* FindPreviousSibling(
2078 const mozilla::dom::FlattenedChildIterator& aIter,
2079 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay);
2081 // Given a potential first-continuation sibling frame for aTargetContent,
2082 // verify that it is an actual valid sibling for it, and return the
2083 // appropriate continuation the new frame for aTargetContent should be
2084 // inserted next to.
2085 nsIFrame* AdjustSiblingFrame(
2086 nsIFrame* aSibling, nsIContent* aTargetContent,
2087 mozilla::Maybe<mozilla::StyleDisplay>& aTargetContentDisplay,
2088 SiblingDirection aDirection);
2090 // Find the right previous sibling for an insertion. This also updates the
2091 // parent frame to point to the correct continuation of the parent frame to
2092 // use, and returns whether this insertion is to be treated as an append.
2093 // aChild is the child being inserted.
2094 // aIsRangeInsertSafe returns whether it is safe to do a range insert with
2095 // aChild being the first child in the range. It is the callers'
2096 // responsibility to check whether a range insert is safe with regards to
2097 // fieldsets.
2098 // The skip parameters are used to ignore a range of children when looking
2099 // for a sibling. All nodes starting from aStartSkipChild and up to but not
2100 // including aEndSkipChild will be skipped over when looking for sibling
2101 // frames. Skipping a range can deal with shadow DOM, but not when there are
2102 // multiple insertion points.
2103 nsIFrame* GetInsertionPrevSibling(InsertionPoint* aInsertion, // inout
2104 nsIContent* aChild, bool* aIsAppend,
2105 bool* aIsRangeInsertSafe,
2106 nsIContent* aStartSkipChild = nullptr,
2107 nsIContent* aEndSkipChild = nullptr);
2109 // see if aContent and aSibling are legitimate siblings due to restrictions
2110 // imposed by table columns
2111 // XXXbz this code is generally wrong, since the frame for aContent
2112 // may be constructed based on tag, not based on aDisplay!
2113 bool IsValidSibling(nsIFrame* aSibling, nsIContent* aContent,
2114 mozilla::Maybe<mozilla::StyleDisplay>& aDisplay);
2116 void QuotesDirty();
2117 void CountersDirty();
2119 void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
2120 nsContainerFrame* aFrame,
2121 nsIContent* aDocElement,
2122 nsFrameList&);
2124 public:
2125 friend class nsFrameConstructorState;
2127 private:
2128 // For allocating FrameConstructionItems from the mFCItemPool arena.
2129 friend struct FrameConstructionItem;
2130 void* AllocateFCItem();
2131 void FreeFCItem(FrameConstructionItem*);
2133 mozilla::dom::Document* mDocument; // Weak ref
2135 // See the comment at the start of ConstructRootFrame for more details
2136 // about the following frames.
2138 // This is just the outermost frame for the root element.
2139 nsContainerFrame* mRootElementFrame = nullptr;
2140 // This is the frame for the root element that has no pseudo-element style.
2141 nsIFrame* mRootElementStyleFrame = nullptr;
2142 // This is the containing block that contains the root element ---
2143 // the real "initial containing block" according to CSS 2.1.
2144 nsCanvasFrame* mDocElementContainingBlock = nullptr;
2145 // This is usually mDocElementContainingBlock, except when printing, where it
2146 // is the canvas frame that is under all the printed pages.
2147 nsCanvasFrame* mCanvasFrame = nullptr;
2148 nsPageSequenceFrame* mPageSequenceFrame = nullptr;
2150 // FrameConstructionItem arena + list of freed items available for re-use.
2151 mozilla::ArenaAllocator<4096, 8> mFCItemPool;
2153 // This indicates what page name to use for the next nsPageContentFrame.
2154 // Set when CSS named pages cause a breakpoint.
2155 // This does not apply to the first page content frame, which has its name
2156 // set by nsPageContentFrame::EnsurePageName() during first reflow.
2157 RefPtr<const nsAtom> mNextPageContentFramePageName;
2159 struct FreeFCItemLink {
2160 FreeFCItemLink* mNext;
2162 FreeFCItemLink* mFirstFreeFCItem;
2163 size_t mFCItemsInUse;
2165 mozilla::ContainStyleScopeManager mContainStyleScopeManager;
2167 // Current ProcessChildren depth.
2168 uint16_t mCurrentDepth;
2169 bool mQuotesDirty : 1;
2170 bool mCountersDirty : 1;
2171 bool mAlwaysCreateFramesForIgnorableWhitespace : 1;
2173 // The layout state from our history entry (to restore scroll positions and
2174 // such from history), or a new one if there was none (so we can store scroll
2175 // positions and such during reframe).
2177 // FIXME(bug 1397239): This can leak some state sometimes for the lifetime of
2178 // the frame constructor, which is not great.
2179 nsCOMPtr<nsILayoutHistoryState> mFrameTreeState;
2182 #endif /* nsCSSFrameConstructor_h___ */