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