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