Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | /* |
michael@0 | 7 | * construction of a frame tree that is nearly isomorphic to the content |
michael@0 | 8 | * tree and updating of that tree in response to dynamic changes |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | #ifndef nsCSSFrameConstructor_h___ |
michael@0 | 12 | #define nsCSSFrameConstructor_h___ |
michael@0 | 13 | |
michael@0 | 14 | #include "mozilla/Attributes.h" |
michael@0 | 15 | |
michael@0 | 16 | #include "nsCOMPtr.h" |
michael@0 | 17 | #include "nsILayoutHistoryState.h" |
michael@0 | 18 | #include "nsQuoteList.h" |
michael@0 | 19 | #include "nsCounterManager.h" |
michael@0 | 20 | #include "nsCSSPseudoElements.h" |
michael@0 | 21 | #include "nsIAnonymousContentCreator.h" |
michael@0 | 22 | #include "nsFrameManager.h" |
michael@0 | 23 | #include "nsIDocument.h" |
michael@0 | 24 | |
michael@0 | 25 | struct nsFrameItems; |
michael@0 | 26 | struct nsAbsoluteItems; |
michael@0 | 27 | class nsStyleContext; |
michael@0 | 28 | struct nsStyleDisplay; |
michael@0 | 29 | class nsIDOMHTMLSelectElement; |
michael@0 | 30 | struct nsGenConInitializer; |
michael@0 | 31 | |
michael@0 | 32 | class nsICSSAnonBoxPseudo; |
michael@0 | 33 | class nsPageContentFrame; |
michael@0 | 34 | struct PendingBinding; |
michael@0 | 35 | class nsGenericDOMDataNode; |
michael@0 | 36 | |
michael@0 | 37 | class nsFrameConstructorState; |
michael@0 | 38 | class nsFrameConstructorSaveState; |
michael@0 | 39 | |
michael@0 | 40 | namespace mozilla { |
michael@0 | 41 | |
michael@0 | 42 | class RestyleManager; |
michael@0 | 43 | |
michael@0 | 44 | namespace dom { |
michael@0 | 45 | |
michael@0 | 46 | class FlattenedChildIterator; |
michael@0 | 47 | |
michael@0 | 48 | } |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | class nsCSSFrameConstructor : public nsFrameManager |
michael@0 | 52 | { |
michael@0 | 53 | public: |
michael@0 | 54 | typedef mozilla::dom::Element Element; |
michael@0 | 55 | |
michael@0 | 56 | friend class mozilla::RestyleManager; |
michael@0 | 57 | |
michael@0 | 58 | nsCSSFrameConstructor(nsIDocument *aDocument, nsIPresShell* aPresShell, |
michael@0 | 59 | nsStyleSet* aStyleSet); |
michael@0 | 60 | ~nsCSSFrameConstructor(void) { |
michael@0 | 61 | NS_ASSERTION(mUpdateCount == 0, "Dying in the middle of our own update?"); |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | // get the alternate text for a content node |
michael@0 | 65 | static void GetAlternateTextFor(nsIContent* aContent, |
michael@0 | 66 | nsIAtom* aTag, // content object's tag |
michael@0 | 67 | nsXPIDLString& aAltText); |
michael@0 | 68 | |
michael@0 | 69 | private: |
michael@0 | 70 | nsCSSFrameConstructor(const nsCSSFrameConstructor& aCopy) MOZ_DELETE; |
michael@0 | 71 | nsCSSFrameConstructor& operator=(const nsCSSFrameConstructor& aCopy) MOZ_DELETE; |
michael@0 | 72 | |
michael@0 | 73 | public: |
michael@0 | 74 | mozilla::RestyleManager* RestyleManager() const |
michael@0 | 75 | { return mPresShell->GetPresContext()->RestyleManager(); } |
michael@0 | 76 | |
michael@0 | 77 | nsIFrame* ConstructRootFrame(); |
michael@0 | 78 | |
michael@0 | 79 | nsresult ReconstructDocElementHierarchy(); |
michael@0 | 80 | |
michael@0 | 81 | // Create frames for content nodes that are marked as needing frames. This |
michael@0 | 82 | // should be called before ProcessPendingRestyles. |
michael@0 | 83 | // Note: It's the caller's responsibility to make sure to wrap a |
michael@0 | 84 | // CreateNeededFrames call in a view update batch and a script blocker. |
michael@0 | 85 | void CreateNeededFrames(); |
michael@0 | 86 | |
michael@0 | 87 | private: |
michael@0 | 88 | void CreateNeededFrames(nsIContent* aContent); |
michael@0 | 89 | |
michael@0 | 90 | enum Operation { |
michael@0 | 91 | CONTENTAPPEND, |
michael@0 | 92 | CONTENTINSERT |
michael@0 | 93 | }; |
michael@0 | 94 | |
michael@0 | 95 | // aChild is the child being inserted for inserts, and the first |
michael@0 | 96 | // child being appended for appends. |
michael@0 | 97 | bool MaybeConstructLazily(Operation aOperation, |
michael@0 | 98 | nsIContent* aContainer, |
michael@0 | 99 | nsIContent* aChild); |
michael@0 | 100 | |
michael@0 | 101 | // Issues a single ContentInserted for each child of aContainer in the range |
michael@0 | 102 | // [aStartChild, aEndChild). |
michael@0 | 103 | void IssueSingleInsertNofications(nsIContent* aContainer, |
michael@0 | 104 | nsIContent* aStartChild, |
michael@0 | 105 | nsIContent* aEndChild, |
michael@0 | 106 | bool aAllowLazyConstruction); |
michael@0 | 107 | |
michael@0 | 108 | // Checks if the children of aContainer in the range [aStartChild, aEndChild) |
michael@0 | 109 | // can be inserted/appended to one insertion point together. If so, returns |
michael@0 | 110 | // that insertion point. If not, returns null and issues single |
michael@0 | 111 | // ContentInserted calls for each child. aEndChild = nullptr indicates that we |
michael@0 | 112 | // are dealing with an append. |
michael@0 | 113 | nsIFrame* GetRangeInsertionPoint(nsIContent* aContainer, |
michael@0 | 114 | nsIContent* aStartChild, |
michael@0 | 115 | nsIContent* aEndChild, |
michael@0 | 116 | bool aAllowLazyConstruction); |
michael@0 | 117 | |
michael@0 | 118 | // Returns true if parent was recreated due to frameset child, false otherwise. |
michael@0 | 119 | bool MaybeRecreateForFrameset(nsIFrame* aParentFrame, |
michael@0 | 120 | nsIContent* aStartChild, |
michael@0 | 121 | nsIContent* aEndChild); |
michael@0 | 122 | |
michael@0 | 123 | public: |
michael@0 | 124 | /** |
michael@0 | 125 | * Lazy frame construction is controlled by the aAllowLazyConstruction bool |
michael@0 | 126 | * parameter of nsCSSFrameConstructor::ContentAppended/Inserted. It is true |
michael@0 | 127 | * for all inserts/appends as passed from the presshell, except for the |
michael@0 | 128 | * insert of the root element, which is always non-lazy. Even if the |
michael@0 | 129 | * aAllowLazyConstruction passed to ContentAppended/Inserted is true we still |
michael@0 | 130 | * may not be able to construct lazily, so we call MaybeConstructLazily. |
michael@0 | 131 | * MaybeConstructLazily does not allow lazy construction if any of the |
michael@0 | 132 | * following are true: |
michael@0 | 133 | * -we are in chrome |
michael@0 | 134 | * -the container is in a native anonymous subtree |
michael@0 | 135 | * -the container is XUL |
michael@0 | 136 | * -is any of the appended/inserted nodes are XUL or editable |
michael@0 | 137 | * -(for inserts) the child is anonymous. In the append case this function |
michael@0 | 138 | * must not be called with anonymous children. |
michael@0 | 139 | * The XUL and chrome checks are because XBL bindings only get applied at |
michael@0 | 140 | * frame construction time and some things depend on the bindings getting |
michael@0 | 141 | * attached synchronously. The editable checks are because the editor seems |
michael@0 | 142 | * to expect frames to be constructed synchronously. |
michael@0 | 143 | * |
michael@0 | 144 | * If MaybeConstructLazily returns false we construct as usual, but if it |
michael@0 | 145 | * returns true then it adds NODE_NEEDS_FRAME bits to the newly |
michael@0 | 146 | * inserted/appended nodes and adds NODE_DESCENDANTS_NEED_FRAMES bits to the |
michael@0 | 147 | * container and up along the parent chain until it hits the root or another |
michael@0 | 148 | * node with that bit set. Then it posts a restyle event to ensure that a |
michael@0 | 149 | * flush happens to construct those frames. |
michael@0 | 150 | * |
michael@0 | 151 | * When the flush happens the presshell calls |
michael@0 | 152 | * nsCSSFrameConstructor::CreateNeededFrames. CreateNeededFrames follows any |
michael@0 | 153 | * nodes with NODE_DESCENDANTS_NEED_FRAMES set down the content tree looking |
michael@0 | 154 | * for nodes with NODE_NEEDS_FRAME set. It calls ContentAppended for any runs |
michael@0 | 155 | * of nodes with NODE_NEEDS_FRAME set that are at the end of their childlist, |
michael@0 | 156 | * and ContentRangeInserted for any other runs that aren't. |
michael@0 | 157 | * |
michael@0 | 158 | * If a node is removed from the document then we don't bother unsetting any |
michael@0 | 159 | * of the lazy bits that might be set on it, its descendants, or any of its |
michael@0 | 160 | * ancestor nodes because that is a slow operation, the work might be wasted |
michael@0 | 161 | * if another node gets inserted in its place, and we can clear the bits |
michael@0 | 162 | * quicker by processing the content tree from top down the next time we call |
michael@0 | 163 | * CreateNeededFrames. (We do clear the bits when BindToTree is called on any |
michael@0 | 164 | * nsIContent; so any nodes added to the document will not have any lazy bits |
michael@0 | 165 | * set.) |
michael@0 | 166 | */ |
michael@0 | 167 | |
michael@0 | 168 | // If aAllowLazyConstruction is true then frame construction of the new |
michael@0 | 169 | // children can be done lazily. |
michael@0 | 170 | nsresult ContentAppended(nsIContent* aContainer, |
michael@0 | 171 | nsIContent* aFirstNewContent, |
michael@0 | 172 | bool aAllowLazyConstruction); |
michael@0 | 173 | |
michael@0 | 174 | // If aAllowLazyConstruction is true then frame construction of the new child |
michael@0 | 175 | // can be done lazily. |
michael@0 | 176 | nsresult ContentInserted(nsIContent* aContainer, |
michael@0 | 177 | nsIContent* aChild, |
michael@0 | 178 | nsILayoutHistoryState* aFrameState, |
michael@0 | 179 | bool aAllowLazyConstruction); |
michael@0 | 180 | |
michael@0 | 181 | // Like ContentInserted but handles inserting the children of aContainer in |
michael@0 | 182 | // the range [aStartChild, aEndChild). aStartChild must be non-null. |
michael@0 | 183 | // aEndChild may be null to indicate the range includes all kids after |
michael@0 | 184 | // aStartChild. If aAllowLazyConstruction is true then frame construction of |
michael@0 | 185 | // the new children can be done lazily. It is only allowed to be true when |
michael@0 | 186 | // inserting a single node. |
michael@0 | 187 | nsresult ContentRangeInserted(nsIContent* aContainer, |
michael@0 | 188 | nsIContent* aStartChild, |
michael@0 | 189 | nsIContent* aEndChild, |
michael@0 | 190 | nsILayoutHistoryState* aFrameState, |
michael@0 | 191 | bool aAllowLazyConstruction); |
michael@0 | 192 | |
michael@0 | 193 | enum RemoveFlags { REMOVE_CONTENT, REMOVE_FOR_RECONSTRUCTION }; |
michael@0 | 194 | nsresult ContentRemoved(nsIContent* aContainer, |
michael@0 | 195 | nsIContent* aChild, |
michael@0 | 196 | nsIContent* aOldNextSibling, |
michael@0 | 197 | RemoveFlags aFlags, |
michael@0 | 198 | bool* aDidReconstruct); |
michael@0 | 199 | |
michael@0 | 200 | nsresult CharacterDataChanged(nsIContent* aContent, |
michael@0 | 201 | CharacterDataChangeInfo* aInfo); |
michael@0 | 202 | |
michael@0 | 203 | // If aContent is a text node that has been optimized away due to being |
michael@0 | 204 | // whitespace next to a block boundary (or for some other reason), stop |
michael@0 | 205 | // doing that and create a frame for it if it should have one. This recreates |
michael@0 | 206 | // frames so be careful (although this should not change actual layout). |
michael@0 | 207 | // Returns the frame for aContent if there is one. |
michael@0 | 208 | nsIFrame* EnsureFrameForTextNode(nsGenericDOMDataNode* aContent); |
michael@0 | 209 | |
michael@0 | 210 | // generate the child frames and process bindings |
michael@0 | 211 | nsresult GenerateChildFrames(nsIFrame* aFrame); |
michael@0 | 212 | |
michael@0 | 213 | // Should be called when a frame is going to be destroyed and |
michael@0 | 214 | // WillDestroyFrameTree hasn't been called yet. |
michael@0 | 215 | void NotifyDestroyingFrame(nsIFrame* aFrame); |
michael@0 | 216 | |
michael@0 | 217 | void BeginUpdate(); |
michael@0 | 218 | void EndUpdate(); |
michael@0 | 219 | void RecalcQuotesAndCounters(); |
michael@0 | 220 | |
michael@0 | 221 | // Gets called when the presshell is destroying itself and also |
michael@0 | 222 | // when we tear down our frame tree to reconstruct it |
michael@0 | 223 | void WillDestroyFrameTree(); |
michael@0 | 224 | |
michael@0 | 225 | // Request to create a continuing frame. This method never returns null. |
michael@0 | 226 | nsIFrame* CreateContinuingFrame(nsPresContext* aPresContext, |
michael@0 | 227 | nsIFrame* aFrame, |
michael@0 | 228 | nsIFrame* aParentFrame, |
michael@0 | 229 | bool aIsFluid = true); |
michael@0 | 230 | |
michael@0 | 231 | // Copy over fixed frames from aParentFrame's prev-in-flow |
michael@0 | 232 | nsresult ReplicateFixedFrames(nsPageContentFrame* aParentFrame); |
michael@0 | 233 | |
michael@0 | 234 | // Get the XBL insertion point for a child |
michael@0 | 235 | nsIFrame* GetInsertionPoint(nsIContent* aContainer, |
michael@0 | 236 | nsIContent* aChildContent, |
michael@0 | 237 | bool* aMultiple = nullptr); |
michael@0 | 238 | |
michael@0 | 239 | nsresult CreateListBoxContent(nsPresContext* aPresContext, |
michael@0 | 240 | nsIFrame* aParentFrame, |
michael@0 | 241 | nsIFrame* aPrevFrame, |
michael@0 | 242 | nsIContent* aChild, |
michael@0 | 243 | nsIFrame** aResult, |
michael@0 | 244 | bool aIsAppend, |
michael@0 | 245 | bool aIsScrollbar, |
michael@0 | 246 | nsILayoutHistoryState* aFrameState); |
michael@0 | 247 | |
michael@0 | 248 | // GetInitialContainingBlock() is deprecated in favor of GetRootElementFrame(); |
michael@0 | 249 | // nsIFrame* GetInitialContainingBlock() { return mRootElementFrame; } |
michael@0 | 250 | // This returns the outermost frame for the root element |
michael@0 | 251 | nsIFrame* GetRootElementFrame() { return mRootElementFrame; } |
michael@0 | 252 | // This returns the frame for the root element that does not |
michael@0 | 253 | // have a psuedo-element style |
michael@0 | 254 | nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; } |
michael@0 | 255 | nsIFrame* GetPageSequenceFrame() { return mPageSequenceFrame; } |
michael@0 | 256 | |
michael@0 | 257 | // Get the frame that is the parent of the root element. |
michael@0 | 258 | nsIFrame* GetDocElementContainingBlock() |
michael@0 | 259 | { return mDocElementContainingBlock; } |
michael@0 | 260 | |
michael@0 | 261 | private: |
michael@0 | 262 | struct FrameConstructionItem; |
michael@0 | 263 | class FrameConstructionItemList; |
michael@0 | 264 | |
michael@0 | 265 | nsIFrame* ConstructPageFrame(nsIPresShell* aPresShell, |
michael@0 | 266 | nsPresContext* aPresContext, |
michael@0 | 267 | nsIFrame* aParentFrame, |
michael@0 | 268 | nsIFrame* aPrevPageFrame, |
michael@0 | 269 | nsIFrame*& aCanvasFrame); |
michael@0 | 270 | |
michael@0 | 271 | void InitAndRestoreFrame (const nsFrameConstructorState& aState, |
michael@0 | 272 | nsIContent* aContent, |
michael@0 | 273 | nsIFrame* aParentFrame, |
michael@0 | 274 | nsIFrame* aNewFrame, |
michael@0 | 275 | bool aAllowCounters = true); |
michael@0 | 276 | |
michael@0 | 277 | // aState can be null if not available; it's used as an optimization. |
michael@0 | 278 | // XXXbz IsValidSibling is the only caller that doesn't pass a state here! |
michael@0 | 279 | already_AddRefed<nsStyleContext> |
michael@0 | 280 | ResolveStyleContext(nsIFrame* aParentFrame, |
michael@0 | 281 | nsIContent* aContent, |
michael@0 | 282 | nsFrameConstructorState* aState); |
michael@0 | 283 | already_AddRefed<nsStyleContext> |
michael@0 | 284 | ResolveStyleContext(nsStyleContext* aParentStyleContext, |
michael@0 | 285 | nsIContent* aContent, |
michael@0 | 286 | nsFrameConstructorState* aState); |
michael@0 | 287 | |
michael@0 | 288 | // Add the frame construction items for the given aContent and aParentFrame |
michael@0 | 289 | // to the list. This might add more than one item in some rare cases. |
michael@0 | 290 | // If aSuppressWhiteSpaceOptimizations is true, optimizations that |
michael@0 | 291 | // may suppress the construction of white-space-only text frames |
michael@0 | 292 | // must be skipped for these items and items around them. |
michael@0 | 293 | void AddFrameConstructionItems(nsFrameConstructorState& aState, |
michael@0 | 294 | nsIContent* aContent, |
michael@0 | 295 | bool aSuppressWhiteSpaceOptimizations, |
michael@0 | 296 | nsIFrame* aParentFrame, |
michael@0 | 297 | FrameConstructionItemList& aItems); |
michael@0 | 298 | |
michael@0 | 299 | // Construct the frames for the document element. This can return null if the |
michael@0 | 300 | // document element is display:none, or if the document element has a |
michael@0 | 301 | // not-yet-loaded XBL binding, or if it's an SVG element that's not <svg>. |
michael@0 | 302 | nsIFrame* ConstructDocElementFrame(Element* aDocElement, |
michael@0 | 303 | nsILayoutHistoryState* aFrameState); |
michael@0 | 304 | |
michael@0 | 305 | // Set up our mDocElementContainingBlock correctly for the given root |
michael@0 | 306 | // content. |
michael@0 | 307 | void SetUpDocElementContainingBlock(nsIContent* aDocElement); |
michael@0 | 308 | |
michael@0 | 309 | /** |
michael@0 | 310 | * CreateAttributeContent creates a single content/frame combination for an |
michael@0 | 311 | * |attr(foo)| generated content. |
michael@0 | 312 | * |
michael@0 | 313 | * @param aParentContent the parent content for the generated content |
michael@0 | 314 | * @param aParentFrame the parent frame for the generated frame |
michael@0 | 315 | * @param aAttrNamespace the namespace of the attribute in question |
michael@0 | 316 | * @param aAttrName the localname of the attribute |
michael@0 | 317 | * @param aStyleContext the style context to use |
michael@0 | 318 | * @param aGeneratedContent the array of generated content to append the |
michael@0 | 319 | * created content to. |
michael@0 | 320 | * @param [out] aNewContent the content node we create |
michael@0 | 321 | * @param [out] aNewFrame the new frame we create |
michael@0 | 322 | */ |
michael@0 | 323 | nsresult CreateAttributeContent(nsIContent* aParentContent, |
michael@0 | 324 | nsIFrame* aParentFrame, |
michael@0 | 325 | int32_t aAttrNamespace, |
michael@0 | 326 | nsIAtom* aAttrName, |
michael@0 | 327 | nsStyleContext* aStyleContext, |
michael@0 | 328 | nsCOMArray<nsIContent>& aGeneratedContent, |
michael@0 | 329 | nsIContent** aNewContent, |
michael@0 | 330 | nsIFrame** aNewFrame); |
michael@0 | 331 | |
michael@0 | 332 | /** |
michael@0 | 333 | * Create a text node containing the given string. If aText is non-null |
michael@0 | 334 | * then we also set aText to the returned node. |
michael@0 | 335 | */ |
michael@0 | 336 | already_AddRefed<nsIContent> CreateGenConTextNode(nsFrameConstructorState& aState, |
michael@0 | 337 | const nsString& aString, |
michael@0 | 338 | nsCOMPtr<nsIDOMCharacterData>* aText, |
michael@0 | 339 | nsGenConInitializer* aInitializer); |
michael@0 | 340 | |
michael@0 | 341 | /** |
michael@0 | 342 | * Create a content node for the given generated content style. |
michael@0 | 343 | * The caller takes care of making it SetIsNativeAnonymousRoot, binding it |
michael@0 | 344 | * to the document, and creating frames for it. |
michael@0 | 345 | * @param aParentContent is the node that has the before/after style |
michael@0 | 346 | * @param aStyleContext is the 'before' or 'after' pseudo-element |
michael@0 | 347 | * style context |
michael@0 | 348 | * @param aContentIndex is the index of the content item to create |
michael@0 | 349 | */ |
michael@0 | 350 | already_AddRefed<nsIContent> CreateGeneratedContent(nsFrameConstructorState& aState, |
michael@0 | 351 | nsIContent* aParentContent, |
michael@0 | 352 | nsStyleContext* aStyleContext, |
michael@0 | 353 | uint32_t aContentIndex); |
michael@0 | 354 | |
michael@0 | 355 | // aFrame may be null; this method doesn't use it directly in any case. |
michael@0 | 356 | void CreateGeneratedContentItem(nsFrameConstructorState& aState, |
michael@0 | 357 | nsIFrame* aFrame, |
michael@0 | 358 | nsIContent* aContent, |
michael@0 | 359 | nsStyleContext* aStyleContext, |
michael@0 | 360 | nsCSSPseudoElements::Type aPseudoElement, |
michael@0 | 361 | FrameConstructionItemList& aItems); |
michael@0 | 362 | |
michael@0 | 363 | // This method can change aFrameList: it can chop off the beginning and put |
michael@0 | 364 | // it in aParentFrame while putting the remainder into a ib-split sibling of |
michael@0 | 365 | // aParentFrame. aPrevSibling must be the frame after which aFrameList is to |
michael@0 | 366 | // be placed on aParentFrame's principal child list. It may be null if |
michael@0 | 367 | // aFrameList is being added at the beginning of the child list. |
michael@0 | 368 | nsresult AppendFramesToParent(nsFrameConstructorState& aState, |
michael@0 | 369 | nsIFrame* aParentFrame, |
michael@0 | 370 | nsFrameItems& aFrameList, |
michael@0 | 371 | nsIFrame* aPrevSibling, |
michael@0 | 372 | bool aIsRecursiveCall = false); |
michael@0 | 373 | |
michael@0 | 374 | // BEGIN TABLE SECTION |
michael@0 | 375 | /** |
michael@0 | 376 | * Construct an outer table frame. This is the FrameConstructionData |
michael@0 | 377 | * callback used for the job. |
michael@0 | 378 | */ |
michael@0 | 379 | nsIFrame* ConstructTable(nsFrameConstructorState& aState, |
michael@0 | 380 | FrameConstructionItem& aItem, |
michael@0 | 381 | nsIFrame* aParentFrame, |
michael@0 | 382 | const nsStyleDisplay* aDisplay, |
michael@0 | 383 | nsFrameItems& aFrameItems); |
michael@0 | 384 | |
michael@0 | 385 | /** |
michael@0 | 386 | * FrameConstructionData callback for constructing table rows and row groups. |
michael@0 | 387 | */ |
michael@0 | 388 | nsIFrame* ConstructTableRowOrRowGroup(nsFrameConstructorState& aState, |
michael@0 | 389 | FrameConstructionItem& aItem, |
michael@0 | 390 | nsIFrame* aParentFrame, |
michael@0 | 391 | const nsStyleDisplay* aStyleDisplay, |
michael@0 | 392 | nsFrameItems& aFrameItems); |
michael@0 | 393 | |
michael@0 | 394 | /** |
michael@0 | 395 | * FrameConstructionData callback used for constructing table columns. |
michael@0 | 396 | */ |
michael@0 | 397 | nsIFrame* ConstructTableCol(nsFrameConstructorState& aState, |
michael@0 | 398 | FrameConstructionItem& aItem, |
michael@0 | 399 | nsIFrame* aParentFrame, |
michael@0 | 400 | const nsStyleDisplay* aStyleDisplay, |
michael@0 | 401 | nsFrameItems& aFrameItems); |
michael@0 | 402 | |
michael@0 | 403 | /** |
michael@0 | 404 | * FrameConstructionData callback used for constructing table cells. |
michael@0 | 405 | */ |
michael@0 | 406 | nsIFrame* ConstructTableCell(nsFrameConstructorState& aState, |
michael@0 | 407 | FrameConstructionItem& aItem, |
michael@0 | 408 | nsIFrame* aParentFrame, |
michael@0 | 409 | const nsStyleDisplay* aStyleDisplay, |
michael@0 | 410 | nsFrameItems& aFrameItems); |
michael@0 | 411 | |
michael@0 | 412 | private: |
michael@0 | 413 | /* An enum of possible parent types for anonymous table object construction */ |
michael@0 | 414 | enum ParentType { |
michael@0 | 415 | eTypeBlock = 0, /* This includes all non-table-related frames */ |
michael@0 | 416 | eTypeRow, |
michael@0 | 417 | eTypeRowGroup, |
michael@0 | 418 | eTypeColGroup, |
michael@0 | 419 | eTypeTable, |
michael@0 | 420 | eParentTypeCount |
michael@0 | 421 | }; |
michael@0 | 422 | |
michael@0 | 423 | /* 3 bits is enough to handle our ParentType values */ |
michael@0 | 424 | #define FCDATA_PARENT_TYPE_OFFSET 29 |
michael@0 | 425 | /* Macro to get the desired parent type out of an mBits member of |
michael@0 | 426 | FrameConstructionData */ |
michael@0 | 427 | #define FCDATA_DESIRED_PARENT_TYPE(_bits) \ |
michael@0 | 428 | ParentType((_bits) >> FCDATA_PARENT_TYPE_OFFSET) |
michael@0 | 429 | /* Macro to create FrameConstructionData bits out of a desired parent type */ |
michael@0 | 430 | #define FCDATA_DESIRED_PARENT_TYPE_TO_BITS(_type) \ |
michael@0 | 431 | (((uint32_t)(_type)) << FCDATA_PARENT_TYPE_OFFSET) |
michael@0 | 432 | |
michael@0 | 433 | /* Get the parent type that aParentFrame has. */ |
michael@0 | 434 | static ParentType GetParentType(nsIFrame* aParentFrame) { |
michael@0 | 435 | return GetParentType(aParentFrame->GetType()); |
michael@0 | 436 | } |
michael@0 | 437 | |
michael@0 | 438 | /* Get the parent type for the given nsIFrame type atom */ |
michael@0 | 439 | static ParentType GetParentType(nsIAtom* aFrameType); |
michael@0 | 440 | |
michael@0 | 441 | /* A constructor function that just creates an nsIFrame object. The caller |
michael@0 | 442 | is responsible for initializing the object, adding it to frame lists, |
michael@0 | 443 | constructing frames for the children, etc. |
michael@0 | 444 | |
michael@0 | 445 | @param nsIPresShell the presshell whose arena should be used to allocate |
michael@0 | 446 | the frame. |
michael@0 | 447 | @param nsStyleContext the style context to use for the frame. */ |
michael@0 | 448 | typedef nsIFrame* (* FrameCreationFunc)(nsIPresShell*, nsStyleContext*); |
michael@0 | 449 | |
michael@0 | 450 | /* A function that can be used to get a FrameConstructionData. Such |
michael@0 | 451 | a function is allowed to return null. |
michael@0 | 452 | |
michael@0 | 453 | @param nsIContent the node for which the frame is being constructed. |
michael@0 | 454 | @param nsStyleContext the style context to be used for the frame. |
michael@0 | 455 | */ |
michael@0 | 456 | struct FrameConstructionData; |
michael@0 | 457 | typedef const FrameConstructionData* |
michael@0 | 458 | (* FrameConstructionDataGetter)(Element*, nsStyleContext*); |
michael@0 | 459 | |
michael@0 | 460 | /* A constructor function that's used for complicated construction tasks. |
michael@0 | 461 | This is expected to create the new frame, initialize it, add whatever |
michael@0 | 462 | needs to be added to aFrameItems (XXXbz is that really necessary? Could |
michael@0 | 463 | caller add? Might there be cases when the returned frame or its |
michael@0 | 464 | placeholder is not the thing that ends up in aFrameItems? If not, would |
michael@0 | 465 | it be safe to do the add into the frame construction state after |
michael@0 | 466 | processing kids? Look into this as a followup!), process children as |
michael@0 | 467 | needed, etc. It is NOT expected to deal with setting the frame on the |
michael@0 | 468 | content. |
michael@0 | 469 | |
michael@0 | 470 | @param aState the frame construction state to use. |
michael@0 | 471 | @param aItem the frame construction item to use |
michael@0 | 472 | @param aParentFrame the frame to set as the parent of the |
michael@0 | 473 | newly-constructed frame. |
michael@0 | 474 | @param aStyleDisplay the display struct from aItem's mStyleContext |
michael@0 | 475 | @param aFrameItems the frame list to add the new frame (or its |
michael@0 | 476 | placeholder) to. |
michael@0 | 477 | @return the frame that was constructed. This frame is what the caller |
michael@0 | 478 | will set as the frame on the content. Guaranteed non-null. |
michael@0 | 479 | */ |
michael@0 | 480 | typedef nsIFrame* |
michael@0 | 481 | (nsCSSFrameConstructor::* FrameFullConstructor)(nsFrameConstructorState& aState, |
michael@0 | 482 | FrameConstructionItem& aItem, |
michael@0 | 483 | nsIFrame* aParentFrame, |
michael@0 | 484 | const nsStyleDisplay* aStyleDisplay, |
michael@0 | 485 | nsFrameItems& aFrameItems); |
michael@0 | 486 | |
michael@0 | 487 | /* Bits that modify the way a FrameConstructionData is handled */ |
michael@0 | 488 | |
michael@0 | 489 | /* If the FCDATA_SKIP_FRAMESET bit is set, then the frame created should not |
michael@0 | 490 | be set as the primary frame on the content node. This should only be used |
michael@0 | 491 | in very rare cases when we create more than one frame for a given content |
michael@0 | 492 | node. */ |
michael@0 | 493 | #define FCDATA_SKIP_FRAMESET 0x1 |
michael@0 | 494 | /* If the FCDATA_FUNC_IS_DATA_GETTER bit is set, then the mFunc of the |
michael@0 | 495 | FrameConstructionData is a getter function that can be used to get the |
michael@0 | 496 | actual FrameConstructionData to use. */ |
michael@0 | 497 | #define FCDATA_FUNC_IS_DATA_GETTER 0x2 |
michael@0 | 498 | /* If the FCDATA_FUNC_IS_FULL_CTOR bit is set, then the FrameConstructionData |
michael@0 | 499 | has an mFullConstructor. In this case, there is no relevant mData or |
michael@0 | 500 | mFunc */ |
michael@0 | 501 | #define FCDATA_FUNC_IS_FULL_CTOR 0x4 |
michael@0 | 502 | /* If FCDATA_DISALLOW_OUT_OF_FLOW is set, do not allow the frame to |
michael@0 | 503 | float or be absolutely positioned. This can also be used with |
michael@0 | 504 | FCDATA_FUNC_IS_FULL_CTOR to indicate what the full-constructor |
michael@0 | 505 | function will do. */ |
michael@0 | 506 | #define FCDATA_DISALLOW_OUT_OF_FLOW 0x8 |
michael@0 | 507 | /* If FCDATA_FORCE_NULL_ABSPOS_CONTAINER is set, make sure to push a |
michael@0 | 508 | null absolute containing block before processing children for this |
michael@0 | 509 | frame. If this is not set, the frame will be pushed as the |
michael@0 | 510 | absolute containing block as needed, based on its style */ |
michael@0 | 511 | #define FCDATA_FORCE_NULL_ABSPOS_CONTAINER 0x10 |
michael@0 | 512 | /* If FCDATA_WRAP_KIDS_IN_BLOCKS is set, the inline kids of the frame |
michael@0 | 513 | will be wrapped in blocks. This is only usable for MathML at the |
michael@0 | 514 | moment. */ |
michael@0 | 515 | #define FCDATA_WRAP_KIDS_IN_BLOCKS 0x20 |
michael@0 | 516 | /* If FCDATA_SUPPRESS_FRAME is set, no frame should be created for the |
michael@0 | 517 | content. If this bit is set, nothing else in the struct needs to be |
michael@0 | 518 | set. */ |
michael@0 | 519 | #define FCDATA_SUPPRESS_FRAME 0x40 |
michael@0 | 520 | /* If FCDATA_MAY_NEED_SCROLLFRAME is set, the new frame should be wrapped in |
michael@0 | 521 | a scrollframe if its overflow type so requires. */ |
michael@0 | 522 | #define FCDATA_MAY_NEED_SCROLLFRAME 0x80 |
michael@0 | 523 | #ifdef MOZ_XUL |
michael@0 | 524 | /* If FCDATA_IS_POPUP is set, the new frame is a XUL popup frame. These need |
michael@0 | 525 | some really weird special handling. */ |
michael@0 | 526 | #define FCDATA_IS_POPUP 0x100 |
michael@0 | 527 | #endif /* MOZ_XUL */ |
michael@0 | 528 | /* If FCDATA_SKIP_ABSPOS_PUSH is set, don't push this frame as an |
michael@0 | 529 | absolute containing block, no matter what its style says. */ |
michael@0 | 530 | #define FCDATA_SKIP_ABSPOS_PUSH 0x200 |
michael@0 | 531 | /* If FCDATA_DISALLOW_GENERATED_CONTENT is set, then don't allow generated |
michael@0 | 532 | content when processing kids of this frame. This should not be used with |
michael@0 | 533 | FCDATA_FUNC_IS_FULL_CTOR */ |
michael@0 | 534 | #define FCDATA_DISALLOW_GENERATED_CONTENT 0x400 |
michael@0 | 535 | /* If FCDATA_IS_TABLE_PART is set, then the frame is some sort of |
michael@0 | 536 | table-related thing and we should not attempt to fetch a table-cell parent |
michael@0 | 537 | for it if it's inside another table-related frame. */ |
michael@0 | 538 | #define FCDATA_IS_TABLE_PART 0x800 |
michael@0 | 539 | /* If FCDATA_IS_INLINE is set, then the frame is a non-replaced CSS |
michael@0 | 540 | inline box. */ |
michael@0 | 541 | #define FCDATA_IS_INLINE 0x1000 |
michael@0 | 542 | /* If FCDATA_IS_LINE_PARTICIPANT is set, the frame is something that will |
michael@0 | 543 | return true for IsFrameOfType(nsIFrame::eLineParticipant) */ |
michael@0 | 544 | #define FCDATA_IS_LINE_PARTICIPANT 0x2000 |
michael@0 | 545 | /* If FCDATA_IS_LINE_BREAK is set, the frame is something that will |
michael@0 | 546 | induce a line break boundary before and after itself. */ |
michael@0 | 547 | #define FCDATA_IS_LINE_BREAK 0x4000 |
michael@0 | 548 | /* If FCDATA_ALLOW_BLOCK_STYLES is set, allow block styles when processing |
michael@0 | 549 | children. This should not be used with FCDATA_FUNC_IS_FULL_CTOR. */ |
michael@0 | 550 | #define FCDATA_ALLOW_BLOCK_STYLES 0x8000 |
michael@0 | 551 | /* If FCDATA_USE_CHILD_ITEMS is set, then use the mChildItems in the relevant |
michael@0 | 552 | FrameConstructionItem instead of trying to process the content's children. |
michael@0 | 553 | This can be used with or without FCDATA_FUNC_IS_FULL_CTOR. |
michael@0 | 554 | The child items might still need table pseudo processing. */ |
michael@0 | 555 | #define FCDATA_USE_CHILD_ITEMS 0x10000 |
michael@0 | 556 | /* If FCDATA_FORCED_NON_SCROLLABLE_BLOCK is set, then this block |
michael@0 | 557 | would have been scrollable but has been forced to be |
michael@0 | 558 | non-scrollable due to being in a paginated context. */ |
michael@0 | 559 | #define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000 |
michael@0 | 560 | /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a |
michael@0 | 561 | block formatting context wrapper around the kids of this frame |
michael@0 | 562 | using the FrameConstructionData's mPseudoAtom for its anonymous |
michael@0 | 563 | box type. */ |
michael@0 | 564 | #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000 |
michael@0 | 565 | /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of |
michael@0 | 566 | an SVG text frame. */ |
michael@0 | 567 | #define FCDATA_IS_SVG_TEXT 0x80000 |
michael@0 | 568 | |
michael@0 | 569 | /* Structure representing information about how a frame should be |
michael@0 | 570 | constructed. */ |
michael@0 | 571 | struct FrameConstructionData { |
michael@0 | 572 | // Flag bits that can modify the way the construction happens |
michael@0 | 573 | uint32_t mBits; |
michael@0 | 574 | // We have exactly one of three types of functions, so use a union for |
michael@0 | 575 | // better cache locality for the ones that aren't pointer-to-member. That |
michael@0 | 576 | // one needs to be separate, because we can't cast between it and the |
michael@0 | 577 | // others and hence wouldn't be able to initialize the union without a |
michael@0 | 578 | // constructor and all the resulting generated code. See documentation |
michael@0 | 579 | // above for FrameCreationFunc, FrameConstructionDataGetter, and |
michael@0 | 580 | // FrameFullConstructor to see what the functions would do. |
michael@0 | 581 | union Func { |
michael@0 | 582 | FrameCreationFunc mCreationFunc; |
michael@0 | 583 | FrameConstructionDataGetter mDataGetter; |
michael@0 | 584 | } mFunc; |
michael@0 | 585 | FrameFullConstructor mFullConstructor; |
michael@0 | 586 | // For cases when FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, the |
michael@0 | 587 | // anonymous box type to use for that wrapper. |
michael@0 | 588 | nsICSSAnonBoxPseudo * const * const mAnonBoxPseudo; |
michael@0 | 589 | }; |
michael@0 | 590 | |
michael@0 | 591 | /* Structure representing a mapping of an atom to a FrameConstructionData. |
michael@0 | 592 | This can be used with non-static atoms, assuming that the nsIAtom* is |
michael@0 | 593 | stored somewhere that this struct can point to (that is, a static |
michael@0 | 594 | nsIAtom*) and that it's allocated before the struct is ever used. */ |
michael@0 | 595 | struct FrameConstructionDataByTag { |
michael@0 | 596 | // Pointer to nsIAtom* is used because we want to initialize this |
michael@0 | 597 | // statically, so before our atom tables are set up. |
michael@0 | 598 | const nsIAtom * const * const mTag; |
michael@0 | 599 | const FrameConstructionData mData; |
michael@0 | 600 | }; |
michael@0 | 601 | |
michael@0 | 602 | /* Structure representing a mapping of an integer to a |
michael@0 | 603 | FrameConstructionData. There are no magic integer values here. */ |
michael@0 | 604 | struct FrameConstructionDataByInt { |
michael@0 | 605 | /* Could be used for display or whatever else */ |
michael@0 | 606 | const int32_t mInt; |
michael@0 | 607 | const FrameConstructionData mData; |
michael@0 | 608 | }; |
michael@0 | 609 | |
michael@0 | 610 | /* Structure that has a FrameConstructionData and style context pseudo-type |
michael@0 | 611 | for a table pseudo-frame */ |
michael@0 | 612 | struct PseudoParentData { |
michael@0 | 613 | const FrameConstructionData mFCData; |
michael@0 | 614 | nsICSSAnonBoxPseudo * const * const mPseudoType; |
michael@0 | 615 | }; |
michael@0 | 616 | /* Array of such structures that we use to properly construct table |
michael@0 | 617 | pseudo-frames as needed */ |
michael@0 | 618 | static const PseudoParentData sPseudoParentData[eParentTypeCount]; |
michael@0 | 619 | |
michael@0 | 620 | /* A function that takes an integer, content, style context, and array of |
michael@0 | 621 | FrameConstructionDataByInts and finds the appropriate frame construction |
michael@0 | 622 | data to use and returns it. This can return null if none of the integers |
michael@0 | 623 | match or if the matching integer has a FrameConstructionDataGetter that |
michael@0 | 624 | returns null. */ |
michael@0 | 625 | static const FrameConstructionData* |
michael@0 | 626 | FindDataByInt(int32_t aInt, Element* aElement, |
michael@0 | 627 | nsStyleContext* aStyleContext, |
michael@0 | 628 | const FrameConstructionDataByInt* aDataPtr, |
michael@0 | 629 | uint32_t aDataLength); |
michael@0 | 630 | |
michael@0 | 631 | /* A function that takes a tag, content, style context, and array of |
michael@0 | 632 | FrameConstructionDataByTags and finds the appropriate frame construction |
michael@0 | 633 | data to use and returns it. This can return null if none of the tags |
michael@0 | 634 | match or if the matching tag has a FrameConstructionDataGetter that |
michael@0 | 635 | returns null. */ |
michael@0 | 636 | static const FrameConstructionData* |
michael@0 | 637 | FindDataByTag(nsIAtom* aTag, Element* aElement, |
michael@0 | 638 | nsStyleContext* aStyleContext, |
michael@0 | 639 | const FrameConstructionDataByTag* aDataPtr, |
michael@0 | 640 | uint32_t aDataLength); |
michael@0 | 641 | |
michael@0 | 642 | /* A class representing a list of FrameConstructionItems */ |
michael@0 | 643 | class FrameConstructionItemList { |
michael@0 | 644 | public: |
michael@0 | 645 | FrameConstructionItemList() : |
michael@0 | 646 | mInlineCount(0), |
michael@0 | 647 | mBlockCount(0), |
michael@0 | 648 | mLineParticipantCount(0), |
michael@0 | 649 | mItemCount(0), |
michael@0 | 650 | mLineBoundaryAtStart(false), |
michael@0 | 651 | mLineBoundaryAtEnd(false), |
michael@0 | 652 | mParentHasNoXBLChildren(false), |
michael@0 | 653 | mTriedConstructingFrames(false) |
michael@0 | 654 | { |
michael@0 | 655 | PR_INIT_CLIST(&mItems); |
michael@0 | 656 | memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts)); |
michael@0 | 657 | } |
michael@0 | 658 | |
michael@0 | 659 | ~FrameConstructionItemList() { |
michael@0 | 660 | PRCList* cur = PR_NEXT_LINK(&mItems); |
michael@0 | 661 | while (cur != &mItems) { |
michael@0 | 662 | PRCList* next = PR_NEXT_LINK(cur); |
michael@0 | 663 | delete ToItem(cur); |
michael@0 | 664 | cur = next; |
michael@0 | 665 | } |
michael@0 | 666 | |
michael@0 | 667 | // Leaves our mItems pointing to deleted memory in both directions, |
michael@0 | 668 | // but that's OK at this point. |
michael@0 | 669 | |
michael@0 | 670 | // Create the undisplayed entries for our mUndisplayedItems, if any, but |
michael@0 | 671 | // only if we have tried constructing frames for this item list. If we |
michael@0 | 672 | // haven't, then we're just throwing it away and will probably try again. |
michael@0 | 673 | if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) { |
michael@0 | 674 | // We could store the frame manager in a member, but just |
michael@0 | 675 | // getting it off the style context is not too bad. |
michael@0 | 676 | nsFrameManager *mgr = |
michael@0 | 677 | mUndisplayedItems[0].mStyleContext->PresContext()->FrameManager(); |
michael@0 | 678 | for (uint32_t i = 0; i < mUndisplayedItems.Length(); ++i) { |
michael@0 | 679 | UndisplayedItem& item = mUndisplayedItems[i]; |
michael@0 | 680 | mgr->SetUndisplayedContent(item.mContent, item.mStyleContext); |
michael@0 | 681 | } |
michael@0 | 682 | } |
michael@0 | 683 | } |
michael@0 | 684 | |
michael@0 | 685 | void SetLineBoundaryAtStart(bool aBoundary) { mLineBoundaryAtStart = aBoundary; } |
michael@0 | 686 | void SetLineBoundaryAtEnd(bool aBoundary) { mLineBoundaryAtEnd = aBoundary; } |
michael@0 | 687 | void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) { |
michael@0 | 688 | mParentHasNoXBLChildren = aHasNoXBLChildren; |
michael@0 | 689 | } |
michael@0 | 690 | void SetTriedConstructingFrames() { mTriedConstructingFrames = true; } |
michael@0 | 691 | bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; } |
michael@0 | 692 | bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; } |
michael@0 | 693 | bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; } |
michael@0 | 694 | bool IsEmpty() const { return PR_CLIST_IS_EMPTY(&mItems); } |
michael@0 | 695 | bool AnyItemsNeedBlockParent() const { return mLineParticipantCount != 0; } |
michael@0 | 696 | bool AreAllItemsInline() const { return mInlineCount == mItemCount; } |
michael@0 | 697 | bool AreAllItemsBlock() const { return mBlockCount == mItemCount; } |
michael@0 | 698 | bool AllWantParentType(ParentType aDesiredParentType) const { |
michael@0 | 699 | return mDesiredParentCounts[aDesiredParentType] == mItemCount; |
michael@0 | 700 | } |
michael@0 | 701 | |
michael@0 | 702 | // aSuppressWhiteSpaceOptimizations is true if optimizations that |
michael@0 | 703 | // skip constructing whitespace frames for this item or items |
michael@0 | 704 | // around it cannot be performed. |
michael@0 | 705 | FrameConstructionItem* AppendItem(const FrameConstructionData* aFCData, |
michael@0 | 706 | nsIContent* aContent, |
michael@0 | 707 | nsIAtom* aTag, |
michael@0 | 708 | int32_t aNameSpaceID, |
michael@0 | 709 | PendingBinding* aPendingBinding, |
michael@0 | 710 | already_AddRefed<nsStyleContext>&& aStyleContext, |
michael@0 | 711 | bool aSuppressWhiteSpaceOptimizations, |
michael@0 | 712 | nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren) |
michael@0 | 713 | { |
michael@0 | 714 | FrameConstructionItem* item = |
michael@0 | 715 | new FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID, |
michael@0 | 716 | aPendingBinding, aStyleContext, |
michael@0 | 717 | aSuppressWhiteSpaceOptimizations, |
michael@0 | 718 | aAnonChildren); |
michael@0 | 719 | PR_APPEND_LINK(item, &mItems); |
michael@0 | 720 | ++mItemCount; |
michael@0 | 721 | ++mDesiredParentCounts[item->DesiredParentType()]; |
michael@0 | 722 | return item; |
michael@0 | 723 | } |
michael@0 | 724 | |
michael@0 | 725 | void AppendUndisplayedItem(nsIContent* aContent, |
michael@0 | 726 | nsStyleContext* aStyleContext) { |
michael@0 | 727 | mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aStyleContext)); |
michael@0 | 728 | } |
michael@0 | 729 | |
michael@0 | 730 | void InlineItemAdded() { ++mInlineCount; } |
michael@0 | 731 | void BlockItemAdded() { ++mBlockCount; } |
michael@0 | 732 | void LineParticipantItemAdded() { ++mLineParticipantCount; } |
michael@0 | 733 | |
michael@0 | 734 | class Iterator; |
michael@0 | 735 | friend class Iterator; |
michael@0 | 736 | |
michael@0 | 737 | class Iterator { |
michael@0 | 738 | public: |
michael@0 | 739 | Iterator(FrameConstructionItemList& list) : |
michael@0 | 740 | mCurrent(PR_NEXT_LINK(&list.mItems)), |
michael@0 | 741 | mEnd(&list.mItems), |
michael@0 | 742 | mList(list) |
michael@0 | 743 | {} |
michael@0 | 744 | Iterator(const Iterator& aOther) : |
michael@0 | 745 | mCurrent(aOther.mCurrent), |
michael@0 | 746 | mEnd(aOther.mEnd), |
michael@0 | 747 | mList(aOther.mList) |
michael@0 | 748 | {} |
michael@0 | 749 | |
michael@0 | 750 | bool operator==(const Iterator& aOther) const { |
michael@0 | 751 | NS_ASSERTION(mEnd == aOther.mEnd, "Iterators for different lists?"); |
michael@0 | 752 | return mCurrent == aOther.mCurrent; |
michael@0 | 753 | } |
michael@0 | 754 | bool operator!=(const Iterator& aOther) const { |
michael@0 | 755 | return !(*this == aOther); |
michael@0 | 756 | } |
michael@0 | 757 | Iterator& operator=(const Iterator& aOther) { |
michael@0 | 758 | NS_ASSERTION(mEnd == aOther.mEnd, "Iterators for different lists?"); |
michael@0 | 759 | mCurrent = aOther.mCurrent; |
michael@0 | 760 | return *this; |
michael@0 | 761 | } |
michael@0 | 762 | |
michael@0 | 763 | FrameConstructionItemList* List() { |
michael@0 | 764 | return &mList; |
michael@0 | 765 | } |
michael@0 | 766 | |
michael@0 | 767 | operator FrameConstructionItem& () { |
michael@0 | 768 | return item(); |
michael@0 | 769 | } |
michael@0 | 770 | |
michael@0 | 771 | FrameConstructionItem& item() { |
michael@0 | 772 | return *FrameConstructionItemList::ToItem(mCurrent); |
michael@0 | 773 | } |
michael@0 | 774 | bool IsDone() const { return mCurrent == mEnd; } |
michael@0 | 775 | bool AtStart() const { return mCurrent == PR_NEXT_LINK(mEnd); } |
michael@0 | 776 | void Next() { |
michael@0 | 777 | NS_ASSERTION(!IsDone(), "Should have checked IsDone()!"); |
michael@0 | 778 | mCurrent = PR_NEXT_LINK(mCurrent); |
michael@0 | 779 | } |
michael@0 | 780 | void Prev() { |
michael@0 | 781 | NS_ASSERTION(!AtStart(), "Should have checked AtStart()!"); |
michael@0 | 782 | mCurrent = PR_PREV_LINK(mCurrent); |
michael@0 | 783 | } |
michael@0 | 784 | void SetToEnd() { mCurrent = mEnd; } |
michael@0 | 785 | |
michael@0 | 786 | // Skip over all items that want a parent type different from the given |
michael@0 | 787 | // one. Return whether the iterator is done after doing that. The |
michael@0 | 788 | // iterator must not be done when this is called. |
michael@0 | 789 | inline bool SkipItemsWantingParentType(ParentType aParentType); |
michael@0 | 790 | |
michael@0 | 791 | // Skip over non-replaced inline frames and positioned frames. |
michael@0 | 792 | // Return whether the iterator is done after doing that. |
michael@0 | 793 | // The iterator must not be done when this is called. |
michael@0 | 794 | inline bool SkipItemsThatNeedAnonFlexItem( |
michael@0 | 795 | const nsFrameConstructorState& aState); |
michael@0 | 796 | |
michael@0 | 797 | // Skip to the first frame that is a non-replaced inline or is |
michael@0 | 798 | // positioned. Return whether the iterator is done after doing that. |
michael@0 | 799 | // The iterator must not be done when this is called. |
michael@0 | 800 | inline bool SkipItemsThatDontNeedAnonFlexItem( |
michael@0 | 801 | const nsFrameConstructorState& aState); |
michael@0 | 802 | |
michael@0 | 803 | // Skip over whitespace. Return whether the iterator is done after doing |
michael@0 | 804 | // that. The iterator must not be done, and must be pointing to a |
michael@0 | 805 | // whitespace item when this is called. |
michael@0 | 806 | inline bool SkipWhitespace(nsFrameConstructorState& aState); |
michael@0 | 807 | |
michael@0 | 808 | // Remove the item pointed to by this iterator from its current list and |
michael@0 | 809 | // Append it to aTargetList. This iterator is advanced to point to the |
michael@0 | 810 | // next item in its list. aIter must not be done. aOther must not be |
michael@0 | 811 | // the list this iterator is iterating over.. |
michael@0 | 812 | void AppendItemToList(FrameConstructionItemList& aTargetList); |
michael@0 | 813 | |
michael@0 | 814 | // As above, but moves all items starting with this iterator until we |
michael@0 | 815 | // get to aEnd; the item pointed to by aEnd is not stolen. This method |
michael@0 | 816 | // might have optimizations over just looping and doing StealItem for |
michael@0 | 817 | // some special cases. After this method returns, this iterator will |
michael@0 | 818 | // point to the item aEnd points to now; aEnd is not modified. |
michael@0 | 819 | // aTargetList must not be the list this iterator is iterating over. |
michael@0 | 820 | void AppendItemsToList(const Iterator& aEnd, |
michael@0 | 821 | FrameConstructionItemList& aTargetList); |
michael@0 | 822 | |
michael@0 | 823 | // Insert aItem in this iterator's list right before the item pointed to |
michael@0 | 824 | // by this iterator. After the insertion, this iterator will continue to |
michael@0 | 825 | // point to the item it now points to (the one just after the |
michael@0 | 826 | // newly-inserted item). This iterator is allowed to be done; in that |
michael@0 | 827 | // case this call just appends the given item to the list. |
michael@0 | 828 | void InsertItem(FrameConstructionItem* aItem); |
michael@0 | 829 | |
michael@0 | 830 | // Delete the items between this iterator and aEnd, including the item |
michael@0 | 831 | // this iterator currently points to but not including the item pointed |
michael@0 | 832 | // to by aEnd. When this returns, this iterator will point to the same |
michael@0 | 833 | // item as aEnd. This iterator must not equal aEnd when this method is |
michael@0 | 834 | // called. |
michael@0 | 835 | void DeleteItemsTo(const Iterator& aEnd); |
michael@0 | 836 | |
michael@0 | 837 | private: |
michael@0 | 838 | PRCList* mCurrent; |
michael@0 | 839 | PRCList* mEnd; |
michael@0 | 840 | FrameConstructionItemList& mList; |
michael@0 | 841 | }; |
michael@0 | 842 | |
michael@0 | 843 | private: |
michael@0 | 844 | static FrameConstructionItem* ToItem(PRCList* item) { |
michael@0 | 845 | return static_cast<FrameConstructionItem*>(item); |
michael@0 | 846 | } |
michael@0 | 847 | |
michael@0 | 848 | struct UndisplayedItem { |
michael@0 | 849 | UndisplayedItem(nsIContent* aContent, nsStyleContext* aStyleContext) : |
michael@0 | 850 | mContent(aContent), mStyleContext(aStyleContext) |
michael@0 | 851 | {} |
michael@0 | 852 | |
michael@0 | 853 | nsIContent * const mContent; |
michael@0 | 854 | nsRefPtr<nsStyleContext> mStyleContext; |
michael@0 | 855 | }; |
michael@0 | 856 | |
michael@0 | 857 | // Adjust our various counts for aItem being added or removed. aDelta |
michael@0 | 858 | // should be either +1 or -1 depending on which is happening. |
michael@0 | 859 | void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta); |
michael@0 | 860 | |
michael@0 | 861 | PRCList mItems; |
michael@0 | 862 | uint32_t mInlineCount; |
michael@0 | 863 | uint32_t mBlockCount; |
michael@0 | 864 | uint32_t mLineParticipantCount; |
michael@0 | 865 | uint32_t mItemCount; |
michael@0 | 866 | uint32_t mDesiredParentCounts[eParentTypeCount]; |
michael@0 | 867 | // True if there is guaranteed to be a line boundary before the |
michael@0 | 868 | // frames created by these items |
michael@0 | 869 | bool mLineBoundaryAtStart; |
michael@0 | 870 | // True if there is guaranteed to be a line boundary after the |
michael@0 | 871 | // frames created by these items |
michael@0 | 872 | bool mLineBoundaryAtEnd; |
michael@0 | 873 | // True if the parent is guaranteed to have no XBL anonymous children |
michael@0 | 874 | bool mParentHasNoXBLChildren; |
michael@0 | 875 | // True if we have tried constructing frames from this list |
michael@0 | 876 | bool mTriedConstructingFrames; |
michael@0 | 877 | |
michael@0 | 878 | nsTArray<UndisplayedItem> mUndisplayedItems; |
michael@0 | 879 | }; |
michael@0 | 880 | |
michael@0 | 881 | typedef FrameConstructionItemList::Iterator FCItemIterator; |
michael@0 | 882 | |
michael@0 | 883 | /* A struct representing an item for which frames might need to be |
michael@0 | 884 | * constructed. This contains all the information needed to construct the |
michael@0 | 885 | * frame other than the parent frame and whatever would be stored in the |
michael@0 | 886 | * frame constructor state. */ |
michael@0 | 887 | struct FrameConstructionItem : public PRCList { |
michael@0 | 888 | // No need to PR_INIT_CLIST in the constructor because the only |
michael@0 | 889 | // place that creates us immediately appends us. |
michael@0 | 890 | FrameConstructionItem(const FrameConstructionData* aFCData, |
michael@0 | 891 | nsIContent* aContent, |
michael@0 | 892 | nsIAtom* aTag, |
michael@0 | 893 | int32_t aNameSpaceID, |
michael@0 | 894 | PendingBinding* aPendingBinding, |
michael@0 | 895 | already_AddRefed<nsStyleContext>& aStyleContext, |
michael@0 | 896 | bool aSuppressWhiteSpaceOptimizations, |
michael@0 | 897 | nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren) : |
michael@0 | 898 | mFCData(aFCData), mContent(aContent), mTag(aTag), |
michael@0 | 899 | mNameSpaceID(aNameSpaceID), |
michael@0 | 900 | mPendingBinding(aPendingBinding), mStyleContext(aStyleContext), |
michael@0 | 901 | mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations), |
michael@0 | 902 | mIsText(false), mIsGeneratedContent(false), |
michael@0 | 903 | mIsAnonymousContentCreatorContent(false), |
michael@0 | 904 | mIsRootPopupgroup(false), mIsAllInline(false), mIsBlock(false), |
michael@0 | 905 | mHasInlineEnds(false), mIsPopup(false), |
michael@0 | 906 | mIsLineParticipant(false), mIsForSVGAElement(false) |
michael@0 | 907 | { |
michael@0 | 908 | if (aAnonChildren) { |
michael@0 | 909 | NS_ASSERTION(!(mFCData->mBits & FCDATA_FUNC_IS_FULL_CTOR) || |
michael@0 | 910 | mFCData->mFullConstructor == |
michael@0 | 911 | &nsCSSFrameConstructor::ConstructInline, |
michael@0 | 912 | "This is going to fail"); |
michael@0 | 913 | NS_ASSERTION(!(mFCData->mBits & FCDATA_USE_CHILD_ITEMS), |
michael@0 | 914 | "nsIAnonymousContentCreator::CreateAnonymousContent " |
michael@0 | 915 | "implementations should not output a list where the " |
michael@0 | 916 | "items have children in this case"); |
michael@0 | 917 | mAnonChildren.SwapElements(*aAnonChildren); |
michael@0 | 918 | } |
michael@0 | 919 | } |
michael@0 | 920 | ~FrameConstructionItem() { |
michael@0 | 921 | if (mIsGeneratedContent) { |
michael@0 | 922 | mContent->UnbindFromTree(); |
michael@0 | 923 | NS_RELEASE(mContent); |
michael@0 | 924 | } |
michael@0 | 925 | } |
michael@0 | 926 | |
michael@0 | 927 | ParentType DesiredParentType() { |
michael@0 | 928 | return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits); |
michael@0 | 929 | } |
michael@0 | 930 | |
michael@0 | 931 | // Indicates whether (when in a flexbox container) this item needs to be |
michael@0 | 932 | // wrapped in an anonymous block. |
michael@0 | 933 | bool NeedsAnonFlexItem(const nsFrameConstructorState& aState); |
michael@0 | 934 | |
michael@0 | 935 | // Don't call this unless the frametree really depends on the answer! |
michael@0 | 936 | // Especially so for generated content, where we don't want to reframe |
michael@0 | 937 | // things. |
michael@0 | 938 | bool IsWhitespace(nsFrameConstructorState& aState) const; |
michael@0 | 939 | |
michael@0 | 940 | bool IsLineBoundary() const { |
michael@0 | 941 | return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK); |
michael@0 | 942 | } |
michael@0 | 943 | |
michael@0 | 944 | // The FrameConstructionData to use. |
michael@0 | 945 | const FrameConstructionData* mFCData; |
michael@0 | 946 | // The nsIContent node to use when initializing the new frame. |
michael@0 | 947 | nsIContent* mContent; |
michael@0 | 948 | // The XBL-resolved tag name to use for frame construction. |
michael@0 | 949 | nsIAtom* mTag; |
michael@0 | 950 | // The XBL-resolved namespace to use for frame construction. |
michael@0 | 951 | int32_t mNameSpaceID; |
michael@0 | 952 | // The PendingBinding for this frame construction item, if any. May be |
michael@0 | 953 | // null. We maintain a list of PendingBindings in the frame construction |
michael@0 | 954 | // state in the order in which AddToAttachedQueue should be called on them: |
michael@0 | 955 | // depth-first, post-order traversal order. Since we actually traverse the |
michael@0 | 956 | // DOM in a mix of breadth-first and depth-first, it is the responsibility |
michael@0 | 957 | // of whoever constructs FrameConstructionItem kids of a given |
michael@0 | 958 | // FrameConstructionItem to push its mPendingBinding as the current |
michael@0 | 959 | // insertion point before doing so and pop it afterward. |
michael@0 | 960 | PendingBinding* mPendingBinding; |
michael@0 | 961 | // The style context to use for creating the new frame. |
michael@0 | 962 | nsRefPtr<nsStyleContext> mStyleContext; |
michael@0 | 963 | // Whether optimizations to skip constructing textframes around |
michael@0 | 964 | // this content need to be suppressed. |
michael@0 | 965 | bool mSuppressWhiteSpaceOptimizations; |
michael@0 | 966 | // Whether this is a text content item. |
michael@0 | 967 | bool mIsText; |
michael@0 | 968 | // Whether this is a generated content container. |
michael@0 | 969 | // If it is, mContent is a strong pointer. |
michael@0 | 970 | bool mIsGeneratedContent; |
michael@0 | 971 | // Whether this is an item for nsIAnonymousContentCreator content. |
michael@0 | 972 | bool mIsAnonymousContentCreatorContent; |
michael@0 | 973 | // Whether this is an item for the root popupgroup. |
michael@0 | 974 | bool mIsRootPopupgroup; |
michael@0 | 975 | // Whether construction from this item will create only frames that are |
michael@0 | 976 | // IsInlineOutside() in the principal child list. This is not precise, but |
michael@0 | 977 | // conservative: if true the frames will really be inline, whereas if false |
michael@0 | 978 | // they might still all be inline. |
michael@0 | 979 | bool mIsAllInline; |
michael@0 | 980 | // Whether construction from this item will create only frames that are |
michael@0 | 981 | // IsBlockOutside() in the principal child list. This is not precise, but |
michael@0 | 982 | // conservative: if true the frames will really be blocks, whereas if false |
michael@0 | 983 | // they might still be blocks (and in particular, out-of-flows that didn't |
michael@0 | 984 | // find a containing block). |
michael@0 | 985 | bool mIsBlock; |
michael@0 | 986 | // Whether construction from this item will give leading and trailing |
michael@0 | 987 | // inline frames. This is equal to mIsAllInline, except for inline frame |
michael@0 | 988 | // items, where it's always true, whereas mIsAllInline might be false due |
michael@0 | 989 | // to {ib} splits. |
michael@0 | 990 | bool mHasInlineEnds; |
michael@0 | 991 | // Whether construction from this item will create a popup that needs to |
michael@0 | 992 | // go into the global popup items. |
michael@0 | 993 | bool mIsPopup; |
michael@0 | 994 | // Whether this item should be treated as a line participant |
michael@0 | 995 | bool mIsLineParticipant; |
michael@0 | 996 | // Whether this item is for an SVG <a> element |
michael@0 | 997 | bool mIsForSVGAElement; |
michael@0 | 998 | |
michael@0 | 999 | // Child frame construction items. |
michael@0 | 1000 | FrameConstructionItemList mChildItems; |
michael@0 | 1001 | |
michael@0 | 1002 | // ContentInfo list for children that have yet to have |
michael@0 | 1003 | // FrameConstructionItem objects created for them. This exists because |
michael@0 | 1004 | // AddFrameConstructionItemsInternal needs a valid frame, but in the case |
michael@0 | 1005 | // that nsIAnonymousContentCreator::CreateAnonymousContent returns items |
michael@0 | 1006 | // that have their own children (so we have a tree of ContentInfo objects |
michael@0 | 1007 | // rather than a flat list) we don't yet have a frame to provide to |
michael@0 | 1008 | // AddFrameConstructionItemsInternal in order to create the items for the |
michael@0 | 1009 | // grandchildren. That prevents FrameConstructionItems from being created |
michael@0 | 1010 | // for these grandchildren (and any descendants that they may have), |
michael@0 | 1011 | // otherwise they could have been added to the mChildItems member of their |
michael@0 | 1012 | // parent FrameConstructionItem. As it is, the grandchildren ContentInfo |
michael@0 | 1013 | // list has to be stored in this mAnonChildren member in order to delay |
michael@0 | 1014 | // construction of the FrameConstructionItems for the grandchildren until |
michael@0 | 1015 | // a frame has been created for their parent item. |
michael@0 | 1016 | nsTArray<nsIAnonymousContentCreator::ContentInfo> mAnonChildren; |
michael@0 | 1017 | |
michael@0 | 1018 | private: |
michael@0 | 1019 | FrameConstructionItem(const FrameConstructionItem& aOther) MOZ_DELETE; /* not implemented */ |
michael@0 | 1020 | }; |
michael@0 | 1021 | |
michael@0 | 1022 | /** |
michael@0 | 1023 | * Function to create the anonymous flex items that we need. |
michael@0 | 1024 | * If aParentFrame is not a nsFlexContainerFrame then this method is a NOP. |
michael@0 | 1025 | * @param aItems the child frame construction items before pseudo creation |
michael@0 | 1026 | * @param aParentFrame the parent frame |
michael@0 | 1027 | */ |
michael@0 | 1028 | void CreateNeededAnonFlexItems(nsFrameConstructorState& aState, |
michael@0 | 1029 | FrameConstructionItemList& aItems, |
michael@0 | 1030 | nsIFrame* aParentFrame); |
michael@0 | 1031 | |
michael@0 | 1032 | /** |
michael@0 | 1033 | * Function to create the table pseudo items we need. |
michael@0 | 1034 | * @param aItems the child frame construction items before pseudo creation |
michael@0 | 1035 | * @param aParentFrame the parent frame we're creating pseudos for |
michael@0 | 1036 | */ |
michael@0 | 1037 | inline void CreateNeededTablePseudos(nsFrameConstructorState& aState, |
michael@0 | 1038 | FrameConstructionItemList& aItems, |
michael@0 | 1039 | nsIFrame* aParentFrame); |
michael@0 | 1040 | |
michael@0 | 1041 | /** |
michael@0 | 1042 | * Function to adjust aParentFrame to deal with captions. |
michael@0 | 1043 | * @param aParentFrame the frame we think should be the parent. This will be |
michael@0 | 1044 | * adjusted to point to the right parent frame. |
michael@0 | 1045 | * @param aFCData the FrameConstructionData that would be used for frame |
michael@0 | 1046 | * construction. |
michael@0 | 1047 | * @param aStyleContext the style context for aChildContent |
michael@0 | 1048 | */ |
michael@0 | 1049 | // XXXbz this function should really go away once we rework pseudo-frame |
michael@0 | 1050 | // handling to be better. This should simply be part of the job of |
michael@0 | 1051 | // GetGeometricParent, and stuff like the frameitems and parent frame should |
michael@0 | 1052 | // be kept track of in the state... |
michael@0 | 1053 | void AdjustParentFrame(nsIFrame* & aParentFrame, |
michael@0 | 1054 | const FrameConstructionData* aFCData, |
michael@0 | 1055 | nsStyleContext* aStyleContext); |
michael@0 | 1056 | |
michael@0 | 1057 | // END TABLE SECTION |
michael@0 | 1058 | |
michael@0 | 1059 | protected: |
michael@0 | 1060 | static nsIFrame* CreatePlaceholderFrameFor(nsIPresShell* aPresShell, |
michael@0 | 1061 | nsIContent* aContent, |
michael@0 | 1062 | nsIFrame* aFrame, |
michael@0 | 1063 | nsStyleContext* aStyleContext, |
michael@0 | 1064 | nsIFrame* aParentFrame, |
michael@0 | 1065 | nsIFrame* aPrevInFlow, |
michael@0 | 1066 | nsFrameState aTypeBit); |
michael@0 | 1067 | |
michael@0 | 1068 | private: |
michael@0 | 1069 | // ConstructSelectFrame puts the new frame in aFrameItems and |
michael@0 | 1070 | // handles the kids of the select. |
michael@0 | 1071 | nsIFrame* ConstructSelectFrame(nsFrameConstructorState& aState, |
michael@0 | 1072 | FrameConstructionItem& aItem, |
michael@0 | 1073 | nsIFrame* aParentFrame, |
michael@0 | 1074 | const nsStyleDisplay* aStyleDisplay, |
michael@0 | 1075 | nsFrameItems& aFrameItems); |
michael@0 | 1076 | |
michael@0 | 1077 | // ConstructFieldSetFrame puts the new frame in aFrameItems and |
michael@0 | 1078 | // handles the kids of the fieldset |
michael@0 | 1079 | nsIFrame* ConstructFieldSetFrame(nsFrameConstructorState& aState, |
michael@0 | 1080 | FrameConstructionItem& aItem, |
michael@0 | 1081 | nsIFrame* aParentFrame, |
michael@0 | 1082 | const nsStyleDisplay* aStyleDisplay, |
michael@0 | 1083 | nsFrameItems& aFrameItems); |
michael@0 | 1084 | |
michael@0 | 1085 | // aParentFrame might be null. If it is, that means it was an |
michael@0 | 1086 | // inline frame. |
michael@0 | 1087 | static const FrameConstructionData* FindTextData(nsIFrame* aParentFrame); |
michael@0 | 1088 | |
michael@0 | 1089 | void ConstructTextFrame(const FrameConstructionData* aData, |
michael@0 | 1090 | nsFrameConstructorState& aState, |
michael@0 | 1091 | nsIContent* aContent, |
michael@0 | 1092 | nsIFrame* aParentFrame, |
michael@0 | 1093 | nsStyleContext* aStyleContext, |
michael@0 | 1094 | nsFrameItems& aFrameItems); |
michael@0 | 1095 | |
michael@0 | 1096 | // If aPossibleTextContent is a text node and doesn't have a frame, append a |
michael@0 | 1097 | // frame construction item for it to aItems. |
michael@0 | 1098 | void AddTextItemIfNeeded(nsFrameConstructorState& aState, |
michael@0 | 1099 | nsIFrame* aParentFrame, |
michael@0 | 1100 | nsIContent* aPossibleTextContent, |
michael@0 | 1101 | FrameConstructionItemList& aItems); |
michael@0 | 1102 | |
michael@0 | 1103 | // If aParentContent's child aContent is a text node and |
michael@0 | 1104 | // doesn't have a frame, try to create a frame for it. |
michael@0 | 1105 | void ReframeTextIfNeeded(nsIContent* aParentContent, |
michael@0 | 1106 | nsIContent* aContent); |
michael@0 | 1107 | |
michael@0 | 1108 | void AddPageBreakItem(nsIContent* aContent, |
michael@0 | 1109 | nsStyleContext* aMainStyleContext, |
michael@0 | 1110 | FrameConstructionItemList& aItems); |
michael@0 | 1111 | |
michael@0 | 1112 | // Function to find FrameConstructionData for aElement. Will return |
michael@0 | 1113 | // null if aElement is not HTML. |
michael@0 | 1114 | // aParentFrame might be null. If it is, that means it was an |
michael@0 | 1115 | // inline frame. |
michael@0 | 1116 | static const FrameConstructionData* FindHTMLData(Element* aContent, |
michael@0 | 1117 | nsIAtom* aTag, |
michael@0 | 1118 | int32_t aNameSpaceID, |
michael@0 | 1119 | nsIFrame* aParentFrame, |
michael@0 | 1120 | nsStyleContext* aStyleContext); |
michael@0 | 1121 | // HTML data-finding helper functions |
michael@0 | 1122 | static const FrameConstructionData* |
michael@0 | 1123 | FindImgData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1124 | static const FrameConstructionData* |
michael@0 | 1125 | FindImgControlData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1126 | static const FrameConstructionData* |
michael@0 | 1127 | FindInputData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1128 | static const FrameConstructionData* |
michael@0 | 1129 | FindObjectData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1130 | static const FrameConstructionData* |
michael@0 | 1131 | FindCanvasData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1132 | |
michael@0 | 1133 | /* Construct a frame from the given FrameConstructionItem. This function |
michael@0 | 1134 | will handle adding the frame to frame lists, processing children, setting |
michael@0 | 1135 | the frame as the primary frame for the item's content, and so forth. |
michael@0 | 1136 | |
michael@0 | 1137 | @param aItem the FrameConstructionItem to use. |
michael@0 | 1138 | @param aState the frame construction state to use. |
michael@0 | 1139 | @param aParentFrame the frame to set as the parent of the |
michael@0 | 1140 | newly-constructed frame. |
michael@0 | 1141 | @param aFrameItems the frame list to add the new frame (or its |
michael@0 | 1142 | placeholder) to. |
michael@0 | 1143 | */ |
michael@0 | 1144 | void ConstructFrameFromItemInternal(FrameConstructionItem& aItem, |
michael@0 | 1145 | nsFrameConstructorState& aState, |
michael@0 | 1146 | nsIFrame* aParentFrame, |
michael@0 | 1147 | nsFrameItems& aFrameItems); |
michael@0 | 1148 | |
michael@0 | 1149 | // possible flags for AddFrameConstructionItemInternal's aFlags argument |
michael@0 | 1150 | /* Allow xbl:base to affect the tag/namespace used. */ |
michael@0 | 1151 | #define ITEM_ALLOW_XBL_BASE 0x1 |
michael@0 | 1152 | /* Allow page-break before and after items to be created if the |
michael@0 | 1153 | style asks for them. */ |
michael@0 | 1154 | #define ITEM_ALLOW_PAGE_BREAK 0x2 |
michael@0 | 1155 | /* The item is a generated content item. */ |
michael@0 | 1156 | #define ITEM_IS_GENERATED_CONTENT 0x4 |
michael@0 | 1157 | /* The item is within an SVG text block frame. */ |
michael@0 | 1158 | #define ITEM_IS_WITHIN_SVG_TEXT 0x8 |
michael@0 | 1159 | /* The item allows items to be created for SVG <textPath> children. */ |
michael@0 | 1160 | #define ITEM_ALLOWS_TEXT_PATH_CHILD 0x10 |
michael@0 | 1161 | /* The item is content created by an nsIAnonymousContentCreator frame */ |
michael@0 | 1162 | #define ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT 0x20 |
michael@0 | 1163 | // The guts of AddFrameConstructionItems |
michael@0 | 1164 | // aParentFrame might be null. If it is, that means it was an |
michael@0 | 1165 | // inline frame. |
michael@0 | 1166 | void AddFrameConstructionItemsInternal(nsFrameConstructorState& aState, |
michael@0 | 1167 | nsIContent* aContent, |
michael@0 | 1168 | nsIFrame* aParentFrame, |
michael@0 | 1169 | nsIAtom* aTag, |
michael@0 | 1170 | int32_t aNameSpaceID, |
michael@0 | 1171 | bool aSuppressWhiteSpaceOptimizations, |
michael@0 | 1172 | nsStyleContext* aStyleContext, |
michael@0 | 1173 | uint32_t aFlags, |
michael@0 | 1174 | nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren, |
michael@0 | 1175 | FrameConstructionItemList& aItems); |
michael@0 | 1176 | |
michael@0 | 1177 | /** |
michael@0 | 1178 | * Construct frames for the given item list and parent frame, and put the |
michael@0 | 1179 | * resulting frames in aFrameItems. |
michael@0 | 1180 | */ |
michael@0 | 1181 | void ConstructFramesFromItemList(nsFrameConstructorState& aState, |
michael@0 | 1182 | FrameConstructionItemList& aItems, |
michael@0 | 1183 | nsIFrame* aParentFrame, |
michael@0 | 1184 | nsFrameItems& aFrameItems); |
michael@0 | 1185 | void ConstructFramesFromItem(nsFrameConstructorState& aState, |
michael@0 | 1186 | FCItemIterator& aItem, |
michael@0 | 1187 | nsIFrame* aParentFrame, |
michael@0 | 1188 | nsFrameItems& aFrameItems); |
michael@0 | 1189 | static bool AtLineBoundary(FCItemIterator& aIter); |
michael@0 | 1190 | |
michael@0 | 1191 | nsresult CreateAnonymousFrames(nsFrameConstructorState& aState, |
michael@0 | 1192 | nsIContent* aParent, |
michael@0 | 1193 | nsIFrame* aParentFrame, |
michael@0 | 1194 | PendingBinding * aPendingBinding, |
michael@0 | 1195 | nsFrameItems& aChildItems); |
michael@0 | 1196 | |
michael@0 | 1197 | nsresult GetAnonymousContent(nsIContent* aParent, |
michael@0 | 1198 | nsIFrame* aParentFrame, |
michael@0 | 1199 | nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonContent); |
michael@0 | 1200 | |
michael@0 | 1201 | //MathML Mod - RBS |
michael@0 | 1202 | /** |
michael@0 | 1203 | * Takes the frames in aBlockItems and wraps them in a new anonymous block |
michael@0 | 1204 | * frame whose content is aContent and whose parent will be aParentFrame. |
michael@0 | 1205 | * The anonymous block is added to aNewItems and aBlockItems is cleared. |
michael@0 | 1206 | */ |
michael@0 | 1207 | void FlushAccumulatedBlock(nsFrameConstructorState& aState, |
michael@0 | 1208 | nsIContent* aContent, |
michael@0 | 1209 | nsIFrame* aParentFrame, |
michael@0 | 1210 | nsFrameItems& aBlockItems, |
michael@0 | 1211 | nsFrameItems& aNewItems); |
michael@0 | 1212 | |
michael@0 | 1213 | // Function to find FrameConstructionData for aContent. Will return |
michael@0 | 1214 | // null if aContent is not MathML. |
michael@0 | 1215 | static const FrameConstructionData* FindMathMLData(Element* aElement, |
michael@0 | 1216 | nsIAtom* aTag, |
michael@0 | 1217 | int32_t aNameSpaceID, |
michael@0 | 1218 | nsStyleContext* aStyleContext); |
michael@0 | 1219 | |
michael@0 | 1220 | // Function to find FrameConstructionData for aContent. Will return |
michael@0 | 1221 | // null if aContent is not XUL. |
michael@0 | 1222 | static const FrameConstructionData* FindXULTagData(Element* aElement, |
michael@0 | 1223 | nsIAtom* aTag, |
michael@0 | 1224 | int32_t aNameSpaceID, |
michael@0 | 1225 | nsStyleContext* aStyleContext); |
michael@0 | 1226 | // XUL data-finding helper functions and structures |
michael@0 | 1227 | #ifdef MOZ_XUL |
michael@0 | 1228 | static const FrameConstructionData* |
michael@0 | 1229 | FindPopupGroupData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1230 | // sXULTextBoxData used for both labels and descriptions |
michael@0 | 1231 | static const FrameConstructionData sXULTextBoxData; |
michael@0 | 1232 | static const FrameConstructionData* |
michael@0 | 1233 | FindXULLabelData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1234 | static const FrameConstructionData* |
michael@0 | 1235 | FindXULDescriptionData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1236 | #ifdef XP_MACOSX |
michael@0 | 1237 | static const FrameConstructionData* |
michael@0 | 1238 | FindXULMenubarData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1239 | #endif /* XP_MACOSX */ |
michael@0 | 1240 | static const FrameConstructionData* |
michael@0 | 1241 | FindXULListBoxBodyData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1242 | static const FrameConstructionData* |
michael@0 | 1243 | FindXULListItemData(Element* aElement, nsStyleContext* aStyleContext); |
michael@0 | 1244 | #endif /* MOZ_XUL */ |
michael@0 | 1245 | |
michael@0 | 1246 | // Function to find FrameConstructionData for aContent using one of the XUL |
michael@0 | 1247 | // display types. Will return null if aDisplay doesn't have a XUL display |
michael@0 | 1248 | // type. This function performs no other checks, so should only be called if |
michael@0 | 1249 | // we know for sure that the content is not something that should get a frame |
michael@0 | 1250 | // constructed by tag. |
michael@0 | 1251 | static const FrameConstructionData* |
michael@0 | 1252 | FindXULDisplayData(const nsStyleDisplay* aDisplay, |
michael@0 | 1253 | Element* aElement, |
michael@0 | 1254 | nsStyleContext* aStyleContext); |
michael@0 | 1255 | |
michael@0 | 1256 | /** |
michael@0 | 1257 | * Constructs an outer frame, an anonymous child that wraps its real |
michael@0 | 1258 | * children, and its descendant frames. This is used by both ConstructOuterSVG |
michael@0 | 1259 | * and ConstructMarker, which both want an anonymous block child for their |
michael@0 | 1260 | * children to go in to. |
michael@0 | 1261 | */ |
michael@0 | 1262 | nsIFrame* ConstructFrameWithAnonymousChild( |
michael@0 | 1263 | nsFrameConstructorState& aState, |
michael@0 | 1264 | FrameConstructionItem& aItem, |
michael@0 | 1265 | nsIFrame* aParentFrame, |
michael@0 | 1266 | const nsStyleDisplay* aDisplay, |
michael@0 | 1267 | nsFrameItems& aFrameItems, |
michael@0 | 1268 | FrameCreationFunc aConstructor, |
michael@0 | 1269 | FrameCreationFunc aInnerConstructor, |
michael@0 | 1270 | nsICSSAnonBoxPseudo* aInnerPseudo, |
michael@0 | 1271 | bool aCandidateRootFrame); |
michael@0 | 1272 | |
michael@0 | 1273 | /** |
michael@0 | 1274 | * Construct an nsSVGOuterSVGFrame. |
michael@0 | 1275 | */ |
michael@0 | 1276 | nsIFrame* ConstructOuterSVG(nsFrameConstructorState& aState, |
michael@0 | 1277 | FrameConstructionItem& aItem, |
michael@0 | 1278 | nsIFrame* aParentFrame, |
michael@0 | 1279 | const nsStyleDisplay* aDisplay, |
michael@0 | 1280 | nsFrameItems& aFrameItems); |
michael@0 | 1281 | |
michael@0 | 1282 | /** |
michael@0 | 1283 | * Construct an nsSVGMarkerFrame. |
michael@0 | 1284 | */ |
michael@0 | 1285 | nsIFrame* ConstructMarker(nsFrameConstructorState& aState, |
michael@0 | 1286 | FrameConstructionItem& aItem, |
michael@0 | 1287 | nsIFrame* aParentFrame, |
michael@0 | 1288 | const nsStyleDisplay* aDisplay, |
michael@0 | 1289 | nsFrameItems& aFrameItems); |
michael@0 | 1290 | |
michael@0 | 1291 | static const FrameConstructionData* FindSVGData(Element* aElement, |
michael@0 | 1292 | nsIAtom* aTag, |
michael@0 | 1293 | int32_t aNameSpaceID, |
michael@0 | 1294 | nsIFrame* aParentFrame, |
michael@0 | 1295 | bool aIsWithinSVGText, |
michael@0 | 1296 | bool aAllowsTextPathChild, |
michael@0 | 1297 | nsStyleContext* aStyleContext); |
michael@0 | 1298 | |
michael@0 | 1299 | /* Not static because it does PropagateScrollToViewport. If this |
michael@0 | 1300 | changes, make this static */ |
michael@0 | 1301 | const FrameConstructionData* |
michael@0 | 1302 | FindDisplayData(const nsStyleDisplay* aDisplay, Element* aElement, |
michael@0 | 1303 | nsIFrame* aParentFrame, nsStyleContext* aStyleContext); |
michael@0 | 1304 | |
michael@0 | 1305 | /** |
michael@0 | 1306 | * Construct a scrollable block frame |
michael@0 | 1307 | */ |
michael@0 | 1308 | nsIFrame* ConstructScrollableBlock(nsFrameConstructorState& aState, |
michael@0 | 1309 | FrameConstructionItem& aItem, |
michael@0 | 1310 | nsIFrame* aParentFrame, |
michael@0 | 1311 | const nsStyleDisplay* aDisplay, |
michael@0 | 1312 | nsFrameItems& aFrameItems); |
michael@0 | 1313 | |
michael@0 | 1314 | /** |
michael@0 | 1315 | * Construct a non-scrollable block frame |
michael@0 | 1316 | */ |
michael@0 | 1317 | nsIFrame* ConstructNonScrollableBlock(nsFrameConstructorState& aState, |
michael@0 | 1318 | FrameConstructionItem& aItem, |
michael@0 | 1319 | nsIFrame* aParentFrame, |
michael@0 | 1320 | const nsStyleDisplay* aDisplay, |
michael@0 | 1321 | nsFrameItems& aFrameItems); |
michael@0 | 1322 | |
michael@0 | 1323 | /** |
michael@0 | 1324 | * This adds FrameConstructionItem objects to aItemsToConstruct for the |
michael@0 | 1325 | * anonymous content returned by an nsIAnonymousContentCreator:: |
michael@0 | 1326 | * CreateAnonymousContent implementation. |
michael@0 | 1327 | */ |
michael@0 | 1328 | void AddFCItemsForAnonymousContent( |
michael@0 | 1329 | nsFrameConstructorState& aState, |
michael@0 | 1330 | nsIFrame* aFrame, |
michael@0 | 1331 | nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems, |
michael@0 | 1332 | FrameConstructionItemList& aItemsToConstruct, |
michael@0 | 1333 | uint32_t aExtraFlags = 0); |
michael@0 | 1334 | |
michael@0 | 1335 | /** |
michael@0 | 1336 | * Construct the frames for the children of aContent. "children" is defined |
michael@0 | 1337 | * as "whatever FlattenedChildIterator returns for aContent". This means we're |
michael@0 | 1338 | * basically operating on children in the "flattened tree" per sXBL/XBL2. |
michael@0 | 1339 | * This method will also handle constructing ::before, ::after, |
michael@0 | 1340 | * ::first-letter, and ::first-line frames, as needed and if allowed. |
michael@0 | 1341 | * |
michael@0 | 1342 | * If the parent is a float containing block, this method will handle pushing |
michael@0 | 1343 | * it as the float containing block in aState (so there's no need for callers |
michael@0 | 1344 | * to push it themselves). |
michael@0 | 1345 | * |
michael@0 | 1346 | * @param aState the frame construction state |
michael@0 | 1347 | * @param aContent the content node whose children need frames |
michael@0 | 1348 | * @param aStyleContext the style context for aContent |
michael@0 | 1349 | * @param aFrame the frame to use as the parent frame for the new in-flow |
michael@0 | 1350 | * kids. Note that this must be its own content insertion frame, but |
michael@0 | 1351 | * need not be be the primary frame for aContent. This frame will be |
michael@0 | 1352 | * pushed as the float containing block, as needed. aFrame is also |
michael@0 | 1353 | * used to find the parent style context for the kids' style contexts |
michael@0 | 1354 | * (not necessary aFrame's style context). |
michael@0 | 1355 | * @param aCanHaveGeneratedContent Whether to allow :before and |
michael@0 | 1356 | * :after styles on the parent. |
michael@0 | 1357 | * @param aFrameItems the list in which we should place the in-flow children |
michael@0 | 1358 | * @param aAllowBlockStyles Whether to allow first-letter and first-line |
michael@0 | 1359 | * styles on the parent. |
michael@0 | 1360 | * @param aPendingBinding Make sure to push this into aState before doing any |
michael@0 | 1361 | * child item construction. |
michael@0 | 1362 | * @param aPossiblyLeafFrame if non-null, this should be used for the isLeaf |
michael@0 | 1363 | * test and the anonymous content creation. If null, aFrame will be |
michael@0 | 1364 | * used. |
michael@0 | 1365 | */ |
michael@0 | 1366 | void ProcessChildren(nsFrameConstructorState& aState, |
michael@0 | 1367 | nsIContent* aContent, |
michael@0 | 1368 | nsStyleContext* aStyleContext, |
michael@0 | 1369 | nsIFrame* aFrame, |
michael@0 | 1370 | const bool aCanHaveGeneratedContent, |
michael@0 | 1371 | nsFrameItems& aFrameItems, |
michael@0 | 1372 | const bool aAllowBlockStyles, |
michael@0 | 1373 | PendingBinding* aPendingBinding, |
michael@0 | 1374 | nsIFrame* aPossiblyLeafFrame = nullptr); |
michael@0 | 1375 | |
michael@0 | 1376 | nsIFrame* GetFrameFor(nsIContent* aContent); |
michael@0 | 1377 | |
michael@0 | 1378 | /** |
michael@0 | 1379 | * These two functions are used when we start frame creation from a non-root |
michael@0 | 1380 | * element. They should recreate the same state that we would have |
michael@0 | 1381 | * arrived at if we had built frames from the root frame to aFrame. |
michael@0 | 1382 | * Therefore, any calls to PushFloatContainingBlock and |
michael@0 | 1383 | * PushAbsoluteContainingBlock during frame construction should get |
michael@0 | 1384 | * corresponding logic in these functions. |
michael@0 | 1385 | */ |
michael@0 | 1386 | public: |
michael@0 | 1387 | enum ContainingBlockType { |
michael@0 | 1388 | ABS_POS, |
michael@0 | 1389 | FIXED_POS |
michael@0 | 1390 | }; |
michael@0 | 1391 | nsIFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame, ContainingBlockType aType); |
michael@0 | 1392 | nsIFrame* GetFloatContainingBlock(nsIFrame* aFrame); |
michael@0 | 1393 | |
michael@0 | 1394 | private: |
michael@0 | 1395 | nsIContent* PropagateScrollToViewport(); |
michael@0 | 1396 | |
michael@0 | 1397 | // Build a scroll frame: |
michael@0 | 1398 | // Calls BeginBuildingScrollFrame, InitAndRestoreFrame, and then FinishBuildingScrollFrame. |
michael@0 | 1399 | // @param aNewFrame the created scrollframe --- output only |
michael@0 | 1400 | // @param aParentFrame the geometric parent that the scrollframe will have. |
michael@0 | 1401 | nsresult |
michael@0 | 1402 | BuildScrollFrame(nsFrameConstructorState& aState, |
michael@0 | 1403 | nsIContent* aContent, |
michael@0 | 1404 | nsStyleContext* aContentStyle, |
michael@0 | 1405 | nsIFrame* aScrolledFrame, |
michael@0 | 1406 | nsIFrame* aParentFrame, |
michael@0 | 1407 | nsIFrame*& aNewFrame); |
michael@0 | 1408 | |
michael@0 | 1409 | // Builds the initial ScrollFrame |
michael@0 | 1410 | already_AddRefed<nsStyleContext> |
michael@0 | 1411 | BeginBuildingScrollFrame(nsFrameConstructorState& aState, |
michael@0 | 1412 | nsIContent* aContent, |
michael@0 | 1413 | nsStyleContext* aContentStyle, |
michael@0 | 1414 | nsIFrame* aParentFrame, |
michael@0 | 1415 | nsIAtom* aScrolledPseudo, |
michael@0 | 1416 | bool aIsRoot, |
michael@0 | 1417 | nsIFrame*& aNewFrame); |
michael@0 | 1418 | |
michael@0 | 1419 | // Completes the building of the scrollframe: |
michael@0 | 1420 | // Creates a view for the scrolledframe and makes it the child of the scrollframe. |
michael@0 | 1421 | void |
michael@0 | 1422 | FinishBuildingScrollFrame(nsIFrame* aScrollFrame, |
michael@0 | 1423 | nsIFrame* aScrolledFrame); |
michael@0 | 1424 | |
michael@0 | 1425 | // InitializeSelectFrame puts scrollFrame in aFrameItems if aBuildCombobox is false |
michael@0 | 1426 | // aBuildCombobox indicates if we are building a combobox that has a dropdown |
michael@0 | 1427 | // popup widget or not. |
michael@0 | 1428 | nsresult |
michael@0 | 1429 | InitializeSelectFrame(nsFrameConstructorState& aState, |
michael@0 | 1430 | nsIFrame* scrollFrame, |
michael@0 | 1431 | nsIFrame* scrolledFrame, |
michael@0 | 1432 | nsIContent* aContent, |
michael@0 | 1433 | nsIFrame* aParentFrame, |
michael@0 | 1434 | nsStyleContext* aStyleContext, |
michael@0 | 1435 | bool aBuildCombobox, |
michael@0 | 1436 | PendingBinding* aPendingBinding, |
michael@0 | 1437 | nsFrameItems& aFrameItems); |
michael@0 | 1438 | |
michael@0 | 1439 | nsresult MaybeRecreateFramesForElement(Element* aElement); |
michael@0 | 1440 | |
michael@0 | 1441 | // If aAsyncInsert is true then a restyle event will be posted to handle the |
michael@0 | 1442 | // required ContentInserted call instead of doing it immediately. |
michael@0 | 1443 | nsresult RecreateFramesForContent(nsIContent* aContent, bool aAsyncInsert); |
michael@0 | 1444 | |
michael@0 | 1445 | // If removal of aFrame from the frame tree requires reconstruction of some |
michael@0 | 1446 | // containing block (either of aFrame or of its parent) due to {ib} splits or |
michael@0 | 1447 | // table pseudo-frames, recreate the relevant frame subtree. The return value |
michael@0 | 1448 | // indicates whether this happened. If this method returns true, *aResult is |
michael@0 | 1449 | // the return value of ReframeContainingBlock or RecreateFramesForContent. If |
michael@0 | 1450 | // this method returns false, the value of *aResult is not affected. aFrame |
michael@0 | 1451 | // and aResult must not be null. aFrame must be the result of a |
michael@0 | 1452 | // GetPrimaryFrame() call on a content node (which means its parent is also |
michael@0 | 1453 | // not null). |
michael@0 | 1454 | bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, |
michael@0 | 1455 | nsresult* aResult); |
michael@0 | 1456 | |
michael@0 | 1457 | nsIFrame* CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, |
michael@0 | 1458 | nsPresContext* aPresContext, |
michael@0 | 1459 | nsIFrame* aFrame, |
michael@0 | 1460 | nsIFrame* aParentFrame, |
michael@0 | 1461 | nsIContent* aContent, |
michael@0 | 1462 | nsStyleContext* aStyleContext); |
michael@0 | 1463 | |
michael@0 | 1464 | nsIFrame* CreateContinuingTableFrame(nsIPresShell* aPresShell, |
michael@0 | 1465 | nsPresContext* aPresContext, |
michael@0 | 1466 | nsIFrame* aFrame, |
michael@0 | 1467 | nsIFrame* aParentFrame, |
michael@0 | 1468 | nsIContent* aContent, |
michael@0 | 1469 | nsStyleContext* aStyleContext); |
michael@0 | 1470 | |
michael@0 | 1471 | //---------------------------------------- |
michael@0 | 1472 | |
michael@0 | 1473 | // Methods support creating block frames and their children |
michael@0 | 1474 | |
michael@0 | 1475 | already_AddRefed<nsStyleContext> |
michael@0 | 1476 | GetFirstLetterStyle(nsIContent* aContent, |
michael@0 | 1477 | nsStyleContext* aStyleContext); |
michael@0 | 1478 | |
michael@0 | 1479 | already_AddRefed<nsStyleContext> |
michael@0 | 1480 | GetFirstLineStyle(nsIContent* aContent, |
michael@0 | 1481 | nsStyleContext* aStyleContext); |
michael@0 | 1482 | |
michael@0 | 1483 | bool ShouldHaveFirstLetterStyle(nsIContent* aContent, |
michael@0 | 1484 | nsStyleContext* aStyleContext); |
michael@0 | 1485 | |
michael@0 | 1486 | // Check whether a given block has first-letter style. Make sure to |
michael@0 | 1487 | // only pass in blocks! And don't pass in null either. |
michael@0 | 1488 | bool HasFirstLetterStyle(nsIFrame* aBlockFrame); |
michael@0 | 1489 | |
michael@0 | 1490 | bool ShouldHaveFirstLineStyle(nsIContent* aContent, |
michael@0 | 1491 | nsStyleContext* aStyleContext); |
michael@0 | 1492 | |
michael@0 | 1493 | void ShouldHaveSpecialBlockStyle(nsIContent* aContent, |
michael@0 | 1494 | nsStyleContext* aStyleContext, |
michael@0 | 1495 | bool* aHaveFirstLetterStyle, |
michael@0 | 1496 | bool* aHaveFirstLineStyle); |
michael@0 | 1497 | |
michael@0 | 1498 | // |aContentParentFrame| should be null if it's really the same as |
michael@0 | 1499 | // |aParentFrame|. |
michael@0 | 1500 | // @param aFrameItems where we want to put the block in case it's in-flow. |
michael@0 | 1501 | // @param aNewFrame an in/out parameter. On input it is the block to be |
michael@0 | 1502 | // constructed. On output it is reset to the outermost |
michael@0 | 1503 | // frame constructed (e.g. if we need to wrap the block in an |
michael@0 | 1504 | // nsColumnSetFrame. |
michael@0 | 1505 | // @param aParentFrame is the desired parent for the (possibly wrapped) |
michael@0 | 1506 | // block |
michael@0 | 1507 | // @param aContentParent is the parent the block would have if it |
michael@0 | 1508 | // were in-flow |
michael@0 | 1509 | // @param aPositionedFrameForAbsPosContainer if non-null, then the new |
michael@0 | 1510 | // block should be an abs-pos container and aPositionedFrameForAbsPosContainer |
michael@0 | 1511 | // is the frame whose style is making this block an abs-pos container. |
michael@0 | 1512 | // @param aPendingBinding the pending binding from this block's frame |
michael@0 | 1513 | // construction item. |
michael@0 | 1514 | void ConstructBlock(nsFrameConstructorState& aState, |
michael@0 | 1515 | const nsStyleDisplay* aDisplay, |
michael@0 | 1516 | nsIContent* aContent, |
michael@0 | 1517 | nsIFrame* aParentFrame, |
michael@0 | 1518 | nsIFrame* aContentParentFrame, |
michael@0 | 1519 | nsStyleContext* aStyleContext, |
michael@0 | 1520 | nsIFrame** aNewFrame, |
michael@0 | 1521 | nsFrameItems& aFrameItems, |
michael@0 | 1522 | nsIFrame* aPositionedFrameForAbsPosContainer, |
michael@0 | 1523 | PendingBinding* aPendingBinding); |
michael@0 | 1524 | |
michael@0 | 1525 | nsIFrame* ConstructInline(nsFrameConstructorState& aState, |
michael@0 | 1526 | FrameConstructionItem& aItem, |
michael@0 | 1527 | nsIFrame* aParentFrame, |
michael@0 | 1528 | const nsStyleDisplay* aDisplay, |
michael@0 | 1529 | nsFrameItems& aFrameItems); |
michael@0 | 1530 | |
michael@0 | 1531 | /** |
michael@0 | 1532 | * Create any additional {ib} siblings needed to contain aChildItems and put |
michael@0 | 1533 | * them in aSiblings. |
michael@0 | 1534 | * |
michael@0 | 1535 | * @param aState the frame constructor state |
michael@0 | 1536 | * @param aInitialInline is an already-existing inline frame that will be |
michael@0 | 1537 | * part of this {ib} split and come before everything |
michael@0 | 1538 | * in aSiblings. |
michael@0 | 1539 | * @param aIsPositioned true if aInitialInline is positioned. |
michael@0 | 1540 | * @param aChildItems is a child list starting with a block; this method |
michael@0 | 1541 | * assumes that the inline has already taken all the |
michael@0 | 1542 | * children it wants. When the method returns aChildItems |
michael@0 | 1543 | * will be empty. |
michael@0 | 1544 | * @param aSiblings the nsFrameItems to put the newly-created siblings into. |
michael@0 | 1545 | * |
michael@0 | 1546 | * This method is responsible for making any SetFrameIsIBSplit calls that are |
michael@0 | 1547 | * needed. |
michael@0 | 1548 | */ |
michael@0 | 1549 | void CreateIBSiblings(nsFrameConstructorState& aState, |
michael@0 | 1550 | nsIFrame* aInitialInline, |
michael@0 | 1551 | bool aIsPositioned, |
michael@0 | 1552 | nsFrameItems& aChildItems, |
michael@0 | 1553 | nsFrameItems& aSiblings); |
michael@0 | 1554 | |
michael@0 | 1555 | /** |
michael@0 | 1556 | * For an inline aParentItem, construct its list of child |
michael@0 | 1557 | * FrameConstructionItems and set its mIsAllInline flag appropriately. |
michael@0 | 1558 | */ |
michael@0 | 1559 | void BuildInlineChildItems(nsFrameConstructorState& aState, |
michael@0 | 1560 | FrameConstructionItem& aParentItem, |
michael@0 | 1561 | bool aItemIsWithinSVGText, |
michael@0 | 1562 | bool aItemAllowsTextPathChild); |
michael@0 | 1563 | |
michael@0 | 1564 | // Determine whether we need to wipe out what we just did and start over |
michael@0 | 1565 | // because we're doing something like adding block kids to an inline frame |
michael@0 | 1566 | // (and therefore need an {ib} split). aPrevSibling must be correct, even in |
michael@0 | 1567 | // aIsAppend cases. Passing aIsAppend false even when an append is happening |
michael@0 | 1568 | // is ok in terms of correctness, but can lead to unnecessary reframing. If |
michael@0 | 1569 | // aIsAppend is true, then the caller MUST call |
michael@0 | 1570 | // nsCSSFrameConstructor::AppendFrames (as opposed to |
michael@0 | 1571 | // nsFrameManager::InsertFrames directly) to add the new frames. |
michael@0 | 1572 | // @return true if we reconstructed the containing block, false |
michael@0 | 1573 | // otherwise |
michael@0 | 1574 | bool WipeContainingBlock(nsFrameConstructorState& aState, |
michael@0 | 1575 | nsIFrame* aContainingBlock, |
michael@0 | 1576 | nsIFrame* aFrame, |
michael@0 | 1577 | FrameConstructionItemList& aItems, |
michael@0 | 1578 | bool aIsAppend, |
michael@0 | 1579 | nsIFrame* aPrevSibling); |
michael@0 | 1580 | |
michael@0 | 1581 | nsresult ReframeContainingBlock(nsIFrame* aFrame); |
michael@0 | 1582 | |
michael@0 | 1583 | //---------------------------------------- |
michael@0 | 1584 | |
michael@0 | 1585 | // Methods support :first-letter style |
michael@0 | 1586 | |
michael@0 | 1587 | void CreateFloatingLetterFrame(nsFrameConstructorState& aState, |
michael@0 | 1588 | nsIFrame* aBlockFrame, |
michael@0 | 1589 | nsIContent* aTextContent, |
michael@0 | 1590 | nsIFrame* aTextFrame, |
michael@0 | 1591 | nsIContent* aBlockContent, |
michael@0 | 1592 | nsIFrame* aParentFrame, |
michael@0 | 1593 | nsStyleContext* aStyleContext, |
michael@0 | 1594 | nsFrameItems& aResult); |
michael@0 | 1595 | |
michael@0 | 1596 | void CreateLetterFrame(nsIFrame* aBlockFrame, |
michael@0 | 1597 | nsIFrame* aBlockContinuation, |
michael@0 | 1598 | nsIContent* aTextContent, |
michael@0 | 1599 | nsIFrame* aParentFrame, |
michael@0 | 1600 | nsFrameItems& aResult); |
michael@0 | 1601 | |
michael@0 | 1602 | void WrapFramesInFirstLetterFrame(nsIContent* aBlockContent, |
michael@0 | 1603 | nsIFrame* aBlockFrame, |
michael@0 | 1604 | nsFrameItems& aBlockFrames); |
michael@0 | 1605 | |
michael@0 | 1606 | /** |
michael@0 | 1607 | * Looks in the block aBlockFrame for a text frame that contains the |
michael@0 | 1608 | * first-letter of the block and creates the necessary first-letter frames |
michael@0 | 1609 | * and returns them in aLetterFrames. |
michael@0 | 1610 | * |
michael@0 | 1611 | * @param aBlockFrame the (first-continuation of) the block we are creating a |
michael@0 | 1612 | * first-letter frame for |
michael@0 | 1613 | * @param aBlockContinuation the current continuation of the block that we |
michael@0 | 1614 | * are looking in for a textframe with suitable |
michael@0 | 1615 | * contents for first-letter |
michael@0 | 1616 | * @param aParentFrame the current frame whose children we are looking at for |
michael@0 | 1617 | * a suitable first-letter textframe |
michael@0 | 1618 | * @param aParentFrameList the first child of aParentFrame |
michael@0 | 1619 | * @param aModifiedParent returns the parent of the textframe that contains |
michael@0 | 1620 | * the first-letter |
michael@0 | 1621 | * @param aTextFrame returns the textframe that had the first-letter |
michael@0 | 1622 | * @param aPrevFrame returns the previous sibling of aTextFrame |
michael@0 | 1623 | * @param aLetterFrames returns the frames that were created |
michael@0 | 1624 | * @param aStopLooking returns whether we should stop looking for a |
michael@0 | 1625 | * first-letter either because it was found or won't be |
michael@0 | 1626 | * found |
michael@0 | 1627 | */ |
michael@0 | 1628 | void WrapFramesInFirstLetterFrame(nsIFrame* aBlockFrame, |
michael@0 | 1629 | nsIFrame* aBlockContinuation, |
michael@0 | 1630 | nsIFrame* aParentFrame, |
michael@0 | 1631 | nsIFrame* aParentFrameList, |
michael@0 | 1632 | nsIFrame** aModifiedParent, |
michael@0 | 1633 | nsIFrame** aTextFrame, |
michael@0 | 1634 | nsIFrame** aPrevFrame, |
michael@0 | 1635 | nsFrameItems& aLetterFrames, |
michael@0 | 1636 | bool* aStopLooking); |
michael@0 | 1637 | |
michael@0 | 1638 | void RecoverLetterFrames(nsIFrame* aBlockFrame); |
michael@0 | 1639 | |
michael@0 | 1640 | // |
michael@0 | 1641 | nsresult RemoveLetterFrames(nsPresContext* aPresContext, |
michael@0 | 1642 | nsIPresShell* aPresShell, |
michael@0 | 1643 | nsIFrame* aBlockFrame); |
michael@0 | 1644 | |
michael@0 | 1645 | // Recursive helper for RemoveLetterFrames |
michael@0 | 1646 | nsresult RemoveFirstLetterFrames(nsPresContext* aPresContext, |
michael@0 | 1647 | nsIPresShell* aPresShell, |
michael@0 | 1648 | nsIFrame* aFrame, |
michael@0 | 1649 | nsIFrame* aBlockFrame, |
michael@0 | 1650 | bool* aStopLooking); |
michael@0 | 1651 | |
michael@0 | 1652 | // Special remove method for those pesky floating first-letter frames |
michael@0 | 1653 | nsresult RemoveFloatingFirstLetterFrames(nsPresContext* aPresContext, |
michael@0 | 1654 | nsIPresShell* aPresShell, |
michael@0 | 1655 | nsIFrame* aBlockFrame, |
michael@0 | 1656 | bool* aStopLooking); |
michael@0 | 1657 | |
michael@0 | 1658 | // Capture state for the frame tree rooted at the frame associated with the |
michael@0 | 1659 | // content object, aContent |
michael@0 | 1660 | void CaptureStateForFramesOf(nsIContent* aContent, |
michael@0 | 1661 | nsILayoutHistoryState* aHistoryState); |
michael@0 | 1662 | |
michael@0 | 1663 | //---------------------------------------- |
michael@0 | 1664 | |
michael@0 | 1665 | // Methods support :first-line style |
michael@0 | 1666 | |
michael@0 | 1667 | // This method chops the initial inline-outside frames out of aFrameItems. |
michael@0 | 1668 | // If aLineFrame is non-null, it appends them to that frame. Otherwise, it |
michael@0 | 1669 | // creates a new line frame, sets the inline frames as its initial child |
michael@0 | 1670 | // list, and inserts that line frame at the front of what's left of |
michael@0 | 1671 | // aFrameItems. In both cases, the kids are reparented to the line frame. |
michael@0 | 1672 | // After this call, aFrameItems holds the frames that need to become kids of |
michael@0 | 1673 | // the block (possibly including line frames). |
michael@0 | 1674 | void WrapFramesInFirstLineFrame(nsFrameConstructorState& aState, |
michael@0 | 1675 | nsIContent* aBlockContent, |
michael@0 | 1676 | nsIFrame* aBlockFrame, |
michael@0 | 1677 | nsIFrame* aLineFrame, |
michael@0 | 1678 | nsFrameItems& aFrameItems); |
michael@0 | 1679 | |
michael@0 | 1680 | // Handle the case when a block with first-line style is appended to (by |
michael@0 | 1681 | // possibly calling WrapFramesInFirstLineFrame as needed). |
michael@0 | 1682 | void AppendFirstLineFrames(nsFrameConstructorState& aState, |
michael@0 | 1683 | nsIContent* aContent, |
michael@0 | 1684 | nsIFrame* aBlockFrame, |
michael@0 | 1685 | nsFrameItems& aFrameItems); |
michael@0 | 1686 | |
michael@0 | 1687 | nsresult InsertFirstLineFrames(nsFrameConstructorState& aState, |
michael@0 | 1688 | nsIContent* aContent, |
michael@0 | 1689 | nsIFrame* aBlockFrame, |
michael@0 | 1690 | nsIFrame** aParentFrame, |
michael@0 | 1691 | nsIFrame* aPrevSibling, |
michael@0 | 1692 | nsFrameItems& aFrameItems); |
michael@0 | 1693 | |
michael@0 | 1694 | // Find the right frame to use for aContent when looking for sibling |
michael@0 | 1695 | // frames for aTargetContent. If aPrevSibling is true, this |
michael@0 | 1696 | // will look for last continuations, etc, as necessary. This calls |
michael@0 | 1697 | // IsValidSibling as needed; if that returns false it returns null. |
michael@0 | 1698 | // |
michael@0 | 1699 | // @param aTargetContentDisplay the CSS display enum for aTargetContent if |
michael@0 | 1700 | // already known, UNSET_DISPLAY otherwise. It will be filled in if needed. |
michael@0 | 1701 | nsIFrame* FindFrameForContentSibling(nsIContent* aContent, |
michael@0 | 1702 | nsIContent* aTargetContent, |
michael@0 | 1703 | uint8_t& aTargetContentDisplay, |
michael@0 | 1704 | bool aPrevSibling); |
michael@0 | 1705 | |
michael@0 | 1706 | // Find the ``rightmost'' frame for the content immediately preceding the one |
michael@0 | 1707 | // aIter points to, following continuations if necessary. aIter is passed by |
michael@0 | 1708 | // value on purpose, so as not to modify the caller's iterator. |
michael@0 | 1709 | nsIFrame* FindPreviousSibling(mozilla::dom::FlattenedChildIterator aIter, |
michael@0 | 1710 | uint8_t& aTargetContentDisplay); |
michael@0 | 1711 | |
michael@0 | 1712 | // Find the frame for the content node immediately following the one aIter |
michael@0 | 1713 | // points to, following continuations if necessary. aIter is passed by value |
michael@0 | 1714 | // on purpose, so as not to modify the caller's iterator. |
michael@0 | 1715 | nsIFrame* FindNextSibling(mozilla::dom::FlattenedChildIterator aIter, |
michael@0 | 1716 | uint8_t& aTargetContentDisplay); |
michael@0 | 1717 | |
michael@0 | 1718 | // Find the right previous sibling for an insertion. This also updates the |
michael@0 | 1719 | // parent frame to point to the correct continuation of the parent frame to |
michael@0 | 1720 | // use, and returns whether this insertion is to be treated as an append. |
michael@0 | 1721 | // aChild is the child being inserted. |
michael@0 | 1722 | // aIsRangeInsertSafe returns whether it is safe to do a range insert with |
michael@0 | 1723 | // aChild being the first child in the range. It is the callers' |
michael@0 | 1724 | // responsibility to check whether a range insert is safe with regards to |
michael@0 | 1725 | // fieldsets. |
michael@0 | 1726 | // The skip parameters are used to ignore a range of children when looking |
michael@0 | 1727 | // for a sibling. All nodes starting from aStartSkipChild and up to but not |
michael@0 | 1728 | // including aEndSkipChild will be skipped over when looking for sibling |
michael@0 | 1729 | // frames. Skipping a range can deal with XBL but not when there are multiple |
michael@0 | 1730 | // insertion points. |
michael@0 | 1731 | nsIFrame* GetInsertionPrevSibling(nsIFrame*& aParentFrame, /* inout */ |
michael@0 | 1732 | nsIContent* aContainer, |
michael@0 | 1733 | nsIContent* aChild, |
michael@0 | 1734 | bool* aIsAppend, |
michael@0 | 1735 | bool* aIsRangeInsertSafe, |
michael@0 | 1736 | nsIContent* aStartSkipChild = nullptr, |
michael@0 | 1737 | nsIContent *aEndSkipChild = nullptr); |
michael@0 | 1738 | |
michael@0 | 1739 | // see if aContent and aSibling are legitimate siblings due to restrictions |
michael@0 | 1740 | // imposed by table columns |
michael@0 | 1741 | // XXXbz this code is generally wrong, since the frame for aContent |
michael@0 | 1742 | // may be constructed based on tag, not based on aDisplay! |
michael@0 | 1743 | bool IsValidSibling(nsIFrame* aSibling, |
michael@0 | 1744 | nsIContent* aContent, |
michael@0 | 1745 | uint8_t& aDisplay); |
michael@0 | 1746 | |
michael@0 | 1747 | void QuotesDirty() { |
michael@0 | 1748 | NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news"); |
michael@0 | 1749 | mQuotesDirty = true; |
michael@0 | 1750 | mDocument->SetNeedLayoutFlush(); |
michael@0 | 1751 | } |
michael@0 | 1752 | |
michael@0 | 1753 | void CountersDirty() { |
michael@0 | 1754 | NS_PRECONDITION(mUpdateCount != 0, "Instant counter updates are bad news"); |
michael@0 | 1755 | mCountersDirty = true; |
michael@0 | 1756 | mDocument->SetNeedLayoutFlush(); |
michael@0 | 1757 | } |
michael@0 | 1758 | |
michael@0 | 1759 | /** |
michael@0 | 1760 | * Add the pair (aContent, aStyleContext) to the undisplayed items |
michael@0 | 1761 | * in aList as needed. This method enforces the invariant that all |
michael@0 | 1762 | * style contexts in the undisplayed content map must be non-pseudo |
michael@0 | 1763 | * contexts and also handles unbinding undisplayed generated content |
michael@0 | 1764 | * as needed. |
michael@0 | 1765 | */ |
michael@0 | 1766 | static void SetAsUndisplayedContent(FrameConstructionItemList& aList, |
michael@0 | 1767 | nsIContent* aContent, |
michael@0 | 1768 | nsStyleContext* aStyleContext, |
michael@0 | 1769 | bool aIsGeneratedContent); |
michael@0 | 1770 | |
michael@0 | 1771 | public: |
michael@0 | 1772 | |
michael@0 | 1773 | friend class nsFrameConstructorState; |
michael@0 | 1774 | |
michael@0 | 1775 | private: |
michael@0 | 1776 | |
michael@0 | 1777 | nsIDocument* mDocument; // Weak ref |
michael@0 | 1778 | |
michael@0 | 1779 | // See the comment at the start of ConstructRootFrame for more details |
michael@0 | 1780 | // about the following frames. |
michael@0 | 1781 | |
michael@0 | 1782 | // This is just the outermost frame for the root element. |
michael@0 | 1783 | nsIFrame* mRootElementFrame; |
michael@0 | 1784 | // This is the frame for the root element that has no pseudo-element style. |
michael@0 | 1785 | nsIFrame* mRootElementStyleFrame; |
michael@0 | 1786 | // This is the containing block for fixed-pos frames --- the |
michael@0 | 1787 | // viewport or page frame |
michael@0 | 1788 | nsIFrame* mFixedContainingBlock; |
michael@0 | 1789 | // This is the containing block that contains the root element --- |
michael@0 | 1790 | // the real "initial containing block" according to CSS 2.1. |
michael@0 | 1791 | nsIFrame* mDocElementContainingBlock; |
michael@0 | 1792 | nsIFrame* mGfxScrollFrame; |
michael@0 | 1793 | nsIFrame* mPageSequenceFrame; |
michael@0 | 1794 | nsQuoteList mQuoteList; |
michael@0 | 1795 | nsCounterManager mCounterManager; |
michael@0 | 1796 | // Current ProcessChildren depth. |
michael@0 | 1797 | uint16_t mCurrentDepth; |
michael@0 | 1798 | uint16_t mUpdateCount; |
michael@0 | 1799 | bool mQuotesDirty : 1; |
michael@0 | 1800 | bool mCountersDirty : 1; |
michael@0 | 1801 | bool mIsDestroyingFrameTree : 1; |
michael@0 | 1802 | // This is true if mDocElementContainingBlock supports absolute positioning |
michael@0 | 1803 | bool mHasRootAbsPosContainingBlock : 1; |
michael@0 | 1804 | bool mAlwaysCreateFramesForIgnorableWhitespace : 1; |
michael@0 | 1805 | |
michael@0 | 1806 | nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState; |
michael@0 | 1807 | }; |
michael@0 | 1808 | |
michael@0 | 1809 | #endif /* nsCSSFrameConstructor_h___ */ |