Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=2:et:sw=2:
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 : #include "nsCSSFrameConstructor.h"
13 :
14 : #include "mozilla/AutoRestore.h"
15 : #include "mozilla/DebugOnly.h"
16 : #include "mozilla/ErrorResult.h"
17 : #include "mozilla/dom/HTMLDetailsElement.h"
18 : #include "mozilla/dom/HTMLSelectElement.h"
19 : #include "mozilla/dom/HTMLSummaryElement.h"
20 : #include "mozilla/EventStates.h"
21 : #include "mozilla/Likely.h"
22 : #include "mozilla/LinkedList.h"
23 : #include "mozilla/PresShell.h"
24 : #include "mozilla/ServoBindings.h"
25 : #include "nsAbsoluteContainingBlock.h"
26 : #include "nsCSSPseudoElements.h"
27 : #include "nsIAtom.h"
28 : #include "nsIFrameInlines.h"
29 : #include "nsGkAtoms.h"
30 : #include "nsPresContext.h"
31 : #include "nsIDocument.h"
32 : #include "nsTableFrame.h"
33 : #include "nsTableColFrame.h"
34 : #include "nsTableRowFrame.h"
35 : #include "nsTableCellFrame.h"
36 : #include "nsIDOMHTMLDocument.h"
37 : #include "nsHTMLParts.h"
38 : #include "nsIPresShell.h"
39 : #include "nsUnicharUtils.h"
40 : #include "mozilla/StyleSetHandle.h"
41 : #include "mozilla/StyleSetHandleInlines.h"
42 : #include "nsViewManager.h"
43 : #include "nsStyleConsts.h"
44 : #ifdef MOZ_XUL
45 : #include "nsXULElement.h"
46 : #include "mozilla/dom/BoxObject.h"
47 : #endif // MOZ_XUL
48 : #include "nsContainerFrame.h"
49 : #include "nsNameSpaceManager.h"
50 : #include "nsIComboboxControlFrame.h"
51 : #include "nsComboboxControlFrame.h"
52 : #include "nsIListControlFrame.h"
53 : #include "nsIDOMCharacterData.h"
54 : #include "nsPlaceholderFrame.h"
55 : #include "nsTableRowGroupFrame.h"
56 : #include "nsIFormControl.h"
57 : #include "nsCSSAnonBoxes.h"
58 : #include "nsTextFragment.h"
59 : #include "nsIAnonymousContentCreator.h"
60 : #include "nsBindingManager.h"
61 : #include "nsXBLBinding.h"
62 : #include "nsContentUtils.h"
63 : #include "nsIScriptError.h"
64 : #ifdef XP_MACOSX
65 : #include "nsIDocShell.h"
66 : #endif
67 : #include "ChildIterator.h"
68 : #include "nsError.h"
69 : #include "nsLayoutUtils.h"
70 : #include "nsAutoPtr.h"
71 : #include "nsBoxFrame.h"
72 : #include "nsBoxLayout.h"
73 : #include "nsFlexContainerFrame.h"
74 : #include "nsGridContainerFrame.h"
75 : #include "RubyUtils.h"
76 : #include "nsRubyFrame.h"
77 : #include "nsRubyBaseFrame.h"
78 : #include "nsRubyBaseContainerFrame.h"
79 : #include "nsRubyTextFrame.h"
80 : #include "nsRubyTextContainerFrame.h"
81 : #include "nsImageFrame.h"
82 : #include "nsIObjectLoadingContent.h"
83 : #include "nsTArray.h"
84 : #include "nsGenericDOMDataNode.h"
85 : #include "mozilla/dom/Element.h"
86 : #include "mozilla/dom/ElementInlines.h"
87 : #include "nsAutoLayoutPhase.h"
88 : #include "nsStyleStructInlines.h"
89 : #include "nsPageContentFrame.h"
90 : #include "mozilla/GeckoStyleContext.h"
91 : #include "mozilla/RestyleManager.h"
92 : #include "mozilla/RestyleManagerInlines.h"
93 : #include "StickyScrollContainer.h"
94 : #include "nsFieldSetFrame.h"
95 : #include "nsInlineFrame.h"
96 : #include "nsBlockFrame.h"
97 : #include "nsCanvasFrame.h"
98 : #include "nsFirstLetterFrame.h"
99 : #include "nsGfxScrollFrame.h"
100 : #include "nsPageFrame.h"
101 : #include "nsSimplePageSequenceFrame.h"
102 : #include "nsTableWrapperFrame.h"
103 : #include "nsIScrollableFrame.h"
104 : #include "nsBackdropFrame.h"
105 : #include "nsTransitionManager.h"
106 : #include "DetailsFrame.h"
107 : #include "nsThemeConstants.h"
108 :
109 : #ifdef MOZ_XUL
110 : #include "nsIRootBox.h"
111 : #endif
112 : #ifdef ACCESSIBILITY
113 : #include "nsAccessibilityService.h"
114 : #endif
115 :
116 : #include "nsXBLService.h"
117 :
118 : #undef NOISY_FIRST_LETTER
119 :
120 : #include "nsMathMLParts.h"
121 : #include "mozilla/dom/SVGTests.h"
122 : #include "nsSVGUtils.h"
123 :
124 : #include "nsRefreshDriver.h"
125 : #include "nsRuleProcessorData.h"
126 : #include "nsTextNode.h"
127 : #include "ActiveLayerTracker.h"
128 : #include "nsIPresShellInlines.h"
129 :
130 : using namespace mozilla;
131 : using namespace mozilla::dom;
132 :
133 : // An alias for convenience.
134 : static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
135 :
136 : nsIFrame*
137 : NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
138 :
139 : nsIFrame*
140 : NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
141 :
142 : nsContainerFrame*
143 : NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
144 : nsContainerFrame*
145 : NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
146 : nsIFrame*
147 : NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
148 : nsIFrame*
149 : NS_NewSVGGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
150 : nsIFrame*
151 : NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
152 : nsIFrame*
153 : NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
154 : nsContainerFrame*
155 : NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
156 : nsIFrame*
157 : NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
158 : nsIFrame*
159 : NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
160 : nsIFrame*
161 : NS_NewSVGSymbolFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
162 : nsIFrame*
163 : NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
164 : nsIFrame*
165 : NS_NewSVGContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
166 : nsIFrame*
167 : NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
168 : nsIFrame*
169 : NS_NewSVGViewFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
170 : extern nsIFrame*
171 : NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
172 : extern nsIFrame*
173 : NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
174 : extern nsIFrame*
175 : NS_NewSVGStopFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
176 : nsContainerFrame*
177 : NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
178 : nsContainerFrame*
179 : NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
180 : extern nsIFrame*
181 : NS_NewSVGImageFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
182 : nsIFrame*
183 : NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
184 : nsIFrame*
185 : NS_NewSVGFilterFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
186 : nsIFrame*
187 : NS_NewSVGPatternFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
188 : nsIFrame*
189 : NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
190 : nsIFrame*
191 : NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
192 : nsIFrame*
193 : NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
194 : nsIFrame*
195 : NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
196 : nsIFrame*
197 : NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
198 :
199 : #include "mozilla/dom/NodeInfo.h"
200 : #include "prenv.h"
201 : #include "nsNodeInfoManager.h"
202 : #include "nsContentCreatorFunctions.h"
203 :
204 : #ifdef DEBUG
205 : // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
206 : // more of the following flags (comma separated) for handy debug
207 : // output.
208 : static bool gNoisyContentUpdates = false;
209 : static bool gReallyNoisyContentUpdates = false;
210 : static bool gNoisyInlineConstruction = false;
211 :
212 : struct FrameCtorDebugFlags {
213 : const char* name;
214 : bool* on;
215 : };
216 :
217 : static FrameCtorDebugFlags gFlags[] = {
218 : { "content-updates", &gNoisyContentUpdates },
219 : { "really-noisy-content-updates", &gReallyNoisyContentUpdates },
220 : { "noisy-inline", &gNoisyInlineConstruction }
221 : };
222 :
223 : #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
224 : #endif
225 :
226 :
227 : #ifdef MOZ_XUL
228 : #include "nsMenuFrame.h"
229 : #include "nsPopupSetFrame.h"
230 : #include "nsTreeColFrame.h"
231 : #include "nsIBoxObject.h"
232 : #include "nsPIListBoxObject.h"
233 : #include "nsListBoxBodyFrame.h"
234 : #include "nsListItemFrame.h"
235 : #include "nsXULLabelFrame.h"
236 :
237 : //------------------------------------------------------------------
238 :
239 : nsIFrame*
240 : NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
241 :
242 : nsContainerFrame*
243 : NS_NewRootBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
244 :
245 : nsContainerFrame*
246 : NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
247 :
248 : nsIFrame*
249 : NS_NewDeckFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
250 :
251 : nsIFrame*
252 : NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
253 :
254 : nsIFrame*
255 : NS_NewStackFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
256 :
257 : nsIFrame*
258 : NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
259 :
260 : nsIFrame*
261 : NS_NewRangeFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
262 :
263 : nsIFrame*
264 : NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
265 :
266 : nsIFrame*
267 : NS_NewTextBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
268 :
269 : nsIFrame*
270 : NS_NewGroupBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
271 :
272 : nsIFrame*
273 : NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
274 :
275 : nsIFrame*
276 : NS_NewSplitterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
277 :
278 : nsIFrame*
279 : NS_NewMenuPopupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
280 :
281 : nsIFrame*
282 : NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
283 :
284 : nsIFrame*
285 : NS_NewMenuFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, uint32_t aFlags);
286 :
287 : nsIFrame*
288 : NS_NewMenuBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
289 :
290 : nsIFrame*
291 : NS_NewTreeBodyFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
292 :
293 : // grid
294 : nsresult
295 : NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsBoxLayout** aNewLayout );
296 : nsIFrame*
297 : NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
298 : nsIFrame*
299 : NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
300 :
301 : // end grid
302 :
303 : nsIFrame*
304 : NS_NewTitleBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
305 :
306 : nsIFrame*
307 : NS_NewResizerFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
308 :
309 :
310 : #endif
311 :
312 : nsHTMLScrollFrame*
313 : NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot);
314 :
315 : nsXULScrollFrame*
316 : NS_NewXULScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
317 : bool aIsRoot, bool aClipAllDescendants);
318 :
319 : nsIFrame*
320 : NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
321 :
322 : nsIFrame*
323 : NS_NewScrollbarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
324 :
325 : nsIFrame*
326 : NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
327 :
328 :
329 : #ifdef NOISY_FINDFRAME
330 : static int32_t FFWC_totalCount=0;
331 : static int32_t FFWC_doLoop=0;
332 : static int32_t FFWC_doSibling=0;
333 : static int32_t FFWC_recursions=0;
334 : static int32_t FFWC_nextInFlows=0;
335 : #endif
336 :
337 : // Wrapper class to handle stack-construction a TreeMatchContext only if we're
338 : // using the Gecko style system.
339 48 : class MOZ_STACK_CLASS TreeMatchContextHolder
340 : {
341 : public:
342 48 : explicit TreeMatchContextHolder(nsIDocument* aDocument)
343 48 : {
344 48 : if (!aDocument->IsStyledByServo()) {
345 96 : mMaybeTreeMatchContext.emplace(aDocument,
346 48 : TreeMatchContext::ForFrameConstruction);
347 : }
348 48 : }
349 :
350 24 : bool Exists() const { return mMaybeTreeMatchContext.isSome(); }
351 48 : operator TreeMatchContext*() { return mMaybeTreeMatchContext.ptrOr(nullptr); }
352 :
353 24 : TreeMatchContext* operator ->()
354 : {
355 24 : MOZ_ASSERT(mMaybeTreeMatchContext.isSome());
356 24 : return mMaybeTreeMatchContext.ptr();
357 : }
358 :
359 : private:
360 : Maybe<TreeMatchContext> mMaybeTreeMatchContext;
361 : };
362 :
363 : // Returns true if aFrame is an anonymous flex/grid item.
364 : static inline bool
365 77 : IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
366 : {
367 77 : const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
368 154 : return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
369 154 : pseudoType == nsCSSAnonBoxes::anonymousGridItem;
370 : }
371 :
372 : // Returns true if aFrame is a flex/grid container.
373 : static inline bool
374 606 : IsFlexOrGridContainer(const nsIFrame* aFrame)
375 : {
376 606 : const LayoutFrameType t = aFrame->Type();
377 606 : return t == LayoutFrameType::FlexContainer ||
378 606 : t == LayoutFrameType::GridContainer;
379 : }
380 :
381 : // Returns true IFF the given nsIFrame is a nsFlexContainerFrame and
382 : // represents a -webkit-{inline-}box container.
383 : static inline bool
384 0 : IsFlexContainerForLegacyBox(const nsIFrame* aFrame)
385 : {
386 0 : return aFrame->IsFlexContainerFrame() &&
387 0 : aFrame->HasAnyStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX);
388 : }
389 :
390 : #if DEBUG
391 : static void
392 0 : AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
393 : const nsIFrame* aParent)
394 : {
395 0 : MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
396 : "expected an anonymous flex or grid item child frame");
397 0 : MOZ_ASSERT(aParent, "expected a parent frame");
398 0 : const nsIAtom* pseudoType = aChild->StyleContext()->GetPseudo();
399 0 : if (pseudoType == nsCSSAnonBoxes::anonymousFlexItem) {
400 0 : MOZ_ASSERT(aParent->IsFlexContainerFrame(),
401 : "anonymous flex items should only exist as children "
402 : "of flex container frames");
403 : } else {
404 0 : MOZ_ASSERT(aParent->IsGridContainerFrame(),
405 : "anonymous grid items should only exist as children "
406 : "of grid container frames");
407 : }
408 0 : }
409 : #else
410 : #define AssertAnonymousFlexOrGridItemParent(x, y) do { /* nothing */ } while(0)
411 : #endif
412 :
413 : static inline nsContainerFrame*
414 0 : GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
415 : {
416 : // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
417 0 : nsIFrame* firstChild = aFieldsetFrame->PrincipalChildList().FirstChild();
418 0 : nsIFrame* inner = firstChild && firstChild->GetNextSibling() ? firstChild->GetNextSibling() : firstChild;
419 0 : return inner ? inner->GetContentInsertionFrame() : nullptr;
420 : }
421 :
422 : #define FCDATA_DECL(_flags, _func) \
423 : { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr }
424 : #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box) \
425 : { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS, \
426 : { (FrameCreationFunc)_func }, nullptr, &_anon_box }
427 :
428 : #define UNREACHABLE_FCDATA() \
429 : { 0, { (FrameCreationFunc)nullptr }, nullptr, nullptr }
430 : //----------------------------------------------------------------------
431 :
432 : /**
433 : * True if aFrame is an actual inline frame in the sense of non-replaced
434 : * display:inline CSS boxes. In other words, it can be affected by {ib}
435 : * splitting and can contain first-letter frames. Basically, this is either an
436 : * inline frame (positioned or otherwise) or an line frame (this last because
437 : * it can contain first-letter and because inserting blocks in the middle of it
438 : * needs to terminate it).
439 : */
440 : static bool
441 44 : IsInlineFrame(const nsIFrame* aFrame)
442 : {
443 44 : return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
444 : }
445 :
446 : /**
447 : * True if aFrame is an instance of an SVG frame class or is an inline/block
448 : * frame being used for SVG text.
449 : */
450 : static bool
451 527 : IsFrameForSVG(const nsIFrame* aFrame)
452 : {
453 896 : return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
454 896 : nsSVGUtils::IsInSVGTextSubtree(aFrame);
455 : }
456 :
457 : /**
458 : * Returns true iff aFrame explicitly prevents its descendants from floating
459 : * (at least, down to the level of descendants which themselves are
460 : * float-containing blocks -- those will manage the floating status of any
461 : * lower-level descendents inside them, of course).
462 : */
463 : static bool
464 540 : ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
465 : {
466 1080 : return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
467 818 : aFrame->IsXULBoxFrame() ||
468 818 : ::IsFlexOrGridContainer(aFrame);
469 : }
470 :
471 : /**
472 : * If any children require a block parent, return the first such child.
473 : * Otherwise return null.
474 : */
475 : static nsIContent*
476 223 : AnyKidsNeedBlockParent(nsIFrame *aFrameList)
477 : {
478 519 : for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
479 : // Line participants, such as text and inline frames, can't be
480 : // directly inside a XUL box; they must be wrapped in an
481 : // intermediate block.
482 301 : if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
483 5 : return k->GetContent();
484 : }
485 : }
486 218 : return nullptr;
487 : }
488 :
489 : // Reparent a frame into a wrapper frame that is a child of its old parent.
490 : static void
491 5 : ReparentFrame(RestyleManager* aRestyleManager,
492 : nsContainerFrame* aNewParentFrame,
493 : nsIFrame* aFrame)
494 : {
495 5 : aFrame->SetParent(aNewParentFrame);
496 5 : aRestyleManager->ReparentStyleContext(aFrame);
497 5 : }
498 :
499 : static void
500 5 : ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
501 : nsContainerFrame* aNewParentFrame,
502 : const nsFrameList& aFrameList)
503 : {
504 5 : RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
505 10 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
506 5 : ReparentFrame(restyleManager, aNewParentFrame, e.get());
507 : }
508 5 : }
509 :
510 : //----------------------------------------------------------------------
511 : //
512 : // When inline frames get weird and have block frames in them, we
513 : // annotate them to help us respond to incremental content changes
514 : // more easily.
515 :
516 : static inline bool
517 287 : IsFramePartOfIBSplit(nsIFrame* aFrame)
518 : {
519 287 : bool result = (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0;
520 287 : MOZ_ASSERT(!result || static_cast<nsBlockFrame*>(do_QueryFrame(aFrame)) ||
521 : static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)),
522 : "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT");
523 287 : return result;
524 : }
525 :
526 0 : static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame)
527 : {
528 0 : NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
529 :
530 : // We only store the "ib-split sibling" annotation with the first
531 : // frame in the continuation chain. Walk back to find that frame now.
532 0 : return aFrame->FirstContinuation()->
533 0 : GetProperty(nsIFrame::IBSplitSibling());
534 : }
535 :
536 0 : static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame)
537 : {
538 0 : NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
539 :
540 : // We only store the ib-split sibling annotation with the first
541 : // frame in the continuation chain. Walk back to find that frame now.
542 0 : return aFrame->FirstContinuation()->
543 0 : GetProperty(nsIFrame::IBSplitPrevSibling());
544 : }
545 :
546 : static nsContainerFrame*
547 0 : GetLastIBSplitSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline)
548 : {
549 0 : for (nsIFrame *frame = aFrame, *next; ; frame = next) {
550 0 : next = GetIBSplitSibling(frame);
551 0 : if (!next ||
552 0 : (!aReturnEmptyTrailingInline && !next->PrincipalChildList().FirstChild() &&
553 0 : !GetIBSplitSibling(next))) {
554 0 : NS_ASSERTION(!next || !frame->IsInlineOutside(),
555 : "Should have a block here!");
556 0 : return static_cast<nsContainerFrame*>(frame);
557 : }
558 : }
559 : NS_NOTREACHED("unreachable code");
560 : return nullptr;
561 : }
562 :
563 : static void
564 0 : SetFrameIsIBSplit(nsContainerFrame* aFrame, nsContainerFrame* aIBSplitSibling)
565 : {
566 0 : NS_PRECONDITION(aFrame, "bad args!");
567 :
568 : // We should be the only continuation
569 0 : NS_ASSERTION(!aFrame->GetPrevContinuation(),
570 : "assigning ib-split sibling to other than first continuation!");
571 0 : NS_ASSERTION(!aFrame->GetNextContinuation() ||
572 : IsFramePartOfIBSplit(aFrame->GetNextContinuation()),
573 : "should have no non-ib-split continuations here");
574 :
575 : // Mark the frame as ib-split.
576 0 : aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
577 :
578 0 : if (aIBSplitSibling) {
579 0 : NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),
580 : "assigning something other than the first continuation as the "
581 : "ib-split sibling");
582 :
583 : // Store the ib-split sibling (if we were given one) with the
584 : // first frame in the flow.
585 0 : aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
586 0 : aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
587 : }
588 0 : }
589 :
590 : static nsIFrame*
591 0 : GetIBContainingBlockFor(nsIFrame* aFrame)
592 : {
593 0 : NS_PRECONDITION(IsFramePartOfIBSplit(aFrame),
594 : "GetIBContainingBlockFor() should only be called on known IB frames");
595 :
596 : // Get the first "normal" ancestor of the target frame.
597 : nsIFrame* parentFrame;
598 : do {
599 0 : parentFrame = aFrame->GetParent();
600 :
601 0 : if (! parentFrame) {
602 0 : NS_ERROR("no unsplit block frame in IB hierarchy");
603 0 : return aFrame;
604 : }
605 :
606 : // Note that we ignore non-ib-split frames which have a pseudo on their
607 : // style context -- they're not the frames we're looking for! In
608 : // particular, they may be hiding a real parent that _is_ in an ib-split.
609 0 : if (!IsFramePartOfIBSplit(parentFrame) &&
610 0 : !parentFrame->StyleContext()->GetPseudo())
611 0 : break;
612 :
613 0 : aFrame = parentFrame;
614 : } while (1);
615 :
616 : // post-conditions
617 0 : NS_ASSERTION(parentFrame, "no normal ancestor found for ib-split frame "
618 : "in GetIBContainingBlockFor");
619 0 : NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt");
620 :
621 0 : return parentFrame;
622 : }
623 :
624 : //----------------------------------------------------------------------
625 :
626 : // Block/inline frame construction logic. We maintain a few invariants here:
627 : //
628 : // 1. Block frames contain block and inline frames.
629 : //
630 : // 2. Inline frames only contain inline frames. If an inline parent has a block
631 : // child then the block child is migrated upward until it lands in a block
632 : // parent (the inline frames containing block is where it will end up).
633 :
634 : // After this function returns, aLink is pointing to the first link at or
635 : // after its starting position for which the next frame is a block. If there
636 : // is no such link, it points to the end of the list.
637 : static void
638 0 : FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink)
639 : {
640 0 : for ( ; !aLink.AtEnd(); aLink.Next()) {
641 0 : if (!aLink.NextFrame()->IsInlineOutside()) {
642 0 : return;
643 : }
644 : }
645 : }
646 :
647 : // This function returns a frame link enumerator pointing to the first link in
648 : // the list for which the next frame is not block. If there is no such link,
649 : // it points to the end of the list.
650 : static nsFrameList::FrameLinkEnumerator
651 0 : FindFirstNonBlock(const nsFrameList& aList)
652 : {
653 0 : nsFrameList::FrameLinkEnumerator link(aList);
654 0 : for (; !link.AtEnd(); link.Next()) {
655 0 : if (link.NextFrame()->IsInlineOutside()) {
656 0 : break;
657 : }
658 : }
659 0 : return link;
660 : }
661 :
662 : inline void
663 72 : SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame)
664 : {
665 72 : NS_PRECONDITION(!aFrame->GetNextSibling(), "Should be using a frame list");
666 72 : nsFrameList temp(aFrame, aFrame);
667 72 : aParent->SetInitialChildList(kPrincipalList, temp);
668 72 : }
669 :
670 : // -----------------------------------------------------------
671 :
672 : // Structure used when constructing formatting object trees.
673 2851 : struct nsFrameItems : public nsFrameList
674 : {
675 : // Appends the frame to the end of the list
676 : void AddChild(nsIFrame* aChild);
677 : };
678 :
679 : void
680 562 : nsFrameItems::AddChild(nsIFrame* aChild)
681 : {
682 562 : NS_PRECONDITION(aChild, "nsFrameItems::AddChild");
683 :
684 : // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild) here,
685 : // but some of our callers put frames that have different
686 : // parents (caption, I'm looking at you) on the same framelist, and
687 : // nsFrameList asserts if you try to do that.
688 562 : if (IsEmpty()) {
689 336 : SetFrames(aChild);
690 : }
691 : else {
692 226 : NS_ASSERTION(aChild != mLastChild,
693 : "Same frame being added to frame list twice?");
694 226 : mLastChild->SetNextSibling(aChild);
695 226 : mLastChild = nsLayoutUtils::GetLastSibling(aChild);
696 : }
697 562 : }
698 :
699 : // -----------------------------------------------------------
700 :
701 : // Structure used when constructing formatting object trees. Contains
702 : // state information needed for absolutely positioned elements
703 : struct nsAbsoluteItems : nsFrameItems {
704 : // containing block for absolutely positioned elements
705 : nsContainerFrame* containingBlock;
706 :
707 : explicit nsAbsoluteItems(nsContainerFrame* aContainingBlock);
708 : #ifdef DEBUG
709 : // XXXbz Does this need a debug-only assignment operator that nulls out the
710 : // childList in the nsAbsoluteItems we're copying? Introducing a difference
711 : // between debug and non-debug behavior seems bad, so I guess not...
712 4604 : ~nsAbsoluteItems() {
713 2302 : NS_ASSERTION(!FirstChild(),
714 : "Dangling child list. Someone forgot to insert it?");
715 2302 : }
716 : #endif
717 :
718 : // Appends the frame to the end of the list
719 : void AddChild(nsIFrame* aChild);
720 : };
721 :
722 2302 : nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock)
723 2302 : : containingBlock(aContainingBlock)
724 : {
725 2302 : }
726 :
727 : // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
728 : void
729 0 : nsAbsoluteItems::AddChild(nsIFrame* aChild)
730 : {
731 0 : aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
732 0 : NS_ASSERTION(aChild->GetPlaceholderFrame(),
733 : "Child without placeholder being added to nsAbsoluteItems?");
734 0 : nsFrameItems::AddChild(aChild);
735 0 : }
736 :
737 : // -----------------------------------------------------------
738 :
739 : // Structure for saving the existing state when pushing/poping containing
740 : // blocks. The destructor restores the state to its previous state
741 : class MOZ_STACK_CLASS nsFrameConstructorSaveState {
742 : public:
743 : typedef nsIFrame::ChildListID ChildListID;
744 : nsFrameConstructorSaveState();
745 : ~nsFrameConstructorSaveState();
746 :
747 : private:
748 : nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
749 : nsAbsoluteItems mSavedItems; // copy of original data
750 :
751 : // The name of the child list in which our frames would belong
752 : ChildListID mChildListID;
753 : nsFrameConstructorState* mState;
754 :
755 : // State used only when we're saving the abs-pos state for a transformed
756 : // element.
757 : nsAbsoluteItems mSavedFixedItems;
758 :
759 : bool mSavedFixedPosIsAbsPos;
760 :
761 : friend class nsFrameConstructorState;
762 : };
763 :
764 : // Structure used to keep track of a list of bindings we need to call
765 : // AddToAttachedQueue on. These should be in post-order depth-first
766 : // flattened tree traversal order.
767 : struct PendingBinding : public LinkedListElement<PendingBinding>
768 : {
769 : #ifdef NS_BUILD_REFCNT_LOGGING
770 332 : PendingBinding() {
771 332 : MOZ_COUNT_CTOR(PendingBinding);
772 332 : }
773 664 : ~PendingBinding() {
774 332 : MOZ_COUNT_DTOR(PendingBinding);
775 332 : }
776 : #endif
777 :
778 : RefPtr<nsXBLBinding> mBinding;
779 : };
780 :
781 : // Structure used for maintaining state information during the
782 : // frame construction process
783 : class MOZ_STACK_CLASS nsFrameConstructorState {
784 : public:
785 : typedef nsIFrame::ChildListID ChildListID;
786 :
787 : nsPresContext *mPresContext;
788 : nsIPresShell *mPresShell;
789 : nsFrameManager *mFrameManager;
790 :
791 : #ifdef MOZ_XUL
792 : // Frames destined for the kPopupList.
793 : nsAbsoluteItems mPopupItems;
794 : #endif
795 :
796 : // Containing block information for out-of-flow frames.
797 : nsAbsoluteItems mFixedItems;
798 : nsAbsoluteItems mAbsoluteItems;
799 : nsAbsoluteItems mFloatedItems;
800 : // The containing block of a frame in the top layer is defined by the
801 : // spec: fixed-positioned frames are children of the viewport frame,
802 : // and absolutely-positioned frames are children of the initial
803 : // containing block. They would not be caught by any other containing
804 : // block, e.g. frames with transform or filter.
805 : nsAbsoluteItems mTopLayerFixedItems;
806 : nsAbsoluteItems mTopLayerAbsoluteItems;
807 :
808 : nsCOMPtr<nsILayoutHistoryState> mFrameState;
809 : // These bits will be added to the state bits of any frame we construct
810 : // using this state.
811 : nsFrameState mAdditionalStateBits;
812 :
813 : // When working with the transform and filter properties, we want to hook
814 : // the abs-pos and fixed-pos lists together, since such
815 : // elements are fixed-pos containing blocks. This flag determines
816 : // whether or not we want to wire the fixed-pos and abs-pos lists
817 : // together.
818 : bool mFixedPosIsAbsPos;
819 :
820 : // A boolean to indicate whether we have a "pending" popupgroup. That is, we
821 : // have already created the FrameConstructionItem for the root popupgroup but
822 : // we have not yet created the relevant frame.
823 : bool mHavePendingPopupgroup;
824 :
825 : // If false (which is the default) then call SetPrimaryFrame() as needed
826 : // during frame construction. If true, don't make any SetPrimaryFrame()
827 : // calls, except for generated content which doesn't have a primary frame
828 : // yet. The mCreatingExtraFrames == true mode is meant to be used for
829 : // construction of random "extra" frames for elements via normal frame
830 : // construction APIs (e.g. replication of things across pages in paginated
831 : // mode).
832 : bool mCreatingExtraFrames;
833 :
834 : nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
835 :
836 : // Selector matching context for. This is null when we're using the Servo style
837 : // system.
838 : TreeMatchContext* mTreeMatchContext;
839 :
840 : // Constructor
841 : // Use the passed-in history state.
842 : //
843 : // aTreeMatchContext is null when we're using the Servo style system.
844 : nsFrameConstructorState(
845 : nsIPresShell* aPresShell,
846 : TreeMatchContext* aTreeMatchContext,
847 : nsContainerFrame* aFixedContainingBlock,
848 : nsContainerFrame* aAbsoluteContainingBlock,
849 : nsContainerFrame* aFloatContainingBlock,
850 : already_AddRefed<nsILayoutHistoryState> aHistoryState);
851 : // Get the history state from the pres context's pres shell.
852 : nsFrameConstructorState(nsIPresShell* aPresShell,
853 : TreeMatchContext* aTreeMatchContext,
854 : nsContainerFrame* aFixedContainingBlock,
855 : nsContainerFrame* aAbsoluteContainingBlock,
856 : nsContainerFrame* aFloatContainingBlock);
857 :
858 : ~nsFrameConstructorState();
859 :
860 491 : bool HasAncestorFilter()
861 : {
862 491 : return mTreeMatchContext && mTreeMatchContext->mAncestorFilter.HasFilter();
863 : }
864 :
865 : // Function to push the existing absolute containing block state and
866 : // create a new scope. Code that uses this function should get matching
867 : // logic in GetAbsoluteContainingBlock.
868 : // Also makes aNewAbsoluteContainingBlock the containing block for
869 : // fixed-pos elements if necessary.
870 : // aPositionedFrame is the frame whose style actually makes
871 : // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
872 : // aPositionedFrame is the element's primary frame and
873 : // aNewAbsoluteContainingBlock is the scrolled frame.
874 : void PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
875 : nsIFrame* aPositionedFrame,
876 : nsFrameConstructorSaveState& aSaveState);
877 :
878 : // Function to push the existing float containing block state and
879 : // create a new scope. Code that uses this function should get matching
880 : // logic in GetFloatContainingBlock.
881 : // Pushing a null float containing block forbids any frames from being
882 : // floated until a new float containing block is pushed.
883 : // XXX we should get rid of null float containing blocks and teach the
884 : // various frame classes to deal with floats instead.
885 : void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
886 : nsFrameConstructorSaveState& aSaveState);
887 :
888 : // Function to return the proper geometric parent for a frame with display
889 : // struct given by aStyleDisplay and parent's frame given by
890 : // aContentParentFrame.
891 : nsContainerFrame* GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
892 : nsContainerFrame* aContentParentFrame) const;
893 :
894 : /**
895 : * Function to add a new frame to the right frame list. This MUST be called
896 : * on frames before their children have been processed if the frames might
897 : * conceivably be out-of-flow; otherwise cleanup in error cases won't work
898 : * right. Also, this MUST be called on frames after they have been
899 : * initialized.
900 : * @param aNewFrame the frame to add
901 : * @param aFrameItems the list to add in-flow frames to
902 : * @param aContent the content pointer for aNewFrame
903 : * @param aStyleContext the style context resolved for aContent
904 : * @param aParentFrame the parent frame for the content if it were in-flow
905 : * @param aCanBePositioned pass false if the frame isn't allowed to be
906 : * positioned
907 : * @param aCanBeFloated pass false if the frame isn't allowed to be
908 : * floated
909 : * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
910 : * (XUL-only)
911 : */
912 : void AddChild(nsIFrame* aNewFrame,
913 : nsFrameItems& aFrameItems,
914 : nsIContent* aContent,
915 : nsStyleContext* aStyleContext,
916 : nsContainerFrame* aParentFrame,
917 : bool aCanBePositioned = true,
918 : bool aCanBeFloated = true,
919 : bool aIsOutOfFlowPopup = false,
920 : bool aInsertAfter = false,
921 : nsIFrame* aInsertAfterFrame = nullptr);
922 :
923 : /**
924 : * Function to return the fixed-pos element list. Normally this will just hand back the
925 : * fixed-pos element list, but in case we're dealing with a transformed element that's
926 : * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should
927 : * use this function if they want to get the list acting as the fixed-pos item parent.
928 : */
929 6 : nsAbsoluteItems& GetFixedItems()
930 : {
931 6 : return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
932 : }
933 24 : const nsAbsoluteItems& GetFixedItems() const
934 : {
935 24 : return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
936 : }
937 :
938 :
939 : /**
940 : * class to automatically push and pop a pending binding in the frame
941 : * constructor state. See nsCSSFrameConstructor::FrameConstructionItem
942 : * mPendingBinding documentation.
943 : */
944 : class PendingBindingAutoPusher;
945 : friend class PendingBindingAutoPusher;
946 : class MOZ_STACK_CLASS PendingBindingAutoPusher {
947 : public:
948 328 : PendingBindingAutoPusher(nsFrameConstructorState& aState,
949 328 : PendingBinding* aPendingBinding) :
950 : mState(aState),
951 328 : mPendingBinding(aState.mCurrentPendingBindingInsertionPoint)
952 : {
953 328 : if (aPendingBinding) {
954 113 : aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
955 : }
956 328 : }
957 :
958 328 : ~PendingBindingAutoPusher()
959 328 : {
960 328 : mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
961 328 : }
962 :
963 : private:
964 : nsFrameConstructorState& mState;
965 : PendingBinding* mPendingBinding;
966 : };
967 :
968 : /**
969 : * Add a new pending binding to the list
970 : */
971 237 : void AddPendingBinding(PendingBinding* aPendingBinding) {
972 237 : if (mCurrentPendingBindingInsertionPoint) {
973 167 : mCurrentPendingBindingInsertionPoint->setPrevious(aPendingBinding);
974 : } else {
975 70 : mPendingBindings.insertBack(aPendingBinding);
976 : }
977 237 : }
978 :
979 : protected:
980 : friend class nsFrameConstructorSaveState;
981 :
982 : /**
983 : * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
984 : * kids to the aChildListID child list of |aFrameItems.containingBlock|.
985 : */
986 : void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
987 : ChildListID aChildListID);
988 :
989 : /**
990 : * GetOutOfFlowFrameItems selects the out-of-flow frame list the new
991 : * frame should be added to. If the frame shouldn't be added to any
992 : * out-of-flow list, it returns nullptr. The corresponding type of
993 : * placeholder is also returned via the aPlaceholderType parameter
994 : * if this method doesn't return nullptr. The caller should check
995 : * whether the returned list really has a containing block.
996 : */
997 : nsAbsoluteItems* GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
998 : bool aCanBePositioned,
999 : bool aCanBeFloated,
1000 : bool aIsOutOfFlowPopup,
1001 : nsFrameState* aPlaceholderType);
1002 :
1003 : void ConstructBackdropFrameFor(nsIContent* aContent, nsIFrame* aFrame);
1004 :
1005 : // Our list of all pending bindings. When we're done, we need to call
1006 : // AddToAttachedQueue on all of them, in order.
1007 : LinkedList<PendingBinding> mPendingBindings;
1008 :
1009 : PendingBinding* mCurrentPendingBindingInsertionPoint;
1010 : };
1011 :
1012 108 : nsFrameConstructorState::nsFrameConstructorState(
1013 : nsIPresShell* aPresShell,
1014 : TreeMatchContext* aTreeMatchContext,
1015 : nsContainerFrame* aFixedContainingBlock,
1016 : nsContainerFrame* aAbsoluteContainingBlock,
1017 : nsContainerFrame* aFloatContainingBlock,
1018 108 : already_AddRefed<nsILayoutHistoryState> aHistoryState)
1019 108 : : mPresContext(aPresShell->GetPresContext()),
1020 : mPresShell(aPresShell),
1021 108 : mFrameManager(aPresShell->FrameManager()),
1022 : #ifdef MOZ_XUL
1023 : mPopupItems(nullptr),
1024 : #endif
1025 : mFixedItems(aFixedContainingBlock),
1026 : mAbsoluteItems(aAbsoluteContainingBlock),
1027 : mFloatedItems(aFloatContainingBlock),
1028 : mTopLayerFixedItems(
1029 108 : static_cast<nsContainerFrame*>(mFrameManager->GetRootFrame())),
1030 : mTopLayerAbsoluteItems(
1031 : aPresShell->FrameConstructor()->GetDocElementContainingBlock()),
1032 : // See PushAbsoluteContaningBlock below
1033 : mFrameState(aHistoryState),
1034 : mAdditionalStateBits(nsFrameState(0)),
1035 : // If the fixed-pos containing block is equal to the abs-pos containing
1036 : // block, use the abs-pos containing block's abs-pos list for fixed-pos
1037 : // frames.
1038 108 : mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
1039 : mHavePendingPopupgroup(false),
1040 : mCreatingExtraFrames(false),
1041 : mTreeMatchContext(aTreeMatchContext),
1042 432 : mCurrentPendingBindingInsertionPoint(nullptr)
1043 : {
1044 : #ifdef MOZ_XUL
1045 108 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
1046 108 : if (rootBox) {
1047 34 : mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
1048 : }
1049 : #endif
1050 108 : MOZ_COUNT_CTOR(nsFrameConstructorState);
1051 108 : }
1052 :
1053 60 : nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
1054 : TreeMatchContext* aTreeMatchContext,
1055 : nsContainerFrame* aFixedContainingBlock,
1056 : nsContainerFrame* aAbsoluteContainingBlock,
1057 60 : nsContainerFrame* aFloatContainingBlock)
1058 : : nsFrameConstructorState(aPresShell,
1059 : aTreeMatchContext,
1060 : aFixedContainingBlock,
1061 : aAbsoluteContainingBlock,
1062 : aFloatContainingBlock,
1063 60 : aPresShell->GetDocument()->GetLayoutHistoryState())
1064 : {
1065 60 : }
1066 :
1067 216 : nsFrameConstructorState::~nsFrameConstructorState()
1068 : {
1069 108 : MOZ_COUNT_DTOR(nsFrameConstructorState);
1070 108 : ProcessFrameInsertions(mTopLayerFixedItems, nsIFrame::kFixedList);
1071 108 : ProcessFrameInsertions(mTopLayerAbsoluteItems, nsIFrame::kAbsoluteList);
1072 108 : ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
1073 108 : ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
1074 108 : ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
1075 : #ifdef MOZ_XUL
1076 108 : ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList);
1077 : #endif
1078 108 : for (int32_t i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
1079 0 : mGeneratedTextNodesWithInitializer[i]->
1080 0 : DeleteProperty(nsGkAtoms::genConInitializerProperty);
1081 : }
1082 108 : if (!mPendingBindings.isEmpty()) {
1083 16 : nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager();
1084 237 : do {
1085 474 : nsAutoPtr<PendingBinding> pendingBinding;
1086 237 : pendingBinding = mPendingBindings.popFirst();
1087 237 : bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
1088 237 : } while (!mPendingBindings.isEmpty());
1089 16 : mCurrentPendingBindingInsertionPoint = nullptr;
1090 : }
1091 108 : }
1092 :
1093 : static nsContainerFrame*
1094 40 : AdjustAbsoluteContainingBlock(nsContainerFrame* aContainingBlockIn)
1095 : {
1096 40 : if (!aContainingBlockIn) {
1097 0 : return nullptr;
1098 : }
1099 :
1100 : // Always use the container's first continuation. (Inline frames can have
1101 : // non-fluid bidi continuations...)
1102 40 : return static_cast<nsContainerFrame*>(aContainingBlockIn->FirstContinuation());
1103 : }
1104 :
1105 : void
1106 40 : nsFrameConstructorState::PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
1107 : nsIFrame* aPositionedFrame,
1108 : nsFrameConstructorSaveState& aSaveState)
1109 : {
1110 40 : aSaveState.mItems = &mAbsoluteItems;
1111 40 : aSaveState.mSavedItems = mAbsoluteItems;
1112 40 : aSaveState.mChildListID = nsIFrame::kAbsoluteList;
1113 40 : aSaveState.mState = this;
1114 40 : aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
1115 :
1116 40 : if (mFixedPosIsAbsPos) {
1117 : // Since we're going to replace mAbsoluteItems, we need to save it into
1118 : // mFixedItems now (and save the current value of mFixedItems).
1119 0 : aSaveState.mSavedFixedItems = mFixedItems;
1120 0 : mFixedItems = mAbsoluteItems;
1121 : }
1122 :
1123 40 : mAbsoluteItems =
1124 80 : nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
1125 :
1126 : /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
1127 : * we're a transformed element.
1128 : */
1129 80 : mFixedPosIsAbsPos = aPositionedFrame &&
1130 40 : aPositionedFrame->IsFixedPosContainingBlock();
1131 :
1132 40 : if (aNewAbsoluteContainingBlock) {
1133 40 : aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
1134 : }
1135 40 : }
1136 :
1137 : void
1138 252 : nsFrameConstructorState::PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
1139 : nsFrameConstructorSaveState& aSaveState)
1140 : {
1141 252 : NS_PRECONDITION(!aNewFloatContainingBlock ||
1142 : aNewFloatContainingBlock->IsFloatContainingBlock(),
1143 : "Please push a real float containing block!");
1144 252 : NS_ASSERTION(!aNewFloatContainingBlock ||
1145 : !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),
1146 : "We should not push a frame that is supposed to _suppress_ "
1147 : "floats as a float containing block!");
1148 252 : aSaveState.mItems = &mFloatedItems;
1149 252 : aSaveState.mSavedItems = mFloatedItems;
1150 252 : aSaveState.mChildListID = nsIFrame::kFloatList;
1151 252 : aSaveState.mState = this;
1152 252 : mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock);
1153 252 : }
1154 :
1155 : nsContainerFrame*
1156 87 : nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
1157 : nsContainerFrame* aContentParentFrame) const
1158 : {
1159 87 : NS_PRECONDITION(aStyleDisplay, "Must have display struct!");
1160 :
1161 : // If there is no container for a fixed, absolute, or floating root
1162 : // frame, we will ignore the positioning. This hack is originally
1163 : // brought to you by the letter T: tables, since other roots don't
1164 : // even call into this code. See bug 178855.
1165 : //
1166 : // XXX Disabling positioning in this case is a hack. If one was so inclined,
1167 : // one could support this either by (1) inserting a dummy block between the
1168 : // table and the canvas or (2) teaching the canvas how to reflow positioned
1169 : // elements. (1) has the usual problems when multiple frames share the same
1170 : // content (notice all the special cases in this file dealing with inner
1171 : // tables and table wrappers which share the same content). (2) requires some
1172 : // work and possible factoring.
1173 : //
1174 : // XXXbz couldn't we just force position to "static" on roots and
1175 : // float to "none"? That's OK per CSS 2.1, as far as I can tell.
1176 :
1177 137 : if (aContentParentFrame &&
1178 50 : nsSVGUtils::IsInSVGTextSubtree(aContentParentFrame)) {
1179 0 : return aContentParentFrame;
1180 : }
1181 :
1182 87 : if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) {
1183 0 : NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(),
1184 : "Absolutely positioned _and_ floating?");
1185 0 : return mFloatedItems.containingBlock;
1186 : }
1187 :
1188 87 : if (aStyleDisplay->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1189 0 : MOZ_ASSERT(aStyleDisplay->mTopLayer == NS_STYLE_TOP_LAYER_TOP,
1190 : "-moz-top-layer should be either none or top");
1191 0 : MOZ_ASSERT(aStyleDisplay->IsAbsolutelyPositionedStyle(),
1192 : "Top layer items should always be absolutely positioned");
1193 0 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED) {
1194 0 : MOZ_ASSERT(mTopLayerFixedItems.containingBlock, "No root frame?");
1195 0 : return mTopLayerFixedItems.containingBlock;
1196 : }
1197 0 : MOZ_ASSERT(aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE);
1198 0 : MOZ_ASSERT(mTopLayerAbsoluteItems.containingBlock);
1199 0 : return mTopLayerAbsoluteItems.containingBlock;
1200 : }
1201 :
1202 89 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
1203 2 : mAbsoluteItems.containingBlock) {
1204 0 : return mAbsoluteItems.containingBlock;
1205 : }
1206 :
1207 99 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
1208 12 : GetFixedItems().containingBlock) {
1209 12 : return GetFixedItems().containingBlock;
1210 : }
1211 :
1212 75 : return aContentParentFrame;
1213 : }
1214 :
1215 : nsAbsoluteItems*
1216 504 : nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
1217 : bool aCanBePositioned,
1218 : bool aCanBeFloated,
1219 : bool aIsOutOfFlowPopup,
1220 : nsFrameState* aPlaceholderType)
1221 : {
1222 : #ifdef MOZ_XUL
1223 504 : if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
1224 29 : MOZ_ASSERT(mPopupItems.containingBlock, "Must have a popup set frame!");
1225 29 : *aPlaceholderType = PLACEHOLDER_FOR_POPUP;
1226 29 : return &mPopupItems;
1227 : }
1228 : #endif // MOZ_XUL
1229 475 : if (aCanBeFloated && aNewFrame->IsFloating()) {
1230 0 : *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1231 0 : return &mFloatedItems;
1232 : }
1233 :
1234 475 : if (aCanBePositioned) {
1235 62 : const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1236 62 : if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1237 0 : *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1238 0 : if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1239 0 : return &mTopLayerFixedItems;
1240 : }
1241 0 : return &mTopLayerAbsoluteItems;
1242 : }
1243 62 : if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) {
1244 1 : *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1245 1 : return &mAbsoluteItems;
1246 : }
1247 61 : if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1248 6 : *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1249 6 : return &GetFixedItems();
1250 : }
1251 : }
1252 468 : return nullptr;
1253 : }
1254 :
1255 : void
1256 0 : nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent,
1257 : nsIFrame* aFrame)
1258 : {
1259 0 : MOZ_ASSERT(aFrame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1260 0 : nsContainerFrame* frame = do_QueryFrame(aFrame);
1261 0 : if (!frame) {
1262 0 : NS_WARNING("Cannot create backdrop frame for non-container frame");
1263 0 : return;
1264 : }
1265 :
1266 0 : RefPtr<nsStyleContext> style = mPresShell->StyleSet()->
1267 0 : ResolvePseudoElementStyle(aContent->AsElement(),
1268 : CSSPseudoElementType::backdrop,
1269 : /* aParentStyleContext */ nullptr,
1270 0 : /* aPseudoElement */ nullptr);
1271 0 : MOZ_ASSERT(style->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1272 : nsContainerFrame* parentFrame =
1273 0 : GetGeometricParent(style->StyleDisplay(), nullptr);
1274 :
1275 0 : nsBackdropFrame* backdropFrame = new (mPresShell) nsBackdropFrame(style);
1276 0 : backdropFrame->Init(aContent, parentFrame, nullptr);
1277 :
1278 : nsFrameState placeholderType;
1279 : nsAbsoluteItems* frameItems = GetOutOfFlowFrameItems(backdropFrame,
1280 : true, true, false,
1281 0 : &placeholderType);
1282 0 : MOZ_ASSERT(placeholderType == PLACEHOLDER_FOR_TOPLAYER);
1283 :
1284 : nsIFrame* placeholder = nsCSSFrameConstructor::
1285 0 : CreatePlaceholderFrameFor(mPresShell, aContent, backdropFrame,
1286 0 : frame, nullptr, PLACEHOLDER_FOR_TOPLAYER);
1287 0 : nsFrameList temp(placeholder, placeholder);
1288 0 : frame->SetInitialChildList(nsIFrame::kBackdropList, temp);
1289 :
1290 0 : frameItems->AddChild(backdropFrame);
1291 : }
1292 :
1293 : void
1294 504 : nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
1295 : nsFrameItems& aFrameItems,
1296 : nsIContent* aContent,
1297 : nsStyleContext* aStyleContext,
1298 : nsContainerFrame* aParentFrame,
1299 : bool aCanBePositioned,
1300 : bool aCanBeFloated,
1301 : bool aIsOutOfFlowPopup,
1302 : bool aInsertAfter,
1303 : nsIFrame* aInsertAfterFrame)
1304 : {
1305 504 : NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen");
1306 :
1307 : nsFrameState placeholderType;
1308 : nsAbsoluteItems* outOfFlowFrameItems =
1309 504 : GetOutOfFlowFrameItems(aNewFrame, aCanBePositioned, aCanBeFloated,
1310 504 : aIsOutOfFlowPopup, &placeholderType);
1311 :
1312 : // The comments in GetGeometricParent regarding root table frames
1313 : // all apply here, unfortunately. Thus, we need to check whether
1314 : // the returned frame items really has containing block.
1315 : nsFrameItems* frameItems;
1316 504 : if (outOfFlowFrameItems && outOfFlowFrameItems->containingBlock) {
1317 35 : MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameItems->containingBlock,
1318 : "Parent of the frame is not the containing block?");
1319 35 : frameItems = outOfFlowFrameItems;
1320 : } else {
1321 469 : frameItems = &aFrameItems;
1322 469 : placeholderType = nsFrameState(0);
1323 : }
1324 :
1325 504 : if (placeholderType) {
1326 35 : NS_ASSERTION(frameItems != &aFrameItems,
1327 : "Putting frame in-flow _and_ want a placeholder?");
1328 : nsIFrame* placeholderFrame =
1329 35 : nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell,
1330 : aContent,
1331 : aNewFrame,
1332 : aParentFrame,
1333 : nullptr,
1334 35 : placeholderType);
1335 :
1336 35 : placeholderFrame->AddStateBits(mAdditionalStateBits);
1337 : // Add the placeholder frame to the flow
1338 35 : aFrameItems.AddChild(placeholderFrame);
1339 :
1340 35 : if (placeholderType == PLACEHOLDER_FOR_TOPLAYER) {
1341 0 : ConstructBackdropFrameFor(aContent, aNewFrame);
1342 : }
1343 : }
1344 : #ifdef DEBUG
1345 : else {
1346 469 : NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
1347 : "In-flow frame has wrong parent");
1348 : }
1349 : #endif
1350 :
1351 504 : if (aInsertAfter) {
1352 0 : frameItems->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1353 : } else {
1354 504 : frameItems->AddChild(aNewFrame);
1355 : }
1356 504 : }
1357 :
1358 : void
1359 940 : nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
1360 : ChildListID aChildListID)
1361 : {
1362 : #define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems && \
1363 : aChildListID == nsIFrame::kFloatList) || \
1364 : ((&aFrameItems == &mAbsoluteItems || \
1365 : &aFrameItems == &mTopLayerAbsoluteItems) && \
1366 : aChildListID == nsIFrame::kAbsoluteList) || \
1367 : ((&aFrameItems == &mFixedItems || \
1368 : &aFrameItems == &mTopLayerFixedItems) && \
1369 : aChildListID == nsIFrame::kFixedList)
1370 : #ifdef MOZ_XUL
1371 940 : NS_PRECONDITION(NS_NONXUL_LIST_TEST ||
1372 : (&aFrameItems == &mPopupItems &&
1373 : aChildListID == nsIFrame::kPopupList),
1374 : "Unexpected aFrameItems/aChildListID combination");
1375 : #else
1376 : NS_PRECONDITION(NS_NONXUL_LIST_TEST,
1377 : "Unexpected aFrameItems/aChildListID combination");
1378 : #endif
1379 :
1380 940 : if (aFrameItems.IsEmpty()) {
1381 930 : return;
1382 : }
1383 :
1384 10 : nsContainerFrame* containingBlock = aFrameItems.containingBlock;
1385 :
1386 10 : NS_ASSERTION(containingBlock,
1387 : "Child list without containing block?");
1388 :
1389 10 : if (aChildListID == nsIFrame::kFixedList) {
1390 : // Put this frame on the transformed-frame's abs-pos list instead, if
1391 : // it has abs-pos children instead of fixed-pos children.
1392 3 : aChildListID = containingBlock->GetAbsoluteListID();
1393 : }
1394 :
1395 : // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1396 : // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1397 : // is set) and doesn't have any frames in the aChildListID child list yet.
1398 10 : const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1399 12 : if (childList.IsEmpty() &&
1400 2 : (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1401 : // If we're injecting absolutely positioned frames, inject them on the
1402 : // absolute containing block
1403 2 : if (aChildListID == containingBlock->GetAbsoluteListID()) {
1404 : containingBlock->GetAbsoluteContainingBlock()->
1405 1 : SetInitialChildList(containingBlock, aChildListID, aFrameItems);
1406 : } else {
1407 1 : containingBlock->SetInitialChildList(aChildListID, aFrameItems);
1408 : }
1409 8 : } else if (aChildListID == nsIFrame::kFixedList ||
1410 : aChildListID == nsIFrame::kAbsoluteList) {
1411 : // The order is not important for abs-pos/fixed-pos frame list, just
1412 : // append the frame items to the list directly.
1413 2 : mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1414 : } else {
1415 : // Note that whether the frame construction context is doing an append or
1416 : // not is not helpful here, since it could be appending to some frame in
1417 : // the middle of the document, which means we're not necessarily
1418 : // appending to the children of the containing block.
1419 : //
1420 : // We need to make sure the 'append to the end of document' case is fast.
1421 : // So first test the last child of the containing block
1422 6 : nsIFrame* lastChild = childList.LastChild();
1423 :
1424 : // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1425 : // so this will make out-of-flows respect the ordering of placeholders,
1426 : // which is great because it takes care of anonymous content.
1427 6 : nsIFrame* firstNewFrame = aFrameItems.FirstChild();
1428 :
1429 : // Cache the ancestor chain so that we can reuse it if needed.
1430 12 : AutoTArray<nsIFrame*, 20> firstNewFrameAncestors;
1431 6 : nsIFrame* notCommonAncestor = nullptr;
1432 6 : if (lastChild) {
1433 : notCommonAncestor = nsLayoutUtils::FillAncestors(firstNewFrame,
1434 : containingBlock,
1435 6 : &firstNewFrameAncestors);
1436 : }
1437 :
1438 12 : if (!lastChild ||
1439 6 : nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame,
1440 : firstNewFrameAncestors,
1441 : notCommonAncestor ?
1442 : containingBlock : nullptr) < 0) {
1443 : // no lastChild, or lastChild comes before the new children, so just append
1444 6 : mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1445 : } else {
1446 : // Try the other children. First collect them to an array so that a
1447 : // reasonable fast binary search can be used to find the insertion point.
1448 0 : AutoTArray<nsIFrame*, 128> children;
1449 0 : for (nsIFrame* f = childList.FirstChild(); f != lastChild;
1450 0 : f = f->GetNextSibling()) {
1451 0 : children.AppendElement(f);
1452 : }
1453 :
1454 0 : nsIFrame* insertionPoint = nullptr;
1455 0 : int32_t imin = 0;
1456 0 : int32_t max = children.Length();
1457 0 : while (max > imin) {
1458 0 : int32_t imid = imin + ((max - imin) / 2);
1459 0 : nsIFrame* f = children[imid];
1460 : int32_t compare =
1461 0 : nsLayoutUtils::CompareTreePosition(f, firstNewFrame, firstNewFrameAncestors,
1462 0 : notCommonAncestor ? containingBlock : nullptr);
1463 0 : if (compare > 0) {
1464 : // f is after the new frame.
1465 0 : max = imid;
1466 0 : insertionPoint = imid > 0 ? children[imid - 1] : nullptr;
1467 0 : } else if (compare < 0) {
1468 : // f is before the new frame.
1469 0 : imin = imid + 1;
1470 0 : insertionPoint = f;
1471 : } else {
1472 : // This is for the old behavior. Should be removed once it is
1473 : // guaranteed that CompareTreePosition can't return 0!
1474 : // See bug 928645.
1475 0 : NS_WARNING("Something odd happening???");
1476 0 : insertionPoint = nullptr;
1477 0 : for (uint32_t i = 0; i < children.Length(); ++i) {
1478 0 : nsIFrame* f = children[i];
1479 0 : if (nsLayoutUtils::CompareTreePosition(f, firstNewFrame,
1480 : firstNewFrameAncestors,
1481 : notCommonAncestor ?
1482 : containingBlock : nullptr) > 0) {
1483 0 : break;
1484 : }
1485 0 : insertionPoint = f;
1486 : }
1487 0 : break;
1488 : }
1489 : }
1490 0 : mFrameManager->InsertFrames(containingBlock, aChildListID,
1491 0 : insertionPoint, aFrameItems);
1492 : }
1493 : }
1494 :
1495 10 : NS_POSTCONDITION(aFrameItems.IsEmpty(), "How did that happen?");
1496 : }
1497 :
1498 :
1499 681 : nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1500 : : mItems(nullptr),
1501 : mSavedItems(nullptr),
1502 : mChildListID(kPrincipalList),
1503 : mState(nullptr),
1504 : mSavedFixedItems(nullptr),
1505 681 : mSavedFixedPosIsAbsPos(false)
1506 : {
1507 681 : }
1508 :
1509 1362 : nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1510 : {
1511 : // Restore the state
1512 681 : if (mItems) {
1513 292 : NS_ASSERTION(mState, "Can't have mItems set without having a state!");
1514 292 : mState->ProcessFrameInsertions(*mItems, mChildListID);
1515 292 : *mItems = mSavedItems;
1516 : #ifdef DEBUG
1517 : // We've transferred the child list, so drop the pointer we held to it.
1518 : // Note that this only matters for the assert in ~nsAbsoluteItems.
1519 292 : mSavedItems.Clear();
1520 : #endif
1521 292 : if (mItems == &mState->mAbsoluteItems) {
1522 40 : mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
1523 40 : if (mSavedFixedPosIsAbsPos) {
1524 : // mAbsoluteItems was moved to mFixedItems, so move mFixedItems back
1525 : // and repair the old mFixedItems now.
1526 0 : mState->mAbsoluteItems = mState->mFixedItems;
1527 0 : mState->mFixedItems = mSavedFixedItems;
1528 : #ifdef DEBUG
1529 0 : mSavedFixedItems.Clear();
1530 : #endif
1531 : }
1532 : }
1533 292 : NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(),
1534 : "Something corrupted our list");
1535 : }
1536 681 : }
1537 :
1538 : /**
1539 : * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1540 : * pointer of the frames in the list, and reparents their views as needed.
1541 : * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1542 : * ancestors as needed. Then it sets the list as the initial child list
1543 : * on aNewParent, unless aNewParent either already has kids or has been
1544 : * reflowed; in that case it appends the new frames. Note that this
1545 : * method differs from ReparentFrames in that it doesn't change the kids'
1546 : * style contexts.
1547 : */
1548 : // XXXbz Since this is only used for {ib} splits, could we just copy the view
1549 : // bits from aOldParent to aNewParent and then use the
1550 : // nsFrameList::ApplySetParent? That would still leave us doing two passes
1551 : // over the list, of course; if we really wanted to we could factor out the
1552 : // relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1553 : // views, which would make most of this function go away.
1554 : static void
1555 0 : MoveChildrenTo(nsIFrame* aOldParent,
1556 : nsContainerFrame* aNewParent,
1557 : nsFrameList& aFrameList)
1558 : {
1559 0 : bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent();
1560 :
1561 0 : if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) {
1562 : // Move the frames into the new view
1563 0 : nsContainerFrame::ReparentFrameViewList(aFrameList, aOldParent, aNewParent);
1564 : }
1565 :
1566 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
1567 0 : e.get()->SetParent(aNewParent);
1568 : }
1569 :
1570 0 : if (aNewParent->PrincipalChildList().IsEmpty() &&
1571 0 : (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1572 0 : aNewParent->SetInitialChildList(kPrincipalList, aFrameList);
1573 : } else {
1574 0 : aNewParent->AppendFrames(kPrincipalList, aFrameList);
1575 : }
1576 0 : }
1577 :
1578 : //----------------------------------------------------------------------
1579 :
1580 28 : nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument* aDocument,
1581 28 : nsIPresShell* aPresShell)
1582 : : nsFrameManager(aPresShell)
1583 : , mDocument(aDocument)
1584 : , mRootElementFrame(nullptr)
1585 : , mRootElementStyleFrame(nullptr)
1586 : , mDocElementContainingBlock(nullptr)
1587 : , mPageSequenceFrame(nullptr)
1588 : , mCurrentDepth(0)
1589 : #ifdef DEBUG
1590 : , mUpdateCount(0)
1591 : #endif
1592 : , mQuotesDirty(false)
1593 : , mCountersDirty(false)
1594 : , mIsDestroyingFrameTree(false)
1595 : , mHasRootAbsPosContainingBlock(false)
1596 28 : , mAlwaysCreateFramesForIgnorableWhitespace(false)
1597 : {
1598 : #ifdef DEBUG
1599 : static bool gFirstTime = true;
1600 28 : if (gFirstTime) {
1601 2 : gFirstTime = false;
1602 2 : char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1603 2 : if (flags) {
1604 0 : bool error = false;
1605 : for (;;) {
1606 0 : char* comma = PL_strchr(flags, ',');
1607 0 : if (comma)
1608 0 : *comma = '\0';
1609 :
1610 0 : bool found = false;
1611 0 : FrameCtorDebugFlags* flag = gFlags;
1612 0 : FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1613 0 : while (flag < limit) {
1614 0 : if (PL_strcasecmp(flag->name, flags) == 0) {
1615 0 : *(flag->on) = true;
1616 0 : printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag->name);
1617 0 : found = true;
1618 0 : break;
1619 : }
1620 0 : ++flag;
1621 : }
1622 :
1623 0 : if (! found)
1624 0 : error = true;
1625 :
1626 0 : if (! comma)
1627 0 : break;
1628 :
1629 0 : *comma = ',';
1630 0 : flags = comma + 1;
1631 0 : }
1632 :
1633 0 : if (error) {
1634 0 : printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1635 0 : FrameCtorDebugFlags* flag = gFlags;
1636 0 : FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1637 0 : while (flag < limit) {
1638 0 : printf(" %s\n", flag->name);
1639 0 : ++flag;
1640 : }
1641 0 : printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1642 0 : printf("names (no whitespace)\n");
1643 : }
1644 : }
1645 : }
1646 : #endif
1647 28 : }
1648 :
1649 : void
1650 126 : nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
1651 : {
1652 126 : NS_PRECONDITION(mUpdateCount != 0,
1653 : "Should be in an update while destroying frames");
1654 :
1655 126 : if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
1656 0 : if (mQuoteList.DestroyNodesFor(aFrame))
1657 0 : QuotesDirty();
1658 : }
1659 :
1660 126 : if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1661 0 : mCounterManager.DestroyNodesFor(aFrame)) {
1662 : // Technically we don't need to update anything if we destroyed only
1663 : // USE nodes. However, this is unlikely to happen in the real world
1664 : // since USE nodes generally go along with INCREMENT nodes.
1665 0 : CountersDirty();
1666 : }
1667 :
1668 126 : RestyleManager()->NotifyDestroyingFrame(aFrame);
1669 :
1670 126 : nsFrameManager::NotifyDestroyingFrame(aFrame);
1671 126 : }
1672 :
1673 0 : struct nsGenConInitializer {
1674 : nsAutoPtr<nsGenConNode> mNode;
1675 : nsGenConList* mList;
1676 : void (nsCSSFrameConstructor::*mDirtyAll)();
1677 :
1678 0 : nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
1679 : void (nsCSSFrameConstructor::*aDirtyAll)())
1680 0 : : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {}
1681 : };
1682 :
1683 : already_AddRefed<nsIContent>
1684 6 : nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState,
1685 : const nsString& aString,
1686 : RefPtr<nsTextNode>* aText,
1687 : nsGenConInitializer* aInitializer)
1688 : {
1689 18 : RefPtr<nsTextNode> content = new nsTextNode(mDocument->NodeInfoManager());
1690 6 : content->SetText(aString, false);
1691 6 : if (aText) {
1692 0 : *aText = content;
1693 : }
1694 6 : if (aInitializer) {
1695 0 : content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
1696 0 : nsINode::DeleteProperty<nsGenConInitializer>);
1697 0 : aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
1698 : }
1699 12 : return content.forget();
1700 : }
1701 :
1702 : already_AddRefed<nsIContent>
1703 6 : nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
1704 : nsIContent* aParentContent,
1705 : nsStyleContext* aStyleContext,
1706 : uint32_t aContentIndex)
1707 : {
1708 : // Get the content value
1709 : const nsStyleContentData &data =
1710 6 : aStyleContext->StyleContent()->ContentAt(aContentIndex);
1711 6 : nsStyleContentType type = data.GetType();
1712 :
1713 6 : switch (type) {
1714 : case eStyleContentType_Image: {
1715 0 : imgRequestProxy* image = data.GetImage();
1716 0 : if (!image) {
1717 : // CSS had something specified that couldn't be converted to an
1718 : // image object
1719 0 : return nullptr;
1720 : }
1721 :
1722 : // Create an image content object and pass it the image request.
1723 : // XXX Check if it's an image type we can handle...
1724 :
1725 0 : RefPtr<NodeInfo> nodeInfo;
1726 0 : nodeInfo = mDocument->NodeInfoManager()->
1727 0 : GetNodeInfo(nsGkAtoms::mozgeneratedcontentimage, nullptr,
1728 0 : kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE);
1729 :
1730 0 : nsCOMPtr<nsIContent> content;
1731 0 : NS_NewGenConImageContent(getter_AddRefs(content), nodeInfo.forget(),
1732 0 : image);
1733 0 : return content.forget();
1734 : }
1735 :
1736 : case eStyleContentType_String:
1737 : return CreateGenConTextNode(aState,
1738 12 : nsDependentString(data.GetString()),
1739 6 : nullptr, nullptr);
1740 :
1741 : case eStyleContentType_Attr: {
1742 0 : nsCOMPtr<nsIAtom> attrName;
1743 0 : int32_t attrNameSpace = kNameSpaceID_None;
1744 0 : nsAutoString contentString(data.GetString());
1745 :
1746 0 : int32_t barIndex = contentString.FindChar('|'); // CSS namespace delimiter
1747 0 : if (-1 != barIndex) {
1748 0 : nsAutoString nameSpaceVal;
1749 0 : contentString.Left(nameSpaceVal, barIndex);
1750 : nsresult error;
1751 0 : attrNameSpace = nameSpaceVal.ToInteger(&error);
1752 0 : contentString.Cut(0, barIndex + 1);
1753 0 : if (contentString.Length()) {
1754 0 : if (mDocument->IsHTMLDocument() && aParentContent->IsHTMLElement()) {
1755 0 : ToLowerCase(contentString);
1756 : }
1757 0 : attrName = NS_Atomize(contentString);
1758 : }
1759 : }
1760 : else {
1761 0 : if (mDocument->IsHTMLDocument() && aParentContent->IsHTMLElement()) {
1762 0 : ToLowerCase(contentString);
1763 : }
1764 0 : attrName = NS_Atomize(contentString);
1765 : }
1766 :
1767 0 : if (!attrName) {
1768 0 : return nullptr;
1769 : }
1770 :
1771 0 : nsCOMPtr<nsIContent> content;
1772 0 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1773 0 : attrNameSpace, attrName, getter_AddRefs(content));
1774 0 : return content.forget();
1775 : }
1776 :
1777 : case eStyleContentType_Counter:
1778 : case eStyleContentType_Counters: {
1779 0 : nsStyleContentData::CounterFunction* counters = data.GetCounters();
1780 : nsCounterList* counterList =
1781 0 : mCounterManager.CounterListFor(counters->mIdent);
1782 :
1783 : nsCounterUseNode* node =
1784 : new nsCounterUseNode(counters, aContentIndex,
1785 0 : type == eStyleContentType_Counters);
1786 :
1787 : nsGenConInitializer* initializer =
1788 : new nsGenConInitializer(node, counterList,
1789 0 : &nsCSSFrameConstructor::CountersDirty);
1790 : return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1791 0 : initializer);
1792 : }
1793 :
1794 : case eStyleContentType_OpenQuote:
1795 : case eStyleContentType_CloseQuote:
1796 : case eStyleContentType_NoOpenQuote:
1797 : case eStyleContentType_NoCloseQuote: {
1798 : nsQuoteNode* node =
1799 0 : new nsQuoteNode(type, aContentIndex);
1800 :
1801 : nsGenConInitializer* initializer =
1802 : new nsGenConInitializer(node, &mQuoteList,
1803 0 : &nsCSSFrameConstructor::QuotesDirty);
1804 : return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1805 0 : initializer);
1806 : }
1807 :
1808 : case eStyleContentType_AltContent: {
1809 : // Use the "alt" attribute; if that fails and the node is an HTML
1810 : // <input>, try the value attribute and then fall back to some default
1811 : // localized text we have.
1812 : // XXX what if the 'alt' attribute is added later, how will we
1813 : // detect that and do the right thing here?
1814 0 : if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
1815 0 : nsCOMPtr<nsIContent> content;
1816 0 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1817 0 : kNameSpaceID_None, nsGkAtoms::alt, getter_AddRefs(content));
1818 0 : return content.forget();
1819 : }
1820 :
1821 0 : if (aParentContent->IsHTMLElement() &&
1822 0 : aParentContent->NodeInfo()->Equals(nsGkAtoms::input)) {
1823 0 : if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
1824 0 : nsCOMPtr<nsIContent> content;
1825 0 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1826 0 : kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content));
1827 0 : return content.forget();
1828 : }
1829 :
1830 0 : nsXPIDLString temp;
1831 : nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
1832 0 : "Submit", temp);
1833 0 : return CreateGenConTextNode(aState, temp, nullptr, nullptr);
1834 : }
1835 :
1836 0 : break;
1837 : }
1838 :
1839 : case eStyleContentType_Uninitialized:
1840 0 : NS_NOTREACHED("uninitialized content type");
1841 0 : return nullptr;
1842 : }
1843 :
1844 0 : return nullptr;
1845 : }
1846 :
1847 : /*
1848 : * aParentFrame - the frame that should be the parent of the generated
1849 : * content. This is the frame for the corresponding content node,
1850 : * which must not be a leaf frame.
1851 : *
1852 : * Any items created are added to aItems.
1853 : *
1854 : * We create an XML element (tag _moz_generated_content_before or
1855 : * _moz_generated_content_after) representing the pseudoelement. We
1856 : * create a DOM node for each 'content' item and make those nodes the
1857 : * children of the XML element. Then we create a frame subtree for
1858 : * the XML element as if it were a regular child of
1859 : * aParentFrame/aParentContent, giving the XML element the ::before or
1860 : * ::after style.
1861 : */
1862 : void
1863 460 : nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState,
1864 : nsContainerFrame* aParentFrame,
1865 : nsIContent* aParentContent,
1866 : nsStyleContext* aStyleContext,
1867 : CSSPseudoElementType aPseudoElement,
1868 : FrameConstructionItemList& aItems)
1869 : {
1870 460 : MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before ||
1871 : aPseudoElement == CSSPseudoElementType::after,
1872 : "unexpected aPseudoElement");
1873 :
1874 460 : MOZ_ASSERT(aParentContent->IsElement());
1875 :
1876 460 : StyleSetHandle styleSet = mPresShell->StyleSet();
1877 :
1878 : // Probe for the existence of the pseudo-element
1879 466 : RefPtr<nsStyleContext> pseudoStyleContext;
1880 : pseudoStyleContext =
1881 920 : styleSet->ProbePseudoElementStyle(aParentContent->AsElement(),
1882 : aPseudoElement,
1883 : aStyleContext,
1884 460 : aState.mTreeMatchContext);
1885 460 : if (!pseudoStyleContext)
1886 454 : return;
1887 :
1888 6 : bool isBefore = aPseudoElement == CSSPseudoElementType::before;
1889 :
1890 : // |ProbePseudoStyleFor| checked the 'display' property and the
1891 : // |ContentCount()| of the 'content' property for us.
1892 12 : RefPtr<NodeInfo> nodeInfo;
1893 6 : nsIAtom* elemName = isBefore ?
1894 6 : nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
1895 12 : nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nullptr,
1896 : kNameSpaceID_None,
1897 6 : nsIDOMNode::ELEMENT_NODE);
1898 12 : nsCOMPtr<Element> container;
1899 6 : nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1900 6 : if (NS_FAILED(rv))
1901 0 : return;
1902 :
1903 : // Cleared when the pseudo is unbound from the tree, so no need to store a
1904 : // strong reference, nor a destructor.
1905 : nsIAtom* property = isBefore
1906 6 : ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
1907 6 : aParentContent->SetProperty(property, container.get());
1908 :
1909 6 : container->SetIsNativeAnonymousRoot();
1910 6 : container->SetPseudoElementType(aPseudoElement);
1911 :
1912 : // If the parent is in a shadow tree, make sure we don't
1913 : // bind with a document because shadow roots and its descendants
1914 : // are not in document.
1915 : nsIDocument* bindDocument =
1916 6 : aParentContent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
1917 6 : rv = container->BindToTree(bindDocument, aParentContent, aParentContent, true);
1918 6 : if (NS_FAILED(rv)) {
1919 0 : container->UnbindFromTree();
1920 0 : return;
1921 : }
1922 :
1923 : // Servo has already eagerly computed the style for the container, so we can
1924 : // just stick the style on the element and avoid an additional traversal.
1925 : //
1926 : // We don't do this for pseudos that may trigger animations or transitions,
1927 : // since those need to be kicked off by the traversal machinery.
1928 6 : bool isServo = pseudoStyleContext->IsServo();
1929 6 : bool hasServoAnimations = false;
1930 6 : if (isServo) {
1931 0 : ServoComputedValues* servoStyle = pseudoStyleContext->ComputedValues();
1932 0 : hasServoAnimations = Servo_ComputedValues_SpecifiesAnimationsOrTransitions(servoStyle);
1933 0 : if (!hasServoAnimations) {
1934 0 : Servo_SetExplicitStyle(container, servoStyle);
1935 : }
1936 : }
1937 :
1938 : // stylo: ServoRestyleManager does not handle transitions yet, and when it
1939 : // does it probably won't need to track reframed style contexts to start
1940 : // transitions correctly.
1941 6 : if (mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->GetAsGecko()) {
1942 : GeckoRestyleManager::ReframingStyleContexts* rsc =
1943 6 : geckoRM->GetReframingStyleContexts();
1944 6 : if (rsc) {
1945 0 : nsStyleContext* oldStyleContext = rsc->Get(container, aPseudoElement);
1946 0 : if (oldStyleContext) {
1947 0 : GeckoRestyleManager::TryInitiatingTransition(aState.mPresContext,
1948 : container,
1949 : oldStyleContext,
1950 0 : &pseudoStyleContext);
1951 : } else {
1952 0 : aState.mPresContext->TransitionManager()->
1953 0 : PruneCompletedTransitions(aParentContent->AsElement(),
1954 0 : aPseudoElement, pseudoStyleContext);
1955 : }
1956 : }
1957 : }
1958 :
1959 6 : uint32_t contentCount = pseudoStyleContext->StyleContent()->ContentCount();
1960 6 : bool createdChildElement = false;
1961 12 : for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
1962 : nsCOMPtr<nsIContent> content =
1963 12 : CreateGeneratedContent(aState, aParentContent, pseudoStyleContext,
1964 12 : contentIndex);
1965 6 : if (content) {
1966 6 : container->AppendChildTo(content, false);
1967 6 : if (content->IsElement()) {
1968 0 : createdChildElement = true;
1969 : }
1970 : }
1971 : }
1972 :
1973 : // We may need to do a synchronous servo traversal in various uncommon cases.
1974 6 : if (isServo) {
1975 0 : if (hasServoAnimations) {
1976 : // If animations are involved, we avoid the SetExplicitStyle optimization
1977 : // above.
1978 0 : mPresShell->StyleSet()->AsServo()->StyleNewSubtree(container);
1979 0 : } else if (createdChildElement) {
1980 : // If we created any children elements, Servo needs to traverse them, but
1981 : // the root is already set up.
1982 0 : mPresShell->StyleSet()->AsServo()->StyleNewChildren(container);
1983 : }
1984 : }
1985 :
1986 6 : AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
1987 : kNameSpaceID_None, true,
1988 : pseudoStyleContext,
1989 : ITEM_IS_GENERATED_CONTENT, nullptr,
1990 6 : aItems);
1991 : }
1992 :
1993 : /****************************************************
1994 : ** BEGIN TABLE SECTION
1995 : ****************************************************/
1996 :
1997 : // The term pseudo frame is being used instead of anonymous frame, since anonymous
1998 : // frame has been used elsewhere to refer to frames that have generated content
1999 :
2000 : // Return whether the given frame is a table pseudo-frame. Note that
2001 : // cell-content and table-outer frames have pseudo-types, but are always
2002 : // created, even for non-anonymous cells and tables respectively. So for those
2003 : // we have to examine the cell or table frame to see whether it's a pseudo
2004 : // frame. In particular, a lone table caption will have a table wrapper as its
2005 : // parent, but will also trigger construction of an empty inner table, which
2006 : // will be the one we can examine to see whether the wrapper was a pseudo-frame.
2007 : static bool
2008 84 : IsTablePseudo(nsIFrame* aFrame)
2009 : {
2010 84 : nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
2011 96 : return pseudoType &&
2012 24 : (pseudoType == nsCSSAnonBoxes::table ||
2013 24 : pseudoType == nsCSSAnonBoxes::inlineTable ||
2014 24 : pseudoType == nsCSSAnonBoxes::tableColGroup ||
2015 24 : pseudoType == nsCSSAnonBoxes::tableRowGroup ||
2016 24 : pseudoType == nsCSSAnonBoxes::tableRow ||
2017 24 : pseudoType == nsCSSAnonBoxes::tableCell ||
2018 12 : (pseudoType == nsCSSAnonBoxes::cellContent &&
2019 0 : aFrame->GetParent()->StyleContext()->GetPseudo() ==
2020 12 : nsCSSAnonBoxes::tableCell) ||
2021 12 : (pseudoType == nsCSSAnonBoxes::tableWrapper &&
2022 0 : (aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo() ==
2023 0 : nsCSSAnonBoxes::table ||
2024 0 : aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo() ==
2025 84 : nsCSSAnonBoxes::inlineTable)));
2026 : }
2027 :
2028 : static bool
2029 128 : IsRubyPseudo(nsIFrame* aFrame)
2030 : {
2031 128 : return RubyUtils::IsRubyPseudo(aFrame->StyleContext()->GetPseudo());
2032 : }
2033 :
2034 : static bool
2035 84 : IsTableOrRubyPseudo(nsIFrame* aFrame)
2036 : {
2037 84 : return IsTablePseudo(aFrame) || IsRubyPseudo(aFrame);
2038 : }
2039 :
2040 : /* static */
2041 : nsCSSFrameConstructor::ParentType
2042 1702 : nsCSSFrameConstructor::GetParentType(LayoutFrameType aFrameType)
2043 : {
2044 1702 : if (aFrameType == LayoutFrameType::Table) {
2045 0 : return eTypeTable;
2046 : }
2047 1702 : if (aFrameType == LayoutFrameType::TableRowGroup) {
2048 0 : return eTypeRowGroup;
2049 : }
2050 1702 : if (aFrameType == LayoutFrameType::TableRow) {
2051 0 : return eTypeRow;
2052 : }
2053 1702 : if (aFrameType == LayoutFrameType::TableColGroup) {
2054 0 : return eTypeColGroup;
2055 : }
2056 1702 : if (aFrameType == LayoutFrameType::RubyBaseContainer) {
2057 0 : return eTypeRubyBaseContainer;
2058 : }
2059 1702 : if (aFrameType == LayoutFrameType::RubyTextContainer) {
2060 0 : return eTypeRubyTextContainer;
2061 : }
2062 1702 : if (aFrameType == LayoutFrameType::Ruby) {
2063 0 : return eTypeRuby;
2064 : }
2065 :
2066 1702 : return eTypeBlock;
2067 : }
2068 :
2069 : static nsContainerFrame*
2070 0 : AdjustCaptionParentFrame(nsContainerFrame* aParentFrame)
2071 : {
2072 0 : if (aParentFrame->IsTableFrame()) {
2073 0 : return aParentFrame->GetParent();
2074 : }
2075 0 : return aParentFrame;
2076 : }
2077 :
2078 : /**
2079 : * If the parent frame is a |tableFrame| and the child is a
2080 : * |captionFrame|, then we want to insert the frames beneath the
2081 : * |tableFrame|'s parent frame. Returns |true| if the parent frame
2082 : * needed to be fixed up.
2083 : */
2084 : static bool
2085 0 : GetCaptionAdjustedParent(nsContainerFrame* aParentFrame,
2086 : const nsIFrame* aChildFrame,
2087 : nsContainerFrame** aAdjParentFrame)
2088 : {
2089 0 : *aAdjParentFrame = aParentFrame;
2090 0 : bool haveCaption = false;
2091 :
2092 0 : if (aChildFrame->IsTableCaption()) {
2093 0 : haveCaption = true;
2094 0 : *aAdjParentFrame = ::AdjustCaptionParentFrame(aParentFrame);
2095 : }
2096 0 : return haveCaption;
2097 : }
2098 :
2099 : void
2100 492 : nsCSSFrameConstructor::AdjustParentFrame(nsContainerFrame** aParentFrame,
2101 : const FrameConstructionData* aFCData,
2102 : nsStyleContext* aStyleContext)
2103 : {
2104 492 : NS_PRECONDITION(aStyleContext, "Must have child's style context");
2105 492 : NS_PRECONDITION(aFCData, "Must have frame construction data");
2106 :
2107 492 : bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0);
2108 :
2109 492 : if (tablePart && aStyleContext->StyleDisplay()->mDisplay ==
2110 : StyleDisplay::TableCaption) {
2111 0 : *aParentFrame = ::AdjustCaptionParentFrame(*aParentFrame);
2112 : }
2113 492 : }
2114 :
2115 : // Pull all the captions present in aItems out into aCaptions
2116 : static void
2117 0 : PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions)
2118 : {
2119 0 : nsIFrame* child = aItems.FirstChild();
2120 0 : while (child) {
2121 0 : nsIFrame* nextSibling = child->GetNextSibling();
2122 0 : if (child->IsTableCaption()) {
2123 0 : aItems.RemoveFrame(child);
2124 0 : aCaptions.AddChild(child);
2125 : }
2126 0 : child = nextSibling;
2127 : }
2128 0 : }
2129 :
2130 :
2131 : // Construct the outer, inner table frames and the children frames for the table.
2132 : // XXX Page break frames for pseudo table frames are not constructed to avoid the risk
2133 : // associated with revising the pseudo frame mechanism. The long term solution
2134 : // of having frames handle page-break-before/after will solve the problem.
2135 : nsIFrame*
2136 0 : nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
2137 : FrameConstructionItem& aItem,
2138 : nsContainerFrame* aParentFrame,
2139 : const nsStyleDisplay* aDisplay,
2140 : nsFrameItems& aFrameItems)
2141 : {
2142 0 : NS_PRECONDITION(aDisplay->mDisplay == StyleDisplay::Table ||
2143 : aDisplay->mDisplay == StyleDisplay::InlineTable,
2144 : "Unexpected call");
2145 :
2146 0 : nsIContent* const content = aItem.mContent;
2147 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2148 0 : const uint32_t nameSpaceID = aItem.mNameSpaceID;
2149 :
2150 : // create the pseudo SC for the table wrapper as a child of the inner SC
2151 0 : RefPtr<nsStyleContext> outerStyleContext;
2152 0 : outerStyleContext = mPresShell->StyleSet()->
2153 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::tableWrapper,
2154 0 : styleContext);
2155 :
2156 : // Create the table wrapper frame which holds the caption and inner table frame
2157 : nsContainerFrame* newFrame;
2158 0 : if (kNameSpaceID_MathML == nameSpaceID)
2159 0 : newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerStyleContext);
2160 : else
2161 0 : newFrame = NS_NewTableWrapperFrame(mPresShell, outerStyleContext);
2162 :
2163 : nsContainerFrame* geometricParent =
2164 0 : aState.GetGeometricParent(outerStyleContext->StyleDisplay(),
2165 0 : aParentFrame);
2166 :
2167 : // Init the table wrapper frame
2168 0 : InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2169 :
2170 : // Create the inner table frame
2171 : nsContainerFrame* innerFrame;
2172 0 : if (kNameSpaceID_MathML == nameSpaceID)
2173 0 : innerFrame = NS_NewMathMLmtableFrame(mPresShell, styleContext);
2174 : else
2175 0 : innerFrame = NS_NewTableFrame(mPresShell, styleContext);
2176 :
2177 0 : InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2178 0 : innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2179 :
2180 : // Put the newly created frames into the right child list
2181 0 : SetInitialSingleChild(newFrame, innerFrame);
2182 :
2183 0 : aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
2184 :
2185 0 : if (!mRootElementFrame) {
2186 : // The frame we're constructing will be the root element frame.
2187 : // Set mRootElementFrame before processing children.
2188 0 : mRootElementFrame = newFrame;
2189 : }
2190 :
2191 0 : nsFrameItems childItems;
2192 :
2193 : // Process children
2194 0 : nsFrameConstructorSaveState absoluteSaveState;
2195 0 : const nsStyleDisplay* display = outerStyleContext->StyleDisplay();
2196 :
2197 : // Mark the table frame as an absolute container if needed
2198 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2199 0 : if (display->IsAbsPosContainingBlock(newFrame)) {
2200 0 : aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2201 : }
2202 0 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2203 : "nsIAnonymousContentCreator::CreateAnonymousContent "
2204 : "implementations for table frames are not currently expected "
2205 : "to output a list where the items have their own children");
2206 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2207 0 : ConstructFramesFromItemList(aState, aItem.mChildItems,
2208 0 : innerFrame, childItems);
2209 : } else {
2210 0 : ProcessChildren(aState, content, styleContext, innerFrame,
2211 0 : true, childItems, false, aItem.mPendingBinding);
2212 : }
2213 :
2214 0 : nsFrameItems captionItems;
2215 0 : PullOutCaptionFrames(childItems, captionItems);
2216 :
2217 : // Set the inner table frame's initial primary list
2218 0 : innerFrame->SetInitialChildList(kPrincipalList, childItems);
2219 :
2220 : // Set the table wrapper frame's secondary childlist lists
2221 0 : if (captionItems.NotEmpty()) {
2222 0 : newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems);
2223 : }
2224 :
2225 0 : return newFrame;
2226 : }
2227 :
2228 : static void
2229 0 : MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState& aState,
2230 : const nsStyleDisplay* aDisplay,
2231 : nsFrameConstructorSaveState& aAbsSaveState,
2232 : nsContainerFrame* aFrame)
2233 : {
2234 : // If we're positioned, then we need to become an absolute containing block
2235 : // for any absolutely positioned children and register for post-reflow fixup.
2236 : //
2237 : // Note that usually if a frame type can be an absolute containing block, we
2238 : // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not.
2239 : // However, in this case flag serves the additional purpose of indicating that
2240 : // the frame was registered with its table frame. This allows us to avoid the
2241 : // overhead of unregistering the frame in most cases.
2242 0 : if (aDisplay->IsAbsPosContainingBlock(aFrame)) {
2243 0 : aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2244 0 : aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2245 0 : nsTableFrame::RegisterPositionedTablePart(aFrame);
2246 : }
2247 0 : }
2248 :
2249 : nsIFrame*
2250 0 : nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
2251 : FrameConstructionItem& aItem,
2252 : nsContainerFrame* aParentFrame,
2253 : const nsStyleDisplay* aDisplay,
2254 : nsFrameItems& aFrameItems)
2255 : {
2256 0 : MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableRow ||
2257 : aDisplay->mDisplay == StyleDisplay::TableRowGroup ||
2258 : aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
2259 : aDisplay->mDisplay == StyleDisplay::TableHeaderGroup,
2260 : "Not a row or row group");
2261 0 : MOZ_ASSERT(aItem.mStyleContext->StyleDisplay() == aDisplay,
2262 : "Display style doesn't match style context");
2263 0 : nsIContent* const content = aItem.mContent;
2264 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2265 0 : const uint32_t nameSpaceID = aItem.mNameSpaceID;
2266 :
2267 : nsContainerFrame* newFrame;
2268 0 : if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2269 0 : if (kNameSpaceID_MathML == nameSpaceID)
2270 0 : newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext);
2271 : else
2272 0 : newFrame = NS_NewTableRowFrame(mPresShell, styleContext);
2273 : } else {
2274 0 : newFrame = NS_NewTableRowGroupFrame(mPresShell, styleContext);
2275 : }
2276 :
2277 0 : InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2278 :
2279 0 : nsFrameConstructorSaveState absoluteSaveState;
2280 : MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2281 : absoluteSaveState,
2282 0 : newFrame);
2283 :
2284 0 : nsFrameItems childItems;
2285 0 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2286 : "nsIAnonymousContentCreator::CreateAnonymousContent "
2287 : "implementations for table frames are not currently expected "
2288 : "to output a list where the items have their own children");
2289 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2290 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
2291 0 : childItems);
2292 : } else {
2293 0 : ProcessChildren(aState, content, styleContext, newFrame,
2294 0 : true, childItems, false, aItem.mPendingBinding);
2295 : }
2296 :
2297 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
2298 0 : aFrameItems.AddChild(newFrame);
2299 0 : return newFrame;
2300 : }
2301 :
2302 : nsIFrame*
2303 0 : nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState& aState,
2304 : FrameConstructionItem& aItem,
2305 : nsContainerFrame* aParentFrame,
2306 : const nsStyleDisplay* aStyleDisplay,
2307 : nsFrameItems& aFrameItems)
2308 : {
2309 0 : nsIContent* const content = aItem.mContent;
2310 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2311 :
2312 0 : nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, styleContext);
2313 0 : InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2314 :
2315 0 : NS_ASSERTION(colFrame->StyleContext() == styleContext,
2316 : "Unexpected style context");
2317 :
2318 0 : aFrameItems.AddChild(colFrame);
2319 :
2320 : // construct additional col frames if the col frame has a span > 1
2321 0 : int32_t span = colFrame->GetSpan();
2322 0 : for (int32_t spanX = 1; spanX < span; spanX++) {
2323 0 : nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, styleContext);
2324 0 : InitAndRestoreFrame(aState, content, aParentFrame, newCol, false);
2325 0 : aFrameItems.LastChild()->SetNextContinuation(newCol);
2326 0 : newCol->SetPrevContinuation(aFrameItems.LastChild());
2327 0 : aFrameItems.AddChild(newCol);
2328 0 : newCol->SetColType(eColAnonymousCol);
2329 : }
2330 :
2331 0 : return colFrame;
2332 : }
2333 :
2334 : nsIFrame*
2335 0 : nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState,
2336 : FrameConstructionItem& aItem,
2337 : nsContainerFrame* aParentFrame,
2338 : const nsStyleDisplay* aDisplay,
2339 : nsFrameItems& aFrameItems)
2340 : {
2341 0 : MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableCell,
2342 : "Unexpected call");
2343 :
2344 0 : nsIContent* const content = aItem.mContent;
2345 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2346 0 : const uint32_t nameSpaceID = aItem.mNameSpaceID;
2347 :
2348 : nsTableFrame* tableFrame =
2349 0 : static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2350 : nsContainerFrame* newFrame;
2351 : // <mtable> is border separate in mathml.css and the MathML code doesn't implement
2352 : // border collapse. For those users who style <mtable> with border collapse,
2353 : // give them the default non-MathML table frames that understand border collapse.
2354 : // This won't break us because MathML table frames are all subclasses of the default
2355 : // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
2356 : // What will happen is just that non-MathML frames won't understand MathML attributes
2357 : // and will therefore miss the special handling that the MathML code does.
2358 0 : if (kNameSpaceID_MathML == nameSpaceID && !tableFrame->IsBorderCollapse()) {
2359 0 : newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext, tableFrame);
2360 : } else {
2361 : // Warning: If you change this and add a wrapper frame around table cell
2362 : // frames, make sure Bug 368554 doesn't regress!
2363 : // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2364 0 : newFrame = NS_NewTableCellFrame(mPresShell, styleContext, tableFrame);
2365 : }
2366 :
2367 : // Initialize the table cell frame
2368 0 : InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2369 0 : newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2370 :
2371 : // Resolve pseudo style and initialize the body cell frame
2372 0 : RefPtr<nsStyleContext> innerPseudoStyle;
2373 0 : innerPseudoStyle = mPresShell->StyleSet()->
2374 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::cellContent,
2375 0 : styleContext);
2376 :
2377 : // Create a block frame that will format the cell's content
2378 : bool isBlock;
2379 : nsContainerFrame* cellInnerFrame;
2380 0 : if (kNameSpaceID_MathML == nameSpaceID) {
2381 0 : cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2382 0 : isBlock = false;
2383 : } else {
2384 0 : cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
2385 0 : isBlock = true;
2386 : }
2387 :
2388 0 : InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame);
2389 :
2390 0 : nsFrameConstructorSaveState absoluteSaveState;
2391 : MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2392 : absoluteSaveState,
2393 0 : newFrame);
2394 :
2395 0 : nsFrameItems childItems;
2396 0 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2397 : "nsIAnonymousContentCreator::CreateAnonymousContent "
2398 : "implementations for table frames are not currently expected "
2399 : "to output a list where the items have their own children");
2400 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2401 : // Need to push ourselves as a float containing block.
2402 : // XXXbz it might be nice to work on getting the parent
2403 : // FrameConstructionItem down into ProcessChildren and just making use of
2404 : // the push there, but that's a bit of work.
2405 0 : nsFrameConstructorSaveState floatSaveState;
2406 0 : if (!isBlock) { /* MathML case */
2407 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
2408 : } else {
2409 0 : aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
2410 : }
2411 :
2412 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
2413 0 : childItems);
2414 : } else {
2415 : // Process the child content
2416 0 : ProcessChildren(aState, content, styleContext, cellInnerFrame,
2417 0 : true, childItems, isBlock, aItem.mPendingBinding);
2418 : }
2419 :
2420 0 : cellInnerFrame->SetInitialChildList(kPrincipalList, childItems);
2421 0 : SetInitialSingleChild(newFrame, cellInnerFrame);
2422 0 : aFrameItems.AddChild(newFrame);
2423 0 : return newFrame;
2424 : }
2425 :
2426 : static inline bool
2427 884 : NeedFrameFor(const nsFrameConstructorState& aState,
2428 : nsIFrame* aParentFrame,
2429 : nsIContent* aChildContent)
2430 : {
2431 : // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2432 : // Remove it once that's fixed.
2433 884 : NS_PRECONDITION(!aChildContent->GetPrimaryFrame() ||
2434 : aState.mCreatingExtraFrames ||
2435 : aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
2436 : "Why did we get called?");
2437 :
2438 : // don't create a whitespace frame if aParentFrame doesn't want it.
2439 : // always create frames for children in generated content. counter(),
2440 : // quotes, and attr() content can easily change dynamically and we don't
2441 : // want to be reconstructing frames. It's not even clear that these
2442 : // should be considered ignorable just because they evaluate to
2443 : // whitespace.
2444 :
2445 : // We could handle all this in CreateNeededPseudoContainers or some other
2446 : // place after we build our frame construction items, but that would involve
2447 : // creating frame construction items for whitespace kids of
2448 : // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2449 : // all anyway, and involve an extra walk down the frame construction item
2450 : // list.
2451 1768 : if ((aParentFrame &&
2452 1464 : (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
2453 2039 : aParentFrame->IsGeneratedContentFrame())) ||
2454 575 : !aChildContent->IsNodeOfType(nsINode::eTEXT)) {
2455 884 : return true;
2456 : }
2457 :
2458 0 : aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2459 0 : NS_REFRAME_IF_WHITESPACE);
2460 0 : return !aChildContent->TextIsOnlyWhitespace();
2461 : }
2462 :
2463 : /***********************************************
2464 : * END TABLE SECTION
2465 : ***********************************************/
2466 :
2467 : nsIFrame*
2468 24 : nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocElement,
2469 : nsILayoutHistoryState* aFrameState)
2470 : {
2471 24 : MOZ_ASSERT(GetRootFrame(),
2472 : "No viewport? Someone forgot to call ConstructRootFrame!");
2473 24 : MOZ_ASSERT(!mDocElementContainingBlock,
2474 : "Shouldn't have a doc element containing block here");
2475 :
2476 : // Resolve a new style context for the viewport since it may be affected
2477 : // by a new root element style (e.g. a propagated 'direction').
2478 : // @see nsStyleContext::ApplyStyleFixups
2479 : {
2480 48 : RefPtr<nsStyleContext> sc = mPresShell->StyleSet()->
2481 72 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport, nullptr);
2482 24 : GetRootFrame()->SetStyleContextWithoutNotification(sc);
2483 : }
2484 :
2485 : // Make sure to call UpdateViewportScrollbarStylesOverride before
2486 : // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2487 : // properly.
2488 48 : DebugOnly<nsIContent*> propagatedScrollFrom;
2489 24 : if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2490 24 : propagatedScrollFrom = presContext->UpdateViewportScrollbarStylesOverride();
2491 : }
2492 :
2493 24 : SetUpDocElementContainingBlock(aDocElement);
2494 :
2495 24 : NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
2496 :
2497 48 : TreeMatchContextHolder matchContext(mDocument);
2498 : // Initialize the ancestor filter with null for now; we'll push
2499 : // aDocElement once we finish resolving style for it.
2500 24 : if (matchContext.Exists()) {
2501 24 : matchContext->InitAncestors(nullptr);
2502 : }
2503 : nsFrameConstructorState state(mPresShell,
2504 : matchContext,
2505 24 : GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2506 : nullptr,
2507 72 : nullptr, do_AddRef(aFrameState));
2508 :
2509 : // XXXbz why, exactly?
2510 24 : if (!mTempFrameTreeState)
2511 24 : state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
2512 :
2513 : // Make sure that we'll handle restyles for this document element in
2514 : // the future. We need this, because the document element might
2515 : // have stale restyle bits from a previous frame constructor for
2516 : // this document. Unlike in AddFrameConstructionItems, it's safe to
2517 : // unset all element restyle flags, since we don't have any
2518 : // siblings.
2519 24 : aDocElement->UnsetRestyleFlagsIfGecko();
2520 :
2521 : // --------- CREATE AREA OR BOX FRAME -------
2522 24 : if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
2523 : // NOTE(emilio): If the root has a non-null binding, we'll stop at the
2524 : // document element and won't process any children, loading the bindings (or
2525 : // failing to do so) will take care of the rest.
2526 0 : set->StyleDocument(TraversalRestyleBehavior::Normal);
2527 : }
2528 :
2529 : // FIXME: Should this use ResolveStyleContext? (The calls in this
2530 : // function are the only case in nsCSSFrameConstructor where we don't
2531 : // do so for the construction of a style context for an element.)
2532 : RefPtr<nsStyleContext> styleContext =
2533 48 : mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
2534 : nullptr,
2535 48 : LazyComputeBehavior::Assert);
2536 :
2537 24 : const nsStyleDisplay* display = styleContext->StyleDisplay();
2538 :
2539 : // Ensure that our XBL bindings are installed.
2540 24 : if (display->mBinding) {
2541 : // Get the XBL loader.
2542 : nsresult rv;
2543 : bool resolveStyle;
2544 :
2545 1 : nsXBLService* xblService = nsXBLService::GetInstance();
2546 1 : if (!xblService) {
2547 0 : return nullptr;
2548 : }
2549 :
2550 2 : RefPtr<nsXBLBinding> binding;
2551 2 : rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
2552 1 : display->mBinding->mExtraData->GetPrincipal(),
2553 2 : getter_AddRefs(binding), &resolveStyle);
2554 1 : if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
2555 : // Binding will load asynchronously.
2556 0 : if (aDocElement->IsStyledByServo()) {
2557 0 : ServoRestyleManager::ClearServoDataFromSubtree(aDocElement);
2558 : }
2559 0 : return nullptr;
2560 : }
2561 :
2562 1 : if (binding) {
2563 : // For backwards compat, keep firing the root's constructor
2564 : // after all of its kids' constructors. So tell the binding
2565 : // manager about it right now.
2566 1 : mDocument->BindingManager()->AddToAttachedQueue(binding);
2567 : }
2568 :
2569 1 : if (resolveStyle) {
2570 : // FIXME: Should this use ResolveStyleContext? (The calls in this
2571 : // function are the only case in nsCSSFrameConstructor where we
2572 : // don't do so for the construction of a style context for an
2573 : // element.)
2574 : //
2575 : // FIXME(emilio): This looks fishy. It really wants to fully re-resolve
2576 : // the style, but it wont if the element is already styled afaict... It
2577 : // seems we handle it on a subsequent restyle?
2578 0 : styleContext = mPresShell->StyleSet()->ResolveStyleFor(
2579 0 : aDocElement, nullptr, LazyComputeBehavior::Assert);
2580 0 : display = styleContext->StyleDisplay();
2581 : }
2582 23 : } else if (display->mBinding.ForceGet() && aDocElement->IsStyledByServo()) {
2583 : // See the comment in AddFrameConstructionItemsInternal for why this is
2584 : // needed.
2585 0 : mPresShell->StyleSet()->AsServo()->StyleNewChildren(aDocElement);
2586 : }
2587 :
2588 : // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2589 :
2590 24 : NS_ASSERTION(!display->IsScrollableOverflow() ||
2591 : state.mPresContext->IsPaginated() ||
2592 : propagatedScrollFrom == aDocElement,
2593 : "Scrollbars should have been propagated to the viewport");
2594 :
2595 24 : if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
2596 0 : SetUndisplayedContent(aDocElement, styleContext);
2597 0 : return nullptr;
2598 : }
2599 :
2600 48 : TreeMatchContext::AutoAncestorPusher ancestorPusher(state.mTreeMatchContext);
2601 24 : ancestorPusher.PushAncestorAndStyleScope(aDocElement);
2602 :
2603 : // Make sure to start any background image loads for the root element now.
2604 24 : styleContext->StartBackgroundImageLoads();
2605 :
2606 48 : nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
2607 24 : if (mHasRootAbsPosContainingBlock) {
2608 : // Push the absolute containing block now so we can absolutely position
2609 : // the root element
2610 23 : mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2611 23 : state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2612 23 : mDocElementContainingBlock,
2613 23 : docElementContainingBlockAbsoluteSaveState);
2614 : }
2615 :
2616 : // The rules from CSS 2.1, section 9.2.4, have already been applied
2617 : // by the style system, so we can assume that display->mDisplay is
2618 : // either NONE, BLOCK, or TABLE.
2619 :
2620 : // contentFrame is the primary frame for the root element. newFrame
2621 : // is the frame that will be the child of the initial containing block.
2622 : // These are usually the same frame but they can be different, in
2623 : // particular if the root frame is positioned, in which case
2624 : // contentFrame is the out-of-flow frame and newFrame is the
2625 : // placeholder.
2626 : nsContainerFrame* contentFrame;
2627 : nsIFrame* newFrame;
2628 24 : bool processChildren = false;
2629 :
2630 48 : nsFrameConstructorSaveState absoluteSaveState;
2631 :
2632 : // Check whether we need to build a XUL box or SVG root frame
2633 : #ifdef MOZ_XUL
2634 24 : if (aDocElement->IsXULElement()) {
2635 1 : contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext);
2636 1 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2637 1 : contentFrame);
2638 1 : newFrame = contentFrame;
2639 1 : processChildren = true;
2640 : }
2641 : else
2642 : #endif
2643 23 : if (aDocElement->IsSVGElement()) {
2644 21 : if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2645 0 : return nullptr;
2646 : }
2647 : // We're going to call the right function ourselves, so no need to give a
2648 : // function to this FrameConstructionData.
2649 :
2650 : // XXXbz on the other hand, if we converted this whole function to
2651 : // FrameConstructionData/Item, then we'd need the right function
2652 : // here... but would probably be able to get away with less code in this
2653 : // function in general.
2654 : // Use a null PendingBinding, since our binding is not in fact pending.
2655 : static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
2656 : already_AddRefed<nsStyleContext> extraRef =
2657 42 : RefPtr<nsStyleContext>(styleContext).forget();
2658 : FrameConstructionItem item(&rootSVGData, aDocElement,
2659 : aDocElement->NodeInfo()->NameAtom(),
2660 : kNameSpaceID_SVG, nullptr, extraRef, true,
2661 42 : nullptr);
2662 :
2663 21 : nsFrameItems frameItems;
2664 21 : contentFrame = static_cast<nsContainerFrame*>(
2665 21 : ConstructOuterSVG(state, item, mDocElementContainingBlock,
2666 : styleContext->StyleDisplay(),
2667 : frameItems));
2668 21 : newFrame = frameItems.FirstChild();
2669 21 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2670 4 : } else if (display->mDisplay == StyleDisplay::Flex ||
2671 2 : display->mDisplay == StyleDisplay::WebkitBox) {
2672 0 : contentFrame = NS_NewFlexContainerFrame(mPresShell, styleContext);
2673 0 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2674 0 : contentFrame);
2675 0 : newFrame = contentFrame;
2676 0 : processChildren = true;
2677 :
2678 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2679 0 : if (display->IsAbsPosContainingBlock(newFrame)) {
2680 : state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2681 0 : absoluteSaveState);
2682 : }
2683 :
2684 2 : } else if (display->mDisplay == StyleDisplay::Grid) {
2685 0 : contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
2686 0 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2687 0 : contentFrame);
2688 0 : newFrame = contentFrame;
2689 0 : processChildren = true;
2690 :
2691 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2692 0 : if (display->IsAbsPosContainingBlock(newFrame)) {
2693 : state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2694 0 : absoluteSaveState);
2695 : }
2696 2 : } else if (display->mDisplay == StyleDisplay::Table) {
2697 : // We're going to call the right function ourselves, so no need to give a
2698 : // function to this FrameConstructionData.
2699 :
2700 : // XXXbz on the other hand, if we converted this whole function to
2701 : // FrameConstructionData/Item, then we'd need the right function
2702 : // here... but would probably be able to get away with less code in this
2703 : // function in general.
2704 : // Use a null PendingBinding, since our binding is not in fact pending.
2705 : static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
2706 : already_AddRefed<nsStyleContext> extraRef =
2707 0 : RefPtr<nsStyleContext>(styleContext).forget();
2708 : FrameConstructionItem item(&rootTableData, aDocElement,
2709 : aDocElement->NodeInfo()->NameAtom(),
2710 : kNameSpaceID_None, nullptr, extraRef, true,
2711 0 : nullptr);
2712 :
2713 0 : nsFrameItems frameItems;
2714 : // if the document is a table then just populate it.
2715 0 : contentFrame = static_cast<nsContainerFrame*>(
2716 0 : ConstructTable(state, item, mDocElementContainingBlock,
2717 : styleContext->StyleDisplay(),
2718 : frameItems));
2719 0 : newFrame = frameItems.FirstChild();
2720 0 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2721 : } else {
2722 2 : MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||
2723 : display->mDisplay == StyleDisplay::FlowRoot,
2724 : "Unhandled display type for root element");
2725 2 : contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
2726 2 : nsFrameItems frameItems;
2727 : // Use a null PendingBinding, since our binding is not in fact pending.
2728 2 : ConstructBlock(state, aDocElement,
2729 : state.GetGeometricParent(display,
2730 : mDocElementContainingBlock),
2731 : mDocElementContainingBlock, styleContext,
2732 : &contentFrame, frameItems,
2733 2 : display->IsAbsPosContainingBlock(contentFrame) ? contentFrame : nullptr,
2734 2 : nullptr);
2735 2 : newFrame = frameItems.FirstChild();
2736 2 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2737 : }
2738 :
2739 24 : MOZ_ASSERT(newFrame);
2740 24 : MOZ_ASSERT(contentFrame);
2741 :
2742 24 : NS_ASSERTION(processChildren ? !mRootElementFrame :
2743 : mRootElementFrame == contentFrame,
2744 : "unexpected mRootElementFrame");
2745 24 : mRootElementFrame = contentFrame;
2746 :
2747 : // Figure out which frame has the main style for the document element,
2748 : // assigning it to mRootElementStyleFrame.
2749 : // Backgrounds should be propagated from that frame to the viewport.
2750 24 : contentFrame->GetParentStyleContext(&mRootElementStyleFrame);
2751 24 : bool isChild = mRootElementStyleFrame &&
2752 24 : mRootElementStyleFrame->GetParent() == contentFrame;
2753 24 : if (!isChild) {
2754 24 : mRootElementStyleFrame = mRootElementFrame;
2755 : }
2756 :
2757 24 : if (processChildren) {
2758 : // Still need to process the child content
2759 1 : nsFrameItems childItems;
2760 :
2761 1 : NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) &&
2762 : !contentFrame->IsFrameOfType(nsIFrame::eSVG),
2763 : "Only XUL frames should reach here");
2764 : // Use a null PendingBinding, since our binding is not in fact pending.
2765 1 : ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
2766 2 : childItems, false, nullptr);
2767 :
2768 : // Set the initial child lists
2769 1 : contentFrame->SetInitialChildList(kPrincipalList, childItems);
2770 : }
2771 :
2772 : // set the primary frame
2773 24 : aDocElement->SetPrimaryFrame(contentFrame);
2774 :
2775 24 : SetInitialSingleChild(mDocElementContainingBlock, newFrame);
2776 :
2777 : // Create frames for anonymous contents if there is a canvas frame.
2778 24 : if (mDocElementContainingBlock->IsCanvasFrame()) {
2779 23 : ConstructAnonymousContentForCanvas(state, mDocElementContainingBlock,
2780 23 : aDocElement);
2781 : }
2782 :
2783 24 : return newFrame;
2784 : }
2785 :
2786 :
2787 : nsIFrame*
2788 24 : nsCSSFrameConstructor::ConstructRootFrame()
2789 : {
2790 48 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
2791 :
2792 24 : StyleSetHandle styleSet = mPresShell->StyleSet();
2793 :
2794 : // --------- BUILD VIEWPORT -----------
2795 : RefPtr<nsStyleContext> viewportPseudoStyle =
2796 48 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport,
2797 48 : nullptr);
2798 : ViewportFrame* viewportFrame =
2799 24 : NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2800 :
2801 : // XXXbz do we _have_ to pass a null content pointer to that frame?
2802 : // Would it really kill us to pass in the root element or something?
2803 : // What would that break?
2804 24 : viewportFrame->Init(nullptr, nullptr, nullptr);
2805 :
2806 24 : viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2807 :
2808 : // Bind the viewport frame to the root view
2809 24 : nsView* rootView = mPresShell->GetViewManager()->GetRootView();
2810 24 : viewportFrame->SetView(rootView);
2811 :
2812 24 : viewportFrame->SyncFrameViewProperties(rootView);
2813 24 : nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
2814 24 : rootView, nullptr, nsContainerFrame::SET_ASYNC);
2815 :
2816 : // Make it an absolute container for fixed-pos elements
2817 24 : viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2818 24 : viewportFrame->MarkAsAbsoluteContainingBlock();
2819 :
2820 48 : return viewportFrame;
2821 : }
2822 :
2823 : void
2824 24 : nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
2825 : {
2826 24 : NS_PRECONDITION(aDocElement, "No element?");
2827 24 : NS_PRECONDITION(!aDocElement->GetParent(), "Not root content?");
2828 24 : NS_PRECONDITION(aDocElement->GetUncomposedDoc(), "Not in a document?");
2829 24 : NS_PRECONDITION(aDocElement->GetUncomposedDoc()->GetRootElement() ==
2830 : aDocElement, "Not the root of the document?");
2831 :
2832 : /*
2833 : how the root frame hierarchy should look
2834 :
2835 : Galley presentation, non-XUL, with scrolling:
2836 :
2837 : ViewportFrame [fixed-cb]
2838 : nsHTMLScrollFrame
2839 : nsCanvasFrame [abs-cb]
2840 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2841 : nsTableWrapperFrame, nsPlaceholderFrame)
2842 :
2843 : Galley presentation, XUL
2844 :
2845 : ViewportFrame [fixed-cb]
2846 : nsRootBoxFrame
2847 : root element frame (nsDocElementBoxFrame)
2848 :
2849 : Print presentation, non-XUL
2850 :
2851 : ViewportFrame
2852 : nsSimplePageSequenceFrame
2853 : nsPageFrame
2854 : nsPageContentFrame [fixed-cb]
2855 : nsCanvasFrame [abs-cb]
2856 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2857 : nsTableWrapperFrame, nsPlaceholderFrame)
2858 :
2859 : Print-preview presentation, non-XUL
2860 :
2861 : ViewportFrame
2862 : nsHTMLScrollFrame
2863 : nsSimplePageSequenceFrame
2864 : nsPageFrame
2865 : nsPageContentFrame [fixed-cb]
2866 : nsCanvasFrame [abs-cb]
2867 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2868 : nsTableWrapperFrame, nsPlaceholderFrame)
2869 :
2870 : Print/print preview of XUL is not supported.
2871 : [fixed-cb]: the default containing block for fixed-pos content
2872 : [abs-cb]: the default containing block for abs-pos content
2873 :
2874 : Meaning of nsCSSFrameConstructor fields:
2875 : mRootElementFrame is "root element frame". This is the primary frame for
2876 : the root element.
2877 : mDocElementContainingBlock is the parent of mRootElementFrame
2878 : (i.e. nsCanvasFrame or nsRootBoxFrame)
2879 :
2880 : mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
2881 : */
2882 :
2883 : // --------- CREATE ROOT FRAME -------
2884 :
2885 :
2886 : // Create the root frame. The document element's frame is a child of the
2887 : // root frame.
2888 : //
2889 : // The root frame serves two purposes:
2890 : // - reserves space for any margins needed for the document element's frame
2891 : // - renders the document element's background. This ensures the background covers
2892 : // the entire canvas as specified by the CSS2 spec
2893 :
2894 24 : nsPresContext* presContext = mPresShell->GetPresContext();
2895 24 : bool isPaginated = presContext->IsRootPaginatedDocument();
2896 24 : nsContainerFrame* viewportFrame = static_cast<nsContainerFrame*>(GetRootFrame());
2897 24 : nsStyleContext* viewportPseudoStyle = viewportFrame->StyleContext();
2898 :
2899 24 : nsContainerFrame* rootFrame = nullptr;
2900 : nsIAtom* rootPseudo;
2901 :
2902 24 : if (!isPaginated) {
2903 : #ifdef MOZ_XUL
2904 24 : if (aDocElement->IsXULElement())
2905 : {
2906 : // pass a temporary stylecontext, the correct one will be set later
2907 1 : rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
2908 : } else
2909 : #endif
2910 : {
2911 : // pass a temporary stylecontext, the correct one will be set later
2912 23 : rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2913 23 : mHasRootAbsPosContainingBlock = true;
2914 : }
2915 :
2916 24 : rootPseudo = nsCSSAnonBoxes::canvas;
2917 24 : mDocElementContainingBlock = rootFrame;
2918 : } else {
2919 : // Create a page sequence frame
2920 0 : rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
2921 0 : mPageSequenceFrame = rootFrame;
2922 0 : rootPseudo = nsCSSAnonBoxes::pageSequence;
2923 0 : rootFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2924 : }
2925 :
2926 :
2927 : // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2928 :
2929 : // If the device supports scrolling (e.g., in galley mode on the screen and
2930 : // for print-preview, but not when printing), then create a scroll frame that
2931 : // will act as the scrolling mechanism for the viewport.
2932 : // XXX Do we even need a viewport when printing to a printer?
2933 :
2934 24 : bool isHTML = aDocElement->IsHTMLElement();
2935 24 : bool isXUL = false;
2936 :
2937 24 : if (!isHTML) {
2938 22 : isXUL = aDocElement->IsXULElement();
2939 : }
2940 :
2941 : // Never create scrollbars for XUL documents
2942 24 : bool isScrollable = isPaginated ? presContext->HasPaginatedScrolling() : !isXUL;
2943 :
2944 : // We no longer need to do overflow propagation here. It's taken care of
2945 : // when we construct frames for the element whose overflow might be
2946 : // propagated
2947 24 : NS_ASSERTION(!isScrollable || !isXUL,
2948 : "XUL documents should never be scrollable - see above");
2949 :
2950 24 : nsContainerFrame* newFrame = rootFrame;
2951 48 : RefPtr<nsStyleContext> rootPseudoStyle;
2952 : // we must create a state because if the scrollbars are GFX it needs the
2953 : // state to build the scrollbar frames.
2954 48 : TreeMatchContextHolder matchContext(mDocument);
2955 48 : nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
2956 :
2957 : // Start off with the viewport as parent; we'll adjust it as needed.
2958 24 : nsContainerFrame* parentFrame = viewportFrame;
2959 :
2960 24 : StyleSetHandle styleSet = mPresShell->StyleSet();
2961 : // If paginated, make sure we don't put scrollbars in
2962 24 : if (!isScrollable) {
2963 : rootPseudoStyle =
2964 2 : styleSet->ResolveInheritingAnonymousBoxStyle(rootPseudo,
2965 1 : viewportPseudoStyle);
2966 : } else {
2967 23 : if (rootPseudo == nsCSSAnonBoxes::canvas) {
2968 23 : rootPseudo = nsCSSAnonBoxes::scrolledCanvas;
2969 : } else {
2970 0 : NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence,
2971 : "Unknown root pseudo");
2972 0 : rootPseudo = nsCSSAnonBoxes::scrolledPageSequence;
2973 : }
2974 :
2975 : // Build the frame. We give it the content we are wrapping which is the
2976 : // document element, the root frame, the parent view port frame, and we
2977 : // should get back the new frame and the scrollable view if one was
2978 : // created.
2979 :
2980 : // resolve a context for the scrollframe
2981 46 : RefPtr<nsStyleContext> styleContext;
2982 : styleContext =
2983 46 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll,
2984 23 : viewportPseudoStyle);
2985 :
2986 : // Note that the viewport scrollframe is always built with
2987 : // overflow:auto style. This forces the scroll frame to create
2988 : // anonymous content for both scrollbars. This is necessary even
2989 : // if the HTML or BODY elements are overriding the viewport
2990 : // scroll style to 'hidden' --- dynamic style changes might put
2991 : // scrollbars back on the viewport and we don't want to have to
2992 : // reframe the viewport to create the scrollbar content.
2993 23 : newFrame = nullptr;
2994 46 : rootPseudoStyle = BeginBuildingScrollFrame( state,
2995 : aDocElement,
2996 : styleContext,
2997 : viewportFrame,
2998 : rootPseudo,
2999 : true,
3000 23 : newFrame);
3001 23 : parentFrame = newFrame;
3002 : }
3003 :
3004 24 : rootFrame->SetStyleContextWithoutNotification(rootPseudoStyle);
3005 24 : rootFrame->Init(aDocElement, parentFrame, nullptr);
3006 :
3007 24 : if (isScrollable) {
3008 23 : FinishBuildingScrollFrame(parentFrame, rootFrame);
3009 : }
3010 :
3011 24 : if (isPaginated) {
3012 : // Create the first page
3013 : // Set the initial child lists
3014 : nsContainerFrame* canvasFrame;
3015 : nsContainerFrame* pageFrame =
3016 0 : ConstructPageFrame(mPresShell, rootFrame, nullptr, canvasFrame);
3017 0 : pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3018 0 : SetInitialSingleChild(rootFrame, pageFrame);
3019 :
3020 : // The eventual parent of the document element frame.
3021 : // XXX should this be set for every new page (in ConstructPageFrame)?
3022 0 : mDocElementContainingBlock = canvasFrame;
3023 0 : mHasRootAbsPosContainingBlock = true;
3024 : }
3025 :
3026 24 : if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
3027 24 : SetInitialSingleChild(viewportFrame, newFrame);
3028 : } else {
3029 0 : nsFrameList newFrameList(newFrame, newFrame);
3030 0 : viewportFrame->AppendFrames(kPrincipalList, newFrameList);
3031 : }
3032 24 : }
3033 :
3034 : void
3035 23 : nsCSSFrameConstructor::ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
3036 : nsIFrame* aFrame,
3037 : nsIContent* aDocElement)
3038 : {
3039 23 : NS_ASSERTION(aFrame->IsCanvasFrame(), "aFrame should be canvas frame!");
3040 :
3041 46 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
3042 23 : GetAnonymousContent(aDocElement, aFrame, anonymousItems);
3043 23 : if (anonymousItems.IsEmpty()) {
3044 0 : return;
3045 : }
3046 :
3047 46 : FrameConstructionItemList itemsToConstruct;
3048 23 : nsContainerFrame* frameAsContainer = do_QueryFrame(aFrame);
3049 23 : AddFCItemsForAnonymousContent(aState, frameAsContainer, anonymousItems, itemsToConstruct);
3050 :
3051 23 : nsFrameItems frameItems;
3052 23 : ConstructFramesFromItemList(aState, itemsToConstruct, frameAsContainer, frameItems);
3053 23 : frameAsContainer->AppendFrames(kPrincipalList, frameItems);
3054 : }
3055 :
3056 : nsContainerFrame*
3057 0 : nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
3058 : nsContainerFrame* aParentFrame,
3059 : nsIFrame* aPrevPageFrame,
3060 : nsContainerFrame*& aCanvasFrame)
3061 : {
3062 0 : nsStyleContext* parentStyleContext = aParentFrame->StyleContext();
3063 0 : StyleSetHandle styleSet = aPresShell->StyleSet();
3064 :
3065 0 : RefPtr<nsStyleContext> pagePseudoStyle;
3066 : pagePseudoStyle =
3067 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::page,
3068 0 : parentStyleContext);
3069 :
3070 0 : nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
3071 :
3072 : // Initialize the page frame and force it to have a view. This makes printing of
3073 : // the pages easier and faster.
3074 0 : pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
3075 :
3076 0 : RefPtr<nsStyleContext> pageContentPseudoStyle;
3077 : pageContentPseudoStyle =
3078 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::pageContent,
3079 0 : pagePseudoStyle);
3080 :
3081 : nsContainerFrame* pageContentFrame =
3082 0 : NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
3083 :
3084 : // Initialize the page content frame and force it to have a view. Also make it the
3085 : // containing block for fixed elements which are repeated on every page.
3086 0 : nsIFrame* prevPageContentFrame = nullptr;
3087 0 : if (aPrevPageFrame) {
3088 0 : prevPageContentFrame = aPrevPageFrame->PrincipalChildList().FirstChild();
3089 0 : NS_ASSERTION(prevPageContentFrame, "missing page content frame");
3090 : }
3091 0 : pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
3092 0 : if (!prevPageContentFrame) {
3093 0 : pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3094 : }
3095 0 : SetInitialSingleChild(pageFrame, pageContentFrame);
3096 : // Make it an absolute container for fixed-pos elements
3097 0 : pageContentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3098 0 : pageContentFrame->MarkAsAbsoluteContainingBlock();
3099 :
3100 0 : RefPtr<nsStyleContext> canvasPseudoStyle;
3101 : canvasPseudoStyle =
3102 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::canvas,
3103 0 : pageContentPseudoStyle);
3104 :
3105 0 : aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
3106 :
3107 0 : nsIFrame* prevCanvasFrame = nullptr;
3108 0 : if (prevPageContentFrame) {
3109 0 : prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
3110 0 : NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
3111 : }
3112 0 : aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
3113 0 : SetInitialSingleChild(pageContentFrame, aCanvasFrame);
3114 0 : return pageFrame;
3115 : }
3116 :
3117 : /* static */
3118 : nsIFrame*
3119 35 : nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell,
3120 : nsIContent* aContent,
3121 : nsIFrame* aFrame,
3122 : nsContainerFrame* aParentFrame,
3123 : nsIFrame* aPrevInFlow,
3124 : nsFrameState aTypeBit)
3125 : {
3126 70 : RefPtr<nsStyleContext> placeholderStyle = aPresShell->StyleSet()->
3127 70 : ResolveStyleForPlaceholder();
3128 :
3129 : // The placeholder frame gets a pseudo style context
3130 : nsPlaceholderFrame* placeholderFrame =
3131 35 : (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
3132 35 : aTypeBit);
3133 :
3134 35 : placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
3135 :
3136 : // Associate the placeholder/out-of-flow with each other.
3137 35 : placeholderFrame->SetOutOfFlowFrame(aFrame);
3138 35 : aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
3139 :
3140 35 : aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
3141 :
3142 70 : return placeholderFrame;
3143 : }
3144 :
3145 : // Clears any lazy bits set in the range [aStartContent, aEndContent). If
3146 : // aEndContent is null, that means to clear bits in all siblings starting with
3147 : // aStartContent. aStartContent must not be null unless aEndContent is also
3148 : // null. We do this so that when new children are inserted under elements whose
3149 : // frame is a leaf the new children don't cause us to try to construct frames
3150 : // for the existing children again.
3151 : static inline void
3152 74 : ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent)
3153 : {
3154 74 : NS_PRECONDITION(aStartContent || !aEndContent,
3155 : "Must have start child if we have an end child");
3156 405 : for (nsIContent* cur = aStartContent; cur != aEndContent;
3157 331 : cur = cur->GetNextSibling()) {
3158 331 : cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
3159 : }
3160 74 : }
3161 :
3162 : nsIFrame*
3163 0 : nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
3164 : FrameConstructionItem& aItem,
3165 : nsContainerFrame* aParentFrame,
3166 : const nsStyleDisplay* aStyleDisplay,
3167 : nsFrameItems& aFrameItems)
3168 : {
3169 0 : nsIContent* const content = aItem.mContent;
3170 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
3171 :
3172 : // Construct a frame-based listbox or combobox
3173 0 : dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromContent(content);
3174 0 : MOZ_ASSERT(sel);
3175 0 : if (sel->IsCombobox()) {
3176 : // Construct a frame-based combo box.
3177 : // The frame-based combo box is built out of three parts. A display area, a button and
3178 : // a dropdown list. The display area and button are created through anonymous content.
3179 : // The drop-down list's frame is created explicitly. The combobox frame shares its content
3180 : // with the drop-down list.
3181 0 : nsFrameState flags = NS_BLOCK_FLOAT_MGR;
3182 : nsComboboxControlFrame* comboboxFrame =
3183 0 : NS_NewComboboxControlFrame(mPresShell, styleContext, flags);
3184 :
3185 : // Save the history state so we don't restore during construction
3186 : // since the complete tree is required before we restore.
3187 0 : nsILayoutHistoryState *historyState = aState.mFrameState;
3188 0 : aState.mFrameState = nullptr;
3189 : // Initialize the combobox frame
3190 0 : InitAndRestoreFrame(aState, content,
3191 : aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3192 0 : comboboxFrame);
3193 :
3194 0 : comboboxFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3195 :
3196 : aState.AddChild(comboboxFrame, aFrameItems, content, styleContext,
3197 0 : aParentFrame);
3198 :
3199 : // Resolve pseudo element style for the dropdown list
3200 0 : RefPtr<nsStyleContext> listStyle;
3201 0 : listStyle = mPresShell->StyleSet()->
3202 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList,
3203 0 : styleContext);
3204 :
3205 : // Create a listbox
3206 0 : nsContainerFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
3207 :
3208 : // Notify the listbox that it is being used as a dropdown list.
3209 0 : nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
3210 0 : if (listControlFrame) {
3211 0 : listControlFrame->SetComboboxFrame(comboboxFrame);
3212 : }
3213 : // Notify combobox that it should use the listbox as it's popup
3214 0 : comboboxFrame->SetDropDown(listFrame);
3215 :
3216 0 : NS_ASSERTION(!listFrame->IsAbsPosContainingBlock(),
3217 : "Ended up with positioned dropdown list somehow.");
3218 0 : NS_ASSERTION(!listFrame->IsFloating(),
3219 : "Ended up with floating dropdown list somehow.");
3220 :
3221 : // Initialize the scroll frame positioned. Note that it is NOT
3222 : // initialized as absolutely positioned.
3223 : nsContainerFrame* scrolledFrame =
3224 0 : NS_NewSelectsAreaFrame(mPresShell, styleContext, flags);
3225 :
3226 0 : InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3227 : comboboxFrame, listStyle, true,
3228 0 : aItem.mPendingBinding, aFrameItems);
3229 :
3230 0 : NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nullptr");
3231 :
3232 : // Create display and button frames from the combobox's anonymous content.
3233 : // The anonymous content is appended to existing anonymous content for this
3234 : // element (the scrollbars).
3235 0 : nsFrameItems childItems;
3236 :
3237 : // nsComboboxControlFrame needs special frame creation behavior for its first
3238 : // piece of anonymous content, which means that we can't take the normal
3239 : // ProcessChildren path.
3240 0 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
3241 0 : DebugOnly<nsresult> rv = GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
3242 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
3243 0 : MOZ_ASSERT(newAnonymousItems.Length() == 2);
3244 :
3245 : // Manually create a frame for the special NAC.
3246 0 : MOZ_ASSERT(newAnonymousItems[0].mContent == comboboxFrame->GetDisplayNode());
3247 0 : newAnonymousItems.RemoveElementAt(0);
3248 0 : nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
3249 0 : MOZ_ASSERT(customFrame);
3250 0 : customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
3251 0 : childItems.AddChild(customFrame);
3252 :
3253 : // The other piece of NAC can take the normal path.
3254 0 : FrameConstructionItemList fcItems;
3255 : AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
3256 0 : fcItems);
3257 0 : ConstructFramesFromItemList(aState, fcItems, comboboxFrame, childItems);
3258 :
3259 0 : comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
3260 :
3261 : // Initialize the additional popup child list which contains the
3262 : // dropdown list frame.
3263 0 : nsFrameItems popupItems;
3264 0 : popupItems.AddChild(listFrame);
3265 : comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList,
3266 0 : popupItems);
3267 :
3268 0 : aState.mFrameState = historyState;
3269 0 : if (aState.mFrameState) {
3270 : // Restore frame state for the entire subtree of |comboboxFrame|.
3271 0 : RestoreFrameState(comboboxFrame, aState.mFrameState);
3272 : }
3273 0 : return comboboxFrame;
3274 : }
3275 :
3276 : // Listbox, not combobox
3277 0 : nsContainerFrame* listFrame = NS_NewListControlFrame(mPresShell, styleContext);
3278 :
3279 0 : nsContainerFrame* scrolledFrame = NS_NewSelectsAreaFrame(
3280 0 : mPresShell, styleContext, NS_BLOCK_FLOAT_MGR);
3281 :
3282 : // ******* this code stolen from Initialze ScrollFrame ********
3283 : // please adjust this code to use BuildScrollFrame.
3284 :
3285 0 : InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3286 : aParentFrame, styleContext, false,
3287 0 : aItem.mPendingBinding, aFrameItems);
3288 :
3289 0 : return listFrame;
3290 : }
3291 :
3292 : /**
3293 : * Used to be InitializeScrollFrame but now it's only used for the select tag
3294 : * But the select tag should really be fixed to use GFX scrollbars that can
3295 : * be create with BuildScrollFrame.
3296 : */
3297 : void
3298 0 : nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
3299 : nsContainerFrame* scrollFrame,
3300 : nsContainerFrame* scrolledFrame,
3301 : nsIContent* aContent,
3302 : nsContainerFrame* aParentFrame,
3303 : nsStyleContext* aStyleContext,
3304 : bool aBuildCombobox,
3305 : PendingBinding* aPendingBinding,
3306 : nsFrameItems& aFrameItems)
3307 : {
3308 : // Initialize it
3309 : nsContainerFrame* geometricParent =
3310 0 : aState.GetGeometricParent(aStyleContext->StyleDisplay(), aParentFrame);
3311 :
3312 : // We don't call InitAndRestoreFrame for scrollFrame because we can only
3313 : // restore the frame state after its parts have been created (in particular,
3314 : // the scrollable view). So we have to split Init and Restore.
3315 :
3316 0 : scrollFrame->Init(aContent, geometricParent, nullptr);
3317 :
3318 0 : if (!aBuildCombobox) {
3319 0 : aState.AddChild(scrollFrame, aFrameItems, aContent,
3320 0 : aStyleContext, aParentFrame);
3321 : }
3322 :
3323 : BuildScrollFrame(aState, aContent, aStyleContext, scrolledFrame,
3324 0 : geometricParent, scrollFrame);
3325 :
3326 0 : if (aState.mFrameState) {
3327 : // Restore frame state for the scroll frame
3328 0 : RestoreFrameStateFor(scrollFrame, aState.mFrameState);
3329 : }
3330 :
3331 : // Process children
3332 0 : nsFrameItems childItems;
3333 :
3334 : ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, false,
3335 0 : childItems, false, aPendingBinding);
3336 :
3337 : // Set the scrolled frame's initial child lists
3338 0 : scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
3339 0 : }
3340 :
3341 : nsIFrame*
3342 0 : nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
3343 : FrameConstructionItem& aItem,
3344 : nsContainerFrame* aParentFrame,
3345 : const nsStyleDisplay* aStyleDisplay,
3346 : nsFrameItems& aFrameItems)
3347 : {
3348 0 : nsIContent* const content = aItem.mContent;
3349 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
3350 :
3351 0 : nsContainerFrame* fieldsetFrame = NS_NewFieldSetFrame(mPresShell, styleContext);
3352 :
3353 : // Initialize it
3354 0 : InitAndRestoreFrame(aState, content,
3355 : aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3356 0 : fieldsetFrame);
3357 :
3358 0 : fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3359 :
3360 : // Resolve style and initialize the frame
3361 0 : RefPtr<nsStyleContext> fieldsetContentStyle;
3362 0 : fieldsetContentStyle = mPresShell->StyleSet()->
3363 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent,
3364 0 : styleContext);
3365 :
3366 0 : const nsStyleDisplay* fieldsetContentDisplay = fieldsetContentStyle->StyleDisplay();
3367 0 : bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3368 0 : nsContainerFrame* scrollFrame = nullptr;
3369 0 : if (isScrollable) {
3370 : fieldsetContentStyle =
3371 0 : BeginBuildingScrollFrame(aState, content, fieldsetContentStyle,
3372 : fieldsetFrame, nsCSSAnonBoxes::scrolledContent,
3373 0 : false, scrollFrame);
3374 : }
3375 :
3376 0 : nsContainerFrame* absPosContainer = nullptr;
3377 0 : if (fieldsetFrame->IsAbsPosContainingBlock()) {
3378 0 : absPosContainer = fieldsetFrame;
3379 : }
3380 :
3381 : // Create the inner ::-moz-fieldset-content frame.
3382 : nsContainerFrame* contentFrameTop;
3383 : nsContainerFrame* contentFrame;
3384 0 : auto parent = scrollFrame ? scrollFrame : fieldsetFrame;
3385 0 : switch (fieldsetContentDisplay->mDisplay) {
3386 : case StyleDisplay::Flex:
3387 0 : contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3388 0 : InitAndRestoreFrame(aState, content, parent, contentFrame);
3389 0 : contentFrameTop = contentFrame;
3390 0 : break;
3391 : case StyleDisplay::Grid:
3392 0 : contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3393 0 : InitAndRestoreFrame(aState, content, parent, contentFrame);
3394 0 : contentFrameTop = contentFrame;
3395 0 : break;
3396 : default: {
3397 0 : MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
3398 : "bug in nsRuleNode::ComputeDisplayData?");
3399 :
3400 0 : nsContainerFrame* columnSetFrame = nullptr;
3401 0 : RefPtr<nsStyleContext> innerSC = fieldsetContentStyle;
3402 0 : const nsStyleColumn* columns = fieldsetContentStyle->StyleColumn();
3403 0 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
3404 0 : columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
3405 : columnSetFrame =
3406 0 : NS_NewColumnSetFrame(mPresShell, fieldsetContentStyle,
3407 0 : nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
3408 0 : InitAndRestoreFrame(aState, content, parent, columnSetFrame);
3409 0 : innerSC = mPresShell->StyleSet()->
3410 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
3411 0 : fieldsetContentStyle);
3412 0 : if (absPosContainer) {
3413 0 : absPosContainer = columnSetFrame;
3414 : }
3415 : }
3416 0 : contentFrame = NS_NewBlockFormattingContext(mPresShell, innerSC);
3417 0 : if (columnSetFrame) {
3418 0 : InitAndRestoreFrame(aState, content, columnSetFrame, contentFrame);
3419 0 : SetInitialSingleChild(columnSetFrame, contentFrame);
3420 0 : contentFrameTop = columnSetFrame;
3421 : } else {
3422 0 : InitAndRestoreFrame(aState, content, parent, contentFrame);
3423 0 : contentFrameTop = contentFrame;
3424 : }
3425 0 : break;
3426 : }
3427 : }
3428 :
3429 0 : aState.AddChild(fieldsetFrame, aFrameItems, content, styleContext, aParentFrame);
3430 :
3431 : // Process children
3432 0 : nsFrameConstructorSaveState absoluteSaveState;
3433 0 : nsFrameItems childItems;
3434 :
3435 0 : contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3436 0 : if (absPosContainer) {
3437 0 : aState.PushAbsoluteContainingBlock(contentFrame, absPosContainer, absoluteSaveState);
3438 : }
3439 :
3440 0 : ProcessChildren(aState, content, styleContext, contentFrame, true,
3441 0 : childItems, true, aItem.mPendingBinding);
3442 :
3443 0 : nsFrameItems fieldsetKids;
3444 0 : fieldsetKids.AddChild(scrollFrame ? scrollFrame : contentFrameTop);
3445 :
3446 0 : for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
3447 0 : nsIFrame* child = e.get();
3448 0 : nsContainerFrame* cif = child->GetContentInsertionFrame();
3449 0 : if (cif && cif->IsLegendFrame()) {
3450 : // We want the legend to be the first frame in the fieldset child list.
3451 : // That way the EventStateManager will do the right thing when tabbing
3452 : // from a selection point within the legend (bug 236071), which is
3453 : // used for implementing legend access keys (bug 81481).
3454 : // GetAdjustedParentFrame() below depends on this frame order.
3455 0 : childItems.RemoveFrame(child);
3456 : // Make sure to reparent the legend so it has the fieldset as the parent.
3457 0 : fieldsetKids.InsertFrame(fieldsetFrame, nullptr, child);
3458 0 : if (scrollFrame) {
3459 : StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(
3460 0 : child, contentFrame);
3461 : }
3462 0 : break;
3463 : }
3464 : }
3465 :
3466 0 : if (isScrollable) {
3467 0 : FinishBuildingScrollFrame(scrollFrame, contentFrameTop);
3468 : }
3469 :
3470 : // Set the inner frame's initial child lists
3471 0 : contentFrame->SetInitialChildList(kPrincipalList, childItems);
3472 :
3473 : // Set the outer frame's initial child list
3474 0 : fieldsetFrame->SetInitialChildList(kPrincipalList, fieldsetKids);
3475 :
3476 0 : fieldsetFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
3477 :
3478 : // Our new frame returned is the outer frame, which is the fieldset frame.
3479 0 : return fieldsetFrame;
3480 : }
3481 :
3482 : nsIFrame*
3483 0 : nsCSSFrameConstructor::ConstructDetailsFrame(nsFrameConstructorState& aState,
3484 : FrameConstructionItem& aItem,
3485 : nsContainerFrame* aParentFrame,
3486 : const nsStyleDisplay* aStyleDisplay,
3487 : nsFrameItems& aFrameItems)
3488 : {
3489 0 : if (!aStyleDisplay->IsScrollableOverflow()) {
3490 : return ConstructNonScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3491 : aStyleDisplay, aFrameItems,
3492 0 : NS_NewDetailsFrame);
3493 : }
3494 :
3495 : // Build a scroll frame to wrap details frame if necessary.
3496 : return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3497 : aStyleDisplay, aFrameItems,
3498 0 : NS_NewDetailsFrame);
3499 : }
3500 :
3501 : static nsIFrame*
3502 0 : FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame)
3503 : {
3504 0 : for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3505 0 : NS_ASSERTION(f->IsGeneratedContentFrame(),
3506 : "should not have exited generated content");
3507 0 : nsIAtom* pseudo = f->StyleContext()->GetPseudo();
3508 0 : if (pseudo == nsCSSPseudoElements::before ||
3509 0 : pseudo == nsCSSPseudoElements::after)
3510 0 : return f;
3511 : }
3512 0 : return nullptr;
3513 : }
3514 :
3515 : #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3516 : #define FULL_CTOR_FCDATA(_flags, _func) \
3517 : { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nullptr }, _func, nullptr }
3518 :
3519 : /* static */
3520 : const nsCSSFrameConstructor::FrameConstructionData*
3521 181 : nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame)
3522 : {
3523 181 : if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3524 : nsIFrame *ancestorFrame =
3525 158 : nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
3526 158 : if (ancestorFrame) {
3527 : static const FrameConstructionData sSVGTextData =
3528 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT,
3529 : NS_NewTextFrame);
3530 158 : if (nsSVGUtils::IsInSVGTextSubtree(ancestorFrame)) {
3531 0 : return &sSVGTextData;
3532 : }
3533 : }
3534 158 : return nullptr;
3535 : }
3536 :
3537 : static const FrameConstructionData sTextData =
3538 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
3539 23 : return &sTextData;
3540 : }
3541 :
3542 : void
3543 18 : nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData,
3544 : nsFrameConstructorState& aState,
3545 : nsIContent* aContent,
3546 : nsContainerFrame* aParentFrame,
3547 : nsStyleContext* aStyleContext,
3548 : nsFrameItems& aFrameItems)
3549 : {
3550 18 : NS_PRECONDITION(aData, "Must have frame construction data");
3551 :
3552 18 : nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aStyleContext);
3553 :
3554 18 : InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3555 :
3556 : // We never need to create a view for a text frame.
3557 :
3558 18 : if (newFrame->IsGeneratedContentFrame()) {
3559 12 : nsAutoPtr<nsGenConInitializer> initializer;
3560 : initializer =
3561 : static_cast<nsGenConInitializer*>(
3562 6 : aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
3563 6 : if (initializer) {
3564 0 : if (initializer->mNode->InitTextFrame(initializer->mList,
3565 0 : FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
3566 0 : (this->*(initializer->mDirtyAll))();
3567 : }
3568 0 : initializer->mNode.forget();
3569 : }
3570 : }
3571 :
3572 : // Add the newly constructed frame to the flow
3573 18 : aFrameItems.AddChild(newFrame);
3574 :
3575 18 : if (!aState.mCreatingExtraFrames)
3576 18 : aContent->SetPrimaryFrame(newFrame);
3577 18 : }
3578 :
3579 : /* static */
3580 : const nsCSSFrameConstructor::FrameConstructionData*
3581 4 : nsCSSFrameConstructor::FindDataByInt(int32_t aInt,
3582 : Element* aElement,
3583 : nsStyleContext* aStyleContext,
3584 : const FrameConstructionDataByInt* aDataPtr,
3585 : uint32_t aDataLength)
3586 : {
3587 26 : for (const FrameConstructionDataByInt *curData = aDataPtr,
3588 4 : *endData = aDataPtr + aDataLength;
3589 26 : curData != endData;
3590 : ++curData) {
3591 26 : if (curData->mInt == aInt) {
3592 4 : const FrameConstructionData* data = &curData->mData;
3593 4 : if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3594 0 : return data->mFunc.mDataGetter(aElement, aStyleContext);
3595 : }
3596 :
3597 4 : return data;
3598 : }
3599 : }
3600 :
3601 0 : return nullptr;
3602 : }
3603 :
3604 : /* static */
3605 : const nsCSSFrameConstructor::FrameConstructionData*
3606 462 : nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
3607 : Element* aElement,
3608 : nsStyleContext* aStyleContext,
3609 : const FrameConstructionDataByTag* aDataPtr,
3610 : uint32_t aDataLength)
3611 : {
3612 8094 : for (const FrameConstructionDataByTag *curData = aDataPtr,
3613 462 : *endData = aDataPtr + aDataLength;
3614 8094 : curData != endData;
3615 : ++curData) {
3616 7916 : if (*curData->mTag == aTag) {
3617 284 : const FrameConstructionData* data = &curData->mData;
3618 284 : if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3619 21 : return data->mFunc.mDataGetter(aElement, aStyleContext);
3620 : }
3621 :
3622 263 : return data;
3623 : }
3624 : }
3625 :
3626 178 : return nullptr;
3627 : }
3628 :
3629 : #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nullptr)
3630 : #define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
3631 : #define SIMPLE_INT_CHAIN(_int, _func) \
3632 : { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3633 : #define COMPLEX_INT_CREATE(_int, _func) \
3634 : { _int, FULL_CTOR_FCDATA(0, _func) }
3635 :
3636 : #define SIMPLE_TAG_CREATE(_tag, _func) \
3637 : { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3638 : #define SIMPLE_TAG_CHAIN(_tag, _func) \
3639 : { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3640 : #define COMPLEX_TAG_CREATE(_tag, _func) \
3641 : { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3642 :
3643 : static bool
3644 47 : IsFrameForFieldSet(nsIFrame* aFrame)
3645 : {
3646 47 : nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
3647 94 : if (pseudo == nsCSSAnonBoxes::fieldsetContent ||
3648 90 : pseudo == nsCSSAnonBoxes::scrolledContent ||
3649 43 : pseudo == nsCSSAnonBoxes::columnContent) {
3650 4 : return IsFrameForFieldSet(aFrame->GetParent());
3651 : }
3652 43 : return aFrame->IsFieldSetFrame();
3653 : }
3654 :
3655 : /* static */
3656 : const nsCSSFrameConstructor::FrameConstructionData*
3657 469 : nsCSSFrameConstructor::FindHTMLData(Element* aElement,
3658 : nsIAtom* aTag,
3659 : int32_t aNameSpaceID,
3660 : nsIFrame* aParentFrame,
3661 : nsStyleContext* aStyleContext)
3662 : {
3663 : // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
3664 : // a valid HTML namespace. This check must match the one in
3665 : // ShouldHaveFirstLineStyle.
3666 469 : if (aNameSpaceID != kNameSpaceID_XHTML) {
3667 451 : return nullptr;
3668 : }
3669 :
3670 18 : NS_ASSERTION(!aParentFrame ||
3671 : aParentFrame->StyleContext()->GetPseudo() !=
3672 : nsCSSAnonBoxes::fieldsetContent ||
3673 : aParentFrame->GetParent()->IsFieldSetFrame(),
3674 : "Unexpected parent for fieldset content anon box");
3675 18 : if (aTag == nsGkAtoms::legend &&
3676 0 : (!aParentFrame || !IsFrameForFieldSet(aParentFrame) ||
3677 0 : aStyleContext->StyleDisplay()->IsFloatingStyle() ||
3678 0 : aStyleContext->StyleDisplay()->IsAbsolutelyPositionedStyle())) {
3679 : // <legend> is only special inside fieldset, we only check the frame tree
3680 : // parent because the content tree parent may not be a <fieldset> due to
3681 : // display:contents, Shadow DOM, or XBL. For floated or absolutely
3682 : // positioned legends we want to construct by display type and
3683 : // not do special legend stuff.
3684 0 : return nullptr;
3685 : }
3686 :
3687 : static const FrameConstructionDataByTag sHTMLData[] = {
3688 : SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
3689 : SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
3690 : nsCSSFrameConstructor::FindImgData),
3691 : { &nsGkAtoms::br,
3692 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
3693 : NS_NewBRFrame) },
3694 : SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
3695 : SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
3696 : SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
3697 : COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
3698 : SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
3699 : SIMPLE_TAG_CHAIN(applet, nsCSSFrameConstructor::FindObjectData),
3700 : SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
3701 : COMPLEX_TAG_CREATE(fieldset,
3702 : &nsCSSFrameConstructor::ConstructFieldSetFrame),
3703 : { &nsGkAtoms::legend,
3704 : FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
3705 : NS_NewLegendFrame) },
3706 : SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
3707 : SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
3708 : { &nsGkAtoms::button,
3709 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_ALLOW_BLOCK_STYLES |
3710 : FCDATA_ALLOW_GRID_FLEX_COLUMNSET,
3711 : NS_NewHTMLButtonControlFrame,
3712 : nsCSSAnonBoxes::buttonContent) },
3713 : SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
3714 : SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
3715 : SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
3716 : SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
3717 : SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
3718 : COMPLEX_TAG_CREATE(details, &nsCSSFrameConstructor::ConstructDetailsFrame)
3719 : };
3720 :
3721 18 : return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
3722 36 : ArrayLength(sHTMLData));
3723 : }
3724 :
3725 : /* static */
3726 : const nsCSSFrameConstructor::FrameConstructionData*
3727 0 : nsCSSFrameConstructor::FindImgData(Element* aElement,
3728 : nsStyleContext* aStyleContext)
3729 : {
3730 0 : if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
3731 0 : return nullptr;
3732 : }
3733 :
3734 : static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
3735 0 : return &sImgData;
3736 : }
3737 :
3738 : /* static */
3739 : const nsCSSFrameConstructor::FrameConstructionData*
3740 0 : nsCSSFrameConstructor::FindImgControlData(Element* aElement,
3741 : nsStyleContext* aStyleContext)
3742 : {
3743 0 : if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
3744 0 : return nullptr;
3745 : }
3746 :
3747 : static const FrameConstructionData sImgControlData =
3748 : SIMPLE_FCDATA(NS_NewImageControlFrame);
3749 0 : return &sImgControlData;
3750 : }
3751 :
3752 : /* static */
3753 : const nsCSSFrameConstructor::FrameConstructionData*
3754 4 : nsCSSFrameConstructor::FindInputData(Element* aElement,
3755 : nsStyleContext* aStyleContext)
3756 : {
3757 : static const FrameConstructionDataByInt sInputData[] = {
3758 : SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewGfxCheckboxControlFrame),
3759 : SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewGfxRadioControlFrame),
3760 : SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
3761 : SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
3762 : nsCSSFrameConstructor::FindImgControlData),
3763 : SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame),
3764 : SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame),
3765 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
3766 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame),
3767 : SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame),
3768 : SIMPLE_INT_CREATE(NS_FORM_INPUT_RANGE, NS_NewRangeFrame),
3769 : SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
3770 : { NS_FORM_INPUT_COLOR,
3771 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewColorControlFrame,
3772 : nsCSSAnonBoxes::buttonContent) },
3773 : // TODO: this is temporary until a frame is written: bug 635240.
3774 : SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
3775 : #if defined(MOZ_WIDGET_ANDROID)
3776 : // On Android, date/time input appears as a normal text box.
3777 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame),
3778 : SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame),
3779 : #else
3780 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewDateTimeControlFrame),
3781 : SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewDateTimeControlFrame),
3782 : #endif
3783 : // TODO: this is temporary until a frame is written: bug 888320
3784 : SIMPLE_INT_CREATE(NS_FORM_INPUT_MONTH, NS_NewTextControlFrame),
3785 : // TODO: this is temporary until a frame is written: bug 888320
3786 : SIMPLE_INT_CREATE(NS_FORM_INPUT_WEEK, NS_NewTextControlFrame),
3787 : // TODO: this is temporary until a frame is written: bug 888320
3788 : SIMPLE_INT_CREATE(NS_FORM_INPUT_DATETIME_LOCAL, NS_NewTextControlFrame),
3789 : { NS_FORM_INPUT_SUBMIT,
3790 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3791 : nsCSSAnonBoxes::buttonContent) },
3792 : { NS_FORM_INPUT_RESET,
3793 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3794 : nsCSSAnonBoxes::buttonContent) },
3795 : { NS_FORM_INPUT_BUTTON,
3796 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3797 : nsCSSAnonBoxes::buttonContent) }
3798 : // Keeping hidden inputs out of here on purpose for so they get frames by
3799 : // display (in practice, none).
3800 : };
3801 :
3802 8 : nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
3803 4 : NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
3804 :
3805 4 : auto controlType = control->ControlType();
3806 :
3807 : // Note that Android widgets don't have theming support and thus
3808 : // appearance:none is the same as any other appearance value.
3809 : // So this chunk doesn't apply there:
3810 : #if !defined(MOZ_WIDGET_ANDROID)
3811 : // radio and checkbox inputs with appearance:none should be constructed
3812 : // by display type. (Note that we're not checking that appearance is
3813 : // not (respectively) NS_THEME_RADIO and NS_THEME_CHECKBOX.)
3814 8 : if ((controlType == NS_FORM_INPUT_CHECKBOX ||
3815 4 : controlType == NS_FORM_INPUT_RADIO) &&
3816 0 : aStyleContext->StyleDisplay()->mAppearance == NS_THEME_NONE) {
3817 0 : return nullptr;
3818 : }
3819 : #endif
3820 :
3821 4 : return FindDataByInt(controlType, aElement, aStyleContext,
3822 8 : sInputData, ArrayLength(sInputData));
3823 : }
3824 :
3825 : /* static */
3826 : const nsCSSFrameConstructor::FrameConstructionData*
3827 0 : nsCSSFrameConstructor::FindObjectData(Element* aElement,
3828 : nsStyleContext* aStyleContext)
3829 : {
3830 : // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3831 : // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3832 : // we want to treat those cases as TYPE_NULL
3833 : uint32_t type;
3834 0 : if (aElement->State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
3835 0 : NS_EVENT_STATE_USERDISABLED |
3836 0 : NS_EVENT_STATE_SUPPRESSED)) {
3837 0 : type = nsIObjectLoadingContent::TYPE_NULL;
3838 : } else {
3839 0 : nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement));
3840 0 : NS_ASSERTION(objContent,
3841 : "applet, embed and object must implement "
3842 : "nsIObjectLoadingContent!");
3843 :
3844 0 : objContent->GetDisplayedType(&type);
3845 : }
3846 :
3847 : static const FrameConstructionDataByInt sObjectData[] = {
3848 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
3849 : NS_NewEmptyFrame),
3850 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
3851 : NS_NewObjectFrame),
3852 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
3853 : NS_NewImageFrame),
3854 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
3855 : NS_NewSubDocumentFrame),
3856 : // Fake plugin handlers load as documents
3857 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_FAKE_PLUGIN,
3858 : NS_NewSubDocumentFrame)
3859 : // Nothing for TYPE_NULL so we'll construct frames by display there
3860 : };
3861 :
3862 0 : return FindDataByInt((int32_t)type, aElement, aStyleContext,
3863 0 : sObjectData, ArrayLength(sObjectData));
3864 : }
3865 :
3866 : /* static */
3867 : const nsCSSFrameConstructor::FrameConstructionData*
3868 0 : nsCSSFrameConstructor::FindCanvasData(Element* aElement,
3869 : nsStyleContext* aStyleContext)
3870 : {
3871 : // We want to check whether script is enabled on the document that
3872 : // could be painting to the canvas. That's the owner document of
3873 : // the canvas, except when the owner document is a static document,
3874 : // in which case it's the original document it was cloned from.
3875 0 : nsIDocument* doc = aElement->OwnerDoc();
3876 0 : if (doc->IsStaticDocument()) {
3877 0 : doc = doc->GetOriginalDocument();
3878 : }
3879 0 : if (!doc->IsScriptEnabled()) {
3880 0 : return nullptr;
3881 : }
3882 :
3883 : static const FrameConstructionData sCanvasData =
3884 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
3885 : nsCSSAnonBoxes::htmlCanvasContent);
3886 0 : return &sCanvasData;
3887 : }
3888 :
3889 : void
3890 469 : nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
3891 : nsFrameConstructorState& aState,
3892 : nsContainerFrame* aParentFrame,
3893 : nsFrameItems& aFrameItems)
3894 : {
3895 469 : const FrameConstructionData* data = aItem.mFCData;
3896 469 : NS_ASSERTION(data, "Must have frame construction data");
3897 :
3898 469 : uint32_t bits = data->mBits;
3899 :
3900 469 : NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
3901 : "Should have dealt with this inside the data finder");
3902 :
3903 : // Some sets of bits are not compatible with each other
3904 : #define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3905 : NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
3906 : "Only one of these bits should be set")
3907 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
3908 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
3909 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
3910 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
3911 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
3912 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3913 : FCDATA_DISALLOW_GENERATED_CONTENT);
3914 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
3915 469 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3916 : FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3917 469 : CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
3918 : FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3919 : #undef CHECK_ONLY_ONE_BIT
3920 469 : NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
3921 : ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
3922 : data->mFullConstructor ==
3923 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
3924 : "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
3925 :
3926 : // Don't create a subdocument frame for iframes if we're creating extra frames
3927 469 : if (aState.mCreatingExtraFrames &&
3928 0 : aItem.mContent->IsHTMLElement(nsGkAtoms::iframe))
3929 : {
3930 0 : return;
3931 : }
3932 :
3933 469 : nsIContent* const content = aItem.mContent;
3934 469 : nsIContent* parent = content->GetParent();
3935 :
3936 : // Push display:contents ancestors.
3937 938 : Maybe<AutoDisplayContentsAncestorPusher> adcp;
3938 469 : if (aState.mTreeMatchContext) {
3939 469 : adcp.emplace(*aState.mTreeMatchContext, aState.mPresContext, parent);
3940 : } else {
3941 0 : MOZ_ASSERT(content->IsStyledByServo());
3942 : }
3943 :
3944 : // Get the parent of the content and check if it is a XBL children element.
3945 : // Push the children element as an ancestor here because it does
3946 : // not have a frame and would not otherwise be pushed as an ancestor. It is
3947 : // necessary to do so in order to correctly handle style resolution on
3948 : // descendants. (If !adcp.IsEmpty() then it was already pushed by
3949 : // AutoDisplayContentsAncestorPusher above.)
3950 : TreeMatchContext::AutoAncestorPusher
3951 938 : insertionPointPusher(aState.mTreeMatchContext);
3952 938 : if (adcp.isSome() && adcp->IsEmpty() && parent &&
3953 469 : nsContentUtils::IsContentInsertionPoint(parent)) {
3954 0 : if (aState.mTreeMatchContext->mAncestorFilter.HasFilter()) {
3955 0 : insertionPointPusher.PushAncestorAndStyleScope(parent);
3956 : } else {
3957 0 : insertionPointPusher.PushStyleScope(parent);
3958 : }
3959 : }
3960 :
3961 : // Push the content as a style ancestor now, so we don't have to do
3962 : // it in our various full-constructor functions. In particular,
3963 : // since a number of full-constructor functions don't actually call
3964 : // ProcessChildren in some cases (e.g. for CSS anonymous table boxes
3965 : // or for situations where only anonymouse children are having
3966 : // frames constructed), this is the best place to bottleneck the
3967 : // pushing of the content instead of having to do it in multiple
3968 : // places.
3969 : TreeMatchContext::AutoAncestorPusher
3970 938 : ancestorPusher(aState.mTreeMatchContext);
3971 469 : if (aState.HasAncestorFilter()) {
3972 455 : ancestorPusher.PushAncestorAndStyleScope(content);
3973 : } else {
3974 14 : ancestorPusher.PushStyleScope(content);
3975 : }
3976 :
3977 : nsIFrame* newFrame;
3978 : nsIFrame* primaryFrame;
3979 469 : nsStyleContext* const styleContext = aItem.mStyleContext;
3980 469 : const nsStyleDisplay* display = styleContext->StyleDisplay();
3981 469 : if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
3982 : newFrame =
3983 21 : (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
3984 42 : display, aFrameItems);
3985 21 : MOZ_ASSERT(newFrame, "Full constructor failed");
3986 21 : primaryFrame = newFrame;
3987 : } else {
3988 : newFrame =
3989 448 : (*data->mFunc.mCreationFunc)(mPresShell, styleContext);
3990 :
3991 448 : bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
3992 448 : bool isPopup = aItem.mIsPopup;
3993 448 : NS_ASSERTION(!isPopup ||
3994 : (aState.mPopupItems.containingBlock &&
3995 : aState.mPopupItems.containingBlock->IsPopupSetFrame()),
3996 : "Should have a containing block here!");
3997 :
3998 : nsContainerFrame* geometricParent =
3999 867 : isPopup ? aState.mPopupItems.containingBlock :
4000 419 : (allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame)
4001 448 : : aParentFrame);
4002 :
4003 : // Must init frameToAddToList to null, since it's inout
4004 448 : nsIFrame* frameToAddToList = nullptr;
4005 596 : if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
4006 148 : display->IsScrollableOverflow()) {
4007 8 : nsContainerFrame* scrollframe = nullptr;
4008 : BuildScrollFrame(aState, content, styleContext, newFrame,
4009 8 : geometricParent, scrollframe);
4010 8 : frameToAddToList = scrollframe;
4011 : } else {
4012 440 : InitAndRestoreFrame(aState, content, geometricParent, newFrame);
4013 440 : frameToAddToList = newFrame;
4014 : }
4015 :
4016 : // Use frameToAddToList as the primary frame. In the non-scrollframe case
4017 : // they're equal, but in the scrollframe case newFrame is the scrolled
4018 : // frame, while frameToAddToList is the scrollframe (and should be the
4019 : // primary frame).
4020 448 : primaryFrame = frameToAddToList;
4021 :
4022 : // If we need to create a block formatting context to wrap our
4023 : // kids, do it now.
4024 448 : const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display;
4025 448 : nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
4026 448 : nsIFrame* maybeAbsoluteContainingBlock = newFrame;
4027 448 : nsIFrame* possiblyLeafFrame = newFrame;
4028 448 : if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
4029 4 : RefPtr<nsStyleContext> outerSC = mPresShell->StyleSet()->
4030 6 : ResolveInheritingAnonymousBoxStyle(*data->mAnonBoxPseudo,
4031 4 : styleContext);
4032 : #ifdef DEBUG
4033 2 : nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
4034 2 : MOZ_ASSERT(containerFrame);
4035 : #endif
4036 2 : nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
4037 : nsContainerFrame* outerFrame;
4038 : nsContainerFrame* innerFrame;
4039 2 : if (bits & FCDATA_ALLOW_GRID_FLEX_COLUMNSET) {
4040 0 : switch (display->mDisplay) {
4041 : case StyleDisplay::Flex:
4042 : case StyleDisplay::InlineFlex:
4043 0 : outerFrame = NS_NewFlexContainerFrame(mPresShell, outerSC);
4044 0 : InitAndRestoreFrame(aState, content, container, outerFrame);
4045 0 : innerFrame = outerFrame;
4046 0 : break;
4047 : case StyleDisplay::Grid:
4048 : case StyleDisplay::InlineGrid:
4049 0 : outerFrame = NS_NewGridContainerFrame(mPresShell, outerSC);
4050 0 : InitAndRestoreFrame(aState, content, container, outerFrame);
4051 0 : innerFrame = outerFrame;
4052 0 : break;
4053 : default: {
4054 0 : nsContainerFrame* columnSetFrame = nullptr;
4055 0 : RefPtr<nsStyleContext> innerSC = outerSC;
4056 0 : const nsStyleColumn* columns = outerSC->StyleColumn();
4057 0 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
4058 0 : columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
4059 : columnSetFrame =
4060 0 : NS_NewColumnSetFrame(mPresShell, outerSC,
4061 0 : nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
4062 0 : InitAndRestoreFrame(aState, content, container, columnSetFrame);
4063 0 : innerSC = mPresShell->StyleSet()->
4064 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
4065 0 : outerSC);
4066 : }
4067 0 : innerFrame = NS_NewBlockFormattingContext(mPresShell, innerSC);
4068 0 : if (columnSetFrame) {
4069 0 : InitAndRestoreFrame(aState, content, columnSetFrame, innerFrame);
4070 0 : SetInitialSingleChild(columnSetFrame, innerFrame);
4071 0 : outerFrame = columnSetFrame;
4072 : } else {
4073 0 : InitAndRestoreFrame(aState, content, container, innerFrame);
4074 0 : outerFrame = innerFrame;
4075 : }
4076 0 : break;
4077 : }
4078 : }
4079 : } else {
4080 2 : innerFrame = NS_NewBlockFormattingContext(mPresShell, outerSC);
4081 2 : InitAndRestoreFrame(aState, content, container, innerFrame);
4082 2 : outerFrame = innerFrame;
4083 : }
4084 :
4085 2 : SetInitialSingleChild(container, outerFrame);
4086 :
4087 2 : container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4088 :
4089 : // Now figure out whether newFrame or outerFrame should be the
4090 : // absolute container.
4091 2 : auto outerDisplay = outerSC->StyleDisplay();
4092 2 : if (outerDisplay->IsAbsPosContainingBlock(outerFrame)) {
4093 2 : maybeAbsoluteContainingBlockDisplay = outerDisplay;
4094 2 : maybeAbsoluteContainingBlock = outerFrame;
4095 2 : maybeAbsoluteContainingBlockStyleFrame = outerFrame;
4096 2 : innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
4097 : }
4098 :
4099 : // Our kids should go into the innerFrame.
4100 2 : newFrame = innerFrame;
4101 : }
4102 :
4103 448 : aState.AddChild(frameToAddToList, aFrameItems, content, styleContext,
4104 448 : aParentFrame, allowOutOfFlow, allowOutOfFlow, isPopup);
4105 :
4106 448 : nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
4107 448 : if (newFrameAsContainer) {
4108 : #ifdef MOZ_XUL
4109 : // Icky XUL stuff, sadly
4110 :
4111 283 : if (aItem.mIsRootPopupgroup) {
4112 1 : NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) &&
4113 : nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
4114 : newFrame,
4115 : "Unexpected PopupSetFrame");
4116 1 : aState.mPopupItems.containingBlock = newFrameAsContainer;
4117 1 : aState.mHavePendingPopupgroup = false;
4118 : }
4119 : #endif /* MOZ_XUL */
4120 :
4121 : // Process the child content if requested
4122 283 : nsFrameItems childItems;
4123 566 : nsFrameConstructorSaveState absoluteSaveState;
4124 :
4125 283 : if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
4126 0 : aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
4127 283 : } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
4128 111 : maybeAbsoluteContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
4129 : // This check is identical to nsStyleDisplay::IsAbsPosContainingBlock
4130 : // except without the assertion that the style display and frame match.
4131 : // When constructing scroll frames we intentionally use the style
4132 : // display for the outer, but make the inner the containing block.
4133 333 : if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() ||
4134 214 : maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() ||
4135 103 : maybeAbsoluteContainingBlockDisplay->IsFixedPosContainingBlock(
4136 121 : maybeAbsoluteContainingBlockStyleFrame)) &&
4137 10 : !nsSVGUtils::IsInSVGTextSubtree(maybeAbsoluteContainingBlockStyleFrame)) {
4138 : nsContainerFrame* cf = static_cast<nsContainerFrame*>(
4139 10 : maybeAbsoluteContainingBlock);
4140 10 : aState.PushAbsoluteContainingBlock(cf, cf, absoluteSaveState);
4141 : }
4142 : }
4143 :
4144 283 : if (!aItem.mAnonChildren.IsEmpty()) {
4145 0 : NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS),
4146 : "We should not have both anonymous and non-anonymous "
4147 : "children in a given FrameConstructorItem");
4148 0 : AddFCItemsForAnonymousContent(aState, newFrameAsContainer, aItem.mAnonChildren,
4149 0 : aItem.mChildItems);
4150 0 : bits |= FCDATA_USE_CHILD_ITEMS;
4151 : }
4152 :
4153 283 : if (bits & FCDATA_USE_CHILD_ITEMS) {
4154 0 : nsFrameConstructorSaveState floatSaveState;
4155 :
4156 0 : if (ShouldSuppressFloatingOfDescendants(newFrame)) {
4157 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
4158 0 : } else if (newFrame->IsFloatContainingBlock()) {
4159 0 : aState.PushFloatContainingBlock(newFrameAsContainer, floatSaveState);
4160 : }
4161 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, newFrameAsContainer,
4162 0 : childItems);
4163 : } else {
4164 : // Process the child frames.
4165 849 : ProcessChildren(aState, content, styleContext, newFrameAsContainer,
4166 283 : !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
4167 : childItems,
4168 283 : (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
4169 283 : aItem.mPendingBinding, possiblyLeafFrame);
4170 : }
4171 :
4172 283 : if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) {
4173 0 : nsFrameItems newItems;
4174 0 : nsFrameItems currentBlockItems;
4175 : nsIFrame* f;
4176 0 : while ((f = childItems.FirstChild()) != nullptr) {
4177 0 : bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
4178 0 : if (!wrapFrame) {
4179 : FlushAccumulatedBlock(aState, content, newFrameAsContainer,
4180 0 : currentBlockItems, newItems);
4181 : }
4182 :
4183 0 : childItems.RemoveFrame(f);
4184 0 : if (wrapFrame) {
4185 0 : currentBlockItems.AddChild(f);
4186 : } else {
4187 0 : newItems.AddChild(f);
4188 : }
4189 : }
4190 : FlushAccumulatedBlock(aState, content, newFrameAsContainer,
4191 0 : currentBlockItems, newItems);
4192 :
4193 0 : if (childItems.NotEmpty()) {
4194 : // an error must have occurred, delete unprocessed frames
4195 0 : childItems.DestroyFrames();
4196 : }
4197 :
4198 0 : childItems = newItems;
4199 : }
4200 :
4201 : // Set the frame's initial child list
4202 : // Note that MathML depends on this being called even if
4203 : // childItems is empty!
4204 283 : newFrameAsContainer->SetInitialChildList(kPrincipalList, childItems);
4205 : }
4206 : }
4207 :
4208 : #ifdef MOZ_XUL
4209 : // More icky XUL stuff
4210 840 : if (aItem.mNameSpaceID == kNameSpaceID_XUL &&
4211 644 : (aItem.mTag == nsGkAtoms::treechildren || // trees always need titletips
4212 623 : content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext) ||
4213 301 : content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltip))) {
4214 49 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
4215 49 : if (rootBox) {
4216 49 : rootBox->AddTooltipSupport(content);
4217 : }
4218 : }
4219 : #endif
4220 :
4221 469 : NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
4222 : ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
4223 : "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
4224 :
4225 469 : if (aItem.mIsAnonymousContentCreatorContent) {
4226 39 : primaryFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
4227 : }
4228 :
4229 : // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
4230 : // generated content that doesn't have one yet. Note that we have to examine
4231 : // the frame bit, because by this point mIsGeneratedContent has been cleared
4232 : // on aItem.
4233 938 : if ((!aState.mCreatingExtraFrames ||
4234 0 : (primaryFrame->HasAnyStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT |
4235 0 : NS_FRAME_GENERATED_CONTENT) &&
4236 938 : !aItem.mContent->GetPrimaryFrame())) &&
4237 469 : !(bits & FCDATA_SKIP_FRAMESET)) {
4238 469 : aItem.mContent->SetPrimaryFrame(primaryFrame);
4239 469 : ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
4240 : }
4241 : }
4242 :
4243 : static void
4244 8 : SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet)
4245 : {
4246 : #ifdef DEBUG
4247 : // Make sure that the node passed to us doesn't have any XBL children
4248 : {
4249 16 : FlattenedChildIterator iter(aNode);
4250 8 : NS_ASSERTION(!iter.XBLInvolved() || !iter.GetNextChild(),
4251 : "The node should not have any XBL children");
4252 : }
4253 : #endif
4254 :
4255 : // Set the flag on the node itself
4256 8 : aNode->SetFlags(aFlagsToSet);
4257 :
4258 : // Set the flag on all of its children recursively
4259 : uint32_t count;
4260 8 : nsIContent * const *children = aNode->GetChildArray(&count);
4261 :
4262 12 : for (uint32_t index = 0; index < count; ++index) {
4263 4 : SetFlagsOnSubtree(children[index], aFlagsToSet);
4264 : }
4265 8 : }
4266 :
4267 : /**
4268 : * This function takes a tree of nsIAnonymousContentCreator::ContentInfo
4269 : * objects where the nsIContent nodes have just been created, and appends the
4270 : * nsIContent children in the tree to their parent. The leaf nsIContent objects
4271 : * are appended first to minimize the number of notifications that are sent
4272 : * out (i.e. by appending as many descendants as posible while their parent is
4273 : * not yet in the document tree).
4274 : *
4275 : * This function is used simply as a convenience so that implementations of
4276 : * nsIAnonymousContentCreator::CreateAnonymousContent don't all have to have
4277 : * their own code to connect the elements that they create.
4278 : */
4279 : static void
4280 62 : ConnectAnonymousTreeDescendants(nsIContent* aParent,
4281 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
4282 : {
4283 62 : uint32_t count = aContent.Length();
4284 62 : for (uint32_t i=0; i < count; i++) {
4285 0 : nsIContent* content = aContent[i].mContent;
4286 0 : NS_ASSERTION(content, "null anonymous content?");
4287 :
4288 0 : ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
4289 :
4290 0 : aParent->AppendChildTo(content, false);
4291 : }
4292 62 : }
4293 :
4294 : static void
4295 16 : SetNativeAnonymousBitOnDescendants(nsIContent* aRoot)
4296 : {
4297 40 : for (nsIContent* curr = aRoot; curr; curr = curr->GetNextNode(aRoot)) {
4298 24 : curr->SetFlags(NODE_IS_NATIVE_ANONYMOUS);
4299 : }
4300 16 : }
4301 :
4302 : nsresult
4303 394 : nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
4304 : nsIFrame* aParentFrame,
4305 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
4306 : {
4307 394 : nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
4308 394 : if (!creator)
4309 300 : return NS_OK;
4310 :
4311 94 : nsresult rv = creator->CreateAnonymousContent(aContent);
4312 94 : if (NS_FAILED(rv)) {
4313 : // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
4314 0 : return rv;
4315 : }
4316 :
4317 94 : uint32_t count = aContent.Length();
4318 156 : for (uint32_t i=0; i < count; i++) {
4319 : // get our child's content and set its parent to our content
4320 62 : nsIContent* content = aContent[i].mContent;
4321 62 : NS_ASSERTION(content, "null anonymous content?");
4322 :
4323 62 : ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
4324 :
4325 62 : LayoutFrameType parentFrameType = aParentFrame->Type();
4326 62 : if (parentFrameType == LayoutFrameType::SVGUse) {
4327 : // least-surprise CSS binding until we do the SVG specified
4328 : // cascading rules for <svg:use> - bug 265894
4329 23 : content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
4330 : } else {
4331 39 : content->SetIsNativeAnonymousRoot();
4332 : // Don't mark descendants of the custom content container
4333 : // as native anonymous. When canvas custom content is initially
4334 : // created and appended to the custom content container, in
4335 : // nsIDocument::InsertAnonymousContent, it is not considered native
4336 : // anonymous content. But if we end up reframing the root element,
4337 : // we will re-create the nsCanvasFrame, and we would end up in here,
4338 : // marking it as NAC. Existing uses of canvas custom content would
4339 : // break if it becomes NAC (since each element starts inheriting
4340 : // styles from its closest non-NAC ancestor, rather than from its
4341 : // parent).
4342 62 : if (!(parentFrameType == LayoutFrameType::Canvas &&
4343 : content == static_cast<nsCanvasFrame*>(aParentFrame)
4344 23 : ->GetCustomContentContainer())) {
4345 16 : SetNativeAnonymousBitOnDescendants(content);
4346 : }
4347 : }
4348 :
4349 62 : bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
4350 :
4351 : // If the parent is in a shadow tree, make sure we don't
4352 : // bind with a document because shadow roots and its descendants
4353 : // are not in document.
4354 : nsIDocument* bindDocument =
4355 62 : aParent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
4356 62 : rv = content->BindToTree(bindDocument, aParent, aParent, true);
4357 : // If the anonymous content creator requested that the content should be
4358 : // editable, honor its request.
4359 : // We need to set the flag on the whole subtree, because existing
4360 : // children's flags have already been set as part of the BindToTree operation.
4361 62 : if (anonContentIsEditable) {
4362 4 : NS_ASSERTION(aParentFrame->IsTextInputFrame(),
4363 : "We only expect this for anonymous content under a text control frame");
4364 4 : SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
4365 : }
4366 62 : if (NS_FAILED(rv)) {
4367 0 : content->UnbindFromTree();
4368 0 : return rv;
4369 : }
4370 : }
4371 :
4372 94 : if (ServoStyleSet* styleSet = mPresShell->StyleSet()->GetAsServo()) {
4373 : // Eagerly compute styles for the anonymous content tree.
4374 0 : for (auto& info : aContent) {
4375 0 : if (info.mContent->IsElement()) {
4376 0 : styleSet->StyleNewSubtree(info.mContent->AsElement());
4377 : }
4378 : }
4379 : }
4380 :
4381 94 : return NS_OK;
4382 : }
4383 :
4384 : static
4385 43 : bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
4386 : {
4387 86 : return (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
4388 : #ifdef MOZ_XUL
4389 86 : aDisplay->mDisplay == StyleDisplay::MozInlineGrid ||
4390 86 : aDisplay->mDisplay == StyleDisplay::MozInlineStack ||
4391 : #endif
4392 43 : aDisplay->mDisplay == StyleDisplay::MozBox
4393 : #ifdef MOZ_XUL
4394 70 : || aDisplay->mDisplay == StyleDisplay::MozGrid ||
4395 70 : aDisplay->mDisplay == StyleDisplay::MozStack ||
4396 70 : aDisplay->mDisplay == StyleDisplay::MozGridGroup ||
4397 70 : aDisplay->mDisplay == StyleDisplay::MozGridLine ||
4398 70 : aDisplay->mDisplay == StyleDisplay::MozDeck ||
4399 113 : aDisplay->mDisplay == StyleDisplay::MozPopup ||
4400 35 : aDisplay->mDisplay == StyleDisplay::MozGroupbox
4401 : #endif
4402 43 : );
4403 : }
4404 :
4405 :
4406 : // XUL frames are not allowed to be out of flow.
4407 : #define SIMPLE_XUL_FCDATA(_func) \
4408 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, \
4409 : _func)
4410 : #define SCROLLABLE_XUL_FCDATA(_func) \
4411 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
4412 : FCDATA_MAY_NEED_SCROLLFRAME, _func)
4413 : // .. but we allow some XUL frames to be _containers_ for out-of-flow content
4414 : // (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
4415 : #define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) \
4416 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4417 : FCDATA_MAY_NEED_SCROLLFRAME, _func)
4418 :
4419 : #define SIMPLE_XUL_CREATE(_tag, _func) \
4420 : { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
4421 : #define SCROLLABLE_XUL_CREATE(_tag, _func) \
4422 : { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
4423 : #define SIMPLE_XUL_DISPLAY_CREATE(_display, _func) \
4424 : FCDATA_FOR_DISPLAY(_display, SIMPLE_XUL_FCDATA(_func))
4425 : #define SCROLLABLE_XUL_DISPLAY_CREATE(_display, _func) \
4426 : FCDATA_FOR_DISPLAY(_display, SCROLLABLE_XUL_FCDATA(_func))
4427 : #define SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(_display, _func) \
4428 : FCDATA_FOR_DISPLAY(_display, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func))
4429 :
4430 : static
4431 0 : nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
4432 : nsStyleContext* aStyleContext)
4433 : {
4434 0 : nsCOMPtr<nsBoxLayout> layout;
4435 0 : NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
4436 0 : return NS_NewBoxFrame(aPresShell, aStyleContext, false, layout);
4437 : }
4438 :
4439 : /* static */
4440 : const nsCSSFrameConstructor::FrameConstructionData*
4441 463 : nsCSSFrameConstructor::FindXULTagData(Element* aElement,
4442 : nsIAtom* aTag,
4443 : int32_t aNameSpaceID,
4444 : nsStyleContext* aStyleContext)
4445 : {
4446 463 : if (aNameSpaceID != kNameSpaceID_XUL) {
4447 141 : return nullptr;
4448 : }
4449 :
4450 : static const FrameConstructionDataByTag sXULTagData[] = {
4451 : #ifdef MOZ_XUL
4452 : SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
4453 : SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
4454 : SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
4455 : SCROLLABLE_XUL_CREATE(autorepeatbutton, NS_NewAutoRepeatBoxFrame),
4456 : SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
4457 : SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
4458 : SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
4459 : SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
4460 : SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
4461 : SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
4462 : SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
4463 : SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
4464 : SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
4465 : SIMPLE_TAG_CHAIN(description, nsCSSFrameConstructor::FindXULDescriptionData),
4466 : SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
4467 : SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
4468 : SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
4469 : #ifdef XP_MACOSX
4470 : SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
4471 : #else
4472 : SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
4473 : #endif /* XP_MACOSX */
4474 : SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData),
4475 : SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
4476 : SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
4477 : SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame),
4478 : SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame),
4479 : SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame),
4480 : SIMPLE_TAG_CHAIN(listboxbody,
4481 : nsCSSFrameConstructor::FindXULListBoxBodyData),
4482 : SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData),
4483 : #endif /* MOZ_XUL */
4484 : SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
4485 : SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
4486 : SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
4487 : };
4488 :
4489 322 : return FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
4490 644 : ArrayLength(sXULTagData));
4491 : }
4492 :
4493 : #ifdef MOZ_XUL
4494 : /* static */
4495 : const nsCSSFrameConstructor::FrameConstructionData*
4496 1 : nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
4497 : nsStyleContext* /* unused */)
4498 : {
4499 1 : if (!aElement->IsRootOfNativeAnonymousSubtree()) {
4500 0 : return nullptr;
4501 : }
4502 :
4503 : static const FrameConstructionData sPopupSetData =
4504 : SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
4505 1 : return &sPopupSetData;
4506 : }
4507 :
4508 : /* static */
4509 : const nsCSSFrameConstructor::FrameConstructionData
4510 : nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
4511 :
4512 : /* static */
4513 : const nsCSSFrameConstructor::FrameConstructionData*
4514 16 : nsCSSFrameConstructor::FindXULLabelData(Element* aElement,
4515 : nsStyleContext* /* unused */)
4516 : {
4517 16 : if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4518 11 : return &sXULTextBoxData;
4519 : }
4520 :
4521 : static const FrameConstructionData sLabelData =
4522 : SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
4523 5 : return &sLabelData;
4524 : }
4525 :
4526 : static nsIFrame*
4527 0 : NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, nsStyleContext *aContext)
4528 : {
4529 : // XXXbz do we really need to set up the block formatting context root? If the
4530 : // parent is not a block we'll get it anyway, and if it is, do we want it?
4531 0 : return NS_NewBlockFormattingContext(aPresShell, aContext);
4532 : }
4533 :
4534 : /* static */
4535 : const nsCSSFrameConstructor::FrameConstructionData*
4536 0 : nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement,
4537 : nsStyleContext* /* unused */)
4538 : {
4539 0 : if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4540 0 : return &sXULTextBoxData;
4541 : }
4542 :
4543 : static const FrameConstructionData sDescriptionData =
4544 : SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame);
4545 0 : return &sDescriptionData;
4546 : }
4547 :
4548 : #ifdef XP_MACOSX
4549 : /* static */
4550 : const nsCSSFrameConstructor::FrameConstructionData*
4551 : nsCSSFrameConstructor::FindXULMenubarData(Element* aElement,
4552 : nsStyleContext* aStyleContext)
4553 : {
4554 : nsCOMPtr<nsIDocShell> treeItem =
4555 : aStyleContext->PresContext()->GetDocShell();
4556 : if (treeItem && nsIDocShellTreeItem::typeChrome == treeItem->ItemType()) {
4557 : nsCOMPtr<nsIDocShellTreeItem> parent;
4558 : treeItem->GetParent(getter_AddRefs(parent));
4559 : if (!parent) {
4560 : // This is the root. Suppress the menubar, since on Mac
4561 : // window menus are not attached to the window.
4562 : static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4563 : return &sSuppressData;
4564 : }
4565 : }
4566 :
4567 : static const FrameConstructionData sMenubarData =
4568 : SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
4569 : return &sMenubarData;
4570 : }
4571 : #endif /* XP_MACOSX */
4572 :
4573 : /* static */
4574 : const nsCSSFrameConstructor::FrameConstructionData*
4575 0 : nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
4576 : nsStyleContext* aStyleContext)
4577 : {
4578 0 : if (aStyleContext->StyleDisplay()->mDisplay !=
4579 : StyleDisplay::MozGridGroup) {
4580 0 : return nullptr;
4581 : }
4582 :
4583 : static const FrameConstructionData sListBoxBodyData =
4584 : SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame);
4585 0 : return &sListBoxBodyData;
4586 : }
4587 :
4588 : /* static */
4589 : const nsCSSFrameConstructor::FrameConstructionData*
4590 0 : nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
4591 : nsStyleContext* aStyleContext)
4592 : {
4593 0 : if (aStyleContext->StyleDisplay()->mDisplay != StyleDisplay::MozGridLine) {
4594 0 : return nullptr;
4595 : }
4596 :
4597 : static const FrameConstructionData sListItemData =
4598 : SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame);
4599 0 : return &sListItemData;
4600 : }
4601 :
4602 : #endif /* MOZ_XUL */
4603 :
4604 : /* static */
4605 : const nsCSSFrameConstructor::FrameConstructionData*
4606 184 : nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
4607 : Element* aElement,
4608 : nsStyleContext* aStyleContext)
4609 : {
4610 : static const FrameConstructionDataByDisplay sXULDisplayData[] = {
4611 : SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozBox,
4612 : NS_NewBoxFrame),
4613 : SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineBox,
4614 : NS_NewBoxFrame),
4615 : #ifdef MOZ_XUL
4616 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGrid, NS_NewGridBoxFrame),
4617 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineGrid, NS_NewGridBoxFrame),
4618 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridGroup,
4619 : NS_NewGridRowGroupFrame),
4620 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridLine,
4621 : NS_NewGridRowLeafFrame),
4622 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozStack, NS_NewStackFrame),
4623 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineStack, NS_NewStackFrame),
4624 : SIMPLE_XUL_DISPLAY_CREATE(StyleDisplay::MozDeck, NS_NewDeckFrame),
4625 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGroupbox, NS_NewGroupBoxFrame),
4626 : FCDATA_FOR_DISPLAY(StyleDisplay::MozPopup,
4627 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
4628 : FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame))
4629 : #endif /* MOZ_XUL */
4630 : };
4631 :
4632 184 : if (aDisplay->mDisplay < StyleDisplay::MozBox) {
4633 20 : return nullptr;
4634 : }
4635 :
4636 164 : MOZ_ASSERT(aDisplay->mDisplay <= StyleDisplay::MozPopup,
4637 : "Someone added a new display value?");
4638 :
4639 : const FrameConstructionDataByDisplay& data =
4640 164 : sXULDisplayData[size_t(aDisplay->mDisplay) - size_t(StyleDisplay::MozBox)];
4641 164 : MOZ_ASSERT(aDisplay->mDisplay == data.mDisplay,
4642 : "Did someone mess with the order?");
4643 :
4644 164 : return &data.mData;
4645 : }
4646 :
4647 : already_AddRefed<nsStyleContext>
4648 43 : nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
4649 : nsIContent* aContent,
4650 : nsStyleContext* aContentStyle,
4651 : nsContainerFrame* aParentFrame,
4652 : nsIAtom* aScrolledPseudo,
4653 : bool aIsRoot,
4654 : nsContainerFrame*& aNewFrame)
4655 : {
4656 43 : nsContainerFrame* gfxScrollFrame = aNewFrame;
4657 :
4658 43 : nsFrameItems anonymousItems;
4659 :
4660 86 : RefPtr<nsStyleContext> contentStyle = aContentStyle;
4661 :
4662 43 : if (!gfxScrollFrame) {
4663 : // Build a XULScrollFrame when the child is a box, otherwise an
4664 : // HTMLScrollFrame
4665 : // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4666 : // I wonder whether we can eliminate that somehow.
4667 43 : const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay();
4668 43 : if (IsXULDisplayType(displayStyle)) {
4669 8 : gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot,
4670 16 : displayStyle->mDisplay == StyleDisplay::MozStack ||
4671 16 : displayStyle->mDisplay == StyleDisplay::MozInlineStack);
4672 : } else {
4673 35 : gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
4674 : }
4675 :
4676 43 : InitAndRestoreFrame(aState, aContent, aParentFrame, gfxScrollFrame);
4677 : }
4678 :
4679 : // if there are any anonymous children for the scroll frame, create
4680 : // frames for them.
4681 : //
4682 : // We can't take the normal ProcessChildren path, because the NAC needs to
4683 : // be parented to the scrollframe, and everything else needs to be parented
4684 : // to the scrolledframe.
4685 86 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4686 86 : DebugOnly<nsresult> rv = GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC);
4687 43 : MOZ_ASSERT(NS_SUCCEEDED(rv));
4688 43 : if (scrollNAC.Length() > 0) {
4689 4 : TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
4690 2 : if (aState.HasAncestorFilter()) {
4691 0 : ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
4692 : } else {
4693 2 : ancestorPusher.PushStyleScope(aContent->AsElement());
4694 : }
4695 :
4696 4 : FrameConstructionItemList items;
4697 2 : AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
4698 2 : ConstructFramesFromItemList(aState, items, gfxScrollFrame, anonymousItems);
4699 : }
4700 :
4701 43 : aNewFrame = gfxScrollFrame;
4702 43 : gfxScrollFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4703 :
4704 : // we used the style that was passed in. So resolve another one.
4705 43 : StyleSetHandle styleSet = mPresShell->StyleSet();
4706 : RefPtr<nsStyleContext> scrolledChildStyle =
4707 86 : styleSet->ResolveInheritingAnonymousBoxStyle(aScrolledPseudo, contentStyle);
4708 :
4709 43 : if (gfxScrollFrame) {
4710 43 : gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems);
4711 : }
4712 :
4713 86 : return scrolledChildStyle.forget();
4714 : }
4715 :
4716 : void
4717 43 : nsCSSFrameConstructor::FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
4718 : nsIFrame* aScrolledFrame)
4719 : {
4720 43 : nsFrameList scrolled(aScrolledFrame, aScrolledFrame);
4721 43 : aScrollFrame->AppendFrames(kPrincipalList, scrolled);
4722 43 : }
4723 :
4724 : /**
4725 : * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
4726 : *
4727 : * ------- for gfx scrollbars ------
4728 : *
4729 : *
4730 : * ScrollFrame
4731 : * ^
4732 : * |
4733 : * Frame (scrolled frame you passed in)
4734 : *
4735 : *
4736 : *-----------------------------------
4737 : * LEGEND:
4738 : *
4739 : * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
4740 : *
4741 : * @param aContent the content node of the child to wrap.
4742 : * @param aScrolledFrame The frame of the content to wrap. This should not be
4743 : * Initialized. This method will initialize it with a scrolled pseudo
4744 : * and no nsIContent. The content will be attached to the scrollframe
4745 : * returned.
4746 : * @param aContentStyle the style context that has already been resolved for the content being passed in.
4747 : *
4748 : * @param aParentFrame The parent to attach the scroll frame to
4749 : *
4750 : * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
4751 : * scrolled frame you passed in. (returned)
4752 : * If this is not null, we'll just use it
4753 : * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
4754 : */
4755 : void
4756 8 : nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
4757 : nsIContent* aContent,
4758 : nsStyleContext* aContentStyle,
4759 : nsIFrame* aScrolledFrame,
4760 : nsContainerFrame* aParentFrame,
4761 : nsContainerFrame*& aNewFrame)
4762 : {
4763 : RefPtr<nsStyleContext> scrolledContentStyle =
4764 16 : BeginBuildingScrollFrame(aState, aContent, aContentStyle, aParentFrame,
4765 : nsCSSAnonBoxes::scrolledContent,
4766 16 : false, aNewFrame);
4767 :
4768 8 : aScrolledFrame->SetStyleContextWithoutNotification(scrolledContentStyle);
4769 8 : InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4770 :
4771 8 : FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
4772 8 : }
4773 :
4774 : const nsCSSFrameConstructor::FrameConstructionData*
4775 20 : nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
4776 : Element* aElement,
4777 : nsStyleContext* aStyleContext)
4778 : {
4779 : static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)),
4780 : "Check eParentTypeCount should not overflow");
4781 :
4782 : // The style system ensures that floated and positioned frames are
4783 : // block-level.
4784 20 : NS_ASSERTION(!(aDisplay->IsFloatingStyle() ||
4785 : aDisplay->IsAbsolutelyPositionedStyle()) ||
4786 : aDisplay->IsBlockOutsideStyle() ||
4787 : aDisplay->mDisplay == StyleDisplay::Contents,
4788 : "Style system did not apply CSS2.1 section 9.7 fixups");
4789 :
4790 : // If this is "body", try propagating its scroll style to the viewport
4791 : // Note that we need to do this even if the body is NOT scrollable;
4792 : // it might have dynamically changed from scrollable to not scrollable,
4793 : // and that might need to be propagated.
4794 : // XXXbz is this the right place to do this? If this code moves,
4795 : // make this function static.
4796 20 : bool propagatedScrollToViewport = false;
4797 20 : if (aElement->IsHTMLElement(nsGkAtoms::body)) {
4798 2 : if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4799 2 : propagatedScrollToViewport =
4800 2 : presContext->UpdateViewportScrollbarStylesOverride() == aElement;
4801 : }
4802 : }
4803 :
4804 20 : NS_ASSERTION(!propagatedScrollToViewport ||
4805 : !mPresShell->GetPresContext()->IsPaginated(),
4806 : "Shouldn't propagate scroll in paginated contexts");
4807 :
4808 20 : if (aDisplay->IsBlockInsideStyle()) {
4809 : // If the frame is a block-level frame and is scrollable, then wrap it in a
4810 : // scroll frame. Except we don't want to do that for paginated contexts for
4811 : // frames that are block-outside and aren't frames for native anonymous stuff.
4812 : // XXX Ignore tables for the time being (except caption)
4813 : const uint32_t kCaptionCtorFlags =
4814 20 : FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable);
4815 20 : bool caption = aDisplay->mDisplay == StyleDisplay::TableCaption;
4816 20 : bool suppressScrollFrame = false;
4817 32 : bool needScrollFrame = aDisplay->IsScrollableOverflow() &&
4818 32 : !propagatedScrollToViewport;
4819 20 : if (needScrollFrame) {
4820 24 : suppressScrollFrame = mPresShell->GetPresContext()->IsPaginated() &&
4821 12 : aDisplay->IsBlockOutsideStyle() &&
4822 0 : !aElement->IsInNativeAnonymousSubtree();
4823 12 : if (!suppressScrollFrame) {
4824 : static const FrameConstructionData sScrollableBlockData[2] =
4825 : { FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock),
4826 : FULL_CTOR_FCDATA(kCaptionCtorFlags,
4827 : &nsCSSFrameConstructor::ConstructScrollableBlock) };
4828 12 : return &sScrollableBlockData[caption];
4829 : }
4830 :
4831 : // If the scrollable frame would have propagated its scrolling to the
4832 : // viewport, we still want to construct a regular block rather than a
4833 : // scrollframe so that it paginates correctly, but we don't want to set
4834 : // the bit on the block that tells it to clip at paint time.
4835 0 : if (mPresShell->GetPresContext()->
4836 0 : ElementWouldPropagateScrollbarStyles(aElement)) {
4837 0 : suppressScrollFrame = false;
4838 : }
4839 : }
4840 :
4841 : // Handle various non-scrollable blocks.
4842 : static const FrameConstructionData sNonScrollableBlockData[2][2] = {
4843 : { FULL_CTOR_FCDATA(0,
4844 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4845 : FULL_CTOR_FCDATA(kCaptionCtorFlags,
4846 : &nsCSSFrameConstructor::ConstructNonScrollableBlock) },
4847 : { FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
4848 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4849 : FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK | kCaptionCtorFlags,
4850 : &nsCSSFrameConstructor::ConstructNonScrollableBlock) }
4851 : };
4852 8 : return &sNonScrollableBlockData[suppressScrollFrame][caption];
4853 : }
4854 :
4855 : // If this is for a <body> node and we've propagated the scroll-frame to the
4856 : // viewport, we need to make sure not to add another layer of scrollbars, so
4857 : // we use a different FCData struct without FCDATA_MAY_NEED_SCROLLFRAME.
4858 0 : if (propagatedScrollToViewport && aDisplay->IsScrollableOverflow()) {
4859 0 : if (aDisplay->mDisplay == StyleDisplay::Flex ||
4860 0 : aDisplay->mDisplay == StyleDisplay::WebkitBox) {
4861 : static const FrameConstructionData sNonScrollableFlexData =
4862 : FCDATA_DECL(0, NS_NewFlexContainerFrame);
4863 0 : return &sNonScrollableFlexData;
4864 : }
4865 0 : if (aDisplay->mDisplay == StyleDisplay::Grid) {
4866 : static const FrameConstructionData sNonScrollableGridData =
4867 : FCDATA_DECL(0, NS_NewGridContainerFrame);
4868 0 : return &sNonScrollableGridData;
4869 : }
4870 : }
4871 :
4872 : // NOTE: Make sure to keep this up to date with the StyleDisplay definition!
4873 : static const FrameConstructionDataByDisplay sDisplayData[] = {
4874 : FCDATA_FOR_DISPLAY(StyleDisplay::None, UNREACHABLE_FCDATA()),
4875 : FCDATA_FOR_DISPLAY(StyleDisplay::Block, UNREACHABLE_FCDATA()),
4876 : FCDATA_FOR_DISPLAY(StyleDisplay::FlowRoot, UNREACHABLE_FCDATA()),
4877 : // To keep the hash table small don't add inline frames (they're
4878 : // typically things like FONT and B), because we can quickly
4879 : // find them if we need to.
4880 : // XXXbz the "quickly" part is a bald-faced lie!
4881 : FCDATA_FOR_DISPLAY(StyleDisplay::Inline,
4882 : FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
4883 : &nsCSSFrameConstructor::ConstructInline)),
4884 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineBlock, UNREACHABLE_FCDATA()),
4885 : FCDATA_FOR_DISPLAY(StyleDisplay::ListItem, UNREACHABLE_FCDATA()),
4886 : FCDATA_FOR_DISPLAY(StyleDisplay::Table,
4887 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4888 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineTable,
4889 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4890 : // NOTE: In the unlikely event that we add another table-part here that has
4891 : // a desired-parent-type (& hence triggers table fixup), we'll need to also
4892 : // update the flexbox chunk in nsStyleContext::ApplyStyleFixups().
4893 : FCDATA_FOR_DISPLAY(StyleDisplay::TableRowGroup,
4894 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4895 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4896 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4897 : FCDATA_FOR_DISPLAY(StyleDisplay::TableColumn,
4898 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4899 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup),
4900 : &nsCSSFrameConstructor::ConstructTableCol)),
4901 : FCDATA_FOR_DISPLAY(StyleDisplay::TableColumnGroup,
4902 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4903 : FCDATA_SKIP_ABSPOS_PUSH |
4904 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4905 : NS_NewTableColGroupFrame)),
4906 : FCDATA_FOR_DISPLAY(StyleDisplay::TableHeaderGroup,
4907 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4908 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4909 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4910 : FCDATA_FOR_DISPLAY(StyleDisplay::TableFooterGroup,
4911 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4912 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4913 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4914 : FCDATA_FOR_DISPLAY(StyleDisplay::TableRow,
4915 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4916 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
4917 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4918 : FCDATA_FOR_DISPLAY(StyleDisplay::TableCell,
4919 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4920 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
4921 : &nsCSSFrameConstructor::ConstructTableCell)),
4922 : FCDATA_FOR_DISPLAY(StyleDisplay::TableCaption, UNREACHABLE_FCDATA()),
4923 : FCDATA_FOR_DISPLAY(StyleDisplay::Flex,
4924 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4925 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineFlex,
4926 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4927 : FCDATA_FOR_DISPLAY(StyleDisplay::Grid,
4928 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4929 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineGrid,
4930 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4931 : FCDATA_FOR_DISPLAY(StyleDisplay::Ruby,
4932 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewRubyFrame)),
4933 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyBase,
4934 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4935 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer),
4936 : NS_NewRubyBaseFrame)),
4937 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyBaseContainer,
4938 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4939 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4940 : NS_NewRubyBaseContainerFrame)),
4941 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyText,
4942 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4943 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
4944 : NS_NewRubyTextFrame)),
4945 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyTextContainer,
4946 : FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4947 : NS_NewRubyTextContainerFrame)),
4948 : FCDATA_FOR_DISPLAY(StyleDisplay::Contents,
4949 : FULL_CTOR_FCDATA(FCDATA_IS_CONTENTS, nullptr/*never called*/)),
4950 : FCDATA_FOR_DISPLAY(StyleDisplay::WebkitBox,
4951 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4952 : FCDATA_FOR_DISPLAY(StyleDisplay::WebkitInlineBox,
4953 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4954 : };
4955 : static_assert(ArrayLength(sDisplayData) == size_t(StyleDisplay::WebkitInlineBox) + 1,
4956 : "Be sure to update sDisplayData if you touch StyleDisplay");
4957 :
4958 0 : MOZ_ASSERT(size_t(aDisplay->mDisplay) < ArrayLength(sDisplayData),
4959 : "XUL display data should have already been handled");
4960 :
4961 : // See the mDisplay fixup code in nsRuleNode::ComputeDisplayData.
4962 0 : MOZ_ASSERT(aDisplay->mDisplay != StyleDisplay::Contents ||
4963 : !aElement->IsRootOfNativeAnonymousSubtree(),
4964 : "display:contents on anonymous content is unsupported");
4965 :
4966 : const FrameConstructionDataByDisplay& data =
4967 0 : sDisplayData[size_t(aDisplay->mDisplay)];
4968 :
4969 0 : MOZ_ASSERT(data.mDisplay == aDisplay->mDisplay,
4970 : "Someone messed up the order in the display values");
4971 :
4972 0 : return &data.mData;
4973 : }
4974 :
4975 : nsIFrame*
4976 12 : nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState,
4977 : FrameConstructionItem& aItem,
4978 : nsContainerFrame* aParentFrame,
4979 : const nsStyleDisplay* aDisplay,
4980 : nsFrameItems& aFrameItems)
4981 : {
4982 : return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
4983 : aDisplay, aFrameItems,
4984 12 : NS_NewBlockFormattingContext);
4985 : }
4986 :
4987 : nsIFrame*
4988 12 : nsCSSFrameConstructor::ConstructScrollableBlockWithConstructor(
4989 : nsFrameConstructorState& aState,
4990 : FrameConstructionItem& aItem,
4991 : nsContainerFrame* aParentFrame,
4992 : const nsStyleDisplay* aDisplay,
4993 : nsFrameItems& aFrameItems,
4994 : BlockFrameCreationFunc aConstructor)
4995 : {
4996 12 : nsIContent* const content = aItem.mContent;
4997 12 : nsStyleContext* const styleContext = aItem.mStyleContext;
4998 :
4999 12 : nsContainerFrame* newFrame = nullptr;
5000 : RefPtr<nsStyleContext> scrolledContentStyle
5001 24 : = BeginBuildingScrollFrame(aState, content, styleContext,
5002 : aState.GetGeometricParent(aDisplay, aParentFrame),
5003 : nsCSSAnonBoxes::scrolledContent,
5004 24 : false, newFrame);
5005 :
5006 : // Create our block frame
5007 : // pass a temporary stylecontext, the correct one will be set later
5008 12 : nsContainerFrame* scrolledFrame = aConstructor(mPresShell, styleContext);
5009 :
5010 : // Make sure to AddChild before we call ConstructBlock so that we
5011 : // end up before our descendants in fixed-pos lists as needed.
5012 12 : aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
5013 :
5014 12 : nsFrameItems blockItem;
5015 24 : ConstructBlock(aState, content, newFrame, newFrame, scrolledContentStyle,
5016 : &scrolledFrame, blockItem,
5017 12 : aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
5018 12 : aItem.mPendingBinding);
5019 :
5020 12 : MOZ_ASSERT(blockItem.OnlyChild() == scrolledFrame,
5021 : "Scrollframe's frameItems should be exactly the scrolled frame!");
5022 12 : FinishBuildingScrollFrame(newFrame, scrolledFrame);
5023 :
5024 24 : return newFrame;
5025 : }
5026 :
5027 : nsIFrame*
5028 8 : nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState& aState,
5029 : FrameConstructionItem& aItem,
5030 : nsContainerFrame* aParentFrame,
5031 : const nsStyleDisplay* aDisplay,
5032 : nsFrameItems& aFrameItems)
5033 : {
5034 : return ConstructNonScrollableBlockWithConstructor(aState, aItem, aParentFrame,
5035 : aDisplay, aFrameItems,
5036 8 : NS_NewBlockFrame);
5037 : }
5038 :
5039 : nsIFrame*
5040 8 : nsCSSFrameConstructor::ConstructNonScrollableBlockWithConstructor(
5041 : nsFrameConstructorState& aState,
5042 : FrameConstructionItem& aItem,
5043 : nsContainerFrame* aParentFrame,
5044 : const nsStyleDisplay* aDisplay,
5045 : nsFrameItems& aFrameItems,
5046 : BlockFrameCreationFunc aConstructor)
5047 : {
5048 8 : nsStyleContext* const styleContext = aItem.mStyleContext;
5049 :
5050 : // We want a block formatting context root in paginated contexts for
5051 : // every block that would be scrollable in a non-paginated context.
5052 : // We mark our blocks with a bit here if this condition is true, so
5053 : // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
5054 : bool clipPaginatedOverflow =
5055 8 : (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
5056 8 : nsFrameState flags = nsFrameState(0);
5057 21 : if ((aDisplay->IsAbsolutelyPositionedStyle() ||
5058 10 : aDisplay->IsFloatingStyle() ||
5059 10 : StyleDisplay::InlineBlock == aDisplay->mDisplay ||
5060 11 : clipPaginatedOverflow) &&
5061 3 : !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
5062 3 : flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS;
5063 3 : if (clipPaginatedOverflow) {
5064 0 : flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
5065 : }
5066 : }
5067 :
5068 8 : nsContainerFrame* newFrame = aConstructor(mPresShell, styleContext);
5069 8 : newFrame->AddStateBits(flags);
5070 16 : ConstructBlock(aState, aItem.mContent,
5071 : aState.GetGeometricParent(aDisplay, aParentFrame),
5072 : aParentFrame, styleContext, &newFrame,
5073 : aFrameItems,
5074 8 : aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
5075 8 : aItem.mPendingBinding);
5076 8 : return newFrame;
5077 : }
5078 :
5079 :
5080 : void
5081 583 : nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
5082 : nsIContent* aContent,
5083 : nsContainerFrame* aParentFrame,
5084 : nsIFrame* aNewFrame,
5085 : bool aAllowCounters)
5086 : {
5087 583 : NS_PRECONDITION(mUpdateCount != 0,
5088 : "Should be in an update while creating frames");
5089 :
5090 583 : MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized");
5091 :
5092 : // Initialize the frame
5093 583 : aNewFrame->Init(aContent, aParentFrame, nullptr);
5094 583 : aNewFrame->AddStateBits(aState.mAdditionalStateBits);
5095 :
5096 583 : if (aState.mFrameState) {
5097 : // Restore frame state for just the newly created frame.
5098 120 : RestoreFrameStateFor(aNewFrame, aState.mFrameState);
5099 : }
5100 :
5101 1161 : if (aAllowCounters &&
5102 578 : mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
5103 0 : CountersDirty();
5104 : }
5105 583 : }
5106 :
5107 : already_AddRefed<nsStyleContext>
5108 876 : nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame,
5109 : nsIContent* aContainer,
5110 : nsIContent* aChild,
5111 : nsFrameConstructorState* aState)
5112 : {
5113 876 : MOZ_ASSERT(aContainer, "Must have parent here");
5114 : // XXX uncomment when bug 1089223 is fixed:
5115 : // MOZ_ASSERT(aContainer == aChild->GetFlattenedTreeParent());
5116 876 : nsStyleContext* parentStyleContext = GetDisplayContentsStyleFor(aContainer);
5117 876 : if (MOZ_LIKELY(!parentStyleContext)) {
5118 876 : aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nullptr);
5119 876 : if (aParentFrame) {
5120 876 : MOZ_ASSERT(aParentFrame->GetContent() == aContainer);
5121 : // Resolve the style context based on the content object and the parent
5122 : // style context
5123 876 : parentStyleContext = aParentFrame->StyleContext();
5124 : } else {
5125 : // Perhaps aParentFrame is a canvasFrame and we're replicating
5126 : // fixed-pos frames.
5127 : // XXX should we create a way to tell ConstructFrame which style
5128 : // context to use, and pass it the style context for the
5129 : // previous page's fixed-pos frame?
5130 : }
5131 : }
5132 :
5133 876 : return ResolveStyleContext(parentStyleContext, aChild, aState);
5134 : }
5135 :
5136 : already_AddRefed<nsStyleContext>
5137 0 : nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame,
5138 : nsIContent* aChild,
5139 : nsFrameConstructorState* aState)
5140 : {
5141 0 : return ResolveStyleContext(aParentFrame, aChild->GetFlattenedTreeParent(), aChild, aState);
5142 : }
5143 :
5144 : already_AddRefed<nsStyleContext>
5145 876 : nsCSSFrameConstructor::ResolveStyleContext(const InsertionPoint& aInsertion,
5146 : nsIContent* aChild,
5147 : nsFrameConstructorState* aState)
5148 : {
5149 876 : return ResolveStyleContext(aInsertion.mParentFrame, aInsertion.mContainer,
5150 876 : aChild, aState);
5151 : }
5152 :
5153 : already_AddRefed<nsStyleContext>
5154 1063 : nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
5155 : nsIContent* aContent,
5156 : nsFrameConstructorState* aState,
5157 : Element* aOriginatingElementOrNull)
5158 : {
5159 1063 : StyleSetHandle styleSet = mPresShell->StyleSet();
5160 1063 : aContent->OwnerDoc()->FlushPendingLinkUpdates();
5161 :
5162 2126 : RefPtr<nsStyleContext> result;
5163 1063 : if (aContent->IsElement()) {
5164 882 : auto pseudoType = aContent->AsElement()->GetPseudoElementType();
5165 882 : if (pseudoType == CSSPseudoElementType::NotPseudo) {
5166 878 : MOZ_ASSERT(!aOriginatingElementOrNull);
5167 878 : if (aState) {
5168 1756 : result = styleSet->ResolveStyleFor(aContent->AsElement(),
5169 : aParentStyleContext,
5170 : LazyComputeBehavior::Assert,
5171 878 : aState->mTreeMatchContext);
5172 : } else {
5173 0 : result = styleSet->ResolveStyleFor(aContent->AsElement(),
5174 : aParentStyleContext,
5175 0 : LazyComputeBehavior::Assert);
5176 : }
5177 : } else {
5178 4 : MOZ_ASSERT(aContent->IsInNativeAnonymousSubtree());
5179 4 : if (!aOriginatingElementOrNull) {
5180 : // For pseudo-implementing NAC created by JS using the ChromeOnly
5181 : // document.createElement(..., { pseudo: ... }) API, we find the
5182 : // originating element by lookup the tree until we find a non-NAC
5183 : // ancestor. (These are the correct semantics for C++-generated pseudo-
5184 : // implementing NAC as well, but for those cases we already have a
5185 : // correct originating element passed in.)
5186 0 : MOZ_ASSERT(nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType));
5187 : aOriginatingElementOrNull =
5188 0 : nsContentUtils::GetClosestNonNativeAnonymousAncestor(aContent->AsElement());
5189 : }
5190 4 : MOZ_ASSERT(aOriginatingElementOrNull);
5191 8 : result = styleSet->ResolvePseudoElementStyle(aOriginatingElementOrNull,
5192 : pseudoType,
5193 : aParentStyleContext,
5194 4 : aContent->AsElement());
5195 : }
5196 : } else {
5197 181 : MOZ_ASSERT(!aOriginatingElementOrNull);
5198 181 : NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
5199 : "shouldn't waste time creating style contexts for "
5200 : "comments and processing instructions");
5201 181 : result = styleSet->ResolveStyleForText(aContent, aParentStyleContext);
5202 : }
5203 :
5204 : // ServoRestyleManager does not handle transitions yet, and when it does
5205 : // it probably won't need to track reframed style contexts to start
5206 : // transitions correctly.
5207 1063 : if (mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->GetAsGecko()) {
5208 : GeckoRestyleManager::ReframingStyleContexts* rsc =
5209 1063 : geckoRM->GetReframingStyleContexts();
5210 1063 : if (rsc) {
5211 : nsStyleContext* oldStyleContext =
5212 190 : rsc->Get(aContent, CSSPseudoElementType::NotPseudo);
5213 190 : nsPresContext* presContext = mPresShell->GetPresContext();
5214 190 : if (oldStyleContext) {
5215 : GeckoRestyleManager::TryInitiatingTransition(presContext, aContent,
5216 99 : oldStyleContext, &result);
5217 91 : } else if (aContent->IsElement()) {
5218 : presContext->TransitionManager()->
5219 87 : PruneCompletedTransitions(aContent->AsElement(),
5220 87 : CSSPseudoElementType::NotPseudo, result);
5221 : }
5222 : }
5223 : }
5224 :
5225 2126 : return result.forget();
5226 : }
5227 :
5228 : // MathML Mod - RBS
5229 : void
5230 0 : nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
5231 : nsIContent* aContent,
5232 : nsContainerFrame* aParentFrame,
5233 : nsFrameItems& aBlockItems,
5234 : nsFrameItems& aNewItems)
5235 : {
5236 0 : if (aBlockItems.IsEmpty()) {
5237 : // Nothing to do
5238 0 : return;
5239 : }
5240 :
5241 0 : nsIAtom* anonPseudo = nsCSSAnonBoxes::mozMathMLAnonymousBlock;
5242 :
5243 : nsStyleContext* parentContext =
5244 : nsFrame::CorrectStyleParentFrame(aParentFrame,
5245 0 : anonPseudo)->StyleContext();
5246 0 : StyleSetHandle styleSet = mPresShell->StyleSet();
5247 0 : RefPtr<nsStyleContext> blockContext;
5248 : blockContext = styleSet->
5249 0 : ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
5250 :
5251 : // then, create a block frame that will wrap the child frames. Make it a
5252 : // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
5253 : // is not a suitable block.
5254 : nsContainerFrame* blockFrame =
5255 0 : NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
5256 0 : blockFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
5257 :
5258 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
5259 0 : ReparentFrames(this, blockFrame, aBlockItems);
5260 : // abs-pos and floats are disabled in MathML children so we don't have to
5261 : // worry about messing up those.
5262 0 : blockFrame->SetInitialChildList(kPrincipalList, aBlockItems);
5263 0 : NS_ASSERTION(aBlockItems.IsEmpty(), "What happened?");
5264 0 : aBlockItems.Clear();
5265 0 : aNewItems.AddChild(blockFrame);
5266 : }
5267 :
5268 : // Only <math> elements can be floated or positioned. All other MathML
5269 : // should be in-flow.
5270 : #define SIMPLE_MATHML_CREATE(_tag, _func) \
5271 : { &nsGkAtoms::_tag, \
5272 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
5273 : FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
5274 : FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
5275 :
5276 : /* static */
5277 : const nsCSSFrameConstructor::FrameConstructionData*
5278 307 : nsCSSFrameConstructor::FindMathMLData(Element* aElement,
5279 : nsIAtom* aTag,
5280 : int32_t aNameSpaceID,
5281 : nsStyleContext* aStyleContext)
5282 : {
5283 : // Make sure that we remain confined in the MathML world
5284 307 : if (aNameSpaceID != kNameSpaceID_MathML)
5285 307 : return nullptr;
5286 :
5287 : // Handle <math> specially, because it sometimes produces inlines
5288 0 : if (aTag == nsGkAtoms::math) {
5289 : // This needs to match the test in EnsureBlockDisplay in
5290 : // nsRuleNode.cpp. Though the behavior here for the display:table
5291 : // case is pretty weird...
5292 0 : if (aStyleContext->StyleDisplay()->IsBlockOutsideStyle()) {
5293 : static const FrameConstructionData sBlockMathData =
5294 : FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
5295 : FCDATA_WRAP_KIDS_IN_BLOCKS,
5296 : NS_NewMathMLmathBlockFrame);
5297 0 : return &sBlockMathData;
5298 : }
5299 :
5300 : static const FrameConstructionData sInlineMathData =
5301 : FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
5302 : FCDATA_IS_LINE_PARTICIPANT |
5303 : FCDATA_WRAP_KIDS_IN_BLOCKS,
5304 : NS_NewMathMLmathInlineFrame);
5305 0 : return &sInlineMathData;
5306 : }
5307 :
5308 :
5309 : static const FrameConstructionDataByTag sMathMLData[] = {
5310 : SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame),
5311 : SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame),
5312 : SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
5313 : SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
5314 : SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
5315 : SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
5316 : SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
5317 : SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
5318 : SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame),
5319 : SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame),
5320 : SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame),
5321 : SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
5322 : SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
5323 : SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
5324 : SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmrowFrame),
5325 : SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
5326 : SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
5327 : SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
5328 : SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
5329 : SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame),
5330 : SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame),
5331 : SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmrowFrame),
5332 : SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame),
5333 : SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame),
5334 : SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame),
5335 : SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame),
5336 : SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame),
5337 : SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame),
5338 : SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)
5339 : };
5340 :
5341 0 : return FindDataByTag(aTag, aElement, aStyleContext, sMathMLData,
5342 0 : ArrayLength(sMathMLData));
5343 : }
5344 :
5345 :
5346 : nsContainerFrame*
5347 22 : nsCSSFrameConstructor::ConstructFrameWithAnonymousChild(
5348 : nsFrameConstructorState& aState,
5349 : FrameConstructionItem& aItem,
5350 : nsContainerFrame* aParentFrame,
5351 : nsFrameItems& aFrameItems,
5352 : ContainerFrameCreationFunc aConstructor,
5353 : ContainerFrameCreationFunc aInnerConstructor,
5354 : nsICSSAnonBoxPseudo* aInnerPseudo,
5355 : bool aCandidateRootFrame)
5356 : {
5357 22 : nsIContent* const content = aItem.mContent;
5358 22 : nsStyleContext* const styleContext = aItem.mStyleContext;
5359 :
5360 : // Create the outer frame:
5361 22 : nsContainerFrame* newFrame = aConstructor(mPresShell, styleContext);
5362 :
5363 44 : InitAndRestoreFrame(aState, content,
5364 : aCandidateRootFrame ?
5365 22 : aState.GetGeometricParent(styleContext->StyleDisplay(),
5366 : aParentFrame) :
5367 : aParentFrame,
5368 22 : newFrame);
5369 22 : newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
5370 :
5371 : // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
5372 44 : RefPtr<nsStyleContext> scForAnon;
5373 44 : scForAnon = mPresShell->StyleSet()->
5374 22 : ResolveInheritingAnonymousBoxStyle(aInnerPseudo, styleContext);
5375 :
5376 : // Create the anonymous inner wrapper frame
5377 22 : nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
5378 :
5379 22 : InitAndRestoreFrame(aState, content, newFrame, innerFrame);
5380 :
5381 : // Put the newly created frames into the right child list
5382 22 : SetInitialSingleChild(newFrame, innerFrame);
5383 :
5384 22 : aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame,
5385 22 : aCandidateRootFrame, aCandidateRootFrame);
5386 :
5387 22 : if (!mRootElementFrame && aCandidateRootFrame) {
5388 : // The frame we're constructing will be the root element frame.
5389 : // Set mRootElementFrame before processing children.
5390 21 : mRootElementFrame = newFrame;
5391 : }
5392 :
5393 22 : nsFrameItems childItems;
5394 :
5395 : // Process children
5396 22 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
5397 : "nsIAnonymousContentCreator::CreateAnonymousContent should not "
5398 : "be implemented for frames for which we explicitly create an "
5399 : "anonymous child to wrap its child frames");
5400 22 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
5401 0 : ConstructFramesFromItemList(aState, aItem.mChildItems,
5402 0 : innerFrame, childItems);
5403 : } else {
5404 22 : ProcessChildren(aState, content, styleContext, innerFrame,
5405 22 : true, childItems, false, aItem.mPendingBinding);
5406 : }
5407 :
5408 : // Set the inner wrapper frame's initial primary list
5409 22 : innerFrame->SetInitialChildList(kPrincipalList, childItems);
5410 :
5411 44 : return newFrame;
5412 : }
5413 :
5414 : nsIFrame*
5415 22 : nsCSSFrameConstructor::ConstructOuterSVG(nsFrameConstructorState& aState,
5416 : FrameConstructionItem& aItem,
5417 : nsContainerFrame* aParentFrame,
5418 : const nsStyleDisplay* aDisplay,
5419 : nsFrameItems& aFrameItems)
5420 : {
5421 22 : return ConstructFrameWithAnonymousChild(
5422 : aState, aItem, aParentFrame, aFrameItems,
5423 : NS_NewSVGOuterSVGFrame, NS_NewSVGOuterSVGAnonChildFrame,
5424 22 : nsCSSAnonBoxes::mozSVGOuterSVGAnonChild, true);
5425 : }
5426 :
5427 : nsIFrame*
5428 0 : nsCSSFrameConstructor::ConstructMarker(nsFrameConstructorState& aState,
5429 : FrameConstructionItem& aItem,
5430 : nsContainerFrame* aParentFrame,
5431 : const nsStyleDisplay* aDisplay,
5432 : nsFrameItems& aFrameItems)
5433 : {
5434 0 : return ConstructFrameWithAnonymousChild(
5435 : aState, aItem, aParentFrame, aFrameItems,
5436 : NS_NewSVGMarkerFrame, NS_NewSVGMarkerAnonChildFrame,
5437 0 : nsCSSAnonBoxes::mozSVGMarkerAnonChild, false);
5438 : }
5439 :
5440 : // Only outer <svg> elements can be floated or positioned. All other SVG
5441 : // should be in-flow.
5442 : #define SIMPLE_SVG_FCDATA(_func) \
5443 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
5444 : FCDATA_SKIP_ABSPOS_PUSH | \
5445 : FCDATA_DISALLOW_GENERATED_CONTENT, _func)
5446 : #define SIMPLE_SVG_CREATE(_tag, _func) \
5447 : { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
5448 :
5449 : static bool
5450 122 : IsFilterPrimitiveChildTag(const nsIAtom* aTag)
5451 : {
5452 244 : return aTag == nsGkAtoms::feDistantLight ||
5453 244 : aTag == nsGkAtoms::fePointLight ||
5454 244 : aTag == nsGkAtoms::feSpotLight ||
5455 244 : aTag == nsGkAtoms::feFuncR ||
5456 244 : aTag == nsGkAtoms::feFuncG ||
5457 244 : aTag == nsGkAtoms::feFuncB ||
5458 366 : aTag == nsGkAtoms::feFuncA ||
5459 244 : aTag == nsGkAtoms::feMergeNode;
5460 : }
5461 :
5462 : /* static */
5463 : const nsCSSFrameConstructor::FrameConstructionData*
5464 307 : nsCSSFrameConstructor::FindSVGData(Element* aElement,
5465 : nsIAtom* aTag,
5466 : int32_t aNameSpaceID,
5467 : nsIFrame* aParentFrame,
5468 : bool aIsWithinSVGText,
5469 : bool aAllowsTextPathChild,
5470 : nsStyleContext* aStyleContext)
5471 : {
5472 307 : if (aNameSpaceID != kNameSpaceID_SVG) {
5473 184 : return nullptr;
5474 : }
5475 :
5476 : static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
5477 : static const FrameConstructionData sContainerData =
5478 : SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
5479 :
5480 123 : bool parentIsSVG = aIsWithinSVGText;
5481 : nsIContent* parentContent =
5482 123 : aParentFrame ? aParentFrame->GetContent() : nullptr;
5483 : // XXXbz should this really be based on the XBL-resolved tag of the parent
5484 : // frame's content? Should it not be based on the type of the parent frame
5485 : // (e.g. whether it's an SVG frame)?
5486 123 : if (parentContent) {
5487 : int32_t parentNSID;
5488 : nsIAtom* parentTag =
5489 : parentContent->OwnerDoc()->BindingManager()->
5490 123 : ResolveTag(parentContent, &parentNSID);
5491 :
5492 : // It's not clear whether the SVG spec intends to allow any SVG
5493 : // content within svg:foreignObject at all (SVG 1.1, section
5494 : // 23.2), but if it does, it better be svg:svg. So given that
5495 : // we're allowing it, treat it as a non-SVG parent.
5496 245 : parentIsSVG = parentNSID == kNameSpaceID_SVG &&
5497 122 : parentTag != nsGkAtoms::foreignObject;
5498 : }
5499 :
5500 246 : if ((aTag != nsGkAtoms::svg && !parentIsSVG) ||
5501 369 : (aTag == nsGkAtoms::desc || aTag == nsGkAtoms::title ||
5502 123 : aTag == nsGkAtoms::metadata)) {
5503 : // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
5504 : // svg:svg not contained within svg:svg are incorrect, although they
5505 : // don't seem to specify error handling. Ignore them, since many of
5506 : // our frame classes can't deal. It *may* be that the document
5507 : // should at that point be considered in error according to F.2, but
5508 : // it's hard to tell.
5509 : //
5510 : // Style mutation can't change this situation, so don't bother
5511 : // adding to the undisplayed content map.
5512 : //
5513 : // We don't currently handle any UI for desc/title/metadata
5514 0 : return &sSuppressData;
5515 : }
5516 :
5517 : // We don't need frames for animation elements
5518 123 : if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
5519 0 : return &sSuppressData;
5520 : }
5521 :
5522 123 : if (aTag == nsGkAtoms::svg && !parentIsSVG) {
5523 : // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
5524 : // of whether they fail conditional processing attributes, since various
5525 : // SVG frames assume that one exists. We handle the non-rendering
5526 : // of failing outer <svg> element contents like <switch> statements,
5527 : // and do the PassesConditionalProcessingTests call in
5528 : // nsSVGOuterSVGFrame::Init.
5529 : static const FrameConstructionData sOuterSVGData =
5530 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
5531 1 : return &sOuterSVGData;
5532 : }
5533 :
5534 122 : if (aTag == nsGkAtoms::marker) {
5535 : static const FrameConstructionData sMarkerSVGData =
5536 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructMarker);
5537 0 : return &sMarkerSVGData;
5538 : }
5539 :
5540 244 : nsCOMPtr<SVGTests> tests(do_QueryInterface(aElement));
5541 122 : if (tests && !tests->PassesConditionalProcessingTests()) {
5542 : // Elements with failing conditional processing attributes never get
5543 : // rendered. Note that this is not where we select which frame in a
5544 : // <switch> to render! That happens in nsSVGSwitchFrame::PaintSVG.
5545 0 : if (aIsWithinSVGText) {
5546 : // SVGTextFrame doesn't handle conditional processing attributes,
5547 : // so don't create frames for descendants of <text> with failing
5548 : // attributes. We need frames not to be created so that text layout
5549 : // is correct.
5550 0 : return &sSuppressData;
5551 : }
5552 : // If we're not inside <text>, create an nsSVGContainerFrame (which is a
5553 : // frame that doesn't render) so that paint servers can still be referenced,
5554 : // even if they live inside an element with failing conditional processing
5555 : // attributes.
5556 0 : return &sContainerData;
5557 : }
5558 :
5559 : // Ensure that a stop frame is a child of a gradient and that gradients
5560 : // can only have stop children.
5561 : bool parentIsGradient =
5562 244 : aParentFrame && (aParentFrame->IsSVGLinearGradientFrame() ||
5563 244 : aParentFrame->IsSVGRadialGradientFrame());
5564 122 : bool stop = (aTag == nsGkAtoms::stop);
5565 244 : if ((parentIsGradient && !stop) ||
5566 244 : (!parentIsGradient && stop)) {
5567 0 : return &sSuppressData;
5568 : }
5569 :
5570 : // Prevent bad frame types being children of filters or parents of filter
5571 : // primitives. If aParentFrame is null, we know that the frame that will
5572 : // be created will be an nsInlineFrame, so it can never be a filter.
5573 122 : bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
5574 122 : bool filterPrimitive = aElement->IsNodeOfType(nsINode::eFILTER);
5575 244 : if ((parentIsFilter && !filterPrimitive) ||
5576 244 : (!parentIsFilter && filterPrimitive)) {
5577 0 : return &sSuppressData;
5578 : }
5579 :
5580 : // Prevent bad frame types being children of filter primitives or parents of
5581 : // filter primitive children. If aParentFrame is null, we know that the frame
5582 : // that will be created will be an nsInlineFrame, so it can never be a filter
5583 : // primitive.
5584 : bool parentIsFEContainerFrame =
5585 122 : aParentFrame && aParentFrame->IsSVGFEContainerFrame();
5586 244 : if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(aTag)) ||
5587 244 : (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(aTag))) {
5588 0 : return &sSuppressData;
5589 : }
5590 :
5591 : // Special cases for text/tspan/textPath, because the kind of frame
5592 : // they get depends on the parent frame. We ignore 'a' elements when
5593 : // determining the parent, however.
5594 122 : if (aIsWithinSVGText) {
5595 : // If aIsWithinSVGText is true, then we know that the "SVG text uses
5596 : // CSS frames" pref was true when this SVG fragment was first constructed.
5597 :
5598 : // We don't use ConstructInline because we want different behavior
5599 : // for generated content.
5600 : static const FrameConstructionData sTSpanData =
5601 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |
5602 : FCDATA_SKIP_ABSPOS_PUSH |
5603 : FCDATA_DISALLOW_GENERATED_CONTENT |
5604 : FCDATA_IS_LINE_PARTICIPANT |
5605 : FCDATA_IS_INLINE |
5606 : FCDATA_USE_CHILD_ITEMS,
5607 : NS_NewInlineFrame);
5608 0 : if (aTag == nsGkAtoms::textPath) {
5609 0 : if (aAllowsTextPathChild) {
5610 0 : return &sTSpanData;
5611 : }
5612 0 : } else if (aTag == nsGkAtoms::tspan ||
5613 0 : aTag == nsGkAtoms::a) {
5614 0 : return &sTSpanData;
5615 : }
5616 0 : return &sSuppressData;
5617 122 : } else if (aTag == nsGkAtoms::text) {
5618 : static const FrameConstructionData sTextData =
5619 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW |
5620 : FCDATA_ALLOW_BLOCK_STYLES,
5621 : NS_NewSVGTextFrame,
5622 : nsCSSAnonBoxes::mozSVGText);
5623 0 : return &sTextData;
5624 244 : } else if (aTag == nsGkAtoms::tspan ||
5625 122 : aTag == nsGkAtoms::textPath) {
5626 0 : return &sSuppressData;
5627 : }
5628 :
5629 : static const FrameConstructionDataByTag sSVGData[] = {
5630 : SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
5631 : SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
5632 : SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
5633 : SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame),
5634 : SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame),
5635 : SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame),
5636 : SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame),
5637 : SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame),
5638 : SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame),
5639 : SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame),
5640 : SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame),
5641 : SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
5642 : SIMPLE_SVG_CREATE(generic_, NS_NewSVGGenericContainerFrame),
5643 : { &nsGkAtoms::foreignObject,
5644 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW,
5645 : NS_NewSVGForeignObjectFrame,
5646 : nsCSSAnonBoxes::mozSVGForeignContent) },
5647 : SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
5648 : SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
5649 : SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
5650 : SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
5651 : SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
5652 : SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame),
5653 : SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
5654 : SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
5655 : SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
5656 : SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
5657 : SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
5658 : SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
5659 : SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
5660 : SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
5661 : SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
5662 : SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
5663 : SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
5664 : SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
5665 : SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
5666 : SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
5667 : SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
5668 : SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
5669 : SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
5670 : SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
5671 : SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
5672 : SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
5673 : SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
5674 : SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
5675 : SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
5676 : SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
5677 : SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
5678 : SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
5679 : SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
5680 : SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
5681 : SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
5682 : SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)
5683 : };
5684 :
5685 : const FrameConstructionData* data =
5686 122 : FindDataByTag(aTag, aElement, aStyleContext, sSVGData,
5687 244 : ArrayLength(sSVGData));
5688 :
5689 122 : if (!data) {
5690 0 : data = &sContainerData;
5691 : }
5692 :
5693 122 : return data;
5694 : }
5695 :
5696 : void
5697 0 : nsCSSFrameConstructor::AddPageBreakItem(nsIContent* aContent,
5698 : FrameConstructionItemList& aItems)
5699 : {
5700 : RefPtr<nsStyleContext> pseudoStyle =
5701 0 : mPresShell->StyleSet()->
5702 0 : ResolveNonInheritingAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak);
5703 :
5704 0 : MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,
5705 : "Unexpected display");
5706 :
5707 : static const FrameConstructionData sPageBreakData =
5708 : FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
5709 :
5710 : // Lie about the tag and namespace so we don't trigger anything
5711 : // interesting during frame construction.
5712 0 : aItems.AppendItem(&sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
5713 0 : kNameSpaceID_None, nullptr, pseudoStyle.forget(),
5714 0 : true, nullptr);
5715 0 : }
5716 :
5717 : bool
5718 884 : nsCSSFrameConstructor::ShouldCreateItemsForChild(nsFrameConstructorState& aState,
5719 : nsIContent* aContent,
5720 : nsContainerFrame* aParentFrame)
5721 : {
5722 884 : aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
5723 884 : if (aContent->IsElement() && !aContent->IsStyledByServo()) {
5724 : // We can't just remove our pending restyle flags, since we may
5725 : // have restyle-later-siblings set on us. But we _can_ remove the
5726 : // "is possible restyle root" flags, and need to. Otherwise we can
5727 : // end up with stale such flags (e.g. if we used to have a
5728 : // display:none parent when our last restyle was posted and
5729 : // processed and now no longer do).
5730 695 : aContent->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS &
5731 695 : ~ELEMENT_PENDING_RESTYLE_FLAGS);
5732 : }
5733 :
5734 : // XXX the GetContent() != aContent check is needed due to bug 135040.
5735 : // Remove it once that's fixed.
5736 1768 : if (aContent->GetPrimaryFrame() &&
5737 884 : aContent->GetPrimaryFrame()->GetContent() == aContent &&
5738 0 : !aState.mCreatingExtraFrames) {
5739 0 : NS_ERROR("asked to create frame construction item for a node that already "
5740 : "has a frame");
5741 0 : return false;
5742 : }
5743 :
5744 : // don't create a whitespace frame if aParent doesn't want it
5745 884 : if (!NeedFrameFor(aState, aParentFrame, aContent)) {
5746 0 : return false;
5747 : }
5748 :
5749 : // never create frames for comments or PIs
5750 1760 : if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
5751 876 : aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
5752 8 : return false;
5753 : }
5754 :
5755 876 : return true;
5756 : }
5757 :
5758 : void
5759 876 : nsCSSFrameConstructor::DoAddFrameConstructionItems(nsFrameConstructorState& aState,
5760 : nsIContent* aContent,
5761 : nsStyleContext* aStyleContext,
5762 : bool aSuppressWhiteSpaceOptimizations,
5763 : nsContainerFrame* aParentFrame,
5764 : nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
5765 : FrameConstructionItemList& aItems)
5766 : {
5767 876 : uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
5768 876 : if (aParentFrame) {
5769 876 : if (nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
5770 0 : flags |= ITEM_IS_WITHIN_SVG_TEXT;
5771 : }
5772 909 : if (aParentFrame->IsBlockFrame() && aParentFrame->GetParent() &&
5773 33 : aParentFrame->GetParent()->IsSVGTextFrame()) {
5774 0 : flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
5775 : }
5776 : }
5777 876 : AddFrameConstructionItemsInternal(aState, aContent, aParentFrame,
5778 : aContent->NodeInfo()->NameAtom(),
5779 : aContent->GetNameSpaceID(),
5780 : aSuppressWhiteSpaceOptimizations,
5781 : aStyleContext,
5782 : flags, aAnonChildren,
5783 876 : aItems);
5784 876 : }
5785 :
5786 : void
5787 884 : nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState,
5788 : nsIContent* aContent,
5789 : bool aSuppressWhiteSpaceOptimizations,
5790 : const InsertionPoint& aInsertion,
5791 : FrameConstructionItemList& aItems)
5792 : {
5793 884 : nsContainerFrame* parentFrame = aInsertion.mParentFrame;
5794 884 : if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
5795 8 : return;
5796 : }
5797 : RefPtr<nsStyleContext> styleContext =
5798 1752 : ResolveStyleContext(aInsertion, aContent, &aState);
5799 876 : DoAddFrameConstructionItems(aState, aContent, styleContext,
5800 : aSuppressWhiteSpaceOptimizations, parentFrame,
5801 876 : nullptr, aItems);
5802 : }
5803 :
5804 : void
5805 294 : nsCSSFrameConstructor::SetAsUndisplayedContent(nsFrameConstructorState& aState,
5806 : FrameConstructionItemList& aList,
5807 : nsIContent* aContent,
5808 : nsStyleContext* aStyleContext,
5809 : bool aIsGeneratedContent)
5810 : {
5811 294 : if (aStyleContext->GetPseudo()) {
5812 0 : if (aIsGeneratedContent) {
5813 0 : aContent->UnbindFromTree();
5814 : }
5815 0 : return;
5816 : }
5817 294 : NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
5818 :
5819 294 : if (aState.mCreatingExtraFrames) {
5820 0 : MOZ_ASSERT(GetUndisplayedContent(aContent),
5821 : "should have called SetUndisplayedContent earlier");
5822 0 : return;
5823 : }
5824 294 : aList.AppendUndisplayedItem(aContent, aStyleContext);
5825 : }
5826 :
5827 : void
5828 944 : nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
5829 : nsIContent* aContent,
5830 : nsContainerFrame* aParentFrame,
5831 : nsIAtom* aTag,
5832 : int32_t aNameSpaceID,
5833 : bool aSuppressWhiteSpaceOptimizations,
5834 : nsStyleContext* aStyleContext,
5835 : uint32_t aFlags,
5836 : nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
5837 : FrameConstructionItemList& aItems)
5838 : {
5839 944 : NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT) ||
5840 : aContent->IsElement(),
5841 : "Shouldn't get anything else here!");
5842 944 : MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
5843 : aContent->NodeInfo()->NameAtom() == nsGkAtoms::area);
5844 :
5845 : // The following code allows the user to specify the base tag
5846 : // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
5847 : // can then be extended arbitrarily.
5848 944 : const nsStyleDisplay* display = aStyleContext->StyleDisplay();
5849 1436 : RefPtr<nsStyleContext> styleContext(aStyleContext);
5850 944 : PendingBinding* pendingBinding = nullptr;
5851 944 : if (aFlags & ITEM_ALLOW_XBL_BASE) {
5852 938 : if (display->mBinding) {
5853 : // Ensure that our XBL bindings are installed.
5854 :
5855 332 : nsXBLService* xblService = nsXBLService::GetInstance();
5856 332 : if (!xblService)
5857 0 : return;
5858 :
5859 : bool resolveStyle;
5860 :
5861 664 : nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
5862 :
5863 996 : nsresult rv = xblService->LoadBindings(
5864 332 : aContent, display->mBinding->GetURI(),
5865 332 : display->mBinding->mExtraData->GetPrincipal(),
5866 664 : getter_AddRefs(newPendingBinding->mBinding), &resolveStyle);
5867 332 : if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
5868 0 : return;
5869 :
5870 332 : if (newPendingBinding->mBinding) {
5871 237 : pendingBinding = newPendingBinding;
5872 : // aState takes over owning newPendingBinding
5873 237 : aState.AddPendingBinding(newPendingBinding.forget());
5874 : }
5875 :
5876 332 : if (resolveStyle) {
5877 125 : if (aContent->IsStyledByServo()) {
5878 0 : Element* element = aContent->AsElement();
5879 0 : ServoStyleSet* styleSet = mPresShell->StyleSet()->AsServo();
5880 :
5881 : // XXX: We should have a better way to restyle ourselves.
5882 0 : ServoRestyleManager::ClearServoDataFromSubtree(element);
5883 0 : styleSet->StyleNewSubtree(element);
5884 :
5885 : // Servo's should_traverse_children() in traversal.rs skips
5886 : // styling descendants of elements with a -moz-binding the
5887 : // first time. Thus call StyleNewChildren() again.
5888 0 : styleSet->StyleNewChildren(element);
5889 : styleContext =
5890 0 : styleSet->ResolveStyleFor(element, nullptr, LazyComputeBehavior::Assert);
5891 : } else {
5892 : styleContext =
5893 125 : ResolveStyleContext(styleContext->GetParent(), aContent, &aState);
5894 : }
5895 :
5896 125 : display = styleContext->StyleDisplay();
5897 125 : aStyleContext = styleContext;
5898 : }
5899 :
5900 332 : aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID);
5901 606 : } else if (display->mBinding.ForceGet()) {
5902 0 : if (aContent->IsStyledByServo()) {
5903 : // Servo's should_traverse_children skips styling descendants of
5904 : // elements with a -moz-binding value. For -moz-binding URLs that can
5905 : // be resolved, we will load the binding above, which will style the
5906 : // children after they have been rearranged in the flattened tree.
5907 : // If the URL couldn't be resolved, we still need to style the children,
5908 : // so we do that here.
5909 0 : mPresShell->StyleSet()->AsServo()->StyleNewChildren(aContent->AsElement());
5910 : }
5911 : }
5912 : }
5913 :
5914 944 : const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
5915 :
5916 : // Pre-check for display "none" - if we find that, don't create
5917 : // any frame at all
5918 944 : if (StyleDisplay::None == display->mDisplay) {
5919 294 : SetAsUndisplayedContent(aState, aItems, aContent, styleContext, isGeneratedContent);
5920 294 : return;
5921 : }
5922 :
5923 650 : bool isText = !aContent->IsElement();
5924 :
5925 : // never create frames for non-option/optgroup kids of <select> and
5926 : // non-option kids of <optgroup> inside a <select>.
5927 : // XXXbz it's not clear how this should best work with XBL.
5928 650 : nsIContent *parent = aContent->GetParent();
5929 650 : if (parent) {
5930 : // Check tag first, since that check will usually fail
5931 1300 : if (parent->IsAnyOfHTMLElements(nsGkAtoms::select, nsGkAtoms::optgroup) &&
5932 : // <option> is ok no matter what
5933 0 : !aContent->IsHTMLElement(nsGkAtoms::option) &&
5934 : // <optgroup> is OK in <select> but not in <optgroup>
5935 0 : (!aContent->IsHTMLElement(nsGkAtoms::optgroup) ||
5936 650 : !parent->IsHTMLElement(nsGkAtoms::select)) &&
5937 : // Allow native anonymous content no matter what
5938 0 : !aContent->IsRootOfNativeAnonymousSubtree()) {
5939 : // No frame for aContent
5940 0 : if (!isText) {
5941 0 : SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
5942 0 : isGeneratedContent);
5943 : }
5944 0 : return;
5945 : }
5946 : }
5947 :
5948 : // When constructing a child of a non-open <details>, create only the frame
5949 : // for the main <summary> element, and skip other elements. This only applies
5950 : // to things that are not roots of native anonymous subtrees (except for
5951 : // ::before and ::after); we always want to create "internal" anonymous
5952 : // content.
5953 650 : auto* details = HTMLDetailsElement::FromContentOrNull(parent);
5954 650 : if (details && !details->Open() &&
5955 0 : (!aContent->IsRootOfNativeAnonymousSubtree() ||
5956 0 : aContent->IsGeneratedContentContainerForBefore() ||
5957 0 : aContent->IsGeneratedContentContainerForAfter())) {
5958 0 : auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
5959 0 : if (!summary || !summary->IsMainSummary()) {
5960 0 : SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
5961 0 : isGeneratedContent);
5962 0 : return;
5963 : }
5964 : }
5965 :
5966 650 : bool isPopup = false;
5967 : // Try to find frame construction data for this content
5968 : const FrameConstructionData* data;
5969 650 : if (isText) {
5970 181 : data = FindTextData(aParentFrame);
5971 181 : if (!data) {
5972 : // Nothing to do here; suppressed text inside SVG
5973 158 : return;
5974 : }
5975 : } else {
5976 469 : Element* element = aContent->AsElement();
5977 :
5978 : // Don't create frames for non-SVG element children of SVG elements.
5979 469 : if (aNameSpaceID != kNameSpaceID_SVG &&
5980 346 : ((aParentFrame &&
5981 346 : IsFrameForSVG(aParentFrame) &&
5982 346 : !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) ||
5983 346 : (aFlags & ITEM_IS_WITHIN_SVG_TEXT))) {
5984 0 : SetAsUndisplayedContent(aState, aItems, element, styleContext,
5985 0 : isGeneratedContent);
5986 0 : return;
5987 : }
5988 :
5989 469 : data = FindHTMLData(element, aTag, aNameSpaceID, aParentFrame,
5990 469 : styleContext);
5991 469 : if (!data) {
5992 463 : data = FindXULTagData(element, aTag, aNameSpaceID, styleContext);
5993 : }
5994 469 : if (!data) {
5995 307 : data = FindMathMLData(element, aTag, aNameSpaceID, styleContext);
5996 : }
5997 469 : if (!data) {
5998 921 : data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
5999 307 : aFlags & ITEM_IS_WITHIN_SVG_TEXT,
6000 307 : aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
6001 307 : styleContext);
6002 : }
6003 :
6004 : // Now check for XUL display types
6005 469 : if (!data) {
6006 184 : data = FindXULDisplayData(display, element, styleContext);
6007 : }
6008 :
6009 : // And general display types
6010 469 : if (!data) {
6011 20 : data = FindDisplayData(display, element, styleContext);
6012 : }
6013 :
6014 469 : NS_ASSERTION(data, "Should have frame construction data now");
6015 :
6016 469 : if (data->mBits & FCDATA_SUPPRESS_FRAME) {
6017 0 : SetAsUndisplayedContent(aState, aItems, element, styleContext, isGeneratedContent);
6018 0 : return;
6019 : }
6020 :
6021 : #ifdef MOZ_XUL
6022 498 : if ((data->mBits & FCDATA_IS_POPUP) &&
6023 44 : (!aParentFrame || // Parent is inline
6024 44 : !aParentFrame->IsMenuFrame())) {
6025 30 : if (!aState.mPopupItems.containingBlock &&
6026 1 : !aState.mHavePendingPopupgroup) {
6027 0 : SetAsUndisplayedContent(aState, aItems, element, styleContext,
6028 0 : isGeneratedContent);
6029 0 : return;
6030 : }
6031 :
6032 29 : isPopup = true;
6033 : }
6034 : #endif /* MOZ_XUL */
6035 : }
6036 :
6037 492 : uint32_t bits = data->mBits;
6038 :
6039 : // Inside colgroups, suppress everything except columns.
6040 492 : if (aParentFrame && aParentFrame->IsTableColGroupFrame() &&
6041 0 : (!(bits & FCDATA_IS_TABLE_PART) ||
6042 0 : display->mDisplay != StyleDisplay::TableColumn)) {
6043 0 : SetAsUndisplayedContent(aState, aItems, aContent, styleContext, isGeneratedContent);
6044 0 : return;
6045 : }
6046 :
6047 : bool canHavePageBreak =
6048 978 : (aFlags & ITEM_ALLOW_PAGE_BREAK) && aState.mPresContext->IsPaginated() &&
6049 0 : !display->IsAbsolutelyPositionedStyle() &&
6050 0 : !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
6051 492 : !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
6052 :
6053 492 : if (canHavePageBreak && display->mBreakBefore) {
6054 0 : AddPageBreakItem(aContent, aItems);
6055 : }
6056 :
6057 492 : if (MOZ_UNLIKELY(bits & FCDATA_IS_CONTENTS)) {
6058 0 : if (!GetDisplayContentsStyleFor(aContent)) {
6059 0 : MOZ_ASSERT(styleContext->GetPseudo() || !isGeneratedContent,
6060 : "Should have had pseudo type");
6061 0 : aState.mFrameManager->SetDisplayContents(aContent, styleContext);
6062 : } else {
6063 0 : aState.mFrameManager->ChangeDisplayContents(aContent, styleContext);
6064 : }
6065 :
6066 0 : TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
6067 0 : if (aState.HasAncestorFilter()) {
6068 0 : ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
6069 : } else {
6070 0 : ancestorPusher.PushStyleScope(aContent->AsElement());
6071 : }
6072 :
6073 0 : if (aParentFrame) {
6074 0 : aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
6075 : }
6076 0 : CreateGeneratedContentItem(aState, aParentFrame, aContent, styleContext,
6077 0 : CSSPseudoElementType::before, aItems);
6078 :
6079 0 : FlattenedChildIterator iter(aContent);
6080 0 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
6081 0 : if (!ShouldCreateItemsForChild(aState, child, aParentFrame)) {
6082 0 : continue;
6083 : }
6084 :
6085 : // Get the parent of the content and check if it is a XBL children element
6086 : // (if the content is a children element then parent != aContent because the
6087 : // FlattenedChildIterator will transitively iterate through <xbl:children>
6088 : // for default content). Push the children element as an ancestor here because
6089 : // it does not have a frame and would not otherwise be pushed as an ancestor.
6090 0 : nsIContent* parent = child->GetParent();
6091 0 : MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
6092 0 : TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
6093 0 : if (parent != aContent && parent->IsElement()) {
6094 0 : if (aState.HasAncestorFilter()) {
6095 0 : ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
6096 : } else {
6097 0 : ancestorPusher.PushStyleScope(parent->AsElement());
6098 : }
6099 : }
6100 :
6101 : RefPtr<nsStyleContext> childContext =
6102 0 : ResolveStyleContext(styleContext, child, &aState);
6103 0 : DoAddFrameConstructionItems(aState, child, childContext,
6104 : aSuppressWhiteSpaceOptimizations,
6105 0 : aParentFrame, aAnonChildren, aItems);
6106 : }
6107 0 : aItems.SetParentHasNoXBLChildren(!iter.XBLInvolved());
6108 :
6109 0 : CreateGeneratedContentItem(aState, aParentFrame, aContent, styleContext,
6110 0 : CSSPseudoElementType::after, aItems);
6111 0 : if (canHavePageBreak && display->mBreakAfter) {
6112 0 : AddPageBreakItem(aContent, aItems);
6113 : }
6114 0 : return;
6115 : }
6116 :
6117 492 : FrameConstructionItem* item = nullptr;
6118 492 : if (details && details->Open()) {
6119 0 : auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
6120 0 : if (summary && summary->IsMainSummary()) {
6121 : // If details is open, the main summary needs to be rendered as if it is
6122 : // the first child, so add the item to the front of the item list.
6123 0 : item = aItems.PrependItem(data, aContent, aTag, aNameSpaceID,
6124 0 : pendingBinding, styleContext.forget(),
6125 0 : aSuppressWhiteSpaceOptimizations, aAnonChildren);
6126 : }
6127 : }
6128 :
6129 492 : if (!item) {
6130 984 : item = aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
6131 984 : pendingBinding, styleContext.forget(),
6132 492 : aSuppressWhiteSpaceOptimizations, aAnonChildren);
6133 : }
6134 492 : item->mIsText = isText;
6135 492 : item->mIsGeneratedContent = isGeneratedContent;
6136 492 : item->mIsAnonymousContentCreatorContent =
6137 492 : aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
6138 492 : if (isGeneratedContent) {
6139 6 : NS_ADDREF(item->mContent);
6140 : }
6141 492 : item->mIsRootPopupgroup =
6142 493 : aNameSpaceID == kNameSpaceID_XUL && aTag == nsGkAtoms::popupgroup &&
6143 1 : aContent->IsRootOfNativeAnonymousSubtree();
6144 492 : if (item->mIsRootPopupgroup) {
6145 1 : aState.mHavePendingPopupgroup = true;
6146 : }
6147 492 : item->mIsPopup = isPopup;
6148 615 : item->mIsForSVGAElement = aNameSpaceID == kNameSpaceID_SVG &&
6149 123 : aTag == nsGkAtoms::a;
6150 :
6151 492 : if (canHavePageBreak && display->mBreakAfter) {
6152 0 : AddPageBreakItem(aContent, aItems);
6153 : }
6154 :
6155 492 : if (bits & FCDATA_IS_INLINE) {
6156 : // To correctly set item->mIsAllInline we need to build up our child items
6157 : // right now.
6158 0 : BuildInlineChildItems(aState, *item,
6159 0 : aFlags & ITEM_IS_WITHIN_SVG_TEXT,
6160 0 : aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD);
6161 0 : item->mHasInlineEnds = true;
6162 0 : item->mIsBlock = false;
6163 : } else {
6164 : // Compute a boolean isInline which is guaranteed to be false for blocks
6165 : // (but may also be false for some inlines).
6166 : bool isInline =
6167 : // Table-internal things are inline-outside if and only if they're kids of
6168 : // inlines, since they'll trigger construction of inline-table
6169 : // pseudos.
6170 492 : ((bits & FCDATA_IS_TABLE_PART) &&
6171 0 : (!aParentFrame || // No aParentFrame means inline
6172 492 : aParentFrame->StyleDisplay()->mDisplay == StyleDisplay::Inline)) ||
6173 : // Things that are inline-outside but aren't inline frames are inline
6174 1313 : display->IsInlineOutsideStyle() ||
6175 : // Popups that are certainly out of flow.
6176 492 : isPopup;
6177 :
6178 : // Set mIsAllInline conservatively. It just might be that even an inline
6179 : // that has mIsAllInline false doesn't need an {ib} split. So this is just
6180 : // an optimization to keep from doing too much work in cases when we can
6181 : // show that mIsAllInline is true..
6182 990 : item->mIsAllInline = item->mHasInlineEnds = isInline ||
6183 : // Figure out whether we're guaranteed this item will be out of flow.
6184 : // This is not a precise test, since one of our ancestor inlines might add
6185 : // an absolute containing block (if it's relatively positioned) when there
6186 : // wasn't such a containing block before. But it's conservative in the
6187 : // sense that anything that will really end up as an in-flow non-inline
6188 : // will test false here. In other words, if this test is true we're
6189 : // guaranteed to be inline; if it's false we don't know what we'll end up
6190 : // as.
6191 : //
6192 : // If we make this test precise, we can remove some of the code dealing
6193 : // with the imprecision in ConstructInline and adjust the comments on
6194 : // mIsAllInline and mIsBlock in the header. And probably remove mIsBlock
6195 : // altogether, since then it will always be equal to !mHasInlineEnds.
6196 312 : (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
6197 12 : aState.GetGeometricParent(display, nullptr));
6198 :
6199 : // Set mIsBlock conservatively. It's OK to set it false for some real
6200 : // blocks, but not OK to set it true for things that aren't blocks. Since
6201 : // isOutOfFlow might be false even in cases when the frame will end up
6202 : // out-of-flow, we can't use it here. But we _can_ say that the frame will
6203 : // for sure end up in-flow if it's not floated or absolutely positioned.
6204 1284 : item->mIsBlock = !isInline &&
6205 593 : !display->IsAbsolutelyPositionedStyle() &&
6206 1078 : !display->IsFloatingStyle() &&
6207 293 : !(bits & FCDATA_IS_SVG_TEXT);
6208 : }
6209 :
6210 492 : if (item->mIsAllInline) {
6211 198 : aItems.InlineItemAdded();
6212 294 : } else if (item->mIsBlock) {
6213 293 : aItems.BlockItemAdded();
6214 : }
6215 :
6216 : // Our item should be treated as a line participant if we have the relevant
6217 : // bit and are going to be in-flow. Note that this really only matters if
6218 : // our ancestor is a box or some such, so the fact that we might have an
6219 : // inline ancestor that might become a containing block is not relevant here.
6220 542 : if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
6221 50 : ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
6222 25 : !aState.GetGeometricParent(display, nullptr))) {
6223 25 : item->mIsLineParticipant = true;
6224 25 : aItems.LineParticipantItemAdded();
6225 : }
6226 : }
6227 :
6228 : static void
6229 6 : AddGenConPseudoToFrame(nsIFrame* aOwnerFrame, nsIContent* aContent)
6230 : {
6231 6 : NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aOwnerFrame),
6232 : "property should only be set on first continuation/ib-sibling");
6233 :
6234 : // FIXME(emilio): Remove this property, and use the frame of the generated
6235 : // content itself to tear the content down? It should be quite simpler.
6236 :
6237 : nsIFrame::ContentArray* value =
6238 6 : aOwnerFrame->GetProperty(nsIFrame::GenConProperty());
6239 6 : if (!value) {
6240 4 : value = new nsIFrame::ContentArray;
6241 4 : aOwnerFrame->AddProperty(nsIFrame::GenConProperty(), value);
6242 : }
6243 6 : value->AppendElement(aContent);
6244 6 : }
6245 :
6246 : /**
6247 : * Return true if the frame construction item pointed to by aIter will
6248 : * create a frame adjacent to a line boundary in the frame tree, and that
6249 : * line boundary is induced by a content node adjacent to the frame's
6250 : * content node in the content tree. The latter condition is necessary so
6251 : * that ContentAppended/ContentInserted/ContentRemoved can easily find any
6252 : * text nodes that were suppressed here.
6253 : */
6254 : bool
6255 23 : nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter)
6256 : {
6257 23 : if (aIter.item().mSuppressWhiteSpaceOptimizations) {
6258 0 : return false;
6259 : }
6260 :
6261 23 : if (aIter.AtStart()) {
6262 35 : if (aIter.List()->HasLineBoundaryAtStart() &&
6263 14 : !aIter.item().mContent->GetPreviousSibling())
6264 14 : return true;
6265 : } else {
6266 2 : FCItemIterator prev = aIter;
6267 2 : prev.Prev();
6268 6 : if (prev.item().IsLineBoundary() &&
6269 4 : !prev.item().mSuppressWhiteSpaceOptimizations &&
6270 2 : aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
6271 2 : return true;
6272 : }
6273 :
6274 7 : FCItemIterator next = aIter;
6275 7 : next.Next();
6276 7 : if (next.IsDone()) {
6277 5 : if (aIter.List()->HasLineBoundaryAtEnd() &&
6278 0 : !aIter.item().mContent->GetNextSibling())
6279 0 : return true;
6280 : } else {
6281 6 : if (next.item().IsLineBoundary() &&
6282 4 : !next.item().mSuppressWhiteSpaceOptimizations &&
6283 2 : aIter.item().mContent->GetNextSibling() == next.item().mContent)
6284 2 : return true;
6285 : }
6286 :
6287 5 : return false;
6288 : }
6289 :
6290 : void
6291 492 : nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
6292 : FCItemIterator& aIter,
6293 : nsContainerFrame* aParentFrame,
6294 : nsFrameItems& aFrameItems)
6295 : {
6296 492 : nsContainerFrame* adjParentFrame = aParentFrame;
6297 492 : FrameConstructionItem& item = aIter.item();
6298 492 : nsStyleContext* styleContext = item.mStyleContext;
6299 492 : AdjustParentFrame(&adjParentFrame, item.mFCData, styleContext);
6300 :
6301 492 : if (item.mIsText) {
6302 : // If this is collapsible whitespace next to a line boundary,
6303 : // don't create a frame. item.IsWhitespace() also sets the
6304 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
6305 : // end up creating a frame, nsTextFrame::Init will clear the flag.)
6306 : // We don't do this for generated content, because some generated
6307 : // text content is empty text nodes that are about to be initialized.
6308 : // (We check mAdditionalStateBits because only the generated content
6309 : // container's frame construction item is marked with
6310 : // mIsGeneratedContent, and we might not have an aParentFrame.)
6311 : // We don't do it for content that may have XBL anonymous siblings,
6312 : // because they make it difficult to correctly create the frame
6313 : // due to dynamic changes.
6314 : // We don't do it for SVG text, since we might need to position and
6315 : // measure the white space glyphs due to x/y/dx/dy attributes.
6316 64 : if (AtLineBoundary(aIter) &&
6317 27 : !styleContext->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
6318 18 : aIter.List()->ParentHasNoXBLChildren() &&
6319 17 : !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
6320 16 : (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
6321 16 : !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
6322 39 : !mAlwaysCreateFramesForIgnorableWhitespace &&
6323 8 : item.IsWhitespace(aState))
6324 28 : return;
6325 :
6326 18 : ConstructTextFrame(item.mFCData, aState, item.mContent,
6327 : adjParentFrame, styleContext,
6328 36 : aFrameItems);
6329 18 : return;
6330 : }
6331 :
6332 : // Start background loads during frame construction so that we're
6333 : // guaranteed that they will be started before onload fires.
6334 469 : styleContext->StartBackgroundImageLoads();
6335 :
6336 469 : nsFrameState savedStateBits = aState.mAdditionalStateBits;
6337 469 : if (item.mIsGeneratedContent) {
6338 : // Ensure that frames created here are all tagged with
6339 : // NS_FRAME_GENERATED_CONTENT.
6340 6 : aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
6341 :
6342 : // Note that we're not necessarily setting this property on the primary
6343 : // frame for the content for which this is generated content. We might be
6344 : // setting it on a table pseudo-frame inserted under that instead. That's
6345 : // OK, though; we just need to do the property set so that the content will
6346 : // get cleaned up when the frame is destroyed.
6347 6 : ::AddGenConPseudoToFrame(aParentFrame, item.mContent);
6348 :
6349 : // Now that we've passed ownership of item.mContent to the frame, unset
6350 : // our generated content flag so we don't release or unbind it ourselves.
6351 6 : item.mIsGeneratedContent = false;
6352 : }
6353 :
6354 : // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
6355 469 : ConstructFrameFromItemInternal(item, aState, adjParentFrame, aFrameItems);
6356 :
6357 469 : aState.mAdditionalStateBits = savedStateBits;
6358 : }
6359 :
6360 :
6361 : inline bool
6362 : IsRootBoxFrame(nsIFrame *aFrame)
6363 : {
6364 : return (aFrame->IsRootFrame());
6365 : }
6366 :
6367 : void
6368 0 : nsCSSFrameConstructor::ReconstructDocElementHierarchy()
6369 : {
6370 0 : Element* rootElement = mDocument->GetRootElement();
6371 0 : if (!rootElement) {
6372 : /* nothing to do */
6373 0 : return;
6374 : }
6375 : RecreateFramesForContent(rootElement, false, REMOVE_FOR_RECONSTRUCTION,
6376 0 : nullptr);
6377 : }
6378 :
6379 : nsContainerFrame*
6380 144 : nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame,
6381 : ContainingBlockType aType)
6382 : {
6383 : // Starting with aFrame, look for a frame that is absolutely positioned or
6384 : // relatively positioned (and transformed, if aType is FIXED)
6385 928 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
6386 889 : if (frame->IsFrameOfType(nsIFrame::eMathML)) {
6387 : // If it's mathml, bail out -- no absolute positioning out from inside
6388 : // mathml frames. Note that we don't make this part of the loop
6389 : // condition because of the stuff at the end of this method...
6390 0 : return nullptr;
6391 : }
6392 :
6393 : // Look for the ICB.
6394 889 : if (aType == FIXED_POS) {
6395 553 : LayoutFrameType t = frame->Type();
6396 553 : if (t == LayoutFrameType::Viewport || t == LayoutFrameType::PageContent) {
6397 84 : return static_cast<nsContainerFrame*>(frame);
6398 : }
6399 : }
6400 :
6401 : // If the frame is positioned, we will probably return it as the containing
6402 : // block (see the exceptions below). Otherwise, we'll start looking at the
6403 : // parent frame, unless we're dealing with a scrollframe.
6404 : // Scrollframes are special since they're not positioned, but their
6405 : // scrolledframe might be. So, we need to check this special case to return
6406 : // the correct containing block (the scrolledframe) in that case.
6407 : // If we're looking for a fixed-pos containing block and the frame is
6408 : // not transformed, skip it.
6409 1588 : if (!frame->IsAbsPosContainingBlock() ||
6410 28 : (aType == FIXED_POS &&
6411 28 : !frame->IsFixedPosContainingBlock())) {
6412 783 : continue;
6413 : }
6414 22 : nsIFrame* absPosCBCandidate = frame;
6415 22 : LayoutFrameType type = absPosCBCandidate->Type();
6416 22 : if (type == LayoutFrameType::FieldSet) {
6417 0 : absPosCBCandidate = static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
6418 0 : if (!absPosCBCandidate) {
6419 0 : continue;
6420 : }
6421 0 : type = absPosCBCandidate->Type();
6422 : }
6423 22 : if (type == LayoutFrameType::Scroll) {
6424 2 : nsIScrollableFrame* scrollFrame = do_QueryFrame(absPosCBCandidate);
6425 2 : absPosCBCandidate = scrollFrame->GetScrolledFrame();
6426 2 : if (!absPosCBCandidate) {
6427 0 : continue;
6428 : }
6429 2 : type = absPosCBCandidate->Type();
6430 : }
6431 : // Only first continuations can be containing blocks.
6432 22 : absPosCBCandidate = absPosCBCandidate->FirstContinuation();
6433 : // Is the frame really an absolute container?
6434 22 : if (!absPosCBCandidate->IsAbsoluteContainer()) {
6435 1 : continue;
6436 : }
6437 :
6438 : // For tables, skip the inner frame and consider the table wrapper frame.
6439 21 : if (type == LayoutFrameType::Table) {
6440 0 : continue;
6441 : }
6442 : // For table wrapper frames, we can just return absPosCBCandidate.
6443 21 : MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(absPosCBCandidate),
6444 : "abs.pos. containing block must be nsContainerFrame sub-class");
6445 21 : return static_cast<nsContainerFrame*>(absPosCBCandidate);
6446 : }
6447 :
6448 39 : MOZ_ASSERT(aType != FIXED_POS, "no ICB in this frame tree?");
6449 :
6450 : // It is possible for the search for the containing block to fail, because
6451 : // no absolute container can be found in the parent chain. In those cases,
6452 : // we fall back to the document element's containing block.
6453 39 : return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr;
6454 : }
6455 :
6456 : nsContainerFrame*
6457 79 : nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
6458 : {
6459 : // Starting with aFrame, look for a frame that is a float containing block.
6460 : // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
6461 : // frames, because they don't seem to be able to deal.
6462 : // The logic here needs to match the logic in ProcessChildren()
6463 416 : for (nsIFrame* containingBlock = aFrame;
6464 391 : containingBlock &&
6465 183 : !ShouldSuppressFloatingOfDescendants(containingBlock);
6466 : containingBlock = containingBlock->GetParent()) {
6467 144 : if (containingBlock->IsFloatContainingBlock()) {
6468 15 : MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(containingBlock),
6469 : "float containing block must be nsContainerFrame sub-class");
6470 15 : return static_cast<nsContainerFrame*>(containingBlock);
6471 : }
6472 : }
6473 :
6474 : // If we didn't find a containing block, then there just isn't
6475 : // one.... return null
6476 64 : return nullptr;
6477 : }
6478 :
6479 : /**
6480 : * This function will check whether aContainer has :after generated content.
6481 : * If so, appending to it should actually insert. The return value is the
6482 : * parent to use for newly-appended content. *aAfterFrame points to the :after
6483 : * frame before which appended content should go, if there is one.
6484 : */
6485 : static nsContainerFrame*
6486 41 : AdjustAppendParentForAfterContent(nsFrameManager* aFrameManager,
6487 : nsIContent* aContainer,
6488 : nsContainerFrame* aParentFrame,
6489 : nsIContent* aChild,
6490 : nsIFrame** aAfterFrame)
6491 : {
6492 : // If the parent frame has any pseudo-elements or aContainer is a
6493 : // display:contents node then we need to walk through the child
6494 : // frames to find the first one that is either a ::after frame for an
6495 : // ancestor of aChild or a frame that is for a node later in the
6496 : // document than aChild and return that in aAfterFrame.
6497 123 : if (aParentFrame->GetProperty(nsIFrame::GenConProperty()) ||
6498 41 : nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(),
6499 : CSSPseudoElementType::after,
6500 82 : aParentFrame->PresContext()) ||
6501 41 : aFrameManager->GetDisplayContentsStyleFor(aContainer)) {
6502 0 : nsIFrame* afterFrame = nullptr;
6503 : nsContainerFrame* parent =
6504 0 : static_cast<nsContainerFrame*>(aParentFrame->LastContinuation());
6505 0 : bool done = false;
6506 0 : while (!done && parent) {
6507 : // Ensure that all normal flow children are on the principal child list.
6508 0 : parent->DrainSelfOverflowList();
6509 :
6510 0 : nsIFrame* child = parent->GetChildList(nsIFrame::kPrincipalList).LastChild();
6511 0 : if (child && child->IsPseudoFrame(aContainer) &&
6512 0 : !child->IsGeneratedContentFrame()) {
6513 : // Drill down into non-generated pseudo frames of aContainer.
6514 0 : nsContainerFrame* childAsContainer = do_QueryFrame(child);
6515 0 : if (childAsContainer) {
6516 0 : parent = nsLayoutUtils::LastContinuationWithChild(childAsContainer);
6517 0 : continue;
6518 : }
6519 : }
6520 :
6521 0 : for (; child; child = child->GetPrevSibling()) {
6522 0 : nsIContent* c = child->GetContent();
6523 0 : if (child->IsGeneratedContentFrame()) {
6524 0 : nsIContent* p = c->GetParent();
6525 0 : if (c->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) {
6526 0 : if (!nsContentUtils::ContentIsDescendantOf(aChild, p) &&
6527 0 : p != aContainer &&
6528 0 : nsContentUtils::PositionIsBefore(p, aChild)) {
6529 : // ::after generated content for content earlier in the doc and not
6530 : // for an ancestor. "p != aContainer" may seem redundant but it
6531 : // checks if the ::after belongs to the XBL insertion point we're
6532 : // inserting aChild into (in which case ContentIsDescendantOf is
6533 : // false even though p == aContainer).
6534 : // See layout/reftests/bugs/482592-1a.xhtml for an example of that.
6535 0 : done = true;
6536 0 : break;
6537 : }
6538 0 : } else if (nsContentUtils::PositionIsBefore(p, aChild)) {
6539 : // Non-::after generated content for content earlier in the doc.
6540 0 : done = true;
6541 0 : break;
6542 : }
6543 0 : } else if (nsContentUtils::PositionIsBefore(c, aChild)) {
6544 : // Content is before aChild.
6545 0 : done = true;
6546 0 : break;
6547 : }
6548 0 : afterFrame = child;
6549 : }
6550 :
6551 0 : parent = static_cast<nsContainerFrame*>(parent->GetPrevContinuation());
6552 : }
6553 0 : if (afterFrame) {
6554 0 : *aAfterFrame = afterFrame;
6555 0 : return afterFrame->GetParent();
6556 : }
6557 : }
6558 :
6559 41 : *aAfterFrame = nullptr;
6560 :
6561 41 : if (IsFramePartOfIBSplit(aParentFrame)) {
6562 : // We might be in a situation where the last part of the {ib} split was
6563 : // empty. Since we have no ::after pseudo-element, we do in fact want to be
6564 : // appending to that last part, so advance to it if needed. Note that here
6565 : // aParentFrame is the result of a GetLastIBSplitSibling call, so must be
6566 : // either the last or next to last ib-split sibling.
6567 0 : nsContainerFrame* trailingInline = GetIBSplitSibling(aParentFrame);
6568 0 : if (trailingInline) {
6569 0 : aParentFrame = trailingInline;
6570 : }
6571 :
6572 : // Always make sure to look at the last continuation of the frame
6573 : // for the {ib} case, even if that continuation is empty. We
6574 : // don't do this for the non-ib-split-frame case, since in the
6575 : // other cases appending to the last nonempty continuation is fine
6576 : // and in fact not doing that can confuse code that doesn't know
6577 : // to pull kids from continuations other than its next one.
6578 : aParentFrame =
6579 0 : static_cast<nsContainerFrame*>(aParentFrame->LastContinuation());
6580 : }
6581 :
6582 41 : return aParentFrame;
6583 : }
6584 :
6585 : /**
6586 : * This function will get the previous sibling to use for an append operation.
6587 : * it takes a parent frame (must not be null) and its :after frame (may be
6588 : * null).
6589 : */
6590 : static nsIFrame*
6591 41 : FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame)
6592 : {
6593 41 : if (aAfterFrame) {
6594 0 : NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent");
6595 0 : NS_ASSERTION(aAfterFrame->GetPrevSibling() ||
6596 : aParentFrame->PrincipalChildList().FirstChild() == aAfterFrame,
6597 : ":after frame must be on the principal child list here");
6598 0 : return aAfterFrame->GetPrevSibling();
6599 : }
6600 :
6601 41 : aParentFrame->DrainSelfOverflowList();
6602 :
6603 41 : return aParentFrame->GetChildList(kPrincipalList).LastChild();
6604 : }
6605 :
6606 : /**
6607 : * This function will get the next sibling for a frame insert operation given
6608 : * the parent and previous sibling. aPrevSibling may be null.
6609 : */
6610 : static nsIFrame*
6611 72 : GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
6612 : {
6613 72 : if (aPrevSibling) {
6614 29 : return aPrevSibling->GetNextSibling();
6615 : }
6616 :
6617 43 : return aParentFrame->PrincipalChildList().FirstChild();
6618 : }
6619 :
6620 : /**
6621 : * This function is called by ContentAppended() and ContentInserted() when
6622 : * appending flowed frames to a parent's principal child list. It handles the
6623 : * case where the parent is the trailing inline of an {ib} split.
6624 : */
6625 : void
6626 28 : nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aState,
6627 : nsContainerFrame* aParentFrame,
6628 : nsFrameItems& aFrameList,
6629 : nsIFrame* aPrevSibling,
6630 : bool aIsRecursiveCall)
6631 : {
6632 28 : NS_PRECONDITION(!IsFramePartOfIBSplit(aParentFrame) ||
6633 : !GetIBSplitSibling(aParentFrame) ||
6634 : !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild(),
6635 : "aParentFrame has a ib-split sibling with kids?");
6636 28 : NS_PRECONDITION(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
6637 : "Parent and prevsibling don't match");
6638 :
6639 28 : nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
6640 :
6641 28 : NS_ASSERTION(nextSibling ||
6642 : !aParentFrame->GetNextContinuation() ||
6643 : !aParentFrame->GetNextContinuation()->PrincipalChildList().FirstChild() ||
6644 : aIsRecursiveCall,
6645 : "aParentFrame has later continuations with kids?");
6646 28 : NS_ASSERTION(nextSibling ||
6647 : !IsFramePartOfIBSplit(aParentFrame) ||
6648 : (IsInlineFrame(aParentFrame) &&
6649 : !GetIBSplitSibling(aParentFrame) &&
6650 : !aParentFrame->GetNextContinuation()) ||
6651 : aIsRecursiveCall,
6652 : "aParentFrame is not last?");
6653 :
6654 : // If we're inserting a list of frames at the end of the trailing inline
6655 : // of an {ib} split, we may need to create additional {ib} siblings to parent
6656 : // them.
6657 28 : if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
6658 : // When we get here, our frame list might start with a block. If it does
6659 : // so, and aParentFrame is an inline, and it and all its previous
6660 : // continuations have no siblings, then put the initial blocks from the
6661 : // frame list into the previous block of the {ib} split. Note that we
6662 : // didn't want to stop at the block part of the split when figuring out
6663 : // initial parent, because that could screw up float parenting; it's easier
6664 : // to do this little fixup here instead.
6665 0 : if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) {
6666 : // See whether our trailing inline is empty
6667 0 : nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
6668 0 : if (firstContinuation->PrincipalChildList().IsEmpty()) {
6669 : // Our trailing inline is empty. Collect our starting blocks from
6670 : // aFrameList, get the right parent frame for them, and put them in.
6671 : nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator =
6672 0 : FindFirstNonBlock(aFrameList);
6673 0 : nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator);
6674 0 : NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
6675 :
6676 0 : nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
6677 0 : prevBlock = static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
6678 0 : NS_ASSERTION(prevBlock, "Should have previous block here");
6679 :
6680 0 : MoveChildrenTo(aParentFrame, prevBlock, blockKids);
6681 : }
6682 : }
6683 :
6684 : // We want to put some of the frames into this inline frame.
6685 0 : nsFrameList::FrameLinkEnumerator firstBlockEnumerator(aFrameList);
6686 0 : FindFirstBlock(firstBlockEnumerator);
6687 :
6688 0 : nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
6689 0 : if (!inlineKids.IsEmpty()) {
6690 0 : AppendFrames(aParentFrame, kPrincipalList, inlineKids);
6691 : }
6692 :
6693 0 : if (!aFrameList.IsEmpty()) {
6694 0 : bool positioned = aParentFrame->IsRelativelyPositioned();
6695 0 : nsFrameItems ibSiblings;
6696 0 : CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
6697 0 : ibSiblings);
6698 :
6699 : // Make sure to trigger reflow of the inline that used to be our
6700 : // last one and now isn't anymore, since its GetSkipSides() has
6701 : // changed.
6702 0 : mPresShell->FrameNeedsReflow(aParentFrame,
6703 : nsIPresShell::eTreeChange,
6704 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
6705 :
6706 : // Recurse so we create new ib siblings as needed for aParentFrame's parent
6707 0 : return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
6708 0 : aParentFrame, true);
6709 : }
6710 0 : return;
6711 : }
6712 :
6713 : // Insert the frames after our aPrevSibling
6714 28 : InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
6715 : }
6716 :
6717 : #define UNSET_DISPLAY static_cast<StyleDisplay>(255)
6718 :
6719 : // This gets called to see if the frames corresponding to aSibling and aContent
6720 : // should be siblings in the frame tree. Although (1) rows and cols, (2) row
6721 : // groups and col groups, (3) row groups and captions, (4) legends and content
6722 : // inside fieldsets, (5) popups and other kids of the menu are siblings from a
6723 : // content perspective, they are not considered siblings in the frame tree.
6724 : bool
6725 19 : nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
6726 : nsIContent* aContent,
6727 : StyleDisplay& aDisplay)
6728 : {
6729 19 : nsIFrame* parentFrame = aSibling->GetParent();
6730 19 : LayoutFrameType parentType = parentFrame->Type();
6731 :
6732 19 : StyleDisplay siblingDisplay = aSibling->GetDisplay();
6733 19 : if (StyleDisplay::TableColumnGroup == siblingDisplay ||
6734 19 : StyleDisplay::TableColumn == siblingDisplay ||
6735 19 : StyleDisplay::TableCaption == siblingDisplay ||
6736 19 : StyleDisplay::TableHeaderGroup == siblingDisplay ||
6737 19 : StyleDisplay::TableRowGroup == siblingDisplay ||
6738 19 : StyleDisplay::TableFooterGroup == siblingDisplay ||
6739 : LayoutFrameType::Menu == parentType) {
6740 : // if we haven't already, construct a style context to find the display type of aContent
6741 0 : if (UNSET_DISPLAY == aDisplay) {
6742 : nsIFrame* styleParent;
6743 0 : aSibling->GetParentStyleContext(&styleParent);
6744 0 : if (!styleParent) {
6745 0 : styleParent = aSibling->GetParent();
6746 : }
6747 0 : if (!styleParent) {
6748 0 : NS_NOTREACHED("Shouldn't happen");
6749 0 : return false;
6750 : }
6751 0 : if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
6752 0 : aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
6753 : // Comments and processing instructions never have frames, so we
6754 : // should not try to generate style contexts for them.
6755 0 : return false;
6756 : }
6757 : // XXXbz when this code is killed, the state argument to
6758 : // ResolveStyleContext can be made non-optional.
6759 : RefPtr<nsStyleContext> styleContext =
6760 0 : ResolveStyleContext(styleParent, aContent, nullptr);
6761 0 : const nsStyleDisplay* display = styleContext->StyleDisplay();
6762 0 : aDisplay = display->mDisplay;
6763 : }
6764 0 : if (LayoutFrameType::Menu == parentType) {
6765 : return
6766 0 : (StyleDisplay::MozPopup == aDisplay) ==
6767 0 : (StyleDisplay::MozPopup == siblingDisplay);
6768 : }
6769 : // To have decent performance we want to return false in cases in which
6770 : // reordering the two siblings has no effect on display. To ensure
6771 : // correctness, we MUST return false in cases where the two siblings have
6772 : // the same desired parent type and live on different display lists.
6773 : // Specificaly, columns and column groups should only consider columns and
6774 : // column groups as valid siblings. Captions should only consider other
6775 : // captions. All other things should consider each other as valid
6776 : // siblings. The restriction in the |if| above on siblingDisplay is ok,
6777 : // because for correctness the only part that really needs to happen is to
6778 : // not consider captions, column groups, and row/header/footer groups
6779 : // siblings of each other. Treating a column or colgroup as a valid
6780 : // sibling of a non-table-related frame will just mean we end up reframing.
6781 0 : if ((siblingDisplay == StyleDisplay::TableCaption) !=
6782 0 : (aDisplay == StyleDisplay::TableCaption)) {
6783 : // One's a caption and the other is not. Not valid siblings.
6784 0 : return false;
6785 : }
6786 :
6787 0 : if ((siblingDisplay == StyleDisplay::TableColumnGroup ||
6788 0 : siblingDisplay == StyleDisplay::TableColumn) !=
6789 0 : (aDisplay == StyleDisplay::TableColumnGroup ||
6790 0 : aDisplay == StyleDisplay::TableColumn)) {
6791 : // One's a column or column group and the other is not. Not valid
6792 : // siblings.
6793 0 : return false;
6794 : }
6795 : // Fall through; it's possible that the display type was overridden and
6796 : // a different sort of frame was constructed, so we may need to return false
6797 : // below.
6798 : }
6799 :
6800 19 : if (IsFrameForFieldSet(parentFrame)) {
6801 : // Legends can be sibling of legends but not of other content in the fieldset
6802 0 : if (nsContainerFrame* cif = aSibling->GetContentInsertionFrame()) {
6803 0 : aSibling = cif;
6804 : }
6805 0 : LayoutFrameType sibType = aSibling->Type();
6806 0 : bool legendContent = aContent->IsHTMLElement(nsGkAtoms::legend);
6807 :
6808 0 : if ((legendContent && (LayoutFrameType::Legend != sibType)) ||
6809 0 : (!legendContent && (LayoutFrameType::Legend == sibType)))
6810 0 : return false;
6811 : }
6812 :
6813 19 : return true;
6814 : }
6815 :
6816 : nsIFrame*
6817 34 : nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
6818 : nsIContent* aTargetContent,
6819 : StyleDisplay& aTargetContentDisplay,
6820 : nsContainerFrame* aParentFrame,
6821 : bool aPrevSibling)
6822 : {
6823 34 : nsIFrame* sibling = aContent->GetPrimaryFrame();
6824 34 : if (!sibling && GetDisplayContentsStyleFor(aContent)) {
6825 : // A display:contents node - check if it has a ::before / ::after frame...
6826 0 : sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
6827 : : nsLayoutUtils::GetBeforeFrame(aContent);
6828 0 : if (!sibling) {
6829 : // ... then recurse into children ...
6830 0 : const bool forward = !aPrevSibling;
6831 0 : FlattenedChildIterator iter(aContent, forward);
6832 0 : sibling = aPrevSibling ?
6833 0 : FindPreviousSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame) :
6834 0 : FindNextSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame);
6835 : }
6836 0 : if (!sibling) {
6837 : // ... then ::after / ::before on the opposite end.
6838 0 : sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
6839 : : nsLayoutUtils::GetBeforeFrame(aContent);
6840 : }
6841 0 : if (!sibling) {
6842 0 : return nullptr;
6843 : }
6844 34 : } else if (!sibling || sibling->GetContent() != aContent) {
6845 : // XXX the GetContent() != aContent check is needed due to bug 135040.
6846 : // Remove it once that's fixed.
6847 15 : return nullptr;
6848 : }
6849 :
6850 : // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
6851 : // out-of-flow frame; we want the placeholder.
6852 19 : if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
6853 0 : nsIFrame* placeholderFrame = sibling->GetPlaceholderFrame();
6854 0 : NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
6855 0 : sibling = placeholderFrame;
6856 : }
6857 :
6858 : // The frame we have now should never be a continuation
6859 19 : NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?");
6860 :
6861 19 : if (aPrevSibling) {
6862 : // The frame may be a ib-split frame (a split inline frame that
6863 : // contains a block). Get the last part of that split.
6864 11 : if (IsFramePartOfIBSplit(sibling)) {
6865 0 : sibling = GetLastIBSplitSibling(sibling, true);
6866 : }
6867 :
6868 : // The frame may have a continuation. If so, we want the last
6869 : // non-overflow-container continuation as our previous sibling.
6870 11 : sibling = sibling->GetTailContinuation();
6871 : }
6872 :
6873 38 : if (aTargetContent &&
6874 19 : !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) {
6875 0 : sibling = nullptr;
6876 : }
6877 :
6878 19 : return sibling;
6879 : }
6880 :
6881 : nsIFrame*
6882 33 : nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter,
6883 : nsIContent* aTargetContent,
6884 : StyleDisplay& aTargetContentDisplay,
6885 : nsContainerFrame* aParentFrame)
6886 : {
6887 : // Note: not all content objects are associated with a frame (e.g., if it's
6888 : // `display: none') so keep looking until we find a previous frame.
6889 33 : while (nsIContent* sibling = aIter.GetPreviousChild()) {
6890 20 : MOZ_ASSERT(sibling != aTargetContent);
6891 : nsIFrame* prevSibling =
6892 : FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
6893 20 : aParentFrame, true);
6894 20 : if (prevSibling) {
6895 : // Found a previous sibling, we're done!
6896 11 : return prevSibling;
6897 : }
6898 9 : }
6899 :
6900 13 : return nullptr;
6901 : }
6902 :
6903 : nsIFrame*
6904 19 : nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter,
6905 : nsIContent* aTargetContent,
6906 : StyleDisplay& aTargetContentDisplay,
6907 : nsContainerFrame* aParentFrame)
6908 : {
6909 19 : while (nsIContent* sibling = aIter.GetNextChild()) {
6910 14 : MOZ_ASSERT(sibling != aTargetContent);
6911 : nsIFrame* nextSibling =
6912 : FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
6913 14 : aParentFrame, false);
6914 :
6915 14 : if (nextSibling) {
6916 : // We found a next sibling, we're done!
6917 8 : return nextSibling;
6918 : }
6919 6 : }
6920 :
6921 5 : return nullptr;
6922 : }
6923 :
6924 : // For fieldsets, returns the area frame, if the child is not a legend.
6925 : static nsContainerFrame*
6926 5 : GetAdjustedParentFrame(nsContainerFrame* aParentFrame,
6927 : nsIContent* aChildContent)
6928 : {
6929 5 : NS_PRECONDITION(!aParentFrame->IsTableWrapperFrame(),
6930 : "Shouldn't be happening!");
6931 :
6932 5 : nsContainerFrame* newParent = nullptr;
6933 :
6934 5 : if (aParentFrame->IsFieldSetFrame()) {
6935 : // If the parent is a fieldSet, use the fieldSet's area frame as the
6936 : // parent unless the new content is a legend.
6937 0 : if (!aChildContent->IsHTMLElement(nsGkAtoms::legend)) {
6938 0 : newParent = GetFieldSetBlockFrame(aParentFrame);
6939 : }
6940 : }
6941 5 : return newParent ? newParent : aParentFrame;
6942 : }
6943 :
6944 : nsIFrame*
6945 24 : nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
6946 : nsIContent* aChild,
6947 : bool* aIsAppend,
6948 : bool* aIsRangeInsertSafe,
6949 : nsIContent* aStartSkipChild,
6950 : nsIContent* aEndSkipChild)
6951 : {
6952 24 : NS_PRECONDITION(aInsertion->mParentFrame, "Must have parent frame to start with");
6953 :
6954 24 : *aIsAppend = false;
6955 :
6956 : // Find the frame that precedes the insertion point. Walk backwards
6957 : // from the parent frame to get the parent content, because if an
6958 : // XBL insertion point is involved, we'll need to use _that_ to find
6959 : // the preceding frame.
6960 48 : FlattenedChildIterator iter(aInsertion->mContainer);
6961 39 : bool xblCase = iter.XBLInvolved() ||
6962 39 : aInsertion->mParentFrame->GetContent() != aInsertion->mContainer;
6963 24 : if (xblCase || !aChild->IsRootOfAnonymousSubtree()) {
6964 : // The check for IsRootOfAnonymousSubtree() is because editor is
6965 : // severely broken and calls us directly for native anonymous
6966 : // nodes that it creates.
6967 24 : if (aStartSkipChild) {
6968 0 : iter.Seek(aStartSkipChild);
6969 : } else {
6970 24 : iter.Seek(aChild);
6971 : }
6972 : } else {
6973 : // Prime the iterator for the call to FindPreviousSibling.
6974 0 : iter.GetNextChild();
6975 0 : MOZ_ASSERT(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
6976 : "Someone passed native anonymous content directly into frame "
6977 : "construction. Stop doing that!");
6978 : }
6979 :
6980 : // Note that FindPreviousSibling is passed the iterator by value, so that
6981 : // the later usage of the iterator starts from the same place.
6982 24 : StyleDisplay childDisplay = UNSET_DISPLAY;
6983 : nsIFrame* prevSibling =
6984 24 : FindPreviousSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
6985 :
6986 : // Now, find the geometric parent so that we can handle
6987 : // continuations properly. Use the prev sibling if we have it;
6988 : // otherwise use the next sibling.
6989 24 : if (prevSibling) {
6990 11 : aInsertion->mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
6991 : } else {
6992 : // If there is no previous sibling, then find the frame that follows
6993 13 : if (aEndSkipChild) {
6994 0 : iter.Seek(aEndSkipChild);
6995 0 : iter.GetPreviousChild();
6996 : }
6997 : nsIFrame* nextSibling =
6998 13 : FindNextSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
6999 13 : if (GetDisplayContentsStyleFor(aInsertion->mContainer)) {
7000 0 : if (!nextSibling) {
7001 : // Our siblings (if any) does not have a frame to guide us.
7002 : // The frame for aChild should be inserted whereever a frame for
7003 : // the container would be inserted. This is needed when inserting
7004 : // into nested display:contents nodes.
7005 0 : nsIContent* child = aInsertion->mContainer;
7006 0 : nsIContent* parent = child->GetParent();
7007 0 : aInsertion->mParentFrame =
7008 0 : ::GetAdjustedParentFrame(aInsertion->mParentFrame, parent);
7009 0 : InsertionPoint fakeInsertion(aInsertion->mParentFrame, parent);
7010 : nsIFrame* result = GetInsertionPrevSibling(&fakeInsertion, child, aIsAppend,
7011 0 : aIsRangeInsertSafe, nullptr, nullptr);
7012 0 : MOZ_ASSERT(aInsertion->mParentFrame->GetContent() ==
7013 : fakeInsertion.mParentFrame->GetContent());
7014 : // fakeInsertion.mParentFrame may now be a continuation of the frame
7015 : // we started with in the ctor above.
7016 0 : aInsertion->mParentFrame = fakeInsertion.mParentFrame;
7017 0 : return result;
7018 : }
7019 :
7020 0 : prevSibling = nextSibling->GetPrevSibling();
7021 : }
7022 :
7023 13 : if (nextSibling) {
7024 8 : aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7025 : } else {
7026 : // No previous or next sibling, so treat this like an appended frame.
7027 5 : *aIsAppend = true;
7028 5 : if (IsFramePartOfIBSplit(aInsertion->mParentFrame)) {
7029 : // Since we're appending, we'll walk to the last anonymous frame
7030 : // that was created for the broken inline frame. But don't walk
7031 : // to the trailing inline if it's empty; stop at the block.
7032 0 : aInsertion->mParentFrame =
7033 0 : GetLastIBSplitSibling(aInsertion->mParentFrame, false);
7034 : }
7035 : // Get continuation that parents the last child. This MUST be done
7036 : // before the AdjustAppendParentForAfterContent call.
7037 5 : aInsertion->mParentFrame =
7038 5 : nsLayoutUtils::LastContinuationWithChild(aInsertion->mParentFrame);
7039 : // Deal with fieldsets
7040 5 : aInsertion->mParentFrame =
7041 5 : ::GetAdjustedParentFrame(aInsertion->mParentFrame, aChild);
7042 : nsIFrame* appendAfterFrame;
7043 5 : aInsertion->mParentFrame =
7044 5 : ::AdjustAppendParentForAfterContent(this, aInsertion->mContainer,
7045 : aInsertion->mParentFrame,
7046 : aChild, &appendAfterFrame);
7047 5 : prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, appendAfterFrame);
7048 : }
7049 : }
7050 :
7051 24 : *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
7052 24 : return prevSibling;
7053 : }
7054 :
7055 : nsContainerFrame*
7056 210 : nsCSSFrameConstructor::GetContentInsertionFrameFor(nsIContent* aContent)
7057 : {
7058 : // Get the primary frame associated with the content
7059 210 : nsIFrame* frame = aContent->GetPrimaryFrame();
7060 :
7061 210 : if (!frame) {
7062 45 : if (GetDisplayContentsStyleFor(aContent)) {
7063 0 : nsIContent* parent = aContent->GetParent();
7064 0 : if (parent && parent == aContent->GetContainingShadow()) {
7065 0 : parent = parent->GetBindingParent();
7066 : }
7067 0 : frame = parent ? GetContentInsertionFrameFor(parent) : nullptr;
7068 : }
7069 45 : if (!frame) {
7070 45 : return nullptr;
7071 : }
7072 : } else {
7073 : // If the content of the frame is not the desired content then this is not
7074 : // really a frame for the desired content.
7075 : // XXX This check is needed due to bug 135040. Remove it once that's fixed.
7076 165 : if (frame->GetContent() != aContent) {
7077 0 : return nullptr;
7078 : }
7079 : }
7080 :
7081 165 : nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
7082 :
7083 165 : NS_ASSERTION(!insertionFrame || insertionFrame == frame || !frame->IsLeaf(),
7084 : "The insertion frame is the primary frame or the primary frame isn't a leaf");
7085 :
7086 165 : return insertionFrame;
7087 : }
7088 :
7089 : static bool
7090 0 : IsSpecialFramesetChild(nsIContent* aContent)
7091 : {
7092 : // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
7093 0 : return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
7094 : }
7095 :
7096 : static void
7097 : InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
7098 :
7099 : #ifdef MOZ_XUL
7100 :
7101 : static
7102 : bool
7103 69 : IsXULListBox(nsIContent* aContainer)
7104 : {
7105 69 : return (aContainer->IsXULElement(nsGkAtoms::listbox));
7106 : }
7107 :
7108 : static
7109 : nsListBoxBodyFrame*
7110 28 : MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild)
7111 : {
7112 28 : if (!aContainer)
7113 0 : return nullptr;
7114 :
7115 28 : if (IsXULListBox(aContainer) &&
7116 0 : aChild->IsXULElement(nsGkAtoms::listitem)) {
7117 0 : RefPtr<nsXULElement> xulElement = nsXULElement::FromContent(aContainer);
7118 0 : IgnoredErrorResult ignored;
7119 0 : nsCOMPtr<nsIBoxObject> boxObject = xulElement->GetBoxObject(ignored);
7120 0 : nsCOMPtr<nsPIListBoxObject> listBoxObject = do_QueryInterface(boxObject);
7121 0 : if (listBoxObject) {
7122 0 : return listBoxObject->GetListBoxBody(false);
7123 : }
7124 : }
7125 :
7126 28 : return nullptr;
7127 : }
7128 : #endif // MOZ_XUL
7129 :
7130 : void
7131 43 : nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState& aState,
7132 : const InsertionPoint& aInsertion,
7133 : nsIContent* aPossibleTextContent,
7134 : FrameConstructionItemList& aItems)
7135 : {
7136 43 : NS_PRECONDITION(aPossibleTextContent, "Must have node");
7137 43 : if (!aPossibleTextContent->IsNodeOfType(nsINode::eTEXT) ||
7138 0 : !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
7139 : // Not text, or not suppressed due to being all-whitespace (if it
7140 : // were being suppressed, it would have the
7141 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
7142 43 : return;
7143 : }
7144 0 : NS_ASSERTION(!aPossibleTextContent->GetPrimaryFrame(),
7145 : "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
7146 : AddFrameConstructionItems(aState, aPossibleTextContent, false,
7147 0 : aInsertion, aItems);
7148 : }
7149 :
7150 : void
7151 0 : nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent,
7152 : nsIContent* aContent)
7153 : {
7154 0 : if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
7155 0 : !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
7156 : // Not text, or not suppressed due to being all-whitespace (if it
7157 : // were being suppressed, it would have the
7158 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
7159 0 : return;
7160 : }
7161 0 : NS_ASSERTION(!aContent->GetPrimaryFrame(),
7162 : "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
7163 0 : ContentInserted(aParentContent, aContent, nullptr, false);
7164 : }
7165 :
7166 : // For inserts aChild should be valid, for appends it should be null.
7167 : // Returns true if this operation can be lazy, false if not.
7168 : bool
7169 61 : nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
7170 : nsIContent* aContainer,
7171 : nsIContent* aChild)
7172 : {
7173 : // XXXmats no lazy frames for display:contents direct descendants yet
7174 : // (bug 979782).
7175 190 : if (mPresShell->GetPresContext()->IsChrome() || !aContainer ||
7176 163 : aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement() ||
7177 34 : GetDisplayContentsStyleFor(aContainer)) {
7178 27 : return false;
7179 : }
7180 :
7181 34 : if (aOperation == CONTENTINSERT) {
7182 0 : if (aChild->IsRootOfAnonymousSubtree() ||
7183 0 : (aChild->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
7184 0 : !aChild->IsInNativeAnonymousSubtree()) ||
7185 0 : aChild->IsEditable() || aChild->IsXULElement()) {
7186 0 : return false;
7187 : }
7188 : } else { // CONTENTAPPEND
7189 34 : NS_ASSERTION(aOperation == CONTENTAPPEND,
7190 : "operation should be either insert or append");
7191 146 : for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
7192 112 : NS_ASSERTION(!child->IsRootOfAnonymousSubtree(),
7193 : "Should be coming through the CONTENTAPPEND case");
7194 112 : if (child->IsXULElement() || child->IsEditable()) {
7195 0 : return false;
7196 : }
7197 : }
7198 : }
7199 :
7200 : // We can construct lazily; just need to set suitable bits in the content
7201 : // tree.
7202 :
7203 : // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
7204 34 : nsIContent* content = aContainer;
7205 :
7206 : #ifdef DEBUG
7207 : // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
7208 : // we want to assert, but leaf frames that process their own children and may
7209 : // ignore anonymous children (eg framesets) make this complicated. So we set
7210 : // these two booleans if we encounter these situations and unset them if we
7211 : // hit a node with a leaf frame.
7212 : //
7213 : // Also, it's fine if one of the nodes without primary frame is a display:
7214 : // contents node except if it's the direct ancestor of the children we're
7215 : // recreating frames for.
7216 34 : bool noPrimaryFrame = false;
7217 34 : bool needsFrameBitSet = false;
7218 : #endif
7219 132 : while (content &&
7220 40 : !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
7221 : #ifdef DEBUG
7222 29 : if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
7223 0 : noPrimaryFrame = needsFrameBitSet = false;
7224 : }
7225 29 : if (!noPrimaryFrame && !content->GetPrimaryFrame() &&
7226 0 : !GetDisplayContentsStyleFor(content)) {
7227 0 : noPrimaryFrame = true;
7228 : }
7229 29 : if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
7230 0 : needsFrameBitSet = true;
7231 : }
7232 : #endif
7233 29 : content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
7234 29 : content = content->GetFlattenedTreeParent();
7235 : }
7236 : #ifdef DEBUG
7237 45 : if (content && content->GetPrimaryFrame() &&
7238 11 : content->GetPrimaryFrame()->IsLeaf()) {
7239 0 : noPrimaryFrame = needsFrameBitSet = false;
7240 : }
7241 34 : NS_ASSERTION(!noPrimaryFrame, "Ancestors of nodes with frames to be "
7242 : "constructed lazily should have frames");
7243 34 : NS_ASSERTION(!needsFrameBitSet, "Ancestors of nodes with frames to be "
7244 : "constructed lazily should not have NEEDS_FRAME bit set");
7245 : #endif
7246 :
7247 : // Set NODE_NEEDS_FRAME on the new nodes.
7248 34 : if (aOperation == CONTENTINSERT) {
7249 0 : NS_ASSERTION(!aChild->GetPrimaryFrame() ||
7250 : aChild->GetPrimaryFrame()->GetContent() != aChild,
7251 : //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
7252 : // check is needed due to bug 135040. Remove it once that's
7253 : // fixed.
7254 : "setting NEEDS_FRAME on a node that already has a frame?");
7255 0 : aChild->SetFlags(NODE_NEEDS_FRAME);
7256 : } else { // CONTENTAPPEND
7257 146 : for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
7258 112 : NS_ASSERTION(!child->GetPrimaryFrame() ||
7259 : child->GetPrimaryFrame()->GetContent() != child,
7260 : //XXX the child->GetPrimaryFrame()->GetContent() != child
7261 : // check is needed due to bug 135040. Remove it once that's
7262 : // fixed.
7263 : "setting NEEDS_FRAME on a node that already has a frame?");
7264 112 : child->SetFlags(NODE_NEEDS_FRAME);
7265 : }
7266 : }
7267 :
7268 34 : if (mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->GetAsGecko()) {
7269 34 : geckoRM->PostRestyleEventForLazyConstruction();
7270 : }
7271 :
7272 34 : return true;
7273 : }
7274 :
7275 : void
7276 29 : nsCSSFrameConstructor::CreateNeededFrames(
7277 : nsIContent* aContent,
7278 : TreeMatchContext& aTreeMatchContext)
7279 : {
7280 29 : MOZ_ASSERT(!aContent->IsStyledByServo());
7281 29 : NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME),
7282 : "shouldn't get here with a content node that has needs frame bit set");
7283 29 : NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
7284 : "should only get here with a content node that has descendants needing frames");
7285 29 : MOZ_ASSERT(aTreeMatchContext.mAncestorFilter.HasFilter(),
7286 : "The whole point of having the tree match context is optimizing "
7287 : "the ancestor filter usage!");
7288 :
7289 29 : aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
7290 :
7291 : // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
7292 : // set) or issue content notifications for our kids first. In absence of
7293 : // anything definitive either way we'll go with the latter.
7294 :
7295 : // It might be better to use GetChildArray and scan it completely first and
7296 : // then issue all notifications. (We have to scan it completely first because
7297 : // constructing frames can set attributes, which can change the storage of
7298 : // child lists).
7299 :
7300 : // Scan the children of aContent to see what operations (if any) we need to
7301 : // perform.
7302 29 : uint32_t childCount = aContent->GetChildCount();
7303 29 : bool inRun = false;
7304 29 : nsIContent* firstChildInRun = nullptr;
7305 186 : for (uint32_t i = 0; i < childCount; i++) {
7306 157 : nsIContent* child = aContent->GetChildAt(i);
7307 157 : if (child->HasFlag(NODE_NEEDS_FRAME)) {
7308 111 : NS_ASSERTION(!child->GetPrimaryFrame() ||
7309 : child->GetPrimaryFrame()->GetContent() != child,
7310 : //XXX the child->GetPrimaryFrame()->GetContent() != child
7311 : // check is needed due to bug 135040. Remove it once that's
7312 : // fixed.
7313 : "NEEDS_FRAME set on a node that already has a frame?");
7314 111 : if (!inRun) {
7315 27 : inRun = true;
7316 27 : firstChildInRun = child;
7317 : }
7318 : } else {
7319 46 : if (inRun) {
7320 0 : inRun = false;
7321 : // generate a ContentRangeInserted for [startOfRun,i)
7322 : ContentRangeInserted(aContent, firstChildInRun, child, nullptr,
7323 : false, // aAllowLazyConstruction
7324 : true, // aForReconstruction
7325 0 : &aTreeMatchContext);
7326 : }
7327 : }
7328 : }
7329 :
7330 29 : if (inRun) {
7331 : ContentAppended(aContent, firstChildInRun,
7332 : false, // aAllowLazyConstruction
7333 : true, // aForReconstruction
7334 27 : &aTreeMatchContext);
7335 : }
7336 :
7337 : // Now descend.
7338 58 : FlattenedChildIterator iter(aContent);
7339 186 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
7340 157 : if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
7341 : TreeMatchContext::AutoAncestorPusher insertionPointPusher(
7342 12 : &aTreeMatchContext);
7343 :
7344 : // Handle stuff like xbl:children.
7345 6 : if (child->GetParent() != aContent && child->GetParent()->IsElement()) {
7346 0 : insertionPointPusher.PushAncestorAndStyleScope(
7347 0 : child->GetParent()->AsElement());
7348 : }
7349 :
7350 12 : TreeMatchContext::AutoAncestorPusher pusher(&aTreeMatchContext);
7351 6 : pusher.PushAncestorAndStyleScope(child);
7352 :
7353 6 : CreateNeededFrames(child, aTreeMatchContext);
7354 : }
7355 : }
7356 29 : }
7357 :
7358 : void
7359 291 : nsCSSFrameConstructor::CreateNeededFrames()
7360 : {
7361 291 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
7362 : "Someone forgot a script blocker");
7363 :
7364 291 : Element* rootElement = mDocument->GetRootElement();
7365 291 : NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME),
7366 : "root element should not have frame created lazily");
7367 291 : if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
7368 23 : BeginUpdate();
7369 : TreeMatchContext treeMatchContext(
7370 46 : mDocument, TreeMatchContext::ForFrameConstruction);
7371 23 : treeMatchContext.InitAncestors(rootElement);
7372 23 : CreateNeededFrames(rootElement, treeMatchContext);
7373 23 : EndUpdate();
7374 : }
7375 291 : }
7376 :
7377 : void
7378 5 : nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
7379 : nsIContent* aStartChild,
7380 : nsIContent* aEndChild,
7381 : bool aAllowLazyConstruction,
7382 : bool aForReconstruction)
7383 : {
7384 10 : for (nsIContent* child = aStartChild;
7385 10 : child != aEndChild;
7386 5 : child = child->GetNextSibling()) {
7387 20 : if ((child->GetPrimaryFrame() || GetUndisplayedContent(child) ||
7388 5 : GetDisplayContentsStyleFor(child))
7389 : #ifdef MOZ_XUL
7390 : // Except listboxes suck, so do NOT skip anything here if
7391 : // we plan to notify a listbox.
7392 5 : && !MaybeGetListBoxBodyFrame(aContainer, child)
7393 : #endif
7394 : ) {
7395 : // Already have a frame or undisplayed entry for this content; a
7396 : // previous ContentRangeInserted in this loop must have reconstructed
7397 : // its insertion parent. Skip it.
7398 0 : continue;
7399 : }
7400 : // Call ContentRangeInserted with this node.
7401 5 : ContentRangeInserted(aContainer, child, child->GetNextSibling(),
7402 : mTempFrameTreeState, aAllowLazyConstruction,
7403 5 : aForReconstruction, nullptr);
7404 : }
7405 5 : }
7406 :
7407 : nsCSSFrameConstructor::InsertionPoint
7408 41 : nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aContainer,
7409 : nsIContent* aStartChild,
7410 : nsIContent* aEndChild,
7411 : bool aAllowLazyConstruction,
7412 : bool aForReconstruction)
7413 : {
7414 : // See if we have an XBL insertion point. If so, then that's our
7415 : // real parent frame; if not, then the frame hasn't been built yet
7416 : // and we just bail.
7417 41 : InsertionPoint insertionPoint = GetInsertionPoint(aContainer, nullptr);
7418 41 : if (!insertionPoint.mParentFrame && !insertionPoint.mMultiple) {
7419 0 : return insertionPoint; // Don't build the frames.
7420 : }
7421 :
7422 41 : bool hasInsertion = false;
7423 41 : if (!insertionPoint.mMultiple) {
7424 : // XXXbz XBL2/sXBL issue
7425 37 : nsIDocument* document = aStartChild->GetComposedDoc();
7426 : // XXXbz how would |document| be null here?
7427 37 : if (document && aStartChild->GetXBLInsertionParent()) {
7428 1 : hasInsertion = true;
7429 : }
7430 : }
7431 :
7432 41 : if (insertionPoint.mMultiple || hasInsertion) {
7433 : // We have an insertion point. There are some additional tests we need to do
7434 : // in order to ensure that an append is a safe operation.
7435 5 : uint32_t childCount = 0;
7436 :
7437 5 : if (!insertionPoint.mMultiple) {
7438 : // We may need to make multiple ContentInserted calls instead. A
7439 : // reasonable heuristic to employ (in order to maintain good performance)
7440 : // is to find out if the insertion point's content node contains any
7441 : // explicit children. If it does not, then it is highly likely that
7442 : // an append is occurring. (Note it is not definite, and there are insane
7443 : // cases we will not deal with by employing this heuristic, but it beats
7444 : // always falling back to multiple ContentInserted calls).
7445 : //
7446 : // In the multiple insertion point case, we know we're going to need to do
7447 : // multiple ContentInserted calls anyway.
7448 : // XXXndeakin This test doesn't work in the new world. Or rather, it works, but
7449 : // it's slow
7450 1 : childCount = insertionPoint.mParentFrame->GetContent()->GetChildCount();
7451 : }
7452 :
7453 : // If we have multiple insertion points or if we have an insertion point
7454 : // and the operation is not a true append or if the insertion point already
7455 : // has explicit children, then we must fall back.
7456 5 : if (insertionPoint.mMultiple || aEndChild != nullptr || childCount > 0) {
7457 : // Now comes the fun part. For each inserted child, make a
7458 : // ContentInserted call as if it had just gotten inserted and
7459 : // let ContentInserted handle the mess.
7460 5 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
7461 5 : aAllowLazyConstruction, aForReconstruction);
7462 5 : insertionPoint.mParentFrame = nullptr;
7463 : }
7464 : }
7465 :
7466 41 : return insertionPoint;
7467 : }
7468 :
7469 : bool
7470 60 : nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
7471 : nsIContent* aStartChild,
7472 : nsIContent* aEndChild)
7473 : {
7474 60 : if (aParentFrame->IsFrameSetFrame()) {
7475 : // Check whether we have any kids we care about.
7476 0 : for (nsIContent* cur = aStartChild;
7477 0 : cur != aEndChild;
7478 0 : cur = cur->GetNextSibling()) {
7479 0 : if (IsSpecialFramesetChild(cur)) {
7480 : // Just reframe the parent, since framesets are weird like that.
7481 0 : RecreateFramesForContent(aParentFrame->GetContent(), false,
7482 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
7483 0 : return true;
7484 : }
7485 : }
7486 : }
7487 60 : return false;
7488 : }
7489 :
7490 : void
7491 0 : nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
7492 : nsIContent* aEndChild)
7493 : {
7494 0 : for (nsIContent* child = aStartChild; child != aEndChild;
7495 0 : child = child->GetNextSibling()) {
7496 0 : nsINode* parent = child->GetFlattenedTreeParent();
7497 0 : if (MOZ_LIKELY(parent) && parent->IsElement()) {
7498 0 : parent->AsElement()->NoteDirtyDescendantsForServo();
7499 : }
7500 : }
7501 0 : }
7502 :
7503 : void
7504 0 : nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
7505 : nsIContent* aEndChild)
7506 : {
7507 0 : ServoStyleSet* styleSet = mPresShell->StyleSet()->AsServo();
7508 :
7509 0 : for (nsIContent* child = aStartChild; child != aEndChild;
7510 0 : child = child->GetNextSibling()) {
7511 : // Calling StyleNewChildren on one child will end up styling another child,
7512 : // if they share the same flattened tree parent. So we check HasServoData()
7513 : // to avoid a wasteful call to GetFlattenedTreeParent (on the child) and
7514 : // StyleNewChildren (on the flattened tree parent) when we detect we've
7515 : // already handled that parent. In the common case of inserting elements
7516 : // into a container that does not have an XBL binding or shadow tree with
7517 : // distributed children, this boils down to a single call to
7518 : // GetFlattenedTreeParent/StyleNewChildren, and traversing the list of
7519 : // children checking HasServoData (which is fast).
7520 0 : if (child->IsElement() && !child->AsElement()->HasServoData()) {
7521 0 : Element* parent = child->AsElement()->GetFlattenedTreeParentElement();
7522 : // NB: Parent may be null if the content is appended to a shadow root, and
7523 : // isn't assigned to any insertion point.
7524 0 : if (MOZ_LIKELY(parent) && parent->HasServoData()) {
7525 0 : styleSet->StyleNewChildren(parent);
7526 : }
7527 : }
7528 : }
7529 0 : }
7530 :
7531 : void
7532 0 : nsCSSFrameConstructor::StyleChildRangeForReconstruct(nsIContent* aStartChild,
7533 : nsIContent* aEndChild)
7534 : {
7535 0 : ServoStyleSet* styleSet = mPresShell->StyleSet()->AsServo();
7536 :
7537 : // We take a parallelism hit here, since we don't have a great API to pass
7538 : // a range of elements to style to Servo.
7539 0 : for (nsIContent* child = aStartChild; child != aEndChild;
7540 0 : child = child->GetNextSibling()) {
7541 0 : if (child->IsElement()) {
7542 0 : styleSet->StyleSubtreeForReconstruct(child->AsElement());
7543 : }
7544 : }
7545 0 : }
7546 :
7547 : void
7548 83 : nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
7549 : nsIContent* aFirstNewContent,
7550 : bool aAllowLazyConstruction,
7551 : bool aForReconstruction,
7552 : TreeMatchContext* aProvidedTreeMatchContext)
7553 : {
7554 83 : MOZ_ASSERT(!aProvidedTreeMatchContext || !aAllowLazyConstruction);
7555 83 : MOZ_ASSERT(!aAllowLazyConstruction || !RestyleManager()->IsInStyleRefresh());
7556 :
7557 119 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7558 83 : NS_PRECONDITION(mUpdateCount != 0,
7559 : "Should be in an update while creating frames");
7560 :
7561 : #ifdef DEBUG
7562 83 : if (gNoisyContentUpdates) {
7563 0 : printf("nsCSSFrameConstructor::ContentAppended container=%p "
7564 : "first-child=%p lazy=%d\n",
7565 : static_cast<void*>(aContainer), aFirstNewContent,
7566 0 : aAllowLazyConstruction);
7567 0 : if (gReallyNoisyContentUpdates && aContainer) {
7568 0 : aContainer->List(stdout, 0);
7569 : }
7570 : }
7571 : #endif
7572 :
7573 : #ifdef DEBUG
7574 351 : for (nsIContent* child = aFirstNewContent;
7575 351 : child;
7576 268 : child = child->GetNextSibling()) {
7577 : // XXX the GetContent() != child check is needed due to bug 135040.
7578 : // Remove it once that's fixed.
7579 268 : NS_ASSERTION(!child->GetPrimaryFrame() ||
7580 : child->GetPrimaryFrame()->GetContent() != child,
7581 : "asked to construct a frame for a node that already has a frame");
7582 : }
7583 : #endif
7584 :
7585 : #ifdef MOZ_XUL
7586 83 : if (aContainer) {
7587 : int32_t namespaceID;
7588 : nsIAtom* tag =
7589 83 : mDocument->BindingManager()->ResolveTag(aContainer, &namespaceID);
7590 :
7591 : // Just ignore tree tags, anyway we don't create any frames for them.
7592 166 : if (tag == nsGkAtoms::treechildren ||
7593 166 : tag == nsGkAtoms::treeitem ||
7594 83 : tag == nsGkAtoms::treerow)
7595 0 : return;
7596 : }
7597 : #endif // MOZ_XUL
7598 :
7599 : // The frame constructor uses this codepath both for bonafide newly-added
7600 : // content and for RestyleManager-driven frame construction (RECONSTRUCT_FRAME
7601 : // and lazy frame construction). If we're using the Servo style system, we
7602 : // want to ensure that styles get resolved in the first case, whereas for the
7603 : // second case they should have already been resolved if needed.
7604 83 : bool isNewlyAddedContentForServo = aContainer->IsStyledByServo() &&
7605 83 : !aForReconstruction;
7606 :
7607 : bool isNewShadowTreeContent =
7608 83 : aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
7609 83 : !aContainer->IsInNativeAnonymousSubtree() &&
7610 83 : !aFirstNewContent->IsInNativeAnonymousSubtree();
7611 :
7612 83 : if (!isNewShadowTreeContent) {
7613 : // See comment in ContentRangeInserted for why this is necessary.
7614 91 : if (!GetContentInsertionFrameFor(aContainer) &&
7615 8 : !aContainer->IsActiveChildrenElement()) {
7616 : // We're punting on frame construction because there's no container frame.
7617 : // The Servo-backed style system handles this case like the lazy frame
7618 : // construction case.
7619 8 : if (isNewlyAddedContentForServo) {
7620 0 : LazilyStyleNewChildRange(aFirstNewContent, nullptr);
7621 : }
7622 8 : return;
7623 : }
7624 :
7625 123 : if (aAllowLazyConstruction &&
7626 48 : MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
7627 34 : if (isNewlyAddedContentForServo) {
7628 0 : LazilyStyleNewChildRange(aFirstNewContent, nullptr);
7629 : }
7630 34 : return;
7631 : }
7632 : }
7633 :
7634 : // We couldn't construct lazily. Make Servo eagerly traverse the new content.
7635 41 : if (aContainer->IsStyledByServo()) {
7636 0 : if (aForReconstruction) {
7637 0 : StyleChildRangeForReconstruct(aFirstNewContent, nullptr);
7638 : } else {
7639 0 : StyleNewChildRange(aFirstNewContent, nullptr);
7640 : }
7641 : }
7642 :
7643 41 : if (isNewShadowTreeContent) {
7644 : // Recreate frames if content is appended into a ShadowRoot
7645 : // because children of ShadowRoot are rendered in place of children
7646 : // of the host.
7647 : //XXXsmaug This is super unefficient!
7648 0 : nsIContent* bindingParent = aContainer->GetBindingParent();
7649 0 : LAYOUT_PHASE_TEMP_EXIT();
7650 : RecreateFramesForContent(bindingParent, false,
7651 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
7652 0 : LAYOUT_PHASE_TEMP_REENTER();
7653 0 : return;
7654 : }
7655 :
7656 41 : LAYOUT_PHASE_TEMP_EXIT();
7657 : InsertionPoint insertion =
7658 : GetRangeInsertionPoint(aContainer, aFirstNewContent, nullptr,
7659 41 : aAllowLazyConstruction, aForReconstruction);
7660 41 : nsContainerFrame*& parentFrame = insertion.mParentFrame;
7661 41 : LAYOUT_PHASE_TEMP_REENTER();
7662 41 : if (!parentFrame) {
7663 5 : return;
7664 : }
7665 :
7666 36 : LAYOUT_PHASE_TEMP_EXIT();
7667 36 : if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
7668 0 : LAYOUT_PHASE_TEMP_REENTER();
7669 0 : return;
7670 : }
7671 36 : LAYOUT_PHASE_TEMP_REENTER();
7672 :
7673 36 : if (parentFrame->IsLeaf()) {
7674 : // Nothing to do here; we shouldn't be constructing kids of leaves
7675 : // Clear lazy bits so we don't try to construct again.
7676 0 : ClearLazyBits(aFirstNewContent, nullptr);
7677 0 : return;
7678 : }
7679 :
7680 36 : if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7681 0 : LAYOUT_PHASE_TEMP_EXIT();
7682 0 : RecreateFramesForContent(parentFrame->GetContent(), false,
7683 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
7684 0 : LAYOUT_PHASE_TEMP_REENTER();
7685 0 : return;
7686 : }
7687 :
7688 : // If the frame we are manipulating is a ib-split frame (that is, one
7689 : // that's been created as a result of a block-in-inline situation) then we
7690 : // need to append to the last ib-split sibling, not to the frame itself.
7691 36 : bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
7692 36 : if (parentIBSplit) {
7693 : #ifdef DEBUG
7694 0 : if (gNoisyContentUpdates) {
7695 0 : printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
7696 0 : nsFrame::ListTag(stdout, parentFrame);
7697 0 : printf(" is ib-split\n");
7698 : }
7699 : #endif
7700 :
7701 : // Since we're appending, we'll walk to the last anonymous frame
7702 : // that was created for the broken inline frame. But don't walk
7703 : // to the trailing inline if it's empty; stop at the block.
7704 0 : parentFrame = GetLastIBSplitSibling(parentFrame, false);
7705 : }
7706 :
7707 : // Get continuation that parents the last child. This MUST be done
7708 : // before the AdjustAppendParentForAfterContent call.
7709 36 : parentFrame = nsLayoutUtils::LastContinuationWithChild(parentFrame);
7710 :
7711 : // We should never get here with fieldsets or details, since they have
7712 : // multiple insertion points.
7713 36 : MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
7714 : "Parent frame should not be fieldset or details!");
7715 :
7716 : // Deal with possible :after generated content on the parent
7717 : nsIFrame* parentAfterFrame;
7718 36 : parentFrame =
7719 36 : ::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame,
7720 : aFirstNewContent, &parentAfterFrame);
7721 :
7722 : // Create some new frames
7723 : //
7724 : // We use the provided tree match context, or create a new one on the fly
7725 : // otherwise.
7726 72 : Maybe<TreeMatchContext> matchContext;
7727 36 : if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
7728 9 : matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
7729 9 : matchContext->InitAncestors(aContainer->AsElement());
7730 : }
7731 : nsFrameConstructorState state(mPresShell,
7732 : matchContext.ptrOr(aProvidedTreeMatchContext),
7733 : GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
7734 : GetAbsoluteContainingBlock(parentFrame, ABS_POS),
7735 72 : GetFloatContainingBlock(parentFrame));
7736 :
7737 : // See if the containing block has :first-letter style applied.
7738 36 : bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
7739 36 : nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
7740 36 : if (containingBlock) {
7741 7 : haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
7742 : haveFirstLineStyle =
7743 7 : ShouldHaveFirstLineStyle(containingBlock->GetContent(),
7744 7 : containingBlock->StyleContext());
7745 : }
7746 :
7747 36 : if (haveFirstLetterStyle) {
7748 : // Before we get going, remove the current letter frames
7749 0 : RemoveLetterFrames(state.mPresShell, containingBlock);
7750 : }
7751 :
7752 36 : LayoutFrameType frameType = parentFrame->Type();
7753 :
7754 72 : FlattenedChildIterator iter(aContainer);
7755 36 : bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
7756 72 : FrameConstructionItemList items;
7757 96 : if (aFirstNewContent->GetPreviousSibling() &&
7758 60 : GetParentType(frameType) == eTypeBlock &&
7759 : haveNoXBLChildren) {
7760 : // If there's a text node in the normal content list just before the new
7761 : // items, and it has no frame, make a frame construction item for it. If it
7762 : // doesn't need a frame, ConstructFramesFromItemList below won't give it
7763 : // one. No need to do all this if our parent type is not block, though,
7764 : // since WipeContainingBlock already handles that situation.
7765 : //
7766 : // Because we're appending, we don't need to worry about any text
7767 : // after the appended content; there can only be XBL anonymous content
7768 : // (text in an XBL binding is not suppressed) or generated content
7769 : // (and bare text nodes are not generated). Native anonymous content
7770 : // generated by frames never participates in inline layout.
7771 24 : AddTextItemIfNeeded(state, insertion,
7772 24 : aFirstNewContent->GetPreviousSibling(), items);
7773 : }
7774 156 : for (nsIContent* child = aFirstNewContent;
7775 156 : child;
7776 120 : child = child->GetNextSibling()) {
7777 120 : AddFrameConstructionItems(state, child, false, insertion, items);
7778 : }
7779 :
7780 36 : nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame);
7781 :
7782 : // Perform special check for diddling around with the frames in
7783 : // a ib-split inline frame.
7784 : // If we're appending before :after content, then we're not really
7785 : // appending, so let WipeContainingBlock know that.
7786 36 : LAYOUT_PHASE_TEMP_EXIT();
7787 36 : if (WipeContainingBlock(state, containingBlock, parentFrame, items,
7788 : true, prevSibling)) {
7789 0 : LAYOUT_PHASE_TEMP_REENTER();
7790 0 : return;
7791 : }
7792 36 : LAYOUT_PHASE_TEMP_REENTER();
7793 :
7794 : // If the parent is a block frame, and we're not in a special case
7795 : // where frames can be moved around, determine if the list is for the
7796 : // start or end of the block.
7797 86 : if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
7798 50 : !haveFirstLineStyle && !parentIBSplit) {
7799 7 : items.SetLineBoundaryAtStart(!prevSibling ||
7800 7 : !prevSibling->IsInlineOutside() ||
7801 7 : prevSibling->IsBrFrame());
7802 : // :after content can't be <br> so no need to check it
7803 7 : items.SetLineBoundaryAtEnd(!parentAfterFrame ||
7804 7 : !parentAfterFrame->IsInlineOutside());
7805 : }
7806 : // To suppress whitespace-only text frames, we have to verify that
7807 : // our container's DOM child list matches its flattened tree child list.
7808 36 : items.SetParentHasNoXBLChildren(haveNoXBLChildren);
7809 :
7810 36 : nsFrameItems frameItems;
7811 36 : ConstructFramesFromItemList(state, items, parentFrame, frameItems);
7812 :
7813 156 : for (nsIContent* child = aFirstNewContent;
7814 156 : child;
7815 120 : child = child->GetNextSibling()) {
7816 : // Invalidate now instead of before the WipeContainingBlock call, just in
7817 : // case we do wipe; in that case we don't need to do this walk at all.
7818 : // XXXbz does that matter? Would it make more sense to save some virtual
7819 : // GetChildAt calls instead and do this during construction of our
7820 : // FrameConstructionItemList?
7821 120 : InvalidateCanvasIfNeeded(mPresShell, child);
7822 : }
7823 :
7824 : // If the container is a table and a caption was appended, it needs to be put
7825 : // in the table wrapper frame's additional child list.
7826 36 : nsFrameItems captionItems;
7827 36 : if (LayoutFrameType::Table == frameType) {
7828 : // Pull out the captions. Note that we don't want to do that as we go,
7829 : // because processing a single caption can add a whole bunch of things to
7830 : // the frame items due to pseudoframe processing. So we'd have to pull
7831 : // captions from a list anyway; might as well do that here.
7832 : // XXXbz this is no longer true; we could pull captions directly out of the
7833 : // FrameConstructionItemList now.
7834 0 : PullOutCaptionFrames(frameItems, captionItems);
7835 : }
7836 :
7837 36 : if (haveFirstLineStyle && parentFrame == containingBlock) {
7838 : // It's possible that some of the new frames go into a
7839 : // first-line frame. Look at them and see...
7840 0 : AppendFirstLineFrames(state, containingBlock->GetContent(),
7841 0 : containingBlock, frameItems);
7842 : }
7843 :
7844 : // Notify the parent frame passing it the list of new frames
7845 : // Append the flowed frames to the principal child list; captions
7846 : // need special treatment
7847 36 : if (captionItems.NotEmpty()) { // append the caption to the table wrapper
7848 0 : NS_ASSERTION(LayoutFrameType::Table == frameType, "how did that happen?");
7849 0 : nsContainerFrame* outerTable = parentFrame->GetParent();
7850 0 : AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7851 : }
7852 :
7853 36 : if (frameItems.NotEmpty()) { // append the in-flow kids
7854 23 : AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
7855 : }
7856 :
7857 : // Recover first-letter frames
7858 36 : if (haveFirstLetterStyle) {
7859 0 : RecoverLetterFrames(containingBlock);
7860 : }
7861 :
7862 : #ifdef DEBUG
7863 36 : if (gReallyNoisyContentUpdates) {
7864 0 : printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
7865 0 : parentFrame->List(stdout, 0);
7866 : }
7867 : #endif
7868 :
7869 : #ifdef ACCESSIBILITY
7870 36 : nsAccessibilityService* accService = nsIPresShell::AccService();
7871 36 : if (accService) {
7872 0 : accService->ContentRangeInserted(mPresShell, aContainer,
7873 0 : aFirstNewContent, nullptr);
7874 : }
7875 : #endif
7876 : }
7877 :
7878 : #ifdef MOZ_XUL
7879 :
7880 : enum content_operation
7881 : {
7882 : CONTENT_INSERTED,
7883 : CONTENT_REMOVED
7884 : };
7885 :
7886 : // Helper function to lookup the listbox body frame and send a notification
7887 : // for insertion or removal of content
7888 : static
7889 28 : bool NotifyListBoxBody(nsPresContext* aPresContext,
7890 : nsIContent* aContainer,
7891 : nsIContent* aChild,
7892 : // Only used for the removed notification
7893 : nsIContent* aOldNextSibling,
7894 : nsIFrame* aChildFrame,
7895 : content_operation aOperation)
7896 : {
7897 : nsListBoxBodyFrame* listBoxBodyFrame =
7898 28 : MaybeGetListBoxBodyFrame(aContainer, aChild);
7899 28 : if (listBoxBodyFrame) {
7900 0 : if (aOperation == CONTENT_REMOVED) {
7901 : // Except if we have an aChildFrame and its parent is not the right
7902 : // thing, then we don't do this. Pseudo frames are so much fun....
7903 0 : if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) {
7904 : listBoxBodyFrame->OnContentRemoved(aPresContext, aContainer,
7905 0 : aChildFrame, aOldNextSibling);
7906 0 : return true;
7907 : }
7908 : } else {
7909 0 : listBoxBodyFrame->OnContentInserted(aChild);
7910 0 : return true;
7911 : }
7912 : }
7913 :
7914 28 : return false;
7915 : }
7916 : #endif // MOZ_XUL
7917 :
7918 : void
7919 43 : nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
7920 : nsIContent* aChild,
7921 : nsILayoutHistoryState* aFrameState,
7922 : bool aAllowLazyConstruction)
7923 : {
7924 43 : ContentRangeInserted(aContainer,
7925 : aChild,
7926 : aChild->GetNextSibling(),
7927 : aFrameState,
7928 43 : aAllowLazyConstruction);
7929 43 : }
7930 :
7931 : // ContentRangeInserted handles creating frames for a range of nodes that
7932 : // aren't at the end of their childlist. ContentRangeInserted isn't a real
7933 : // content notification, but rather it handles regular ContentInserted calls
7934 : // for a single node as well as the lazy construction of frames for a range of
7935 : // nodes when called from CreateNeededFrames. For a range of nodes to be
7936 : // suitable to have its frames constructed all at once they must meet the same
7937 : // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
7938 : // these), plus more. Namely when finding the insertion prevsibling we must not
7939 : // need to consult something specific to any one node in the range, so that the
7940 : // insertion prevsibling would be the same for each node in the range. So we
7941 : // pass the first node in the range to GetInsertionPrevSibling, and if
7942 : // IsValidSibling (the only place GetInsertionPrevSibling might look at the
7943 : // passed in node itself) needs to resolve style on the node we record this and
7944 : // return that this range needs to be split up and inserted separately. Table
7945 : // captions need extra attention as we need to determine where to insert them
7946 : // in the caption list, while skipping any nodes in the range being inserted
7947 : // (because when we treat the caption frames the other nodes have had their
7948 : // frames constructed but not yet inserted into the frame tree).
7949 : void
7950 65 : nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
7951 : nsIContent* aStartChild,
7952 : nsIContent* aEndChild,
7953 : nsILayoutHistoryState* aFrameState,
7954 : bool aAllowLazyConstruction,
7955 : bool aForReconstruction,
7956 : TreeMatchContext* aProvidedTreeMatchContext)
7957 : {
7958 65 : MOZ_ASSERT(!aProvidedTreeMatchContext || !aAllowLazyConstruction);
7959 65 : MOZ_ASSERT(!aAllowLazyConstruction || !RestyleManager()->IsInStyleRefresh());
7960 :
7961 89 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7962 65 : NS_PRECONDITION(mUpdateCount != 0,
7963 : "Should be in an update while creating frames");
7964 :
7965 65 : NS_PRECONDITION(aStartChild, "must always pass a child");
7966 :
7967 : #ifdef DEBUG
7968 65 : if (gNoisyContentUpdates) {
7969 0 : printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
7970 : "start-child=%p end-child=%p lazy=%d\n",
7971 : static_cast<void*>(aContainer),
7972 : static_cast<void*>(aStartChild), static_cast<void*>(aEndChild),
7973 0 : aAllowLazyConstruction);
7974 0 : if (gReallyNoisyContentUpdates) {
7975 0 : if (aContainer) {
7976 0 : aContainer->List(stdout,0);
7977 : } else {
7978 0 : aStartChild->List(stdout, 0);
7979 : }
7980 : }
7981 : }
7982 :
7983 130 : for (nsIContent* child = aStartChild;
7984 130 : child != aEndChild;
7985 65 : child = child->GetNextSibling()) {
7986 : // XXX the GetContent() != child check is needed due to bug 135040.
7987 : // Remove it once that's fixed.
7988 65 : NS_ASSERTION(!child->GetPrimaryFrame() ||
7989 : child->GetPrimaryFrame()->GetContent() != child,
7990 : "asked to construct a frame for a node that already has a frame");
7991 : }
7992 : #endif
7993 :
7994 65 : bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
7995 65 : NS_ASSERTION(isSingleInsert || !aAllowLazyConstruction,
7996 : "range insert shouldn't be lazy");
7997 65 : NS_ASSERTION(isSingleInsert || aEndChild,
7998 : "range should not include all nodes after aStartChild");
7999 :
8000 : #ifdef MOZ_XUL
8001 65 : if (aContainer && IsXULListBox(aContainer)) {
8002 0 : if (isSingleInsert) {
8003 0 : if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer,
8004 : // The insert case in NotifyListBoxBody
8005 : // doesn't use "old next sibling".
8006 : aStartChild, nullptr, nullptr, CONTENT_INSERTED)) {
8007 0 : return;
8008 : }
8009 : } else {
8010 : // We don't handle a range insert to a listbox parent, issue single
8011 : // ContertInserted calls for each node inserted.
8012 0 : LAYOUT_PHASE_TEMP_EXIT();
8013 0 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
8014 0 : aAllowLazyConstruction, aForReconstruction);
8015 0 : LAYOUT_PHASE_TEMP_REENTER();
8016 0 : return;
8017 : }
8018 : }
8019 : #endif // MOZ_XUL
8020 :
8021 : // If we have a null parent, then this must be the document element being
8022 : // inserted, or some other child of the document in the DOM (might be a PI,
8023 : // say).
8024 65 : if (!aContainer) {
8025 24 : NS_ASSERTION(isSingleInsert,
8026 : "root node insertion should be a single insertion");
8027 24 : Element* docElement = mDocument->GetRootElement();
8028 :
8029 24 : if (aStartChild != docElement) {
8030 : // Not the root element; just bail out
8031 0 : return;
8032 : }
8033 :
8034 24 : NS_PRECONDITION(!mRootElementFrame, "root element frame already created");
8035 :
8036 : // Create frames for the document element and its child elements
8037 24 : if (ConstructDocElementFrame(docElement, aFrameState)) {
8038 24 : InvalidateCanvasIfNeeded(mPresShell, aStartChild);
8039 : #ifdef DEBUG
8040 24 : if (gReallyNoisyContentUpdates) {
8041 : printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
8042 0 : "model:\n");
8043 0 : mRootElementFrame->List(stdout, 0);
8044 : }
8045 : #endif
8046 : }
8047 :
8048 24 : if (aFrameState) {
8049 : // Restore frame state for the root scroll frame if there is one
8050 0 : if (nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame()) {
8051 0 : RestoreFrameStateFor(rootScrollFrame, aFrameState);
8052 : }
8053 : }
8054 :
8055 : #ifdef ACCESSIBILITY
8056 24 : if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
8057 0 : accService->ContentRangeInserted(mPresShell, aContainer,
8058 0 : aStartChild, aEndChild);
8059 : }
8060 : #endif
8061 :
8062 24 : return;
8063 : }
8064 :
8065 : // The frame constructor uses this codepath both for bonafide newly-added
8066 : // content and for RestyleManager-driven frame construction (RECONSTRUCT_FRAME
8067 : // and lazy frame construction). If we're using the Servo style system, we
8068 : // want to ensure that styles get resolved in the first case, whereas for the
8069 : // second case they should have already been resolved if needed.
8070 41 : bool isNewlyAddedContentForServo = aContainer->IsStyledByServo() &&
8071 41 : !aForReconstruction;
8072 :
8073 : bool isNewShadowTreeContent =
8074 41 : aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
8075 0 : !aContainer->IsInNativeAnonymousSubtree() &&
8076 41 : (!aStartChild || !aStartChild->IsInNativeAnonymousSubtree()) &&
8077 41 : (!aEndChild || !aEndChild->IsInNativeAnonymousSubtree());
8078 :
8079 41 : if (!isNewShadowTreeContent) {
8080 41 : nsContainerFrame* parentFrame = GetContentInsertionFrameFor(aContainer);
8081 : // The xbl:children element won't have a frame, but default content can have the children as
8082 : // a parent. While its uncommon to change the structure of the default content itself, a label,
8083 : // for example, can be reframed by having its value attribute set or removed.
8084 41 : if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
8085 : // We're punting on frame construction because there's no container frame.
8086 : // The Servo-backed style system handles this case like the lazy frame
8087 : // construction case.
8088 12 : if (isNewlyAddedContentForServo) {
8089 0 : LazilyStyleNewChildRange(aStartChild, aEndChild);
8090 : }
8091 12 : return;
8092 : }
8093 :
8094 : // Otherwise, we've got parent content. Find its frame.
8095 29 : NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer ||
8096 : GetDisplayContentsStyleFor(aContainer), "New XBL code is possibly wrong!");
8097 :
8098 42 : if (aAllowLazyConstruction &&
8099 13 : MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
8100 0 : if (isNewlyAddedContentForServo) {
8101 0 : LazilyStyleNewChildRange(aStartChild, aEndChild);
8102 : }
8103 0 : return;
8104 : }
8105 : }
8106 :
8107 : // We couldn't construct lazily. Make Servo eagerly traverse the new content.
8108 29 : if (aContainer->IsStyledByServo()) {
8109 0 : if (aForReconstruction) {
8110 0 : StyleChildRangeForReconstruct(aStartChild, aEndChild);
8111 : } else {
8112 0 : StyleNewChildRange(aStartChild, aEndChild);
8113 : }
8114 : }
8115 :
8116 29 : if (isNewShadowTreeContent) {
8117 : // Recreate frames if content is inserted into a ShadowRoot
8118 : // because children of ShadowRoot are rendered in place of
8119 : // the children of the host.
8120 : //XXXsmaug This is super unefficient!
8121 0 : nsIContent* bindingParent = aContainer->GetBindingParent();
8122 0 : LAYOUT_PHASE_TEMP_EXIT();
8123 : RecreateFramesForContent(bindingParent, false,
8124 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
8125 0 : LAYOUT_PHASE_TEMP_REENTER();
8126 0 : return;
8127 : }
8128 :
8129 29 : InsertionPoint insertion;
8130 29 : if (isSingleInsert) {
8131 : // See if we have an XBL insertion point. If so, then that's our
8132 : // real parent frame; if not, then the frame hasn't been built yet
8133 : // and we just bail.
8134 29 : insertion = GetInsertionPoint(aContainer, aStartChild);
8135 : } else {
8136 : // Get our insertion point. If we need to issue single ContentInserted's
8137 : // GetRangeInsertionPoint will take care of that for us.
8138 0 : LAYOUT_PHASE_TEMP_EXIT();
8139 0 : insertion = GetRangeInsertionPoint(aContainer, aStartChild, aEndChild,
8140 : aAllowLazyConstruction,
8141 0 : aForReconstruction);
8142 0 : LAYOUT_PHASE_TEMP_REENTER();
8143 : }
8144 :
8145 29 : if (!insertion.mParentFrame) {
8146 5 : return;
8147 : }
8148 :
8149 : bool isAppend, isRangeInsertSafe;
8150 : nsIFrame* prevSibling = GetInsertionPrevSibling(&insertion, aStartChild,
8151 24 : &isAppend, &isRangeInsertSafe);
8152 :
8153 : // check if range insert is safe
8154 24 : if (!isSingleInsert && !isRangeInsertSafe) {
8155 : // must fall back to a single ContertInserted for each child in the range
8156 0 : LAYOUT_PHASE_TEMP_EXIT();
8157 0 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
8158 0 : aAllowLazyConstruction, aForReconstruction);
8159 0 : LAYOUT_PHASE_TEMP_REENTER();
8160 0 : return;
8161 : }
8162 :
8163 24 : nsIContent* container = insertion.mParentFrame->GetContent();
8164 :
8165 24 : LayoutFrameType frameType = insertion.mParentFrame->Type();
8166 24 : LAYOUT_PHASE_TEMP_EXIT();
8167 24 : if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild)) {
8168 0 : LAYOUT_PHASE_TEMP_REENTER();
8169 0 : return;
8170 : }
8171 24 : LAYOUT_PHASE_TEMP_REENTER();
8172 :
8173 : // We should only get here with fieldsets when doing a single insert, because
8174 : // fieldsets have multiple insertion points.
8175 24 : NS_ASSERTION(isSingleInsert || frameType != LayoutFrameType::FieldSet,
8176 : "Unexpected parent");
8177 24 : if (IsFrameForFieldSet(insertion.mParentFrame) &&
8178 0 : aStartChild->NodeInfo()->NameAtom() == nsGkAtoms::legend) {
8179 : // Just reframe the parent, since figuring out whether this
8180 : // should be the new legend and then handling it is too complex.
8181 : // We could do a little better here --- check if the fieldset already
8182 : // has a legend which occurs earlier in its child list than this node,
8183 : // and if so, proceed. But we'd have to extend nsFieldSetFrame
8184 : // to locate this legend in the inserted frames and extract it.
8185 0 : LAYOUT_PHASE_TEMP_EXIT();
8186 0 : RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
8187 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
8188 0 : LAYOUT_PHASE_TEMP_REENTER();
8189 0 : return;
8190 : }
8191 :
8192 : // We should only get here with details when doing a single insertion because
8193 : // we treat details frame as if it has multiple insertion points.
8194 24 : MOZ_ASSERT(isSingleInsert || frameType != LayoutFrameType::Details);
8195 24 : if (frameType == LayoutFrameType::Details) {
8196 : // When inserting an element into <details>, just reframe the details frame
8197 : // and let it figure out where the element should be laid out. It might seem
8198 : // expensive to recreate the entire details frame, but it's the simplest way
8199 : // to handle the insertion.
8200 0 : LAYOUT_PHASE_TEMP_EXIT();
8201 0 : RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
8202 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
8203 0 : LAYOUT_PHASE_TEMP_REENTER();
8204 0 : return;
8205 : }
8206 :
8207 : // Don't construct kids of leaves
8208 24 : if (insertion.mParentFrame->IsLeaf()) {
8209 : // Clear lazy bits so we don't try to construct again.
8210 0 : ClearLazyBits(aStartChild, aEndChild);
8211 0 : return;
8212 : }
8213 :
8214 24 : if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
8215 0 : LAYOUT_PHASE_TEMP_EXIT();
8216 0 : RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
8217 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
8218 0 : LAYOUT_PHASE_TEMP_REENTER();
8219 0 : return;
8220 : }
8221 :
8222 48 : Maybe<TreeMatchContext> matchContext;
8223 24 : if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
8224 24 : matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
8225 24 : matchContext->InitAncestors(aContainer ? aContainer->AsElement() : nullptr);
8226 : }
8227 : nsFrameConstructorState state(mPresShell,
8228 : matchContext.ptrOr(aProvidedTreeMatchContext),
8229 24 : GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
8230 24 : GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
8231 24 : GetFloatContainingBlock(insertion.mParentFrame),
8232 120 : do_AddRef(aFrameState));
8233 :
8234 : // Recover state for the containing block - we need to know if
8235 : // it has :first-letter or :first-line style applied to it. The
8236 : // reason we care is that the internal structure in these cases
8237 : // is not the normal structure and requires custom updating
8238 : // logic.
8239 24 : nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
8240 24 : bool haveFirstLetterStyle = false;
8241 24 : bool haveFirstLineStyle = false;
8242 :
8243 : // In order to shave off some cycles, we only dig up the
8244 : // containing block haveFirst* flags if the parent frame where
8245 : // the insertion/append is occurring is an inline or block
8246 : // container. For other types of containers this isn't relevant.
8247 24 : StyleDisplay parentDisplay = insertion.mParentFrame->GetDisplay();
8248 :
8249 : // Examine the insertion.mParentFrame where the insertion is taking
8250 : // place. If it's a certain kind of container then some special
8251 : // processing is done.
8252 24 : if ((StyleDisplay::Block == parentDisplay) ||
8253 19 : (StyleDisplay::ListItem == parentDisplay) ||
8254 19 : (StyleDisplay::Inline == parentDisplay) ||
8255 : (StyleDisplay::InlineBlock == parentDisplay)) {
8256 : // Recover the special style flags for the containing block
8257 5 : if (containingBlock) {
8258 2 : haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
8259 : haveFirstLineStyle =
8260 2 : ShouldHaveFirstLineStyle(containingBlock->GetContent(),
8261 2 : containingBlock->StyleContext());
8262 : }
8263 :
8264 5 : if (haveFirstLetterStyle) {
8265 : // If our current insertion.mParentFrame is a Letter frame, use its parent as our
8266 : // new parent hint
8267 0 : if (insertion.mParentFrame->IsLetterFrame()) {
8268 : // If insertion.mParentFrame is out of flow, then we actually want the parent of
8269 : // the placeholder frame.
8270 0 : if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8271 : nsPlaceholderFrame* placeholderFrame =
8272 0 : insertion.mParentFrame->GetPlaceholderFrame();
8273 0 : NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
8274 0 : insertion.mParentFrame = placeholderFrame->GetParent();
8275 : } else {
8276 0 : insertion.mParentFrame = insertion.mParentFrame->GetParent();
8277 : }
8278 : }
8279 :
8280 : // Remove the old letter frames before doing the insertion
8281 0 : RemoveLetterFrames(mPresShell, state.mFloatedItems.containingBlock);
8282 :
8283 : // Removing the letterframes messes around with the frame tree, removing
8284 : // and creating frames. We need to reget our prevsibling, parent frame,
8285 : // etc.
8286 : prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend,
8287 0 : &isRangeInsertSafe);
8288 :
8289 : // Need check whether a range insert is still safe.
8290 0 : if (!isSingleInsert && !isRangeInsertSafe) {
8291 : // Need to recover the letter frames first.
8292 0 : RecoverLetterFrames(state.mFloatedItems.containingBlock);
8293 :
8294 : // must fall back to a single ContertInserted for each child in the range
8295 0 : LAYOUT_PHASE_TEMP_EXIT();
8296 0 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
8297 0 : aAllowLazyConstruction, aForReconstruction);
8298 0 : LAYOUT_PHASE_TEMP_REENTER();
8299 0 : return;
8300 : }
8301 :
8302 0 : container = insertion.mParentFrame->GetContent();
8303 0 : frameType = insertion.mParentFrame->Type();
8304 : }
8305 : }
8306 :
8307 24 : if (!prevSibling) {
8308 : // We're inserting the new frames as the first child. See if the
8309 : // parent has a :before pseudo-element
8310 13 : nsIFrame* firstChild = insertion.mParentFrame->PrincipalChildList().FirstChild();
8311 :
8312 21 : if (firstChild &&
8313 8 : nsLayoutUtils::IsGeneratedContentFor(container, firstChild,
8314 : nsCSSPseudoElements::before)) {
8315 : // Insert the new frames after the last continuation of the :before
8316 0 : prevSibling = firstChild->GetTailContinuation();
8317 0 : insertion.mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
8318 : // Don't change isAppend here; we'll can call AppendFrames as needed, and
8319 : // the change to our prevSibling doesn't affect that.
8320 : }
8321 : }
8322 :
8323 48 : FrameConstructionItemList items;
8324 24 : ParentType parentType = GetParentType(frameType);
8325 48 : FlattenedChildIterator iter(aContainer);
8326 24 : bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
8327 60 : if (aStartChild->GetPreviousSibling() &&
8328 36 : parentType == eTypeBlock && haveNoXBLChildren) {
8329 : // If there's a text node in the normal content list just before the
8330 : // new nodes, and it has no frame, make a frame construction item for
8331 : // it, because it might need a frame now. No need to do this if our
8332 : // parent type is not block, though, since WipeContainingBlock
8333 : // already handles that sitation.
8334 8 : AddTextItemIfNeeded(state, insertion, aStartChild->GetPreviousSibling(),
8335 8 : items);
8336 : }
8337 :
8338 24 : if (isSingleInsert) {
8339 24 : AddFrameConstructionItems(state, aStartChild,
8340 24 : aStartChild->IsRootOfAnonymousSubtree(),
8341 24 : insertion, items);
8342 : } else {
8343 0 : for (nsIContent* child = aStartChild;
8344 0 : child != aEndChild;
8345 0 : child = child->GetNextSibling()){
8346 0 : AddFrameConstructionItems(state, child, false, insertion, items);
8347 : }
8348 : }
8349 :
8350 24 : if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) {
8351 : // If there's a text node in the normal content list just after the
8352 : // new nodes, and it has no frame, make a frame construction item for
8353 : // it, because it might need a frame now. No need to do this if our
8354 : // parent type is not block, though, since WipeContainingBlock
8355 : // already handles that sitation.
8356 11 : AddTextItemIfNeeded(state, insertion, aEndChild, items);
8357 : }
8358 :
8359 : // Perform special check for diddling around with the frames in
8360 : // a special inline frame.
8361 : // If we're appending before :after content, then we're not really
8362 : // appending, so let WipeContainingBlock know that.
8363 24 : LAYOUT_PHASE_TEMP_EXIT();
8364 24 : if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
8365 : isAppend, prevSibling)) {
8366 0 : LAYOUT_PHASE_TEMP_REENTER();
8367 0 : return;
8368 : }
8369 24 : LAYOUT_PHASE_TEMP_REENTER();
8370 :
8371 : // If the container is a table and a caption will be appended, it needs to be
8372 : // put in the table wrapper frame's additional child list.
8373 : // We make no attempt here to set flags to indicate whether the list
8374 : // will be at the start or end of a block. It doesn't seem worthwhile.
8375 24 : nsFrameItems frameItems, captionItems;
8376 24 : ConstructFramesFromItemList(state, items, insertion.mParentFrame, frameItems);
8377 :
8378 24 : if (frameItems.NotEmpty()) {
8379 40 : for (nsIContent* child = aStartChild;
8380 40 : child != aEndChild;
8381 20 : child = child->GetNextSibling()){
8382 20 : InvalidateCanvasIfNeeded(mPresShell, child);
8383 : }
8384 :
8385 20 : if (LayoutFrameType::Table == frameType ||
8386 : LayoutFrameType::TableWrapper == frameType) {
8387 0 : PullOutCaptionFrames(frameItems, captionItems);
8388 : }
8389 : }
8390 :
8391 : // If the parent of our current prevSibling is different from the frame we'll
8392 : // actually use as the parent, then the calculated insertion point is now
8393 : // invalid and as it is unknown where to insert correctly we append instead
8394 : // (bug 341858).
8395 : // This can affect our prevSibling and isAppend, but should not have any
8396 : // effect on the WipeContainingBlock above, since this should only happen
8397 : // when neither parent is a ib-split frame and should not affect whitespace
8398 : // handling inside table-related frames (and in fact, can only happen when
8399 : // one of the parents is a table wrapper and one is an inner table or when the
8400 : // parent is a fieldset or fieldset content frame). So it won't affect the
8401 : // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo
8402 : // handling will only be affected by us maybe thinking we're not inserting
8403 : // at the beginning, whereas we really are. That would have made us reframe
8404 : // unnecessarily, but that's ok.
8405 : // XXXbz we should push our frame construction item code up higher, so we
8406 : // know what our items are by the time we start figuring out previous
8407 : // siblings
8408 33 : if (prevSibling && frameItems.NotEmpty() &&
8409 9 : frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) {
8410 : #ifdef DEBUG
8411 0 : nsIFrame* frame1 = frameItems.FirstChild()->GetParent();
8412 0 : nsIFrame* frame2 = prevSibling->GetParent();
8413 0 : NS_ASSERTION(!IsFramePartOfIBSplit(frame1) &&
8414 : !IsFramePartOfIBSplit(frame2),
8415 : "Neither should be ib-split");
8416 0 : NS_ASSERTION((frame1->IsTableFrame() &&
8417 : frame2->IsTableWrapperFrame()) ||
8418 : (frame1->IsTableWrapperFrame() &&
8419 : frame2->IsTableFrame()) ||
8420 : frame1->IsFieldSetFrame() ||
8421 : (frame1->GetParent() &&
8422 : frame1->GetParent()->IsFieldSetFrame()),
8423 : "Unexpected frame types");
8424 : #endif
8425 0 : isAppend = true;
8426 : nsIFrame* appendAfterFrame;
8427 0 : insertion.mParentFrame =
8428 0 : ::AdjustAppendParentForAfterContent(this, container,
8429 : frameItems.FirstChild()->GetParent(),
8430 : aStartChild, &appendAfterFrame);
8431 0 : prevSibling = ::FindAppendPrevSibling(insertion.mParentFrame, appendAfterFrame);
8432 : }
8433 :
8434 24 : if (haveFirstLineStyle && insertion.mParentFrame == containingBlock) {
8435 : // It's possible that the new frame goes into a first-line
8436 : // frame. Look at it and see...
8437 0 : if (isAppend) {
8438 : // Use append logic when appending
8439 0 : AppendFirstLineFrames(state, containingBlock->GetContent(),
8440 0 : containingBlock, frameItems);
8441 : }
8442 : else {
8443 : // Use more complicated insert logic when inserting
8444 : // XXXbz this method is a no-op, so it's easy for the args being passed
8445 : // here to make no sense without anyone noticing... If it ever stops
8446 : // being a no-op, vet them carefully!
8447 : InsertFirstLineFrames(state, container, containingBlock, &insertion.mParentFrame,
8448 0 : prevSibling, frameItems);
8449 : }
8450 : }
8451 :
8452 : // We might have captions; put them into the caption list of the
8453 : // table wrapper frame.
8454 24 : if (captionItems.NotEmpty()) {
8455 0 : NS_ASSERTION(LayoutFrameType::Table == frameType ||
8456 : LayoutFrameType::TableWrapper == frameType,
8457 : "parent for caption is not table?");
8458 : // We need to determine where to put the caption items; start with the
8459 : // the parent frame that has already been determined and get the insertion
8460 : // prevsibling of the first caption item.
8461 : bool captionIsAppend;
8462 0 : nsIFrame* captionPrevSibling = nullptr;
8463 :
8464 : // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
8465 : bool ignored;
8466 0 : InsertionPoint captionInsertion(insertion.mParentFrame, insertion.mContainer);
8467 0 : if (isSingleInsert) {
8468 : captionPrevSibling =
8469 : GetInsertionPrevSibling(&captionInsertion, aStartChild,
8470 0 : &captionIsAppend, &ignored);
8471 : } else {
8472 0 : nsIContent* firstCaption = captionItems.FirstChild()->GetContent();
8473 : // It is very important here that we skip the children in
8474 : // [aStartChild,aEndChild) when looking for a
8475 : // prevsibling.
8476 : captionPrevSibling =
8477 : GetInsertionPrevSibling(&captionInsertion, firstCaption,
8478 : &captionIsAppend, &ignored,
8479 0 : aStartChild, aEndChild);
8480 : }
8481 :
8482 0 : nsContainerFrame* outerTable = nullptr;
8483 0 : if (GetCaptionAdjustedParent(captionInsertion.mParentFrame,
8484 0 : captionItems.FirstChild(),
8485 : &outerTable)) {
8486 : // If the parent is not a table wrapper frame we will try to add frames
8487 : // to a named child list that the parent does not honor and the frames
8488 : // will get lost.
8489 0 : NS_ASSERTION(outerTable->IsTableWrapperFrame(),
8490 : "Pseudo frame construction failure; "
8491 : "a caption can be only a child of a table wrapper frame");
8492 :
8493 : // If the parent of our current prevSibling is different from the frame
8494 : // we'll actually use as the parent, then the calculated insertion
8495 : // point is now invalid (bug 341382).
8496 0 : if (captionPrevSibling &&
8497 0 : captionPrevSibling->GetParent() != outerTable) {
8498 0 : captionPrevSibling = nullptr;
8499 : }
8500 0 : if (captionIsAppend) {
8501 0 : AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
8502 : } else {
8503 0 : InsertFrames(outerTable, nsIFrame::kCaptionList,
8504 0 : captionPrevSibling, captionItems);
8505 : }
8506 : }
8507 : }
8508 :
8509 24 : if (frameItems.NotEmpty()) {
8510 : // Notify the parent frame
8511 20 : if (isAppend) {
8512 5 : AppendFramesToParent(state, insertion.mParentFrame, frameItems, prevSibling);
8513 : } else {
8514 15 : InsertFrames(insertion.mParentFrame, kPrincipalList, prevSibling, frameItems);
8515 : }
8516 : }
8517 :
8518 24 : if (haveFirstLetterStyle) {
8519 : // Recover the letter frames for the containing block when
8520 : // it has first-letter style.
8521 0 : RecoverLetterFrames(state.mFloatedItems.containingBlock);
8522 : }
8523 :
8524 : #ifdef DEBUG
8525 24 : if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
8526 0 : printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
8527 0 : insertion.mParentFrame->List(stdout, 0);
8528 : }
8529 : #endif
8530 :
8531 : #ifdef ACCESSIBILITY
8532 24 : nsAccessibilityService* accService = nsIPresShell::AccService();
8533 24 : if (accService) {
8534 0 : accService->ContentRangeInserted(mPresShell, aContainer,
8535 0 : aStartChild, aEndChild);
8536 : }
8537 : #endif
8538 : }
8539 :
8540 : void
8541 28 : nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
8542 : nsIContent* aChild,
8543 : nsIContent* aOldNextSibling,
8544 : RemoveFlags aFlags,
8545 : bool* aDidReconstruct,
8546 : nsIContent** aDestroyedFramesFor)
8547 : {
8548 56 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
8549 28 : NS_PRECONDITION(mUpdateCount != 0,
8550 : "Should be in an update while destroying frames");
8551 :
8552 28 : *aDidReconstruct = false;
8553 28 : if (aDestroyedFramesFor) {
8554 0 : *aDestroyedFramesFor = aChild;
8555 : }
8556 :
8557 : // We're destroying our frame(s). This normally happens either when the
8558 : // content is being removed from the DOM (in which case we'll drop all Servo
8559 : // data in UnbindFromTree), or when we're recreating frames (usually in
8560 : // response to having retrieved a ReconstructFrame change hint after
8561 : // restyling). In both of those cases, there are no pending restyles we need
8562 : // to worry about.
8563 : //
8564 : // However, there is also the (rare) DestroyFramesFor path, in which we tear
8565 : // down (and usually recreate) the frames for a subtree. In this case, leaving
8566 : // the style data on the elements is problematic for our invariants, because
8567 : // there might be pending restyles in the subtree. If we simply leave them
8568 : // as-is, the subsequent traversal when recreating frames will generate a
8569 : // bunch of bogus change hints to update frames that no longer exist.
8570 : //
8571 : // So the two obvious options are to (1) process all pending restyles and take
8572 : // all the change hints before destroying the frames, or (2) drop all the
8573 : // style data. We chose the latter, since that matches the performance
8574 : // characteristics of the old Gecko style system.
8575 : //
8576 : // That said, it's almost certainly possible to optimize this if it turns out
8577 : // to be hot. It's just not a priority at the moment.
8578 : //
8579 : // FIXME(emilio): This really really feels like a hack, and it's only for the
8580 : // XBL/Shadow DOM path, so we should do this there instead.
8581 28 : if (aFlags == REMOVE_DESTROY_FRAMES && aChild->IsElement() &&
8582 0 : aChild->IsStyledByServo()) {
8583 0 : ServoRestyleManager::ClearServoDataFromSubtree(aChild->AsElement());
8584 : }
8585 :
8586 28 : nsPresContext* presContext = mPresShell->GetPresContext();
8587 28 : MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
8588 :
8589 28 : if (aChild->IsHTMLElement(nsGkAtoms::body) ||
8590 0 : (!aContainer && aChild->IsElement())) {
8591 : // We might be removing the element that we propagated viewport scrollbar
8592 : // styles from. Recompute those. (This clause covers two of the three
8593 : // possible scrollbar-propagation sources: the <body> [as aChild or a
8594 : // descendant] and the root node. The other possible scrollbar-propagation
8595 : // source is a fullscreen element, and we have code elsewhere to update
8596 : // scrollbars after fullscreen elements are removed -- specifically, it's
8597 : // part of the fullscreen cleanup code called by Element::UnbindFromTree.)
8598 0 : presContext->UpdateViewportScrollbarStylesOverride();
8599 : }
8600 :
8601 : #ifdef DEBUG
8602 28 : if (gNoisyContentUpdates) {
8603 : printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
8604 : "old-next-sibling=%p\n",
8605 : static_cast<void*>(aContainer),
8606 : static_cast<void*>(aChild),
8607 0 : static_cast<void*>(aOldNextSibling));
8608 0 : if (gReallyNoisyContentUpdates) {
8609 0 : aContainer->List(stdout, 0);
8610 : }
8611 : }
8612 : #endif
8613 :
8614 28 : nsIFrame* childFrame = aChild->GetPrimaryFrame();
8615 28 : if (!childFrame || childFrame->GetContent() != aChild) {
8616 : // XXXbz the GetContent() != aChild check is needed due to bug 135040.
8617 : // Remove it once that's fixed.
8618 9 : ClearUndisplayedContentIn(aChild, aContainer);
8619 : }
8620 28 : MOZ_ASSERT(!childFrame || !GetDisplayContentsStyleFor(aChild),
8621 : "display:contents nodes shouldn't have a frame");
8622 28 : if (!childFrame && GetDisplayContentsStyleFor(aChild)) {
8623 0 : nsIContent* ancestor = aContainer;
8624 0 : MOZ_ASSERT(ancestor, "display: contents on the root?");
8625 0 : while (!ancestor->GetPrimaryFrame()) {
8626 : // FIXME(emilio): Should this use the flattened tree parent instead?
8627 0 : ancestor = ancestor->GetParent();
8628 0 : MOZ_ASSERT(ancestor, "we can't have a display: contents subtree root!");
8629 : }
8630 :
8631 0 : nsIFrame* ancestorFrame = ancestor->GetPrimaryFrame();
8632 0 : if (ancestorFrame->GetProperty(nsIFrame::GenConProperty())) {
8633 0 : *aDidReconstruct = true;
8634 0 : LAYOUT_PHASE_TEMP_EXIT();
8635 :
8636 : // XXXmats Can we recreate frames only for the ::after/::before content?
8637 : // XXX Perhaps even only those that belong to the aChild sub-tree?
8638 0 : RecreateFramesForContent(ancestor, false, aFlags, aDestroyedFramesFor);
8639 0 : LAYOUT_PHASE_TEMP_REENTER();
8640 0 : return;
8641 : }
8642 :
8643 0 : FlattenedChildIterator iter(aChild);
8644 0 : for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
8645 0 : if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
8646 0 : LAYOUT_PHASE_TEMP_EXIT();
8647 0 : ContentRemoved(aChild, c, nullptr, aFlags, aDidReconstruct, aDestroyedFramesFor);
8648 0 : LAYOUT_PHASE_TEMP_REENTER();
8649 0 : if (aFlags != REMOVE_DESTROY_FRAMES && *aDidReconstruct) {
8650 0 : return;
8651 : }
8652 : }
8653 : }
8654 0 : ClearDisplayContentsIn(aChild, aContainer);
8655 : }
8656 :
8657 : #ifdef MOZ_XUL
8658 28 : if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
8659 : childFrame, CONTENT_REMOVED)) {
8660 0 : if (aFlags == REMOVE_DESTROY_FRAMES) {
8661 0 : CaptureStateForFramesOf(aChild, mTempFrameTreeState);
8662 : }
8663 0 : return;
8664 : }
8665 : #endif // MOZ_XUL
8666 :
8667 : // If we're removing the root, then make sure to remove things starting at
8668 : // the viewport's child instead of the primary frame (which might even be
8669 : // null if the root had an XBL binding or display:none, even though the
8670 : // frames above it got created). We do the adjustment after the childFrame
8671 : // check above, because we do want to clear any undisplayed content we might
8672 : // have for the root. Detecting removal of a root is a little exciting; in
8673 : // particular, having a null aContainer is necessary but NOT sufficient. Due
8674 : // to how we process reframes, the content node might not even be in our
8675 : // document by now. So explicitly check whether the viewport's first kid's
8676 : // content node is aChild.
8677 28 : bool isRoot = false;
8678 28 : if (!aContainer) {
8679 0 : nsIFrame* viewport = GetRootFrame();
8680 0 : if (viewport) {
8681 0 : nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
8682 0 : if (firstChild && firstChild->GetContent() == aChild) {
8683 0 : isRoot = true;
8684 0 : childFrame = firstChild;
8685 0 : NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
8686 : }
8687 : }
8688 : }
8689 :
8690 56 : if (aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
8691 28 : !aContainer->IsInNativeAnonymousSubtree() &&
8692 0 : !aChild->IsInNativeAnonymousSubtree()) {
8693 : // Recreate frames if content is removed from a ShadowRoot because it may
8694 : // contain an insertion point which can change how the host is rendered.
8695 : //
8696 : // XXXsmaug This is super unefficient!
8697 0 : nsIContent* bindingParent = aContainer->GetBindingParent();
8698 0 : *aDidReconstruct = true;
8699 0 : LAYOUT_PHASE_TEMP_EXIT();
8700 0 : RecreateFramesForContent(bindingParent, false, aFlags, aDestroyedFramesFor);
8701 0 : LAYOUT_PHASE_TEMP_REENTER();
8702 0 : return;
8703 : }
8704 :
8705 28 : if (aFlags == REMOVE_DESTROY_FRAMES) {
8706 0 : CaptureStateForFramesOf(aChild, mTempFrameTreeState);
8707 : }
8708 :
8709 28 : if (childFrame) {
8710 19 : InvalidateCanvasIfNeeded(mPresShell, aChild);
8711 :
8712 : // See whether we need to remove more than just childFrame
8713 19 : LAYOUT_PHASE_TEMP_EXIT();
8714 : nsIContent* container;
8715 19 : if (MaybeRecreateContainerForFrameRemoval(childFrame, aFlags, &container)) {
8716 0 : LAYOUT_PHASE_TEMP_REENTER();
8717 0 : MOZ_ASSERT(container);
8718 0 : *aDidReconstruct = true;
8719 0 : if (aDestroyedFramesFor) {
8720 0 : *aDestroyedFramesFor = container;
8721 : }
8722 0 : return;
8723 : }
8724 19 : LAYOUT_PHASE_TEMP_REENTER();
8725 :
8726 : // Get the childFrame's parent frame
8727 19 : nsIFrame* parentFrame = childFrame->GetParent();
8728 19 : LayoutFrameType parentType = parentFrame->Type();
8729 :
8730 19 : if (parentType == LayoutFrameType::FrameSet &&
8731 0 : IsSpecialFramesetChild(aChild)) {
8732 : // Just reframe the parent, since framesets are weird like that.
8733 0 : *aDidReconstruct = true;
8734 0 : LAYOUT_PHASE_TEMP_EXIT();
8735 0 : RecreateFramesForContent(parentFrame->GetContent(), false,
8736 0 : aFlags, aDestroyedFramesFor);
8737 0 : LAYOUT_PHASE_TEMP_REENTER();
8738 0 : return;
8739 : }
8740 :
8741 : // If we're a child of MathML, then we should reframe the MathML content.
8742 : // If we're non-MathML, then we would be wrapped in a block so we need to
8743 : // check our grandparent in that case.
8744 : nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
8745 19 : ? parentFrame->GetParent()
8746 19 : : parentFrame;
8747 19 : if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
8748 0 : *aDidReconstruct = true;
8749 0 : LAYOUT_PHASE_TEMP_EXIT();
8750 0 : RecreateFramesForContent(possibleMathMLAncestor->GetContent(),
8751 0 : false, aFlags, aDestroyedFramesFor);
8752 0 : LAYOUT_PHASE_TEMP_REENTER();
8753 0 : return;
8754 : }
8755 :
8756 : // Undo XUL wrapping if it's no longer needed.
8757 : // (If we're in the XUL block-wrapping situation, parentFrame is the
8758 : // wrapper frame.)
8759 19 : nsIFrame* grandparentFrame = parentFrame->GetParent();
8760 50 : if (grandparentFrame && grandparentFrame->IsXULBoxFrame() &&
8761 12 : (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
8762 : // check if this frame is the only one needing wrapping
8763 19 : aChild == AnyKidsNeedBlockParent(parentFrame->PrincipalChildList().FirstChild()) &&
8764 0 : !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
8765 0 : *aDidReconstruct = true;
8766 0 : LAYOUT_PHASE_TEMP_EXIT();
8767 0 : RecreateFramesForContent(grandparentFrame->GetContent(), true,
8768 0 : aFlags, aDestroyedFramesFor);
8769 0 : LAYOUT_PHASE_TEMP_REENTER();
8770 0 : return;
8771 : }
8772 :
8773 : #ifdef ACCESSIBILITY
8774 19 : nsAccessibilityService* accService = nsIPresShell::AccService();
8775 19 : if (accService) {
8776 0 : accService->ContentRemoved(mPresShell, aChild);
8777 : }
8778 : #endif
8779 :
8780 : // Examine the containing-block for the removed content and see if
8781 : // :first-letter style applies.
8782 19 : nsIFrame* inflowChild = childFrame;
8783 19 : if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8784 0 : inflowChild = childFrame->GetPlaceholderFrame();
8785 0 : NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
8786 : }
8787 : nsContainerFrame* containingBlock =
8788 19 : GetFloatContainingBlock(inflowChild->GetParent());
8789 19 : bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
8790 19 : if (haveFLS) {
8791 : // Trap out to special routine that handles adjusting a blocks
8792 : // frame tree when first-letter style is present.
8793 : #ifdef NOISY_FIRST_LETTER
8794 : printf("ContentRemoved: containingBlock=");
8795 : nsFrame::ListTag(stdout, containingBlock);
8796 : printf(" parentFrame=");
8797 : nsFrame::ListTag(stdout, parentFrame);
8798 : printf(" childFrame=");
8799 : nsFrame::ListTag(stdout, childFrame);
8800 : printf("\n");
8801 : #endif
8802 :
8803 : // First update the containing blocks structure by removing the
8804 : // existing letter frames. This makes the subsequent logic
8805 : // simpler.
8806 0 : RemoveLetterFrames(mPresShell, containingBlock);
8807 :
8808 : // Recover childFrame and parentFrame
8809 0 : childFrame = aChild->GetPrimaryFrame();
8810 0 : if (!childFrame || childFrame->GetContent() != aChild) {
8811 : // XXXbz the GetContent() != aChild check is needed due to bug 135040.
8812 : // Remove it once that's fixed.
8813 0 : ClearUndisplayedContentIn(aChild, aContainer);
8814 0 : return;
8815 : }
8816 0 : parentFrame = childFrame->GetParent();
8817 0 : parentType = parentFrame->Type();
8818 :
8819 : #ifdef NOISY_FIRST_LETTER
8820 : printf(" ==> revised parentFrame=");
8821 : nsFrame::ListTag(stdout, parentFrame);
8822 : printf(" childFrame=");
8823 : nsFrame::ListTag(stdout, childFrame);
8824 : printf("\n");
8825 : #endif
8826 : }
8827 :
8828 : #ifdef DEBUG
8829 19 : if (gReallyNoisyContentUpdates) {
8830 0 : printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
8831 0 : nsFrame::ListTag(stdout, childFrame);
8832 0 : putchar('\n');
8833 0 : parentFrame->List(stdout, 0);
8834 : }
8835 : #endif
8836 :
8837 :
8838 : // Notify the parent frame that it should delete the frame
8839 19 : if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8840 0 : childFrame = childFrame->GetPlaceholderFrame();
8841 0 : NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
8842 0 : parentFrame = childFrame->GetParent();
8843 : }
8844 19 : RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
8845 :
8846 19 : if (isRoot) {
8847 0 : mRootElementFrame = nullptr;
8848 0 : mRootElementStyleFrame = nullptr;
8849 0 : mDocElementContainingBlock = nullptr;
8850 0 : mPageSequenceFrame = nullptr;
8851 0 : mHasRootAbsPosContainingBlock = false;
8852 : }
8853 :
8854 19 : if (haveFLS && mRootElementFrame) {
8855 0 : RecoverLetterFrames(containingBlock);
8856 : }
8857 :
8858 : // If we're just reconstructing frames for the element, then the
8859 : // following ContentInserted notification on the element will
8860 : // take care of fixing up any adjacent text nodes. We don't need
8861 : // to do this if the table parent type of our parent type is not
8862 : // eTypeBlock, though, because in that case the whitespace isn't
8863 : // being suppressed due to us anyway.
8864 38 : if (aContainer && !aChild->IsRootOfAnonymousSubtree() &&
8865 24 : aFlags == REMOVE_CONTENT &&
8866 5 : GetParentType(parentType) == eTypeBlock) {
8867 : // Adjacent whitespace-only text nodes might have been suppressed if
8868 : // this node does not have inline ends. Create frames for them now
8869 : // if necessary.
8870 : // Reframe any text node just before the node being removed, if there is
8871 : // one, and if it's not the last child or the first child. If a whitespace
8872 : // textframe was being suppressed and it's now the last child or first
8873 : // child then it can stay suppressed since the parent must be a block
8874 : // and hence it's adjacent to a block end.
8875 : // If aOldNextSibling is null, then the text node before the node being
8876 : // removed is the last node, and we don't need to worry about it.
8877 5 : if (aOldNextSibling) {
8878 0 : nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
8879 0 : if (prevSibling && prevSibling->GetPreviousSibling()) {
8880 0 : LAYOUT_PHASE_TEMP_EXIT();
8881 0 : ReframeTextIfNeeded(aContainer, prevSibling);
8882 0 : LAYOUT_PHASE_TEMP_REENTER();
8883 : }
8884 : }
8885 : // Reframe any text node just after the node being removed, if there is
8886 : // one, and if it's not the last child or the first child.
8887 5 : if (aOldNextSibling && aOldNextSibling->GetNextSibling() &&
8888 0 : aOldNextSibling->GetPreviousSibling()) {
8889 0 : LAYOUT_PHASE_TEMP_EXIT();
8890 0 : ReframeTextIfNeeded(aContainer, aOldNextSibling);
8891 0 : LAYOUT_PHASE_TEMP_REENTER();
8892 : }
8893 : }
8894 :
8895 : #ifdef DEBUG
8896 19 : if (gReallyNoisyContentUpdates && parentFrame) {
8897 0 : printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
8898 0 : parentFrame->List(stdout, 0);
8899 : }
8900 : #endif
8901 : }
8902 : }
8903 :
8904 : /**
8905 : * This method invalidates the canvas when frames are removed or added for a
8906 : * node that might have its background propagated to the canvas, i.e., a
8907 : * document root node or an HTML BODY which is a child of the root node.
8908 : *
8909 : * @param aFrame a frame for a content node about to be removed or a frame that
8910 : * was just created for a content node that was inserted.
8911 : */
8912 : static void
8913 183 : InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node)
8914 : {
8915 183 : NS_PRECONDITION(presShell->GetRootFrame(), "What happened here?");
8916 183 : NS_PRECONDITION(presShell->GetPresContext(), "Say what?");
8917 :
8918 : // Note that both in ContentRemoved and ContentInserted the content node
8919 : // will still have the right parent pointer, so looking at that is ok.
8920 :
8921 183 : nsIContent* parent = node->GetParent();
8922 183 : if (parent) {
8923 : // Has a parent; might not be what we want
8924 159 : nsIContent* grandParent = parent->GetParent();
8925 159 : if (grandParent) {
8926 : // Has a grandparent, so not what we want
8927 82 : return;
8928 : }
8929 :
8930 : // Check whether it's an HTML body
8931 77 : if (!node->IsHTMLElement(nsGkAtoms::body)) {
8932 77 : return;
8933 : }
8934 : }
8935 :
8936 : // At this point the node has no parent or it's an HTML <body> child of the
8937 : // root. We might not need to invalidate in this case (eg we might be in
8938 : // XHTML or something), but chances are we want to. Play it safe.
8939 : // Invalidate the viewport.
8940 :
8941 24 : nsIFrame* rootFrame = presShell->GetRootFrame();
8942 24 : rootFrame->InvalidateFrameSubtree();
8943 : }
8944 :
8945 : nsIFrame*
8946 0 : nsCSSFrameConstructor::EnsureFrameForTextNode(nsGenericDOMDataNode* aContent)
8947 : {
8948 0 : if (aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
8949 0 : !mAlwaysCreateFramesForIgnorableWhitespace) {
8950 : // Text frame may have been suppressed. Disable suppression and signal
8951 : // that a flush should be performed. We do this on a document-wide
8952 : // basis so that pages that repeatedly query metrics for
8953 : // collapsed-whitespace text nodes don't trigger pathological behavior.
8954 0 : mAlwaysCreateFramesForIgnorableWhitespace = true;
8955 0 : nsAutoScriptBlocker blocker;
8956 0 : BeginUpdate();
8957 0 : ReconstructDocElementHierarchy();
8958 0 : EndUpdate();
8959 : }
8960 0 : return aContent->GetPrimaryFrame();
8961 : }
8962 :
8963 : void
8964 1 : nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
8965 : CharacterDataChangeInfo* aInfo)
8966 : {
8967 2 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
8968 :
8969 2 : if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
8970 2 : !aContent->TextIsOnlyWhitespace()) ||
8971 1 : (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
8972 0 : aContent->TextIsOnlyWhitespace())) {
8973 : #ifdef DEBUG
8974 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
8975 0 : NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
8976 : "Bit should never be set on generated content");
8977 : #endif
8978 0 : LAYOUT_PHASE_TEMP_EXIT();
8979 : RecreateFramesForContent(aContent, false,
8980 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
8981 0 : LAYOUT_PHASE_TEMP_REENTER();
8982 0 : return;
8983 : }
8984 :
8985 : // Find the child frame
8986 1 : nsIFrame* frame = aContent->GetPrimaryFrame();
8987 :
8988 : // Notify the first frame that maps the content. It will generate a reflow
8989 : // command
8990 :
8991 : // It's possible the frame whose content changed isn't inserted into the
8992 : // frame hierarchy yet, or that there is no frame that maps the content
8993 1 : if (nullptr != frame) {
8994 : #if 0
8995 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
8996 : ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
8997 : aContent, ContentTag(aContent, 0),
8998 : aSubContent, frame));
8999 : #endif
9000 :
9001 : // Special check for text content that is a child of a letter frame. If
9002 : // this happens, we should remove the letter frame, do whatever we're
9003 : // planning to do with this notification, then put the letter frame back.
9004 : // Note that this is basically what RecreateFramesForContent ends up doing;
9005 : // the reason we dont' want to call that here is that our text content
9006 : // could be native anonymous, in which case RecreateFramesForContent would
9007 : // completely barf on it. And recreating the non-anonymous ancestor would
9008 : // just lead us to come back into this notification (e.g. if quotes or
9009 : // counters are involved), leading to a loop.
9010 0 : nsContainerFrame* block = GetFloatContainingBlock(frame);
9011 0 : bool haveFirstLetterStyle = false;
9012 0 : if (block) {
9013 : // See if the block has first-letter style applied to it.
9014 0 : haveFirstLetterStyle = HasFirstLetterStyle(block);
9015 0 : if (haveFirstLetterStyle) {
9016 0 : RemoveLetterFrames(mPresShell, block);
9017 : // Reget |frame|, since we might have killed it.
9018 : // Do we really need to call CharacterDataChanged in this case, though?
9019 0 : frame = aContent->GetPrimaryFrame();
9020 0 : NS_ASSERTION(frame, "Should have frame here!");
9021 : }
9022 : }
9023 :
9024 0 : frame->CharacterDataChanged(aInfo);
9025 :
9026 0 : if (haveFirstLetterStyle) {
9027 0 : RecoverLetterFrames(block);
9028 : }
9029 : }
9030 : }
9031 :
9032 : void
9033 835 : nsCSSFrameConstructor::BeginUpdate() {
9034 835 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
9035 : "Someone forgot a script blocker");
9036 :
9037 : nsRootPresContext* rootPresContext =
9038 835 : mPresShell->GetPresContext()->GetRootPresContext();
9039 835 : if (rootPresContext) {
9040 835 : rootPresContext->IncrementDOMGeneration();
9041 : }
9042 :
9043 : #ifdef DEBUG
9044 835 : ++mUpdateCount;
9045 : #endif
9046 835 : }
9047 :
9048 : void
9049 835 : nsCSSFrameConstructor::EndUpdate()
9050 : {
9051 : #ifdef DEBUG
9052 835 : NS_ASSERTION(mUpdateCount, "Negative mUpdateCount!");
9053 835 : --mUpdateCount;
9054 : #endif
9055 835 : }
9056 :
9057 : void
9058 105 : nsCSSFrameConstructor::RecalcQuotesAndCounters()
9059 : {
9060 210 : nsAutoScriptBlocker scriptBlocker;
9061 :
9062 105 : if (mQuotesDirty) {
9063 0 : mQuotesDirty = false;
9064 0 : mQuoteList.RecalcAll();
9065 : }
9066 :
9067 105 : if (mCountersDirty) {
9068 0 : mCountersDirty = false;
9069 0 : mCounterManager.RecalcAll();
9070 : }
9071 :
9072 105 : NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
9073 105 : NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
9074 105 : }
9075 :
9076 : void
9077 0 : nsCSSFrameConstructor::NotifyCounterStylesAreDirty()
9078 : {
9079 0 : NS_PRECONDITION(mUpdateCount != 0, "Should be in an update");
9080 0 : mCounterManager.SetAllDirty();
9081 0 : CountersDirty();
9082 0 : }
9083 :
9084 : void
9085 4 : nsCSSFrameConstructor::WillDestroyFrameTree()
9086 : {
9087 : #if defined(DEBUG_dbaron_off)
9088 : mCounterManager.Dump();
9089 : #endif
9090 :
9091 4 : mIsDestroyingFrameTree = true;
9092 :
9093 : // Prevent frame tree destruction from being O(N^2)
9094 4 : mQuoteList.Clear();
9095 4 : mCounterManager.Clear();
9096 :
9097 : // Remove our presshell as a style flush observer. But leave
9098 : // RestyleManager::mObservingRefreshDriver true so we don't readd to
9099 : // it even if someone tries to post restyle events on us from this
9100 : // point on for some reason.
9101 4 : mPresShell->GetPresContext()->RefreshDriver()->
9102 8 : RemoveStyleFlushObserver(mPresShell);
9103 :
9104 4 : nsFrameManager::Destroy();
9105 4 : }
9106 :
9107 : //STATIC
9108 :
9109 : // XXXbz I'd really like this method to go away. Once we have inline-block and
9110 : // I can just use that for sized broken images, that can happen, maybe.
9111 : void
9112 0 : nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent,
9113 : nsIAtom* aTag,
9114 : nsXPIDLString& aAltText)
9115 : {
9116 : // The "alt" attribute specifies alternate text that is rendered
9117 : // when the image can not be displayed.
9118 0 : if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText)) {
9119 0 : return;
9120 : }
9121 :
9122 0 : if (nsGkAtoms::input == aTag) {
9123 : // If there's no "alt" attribute, and aContent is an input element, then use
9124 : // the value of the "value" attribute
9125 0 : if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
9126 0 : return;
9127 : }
9128 :
9129 : // If there's no "value" attribute either, then use the localized string for
9130 : // "Submit" as the alternate text.
9131 : nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
9132 0 : "Submit", aAltText);
9133 : }
9134 : }
9135 :
9136 : nsIFrame*
9137 0 : nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
9138 : nsPresContext* aPresContext,
9139 : nsIFrame* aFrame,
9140 : nsContainerFrame* aParentFrame,
9141 : nsIContent* aContent,
9142 : nsStyleContext* aStyleContext)
9143 : {
9144 0 : nsTableWrapperFrame* newFrame = NS_NewTableWrapperFrame(aPresShell, aStyleContext);
9145 :
9146 0 : newFrame->Init(aContent, aParentFrame, aFrame);
9147 :
9148 : // Create a continuing inner table frame, and if there's a caption then
9149 : // replicate the caption
9150 0 : nsFrameItems newChildFrames;
9151 :
9152 0 : nsIFrame* childFrame = aFrame->PrincipalChildList().FirstChild();
9153 0 : if (childFrame) {
9154 : nsIFrame* continuingTableFrame =
9155 0 : CreateContinuingFrame(aPresContext, childFrame, newFrame);
9156 0 : newChildFrames.AddChild(continuingTableFrame);
9157 :
9158 0 : NS_ASSERTION(!childFrame->GetNextSibling(),"there can be only one inner table frame");
9159 : }
9160 :
9161 : // Set the table wrapper's initial child list
9162 0 : newFrame->SetInitialChildList(kPrincipalList, newChildFrames);
9163 :
9164 0 : return newFrame;
9165 : }
9166 :
9167 : nsIFrame*
9168 0 : nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
9169 : nsIFrame* aFrame,
9170 : nsContainerFrame* aParentFrame,
9171 : nsIContent* aContent,
9172 : nsStyleContext* aStyleContext)
9173 : {
9174 0 : nsTableFrame* newFrame = NS_NewTableFrame(aPresShell, aStyleContext);
9175 :
9176 0 : newFrame->Init(aContent, aParentFrame, aFrame);
9177 :
9178 : // Replicate any header/footer frames
9179 0 : nsFrameItems childFrames;
9180 0 : for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
9181 : // See if it's a header/footer, possibly wrapped in a scroll frame.
9182 : nsTableRowGroupFrame* rowGroupFrame =
9183 0 : static_cast<nsTableRowGroupFrame*>(childFrame);
9184 : // If the row group was continued, then don't replicate it.
9185 0 : nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
9186 0 : if (rgNextInFlow) {
9187 0 : rowGroupFrame->SetRepeatable(false);
9188 : }
9189 0 : else if (rowGroupFrame->IsRepeatable()) {
9190 : // Replicate the header/footer frame.
9191 : nsTableRowGroupFrame* headerFooterFrame;
9192 0 : nsFrameItems childItems;
9193 :
9194 0 : TreeMatchContextHolder matchContext(mDocument);
9195 : nsFrameConstructorState state(mPresShell,
9196 : matchContext,
9197 : GetAbsoluteContainingBlock(newFrame, FIXED_POS),
9198 : GetAbsoluteContainingBlock(newFrame, ABS_POS),
9199 0 : nullptr);
9200 0 : state.mCreatingExtraFrames = true;
9201 :
9202 0 : nsStyleContext* const headerFooterStyleContext = rowGroupFrame->StyleContext();
9203 : headerFooterFrame = static_cast<nsTableRowGroupFrame*>
9204 0 : (NS_NewTableRowGroupFrame(aPresShell, headerFooterStyleContext));
9205 :
9206 0 : nsIContent* headerFooter = rowGroupFrame->GetContent();
9207 0 : headerFooterFrame->Init(headerFooter, newFrame, nullptr);
9208 :
9209 0 : nsFrameConstructorSaveState absoluteSaveState;
9210 0 : MakeTablePartAbsoluteContainingBlockIfNeeded(state,
9211 : headerFooterStyleContext->StyleDisplay(),
9212 : absoluteSaveState,
9213 0 : headerFooterFrame);
9214 :
9215 0 : ProcessChildren(state, headerFooter, rowGroupFrame->StyleContext(),
9216 : headerFooterFrame, true, childItems, false,
9217 0 : nullptr);
9218 0 : NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
9219 0 : headerFooterFrame->SetInitialChildList(kPrincipalList, childItems);
9220 0 : headerFooterFrame->SetRepeatable(true);
9221 :
9222 : // Table specific initialization
9223 0 : headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
9224 :
9225 : // XXX Deal with absolute and fixed frames...
9226 0 : childFrames.AddChild(headerFooterFrame);
9227 : }
9228 : }
9229 :
9230 : // Set the table frame's initial child list
9231 0 : newFrame->SetInitialChildList(kPrincipalList, childFrames);
9232 :
9233 0 : return newFrame;
9234 : }
9235 :
9236 : nsIFrame*
9237 0 : nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
9238 : nsIFrame* aFrame,
9239 : nsContainerFrame* aParentFrame,
9240 : bool aIsFluid)
9241 : {
9242 0 : nsIPresShell* shell = aPresContext->PresShell();
9243 0 : nsStyleContext* styleContext = aFrame->StyleContext();
9244 0 : nsIFrame* newFrame = nullptr;
9245 0 : nsIFrame* nextContinuation = aFrame->GetNextContinuation();
9246 0 : nsIFrame* nextInFlow = aFrame->GetNextInFlow();
9247 :
9248 : // Use the frame type to determine what type of frame to create
9249 0 : LayoutFrameType frameType = aFrame->Type();
9250 0 : nsIContent* content = aFrame->GetContent();
9251 :
9252 0 : NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE,
9253 : "why CreateContinuingFrame for a non-splittable frame?");
9254 :
9255 0 : if (LayoutFrameType::Text == frameType) {
9256 0 : newFrame = NS_NewContinuingTextFrame(shell, styleContext);
9257 0 : newFrame->Init(content, aParentFrame, aFrame);
9258 0 : } else if (LayoutFrameType::Inline == frameType) {
9259 0 : newFrame = NS_NewInlineFrame(shell, styleContext);
9260 0 : newFrame->Init(content, aParentFrame, aFrame);
9261 0 : } else if (LayoutFrameType::Block == frameType) {
9262 0 : MOZ_ASSERT(!aFrame->IsTableCaption(),
9263 : "no support for fragmenting table captions yet");
9264 0 : newFrame = NS_NewBlockFrame(shell, styleContext);
9265 0 : newFrame->Init(content, aParentFrame, aFrame);
9266 : #ifdef MOZ_XUL
9267 0 : } else if (LayoutFrameType::XULLabel == frameType) {
9268 0 : newFrame = NS_NewXULLabelFrame(shell, styleContext);
9269 0 : newFrame->Init(content, aParentFrame, aFrame);
9270 : #endif
9271 0 : } else if (LayoutFrameType::ColumnSet == frameType) {
9272 0 : MOZ_ASSERT(!aFrame->IsTableCaption(),
9273 : "no support for fragmenting table captions yet");
9274 0 : newFrame = NS_NewColumnSetFrame(shell, styleContext, nsFrameState(0));
9275 0 : newFrame->Init(content, aParentFrame, aFrame);
9276 0 : } else if (LayoutFrameType::Page == frameType) {
9277 : nsContainerFrame* canvasFrame;
9278 0 : newFrame = ConstructPageFrame(shell, aParentFrame, aFrame, canvasFrame);
9279 0 : } else if (LayoutFrameType::TableWrapper == frameType) {
9280 : newFrame =
9281 : CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
9282 0 : content, styleContext);
9283 :
9284 0 : } else if (LayoutFrameType::Table == frameType) {
9285 : newFrame =
9286 : CreateContinuingTableFrame(shell, aFrame, aParentFrame,
9287 0 : content, styleContext);
9288 :
9289 0 : } else if (LayoutFrameType::TableRowGroup == frameType) {
9290 0 : newFrame = NS_NewTableRowGroupFrame(shell, styleContext);
9291 0 : newFrame->Init(content, aParentFrame, aFrame);
9292 0 : if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
9293 0 : nsTableFrame::RegisterPositionedTablePart(newFrame);
9294 : }
9295 0 : } else if (LayoutFrameType::TableRow == frameType) {
9296 0 : nsTableRowFrame* rowFrame = NS_NewTableRowFrame(shell, styleContext);
9297 :
9298 0 : rowFrame->Init(content, aParentFrame, aFrame);
9299 0 : if (rowFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
9300 0 : nsTableFrame::RegisterPositionedTablePart(rowFrame);
9301 : }
9302 :
9303 : // Create a continuing frame for each table cell frame
9304 0 : nsFrameItems newChildList;
9305 0 : nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
9306 0 : while (cellFrame) {
9307 : // See if it's a table cell frame
9308 0 : if (IS_TABLE_CELL(cellFrame->Type())) {
9309 : nsIFrame* continuingCellFrame =
9310 0 : CreateContinuingFrame(aPresContext, cellFrame, rowFrame);
9311 0 : newChildList.AddChild(continuingCellFrame);
9312 : }
9313 0 : cellFrame = cellFrame->GetNextSibling();
9314 : }
9315 :
9316 0 : rowFrame->SetInitialChildList(kPrincipalList, newChildList);
9317 0 : newFrame = rowFrame;
9318 :
9319 0 : } else if (IS_TABLE_CELL(frameType)) {
9320 : // Warning: If you change this and add a wrapper frame around table cell
9321 : // frames, make sure Bug 368554 doesn't regress!
9322 : // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
9323 : nsTableFrame* tableFrame =
9324 0 : static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
9325 : nsTableCellFrame* cellFrame =
9326 0 : NS_NewTableCellFrame(shell, styleContext, tableFrame);
9327 :
9328 0 : cellFrame->Init(content, aParentFrame, aFrame);
9329 0 : if (cellFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
9330 0 : nsTableFrame::RegisterPositionedTablePart(cellFrame);
9331 : }
9332 :
9333 : // Create a continuing area frame
9334 0 : nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
9335 : nsIFrame* continuingBlockFrame =
9336 : CreateContinuingFrame(aPresContext, blockFrame,
9337 0 : static_cast<nsContainerFrame*>(cellFrame));
9338 :
9339 0 : SetInitialSingleChild(cellFrame, continuingBlockFrame);
9340 0 : newFrame = cellFrame;
9341 0 : } else if (LayoutFrameType::Line == frameType) {
9342 0 : newFrame = NS_NewFirstLineFrame(shell, styleContext);
9343 0 : newFrame->Init(content, aParentFrame, aFrame);
9344 0 : } else if (LayoutFrameType::Letter == frameType) {
9345 0 : newFrame = NS_NewFirstLetterFrame(shell, styleContext);
9346 0 : newFrame->Init(content, aParentFrame, aFrame);
9347 0 : } else if (LayoutFrameType::Image == frameType) {
9348 0 : newFrame = NS_NewImageFrame(shell, styleContext);
9349 0 : newFrame->Init(content, aParentFrame, aFrame);
9350 0 : } else if (LayoutFrameType::ImageControl == frameType) {
9351 0 : newFrame = NS_NewImageControlFrame(shell, styleContext);
9352 0 : newFrame->Init(content, aParentFrame, aFrame);
9353 0 : } else if (LayoutFrameType::Placeholder == frameType) {
9354 : // create a continuing out of flow frame
9355 0 : nsIFrame* oofFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
9356 : nsIFrame* oofContFrame =
9357 0 : CreateContinuingFrame(aPresContext, oofFrame, aParentFrame);
9358 : newFrame =
9359 0 : CreatePlaceholderFrameFor(shell, content, oofContFrame,
9360 : aParentFrame, aFrame,
9361 0 : aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK);
9362 0 : } else if (LayoutFrameType::FieldSet == frameType) {
9363 0 : nsContainerFrame* fieldset = NS_NewFieldSetFrame(shell, styleContext);
9364 :
9365 0 : fieldset->Init(content, aParentFrame, aFrame);
9366 :
9367 : // Create a continuing area frame
9368 : // XXXbz we really shouldn't have to do this by hand!
9369 0 : nsContainerFrame* blockFrame = GetFieldSetBlockFrame(aFrame);
9370 0 : if (blockFrame) {
9371 : nsIFrame* continuingBlockFrame =
9372 0 : CreateContinuingFrame(aPresContext, blockFrame, fieldset);
9373 : // Set the fieldset's initial child list
9374 0 : SetInitialSingleChild(fieldset, continuingBlockFrame);
9375 : } else {
9376 0 : MOZ_ASSERT(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
9377 : "FieldSet block may only be null for overflow containers");
9378 : }
9379 0 : newFrame = fieldset;
9380 0 : } else if (LayoutFrameType::Legend == frameType) {
9381 0 : newFrame = NS_NewLegendFrame(shell, styleContext);
9382 0 : newFrame->Init(content, aParentFrame, aFrame);
9383 0 : } else if (LayoutFrameType::FlexContainer == frameType) {
9384 0 : newFrame = NS_NewFlexContainerFrame(shell, styleContext);
9385 0 : newFrame->Init(content, aParentFrame, aFrame);
9386 0 : } else if (LayoutFrameType::GridContainer == frameType) {
9387 0 : newFrame = NS_NewGridContainerFrame(shell, styleContext);
9388 0 : newFrame->Init(content, aParentFrame, aFrame);
9389 0 : } else if (LayoutFrameType::Ruby == frameType) {
9390 0 : newFrame = NS_NewRubyFrame(shell, styleContext);
9391 0 : newFrame->Init(content, aParentFrame, aFrame);
9392 0 : } else if (LayoutFrameType::RubyBaseContainer == frameType) {
9393 0 : newFrame = NS_NewRubyBaseContainerFrame(shell, styleContext);
9394 0 : newFrame->Init(content, aParentFrame, aFrame);
9395 0 : } else if (LayoutFrameType::RubyTextContainer == frameType) {
9396 0 : newFrame = NS_NewRubyTextContainerFrame(shell, styleContext);
9397 0 : newFrame->Init(content, aParentFrame, aFrame);
9398 0 : } else if (LayoutFrameType::Details == frameType) {
9399 0 : newFrame = NS_NewDetailsFrame(shell, styleContext);
9400 0 : newFrame->Init(content, aParentFrame, aFrame);
9401 : } else {
9402 0 : MOZ_CRASH("unexpected frame type");
9403 : }
9404 :
9405 : // Init() set newFrame to be a fluid continuation of aFrame.
9406 : // If we want a non-fluid continuation, we need to call SetPrevContinuation()
9407 : // to reset NS_FRAME_IS_FLUID_CONTINUATION.
9408 0 : if (!aIsFluid) {
9409 0 : newFrame->SetPrevContinuation(aFrame);
9410 : }
9411 :
9412 : // A continuation of generated content is also generated content
9413 0 : if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
9414 0 : newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
9415 : }
9416 :
9417 : // A continuation of nsIAnonymousContentCreator content is also
9418 : // nsIAnonymousContentCreator created content
9419 0 : if (aFrame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
9420 0 : newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
9421 : }
9422 :
9423 : // A continuation of an out-of-flow is also an out-of-flow
9424 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
9425 0 : newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
9426 : }
9427 :
9428 0 : if (nextInFlow) {
9429 0 : nextInFlow->SetPrevInFlow(newFrame);
9430 0 : newFrame->SetNextInFlow(nextInFlow);
9431 0 : } else if (nextContinuation) {
9432 0 : nextContinuation->SetPrevContinuation(newFrame);
9433 0 : newFrame->SetNextContinuation(nextContinuation);
9434 : }
9435 :
9436 0 : NS_POSTCONDITION(!newFrame->GetNextSibling(), "unexpected sibling");
9437 0 : return newFrame;
9438 : }
9439 :
9440 : nsresult
9441 0 : nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
9442 : {
9443 : // Now deal with fixed-pos things.... They should appear on all pages,
9444 : // so we want to move over the placeholders when processing the child
9445 : // of the pageContentFrame.
9446 :
9447 0 : nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
9448 0 : if (!prevPageContentFrame) {
9449 0 : return NS_OK;
9450 : }
9451 : nsContainerFrame* canvasFrame =
9452 0 : do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
9453 0 : nsIFrame* prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
9454 0 : if (!canvasFrame || !prevCanvasFrame) {
9455 : // document's root element frame missing
9456 0 : return NS_ERROR_UNEXPECTED;
9457 : }
9458 :
9459 0 : nsFrameItems fixedPlaceholders;
9460 0 : nsIFrame* firstFixed = prevPageContentFrame->GetChildList(nsIFrame::kFixedList).FirstChild();
9461 0 : if (!firstFixed) {
9462 0 : return NS_OK;
9463 : }
9464 :
9465 : // Don't allow abs-pos descendants of the fixed content to escape the content.
9466 : // This should not normally be possible (because fixed-pos elements should
9467 : // be absolute containers) but fixed-pos tables currently aren't abs-pos
9468 : // containers.
9469 0 : TreeMatchContextHolder matchContext(mDocument);
9470 : nsFrameConstructorState state(mPresShell,
9471 : matchContext,
9472 : aParentFrame,
9473 : nullptr,
9474 0 : mRootElementFrame);
9475 0 : state.mCreatingExtraFrames = true;
9476 :
9477 : // We can't use an ancestor filter here, because we're not going to
9478 : // be usefully recurring down the tree. This means that other
9479 : // places in frame construction can't assume a filter is
9480 : // initialized!
9481 :
9482 : // Iterate across fixed frames and replicate each whose placeholder is a
9483 : // descendant of aFrame. (We don't want to explicitly copy placeholders that
9484 : // are within fixed frames, because that would cause duplicates on the new
9485 : // page - bug 389619)
9486 0 : for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
9487 0 : nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
9488 0 : if (prevPlaceholder &&
9489 0 : nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
9490 : // We want to use the same style as the primary style frame for
9491 : // our content
9492 0 : nsIContent* content = fixed->GetContent();
9493 : nsStyleContext* styleContext =
9494 0 : nsLayoutUtils::GetStyleFrame(content)->StyleContext();
9495 0 : FrameConstructionItemList items;
9496 0 : AddFrameConstructionItemsInternal(state, content, canvasFrame,
9497 : content->NodeInfo()->NameAtom(),
9498 : content->GetNameSpaceID(),
9499 : true,
9500 : styleContext,
9501 : ITEM_ALLOW_XBL_BASE |
9502 : ITEM_ALLOW_PAGE_BREAK,
9503 0 : nullptr, items);
9504 0 : ConstructFramesFromItemList(state, items, canvasFrame, fixedPlaceholders);
9505 : }
9506 : }
9507 :
9508 : // Add the placeholders to our primary child list.
9509 : // XXXbz this is a little screwed up, since the fixed frames will have
9510 : // broken auto-positioning. Oh, well.
9511 0 : NS_ASSERTION(!canvasFrame->PrincipalChildList().FirstChild(),
9512 : "leaking frames; doc root continuation must be empty");
9513 0 : canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders);
9514 0 : return NS_OK;
9515 : }
9516 :
9517 : nsCSSFrameConstructor::InsertionPoint
9518 90 : nsCSSFrameConstructor::GetInsertionPoint(nsIContent* aContainer,
9519 : nsIContent* aChild)
9520 : {
9521 90 : nsBindingManager* bindingManager = mDocument->BindingManager();
9522 :
9523 : nsIContent* insertionElement;
9524 90 : if (aChild) {
9525 : // We've got an explicit insertion child. Check to see if it's
9526 : // anonymous.
9527 49 : if (aChild->GetBindingParent() == aContainer) {
9528 : // This child content is anonymous. Don't use the insertion
9529 : // point, since that's only for the explicit kids.
9530 3 : return InsertionPoint(GetContentInsertionFrameFor(aContainer), aContainer);
9531 : }
9532 :
9533 46 : if (nsContentUtils::HasDistributedChildren(aContainer)) {
9534 : // The container distributes nodes, use the frame of the flattened tree parent.
9535 : // It may be the case that the node is distributed but not matched to any
9536 : // insertion points, so there is no flattened parent.
9537 0 : nsIContent* flattenedParent = aChild->GetFlattenedTreeParent();
9538 0 : if (flattenedParent) {
9539 : return InsertionPoint(GetContentInsertionFrameFor(flattenedParent),
9540 0 : flattenedParent);
9541 : }
9542 0 : return InsertionPoint();
9543 : }
9544 :
9545 46 : insertionElement = bindingManager->FindNestedInsertionPoint(aContainer, aChild);
9546 : } else {
9547 41 : if (nsContentUtils::HasDistributedChildren(aContainer)) {
9548 : // The container distributes nodes to shadow DOM insertion points.
9549 : // Return with aMultiple set to true to induce callers to insert children
9550 : // individually into the node's flattened tree parent.
9551 4 : return InsertionPoint(nullptr, nullptr, true);
9552 : }
9553 :
9554 : bool multiple;
9555 41 : insertionElement = bindingManager->FindNestedSingleInsertionPoint(aContainer, &multiple);
9556 41 : if (multiple) {
9557 4 : return InsertionPoint(nullptr, nullptr, true);
9558 : }
9559 : }
9560 :
9561 83 : if (!insertionElement) {
9562 : // The FindNested{,Single}InsertionPoint methods return null in the case
9563 : // that there is a binding with anonymous content but no insertion point.
9564 : // In that case the element doesn't belong in the flattened tree, and we
9565 : // don't want to render it.
9566 0 : return InsertionPoint();
9567 : }
9568 :
9569 : InsertionPoint insertion(GetContentInsertionFrameFor(insertionElement),
9570 83 : insertionElement);
9571 :
9572 : // Fieldset frames have multiple normal flow child frame lists so handle it
9573 : // the same as if it had multiple content insertion points.
9574 83 : if (insertion.mParentFrame && insertion.mParentFrame->IsFieldSetFrame()) {
9575 0 : insertion.mMultiple = true;
9576 : }
9577 :
9578 : // A details frame moves the first summary frame to be its first child, so we
9579 : // treat it as if it has multiple content insertion points.
9580 83 : if (insertion.mParentFrame && insertion.mParentFrame->IsDetailsFrame()) {
9581 0 : insertion.mMultiple = true;
9582 : }
9583 :
9584 83 : return insertion;
9585 : }
9586 :
9587 : // Capture state for the frame tree rooted at the frame associated with the
9588 : // content object, aContent
9589 : void
9590 17 : nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
9591 : nsILayoutHistoryState* aHistoryState)
9592 : {
9593 17 : if (!aHistoryState) {
9594 0 : return;
9595 : }
9596 17 : nsIFrame* frame = aContent->GetPrimaryFrame();
9597 17 : if (frame == mRootElementFrame) {
9598 0 : frame = mRootElementFrame ?
9599 0 : GetAbsoluteContainingBlock(mRootElementFrame, FIXED_POS) :
9600 0 : GetRootFrame();
9601 : }
9602 45 : for ( ; frame;
9603 : frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
9604 14 : CaptureFrameState(frame, aHistoryState);
9605 : }
9606 : }
9607 :
9608 : static bool
9609 6 : DefinitelyEqualURIsAndPrincipal(mozilla::css::URLValue* aURI1,
9610 : mozilla::css::URLValue* aURI2)
9611 : {
9612 12 : return aURI1 == aURI2 ||
9613 6 : (aURI1 && aURI2 && aURI1->DefinitelyEqualURIsAndPrincipal(*aURI2));
9614 : }
9615 :
9616 : nsStyleContext*
9617 50 : nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
9618 : {
9619 100 : RefPtr<nsStyleContext> oldContext = GetUndisplayedContent(aElement);
9620 50 : StyleDisplay oldDisplay = StyleDisplay::None;
9621 50 : if (!oldContext) {
9622 42 : oldContext = GetDisplayContentsStyleFor(aElement);
9623 42 : if (!oldContext) {
9624 42 : return nullptr;
9625 : }
9626 0 : oldDisplay = StyleDisplay::Contents;
9627 : }
9628 :
9629 : // The parent has a frame, so try resolving a new context.
9630 16 : RefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->
9631 24 : ResolveStyleFor(aElement, oldContext->GetParent(),
9632 16 : LazyComputeBehavior::Assert);
9633 :
9634 8 : if (oldDisplay == StyleDisplay::None) {
9635 8 : ChangeUndisplayedContent(aElement, newContext);
9636 : } else {
9637 0 : ChangeDisplayContents(aElement, newContext);
9638 : }
9639 :
9640 8 : const nsStyleDisplay* disp = newContext->StyleDisplay();
9641 8 : if (oldDisplay == disp->mDisplay) {
9642 : // We can skip trying to recreate frames here, but only if our style
9643 : // context does not have a binding URI that differs from our old one.
9644 : // Otherwise, we should try to recreate, because we may want to apply the
9645 : // new binding
9646 6 : if (!disp->mBinding) {
9647 0 : return newContext;
9648 : }
9649 6 : const nsStyleDisplay* oldDisp = oldContext->PeekStyleDisplay();
9650 12 : if (oldDisp &&
9651 6 : DefinitelyEqualURIsAndPrincipal(disp->mBinding, oldDisp->mBinding)) {
9652 6 : return newContext;
9653 : }
9654 : }
9655 :
9656 2 : RecreateFramesForContent(aElement, false, REMOVE_FOR_RECONSTRUCTION, nullptr);
9657 2 : return nullptr;
9658 : }
9659 :
9660 : static bool
9661 18 : IsWhitespaceFrame(nsIFrame* aFrame)
9662 : {
9663 18 : MOZ_ASSERT(aFrame, "invalid argument");
9664 18 : return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
9665 : }
9666 :
9667 : static nsIFrame*
9668 0 : FindFirstNonWhitespaceChild(nsIFrame* aParentFrame)
9669 : {
9670 0 : nsIFrame* f = aParentFrame->PrincipalChildList().FirstChild();
9671 0 : while (f && IsWhitespaceFrame(f)) {
9672 0 : f = f->GetNextSibling();
9673 : }
9674 0 : return f;
9675 : }
9676 :
9677 : static nsIFrame*
9678 33 : FindNextNonWhitespaceSibling(nsIFrame* aFrame)
9679 : {
9680 33 : nsIFrame* f = aFrame;
9681 33 : do {
9682 33 : f = f->GetNextSibling();
9683 33 : } while (f && IsWhitespaceFrame(f));
9684 33 : return f;
9685 : }
9686 :
9687 : static nsIFrame*
9688 0 : FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
9689 : {
9690 0 : nsIFrame* f = aFrame;
9691 0 : do {
9692 0 : f = f->GetPrevSibling();
9693 0 : } while (f && IsWhitespaceFrame(f));
9694 0 : return f;
9695 : }
9696 :
9697 : bool
9698 33 : nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
9699 : RemoveFlags aFlags,
9700 : nsIContent** aDestroyedFramesFor)
9701 : {
9702 33 : NS_PRECONDITION(aFrame, "Must have a frame");
9703 33 : NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
9704 33 : NS_PRECONDITION(aFrame == aFrame->FirstContinuation(),
9705 : "aFrame not the result of GetPrimaryFrame()?");
9706 :
9707 33 : *aDestroyedFramesFor = nullptr;
9708 :
9709 33 : if (IsFramePartOfIBSplit(aFrame)) {
9710 : // The removal functions can't handle removal of an {ib} split directly; we
9711 : // need to rebuild the containing block.
9712 : #ifdef DEBUG
9713 0 : if (gNoisyContentUpdates) {
9714 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9715 0 : "frame=");
9716 0 : nsFrame::ListTag(stdout, aFrame);
9717 0 : printf(" is ib-split\n");
9718 : }
9719 : #endif
9720 :
9721 0 : ReframeContainingBlock(aFrame, aFlags, aDestroyedFramesFor);
9722 0 : return true;
9723 : }
9724 :
9725 33 : nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
9726 33 : if (insertionFrame && insertionFrame->IsLegendFrame() &&
9727 0 : aFrame->GetParent()->IsFieldSetFrame()) {
9728 : // When we remove the legend for a fieldset, we should reframe
9729 : // the fieldset to ensure another legend is used, if there is one
9730 0 : RecreateFramesForContent(aFrame->GetParent()->GetContent(), false,
9731 0 : aFlags, aDestroyedFramesFor);
9732 0 : return true;
9733 : }
9734 :
9735 : nsIFrame* inFlowFrame =
9736 33 : (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
9737 33 : aFrame->GetPlaceholderFrame() : aFrame;
9738 33 : MOZ_ASSERT(inFlowFrame, "How did that happen?");
9739 33 : MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
9740 : "placeholder for primary frame has previous continuations?");
9741 33 : nsIFrame* parent = inFlowFrame->GetParent();
9742 :
9743 33 : if (parent && parent->IsDetailsFrame()) {
9744 : HTMLSummaryElement* summary =
9745 0 : HTMLSummaryElement::FromContent(aFrame->GetContent());
9746 0 : DetailsFrame* detailsFrame = static_cast<DetailsFrame*>(parent);
9747 :
9748 : // Unlike adding summary element cases, we need to check children of the
9749 : // parent details frame since at this moment the summary element has been
9750 : // already removed from the parent details element's child list.
9751 0 : if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) {
9752 : // When removing a summary, we should reframe the parent details frame to
9753 : // ensure that another summary is used or the default summary is
9754 : // generated.
9755 0 : RecreateFramesForContent(parent->GetContent(),
9756 : false, REMOVE_FOR_RECONSTRUCTION,
9757 0 : aDestroyedFramesFor);
9758 0 : return true;
9759 : }
9760 : }
9761 :
9762 : // Now check for possibly needing to reconstruct due to a pseudo parent
9763 : // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
9764 : // need to be checked here, since all other types of parent will be catched
9765 : // by "Check ruby containers" section below.
9766 33 : if (IsTableOrRubyPseudo(parent)) {
9767 0 : if (FindFirstNonWhitespaceChild(parent) == inFlowFrame ||
9768 0 : !FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()) ||
9769 : // If it is a whitespace, and is the only child of the parent, the
9770 : // pseudo parent was created for the space, and should now be removed.
9771 0 : (IsWhitespaceFrame(aFrame) &&
9772 0 : parent->PrincipalChildList().OnlyChild()) ||
9773 : // If we're a table-column-group, then the OnlyChild check above is
9774 : // not going to catch cases when we're the first child.
9775 0 : (inFlowFrame->IsTableColGroupFrame() &&
9776 0 : parent->GetChildList(nsIFrame::kColGroupList).FirstChild() == inFlowFrame) ||
9777 : // Similar if we're a table-caption.
9778 0 : (inFlowFrame->IsTableCaption() &&
9779 0 : parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
9780 : // We're the first or last frame in the pseudo. Need to reframe.
9781 : // Good enough to recreate frames for |parent|'s content
9782 0 : RecreateFramesForContent(parent->GetContent(), true, aFlags,
9783 0 : aDestroyedFramesFor);
9784 0 : return true;
9785 : }
9786 : }
9787 :
9788 : // Might need to reconstruct things if this frame's nextSibling is a table
9789 : // or ruby pseudo, since removal of this frame might mean that this pseudo
9790 : // needs to get merged with the frame's prevSibling if that's also a table
9791 : // or ruby pseudo.
9792 : nsIFrame* nextSibling =
9793 33 : FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
9794 33 : NS_ASSERTION(!IsTableOrRubyPseudo(inFlowFrame), "Shouldn't happen here");
9795 : // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
9796 : // need to be checked here, since all other types of such frames will have
9797 : // a ruby container parent, and be catched by "Check ruby containers" below.
9798 33 : if (nextSibling && IsTableOrRubyPseudo(nextSibling)) {
9799 0 : nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
9800 0 : if (prevSibling && IsTableOrRubyPseudo(prevSibling)) {
9801 : #ifdef DEBUG
9802 0 : if (gNoisyContentUpdates) {
9803 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9804 0 : "frame=");
9805 0 : nsFrame::ListTag(stdout, aFrame);
9806 : printf(" has a table pseudo next sibling of different type and a "
9807 0 : "table pseudo prevsibling\n");
9808 : }
9809 : #endif
9810 : // Good enough to recreate frames for aFrame's parent's content; even if
9811 : // aFrame's parent is a pseudo, that'll be the right content node.
9812 0 : RecreateFramesForContent(parent->GetContent(), true, aFlags,
9813 0 : aDestroyedFramesFor);
9814 0 : return true;
9815 : }
9816 : }
9817 :
9818 : // Check ruby containers
9819 33 : LayoutFrameType parentType = parent->Type();
9820 66 : if (parentType == LayoutFrameType::Ruby ||
9821 33 : RubyUtils::IsRubyContainerBox(parentType)) {
9822 : // In ruby containers, pseudo frames may be created from
9823 : // whitespaces or even nothing. There are two cases we actually
9824 : // need to handle here, but hard to check exactly:
9825 : // 1. Status of spaces beside the frame may vary, and related
9826 : // frames may be constructed or destroyed accordingly.
9827 : // 2. The type of the first child of a ruby frame determines
9828 : // whether a pseudo ruby base container should exist.
9829 0 : RecreateFramesForContent(parent->GetContent(), true, aFlags,
9830 0 : aDestroyedFramesFor);
9831 0 : return true;
9832 : }
9833 :
9834 : // Might need to reconstruct things if the removed frame's nextSibling is an
9835 : // anonymous flex item. The removed frame might've been what divided two
9836 : // runs of inline content into two anonymous flex items, which would now
9837 : // need to be merged.
9838 : // NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
9839 : // we're only interested in anonymous flex items here, and those can never
9840 : // be adjacent to whitespace, since they absorb contiguous runs of inline
9841 : // non-replaced content (including whitespace).
9842 33 : if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
9843 0 : AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
9844 : #ifdef DEBUG
9845 0 : if (gNoisyContentUpdates) {
9846 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9847 0 : "frame=");
9848 0 : nsFrame::ListTag(stdout, aFrame);
9849 0 : printf(" has an anonymous flex item as its next sibling\n");
9850 : }
9851 : #endif // DEBUG
9852 : // Recreate frames for the flex container (the removed frame's parent)
9853 0 : RecreateFramesForContent(parent->GetContent(), true, aFlags,
9854 0 : aDestroyedFramesFor);
9855 0 : return true;
9856 : }
9857 :
9858 : // Might need to reconstruct things if the removed frame's nextSibling is
9859 : // null and its parent is an anonymous flex item. (This might be the last
9860 : // remaining child of that anonymous flex item, which can then go away.)
9861 33 : if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
9862 0 : AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
9863 : #ifdef DEBUG
9864 0 : if (gNoisyContentUpdates) {
9865 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9866 0 : "frame=");
9867 0 : nsFrame::ListTag(stdout, aFrame);
9868 0 : printf(" has an anonymous flex item as its parent\n");
9869 : }
9870 : #endif // DEBUG
9871 : // Recreate frames for the flex container (the removed frame's grandparent)
9872 0 : RecreateFramesForContent(parent->GetParent()->GetContent(), true,
9873 0 : aFlags, aDestroyedFramesFor);
9874 0 : return true;
9875 : }
9876 :
9877 : #ifdef MOZ_XUL
9878 33 : if (aFrame->IsPopupSetFrame()) {
9879 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
9880 0 : if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
9881 0 : ReconstructDocElementHierarchy();
9882 0 : return true;
9883 : }
9884 : }
9885 : #endif
9886 :
9887 : // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
9888 : // a non-fluid continuation, i.e. it was split by bidi resolution
9889 87 : if (!inFlowFrame->GetPrevSibling() &&
9890 48 : !inFlowFrame->GetNextSibling() &&
9891 30 : ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
9892 15 : (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
9893 0 : RecreateFramesForContent(parent->GetContent(), true, aFlags,
9894 0 : aDestroyedFramesFor);
9895 0 : return true;
9896 : }
9897 :
9898 : // We might still need to reconstruct things if the parent of inFlowFrame is
9899 : // ib-split, since in that case the removal of aFrame might affect the
9900 : // splitting of its parent.
9901 33 : if (!IsFramePartOfIBSplit(parent)) {
9902 33 : return false;
9903 : }
9904 :
9905 : // If inFlowFrame is not the only in-flow child of |parent|, then removing
9906 : // it will change nothing about the {ib} split.
9907 0 : if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
9908 0 : inFlowFrame->LastContinuation()->GetNextSibling()) {
9909 0 : return false;
9910 : }
9911 :
9912 : // If the parent is the first or last part of the {ib} split, then
9913 : // removing one of its kids will have no effect on the splitting.
9914 : // Get the first continuation up front so we don't have to do it twice.
9915 0 : nsIFrame* parentFirstContinuation = parent->FirstContinuation();
9916 0 : if (!GetIBSplitSibling(parentFirstContinuation) ||
9917 0 : !GetIBSplitPrevSibling(parentFirstContinuation)) {
9918 0 : return false;
9919 : }
9920 :
9921 : #ifdef DEBUG
9922 0 : if (gNoisyContentUpdates) {
9923 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9924 0 : "frame=");
9925 0 : nsFrame::ListTag(stdout, parent);
9926 0 : printf(" is ib-split\n");
9927 : }
9928 : #endif
9929 :
9930 0 : ReframeContainingBlock(parent, aFlags, aDestroyedFramesFor);
9931 0 : return true;
9932 : }
9933 :
9934 : void
9935 17 : nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
9936 : bool aAsyncInsert,
9937 : RemoveFlags aFlags,
9938 : nsIContent** aDestroyedFramesFor)
9939 : {
9940 17 : NS_PRECONDITION(!aAsyncInsert || aContent->IsElement(),
9941 : "Can only insert elements async");
9942 : // If there is no document, we don't want to recreate frames for it. (You
9943 : // shouldn't generally be giving this method content without a document
9944 : // anyway).
9945 : // Rebuilding the frame tree can have bad effects, especially if it's the
9946 : // frame tree for chrome (see bug 157322).
9947 17 : if (NS_WARN_IF(!aContent->GetComposedDoc())) {
9948 0 : return;
9949 : }
9950 :
9951 : // Is the frame ib-split? If so, we need to reframe the containing
9952 : // block *here*, rather than trying to remove and re-insert the
9953 : // content (which would otherwise result in *two* nested reframe
9954 : // containing block from ContentRemoved() and ContentInserted(),
9955 : // below!). We'd really like to optimize away one of those
9956 : // containing block reframes, hence the code here.
9957 :
9958 17 : nsIFrame* frame = aContent->GetPrimaryFrame();
9959 17 : if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
9960 : // Reframe the topmost MathML element to prevent exponential blowup
9961 : // (see bug 397518)
9962 : while (true) {
9963 0 : nsIContent* parentContent = aContent->GetParent();
9964 0 : nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame();
9965 0 : if (!parentContentFrame || !parentContentFrame->IsFrameOfType(nsIFrame::eMathML))
9966 0 : break;
9967 0 : aContent = parentContent;
9968 0 : frame = parentContentFrame;
9969 0 : }
9970 : }
9971 :
9972 17 : if (frame) {
9973 14 : nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
9974 14 : if (nonGeneratedAncestor->GetContent() != aContent) {
9975 0 : return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), aAsyncInsert,
9976 0 : aFlags, aDestroyedFramesFor);
9977 : }
9978 :
9979 14 : if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
9980 : // Recreate the frames for the entire nsIAnonymousContentCreator tree
9981 : // since |frame| or one of its descendants may need an nsStyleContext
9982 : // that associates it to a CSS pseudo-element, and only the
9983 : // nsIAnonymousContentCreator that created this content knows how to make
9984 : // that happen.
9985 0 : nsIAnonymousContentCreator* acc = nullptr;
9986 0 : nsIFrame* ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
9987 0 : while (!(acc = do_QueryFrame(ancestor))) {
9988 0 : ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(ancestor);
9989 : }
9990 0 : NS_ASSERTION(acc, "Where is the nsIAnonymousContentCreator? We may fail "
9991 : "to recreate its content correctly");
9992 : // nsSVGUseFrame is special, and we know this is unnecessary for it.
9993 0 : if (!ancestor->IsSVGUseFrame()) {
9994 0 : NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
9995 : "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
9996 0 : return RecreateFramesForContent(ancestor->GetContent(), aAsyncInsert,
9997 0 : aFlags, aDestroyedFramesFor);
9998 : }
9999 : }
10000 :
10001 14 : nsIFrame* parent = frame->GetParent();
10002 14 : nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
10003 : // If the parent frame is a leaf then the subsequent insert will fail to
10004 : // create a frame, so we need to recreate the parent content. This happens
10005 : // with native anonymous content from the editor.
10006 14 : if (parent && parent->IsLeaf() && parentContent &&
10007 : parentContent != aContent) {
10008 0 : return RecreateFramesForContent(parentContent, aAsyncInsert, aFlags,
10009 0 : aDestroyedFramesFor);
10010 : }
10011 : }
10012 :
10013 : nsIContent* container;
10014 17 : if (frame && MaybeRecreateContainerForFrameRemoval(frame, aFlags,
10015 : &container)) {
10016 0 : MOZ_ASSERT(container);
10017 0 : if (aDestroyedFramesFor) {
10018 0 : *aDestroyedFramesFor = container;
10019 : }
10020 0 : return;
10021 : }
10022 :
10023 17 : nsINode* containerNode = aContent->GetParentNode();
10024 : // XXXbz how can containerNode be null here?
10025 17 : if (containerNode) {
10026 : // Before removing the frames associated with the content object,
10027 : // ask them to save their state onto a temporary state object.
10028 17 : CaptureStateForFramesOf(aContent, mTempFrameTreeState);
10029 :
10030 : // Need the nsIContent parent, which might be null here, since we need to
10031 : // pass it to ContentInserted and ContentRemoved.
10032 34 : nsCOMPtr<nsIContent> container = aContent->GetParent();
10033 :
10034 : // Remove the frames associated with the content object.
10035 : bool didReconstruct;
10036 30 : nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ?
10037 30 : nullptr : aContent->GetNextSibling();
10038 17 : const bool reconstruct = aFlags != REMOVE_DESTROY_FRAMES;
10039 17 : RemoveFlags flags = reconstruct ? REMOVE_FOR_RECONSTRUCTION : aFlags;
10040 17 : ContentRemoved(container, aContent, nextSibling, flags,
10041 17 : &didReconstruct, aDestroyedFramesFor);
10042 17 : if (reconstruct && !didReconstruct) {
10043 : // Now, recreate the frames associated with this content object. If
10044 : // ContentRemoved triggered reconstruction, then we don't need to do this
10045 : // because the frames will already have been built.
10046 17 : if (aAsyncInsert) {
10047 : // XXXmats doesn't frame state need to be restored in this case too?
10048 0 : RestyleManager()->PostRestyleEvent(
10049 0 : aContent->AsElement(), nsRestyleHint(0), nsChangeHint_ReconstructFrame);
10050 : } else {
10051 17 : ContentRangeInserted(container, aContent, aContent->GetNextSibling(),
10052 : mTempFrameTreeState,
10053 : false, // aAllowLazyConstruction
10054 : true, // aForReconstruction
10055 17 : nullptr);
10056 : }
10057 : }
10058 : }
10059 : }
10060 :
10061 : void
10062 0 : nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent,
10063 : nsIContent** aDestroyedFramesFor)
10064 : {
10065 0 : MOZ_ASSERT(aContent && aContent->GetParentNode());
10066 :
10067 : bool didReconstruct;
10068 : nsIContent* nextSibling =
10069 0 : aContent->IsRootOfAnonymousSubtree() ? nullptr : aContent->GetNextSibling();
10070 0 : ContentRemoved(aContent->GetParent(), aContent, nextSibling,
10071 0 : REMOVE_DESTROY_FRAMES, &didReconstruct, aDestroyedFramesFor);
10072 0 : }
10073 :
10074 : //////////////////////////////////////////////////////////////////////
10075 :
10076 : // Block frame construction code
10077 :
10078 : already_AddRefed<nsStyleContext>
10079 0 : nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
10080 : nsStyleContext* aStyleContext)
10081 : {
10082 0 : if (aContent) {
10083 0 : return mPresShell->StyleSet()->
10084 : ResolvePseudoElementStyle(aContent->AsElement(),
10085 : CSSPseudoElementType::firstLetter,
10086 : aStyleContext,
10087 0 : nullptr);
10088 : }
10089 0 : return nullptr;
10090 : }
10091 :
10092 : already_AddRefed<nsStyleContext>
10093 0 : nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
10094 : nsStyleContext* aStyleContext)
10095 : {
10096 0 : if (aContent) {
10097 0 : return mPresShell->StyleSet()->
10098 : ResolvePseudoElementStyle(aContent->AsElement(),
10099 : CSSPseudoElementType::firstLine,
10100 : aStyleContext,
10101 0 : nullptr);
10102 : }
10103 0 : return nullptr;
10104 : }
10105 :
10106 : // Predicate to see if a given content (block element) has
10107 : // first-letter style applied to it.
10108 : bool
10109 22 : nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
10110 : nsStyleContext* aStyleContext)
10111 : {
10112 22 : return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
10113 : CSSPseudoElementType::firstLetter,
10114 44 : mPresShell->GetPresContext());
10115 : }
10116 :
10117 : bool
10118 15 : nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame)
10119 : {
10120 15 : NS_PRECONDITION(aBlockFrame, "Need a frame");
10121 15 : NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
10122 : "Not a block frame?");
10123 :
10124 15 : return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0;
10125 : }
10126 :
10127 : bool
10128 31 : nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
10129 : nsStyleContext* aStyleContext)
10130 : {
10131 : bool hasFirstLine =
10132 31 : nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
10133 : CSSPseudoElementType::firstLine,
10134 62 : mPresShell->GetPresContext());
10135 31 : if (hasFirstLine) {
10136 : // But disable for fieldsets
10137 : int32_t namespaceID;
10138 0 : nsIAtom* tag = mDocument->BindingManager()->ResolveTag(aContent,
10139 0 : &namespaceID);
10140 : // This check must match the one in FindHTMLData.
10141 0 : hasFirstLine = tag != nsGkAtoms::fieldset ||
10142 0 : namespaceID != kNameSpaceID_XHTML;
10143 : }
10144 :
10145 31 : return hasFirstLine;
10146 : }
10147 :
10148 : void
10149 22 : nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent* aContent,
10150 : nsStyleContext* aStyleContext,
10151 : bool* aHaveFirstLetterStyle,
10152 : bool* aHaveFirstLineStyle)
10153 : {
10154 22 : *aHaveFirstLetterStyle =
10155 22 : ShouldHaveFirstLetterStyle(aContent, aStyleContext);
10156 22 : *aHaveFirstLineStyle =
10157 22 : ShouldHaveFirstLineStyle(aContent, aStyleContext);
10158 22 : }
10159 :
10160 : /* static */
10161 : const nsCSSFrameConstructor::PseudoParentData
10162 : nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
10163 : { // Cell
10164 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
10165 : FCDATA_USE_CHILD_ITEMS |
10166 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
10167 : &nsCSSFrameConstructor::ConstructTableCell),
10168 : &nsCSSAnonBoxes::tableCell
10169 : },
10170 : { // Row
10171 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
10172 : FCDATA_USE_CHILD_ITEMS |
10173 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
10174 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
10175 : &nsCSSAnonBoxes::tableRow
10176 : },
10177 : { // Row group
10178 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
10179 : FCDATA_USE_CHILD_ITEMS |
10180 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
10181 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
10182 : &nsCSSAnonBoxes::tableRowGroup
10183 : },
10184 : { // Column group
10185 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
10186 : FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
10187 : FCDATA_SKIP_ABSPOS_PUSH |
10188 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
10189 : NS_NewTableColGroupFrame),
10190 : &nsCSSAnonBoxes::tableColGroup
10191 : },
10192 : { // Table
10193 : FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
10194 : &nsCSSFrameConstructor::ConstructTable),
10195 : &nsCSSAnonBoxes::table
10196 : },
10197 : { // Ruby
10198 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
10199 : FCDATA_USE_CHILD_ITEMS |
10200 : FCDATA_SKIP_FRAMESET,
10201 : NS_NewRubyFrame),
10202 : &nsCSSAnonBoxes::ruby
10203 : },
10204 : { // Ruby Base
10205 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
10206 : FCDATA_IS_LINE_PARTICIPANT |
10207 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
10208 : FCDATA_SKIP_FRAMESET,
10209 : NS_NewRubyBaseFrame),
10210 : &nsCSSAnonBoxes::rubyBase
10211 : },
10212 : { // Ruby Base Container
10213 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
10214 : FCDATA_IS_LINE_PARTICIPANT |
10215 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
10216 : FCDATA_SKIP_FRAMESET,
10217 : NS_NewRubyBaseContainerFrame),
10218 : &nsCSSAnonBoxes::rubyBaseContainer
10219 : },
10220 : { // Ruby Text
10221 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
10222 : FCDATA_IS_LINE_PARTICIPANT |
10223 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
10224 : FCDATA_SKIP_FRAMESET,
10225 : NS_NewRubyTextFrame),
10226 : &nsCSSAnonBoxes::rubyText
10227 : },
10228 : { // Ruby Text Container
10229 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
10230 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
10231 : FCDATA_SKIP_FRAMESET,
10232 : NS_NewRubyTextContainerFrame),
10233 : &nsCSSAnonBoxes::rubyTextContainer
10234 : }
10235 : };
10236 :
10237 : void
10238 413 : nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
10239 : nsFrameConstructorState& aState,
10240 : FrameConstructionItemList& aItems,
10241 : nsIFrame* aParentFrame)
10242 : {
10243 413 : if (aItems.IsEmpty()) {
10244 539 : return;
10245 : }
10246 287 : const LayoutFrameType parentType = aParentFrame->Type();
10247 287 : if (parentType != LayoutFrameType::FlexContainer &&
10248 : parentType != LayoutFrameType::GridContainer) {
10249 287 : return;
10250 : }
10251 :
10252 0 : const bool isWebkitBox = IsFlexContainerForLegacyBox(aParentFrame);
10253 0 : FCItemIterator iter(aItems);
10254 0 : do {
10255 : // Advance iter past children that don't want to be wrapped
10256 0 : if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, isWebkitBox)) {
10257 : // Hit the end of the items without finding any remaining children that
10258 : // need to be wrapped. We're finished!
10259 0 : return;
10260 : }
10261 :
10262 : // If our next potentially-wrappable child is whitespace, then see if
10263 : // there's anything wrappable immediately after it. If not, we just drop
10264 : // the whitespace and move on. (We're not supposed to create any anonymous
10265 : // flex/grid items that _only_ contain whitespace).
10266 : // (BUT if this is generated content, then we don't give whitespace nodes
10267 : // any special treatment, because they're probably not really whitespace --
10268 : // they're just temporarily empty, waiting for their generated text.)
10269 : // XXXdholbert If this node's generated text will *actually end up being
10270 : // entirely whitespace*, then we technically should still skip over it, per
10271 : // the CSS grid & flexbox specs. I'm not bothering with that at this point,
10272 : // since it's a pretty extreme edge case.
10273 0 : if (!aParentFrame->IsGeneratedContentFrame() &&
10274 0 : iter.item().IsWhitespace(aState)) {
10275 0 : FCItemIterator afterWhitespaceIter(iter);
10276 0 : bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
10277 : bool nextChildNeedsAnonItem =
10278 0 : !hitEnd &&
10279 0 : afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox);
10280 :
10281 0 : if (!nextChildNeedsAnonItem) {
10282 : // There's nothing after the whitespace that we need to wrap, so we
10283 : // just drop this run of whitespace.
10284 0 : iter.DeleteItemsTo(afterWhitespaceIter);
10285 0 : if (hitEnd) {
10286 : // Nothing left to do -- we're finished!
10287 0 : return;
10288 : }
10289 : // else, we have a next child and it does not want to be wrapped. So,
10290 : // we jump back to the beginning of the loop to skip over that child
10291 : // (and anything else non-wrappable after it)
10292 0 : MOZ_ASSERT(!iter.IsDone() &&
10293 : !iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox),
10294 : "hitEnd and/or nextChildNeedsAnonItem lied");
10295 0 : continue;
10296 : }
10297 : }
10298 :
10299 : // Now |iter| points to the first child that needs to be wrapped in an
10300 : // anonymous flex/grid item. Now we see how many children after it also want
10301 : // to be wrapped in an anonymous flex/grid item.
10302 0 : FCItemIterator endIter(iter); // iterator to find the end of the group
10303 0 : endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isWebkitBox);
10304 :
10305 0 : NS_ASSERTION(iter != endIter,
10306 : "Should've had at least one wrappable child to seek past");
10307 :
10308 : // Now, we create the anonymous flex or grid item to contain the children
10309 : // between |iter| and |endIter|.
10310 0 : nsIAtom* pseudoType = (aParentFrame->IsFlexContainerFrame())
10311 : ? nsCSSAnonBoxes::anonymousFlexItem
10312 0 : : nsCSSAnonBoxes::anonymousGridItem;
10313 0 : nsStyleContext* parentStyle = aParentFrame->StyleContext();
10314 0 : nsIContent* parentContent = aParentFrame->GetContent();
10315 : already_AddRefed<nsStyleContext> wrapperStyle =
10316 0 : mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
10317 0 : parentStyle);
10318 :
10319 : static const FrameConstructionData sBlockFormattingContextFCData =
10320 : FCDATA_DECL(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
10321 : NS_NewBlockFormattingContext);
10322 :
10323 : FrameConstructionItem* newItem =
10324 : new FrameConstructionItem(&sBlockFormattingContextFCData,
10325 : // Use the content of our parent frame
10326 : parentContent,
10327 : // Lie about the tag; it doesn't matter anyway
10328 : pseudoType,
10329 0 : iter.item().mNameSpaceID,
10330 : // no pending binding
10331 : nullptr,
10332 : wrapperStyle,
10333 0 : true, nullptr);
10334 :
10335 0 : newItem->mIsAllInline = newItem->mHasInlineEnds =
10336 0 : newItem->mStyleContext->StyleDisplay()->IsInlineOutsideStyle();
10337 0 : newItem->mIsBlock = !newItem->mIsAllInline;
10338 :
10339 0 : MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,
10340 : "expecting anonymous flex/grid items to be block-level "
10341 : "(this will make a difference when we encounter "
10342 : "'align-items: baseline')");
10343 :
10344 : // Anonymous flex and grid items induce line boundaries around their
10345 : // contents.
10346 0 : newItem->mChildItems.SetLineBoundaryAtStart(true);
10347 0 : newItem->mChildItems.SetLineBoundaryAtEnd(true);
10348 : // The parent of the items in aItems is also the parent of the items
10349 : // in mChildItems
10350 0 : newItem->mChildItems.SetParentHasNoXBLChildren(
10351 0 : aItems.ParentHasNoXBLChildren());
10352 :
10353 : // Eat up all items between |iter| and |endIter| and put them in our
10354 : // wrapper. This advances |iter| to point to |endIter|.
10355 0 : iter.AppendItemsToList(endIter, newItem->mChildItems);
10356 :
10357 0 : iter.InsertItem(newItem);
10358 0 : } while (!iter.IsDone());
10359 : }
10360 :
10361 : /* static */ nsCSSFrameConstructor::RubyWhitespaceType
10362 0 : nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
10363 : StyleDisplay aNextDisplay)
10364 : {
10365 0 : MOZ_ASSERT(nsStyleDisplay::IsRubyDisplayType(aPrevDisplay) &&
10366 : nsStyleDisplay::IsRubyDisplayType(aNextDisplay));
10367 0 : if (aPrevDisplay == aNextDisplay &&
10368 0 : (aPrevDisplay == StyleDisplay::RubyBase ||
10369 : aPrevDisplay == StyleDisplay::RubyText)) {
10370 0 : return eRubyInterLeafWhitespace;
10371 : }
10372 0 : if (aNextDisplay == StyleDisplay::RubyText ||
10373 : aNextDisplay == StyleDisplay::RubyTextContainer) {
10374 0 : return eRubyInterLevelWhitespace;
10375 : }
10376 0 : return eRubyInterSegmentWhitespace;
10377 : }
10378 :
10379 : /**
10380 : * This function checks the content from |aStartIter| to |aEndIter|,
10381 : * determines whether it contains only whitespace, and if yes,
10382 : * interprets the type of whitespace. This method does not change
10383 : * any of the iters.
10384 : */
10385 : /* static */ nsCSSFrameConstructor::RubyWhitespaceType
10386 0 : nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
10387 : const FCItemIterator& aStartIter,
10388 : const FCItemIterator& aEndIter)
10389 : {
10390 0 : if (!aStartIter.item().IsWhitespace(aState)) {
10391 0 : return eRubyNotWhitespace;
10392 : }
10393 :
10394 0 : FCItemIterator spaceEndIter(aStartIter);
10395 0 : spaceEndIter.SkipWhitespace(aState);
10396 0 : if (spaceEndIter != aEndIter) {
10397 0 : return eRubyNotWhitespace;
10398 : }
10399 :
10400 : // Any leading or trailing whitespace in non-pseudo ruby box
10401 : // should have been trimmed, hence there should not be any
10402 : // whitespace at the start or the end.
10403 0 : MOZ_ASSERT(!aStartIter.AtStart() && !aEndIter.IsDone());
10404 0 : FCItemIterator prevIter(aStartIter);
10405 0 : prevIter.Prev();
10406 : return ComputeRubyWhitespaceType(
10407 0 : prevIter.item().mStyleContext->StyleDisplay()->mDisplay,
10408 0 : aEndIter.item().mStyleContext->StyleDisplay()->mDisplay);
10409 : }
10410 :
10411 :
10412 : /**
10413 : * This function eats up consecutive items which do not want the current
10414 : * parent into either a ruby base box or a ruby text box. When it
10415 : * returns, |aIter| points to the first item it doesn't wrap.
10416 : */
10417 : void
10418 0 : nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
10419 : FCItemIterator& aIter,
10420 : nsStyleContext* aParentStyle, nsIContent* aParentContent)
10421 : {
10422 0 : StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
10423 : ParentType parentType, wrapperType;
10424 0 : if (parentDisplay == StyleDisplay::RubyTextContainer) {
10425 0 : parentType = eTypeRubyTextContainer;
10426 0 : wrapperType = eTypeRubyText;
10427 : } else {
10428 0 : MOZ_ASSERT(parentDisplay == StyleDisplay::RubyBaseContainer);
10429 0 : parentType = eTypeRubyBaseContainer;
10430 0 : wrapperType = eTypeRubyBase;
10431 : }
10432 :
10433 0 : MOZ_ASSERT(aIter.item().DesiredParentType() != parentType,
10434 : "Should point to something needs to be wrapped.");
10435 :
10436 0 : FCItemIterator endIter(aIter);
10437 0 : endIter.SkipItemsNotWantingParentType(parentType);
10438 :
10439 : WrapItemsInPseudoParent(aParentContent, aParentStyle,
10440 0 : wrapperType, aIter, endIter);
10441 0 : }
10442 :
10443 : /**
10444 : * This function eats up consecutive items into a ruby level container.
10445 : * It may create zero or one level container. When it returns, |aIter|
10446 : * points to the first item it doesn't wrap.
10447 : */
10448 : void
10449 0 : nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
10450 : nsFrameConstructorState& aState, FCItemIterator& aIter,
10451 : nsStyleContext* aParentStyle, nsIContent* aParentContent)
10452 : {
10453 0 : MOZ_ASSERT(aIter.item().DesiredParentType() != eTypeRuby,
10454 : "Pointing to a level container?");
10455 :
10456 0 : FrameConstructionItem& firstItem = aIter.item();
10457 0 : ParentType wrapperType = firstItem.DesiredParentType();
10458 0 : if (wrapperType != eTypeRubyTextContainer) {
10459 : // If the first item is not ruby text,
10460 : // it should be in a base container.
10461 0 : wrapperType = eTypeRubyBaseContainer;
10462 : }
10463 :
10464 0 : FCItemIterator endIter(aIter);
10465 0 : do {
10466 0 : if (endIter.SkipItemsWantingParentType(wrapperType) ||
10467 : // If the skipping above stops at some item which wants a
10468 : // different ruby parent, then we have finished.
10469 0 : IsRubyParentType(endIter.item().DesiredParentType())) {
10470 : // No more items need to be wrapped in this level container.
10471 0 : break;
10472 : }
10473 :
10474 0 : FCItemIterator contentEndIter(endIter);
10475 0 : contentEndIter.SkipItemsNotWantingRubyParent();
10476 : // endIter must be on something doesn't want a ruby parent.
10477 0 : MOZ_ASSERT(contentEndIter != endIter);
10478 :
10479 : // InterpretRubyWhitespace depends on the fact that any leading or
10480 : // trailing whitespace described in the spec have been trimmed at
10481 : // this point. With this precondition, it is safe not to check
10482 : // whether contentEndIter has been done.
10483 : RubyWhitespaceType whitespaceType =
10484 0 : InterpretRubyWhitespace(aState, endIter, contentEndIter);
10485 0 : if (whitespaceType == eRubyInterLevelWhitespace) {
10486 : // Remove inter-level whitespace.
10487 0 : bool atStart = (aIter == endIter);
10488 0 : endIter.DeleteItemsTo(contentEndIter);
10489 0 : if (atStart) {
10490 0 : aIter = endIter;
10491 : }
10492 0 : } else if (whitespaceType == eRubyInterSegmentWhitespace) {
10493 : // If this level container starts with inter-segment whitespaces,
10494 : // wrap them. Break at contentEndIter. Otherwise, leave it here.
10495 : // Break at endIter. They will be wrapped when we are here again.
10496 0 : if (aIter == endIter) {
10497 0 : MOZ_ASSERT(wrapperType == eTypeRubyBaseContainer,
10498 : "Inter-segment whitespace should be wrapped in rbc");
10499 0 : endIter = contentEndIter;
10500 : }
10501 0 : break;
10502 0 : } else if (wrapperType == eTypeRubyTextContainer &&
10503 : whitespaceType != eRubyInterLeafWhitespace) {
10504 : // Misparented inline content that's not inter-annotation
10505 : // whitespace doesn't belong in a pseudo ruby text container.
10506 : // Break at endIter.
10507 : break;
10508 : } else {
10509 0 : endIter = contentEndIter;
10510 : }
10511 0 : } while (!endIter.IsDone());
10512 :
10513 : // It is possible that everything our parent wants us to wrap is
10514 : // simply an inter-level whitespace, which has been trimmed, or
10515 : // an inter-segment whitespace, which will be wrapped later.
10516 : // In those cases, don't create anything.
10517 0 : if (aIter != endIter) {
10518 : WrapItemsInPseudoParent(aParentContent, aParentStyle,
10519 0 : wrapperType, aIter, endIter);
10520 : }
10521 0 : }
10522 :
10523 : /**
10524 : * This function trims leading and trailing whitespaces
10525 : * in the given item list.
10526 : */
10527 : void
10528 0 : nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
10529 : nsFrameConstructorState& aState,
10530 : FrameConstructionItemList& aItems)
10531 : {
10532 0 : FCItemIterator iter(aItems);
10533 0 : if (!iter.IsDone() &&
10534 0 : iter.item().IsWhitespace(aState)) {
10535 0 : FCItemIterator spaceEndIter(iter);
10536 0 : spaceEndIter.SkipWhitespace(aState);
10537 0 : iter.DeleteItemsTo(spaceEndIter);
10538 : }
10539 :
10540 0 : iter.SetToEnd();
10541 0 : if (!iter.AtStart()) {
10542 0 : FCItemIterator spaceEndIter(iter);
10543 0 : do {
10544 0 : iter.Prev();
10545 0 : if (iter.AtStart()) {
10546 : // It's fine to not check the first item, because we
10547 : // should have trimmed leading whitespaces above.
10548 0 : break;
10549 : }
10550 0 : } while (iter.item().IsWhitespace(aState));
10551 0 : iter.Next();
10552 0 : if (iter != spaceEndIter) {
10553 0 : iter.DeleteItemsTo(spaceEndIter);
10554 : }
10555 : }
10556 0 : }
10557 :
10558 : /**
10559 : * This function walks through the child list (aItems) and creates
10560 : * needed pseudo ruby boxes to wrap misparented children.
10561 : */
10562 : void
10563 413 : nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
10564 : nsFrameConstructorState& aState,
10565 : FrameConstructionItemList& aItems,
10566 : nsIFrame* aParentFrame)
10567 : {
10568 413 : const ParentType ourParentType = GetParentType(aParentFrame);
10569 413 : if (!IsRubyParentType(ourParentType) ||
10570 0 : aItems.AllWantParentType(ourParentType)) {
10571 413 : return;
10572 : }
10573 :
10574 0 : if (!IsRubyPseudo(aParentFrame)) {
10575 : // Normally, ruby pseudo frames start from and end at some elements,
10576 : // which means they don't have leading and trailing whitespaces at
10577 : // all. But there are two cases where they do actually have leading
10578 : // or trailing whitespaces:
10579 : // 1. It is an inter-segment whitespace which in an individual ruby
10580 : // base container.
10581 : // 2. The pseudo frame starts from or ends at consecutive inline
10582 : // content, which is not pure whitespace, but includes some.
10583 : // In either case, the whitespaces are not the leading or trailing
10584 : // whitespaces defined in the spec, and thus should not be trimmed.
10585 0 : TrimLeadingAndTrailingWhitespaces(aState, aItems);
10586 : }
10587 :
10588 0 : FCItemIterator iter(aItems);
10589 0 : nsIContent* parentContent = aParentFrame->GetContent();
10590 0 : nsStyleContext* parentStyle = aParentFrame->StyleContext();
10591 0 : while (!iter.IsDone()) {
10592 0 : if (!iter.SkipItemsWantingParentType(ourParentType)) {
10593 0 : if (ourParentType == eTypeRuby) {
10594 : WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
10595 0 : parentContent);
10596 : } else {
10597 0 : WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
10598 : }
10599 : }
10600 : }
10601 : }
10602 :
10603 : /*
10604 : * This function works as follows: we walk through the child list (aItems) and
10605 : * find items that cannot have aParentFrame as their parent. We wrap
10606 : * continuous runs of such items into a FrameConstructionItem for a frame that
10607 : * gets them closer to their desired parents. For example, a run of non-row
10608 : * children of a row-group will get wrapped in a row. When we later construct
10609 : * the frame for this wrapper (in this case for the row), it'll be the correct
10610 : * parent for the cells in the set of items we wrapped or we'll wrap cells
10611 : * around everything else. At the end of this method, aItems is guaranteed to
10612 : * contain only items for frames that can be direct kids of aParentFrame.
10613 : */
10614 : void
10615 413 : nsCSSFrameConstructor::CreateNeededPseudoContainers(
10616 : nsFrameConstructorState& aState,
10617 : FrameConstructionItemList& aItems,
10618 : nsIFrame* aParentFrame)
10619 : {
10620 413 : ParentType ourParentType = GetParentType(aParentFrame);
10621 826 : if (IsRubyParentType(ourParentType) ||
10622 413 : aItems.AllWantParentType(ourParentType)) {
10623 : // Nothing to do here
10624 826 : return;
10625 : }
10626 :
10627 0 : FCItemIterator iter(aItems);
10628 0 : do {
10629 0 : if (iter.SkipItemsWantingParentType(ourParentType)) {
10630 : // Nothing else to do here; we're finished
10631 0 : return;
10632 : }
10633 :
10634 : // Now we're pointing to the first child that wants a different parent
10635 : // type.
10636 :
10637 : // Now try to figure out what kids we can group together. We can generally
10638 : // group everything that has a different desired parent type from us. Two
10639 : // exceptions to this:
10640 : // 1) If our parent type is table, we can't group columns with anything
10641 : // else other than whitespace.
10642 : // 2) Whitespace that lies between two things we can group which both want
10643 : // a non-block parent should be dropped, even if we can't group them
10644 : // with each other and even if the whitespace wants a parent of
10645 : // ourParentType. Ends of the list count as things that don't want a
10646 : // block parent (so that for example we'll drop a whitespace-only list).
10647 :
10648 0 : FCItemIterator endIter(iter); /* iterator to find the end of the group */
10649 0 : ParentType groupingParentType = endIter.item().DesiredParentType();
10650 0 : if (aItems.AllWantParentType(groupingParentType) &&
10651 : groupingParentType != eTypeBlock) {
10652 : // Just group them all and be done with it. We need the check for
10653 : // eTypeBlock here to catch the "all the items are whitespace" case
10654 : // described above.
10655 0 : endIter.SetToEnd();
10656 : } else {
10657 : // Locate the end of the group.
10658 :
10659 : // Keep track of the type the previous item wanted, in case we have to
10660 : // deal with whitespace. Start it off with ourParentType, since that's
10661 : // the last thing |iter| would have skipped over.
10662 0 : ParentType prevParentType = ourParentType;
10663 0 : do {
10664 : // Walk an iterator past any whitespace that we might be able to drop
10665 : // from the list
10666 0 : FCItemIterator spaceEndIter(endIter);
10667 0 : if (prevParentType != eTypeBlock &&
10668 0 : !aParentFrame->IsGeneratedContentFrame() &&
10669 0 : spaceEndIter.item().IsWhitespace(aState)) {
10670 0 : bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
10671 :
10672 : // We drop the whitespace in the following cases:
10673 : // 1) If these are not trailing spaces and the next item wants a table
10674 : // or table-part parent
10675 : // 2) If these are trailing spaces and aParentFrame is a
10676 : // tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
10677 : // (Being a tabular container pretty much means ourParentType is
10678 : // not eTypeBlock besides the eTypeColGroup case, which won't
10679 : // reach here.)
10680 0 : if ((!trailingSpaces &&
10681 0 : IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
10682 0 : (trailingSpaces && ourParentType != eTypeBlock)) {
10683 0 : bool updateStart = (iter == endIter);
10684 0 : endIter.DeleteItemsTo(spaceEndIter);
10685 0 : NS_ASSERTION(trailingSpaces == endIter.IsDone(),
10686 : "These should match");
10687 :
10688 0 : if (updateStart) {
10689 0 : iter = endIter;
10690 : }
10691 :
10692 0 : if (trailingSpaces) {
10693 0 : break; /* Found group end */
10694 : }
10695 :
10696 0 : if (updateStart) {
10697 : // Update groupingParentType, since it might have been eTypeBlock
10698 : // just because of the whitespace.
10699 0 : groupingParentType = iter.item().DesiredParentType();
10700 : }
10701 : }
10702 : }
10703 :
10704 : // Now endIter points to a non-whitespace item or a non-droppable
10705 : // whitespace item. In the latter case, if this is the end of the group
10706 : // we'll traverse this whitespace again. But it'll all just be quick
10707 : // DesiredParentType() checks which will match ourParentType (that's
10708 : // what it means that this is the group end), so it's OK.
10709 : // However, when we are grouping a ruby parent, and endIter points to
10710 : // a non-droppable whitespace, if the next non-whitespace item also
10711 : // wants a ruby parent, the whitespace should also be included into
10712 : // the current ruby container.
10713 0 : prevParentType = endIter.item().DesiredParentType();
10714 0 : if (prevParentType == ourParentType &&
10715 0 : (endIter == spaceEndIter ||
10716 0 : spaceEndIter.IsDone() ||
10717 0 : !IsRubyParentType(groupingParentType) ||
10718 0 : !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
10719 : // End the group at endIter.
10720 0 : break;
10721 : }
10722 :
10723 0 : if (ourParentType == eTypeTable &&
10724 0 : (prevParentType == eTypeColGroup) !=
10725 : (groupingParentType == eTypeColGroup)) {
10726 : // Either we started with columns and now found something else, or vice
10727 : // versa. In any case, end the grouping.
10728 0 : break;
10729 : }
10730 :
10731 : // If we have some whitespace that we were not able to drop and there is
10732 : // an item after the whitespace that is already properly parented, then
10733 : // make sure to include the spaces in our group but stop the group after
10734 : // that.
10735 0 : if (spaceEndIter != endIter &&
10736 0 : !spaceEndIter.IsDone() &&
10737 0 : ourParentType == spaceEndIter.item().DesiredParentType()) {
10738 0 : endIter = spaceEndIter;
10739 0 : break;
10740 : }
10741 :
10742 : // Include the whitespace we didn't drop (if any) in the group.
10743 0 : endIter = spaceEndIter;
10744 0 : prevParentType = endIter.item().DesiredParentType();
10745 :
10746 0 : endIter.Next();
10747 0 : } while (!endIter.IsDone());
10748 : }
10749 :
10750 0 : if (iter == endIter) {
10751 : // Nothing to wrap here; just skipped some whitespace
10752 0 : continue;
10753 : }
10754 :
10755 : // Now group together all the items between iter and endIter. The right
10756 : // parent type to use depends on ourParentType.
10757 : ParentType wrapperType;
10758 0 : switch (ourParentType) {
10759 : case eTypeRow:
10760 : // The parent type for a cell is eTypeBlock, since that's what a cell
10761 : // looks like to its kids.
10762 0 : wrapperType = eTypeBlock;
10763 0 : break;
10764 : case eTypeRowGroup:
10765 0 : wrapperType = eTypeRow;
10766 0 : break;
10767 : case eTypeTable:
10768 : // Either colgroup or rowgroup, depending on what we're grouping.
10769 0 : wrapperType = groupingParentType == eTypeColGroup ?
10770 : eTypeColGroup : eTypeRowGroup;
10771 0 : break;
10772 : case eTypeColGroup:
10773 0 : MOZ_CRASH("Colgroups should be suppresing non-col child items");
10774 : default:
10775 0 : NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type");
10776 0 : if (IsRubyParentType(groupingParentType)) {
10777 0 : wrapperType = eTypeRuby;
10778 : } else {
10779 0 : NS_ASSERTION(IsTableParentType(groupingParentType),
10780 : "groupingParentType should be either Ruby or table");
10781 0 : wrapperType = eTypeTable;
10782 : }
10783 : }
10784 :
10785 0 : nsStyleContext* parentStyle = aParentFrame->StyleContext();
10786 0 : WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
10787 0 : wrapperType, iter, endIter);
10788 :
10789 : // Now |iter| points to the item that was the first one we didn't wrap;
10790 : // loop and see whether we need to skip it or wrap it in something
10791 : // different.
10792 0 : } while (!iter.IsDone());
10793 : }
10794 :
10795 : /**
10796 : * This method wraps frame construction item from |aIter| to
10797 : * |aEndIter|. After it returns, aIter points to the first item
10798 : * after the wrapper.
10799 : */
10800 : void
10801 0 : nsCSSFrameConstructor::WrapItemsInPseudoParent(nsIContent* aParentContent,
10802 : nsStyleContext* aParentStyle,
10803 : ParentType aWrapperType,
10804 : FCItemIterator& aIter,
10805 : const FCItemIterator& aEndIter)
10806 : {
10807 0 : const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
10808 0 : nsIAtom* pseudoType = *pseudoData.mPseudoType;
10809 0 : StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
10810 :
10811 0 : if (pseudoType == nsCSSAnonBoxes::table &&
10812 0 : (parentDisplay == StyleDisplay::Inline ||
10813 0 : parentDisplay == StyleDisplay::RubyBase ||
10814 : parentDisplay == StyleDisplay::RubyText)) {
10815 0 : pseudoType = nsCSSAnonBoxes::inlineTable;
10816 : }
10817 :
10818 : already_AddRefed<nsStyleContext> wrapperStyle =
10819 0 : mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
10820 0 : aParentStyle);
10821 : FrameConstructionItem* newItem =
10822 : new FrameConstructionItem(&pseudoData.mFCData,
10823 : // Use the content of our parent frame
10824 : aParentContent,
10825 : // Lie about the tag; it doesn't matter anyway
10826 : pseudoType,
10827 : // The namespace does matter, however; it needs
10828 : // to match that of our first child item to
10829 : // match the old behavior
10830 0 : aIter.item().mNameSpaceID,
10831 : // no pending binding
10832 : nullptr,
10833 : wrapperStyle,
10834 0 : true, nullptr);
10835 :
10836 0 : const nsStyleDisplay* disp = newItem->mStyleContext->StyleDisplay();
10837 : // Here we're cheating a tad... technically, table-internal items should be
10838 : // inline if aParentFrame is inline, but they'll get wrapped in an
10839 : // inline-table in the end, so it'll all work out. In any case, arguably
10840 : // we don't need to maintain this state at this point... but it's better
10841 : // to, I guess.
10842 0 : newItem->mIsAllInline = newItem->mHasInlineEnds =
10843 0 : disp->IsInlineOutsideStyle();
10844 :
10845 0 : bool isRuby = disp->IsRubyDisplayType();
10846 : // All types of ruby frames need a block frame to provide line layout,
10847 : // hence they are always line participant.
10848 0 : newItem->mIsLineParticipant = isRuby;
10849 :
10850 0 : if (!isRuby) {
10851 : // Table pseudo frames always induce line boundaries around their
10852 : // contents.
10853 0 : newItem->mChildItems.SetLineBoundaryAtStart(true);
10854 0 : newItem->mChildItems.SetLineBoundaryAtEnd(true);
10855 : }
10856 : // The parent of the items in aItems is also the parent of the items
10857 : // in mChildItems
10858 0 : newItem->mChildItems.SetParentHasNoXBLChildren(
10859 0 : aIter.List()->ParentHasNoXBLChildren());
10860 :
10861 : // Eat up all items between |aIter| and |aEndIter| and put them in our
10862 : // wrapper Advances |aIter| to point to |aEndIter|.
10863 0 : aIter.AppendItemsToList(aEndIter, newItem->mChildItems);
10864 :
10865 0 : aIter.InsertItem(newItem);
10866 0 : }
10867 :
10868 : void
10869 413 : nsCSSFrameConstructor::CreateNeededPseudoSiblings(
10870 : nsFrameConstructorState& aState,
10871 : FrameConstructionItemList& aItems,
10872 : nsIFrame* aParentFrame)
10873 : {
10874 700 : if (aItems.IsEmpty() ||
10875 287 : GetParentType(aParentFrame) != eTypeRuby) {
10876 826 : return;
10877 : }
10878 :
10879 0 : FCItemIterator iter(aItems);
10880 0 : StyleDisplay firstDisplay = iter.item().mStyleContext->StyleDisplay()->mDisplay;
10881 0 : if (firstDisplay == StyleDisplay::RubyBaseContainer) {
10882 0 : return;
10883 : }
10884 0 : NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,
10885 : "Child of ruby frame should either a rbc or a rtc");
10886 :
10887 : const PseudoParentData& pseudoData =
10888 0 : sPseudoParentData[eTypeRubyBaseContainer];
10889 0 : already_AddRefed<nsStyleContext> pseudoStyle = mPresShell->StyleSet()->
10890 0 : ResolveInheritingAnonymousBoxStyle(*pseudoData.mPseudoType,
10891 0 : aParentFrame->StyleContext());
10892 : FrameConstructionItem* newItem =
10893 : new FrameConstructionItem(&pseudoData.mFCData,
10894 : // Use the content of the parent frame
10895 0 : aParentFrame->GetContent(),
10896 : // Tag type
10897 0 : *pseudoData.mPseudoType,
10898 : // Use the namespace of the rtc frame
10899 0 : iter.item().mNameSpaceID,
10900 : // no pending binding
10901 : nullptr,
10902 : pseudoStyle,
10903 0 : true, nullptr);
10904 0 : newItem->mIsAllInline = true;
10905 0 : newItem->mChildItems.SetParentHasNoXBLChildren(true);
10906 0 : iter.InsertItem(newItem);
10907 : }
10908 :
10909 : #ifdef DEBUG
10910 : /**
10911 : * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
10912 : * rather than being a direct child of aContainerFrame.
10913 : *
10914 : * NOTE: aContainerFrame must be a flex or grid container - this function is
10915 : * purely for sanity-checking the children of these container types.
10916 : * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
10917 : * logic (which operates a bit earlier, on FCData instead of frames).
10918 : */
10919 : static bool
10920 0 : FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
10921 : const nsIFrame* aFrame)
10922 : {
10923 0 : LayoutFrameType containerType = aContainerFrame->Type();
10924 0 : MOZ_ASSERT(containerType == LayoutFrameType::FlexContainer ||
10925 : containerType == LayoutFrameType::GridContainer);
10926 :
10927 : // Any line-participant frames (e.g. text) definitely want to be wrapped in
10928 : // an anonymous flex/grid item.
10929 0 : if (aFrame->IsFrameOfType(nsIFrame::eLineParticipant)) {
10930 0 : return true;
10931 : }
10932 :
10933 : // If the container is a -webkit-box/-webkit-inline-box, then placeholders
10934 : // also need to be wrapped, for compatibility.
10935 0 : if (containerType == LayoutFrameType::FlexContainer &&
10936 0 : aContainerFrame->HasAnyStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX) &&
10937 0 : aFrame->IsPlaceholderFrame()) {
10938 0 : return true;
10939 : }
10940 :
10941 0 : return false;
10942 : }
10943 : #endif
10944 :
10945 : static void
10946 413 : VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
10947 : const nsFrameList& aChildren)
10948 : {
10949 : #ifdef DEBUG
10950 413 : auto parentType = aParentFrame->Type();
10951 413 : if (parentType != LayoutFrameType::FlexContainer &&
10952 : parentType != LayoutFrameType::GridContainer) {
10953 413 : return;
10954 : }
10955 :
10956 0 : bool prevChildWasAnonItem = false;
10957 0 : for (const nsIFrame* child : aChildren) {
10958 0 : MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(aParentFrame, child),
10959 : "frame wants to be inside an anonymous item, but it isn't");
10960 0 : if (IsAnonymousFlexOrGridItem(child)) {
10961 0 : AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
10962 0 : MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row");
10963 0 : nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
10964 0 : MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty");
10965 0 : prevChildWasAnonItem = true;
10966 : } else {
10967 0 : prevChildWasAnonItem = false;
10968 : }
10969 : }
10970 : #endif
10971 : }
10972 :
10973 : inline void
10974 413 : nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState,
10975 : FrameConstructionItemList& aItems,
10976 : nsContainerFrame* aParentFrame,
10977 : nsFrameItems& aFrameItems)
10978 : {
10979 413 : CreateNeededPseudoContainers(aState, aItems, aParentFrame);
10980 413 : CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
10981 413 : CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
10982 413 : CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
10983 :
10984 413 : aItems.SetTriedConstructingFrames();
10985 905 : for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
10986 492 : NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
10987 : "Needed pseudos didn't get created; expect bad things");
10988 492 : ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
10989 : }
10990 :
10991 413 : VerifyGridFlexContainerChildren(aParentFrame, aFrameItems);
10992 413 : NS_ASSERTION(!aState.mHavePendingPopupgroup,
10993 : "Should have proccessed it by now");
10994 413 : }
10995 :
10996 : void
10997 353 : nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
10998 : nsFrameConstructorState& aState,
10999 : nsContainerFrame* aFrame,
11000 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
11001 : FrameConstructionItemList& aItemsToConstruct,
11002 : uint32_t aExtraFlags)
11003 : {
11004 415 : for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) {
11005 62 : nsIContent* content = aAnonymousItems[i].mContent;
11006 : // Gecko-styled nodes should have no pending restyle flags.
11007 62 : MOZ_ASSERT(content->IsStyledByServo() ||
11008 : !content->IsElement() ||
11009 : !(content->GetFlags() & ELEMENT_ALL_RESTYLE_FLAGS));
11010 : // Assert some things about this content
11011 62 : MOZ_ASSERT(!(content->GetFlags() &
11012 : (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
11013 : "Should not be marked as needing frames");
11014 62 : MOZ_ASSERT(!content->GetPrimaryFrame(),
11015 : "Should have no existing frame");
11016 62 : MOZ_ASSERT(!content->IsNodeOfType(nsINode::eCOMMENT) &&
11017 : !content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION),
11018 : "Why is someone creating garbage anonymous content");
11019 :
11020 124 : RefPtr<nsStyleContext> styleContext;
11021 : Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
11022 124 : parentDisplayBasedStyleFixupSkipper;
11023 62 : MOZ_ASSERT(aState.mTreeMatchContext || content->IsStyledByServo());
11024 62 : if (aState.mTreeMatchContext) {
11025 62 : parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
11026 : }
11027 :
11028 : // Make sure we eagerly performed the servo cascade when the anonymous
11029 : // nodes were created.
11030 62 : MOZ_ASSERT(!content->IsStyledByServo() || !content->IsElement() ||
11031 : content->AsElement()->HasServoData());
11032 :
11033 : // Determine whether this NAC is pseudo-implementing.
11034 62 : nsIAtom* pseudo = nullptr;
11035 62 : if (content->IsElement()) {
11036 62 : auto pseudoType = content->AsElement()->GetPseudoElementType();
11037 62 : if (pseudoType != CSSPseudoElementType::NotPseudo) {
11038 4 : pseudo = nsCSSPseudoElements::GetPseudoAtom(pseudoType);
11039 : }
11040 : }
11041 :
11042 : // Determine the appropriate parent style for this NAC, and if the NAC
11043 : // implements a pseudo-element, the appropriate originating element
11044 : // (that is to say, the element to the left of the ::pseudo-element in
11045 : // the selector). This is all rather tricky, and merits some discussion.
11046 : //
11047 : // First, it's important to note that author stylesheets generally do not
11048 : // apply to elements in native-anonymous subtrees. The exceptions to
11049 : // this are web-exposed pseudo-elements, where authors can style the
11050 : // pseudo-implementing NAC if the originating element is not itself in a NAC
11051 : // subtree.
11052 : //
11053 : // For this reason, it's very important that we avoid using a style parent
11054 : // that is inside a NAC subtree together with an originating element that
11055 : // is not inside a NAC subtree, since that would allow authors to
11056 : // explicitly inherit styles from internal elements, potentially making
11057 : // the NAC hierarchy observable. To ensure this, and generally simplify
11058 : // things, we always set the originating element to the style parent.
11059 : //
11060 : // As a consequence of the above, all web-exposed pseudo-elements (which,
11061 : // by definition, must have a content-accessible originating element) must
11062 : // also inherit style from that same content-accessible element. To avoid
11063 : // unintuitive behavior differences between NAC elements that do and don't
11064 : // correspond to web-exposed pseudo-elements, we follow this protocol for
11065 : // all NAC, pseudo-implementing or not.
11066 : //
11067 : // However, things get tricky with the <video> element, where we have a
11068 : // bunch of XBL-generated anonymous content descending from a native-
11069 : // anonymous XULElement. The XBL elements inherit style from their
11070 : // flattened tree parent, because that's how XBL works. But then we need
11071 : // to figure out what to do when one of those anonymous XBL elements
11072 : // (like an <input> element) generates its own (possibly pseudo-element-
11073 : // implementing) NAC.
11074 : //
11075 : // In this case, we inherit style from the XBL-generated NAC-creating
11076 : // element, rather than the <video> element. There are a number of good
11077 : // reasons for this. First, inheriting from the great-grandparent while
11078 : // the parent inherits from the grandparent would be bizarre at best.
11079 : // Second, exposing pseudo-elements from elements within our particular
11080 : // XBL implementation would allow content styles to (un)intentionally
11081 : // alter the video controls, which would be very bad. Third, our UA
11082 : // stylesheets have selectors like:
11083 : //
11084 : // input[type=range][orient=horizontal]::-moz-range-track
11085 : //
11086 : // and we need to make sure that the originating element is the <input>,
11087 : // not the <video>, because that's where the |orient| attribute lives.
11088 : //
11089 : // The upshot of all of this is that, to find the style parent (and
11090 : // originating element, if applicable), we walk up our parent chain to the
11091 : // first element that is not itself NAC (distinct from whether it happens
11092 : // to be in a NAC subtree).
11093 : //
11094 : // The one exception to all of this is scrollbar content, which we parent
11095 : // directly to the scrollframe. This is because the special-snowflake
11096 : // construction of scroll frames doesn't result in the placeholder frame
11097 : // being constructed until later, which means that GetInFlowParent() doesn't
11098 : // work right in the case of out-of-flow scrollframes.
11099 : //
11100 : // To implement all this, we need to pass the correct parent style context
11101 : // here because SetPrimaryFrame() may not have been called on the content
11102 : // yet and thus ResolveStyleContext can't find it otherwise.
11103 : //
11104 : // We don't need to worry about display:contents here, because such
11105 : // elements don't get a frame and thus can't generate NAC. But we do need
11106 : // to worry about anonymous boxes, which CorrectStyleParentFrame handles
11107 : // for us.
11108 62 : nsIFrame* inheritFrame = aFrame;
11109 62 : if (!content->IsNativeScrollbarContent()) {
11110 56 : while (inheritFrame->GetContent()->IsNativeAnonymous()) {
11111 0 : inheritFrame = inheritFrame->GetInFlowParent();
11112 : }
11113 : }
11114 :
11115 : nsIFrame* styleParentFrame =
11116 62 : nsFrame::CorrectStyleParentFrame(inheritFrame, pseudo);
11117 : // The only way we can not have a style parent now is if inheritFrame is the
11118 : // canvas frame and we're the NAC parent for all the things added via
11119 : // nsIDocument::InsertAnonymousContent.
11120 62 : MOZ_ASSERT(styleParentFrame || inheritFrame->IsCanvasFrame());
11121 : // And that anonymous div has no pseudo.
11122 62 : MOZ_ASSERT(styleParentFrame || !pseudo);
11123 :
11124 : Element* originating =
11125 62 : pseudo ? styleParentFrame->GetContent()->AsElement() : nullptr;
11126 : nsStyleContext* parentStyle =
11127 62 : styleParentFrame ? styleParentFrame->StyleContext() : nullptr;
11128 : styleContext =
11129 62 : ResolveStyleContext(parentStyle, content, &aState, originating);
11130 :
11131 62 : nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
11132 62 : if (!aAnonymousItems[i].mChildren.IsEmpty()) {
11133 0 : anonChildren = &aAnonymousItems[i].mChildren;
11134 : }
11135 :
11136 : uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK |
11137 62 : ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags;
11138 :
11139 62 : AddFrameConstructionItemsInternal(aState, content, aFrame,
11140 : content->NodeInfo()->NameAtom(),
11141 : content->GetNameSpaceID(),
11142 : true, styleContext, flags,
11143 62 : anonChildren, aItemsToConstruct);
11144 : }
11145 353 : }
11146 :
11147 : void
11148 328 : nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
11149 : nsIContent* aContent,
11150 : nsStyleContext* aStyleContext,
11151 : nsContainerFrame* aFrame,
11152 : const bool aCanHaveGeneratedContent,
11153 : nsFrameItems& aFrameItems,
11154 : const bool aAllowBlockStyles,
11155 : PendingBinding* aPendingBinding,
11156 : nsIFrame* aPossiblyLeafFrame)
11157 : {
11158 328 : NS_PRECONDITION(aFrame, "Must have parent frame here");
11159 328 : NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
11160 : "Parent frame in ProcessChildren should be its own "
11161 : "content insertion frame");
11162 328 : const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
11163 : static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
11164 656 : AutoRestore<uint16_t> savedDepth(mCurrentDepth);
11165 328 : if (mCurrentDepth != UINT16_MAX) {
11166 328 : ++mCurrentDepth;
11167 : }
11168 :
11169 328 : if (!aPossiblyLeafFrame) {
11170 45 : aPossiblyLeafFrame = aFrame;
11171 : }
11172 :
11173 : // XXXbz ideally, this would do all the pushing of various
11174 : // containing blocks as needed, so callers don't have to do it...
11175 :
11176 328 : bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
11177 328 : if (aAllowBlockStyles) {
11178 : ShouldHaveSpecialBlockStyle(aContent, aStyleContext, &haveFirstLetterStyle,
11179 22 : &haveFirstLineStyle);
11180 : }
11181 :
11182 328 : const bool isFlexOrGridContainer = ::IsFlexOrGridContainer(aFrame);
11183 : // The logic here needs to match the logic in GetFloatContainingBlock()
11184 : // (Since we already have isFlexOrGridContainer, we check that eagerly instead
11185 : // of letting ShouldSuppressFloatingOfDescendants look it up redundantly.)
11186 656 : nsFrameConstructorSaveState floatSaveState;
11187 656 : if (isFlexOrGridContainer ||
11188 328 : ShouldSuppressFloatingOfDescendants(aFrame)) {
11189 223 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
11190 105 : } else if (aFrame->IsFloatContainingBlock()) {
11191 29 : aState.PushFloatContainingBlock(aFrame, floatSaveState);
11192 : }
11193 :
11194 : nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
11195 656 : aPendingBinding);
11196 :
11197 656 : FrameConstructionItemList itemsToConstruct;
11198 :
11199 : // If we have first-letter or first-line style then frames can get
11200 : // moved around so don't set these flags.
11201 328 : if (aAllowBlockStyles && !haveFirstLetterStyle && !haveFirstLineStyle) {
11202 22 : itemsToConstruct.SetLineBoundaryAtStart(true);
11203 22 : itemsToConstruct.SetLineBoundaryAtEnd(true);
11204 : }
11205 :
11206 : // Create any anonymous frames we need here. This must happen before the
11207 : // non-anonymous children are processed to ensure that popups are never
11208 : // constructed before the popupset.
11209 656 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
11210 328 : GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
11211 : #ifdef DEBUG
11212 361 : for (uint32_t i = 0; i < anonymousItems.Length(); ++i) {
11213 33 : MOZ_ASSERT(anonymousItems[i].mContent->IsRootOfAnonymousSubtree(),
11214 : "Content should know it's an anonymous subtree");
11215 : }
11216 : #endif
11217 : AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
11218 328 : itemsToConstruct);
11219 :
11220 328 : if (!aPossiblyLeafFrame->IsLeaf()) {
11221 : // :before/:after content should have the same style context parent
11222 : // as normal kids.
11223 : // Note that we don't use this style context for looking up things like
11224 : // special block styles because in some cases involving table pseudo-frames
11225 : // it has nothing to do with the parent frame's desired behavior.
11226 : nsStyleContext* styleContext;
11227 :
11228 254 : if (aCanHaveGeneratedContent) {
11229 230 : aFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
11230 : styleContext =
11231 230 : nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->StyleContext();
11232 : // Probe for generated content before
11233 : CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
11234 : CSSPseudoElementType::before,
11235 230 : itemsToConstruct);
11236 : }
11237 :
11238 254 : const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
11239 254 : if (!addChildItems) {
11240 0 : NS_WARNING("ProcessChildren max depth exceeded");
11241 : }
11242 :
11243 : // Don't blockify 'display' in ApplyStyleFixups unless aFrame really is
11244 : // a flex/grid container frame, not just has display:flex/grid.
11245 : Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
11246 508 : parentDisplayBasedStyleFixupSkipper;
11247 254 : MOZ_ASSERT(aState.mTreeMatchContext || aContent->IsStyledByServo());
11248 254 : if (!isFlexOrGridContainer && aState.mTreeMatchContext) {
11249 254 : parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
11250 : }
11251 :
11252 254 : InsertionPoint insertion(aFrame, nullptr);
11253 508 : FlattenedChildIterator iter(aContent);
11254 994 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
11255 : // Get the parent of the content and check if it is a XBL children element
11256 : // (if the content is a children element then parent != aContent because the
11257 : // FlattenedChildIterator will transitively iterate through <xbl:children>
11258 : // for default content). Push the children element as an ancestor here because
11259 : // it does not have a frame and would not otherwise be pushed as an ancestor.
11260 740 : insertion.mContainer = aContent;
11261 740 : nsIContent* parent = child->GetParent();
11262 740 : MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
11263 1480 : TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
11264 740 : if (parent != aContent && parent->IsElement()) {
11265 20 : insertion.mContainer = child->GetFlattenedTreeParent();
11266 20 : MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(parent, child).mContainer);
11267 20 : if (aState.HasAncestorFilter()) {
11268 20 : ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
11269 : } else {
11270 0 : ancestorPusher.PushStyleScope(parent->AsElement());
11271 : }
11272 : }
11273 :
11274 : // Frame construction item construction should not post
11275 : // restyles, so removing restyle flags here is safe.
11276 740 : child->UnsetRestyleFlagsIfGecko();
11277 740 : if (addChildItems) {
11278 740 : AddFrameConstructionItems(aState, child, iter.XBLInvolved(), insertion,
11279 740 : itemsToConstruct);
11280 : } else {
11281 0 : ClearLazyBits(child, child->GetNextSibling());
11282 : }
11283 : }
11284 254 : itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
11285 :
11286 254 : if (aCanHaveGeneratedContent) {
11287 : // Probe for generated content after
11288 : CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
11289 : CSSPseudoElementType::after,
11290 230 : itemsToConstruct);
11291 : }
11292 : } else {
11293 74 : ClearLazyBits(aContent->GetFirstChild(), nullptr);
11294 : }
11295 :
11296 328 : ConstructFramesFromItemList(aState, itemsToConstruct, aFrame, aFrameItems);
11297 :
11298 328 : NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsXULBoxFrame(),
11299 : "can't be both block and box");
11300 :
11301 328 : if (haveFirstLetterStyle) {
11302 0 : WrapFramesInFirstLetterFrame(aFrame, aFrameItems);
11303 : }
11304 328 : if (haveFirstLineStyle) {
11305 : WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr,
11306 0 : aFrameItems);
11307 : }
11308 :
11309 : // We might end up with first-line frames that change
11310 : // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
11311 : // should never happen for cases whan aFrame->IsXULBoxFrame().
11312 328 : NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsXULBoxFrame(),
11313 : "Shouldn't have first-line style if we're a box");
11314 328 : NS_ASSERTION(!aFrame->IsXULBoxFrame() ||
11315 : itemsToConstruct.AnyItemsNeedBlockParent() ==
11316 : (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr),
11317 : "Something went awry in our block parent calculations");
11318 :
11319 328 : if (aFrame->IsXULBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
11320 : // XXXbz we could do this on the FrameConstructionItemList level,
11321 : // no? And if we cared we could look through the item list
11322 : // instead of groveling through the framelist here..
11323 5 : nsStyleContext *frameStyleContext = aFrame->StyleContext();
11324 : // Report a warning for non-GC frames, for chrome:
11325 5 : if (!aFrame->IsGeneratedContentFrame() &&
11326 0 : mPresShell->GetPresContext()->IsChrome()) {
11327 0 : nsIContent *badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild());
11328 0 : nsDependentAtomString parentTag(aContent->NodeInfo()->NameAtom()),
11329 0 : kidTag(badKid->NodeInfo()->NameAtom());
11330 0 : const char16_t* params[] = { parentTag.get(), kidTag.get() };
11331 0 : const nsStyleDisplay *display = frameStyleContext->StyleDisplay();
11332 : const char *message =
11333 0 : (display->mDisplay == StyleDisplay::MozInlineBox)
11334 0 : ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
11335 0 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
11336 0 : NS_LITERAL_CSTRING("Layout: FrameConstructor"),
11337 0 : mDocument,
11338 : nsContentUtils::eXUL_PROPERTIES,
11339 : message,
11340 0 : params, ArrayLength(params));
11341 : }
11342 :
11343 10 : RefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()->
11344 15 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock,
11345 10 : frameStyleContext);
11346 5 : nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
11347 : // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
11348 : // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
11349 : // a real block placed here wouldn't get those set on it.
11350 :
11351 5 : InitAndRestoreFrame(aState, aContent, aFrame, blockFrame, false);
11352 :
11353 5 : NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
11354 5 : ReparentFrames(this, blockFrame, aFrameItems);
11355 :
11356 5 : blockFrame->SetInitialChildList(kPrincipalList, aFrameItems);
11357 5 : NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?");
11358 5 : aFrameItems.Clear();
11359 5 : aFrameItems.AddChild(blockFrame);
11360 :
11361 5 : aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
11362 : }
11363 328 : }
11364 :
11365 : //----------------------------------------------------------------------
11366 :
11367 : // Support for :first-line style
11368 :
11369 : // Special routine to handle placing a list of frames into a block
11370 : // frame that has first-line style. The routine ensures that the first
11371 : // collection of inline frames end up in a first-line frame.
11372 : // NOTE: aState may have containing block information related to a
11373 : // different part of the frame tree than where the first line occurs.
11374 : // In particular aState may be set up for where ContentInserted or
11375 : // ContentAppended is inserting content, which may be some
11376 : // non-first-in-flow continuation of the block to which the first-line
11377 : // belongs. So this function needs to be careful about how it uses
11378 : // aState.
11379 : void
11380 0 : nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
11381 : nsFrameConstructorState& aState,
11382 : nsIContent* aBlockContent,
11383 : nsContainerFrame* aBlockFrame,
11384 : nsFirstLineFrame* aLineFrame,
11385 : nsFrameItems& aFrameItems)
11386 : {
11387 : // Find the part of aFrameItems that we want to put in the first-line
11388 0 : nsFrameList::FrameLinkEnumerator link(aFrameItems);
11389 0 : while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) {
11390 0 : link.Next();
11391 : }
11392 :
11393 0 : nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
11394 :
11395 0 : if (firstLineChildren.IsEmpty()) {
11396 : // Nothing is supposed to go into the first-line; nothing to do
11397 0 : return;
11398 : }
11399 :
11400 0 : if (!aLineFrame) {
11401 : // Create line frame
11402 : nsStyleContext* parentStyle =
11403 : nsFrame::CorrectStyleParentFrame(aBlockFrame,
11404 : nsCSSPseudoElements::firstLine)->
11405 0 : StyleContext();
11406 0 : RefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent,
11407 0 : parentStyle);
11408 :
11409 0 : aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
11410 :
11411 : // Initialize the line frame
11412 0 : InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
11413 :
11414 : // The lineFrame will be the block's first child; the rest of the
11415 : // frame list (after lastInlineFrame) will be the second and
11416 : // subsequent children; insert lineFrame into aFrameItems.
11417 0 : aFrameItems.InsertFrame(nullptr, nullptr, aLineFrame);
11418 :
11419 0 : NS_ASSERTION(aLineFrame->StyleContext() == firstLineStyle,
11420 : "Bogus style context on line frame");
11421 : }
11422 :
11423 : // Give the inline frames to the lineFrame <b>after</b> reparenting them
11424 0 : ReparentFrames(this, aLineFrame, firstLineChildren);
11425 0 : if (aLineFrame->PrincipalChildList().IsEmpty() &&
11426 0 : (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
11427 0 : aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren);
11428 : } else {
11429 0 : AppendFrames(aLineFrame, kPrincipalList, firstLineChildren);
11430 : }
11431 : }
11432 :
11433 : // Special routine to handle appending a new frame to a block frame's
11434 : // child list. Takes care of placing the new frame into the right
11435 : // place when first-line style is present.
11436 : void
11437 0 : nsCSSFrameConstructor::AppendFirstLineFrames(
11438 : nsFrameConstructorState& aState,
11439 : nsIContent* aBlockContent,
11440 : nsContainerFrame* aBlockFrame,
11441 : nsFrameItems& aFrameItems)
11442 : {
11443 : // It's possible that aBlockFrame needs to have a first-line frame
11444 : // created because it doesn't currently have any children.
11445 0 : const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
11446 0 : if (blockKids.IsEmpty()) {
11447 : WrapFramesInFirstLineFrame(aState, aBlockContent,
11448 0 : aBlockFrame, nullptr, aFrameItems);
11449 0 : return;
11450 : }
11451 :
11452 : // Examine the last block child - if it's a first-line frame then
11453 : // appended frames need special treatment.
11454 0 : nsIFrame* lastBlockKid = blockKids.LastChild();
11455 0 : if (!lastBlockKid->IsLineFrame()) {
11456 : // No first-line frame at the end of the list, therefore there is
11457 : // an intervening block between any first-line frame the frames
11458 : // we are appending. Therefore, we don't need any special
11459 : // treatment of the appended frames.
11460 0 : return;
11461 : }
11462 :
11463 0 : nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
11464 : WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame,
11465 0 : lineFrame, aFrameItems);
11466 : }
11467 :
11468 : // Special routine to handle inserting a new frame into a block
11469 : // frame's child list. Takes care of placing the new frame into the
11470 : // right place when first-line style is present.
11471 : void
11472 0 : nsCSSFrameConstructor::InsertFirstLineFrames(
11473 : nsFrameConstructorState& aState,
11474 : nsIContent* aContent,
11475 : nsIFrame* aBlockFrame,
11476 : nsContainerFrame** aParentFrame,
11477 : nsIFrame* aPrevSibling,
11478 : nsFrameItems& aFrameItems)
11479 : {
11480 : // XXXbz If you make this method actually do something, check to
11481 : // make sure that the caller is passing what you expect. In
11482 : // particular, which content is aContent? And audit the rest of
11483 : // this code too; it makes bogus assumptions and may not build.
11484 : #if 0
11485 : nsIFrame* parentFrame = *aParentFrame;
11486 : nsIFrame* newFrame = aFrameItems.childList;
11487 : bool isInline = IsInlineOutside(newFrame);
11488 :
11489 : if (!aPrevSibling) {
11490 : // Insertion will become the first frame. Two cases: we either
11491 : // already have a first-line frame or we don't.
11492 : nsIFrame* firstBlockKid = aBlockFrame->PrincipalChildList().FirstChild();
11493 : if (firstBlockKid->IsLineFrame()) {
11494 : // We already have a first-line frame
11495 : nsIFrame* lineFrame = firstBlockKid;
11496 :
11497 : if (isInline) {
11498 : // Easy case: the new inline frame will go into the lineFrame.
11499 : ReparentFrame(this, lineFrame, newFrame);
11500 : InsertFrames(lineFrame, kPrincipalList, nullptr, newFrame);
11501 :
11502 : // Since the frame is going into the lineFrame, don't let it
11503 : // go into the block too.
11504 : aFrameItems.childList = nullptr;
11505 : aFrameItems.lastChild = nullptr;
11506 : }
11507 : else {
11508 : // Harder case: We are about to insert a block level element
11509 : // before the first-line frame.
11510 : // XXX need a method to steal away frames from the line-frame
11511 : }
11512 : }
11513 : else {
11514 : // We do not have a first-line frame
11515 : if (isInline) {
11516 : // We now need a first-line frame to contain the inline frame.
11517 : nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle);
11518 :
11519 : if (NS_SUCCEEDED(rv)) {
11520 : // Lookup first-line style context
11521 : nsStyleContext* parentStyle =
11522 : nsFrame::CorrectStyleParentFrame(aBlockFrame,
11523 : nsCSSPseudoElements::firstLine)->
11524 : StyleContext();
11525 : RefPtr<nsStyleContext> firstLineStyle =
11526 : GetFirstLineStyle(aContent, parentStyle);
11527 :
11528 : // Initialize the line frame
11529 : InitAndRestoreFrame(aState, aContent, aBlockFrame, lineFrame);
11530 :
11531 : // Make sure the caller inserts the lineFrame into the
11532 : // blocks list of children.
11533 : aFrameItems.childList = lineFrame;
11534 : aFrameItems.lastChild = lineFrame;
11535 :
11536 : // Give the inline frames to the lineFrame <b>after</b>
11537 : // reparenting them
11538 : NS_ASSERTION(lineFrame->StyleContext() == firstLineStyle,
11539 : "Bogus style context on line frame");
11540 : ReparentFrame(aPresContext, lineFrame, newFrame);
11541 : lineFrame->SetInitialChildList(kPrincipalList, newFrame);
11542 : }
11543 : }
11544 : else {
11545 : // Easy case: the regular insertion logic can insert the new
11546 : // frame because it's a block frame.
11547 : }
11548 : }
11549 : }
11550 : else {
11551 : // Insertion will not be the first frame.
11552 : nsIFrame* prevSiblingParent = aPrevSibling->GetParent();
11553 : if (prevSiblingParent == aBlockFrame) {
11554 : // Easy case: The prev-siblings parent is the block
11555 : // frame. Therefore the prev-sibling is not currently in a
11556 : // line-frame. Therefore the new frame which is going after it,
11557 : // regardless of type, is not going into a line-frame.
11558 : }
11559 : else {
11560 : // If the prevSiblingParent is not the block-frame then it must
11561 : // be a line-frame (if it were a letter-frame, that logic would
11562 : // already have adjusted the prev-sibling to be the
11563 : // letter-frame).
11564 : if (isInline) {
11565 : // Easy case: the insertion can go where the caller thinks it
11566 : // should go (which is into prevSiblingParent).
11567 : }
11568 : else {
11569 : // Block elements don't end up in line-frames, therefore
11570 : // change the insertion point to aBlockFrame. However, there
11571 : // might be more inline elements following aPrevSibling that
11572 : // need to be pulled out of the line-frame and become children
11573 : // of the block.
11574 : nsIFrame* nextSibling = aPrevSibling->GetNextSibling();
11575 : nsIFrame* nextLineFrame = prevSiblingParent->GetNextInFlow();
11576 : if (nextSibling || nextLineFrame) {
11577 : // Oy. We have work to do. Create a list of the new frames
11578 : // that are going into the block by stripping them away from
11579 : // the line-frame(s).
11580 : if (nextSibling) {
11581 : nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent;
11582 : nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling);
11583 : // XXX do something with 'tail'
11584 : }
11585 :
11586 : nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame;
11587 : for (;;) {
11588 : nextLineFrame = nextLineFrame->GetNextInFlow();
11589 : if (!nextLineFrame) {
11590 : break;
11591 : }
11592 : nsIFrame* kids = nextLineFrame->PrincipalChildList().FirstChild();
11593 : }
11594 : }
11595 : else {
11596 : // We got lucky: aPrevSibling was the last inline frame in
11597 : // the line-frame.
11598 : ReparentFrame(this, aBlockFrame, newFrame);
11599 : InsertFrames(aBlockFrame, kPrincipalList,
11600 : prevSiblingParent, newFrame);
11601 : aFrameItems.childList = nullptr;
11602 : aFrameItems.lastChild = nullptr;
11603 : }
11604 : }
11605 : }
11606 : }
11607 :
11608 : #endif
11609 0 : }
11610 :
11611 : //----------------------------------------------------------------------
11612 :
11613 : // First-letter support
11614 :
11615 : // Determine how many characters in the text fragment apply to the
11616 : // first letter
11617 : static int32_t
11618 0 : FirstLetterCount(const nsTextFragment* aFragment)
11619 : {
11620 0 : int32_t count = 0;
11621 0 : int32_t firstLetterLength = 0;
11622 :
11623 0 : int32_t i, n = aFragment->GetLength();
11624 0 : for (i = 0; i < n; i++) {
11625 0 : char16_t ch = aFragment->CharAt(i);
11626 : // FIXME: take content language into account when deciding whitespace.
11627 0 : if (dom::IsSpaceCharacter(ch)) {
11628 0 : if (firstLetterLength) {
11629 0 : break;
11630 : }
11631 0 : count++;
11632 0 : continue;
11633 : }
11634 : // XXX I18n
11635 0 : if ((ch == '\'') || (ch == '\"')) {
11636 0 : if (firstLetterLength) {
11637 0 : break;
11638 : }
11639 : // keep looping
11640 0 : firstLetterLength = 1;
11641 : }
11642 : else {
11643 0 : count++;
11644 0 : break;
11645 : }
11646 : }
11647 :
11648 0 : return count;
11649 : }
11650 :
11651 : static bool
11652 0 : NeedFirstLetterContinuation(nsIContent* aContent)
11653 : {
11654 0 : NS_PRECONDITION(aContent, "null ptr");
11655 :
11656 0 : bool result = false;
11657 0 : if (aContent) {
11658 0 : const nsTextFragment* frag = aContent->GetText();
11659 0 : if (frag) {
11660 0 : int32_t flc = FirstLetterCount(frag);
11661 0 : int32_t tl = frag->GetLength();
11662 0 : if (flc < tl) {
11663 0 : result = true;
11664 : }
11665 : }
11666 : }
11667 0 : return result;
11668 : }
11669 :
11670 0 : static bool IsFirstLetterContent(nsIContent* aContent)
11671 : {
11672 0 : return aContent->TextLength() &&
11673 0 : !aContent->TextIsOnlyWhitespace();
11674 : }
11675 :
11676 : /**
11677 : * Create a letter frame, only make it a floating frame.
11678 : */
11679 : nsFirstLetterFrame*
11680 0 : nsCSSFrameConstructor::CreateFloatingLetterFrame(
11681 : nsFrameConstructorState& aState,
11682 : nsIContent* aTextContent,
11683 : nsIFrame* aTextFrame,
11684 : nsContainerFrame* aParentFrame,
11685 : nsStyleContext* aStyleContext,
11686 : nsFrameItems& aResult)
11687 : {
11688 : nsFirstLetterFrame* letterFrame =
11689 0 : NS_NewFirstLetterFrame(mPresShell, aStyleContext);
11690 : // We don't want to use a text content for a non-text frame (because we want
11691 : // its primary frame to be a text frame). So use its parent for the
11692 : // first-letter.
11693 0 : nsIContent* letterContent = aTextContent->GetParent();
11694 0 : nsContainerFrame* containingBlock = aState.GetGeometricParent(
11695 0 : aStyleContext->StyleDisplay(), aParentFrame);
11696 0 : InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
11697 :
11698 : // Init the text frame to refer to the letter frame. Make sure we
11699 : // get a proper style context for it (the one passed in is for the
11700 : // letter frame and will have the float property set on it; the text
11701 : // frame shouldn't have that set).
11702 0 : StyleSetHandle styleSet = mPresShell->StyleSet();
11703 : RefPtr<nsStyleContext> textSC = styleSet->
11704 0 : ResolveStyleForText(aTextContent, aStyleContext);
11705 0 : aTextFrame->SetStyleContextWithoutNotification(textSC);
11706 0 : InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
11707 :
11708 : // And then give the text frame to the letter frame
11709 0 : SetInitialSingleChild(letterFrame, aTextFrame);
11710 :
11711 : // See if we will need to continue the text frame (does it contain
11712 : // more than just the first-letter text or not?) If it does, then we
11713 : // create (in advance) a continuation frame for it.
11714 0 : nsIFrame* nextTextFrame = nullptr;
11715 0 : if (NeedFirstLetterContinuation(aTextContent)) {
11716 : // Create continuation
11717 : nextTextFrame =
11718 0 : CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame);
11719 : // Repair the continuations style context
11720 0 : nsStyleContext* parentStyleContext = aStyleContext->GetParentAllowServo();
11721 0 : if (parentStyleContext) {
11722 : RefPtr<nsStyleContext> newSC = styleSet->
11723 0 : ResolveStyleForText(aTextContent, parentStyleContext);
11724 0 : nextTextFrame->SetStyleContext(newSC);
11725 : }
11726 : }
11727 :
11728 0 : NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
11729 : // Put the new float before any of the floats in the block we're doing
11730 : // first-letter for, that is, before any floats whose parent is
11731 : // containingBlock.
11732 0 : nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
11733 0 : while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) {
11734 0 : link.Next();
11735 : }
11736 :
11737 0 : aState.AddChild(letterFrame, aResult, letterContent, aStyleContext,
11738 : aParentFrame, false, true, false, true,
11739 0 : link.PrevFrame());
11740 :
11741 0 : if (nextTextFrame) {
11742 0 : aResult.AddChild(nextTextFrame);
11743 : }
11744 :
11745 0 : return letterFrame;
11746 : }
11747 :
11748 : /**
11749 : * Create a new letter frame for aTextFrame. The letter frame will be
11750 : * a child of aParentFrame.
11751 : */
11752 : void
11753 0 : nsCSSFrameConstructor::CreateLetterFrame(nsContainerFrame* aBlockFrame,
11754 : nsContainerFrame* aBlockContinuation,
11755 : nsIContent* aTextContent,
11756 : nsContainerFrame* aParentFrame,
11757 : nsFrameItems& aResult)
11758 : {
11759 0 : NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT),
11760 : "aTextContent isn't text");
11761 0 : NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
11762 : "Not a block frame?");
11763 :
11764 : // Get style context for the first-letter-frame. Keep this in sync with
11765 : // nsBlockFrame::UpdatePseudoElementStyles.
11766 : nsStyleContext* parentStyleContext =
11767 : nsFrame::CorrectStyleParentFrame(aParentFrame,
11768 : nsCSSPseudoElements::firstLetter)->
11769 0 : StyleContext();
11770 :
11771 : // Use content from containing block so that we can actually
11772 : // find a matching style rule.
11773 0 : nsIContent* blockContent = aBlockFrame->GetContent();
11774 :
11775 : // Create first-letter style rule
11776 0 : RefPtr<nsStyleContext> sc = GetFirstLetterStyle(blockContent,
11777 0 : parentStyleContext);
11778 0 : if (sc) {
11779 0 : RefPtr<nsStyleContext> textSC = mPresShell->StyleSet()->
11780 0 : ResolveStyleForText(aTextContent, sc);
11781 :
11782 : // Create a new text frame (the original one will be discarded)
11783 : // pass a temporary stylecontext, the correct one will be set
11784 : // later. Start off by unsetting the primary frame for
11785 : // aTextContent, so it's no longer pointing to the to-be-destroyed
11786 : // frame.
11787 : // XXXbz it would be really nice to destroy the old frame _first_,
11788 : // then create the new one, so we could avoid this hack.
11789 0 : aTextContent->SetPrimaryFrame(nullptr);
11790 0 : nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
11791 :
11792 0 : NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
11793 : "Containing block is confused");
11794 0 : TreeMatchContextHolder matchContext(mDocument);
11795 : nsFrameConstructorState state(mPresShell,
11796 : matchContext,
11797 : GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
11798 : GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
11799 0 : aBlockContinuation);
11800 :
11801 : // Create the right type of first-letter frame
11802 0 : const nsStyleDisplay* display = sc->StyleDisplay();
11803 : nsFirstLetterFrame* letterFrame;
11804 0 : if (display->IsFloatingStyle() &&
11805 0 : !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
11806 : // Make a floating first-letter frame
11807 0 : letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
11808 0 : aParentFrame, sc, aResult);
11809 : }
11810 : else {
11811 : // Make an inflow first-letter frame
11812 0 : letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
11813 :
11814 : // Initialize the first-letter-frame. We don't want to use a text
11815 : // content for a non-text frame (because we want its primary frame to
11816 : // be a text frame). So use its parent for the first-letter.
11817 0 : nsIContent* letterContent = aTextContent->GetParent();
11818 0 : letterFrame->Init(letterContent, aParentFrame, nullptr);
11819 :
11820 0 : InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
11821 :
11822 0 : SetInitialSingleChild(letterFrame, textFrame);
11823 0 : aResult.Clear();
11824 0 : aResult.AddChild(letterFrame);
11825 0 : NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
11826 : "should have the first continuation here");
11827 0 : aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
11828 : }
11829 0 : MOZ_ASSERT(!aBlockFrame->GetPrevContinuation(),
11830 : "Setting up a first-letter frame on a non-first block continuation?");
11831 0 : auto parent = static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
11832 0 : parent->SetHasFirstLetterChild();
11833 0 : aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
11834 0 : letterFrame);
11835 0 : aTextContent->SetPrimaryFrame(textFrame);
11836 : }
11837 0 : }
11838 :
11839 : void
11840 0 : nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
11841 : nsContainerFrame* aBlockFrame,
11842 : nsFrameItems& aBlockFrames)
11843 : {
11844 0 : aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
11845 :
11846 0 : nsContainerFrame* parentFrame = nullptr;
11847 0 : nsIFrame* textFrame = nullptr;
11848 0 : nsIFrame* prevFrame = nullptr;
11849 0 : nsFrameItems letterFrames;
11850 0 : bool stopLooking = false;
11851 0 : WrapFramesInFirstLetterFrame(aBlockFrame, aBlockFrame, aBlockFrame,
11852 : aBlockFrames.FirstChild(),
11853 : &parentFrame, &textFrame, &prevFrame,
11854 0 : letterFrames, &stopLooking);
11855 0 : if (parentFrame) {
11856 0 : if (parentFrame == aBlockFrame) {
11857 : // Take textFrame out of the block's frame list and substitute the
11858 : // letter frame(s) instead.
11859 0 : aBlockFrames.DestroyFrame(textFrame);
11860 0 : aBlockFrames.InsertFrames(nullptr, prevFrame, letterFrames);
11861 : }
11862 : else {
11863 : // Take the old textFrame out of the inline parent's child list
11864 0 : RemoveFrame(kPrincipalList, textFrame);
11865 :
11866 : // Insert in the letter frame(s)
11867 0 : parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
11868 : }
11869 : }
11870 0 : }
11871 :
11872 : void
11873 0 : nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
11874 : nsContainerFrame* aBlockFrame,
11875 : nsContainerFrame* aBlockContinuation,
11876 : nsContainerFrame* aParentFrame,
11877 : nsIFrame* aParentFrameList,
11878 : nsContainerFrame** aModifiedParent,
11879 : nsIFrame** aTextFrame,
11880 : nsIFrame** aPrevFrame,
11881 : nsFrameItems& aLetterFrames,
11882 : bool* aStopLooking)
11883 : {
11884 0 : nsIFrame* prevFrame = nullptr;
11885 0 : nsIFrame* frame = aParentFrameList;
11886 :
11887 0 : while (frame) {
11888 0 : nsIFrame* nextFrame = frame->GetNextSibling();
11889 :
11890 0 : LayoutFrameType frameType = frame->Type();
11891 0 : if (LayoutFrameType::Text == frameType) {
11892 : // Wrap up first-letter content in a letter frame
11893 0 : nsIContent* textContent = frame->GetContent();
11894 0 : if (IsFirstLetterContent(textContent)) {
11895 : // Create letter frame to wrap up the text
11896 : CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
11897 0 : aParentFrame, aLetterFrames);
11898 :
11899 : // Provide adjustment information for parent
11900 0 : *aModifiedParent = aParentFrame;
11901 0 : *aTextFrame = frame;
11902 0 : *aPrevFrame = prevFrame;
11903 0 : *aStopLooking = true;
11904 0 : return;
11905 : }
11906 0 : } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
11907 0 : nsIFrame* kids = frame->PrincipalChildList().FirstChild();
11908 : WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
11909 : static_cast<nsContainerFrame*>(frame),
11910 : kids, aModifiedParent, aTextFrame,
11911 0 : aPrevFrame, aLetterFrames, aStopLooking);
11912 0 : if (*aStopLooking) {
11913 0 : return;
11914 : }
11915 : }
11916 : else {
11917 : // This will stop us looking to create more letter frames. For
11918 : // example, maybe the frame-type is "letterFrame" or
11919 : // "placeholderFrame". This keeps us from creating extra letter
11920 : // frames, and also prevents us from creating letter frames when
11921 : // the first real content child of a block is not text (e.g. an
11922 : // image, hr, etc.)
11923 0 : *aStopLooking = true;
11924 0 : break;
11925 : }
11926 :
11927 0 : prevFrame = frame;
11928 0 : frame = nextFrame;
11929 : }
11930 : }
11931 :
11932 : static nsIFrame*
11933 0 : FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID)
11934 : {
11935 0 : nsFrameList list = aFrame->GetChildList(aListID);
11936 0 : for (nsFrameList::Enumerator e(list); !e.AtEnd(); e.Next()) {
11937 0 : if (e.get()->IsLetterFrame()) {
11938 0 : return e.get();
11939 : }
11940 : }
11941 0 : return nullptr;
11942 : }
11943 :
11944 : void
11945 0 : nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
11946 : nsIPresShell* aPresShell,
11947 : nsIFrame* aBlockFrame)
11948 : {
11949 : // Look for the first letter frame on the kFloatList, then kPushedFloatsList.
11950 : nsIFrame* floatFrame =
11951 0 : ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kFloatList);
11952 0 : if (!floatFrame) {
11953 : floatFrame =
11954 0 : ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList);
11955 0 : if (!floatFrame) {
11956 0 : return;
11957 : }
11958 : }
11959 :
11960 : // Take the text frame away from the letter frame (so it isn't
11961 : // destroyed when we destroy the letter frame).
11962 0 : nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
11963 0 : if (!textFrame) {
11964 0 : return;
11965 : }
11966 :
11967 : // Discover the placeholder frame for the letter frame
11968 0 : nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
11969 0 : if (!placeholderFrame) {
11970 : // Somethings really wrong
11971 0 : return;
11972 : }
11973 0 : nsContainerFrame* parentFrame = placeholderFrame->GetParent();
11974 0 : if (!parentFrame) {
11975 : // Somethings really wrong
11976 0 : return;
11977 : }
11978 0 : static_cast<nsContainerFrame*>(parentFrame->FirstContinuation())->
11979 0 : ClearHasFirstLetterChild();
11980 :
11981 : // Create a new text frame with the right style context that maps
11982 : // all of the content that was previously part of the letter frame
11983 : // (and probably continued elsewhere).
11984 0 : nsStyleContext* parentSC = parentFrame->StyleContext();
11985 0 : nsIContent* textContent = textFrame->GetContent();
11986 0 : if (!textContent) {
11987 0 : return;
11988 : }
11989 0 : RefPtr<nsStyleContext> newSC = aPresShell->StyleSet()->
11990 0 : ResolveStyleForText(textContent, parentSC);
11991 0 : nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
11992 0 : newTextFrame->Init(textContent, parentFrame, nullptr);
11993 :
11994 : // Destroy the old text frame's continuations (the old text frame
11995 : // will be destroyed when its letter frame is destroyed).
11996 0 : nsIFrame* frameToDelete = textFrame->LastContinuation();
11997 0 : while (frameToDelete != textFrame) {
11998 0 : nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
11999 0 : RemoveFrame(kPrincipalList, frameToDelete);
12000 0 : frameToDelete = nextFrameToDelete;
12001 : }
12002 :
12003 0 : nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
12004 :
12005 : // Now that everything is set...
12006 : #ifdef NOISY_FIRST_LETTER
12007 : printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
12008 : textContent.get(), textFrame, newTextFrame);
12009 : #endif
12010 :
12011 : // Remove placeholder frame and the float
12012 0 : RemoveFrame(kPrincipalList, placeholderFrame);
12013 :
12014 : // Now that the old frames are gone, we can start pointing to our
12015 : // new primary frame.
12016 0 : textContent->SetPrimaryFrame(newTextFrame);
12017 :
12018 : // Wallpaper bug 822910.
12019 0 : bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
12020 0 : if (offsetsNeedFixing) {
12021 0 : prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
12022 : }
12023 :
12024 : // Insert text frame in its place
12025 0 : nsFrameList textList(newTextFrame, newTextFrame);
12026 0 : InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
12027 :
12028 0 : if (offsetsNeedFixing) {
12029 0 : prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
12030 : }
12031 : }
12032 :
12033 : void
12034 0 : nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell,
12035 : nsContainerFrame* aFrame,
12036 : nsContainerFrame* aBlockFrame,
12037 : bool* aStopLooking)
12038 : {
12039 0 : nsIFrame* prevSibling = nullptr;
12040 0 : nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
12041 :
12042 0 : while (kid) {
12043 0 : if (kid->IsLetterFrame()) {
12044 : // Bingo. Found it. First steal away the text frame.
12045 0 : static_cast<nsContainerFrame*>(aFrame->FirstContinuation())->
12046 0 : ClearHasFirstLetterChild();
12047 0 : nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
12048 0 : if (!textFrame) {
12049 0 : break;
12050 : }
12051 :
12052 : // Create a new textframe
12053 0 : nsStyleContext* parentSC = aFrame->StyleContext();
12054 0 : if (!parentSC) {
12055 0 : break;
12056 : }
12057 0 : nsIContent* textContent = textFrame->GetContent();
12058 0 : if (!textContent) {
12059 0 : break;
12060 : }
12061 0 : RefPtr<nsStyleContext> newSC = aPresShell->StyleSet()->
12062 0 : ResolveStyleForText(textContent, parentSC);
12063 0 : textFrame = NS_NewTextFrame(aPresShell, newSC);
12064 0 : textFrame->Init(textContent, aFrame, nullptr);
12065 :
12066 : // Next rip out the kid and replace it with the text frame
12067 0 : RemoveFrame(kPrincipalList, kid);
12068 :
12069 : // Now that the old frames are gone, we can start pointing to our
12070 : // new primary frame.
12071 0 : textContent->SetPrimaryFrame(textFrame);
12072 :
12073 : // Wallpaper bug 822910.
12074 0 : bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
12075 0 : if (offsetsNeedFixing) {
12076 0 : prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
12077 : }
12078 :
12079 : // Insert text frame in its place
12080 0 : nsFrameList textList(textFrame, textFrame);
12081 0 : InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
12082 :
12083 0 : if (offsetsNeedFixing) {
12084 0 : prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
12085 : }
12086 :
12087 0 : *aStopLooking = true;
12088 0 : NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
12089 : "should have the first continuation here");
12090 0 : aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
12091 0 : break;
12092 : }
12093 0 : else if (IsInlineFrame(kid)) {
12094 0 : nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
12095 0 : if (kidAsContainerFrame) {
12096 : // Look inside child inline frame for the letter frame.
12097 : RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame,
12098 0 : aBlockFrame, aStopLooking);
12099 0 : if (*aStopLooking) {
12100 0 : break;
12101 : }
12102 : }
12103 : }
12104 0 : prevSibling = kid;
12105 0 : kid = kid->GetNextSibling();
12106 : }
12107 0 : }
12108 :
12109 : void
12110 0 : nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
12111 : nsContainerFrame* aBlockFrame)
12112 : {
12113 : aBlockFrame =
12114 0 : static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
12115 0 : aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
12116 0 : nsContainerFrame* continuation = aBlockFrame;
12117 :
12118 0 : bool stopLooking = false;
12119 0 : do {
12120 0 : RemoveFloatingFirstLetterFrames(aPresShell, continuation);
12121 : RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
12122 0 : &stopLooking);
12123 0 : if (stopLooking) {
12124 0 : break;
12125 : }
12126 : continuation =
12127 0 : static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
12128 0 : } while (continuation);
12129 0 : }
12130 :
12131 : // Fixup the letter frame situation for the given block
12132 : void
12133 0 : nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame)
12134 : {
12135 : aBlockFrame =
12136 0 : static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
12137 0 : nsContainerFrame* continuation = aBlockFrame;
12138 :
12139 0 : nsContainerFrame* parentFrame = nullptr;
12140 0 : nsIFrame* textFrame = nullptr;
12141 0 : nsIFrame* prevFrame = nullptr;
12142 0 : nsFrameItems letterFrames;
12143 0 : bool stopLooking = false;
12144 0 : do {
12145 : // XXX shouldn't this bit be set already (bug 408493), assert instead?
12146 0 : continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
12147 0 : WrapFramesInFirstLetterFrame(aBlockFrame, continuation, continuation,
12148 0 : continuation->PrincipalChildList().FirstChild(),
12149 : &parentFrame, &textFrame, &prevFrame,
12150 0 : letterFrames, &stopLooking);
12151 0 : if (stopLooking) {
12152 0 : break;
12153 : }
12154 : continuation =
12155 0 : static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
12156 0 : } while (continuation);
12157 :
12158 0 : if (parentFrame) {
12159 : // Take the old textFrame out of the parents child list
12160 0 : RemoveFrame(kPrincipalList, textFrame);
12161 :
12162 : // Insert in the letter frame(s)
12163 0 : parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
12164 : }
12165 0 : }
12166 :
12167 : //----------------------------------------------------------------------
12168 :
12169 : // listbox Widget Routines
12170 :
12171 : void
12172 0 : nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
12173 : nsIFrame* aPrevFrame,
12174 : nsIContent* aChild,
12175 : nsIFrame** aNewFrame,
12176 : bool aIsAppend)
12177 : {
12178 : #ifdef MOZ_XUL
12179 : // Construct a new frame
12180 0 : if (nullptr != aParentFrame) {
12181 0 : nsFrameItems frameItems;
12182 0 : TreeMatchContextHolder matchContext(mDocument);
12183 : nsFrameConstructorState state(mPresShell,
12184 : matchContext,
12185 : GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
12186 : GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
12187 : GetFloatContainingBlock(aParentFrame),
12188 0 : do_AddRef(mTempFrameTreeState.get()));
12189 :
12190 : // If we ever initialize the ancestor filter on |state|, make sure
12191 : // to push the right parent!
12192 :
12193 0 : RefPtr<nsStyleContext> styleContext;
12194 0 : styleContext = ResolveStyleContext(aParentFrame, aChild, &state);
12195 :
12196 : // Pre-check for display "none" - only if we find that, do we create
12197 : // any frame at all
12198 0 : const nsStyleDisplay* display = styleContext->StyleDisplay();
12199 :
12200 0 : if (StyleDisplay::None == display->mDisplay) {
12201 0 : *aNewFrame = nullptr;
12202 0 : return;
12203 : }
12204 :
12205 0 : BeginUpdate();
12206 :
12207 0 : FrameConstructionItemList items;
12208 0 : AddFrameConstructionItemsInternal(state, aChild, aParentFrame,
12209 : aChild->NodeInfo()->NameAtom(),
12210 : aChild->GetNameSpaceID(),
12211 : true, styleContext,
12212 0 : ITEM_ALLOW_XBL_BASE, nullptr, items);
12213 0 : ConstructFramesFromItemList(state, items, aParentFrame, frameItems);
12214 :
12215 0 : nsIFrame* newFrame = frameItems.FirstChild();
12216 0 : *aNewFrame = newFrame;
12217 :
12218 0 : if (newFrame) {
12219 : // Notify the parent frame
12220 0 : if (aIsAppend)
12221 0 : ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
12222 : else
12223 0 : ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
12224 : }
12225 :
12226 0 : EndUpdate();
12227 :
12228 : #ifdef ACCESSIBILITY
12229 0 : if (newFrame) {
12230 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
12231 0 : if (accService) {
12232 0 : accService->ContentRangeInserted(mPresShell, aChild->GetParent(),
12233 0 : aChild, aChild->GetNextSibling());
12234 : }
12235 : }
12236 : #endif
12237 : }
12238 : #endif
12239 : }
12240 :
12241 : //----------------------------------------
12242 :
12243 : void
12244 22 : nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
12245 : nsIContent* aContent,
12246 : nsContainerFrame* aParentFrame,
12247 : nsContainerFrame* aContentParentFrame,
12248 : nsStyleContext* aStyleContext,
12249 : nsContainerFrame** aNewFrame,
12250 : nsFrameItems& aFrameItems,
12251 : nsIFrame* aPositionedFrameForAbsPosContainer,
12252 : PendingBinding* aPendingBinding)
12253 : {
12254 : // Create column wrapper if necessary
12255 22 : nsContainerFrame* blockFrame = *aNewFrame;
12256 22 : NS_ASSERTION((blockFrame->IsBlockFrame() || blockFrame->IsDetailsFrame()),
12257 : "not a block frame nor a details frame?");
12258 22 : nsContainerFrame* parent = aParentFrame;
12259 44 : RefPtr<nsStyleContext> blockStyle = aStyleContext;
12260 22 : const nsStyleColumn* columns = aStyleContext->StyleColumn();
12261 :
12262 44 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO
12263 22 : || columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
12264 : nsContainerFrame* columnSetFrame =
12265 0 : NS_NewColumnSetFrame(mPresShell, aStyleContext,
12266 0 : nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
12267 :
12268 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
12269 0 : blockStyle = mPresShell->StyleSet()->
12270 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
12271 0 : aStyleContext);
12272 0 : parent = columnSetFrame;
12273 0 : *aNewFrame = columnSetFrame;
12274 0 : if (aPositionedFrameForAbsPosContainer == blockFrame) {
12275 0 : aPositionedFrameForAbsPosContainer = columnSetFrame;
12276 : }
12277 :
12278 0 : SetInitialSingleChild(columnSetFrame, blockFrame);
12279 : }
12280 :
12281 22 : blockFrame->SetStyleContextWithoutNotification(blockStyle);
12282 22 : InitAndRestoreFrame(aState, aContent, parent, blockFrame);
12283 :
12284 22 : aState.AddChild(*aNewFrame, aFrameItems, aContent, aStyleContext,
12285 : aContentParentFrame ? aContentParentFrame :
12286 22 : aParentFrame);
12287 22 : if (!mRootElementFrame) {
12288 : // The frame we're constructing will be the root element frame.
12289 : // Set mRootElementFrame before processing children.
12290 2 : mRootElementFrame = *aNewFrame;
12291 : }
12292 :
12293 : // We should make the outer frame be the absolute containing block,
12294 : // if one is required. We have to do this because absolute
12295 : // positioning must be computed with respect to the CSS dimensions
12296 : // of the element, which are the dimensions of the outer block. But
12297 : // we can't really do that because only blocks can have absolute
12298 : // children. So use the block and try to compensate with hacks
12299 : // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
12300 44 : nsFrameConstructorSaveState absoluteSaveState;
12301 22 : (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
12302 22 : if (aPositionedFrameForAbsPosContainer) {
12303 : // NS_ASSERTION(aRelPos, "should have made area frame for this");
12304 7 : aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
12305 : }
12306 :
12307 : // Process the child content
12308 22 : nsFrameItems childItems;
12309 : ProcessChildren(aState, aContent, aStyleContext, blockFrame, true,
12310 22 : childItems, true, aPendingBinding);
12311 :
12312 : // Set the frame's initial child list
12313 22 : blockFrame->SetInitialChildList(kPrincipalList, childItems);
12314 22 : }
12315 :
12316 : nsIFrame*
12317 0 : nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
12318 : FrameConstructionItem& aItem,
12319 : nsContainerFrame* aParentFrame,
12320 : const nsStyleDisplay* aDisplay,
12321 : nsFrameItems& aFrameItems)
12322 : {
12323 : // If an inline frame has non-inline kids, then we chop up the child list
12324 : // into runs of blocks and runs of inlines, create anonymous block frames to
12325 : // contain the runs of blocks, inline frames with our style context for the
12326 : // runs of inlines, and put all these frames, in order, into aFrameItems. We
12327 : // return the the first one. The whole setup is called an {ib}
12328 : // split; in what follows "frames in the split" refers to the anonymous blocks
12329 : // and inlines that contain our children.
12330 : //
12331 : // {ib} splits maintain the following invariants:
12332 : // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
12333 : // set.
12334 : // 2) Each frame in the split has the nsIFrame::IBSplitSibling
12335 : // property pointing to the next frame in the split, except for the last
12336 : // one, which does not have it set.
12337 : // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
12338 : // property pointing to the previous frame in the split, except for the
12339 : // first one, which does not have it set.
12340 : // 4) The first and last frame in the split are always inlines.
12341 : //
12342 : // An invariant that is NOT maintained is that the wrappers are actually
12343 : // linked via GetNextSibling linkage. A simple example is an inline
12344 : // containing an inline that contains a block. The three parts of the inner
12345 : // inline end up with three different parents.
12346 : //
12347 : // For example, this HTML:
12348 : // <span>
12349 : // <div>a</div>
12350 : // <span>
12351 : // b
12352 : // <div>c</div>
12353 : // </span>
12354 : // d
12355 : // <div>e</div>
12356 : // f
12357 : // </span>
12358 : // Gives the following frame tree:
12359 : //
12360 : // Inline (outer span)
12361 : // Block (anonymous, outer span)
12362 : // Block (div)
12363 : // Text("a")
12364 : // Inline (outer span)
12365 : // Inline (inner span)
12366 : // Text("b")
12367 : // Block (anonymous, outer span)
12368 : // Block (anonymous, inner span)
12369 : // Block (div)
12370 : // Text("c")
12371 : // Inline (outer span)
12372 : // Inline (inner span)
12373 : // Text("d")
12374 : // Block (anonymous, outer span)
12375 : // Block (div)
12376 : // Text("e")
12377 : // Inline (outer span)
12378 : // Text("f")
12379 :
12380 0 : nsIContent* const content = aItem.mContent;
12381 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
12382 :
12383 : bool positioned =
12384 0 : StyleDisplay::Inline == aDisplay->mDisplay &&
12385 0 : aDisplay->IsRelativelyPositionedStyle() &&
12386 0 : !nsSVGUtils::IsInSVGTextSubtree(aParentFrame);
12387 :
12388 0 : nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext);
12389 :
12390 : // Initialize the frame
12391 0 : InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
12392 :
12393 : // Inline frames can always have generated content
12394 0 : newFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
12395 :
12396 0 : nsFrameConstructorSaveState absoluteSaveState; // definition cannot be inside next block
12397 : // because the object's destructor is significant
12398 : // this is part of the fix for bug 42372
12399 :
12400 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
12401 0 : if (positioned) {
12402 : // Relatively positioned frames becomes a container for child
12403 : // frames that are positioned
12404 0 : aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
12405 : }
12406 :
12407 : // Process the child content
12408 0 : nsFrameItems childItems;
12409 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame, childItems);
12410 :
12411 0 : nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
12412 0 : if (!aItem.mIsAllInline) {
12413 0 : FindFirstBlock(firstBlockEnumerator);
12414 : }
12415 :
12416 0 : if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) {
12417 : // This part is easy. We either already know we have no non-inline kids,
12418 : // or haven't found any when constructing actual frames (the latter can
12419 : // happen only if out-of-flows that we thought had no containing block
12420 : // acquired one when ancestor inline frames and {ib} splits got
12421 : // constructed). Just put all the kids into the single inline frame and
12422 : // bail.
12423 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
12424 0 : aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
12425 0 : return newFrame;
12426 : }
12427 :
12428 : // This inline frame contains several types of children. Therefore this frame
12429 : // has to be chopped into several pieces, as described above.
12430 :
12431 : // Grab the first inline's kids
12432 0 : nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
12433 0 : newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
12434 :
12435 0 : aFrameItems.AddChild(newFrame);
12436 :
12437 0 : newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
12438 0 : CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
12439 :
12440 0 : return newFrame;
12441 : }
12442 :
12443 : void
12444 0 : nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
12445 : nsContainerFrame* aInitialInline,
12446 : bool aIsPositioned,
12447 : nsFrameItems& aChildItems,
12448 : nsFrameItems& aSiblings)
12449 : {
12450 0 : nsIContent* content = aInitialInline->GetContent();
12451 0 : nsStyleContext* styleContext = aInitialInline->StyleContext();
12452 0 : nsContainerFrame* parentFrame = aInitialInline->GetParent();
12453 :
12454 : // Resolve the right style context for our anonymous blocks.
12455 : // The distinction in styles is needed because of CSS 2.1, section
12456 : // 9.2.1.1, which says:
12457 : // When such an inline box is affected by relative positioning, any
12458 : // resulting translation also affects the block-level box contained
12459 : // in the inline box.
12460 0 : RefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()->
12461 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
12462 0 : styleContext);
12463 :
12464 : nsContainerFrame* lastNewInline =
12465 0 : static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
12466 0 : do {
12467 : // On entry to this loop aChildItems is not empty and the first frame in it
12468 : // is block-level.
12469 0 : NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items");
12470 0 : NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(),
12471 : "Must have list starting with block");
12472 :
12473 : // The initial run of blocks belongs to an anonymous block that we create
12474 : // right now. The anonymous block will be the parent of these block
12475 : // children of the inline.
12476 0 : nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
12477 0 : InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
12478 :
12479 : // Find the first non-block child which defines the end of our block kids
12480 : // and the start of our next inline's kids
12481 : nsFrameList::FrameLinkEnumerator firstNonBlock =
12482 0 : FindFirstNonBlock(aChildItems);
12483 0 : nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock);
12484 :
12485 0 : MoveChildrenTo(aInitialInline, blockFrame, blockKids);
12486 :
12487 0 : SetFrameIsIBSplit(lastNewInline, blockFrame);
12488 0 : aSiblings.AddChild(blockFrame);
12489 :
12490 : // Now grab the initial inlines in aChildItems and put them into an inline
12491 : // frame.
12492 0 : nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, styleContext);
12493 0 : InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
12494 0 : inlineFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
12495 0 : NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
12496 0 : if (aIsPositioned) {
12497 0 : inlineFrame->MarkAsAbsoluteContainingBlock();
12498 : }
12499 :
12500 0 : if (aChildItems.NotEmpty()) {
12501 0 : nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
12502 0 : FindFirstBlock(firstBlock);
12503 0 : nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
12504 :
12505 0 : MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
12506 : }
12507 :
12508 0 : SetFrameIsIBSplit(blockFrame, inlineFrame);
12509 0 : aSiblings.AddChild(inlineFrame);
12510 0 : lastNewInline = inlineFrame;
12511 0 : } while (aChildItems.NotEmpty());
12512 :
12513 0 : SetFrameIsIBSplit(lastNewInline, nullptr);
12514 0 : }
12515 :
12516 : void
12517 0 : nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
12518 : FrameConstructionItem& aParentItem,
12519 : bool aItemIsWithinSVGText,
12520 : bool aItemAllowsTextPathChild)
12521 : {
12522 : // XXXbz should we preallocate aParentItem.mChildItems to some sane
12523 : // length? Maybe even to parentContent->GetChildCount()?
12524 : nsFrameConstructorState::PendingBindingAutoPusher
12525 0 : pusher(aState, aParentItem.mPendingBinding);
12526 :
12527 0 : nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
12528 0 : nsIContent* const parentContent = aParentItem.mContent;
12529 :
12530 0 : TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
12531 0 : if (aState.HasAncestorFilter()) {
12532 0 : ancestorPusher.PushAncestorAndStyleScope(parentContent->AsElement());
12533 : } else {
12534 0 : ancestorPusher.PushStyleScope(parentContent->AsElement());
12535 : }
12536 :
12537 0 : if (!aItemIsWithinSVGText) {
12538 : // Probe for generated content before
12539 0 : CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext,
12540 : CSSPseudoElementType::before,
12541 0 : aParentItem.mChildItems);
12542 : }
12543 :
12544 0 : uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
12545 0 : if (aItemIsWithinSVGText) {
12546 0 : flags |= ITEM_IS_WITHIN_SVG_TEXT;
12547 : }
12548 0 : if (aItemAllowsTextPathChild && aParentItem.mIsForSVGAElement) {
12549 0 : flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
12550 : }
12551 :
12552 0 : if (!aParentItem.mAnonChildren.IsEmpty()) {
12553 : // Use the anon-children list instead of the content tree child list so
12554 : // that we use any special style context that should be associated with
12555 : // the children, and so that we won't try to construct grandchildren frame
12556 : // constructor items before the frame is available for their parent.
12557 0 : AddFCItemsForAnonymousContent(aState, nullptr, aParentItem.mAnonChildren,
12558 0 : aParentItem.mChildItems, flags);
12559 : } else {
12560 : // Use the content tree child list:
12561 0 : FlattenedChildIterator iter(parentContent);
12562 0 : for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
12563 : // Get the parent of the content and check if it is a XBL children element
12564 : // (if the content is a children element then contentParent != parentContent because the
12565 : // FlattenedChildIterator will transitively iterate through <xbl:children>
12566 : // for default content). Push the children element as an ancestor here because
12567 : // it does not have a frame and would not otherwise be pushed as an ancestor.
12568 0 : nsIContent* contentParent = content->GetParent();
12569 0 : MOZ_ASSERT(contentParent, "Parent must be non-null because we are iterating children.");
12570 0 : TreeMatchContext::AutoAncestorPusher insertionPointPusher(aState.mTreeMatchContext);
12571 0 : if (contentParent != parentContent && contentParent->IsElement()) {
12572 0 : if (aState.HasAncestorFilter()) {
12573 0 : insertionPointPusher.PushAncestorAndStyleScope(contentParent->AsElement());
12574 : } else {
12575 0 : insertionPointPusher.PushStyleScope(contentParent->AsElement());
12576 : }
12577 : }
12578 :
12579 : // Manually check for comments/PIs, since we don't have a frame to pass to
12580 : // AddFrameConstructionItems. We know our parent is a non-replaced inline,
12581 : // so there is no need to do the NeedFrameFor check.
12582 0 : content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
12583 0 : if (content->IsNodeOfType(nsINode::eCOMMENT) ||
12584 0 : content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
12585 0 : continue;
12586 : }
12587 :
12588 : // See comment explaining why we need to remove the "is possible
12589 : // restyle root" flags in AddFrameConstructionItems. But note
12590 : // that we can remove all restyle flags, just like in
12591 : // ProcessChildren and for the same reason.
12592 0 : content->UnsetRestyleFlagsIfGecko();
12593 :
12594 : RefPtr<nsStyleContext> childContext =
12595 0 : ResolveStyleContext(parentStyleContext, content, &aState);
12596 :
12597 0 : AddFrameConstructionItemsInternal(aState, content, nullptr,
12598 : content->NodeInfo()->NameAtom(),
12599 : content->GetNameSpaceID(),
12600 0 : iter.XBLInvolved(), childContext,
12601 : flags, nullptr,
12602 0 : aParentItem.mChildItems);
12603 : }
12604 : }
12605 :
12606 0 : if (!aItemIsWithinSVGText) {
12607 : // Probe for generated content after
12608 0 : CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext,
12609 : CSSPseudoElementType::after,
12610 0 : aParentItem.mChildItems);
12611 : }
12612 :
12613 0 : aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
12614 0 : }
12615 :
12616 : // return whether it's ok to append (in the AppendFrames sense) to
12617 : // aParentFrame if our nextSibling is aNextSibling. aParentFrame must
12618 : // be an ib-split inline.
12619 : static bool
12620 0 : IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
12621 : {
12622 0 : NS_PRECONDITION(IsInlineFrame(aParentFrame),
12623 : "Must have an inline parent here");
12624 0 : do {
12625 0 : NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),
12626 : "How is this not part of an ib-split?");
12627 0 : if (aNextSibling || aParentFrame->GetNextContinuation() ||
12628 0 : GetIBSplitSibling(aParentFrame)) {
12629 0 : return false;
12630 : }
12631 :
12632 0 : aNextSibling = aParentFrame->GetNextSibling();
12633 0 : aParentFrame = aParentFrame->GetParent();
12634 : } while (IsInlineFrame(aParentFrame));
12635 :
12636 0 : return true;
12637 : }
12638 :
12639 : bool
12640 60 : nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
12641 : nsIFrame* aContainingBlock,
12642 : nsIFrame* aFrame,
12643 : FrameConstructionItemList& aItems,
12644 : bool aIsAppend,
12645 : nsIFrame* aPrevSibling)
12646 : {
12647 60 : if (aItems.IsEmpty()) {
12648 16 : return false;
12649 : }
12650 :
12651 : // Before we go and append the frames, we must check for several
12652 : // special situations.
12653 :
12654 : // Situation #1 is a XUL frame that contains frames that are required
12655 : // to be wrapped in blocks.
12656 110 : if (aFrame->IsXULBoxFrame() &&
12657 66 : !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
12658 22 : aItems.AnyItemsNeedBlockParent()) {
12659 0 : RecreateFramesForContent(aFrame->GetContent(), true,
12660 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
12661 0 : return true;
12662 : }
12663 :
12664 44 : nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
12665 :
12666 : // Situation #2 is a flex or grid container frame into which we're inserting
12667 : // new inline non-replaced children, adjacent to an existing anonymous
12668 : // flex or grid item.
12669 44 : LayoutFrameType frameType = aFrame->Type();
12670 44 : if (frameType == LayoutFrameType::FlexContainer ||
12671 : frameType == LayoutFrameType::GridContainer) {
12672 0 : FCItemIterator iter(aItems);
12673 :
12674 : // Check if we're adding to-be-wrapped content right *after* an existing
12675 : // anonymous flex or grid item (which would need to absorb this content).
12676 0 : const bool isWebkitBox = IsFlexContainerForLegacyBox(aFrame);
12677 0 : if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
12678 0 : iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
12679 0 : RecreateFramesForContent(aFrame->GetContent(), true,
12680 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
12681 0 : return true;
12682 : }
12683 :
12684 : // Check if we're adding to-be-wrapped content right *before* an existing
12685 : // anonymous flex or grid item (which would need to absorb this content).
12686 0 : if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
12687 : // Jump to the last entry in the list
12688 0 : iter.SetToEnd();
12689 0 : iter.Prev();
12690 0 : if (iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
12691 0 : RecreateFramesForContent(aFrame->GetContent(), true,
12692 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
12693 0 : return true;
12694 : }
12695 : }
12696 : }
12697 :
12698 : // Situation #3 is an anonymous flex or grid item that's getting new children
12699 : // who don't want to be wrapped.
12700 44 : if (IsAnonymousFlexOrGridItem(aFrame)) {
12701 0 : AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
12702 :
12703 : // We need to push a null float containing block to be sure that
12704 : // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
12705 : // inserted content. (In particular, this is necessary in order for
12706 : // its "GetGeometricParent" call to return the correct result.)
12707 : // We're not honoring floats on this content because it has the
12708 : // _flex/grid container_ as its parent in the content tree.
12709 0 : nsFrameConstructorSaveState floatSaveState;
12710 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
12711 :
12712 0 : FCItemIterator iter(aItems);
12713 : // Skip over things that _do_ need an anonymous flex item, because
12714 : // they're perfectly happy to go here -- they won't cause a reframe.
12715 0 : nsIFrame* containerFrame = aFrame->GetParent();
12716 0 : const bool isWebkitBox = IsFlexContainerForLegacyBox(containerFrame);
12717 0 : if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState,
12718 : isWebkitBox)) {
12719 : // We hit something that _doesn't_ need an anonymous flex item!
12720 : // Rebuild the flex container to bust it out.
12721 0 : RecreateFramesForContent(containerFrame->GetContent(), true,
12722 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
12723 0 : return true;
12724 : }
12725 :
12726 : // If we get here, then everything in |aItems| needs to be wrapped in
12727 : // an anonymous flex or grid item. That's where it's already going - good!
12728 : }
12729 :
12730 : // Situation #4 is a ruby-related frame that's getting new children.
12731 : // The situation for ruby is complex, especially when interacting with
12732 : // spaces. It containes these two special cases apart from tables:
12733 : // 1) There are effectively three types of white spaces in ruby frames
12734 : // we handle differently: leading/tailing/inter-level space,
12735 : // inter-base/inter-annotation space, and inter-segment space.
12736 : // These three types of spaces can be converted to each other when
12737 : // their sibling changes.
12738 : // 2) The first effective child of a ruby frame must always be a ruby
12739 : // base container. It should be created or destroyed accordingly.
12740 88 : if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
12741 44 : RubyUtils::IsRubyContainerBox(frameType)) {
12742 : // We want to optimize it better, and avoid reframing as much as
12743 : // possible. But given the cases above, and the fact that a ruby
12744 : // usually won't be very large, it should be fine to reframe it.
12745 0 : RecreateFramesForContent(aFrame->GetContent(), true,
12746 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
12747 0 : return true;
12748 : }
12749 :
12750 : // Situation #5 is a case when table pseudo-frames don't work out right
12751 44 : ParentType parentType = GetParentType(aFrame);
12752 : // If all the kids want a parent of the type that aFrame is, then we're all
12753 : // set to go. Indeed, there won't be any table pseudo-frames created between
12754 : // aFrame and the kids, so those won't need to be merged with any table
12755 : // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
12756 : // table pseudo-frame, then all the kids in this list would have wanted a
12757 : // frame of that type wrapping them anyway, so putting them inside it is ok.
12758 44 : if (!aItems.AllWantParentType(parentType)) {
12759 : // Don't give up yet. If parentType is not eTypeBlock and the parent is
12760 : // not a generated content frame, then try filtering whitespace out of the
12761 : // list.
12762 0 : if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
12763 : // For leading whitespace followed by a kid that wants our parent type,
12764 : // there are four cases:
12765 : // 1) We have a previous sibling which is not a table pseudo. That means
12766 : // that previous sibling wanted a (non-block) parent of the type we're
12767 : // looking at. Then the whitespace comes between two table-internal
12768 : // elements, so should be collapsed out.
12769 : // 2) We have a previous sibling which is a table pseudo. It might have
12770 : // kids who want this whitespace, so we need to reframe.
12771 : // 3) We have no previous sibling and our parent frame is not a table
12772 : // pseudo. That means that we'll be at the beginning of our actual
12773 : // non-block-type parent, and the whitespace is OK to collapse out.
12774 : // If something is ever inserted before us, it'll find our own parent
12775 : // as its parent and if it's something that would care about the
12776 : // whitespace it'll want a block parent, so it'll trigger a reframe at
12777 : // that point.
12778 : // 4) We have no previous sibling and our parent frame is a table pseudo.
12779 : // Need to reframe.
12780 : // All that is predicated on finding the correct previous sibling. We
12781 : // might have to walk backwards along continuations from aFrame to do so.
12782 : //
12783 : // It's always OK to drop whitespace between any two items that want a
12784 : // parent of type parentType.
12785 : //
12786 : // For trailing whitespace preceded by a kid that wants our parent type,
12787 : // there are four cases:
12788 : // 1) We have a next sibling which is not a table pseudo. That means
12789 : // that next sibling wanted a (non-block) parent of the type we're
12790 : // looking at. Then the whitespace comes between two table-internal
12791 : // elements, so should be collapsed out.
12792 : // 2) We have a next sibling which is a table pseudo. It might have
12793 : // kids who want this whitespace, so we need to reframe.
12794 : // 3) We have no next sibling and our parent frame is not a table
12795 : // pseudo. That means that we'll be at the end of our actual
12796 : // non-block-type parent, and the whitespace is OK to collapse out.
12797 : // If something is ever inserted after us, it'll find our own parent
12798 : // as its parent and if it's something that would care about the
12799 : // whitespace it'll want a block parent, so it'll trigger a reframe at
12800 : // that point.
12801 : // 4) We have no next sibling and our parent frame is a table pseudo.
12802 : // Need to reframe.
12803 : // All that is predicated on finding the correct next sibling. We might
12804 : // have to walk forward along continuations from aFrame to do so. That
12805 : // said, in the case when nextSibling is null at this point and aIsAppend
12806 : // is true, we know we're in case 3. Furthermore, in that case we don't
12807 : // even have to worry about the table pseudo situation; we know our
12808 : // parent is not a table pseudo there.
12809 0 : FCItemIterator iter(aItems);
12810 0 : FCItemIterator start(iter);
12811 0 : do {
12812 0 : if (iter.SkipItemsWantingParentType(parentType)) {
12813 0 : break;
12814 : }
12815 :
12816 : // iter points to an item that wants a different parent. If it's not
12817 : // whitespace, we're done; no more point scanning the list.
12818 0 : if (!iter.item().IsWhitespace(aState)) {
12819 0 : break;
12820 : }
12821 :
12822 0 : if (iter == start) {
12823 : // Leading whitespace. How to handle this depends on our
12824 : // previous sibling and aFrame. See the long comment above.
12825 0 : nsIFrame* prevSibling = aPrevSibling;
12826 0 : if (!prevSibling) {
12827 : // Try to find one after all
12828 0 : nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
12829 0 : while (parentPrevCont) {
12830 0 : prevSibling = parentPrevCont->GetChildList(kPrincipalList).LastChild();
12831 0 : if (prevSibling) {
12832 0 : break;
12833 : }
12834 0 : parentPrevCont = parentPrevCont->GetPrevContinuation();
12835 : }
12836 : };
12837 0 : if (prevSibling) {
12838 0 : if (IsTablePseudo(prevSibling)) {
12839 : // need to reframe
12840 0 : break;
12841 : }
12842 0 : } else if (IsTablePseudo(aFrame)) {
12843 : // need to reframe
12844 0 : break;
12845 : }
12846 : }
12847 :
12848 0 : FCItemIterator spaceEndIter(iter);
12849 : // Advance spaceEndIter past any whitespace
12850 0 : bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
12851 :
12852 : bool okToDrop;
12853 0 : if (trailingSpaces) {
12854 : // Trailing whitespace. How to handle this depeds on aIsAppend, our
12855 : // next sibling and aFrame. See the long comment above.
12856 0 : okToDrop = aIsAppend && !nextSibling;
12857 0 : if (!okToDrop) {
12858 0 : if (!nextSibling) {
12859 : // Try to find one after all
12860 0 : nsIFrame* parentNextCont = aFrame->GetNextContinuation();
12861 0 : while (parentNextCont) {
12862 0 : nextSibling = parentNextCont->PrincipalChildList().FirstChild();
12863 0 : if (nextSibling) {
12864 0 : break;
12865 : }
12866 0 : parentNextCont = parentNextCont->GetNextContinuation();
12867 : }
12868 : }
12869 :
12870 0 : okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
12871 0 : (!nextSibling && !IsTablePseudo(aFrame));
12872 : }
12873 : #ifdef DEBUG
12874 : else {
12875 0 : NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
12876 : }
12877 : #endif
12878 : } else {
12879 0 : okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
12880 : }
12881 :
12882 0 : if (okToDrop) {
12883 0 : iter.DeleteItemsTo(spaceEndIter);
12884 : } else {
12885 : // We're done: we don't want to drop the whitespace, and it has the
12886 : // wrong parent type.
12887 0 : break;
12888 : }
12889 :
12890 : // Now loop, since |iter| points to item right after the whitespace we
12891 : // removed.
12892 0 : } while (!iter.IsDone());
12893 : }
12894 :
12895 : // We might be able to figure out some sort of optimizations here, but they
12896 : // would have to depend on having a correct aPrevSibling and a correct next
12897 : // sibling. For example, we can probably avoid reframing if none of
12898 : // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
12899 : // doesn't seem worth it to worry about that for now, especially since we
12900 : // in fact do not have a reliable aPrevSibling, nor any next sibling, in
12901 : // this method.
12902 :
12903 : // aItems might have changed, so recheck the parent type thing. In fact,
12904 : // it might be empty, so recheck that too.
12905 0 : if (aItems.IsEmpty()) {
12906 0 : return false;
12907 : }
12908 :
12909 0 : if (!aItems.AllWantParentType(parentType)) {
12910 : // Reframing aFrame->GetContent() is good enough, since the content of
12911 : // table pseudo-frames is the ancestor content.
12912 0 : RecreateFramesForContent(aFrame->GetContent(), true,
12913 0 : REMOVE_FOR_RECONSTRUCTION, nullptr);
12914 0 : return true;
12915 : }
12916 : }
12917 :
12918 : // Now we have several cases involving {ib} splits. Put them all in a
12919 : // do/while with breaks to take us to the "go and reconstruct" code.
12920 : do {
12921 44 : if (IsInlineFrame(aFrame)) {
12922 0 : if (aItems.AreAllItemsInline()) {
12923 : // We can just put the kids in.
12924 0 : return false;
12925 : }
12926 :
12927 0 : if (!IsFramePartOfIBSplit(aFrame)) {
12928 : // Need to go ahead and reconstruct.
12929 0 : break;
12930 : }
12931 :
12932 : // Now we're adding kids including some blocks to an inline part of an
12933 : // {ib} split. If we plan to call AppendFrames, and don't have a next
12934 : // sibling for the new frames, and our parent is the last continuation of
12935 : // the last part of the {ib} split, and the same is true of all our
12936 : // ancestor inlines (they have no following continuations and they're the
12937 : // last part of their {ib} splits and we'd be adding to the end for all
12938 : // of them), then AppendFrames will handle things for us. Bail out in
12939 : // that case.
12940 0 : if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
12941 0 : return false;
12942 : }
12943 :
12944 : // Need to reconstruct.
12945 0 : break;
12946 : }
12947 :
12948 : // Now we know we have a block parent. If it's not part of an
12949 : // ib-split, we're all set.
12950 44 : if (!IsFramePartOfIBSplit(aFrame)) {
12951 44 : return false;
12952 : }
12953 :
12954 : // We're adding some kids to a block part of an {ib} split. If all the
12955 : // kids are blocks, we don't need to reconstruct.
12956 0 : if (aItems.AreAllItemsBlock()) {
12957 0 : return false;
12958 : }
12959 :
12960 : // We might have some inline kids for this block. Just fall out of the
12961 : // loop and reconstruct.
12962 : } while (0);
12963 :
12964 : // If we don't have a containing block, start with aFrame and look for one.
12965 0 : if (!aContainingBlock) {
12966 0 : aContainingBlock = aFrame;
12967 : }
12968 :
12969 : // To find the right block to reframe, just walk up the tree until we find a
12970 : // frame that is:
12971 : // 1) Not part of an IB split
12972 : // 2) Not a pseudo-frame
12973 : // 3) Not an inline frame
12974 : // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
12975 : // enforces that the root is display:none, display:table, or display:block.
12976 : // Note that walking up "too far" is OK in terms of correctness, even if it
12977 : // might be a little inefficient. This is why we walk out of all
12978 : // pseudo-frames -- telling which ones are or are not OK to walk out of is
12979 : // too hard (and I suspect that we do in fact need to walk out of all of
12980 : // them).
12981 0 : while (IsFramePartOfIBSplit(aContainingBlock) ||
12982 0 : aContainingBlock->IsInlineOutside() ||
12983 0 : aContainingBlock->StyleContext()->GetPseudo()) {
12984 0 : aContainingBlock = aContainingBlock->GetParent();
12985 0 : NS_ASSERTION(aContainingBlock,
12986 : "Must have non-inline, non-ib-split, non-pseudo frame as "
12987 : "root (or child of root, for a table root)!");
12988 : }
12989 :
12990 : // Tell parent of the containing block to reformulate the
12991 : // entire block. This is painful and definitely not optimal
12992 : // but it will *always* get the right answer.
12993 :
12994 0 : nsIContent *blockContent = aContainingBlock->GetContent();
12995 : #ifdef DEBUG
12996 0 : if (gNoisyContentUpdates) {
12997 : printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
12998 0 : static_cast<void*>(blockContent));
12999 : }
13000 : #endif
13001 : RecreateFramesForContent(blockContent, true, REMOVE_FOR_RECONSTRUCTION,
13002 0 : nullptr);
13003 0 : return true;
13004 : }
13005 :
13006 : void
13007 0 : nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
13008 : RemoveFlags aFlags,
13009 : nsIContent** aDestroyedFramesFor)
13010 : {
13011 :
13012 : #ifdef DEBUG
13013 : // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
13014 : // so I want to see when it is happening! Unfortunately, it is happening way to often because
13015 : // so much content on the web causes block-in-inline frame situations and we handle them
13016 : // very poorly
13017 0 : if (gNoisyContentUpdates) {
13018 : printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
13019 0 : static_cast<void*>(aFrame));
13020 : }
13021 : #endif
13022 :
13023 : // XXXbz how exactly would we get here while isReflowing anyway? Should this
13024 : // whole test be ifdef DEBUG?
13025 0 : if (mPresShell->IsReflowLocked()) {
13026 : // don't ReframeContainingBlock, this will result in a crash
13027 : // if we remove a tree that's in reflow - see bug 121368 for testcase
13028 0 : NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
13029 0 : return;
13030 : }
13031 :
13032 : // Get the first "normal" ancestor of the target frame.
13033 0 : nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
13034 0 : if (containingBlock) {
13035 : // From here we look for the containing block in case the target
13036 : // frame is already a block (which can happen when an inline frame
13037 : // wraps some of its content in an anonymous block; see
13038 : // ConstructInline)
13039 :
13040 : // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
13041 : // GetIBContainingBlock works much better and provides the correct container in all cases
13042 : // so GetFloatContainingBlock(aFrame) has been removed
13043 :
13044 : // And get the containingBlock's content
13045 0 : nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent();
13046 0 : if (blockContent) {
13047 : #ifdef DEBUG
13048 0 : if (gNoisyContentUpdates) {
13049 0 : printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent));
13050 : }
13051 : #endif
13052 0 : return RecreateFramesForContent(blockContent, true, aFlags, aDestroyedFramesFor);
13053 : }
13054 : }
13055 :
13056 : // If we get here, we're screwed!
13057 0 : return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
13058 0 : true, aFlags, nullptr);
13059 : }
13060 :
13061 : void
13062 0 : nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
13063 : {
13064 : {
13065 0 : nsAutoScriptBlocker scriptBlocker;
13066 0 : BeginUpdate();
13067 :
13068 0 : nsFrameItems childItems;
13069 0 : TreeMatchContextHolder matchContext(mDocument);
13070 0 : nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
13071 : // We don't have a parent frame with a pending binding constructor here,
13072 : // so no need to worry about ordering of the kids' constructors with it.
13073 : // Pass null for the PendingBinding.
13074 0 : ProcessChildren(state, aFrame->GetContent(), aFrame->StyleContext(),
13075 : aFrame, false, childItems, false,
13076 0 : nullptr);
13077 :
13078 0 : aFrame->SetInitialChildList(kPrincipalList, childItems);
13079 :
13080 0 : EndUpdate();
13081 : }
13082 :
13083 : #ifdef ACCESSIBILITY
13084 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
13085 0 : if (accService) {
13086 0 : nsIContent* container = aFrame->GetContent();
13087 0 : nsIContent* child = container->GetFirstChild();
13088 0 : if (child) {
13089 0 : accService->ContentRangeInserted(mPresShell, container, child, nullptr);
13090 : }
13091 : }
13092 : #endif
13093 :
13094 : // call XBL constructors after the frames are created
13095 0 : mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
13096 0 : }
13097 :
13098 : //////////////////////////////////////////////////////////
13099 : // nsCSSFrameConstructor::FrameConstructionItem methods //
13100 : //////////////////////////////////////////////////////////
13101 : bool
13102 8 : nsCSSFrameConstructor::
13103 : FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const
13104 : {
13105 8 : NS_PRECONDITION(aState.mCreatingExtraFrames ||
13106 : !mContent->GetPrimaryFrame(), "How did that happen?");
13107 8 : if (!mIsText) {
13108 0 : return false;
13109 : }
13110 8 : mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
13111 8 : NS_REFRAME_IF_WHITESPACE);
13112 8 : return mContent->TextIsOnlyWhitespace();
13113 : }
13114 :
13115 : //////////////////////////////////////////////////////////////
13116 : // nsCSSFrameConstructor::FrameConstructionItemList methods //
13117 : //////////////////////////////////////////////////////////////
13118 : void
13119 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13120 : AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta)
13121 : {
13122 0 : NS_PRECONDITION(aDelta == 1 || aDelta == -1, "Unexpected delta");
13123 0 : mItemCount += aDelta;
13124 0 : if (aItem->mIsAllInline) {
13125 0 : mInlineCount += aDelta;
13126 : }
13127 0 : if (aItem->mIsBlock) {
13128 0 : mBlockCount += aDelta;
13129 : }
13130 0 : if (aItem->mIsLineParticipant) {
13131 0 : mLineParticipantCount += aDelta;
13132 : }
13133 0 : mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
13134 0 : }
13135 :
13136 : ////////////////////////////////////////////////////////////////////////
13137 : // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
13138 : ////////////////////////////////////////////////////////////////////////
13139 : inline bool
13140 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13141 : Iterator::SkipItemsWantingParentType(ParentType aParentType)
13142 : {
13143 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
13144 0 : while (item().DesiredParentType() == aParentType) {
13145 0 : Next();
13146 0 : if (IsDone()) {
13147 0 : return true;
13148 : }
13149 : }
13150 0 : return false;
13151 : }
13152 :
13153 : inline bool
13154 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13155 : Iterator::SkipItemsNotWantingParentType(ParentType aParentType)
13156 : {
13157 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
13158 0 : while (item().DesiredParentType() != aParentType) {
13159 0 : Next();
13160 0 : if (IsDone()) {
13161 0 : return true;
13162 : }
13163 : }
13164 0 : return false;
13165 : }
13166 :
13167 : // Note: we implement -webkit-box & -webkit-inline-box using
13168 : // nsFlexContainerFrame, but we use different rules for what gets wrapped in an
13169 : // anonymous flex item.
13170 : bool
13171 0 : nsCSSFrameConstructor::FrameConstructionItem::
13172 : NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
13173 : bool aIsWebkitBox)
13174 : {
13175 0 : if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
13176 : // This will be an inline non-replaced box.
13177 0 : return true;
13178 : }
13179 :
13180 0 : if (aIsWebkitBox) {
13181 0 : if (mStyleContext->StyleDisplay()->IsInlineOutsideStyle()) {
13182 : // In a -webkit-box, all inline-level content gets wrapped in anon item.
13183 0 : return true;
13184 : }
13185 0 : if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
13186 0 : aState.GetGeometricParent(mStyleContext->StyleDisplay(), nullptr)) {
13187 : // We're abspos or fixedpos, which means we'll spawn a placeholder which
13188 : // (because our container is a -webkit-box) we'll need to wrap in an
13189 : // anonymous flex item. So, we just treat _this_ frame as if _it_ needs
13190 : // to be wrapped in an anonymous flex item, and then when we spawn the
13191 : // placeholder, it'll end up in the right spot.
13192 0 : return true;
13193 : }
13194 : }
13195 :
13196 0 : return false;
13197 : }
13198 :
13199 : inline bool
13200 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13201 : Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
13202 : const nsFrameConstructorState& aState,
13203 : bool aIsWebkitBox)
13204 : {
13205 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
13206 0 : while (item().NeedsAnonFlexOrGridItem(aState, aIsWebkitBox)) {
13207 0 : Next();
13208 0 : if (IsDone()) {
13209 0 : return true;
13210 : }
13211 : }
13212 0 : return false;
13213 : }
13214 :
13215 : inline bool
13216 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13217 : Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
13218 : const nsFrameConstructorState& aState,
13219 : bool aIsWebkitBox)
13220 : {
13221 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
13222 0 : while (!(item().NeedsAnonFlexOrGridItem(aState, aIsWebkitBox))) {
13223 0 : Next();
13224 0 : if (IsDone()) {
13225 0 : return true;
13226 : }
13227 : }
13228 0 : return false;
13229 : }
13230 :
13231 : inline bool
13232 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13233 : Iterator::SkipItemsNotWantingRubyParent()
13234 : {
13235 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
13236 0 : while (!IsRubyParentType(item().DesiredParentType())) {
13237 0 : Next();
13238 0 : if (IsDone()) {
13239 0 : return true;
13240 : }
13241 : }
13242 0 : return false;
13243 : }
13244 :
13245 : inline bool
13246 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13247 : Iterator::SkipWhitespace(nsFrameConstructorState& aState)
13248 : {
13249 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
13250 0 : NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?");
13251 0 : do {
13252 0 : Next();
13253 0 : if (IsDone()) {
13254 0 : return true;
13255 : }
13256 0 : } while (item().IsWhitespace(aState));
13257 :
13258 0 : return false;
13259 : }
13260 :
13261 : void
13262 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13263 : Iterator::AppendItemToList(FrameConstructionItemList& aTargetList)
13264 : {
13265 0 : NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
13266 0 : NS_PRECONDITION(!IsDone(), "should not be done");
13267 :
13268 0 : FrameConstructionItem* item = mCurrent;
13269 0 : Next();
13270 0 : item->remove();
13271 0 : aTargetList.mItems.insertBack(item);
13272 :
13273 0 : mList.AdjustCountsForItem(item, -1);
13274 0 : aTargetList.AdjustCountsForItem(item, 1);
13275 0 : }
13276 :
13277 : void
13278 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13279 : Iterator::AppendItemsToList(const Iterator& aEnd,
13280 : FrameConstructionItemList& aTargetList)
13281 : {
13282 0 : NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
13283 0 : NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
13284 :
13285 : // We can't just move our guts to the other list if it already has
13286 : // some information or if we're not moving our entire list.
13287 0 : if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() ||
13288 0 : !aTargetList.mUndisplayedItems.IsEmpty()) {
13289 0 : do {
13290 0 : AppendItemToList(aTargetList);
13291 : } while (*this != aEnd);
13292 0 : return;
13293 : }
13294 :
13295 : // Move our entire list of items into the empty target list.
13296 0 : aTargetList.mItems = Move(mList.mItems);
13297 :
13298 : // Copy over the various counters
13299 0 : aTargetList.mInlineCount = mList.mInlineCount;
13300 0 : aTargetList.mBlockCount = mList.mBlockCount;
13301 0 : aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
13302 0 : aTargetList.mItemCount = mList.mItemCount;
13303 0 : memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
13304 0 : sizeof(aTargetList.mDesiredParentCounts));
13305 :
13306 : // Swap out undisplayed item arrays, before we nuke the array on our end
13307 0 : aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
13308 :
13309 : // reset mList
13310 0 : mList.~FrameConstructionItemList();
13311 0 : new (&mList) FrameConstructionItemList();
13312 :
13313 : // Point ourselves to aEnd, as advertised
13314 0 : SetToEnd();
13315 0 : NS_POSTCONDITION(*this == aEnd, "How did that happen?");
13316 : }
13317 :
13318 : void
13319 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13320 : Iterator::InsertItem(FrameConstructionItem* aItem)
13321 : {
13322 0 : if (IsDone()) {
13323 0 : mList.mItems.insertBack(aItem);
13324 : } else {
13325 : // Just insert the item before us. There's no magic here.
13326 0 : mCurrent->setPrevious(aItem);
13327 : }
13328 0 : mList.AdjustCountsForItem(aItem, 1);
13329 :
13330 0 : NS_POSTCONDITION(aItem->getNext() == mCurrent, "How did that happen?");
13331 0 : }
13332 :
13333 : void
13334 0 : nsCSSFrameConstructor::FrameConstructionItemList::
13335 : Iterator::DeleteItemsTo(const Iterator& aEnd)
13336 : {
13337 0 : NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
13338 0 : NS_PRECONDITION(*this != aEnd, "Shouldn't be at aEnd yet");
13339 :
13340 0 : do {
13341 0 : NS_ASSERTION(!IsDone(), "Ran off end of list?");
13342 0 : FrameConstructionItem* item = mCurrent;
13343 0 : Next();
13344 0 : item->remove();
13345 0 : mList.AdjustCountsForItem(item, -1);
13346 0 : delete item;
13347 : } while (*this != aEnd);
13348 0 : }
13349 :
13350 : void
13351 0 : nsCSSFrameConstructor::QuotesDirty()
13352 : {
13353 0 : NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news");
13354 0 : mQuotesDirty = true;
13355 0 : mPresShell->SetNeedLayoutFlush();
13356 0 : }
13357 :
13358 : void
13359 0 : nsCSSFrameConstructor::CountersDirty()
13360 : {
13361 0 : NS_PRECONDITION(mUpdateCount != 0, "Instant counter updates are bad news");
13362 0 : mCountersDirty = true;
13363 0 : mPresShell->SetNeedLayoutFlush();
13364 0 : }
|