Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * construction of a frame tree that is nearly isomorphic to the content
9 : * tree and updating of that tree in response to dynamic changes
10 : */
11 :
12 : #include "nsCSSFrameConstructor.h"
13 :
14 : #include "mozilla/AutoRestore.h"
15 : #include "mozilla/ComputedStyleInlines.h"
16 : #include "mozilla/DebugOnly.h"
17 : #include "mozilla/ErrorResult.h"
18 : #include "mozilla/dom/HTMLDetailsElement.h"
19 : #include "mozilla/dom/HTMLSelectElement.h"
20 : #include "mozilla/dom/HTMLSummaryElement.h"
21 : #include "mozilla/EventStates.h"
22 : #include "mozilla/Likely.h"
23 : #include "mozilla/LinkedList.h"
24 : #include "mozilla/MemoryReporting.h"
25 : #include "mozilla/PresShell.h"
26 : #include "mozilla/ServoBindings.h"
27 : #include "mozilla/ServoStyleSetInlines.h"
28 : #include "mozilla/StaticPrefs.h"
29 : #include "nsAbsoluteContainingBlock.h"
30 : #include "nsCSSPseudoElements.h"
31 : #include "nsAtom.h"
32 : #include "nsIFrameInlines.h"
33 : #include "nsGkAtoms.h"
34 : #include "nsPresContext.h"
35 : #include "nsIDocument.h"
36 : #include "nsIDocumentInlines.h"
37 : #include "nsTableFrame.h"
38 : #include "nsTableColFrame.h"
39 : #include "nsTableRowFrame.h"
40 : #include "nsTableCellFrame.h"
41 : #include "nsHTMLParts.h"
42 : #include "nsIPresShell.h"
43 : #include "nsUnicharUtils.h"
44 : #include "nsViewManager.h"
45 : #include "nsStyleConsts.h"
46 : #ifdef MOZ_XUL
47 : #include "nsXULElement.h"
48 : #include "mozilla/dom/BoxObject.h"
49 : #endif // MOZ_XUL
50 : #include "nsContainerFrame.h"
51 : #include "nsNameSpaceManager.h"
52 : #include "nsIComboboxControlFrame.h"
53 : #include "nsComboboxControlFrame.h"
54 : #include "nsIListControlFrame.h"
55 : #include "nsPlaceholderFrame.h"
56 : #include "nsTableRowGroupFrame.h"
57 : #include "nsIFormControl.h"
58 : #include "nsCSSAnonBoxes.h"
59 : #include "nsTextFragment.h"
60 : #include "nsIAnonymousContentCreator.h"
61 : #include "nsBindingManager.h"
62 : #include "nsXBLBinding.h"
63 : #include "nsContentUtils.h"
64 : #include "nsIScriptError.h"
65 : #ifdef XP_MACOSX
66 : #include "nsIDocShell.h"
67 : #endif
68 : #include "ChildIterator.h"
69 : #include "nsError.h"
70 : #include "nsLayoutUtils.h"
71 : #include "nsAutoPtr.h"
72 : #include "nsBoxFrame.h"
73 : #include "nsBoxLayout.h"
74 : #include "nsFlexContainerFrame.h"
75 : #include "nsGridContainerFrame.h"
76 : #include "RubyUtils.h"
77 : #include "nsRubyFrame.h"
78 : #include "nsRubyBaseFrame.h"
79 : #include "nsRubyBaseContainerFrame.h"
80 : #include "nsRubyTextFrame.h"
81 : #include "nsRubyTextContainerFrame.h"
82 : #include "nsImageFrame.h"
83 : #include "nsIObjectLoadingContent.h"
84 : #include "nsTArray.h"
85 : #include "mozilla/dom/CharacterData.h"
86 : #include "mozilla/dom/Element.h"
87 : #include "mozilla/dom/ElementInlines.h"
88 : #include "nsAutoLayoutPhase.h"
89 : #include "nsStyleStructInlines.h"
90 : #include "nsPageContentFrame.h"
91 : #include "mozilla/RestyleManager.h"
92 : #include "StickyScrollContainer.h"
93 : #include "nsFieldSetFrame.h"
94 : #include "nsInlineFrame.h"
95 : #include "nsBlockFrame.h"
96 : #include "nsCanvasFrame.h"
97 : #include "nsFirstLetterFrame.h"
98 : #include "nsGfxScrollFrame.h"
99 : #include "nsPageFrame.h"
100 : #include "nsSimplePageSequenceFrame.h"
101 : #include "nsTableWrapperFrame.h"
102 : #include "nsIScrollableFrame.h"
103 : #include "nsBackdropFrame.h"
104 : #include "nsTransitionManager.h"
105 : #include "DetailsFrame.h"
106 : #include "nsThemeConstants.h"
107 :
108 : #ifdef MOZ_XUL
109 : #include "nsIRootBox.h"
110 : #endif
111 : #ifdef ACCESSIBILITY
112 : #include "nsAccessibilityService.h"
113 : #endif
114 :
115 : #include "nsXBLService.h"
116 :
117 : #undef NOISY_FIRST_LETTER
118 :
119 : #include "nsMathMLParts.h"
120 : #include "mozilla/dom/SVGTests.h"
121 : #include "nsSVGUtils.h"
122 :
123 : #include "nsRefreshDriver.h"
124 : #include "nsTextNode.h"
125 : #include "ActiveLayerTracker.h"
126 : #include "nsIPresShellInlines.h"
127 :
128 : using namespace mozilla;
129 : using namespace mozilla::dom;
130 :
131 : // An alias for convenience.
132 : static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
133 :
134 : nsIFrame*
135 : NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
136 :
137 : nsIFrame*
138 : NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
139 :
140 : nsContainerFrame*
141 : NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
142 : nsContainerFrame*
143 : NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
144 : nsIFrame*
145 : NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
146 : nsIFrame*
147 : NS_NewSVGGeometryFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
148 : nsIFrame*
149 : NS_NewSVGGFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
150 : nsIFrame*
151 : NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
152 : nsContainerFrame*
153 : NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
154 : nsIFrame*
155 : NS_NewSVGAFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
156 : nsIFrame*
157 : NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
158 : nsIFrame*
159 : NS_NewSVGSymbolFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
160 : nsIFrame*
161 : NS_NewSVGTextFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
162 : nsIFrame*
163 : NS_NewSVGContainerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
164 : nsIFrame*
165 : NS_NewSVGUseFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
166 : nsIFrame*
167 : NS_NewSVGViewFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
168 : extern nsIFrame*
169 : NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
170 : extern nsIFrame*
171 : NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
172 : extern nsIFrame*
173 : NS_NewSVGStopFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
174 : nsContainerFrame*
175 : NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
176 : nsContainerFrame*
177 : NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
178 : extern nsIFrame*
179 : NS_NewSVGImageFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
180 : nsIFrame*
181 : NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
182 : nsIFrame*
183 : NS_NewSVGFilterFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
184 : nsIFrame*
185 : NS_NewSVGPatternFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
186 : nsIFrame*
187 : NS_NewSVGMaskFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
188 : nsIFrame*
189 : NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
190 : nsIFrame*
191 : NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
192 : nsIFrame*
193 : NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
194 : nsIFrame*
195 : NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
196 :
197 : #include "mozilla/dom/NodeInfo.h"
198 : #include "prenv.h"
199 : #include "nsNodeInfoManager.h"
200 : #include "nsContentCreatorFunctions.h"
201 :
202 : #ifdef DEBUG
203 : // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
204 : // more of the following flags (comma separated) for handy debug
205 : // output.
206 : static bool gNoisyContentUpdates = false;
207 : static bool gReallyNoisyContentUpdates = false;
208 : static bool gNoisyInlineConstruction = false;
209 :
210 : struct FrameCtorDebugFlags {
211 : const char* name;
212 : bool* on;
213 : };
214 :
215 : static FrameCtorDebugFlags gFlags[] = {
216 : { "content-updates", &gNoisyContentUpdates },
217 : { "really-noisy-content-updates", &gReallyNoisyContentUpdates },
218 : { "noisy-inline", &gNoisyInlineConstruction }
219 : };
220 :
221 : #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
222 : #endif
223 :
224 :
225 : #ifdef MOZ_XUL
226 : #include "nsMenuFrame.h"
227 : #include "nsPopupSetFrame.h"
228 : #include "nsTreeColFrame.h"
229 : #include "nsIBoxObject.h"
230 : #include "nsPIListBoxObject.h"
231 : #include "nsListBoxBodyFrame.h"
232 : #include "nsListItemFrame.h"
233 : #include "nsXULLabelFrame.h"
234 :
235 : //------------------------------------------------------------------
236 :
237 : nsContainerFrame*
238 : NS_NewRootBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
239 :
240 : nsContainerFrame*
241 : NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
242 :
243 : nsIFrame*
244 : NS_NewDeckFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
245 :
246 : nsIFrame*
247 : NS_NewLeafBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
248 :
249 : nsIFrame*
250 : NS_NewStackFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
251 :
252 : nsIFrame*
253 : NS_NewProgressMeterFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
254 :
255 : nsIFrame*
256 : NS_NewRangeFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
257 :
258 : nsIFrame*
259 : NS_NewImageBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
260 :
261 : nsIFrame*
262 : NS_NewTextBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
263 :
264 : nsIFrame*
265 : NS_NewGroupBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
266 :
267 : nsIFrame*
268 : NS_NewButtonBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
269 :
270 : nsIFrame*
271 : NS_NewSplitterFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
272 :
273 : nsIFrame*
274 : NS_NewMenuPopupFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
275 :
276 : nsIFrame*
277 : NS_NewPopupSetFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
278 :
279 : nsIFrame*
280 : NS_NewMenuFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle, uint32_t aFlags);
281 :
282 : nsIFrame*
283 : NS_NewMenuBarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
284 :
285 : nsIFrame*
286 : NS_NewTreeBodyFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
287 :
288 : // grid
289 : nsresult
290 : NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsBoxLayout** aNewLayout );
291 : nsIFrame*
292 : NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
293 : nsIFrame*
294 : NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
295 :
296 : // end grid
297 :
298 : nsIFrame*
299 : NS_NewTitleBarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
300 :
301 : nsIFrame*
302 : NS_NewResizerFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
303 :
304 :
305 : #endif
306 :
307 : nsHTMLScrollFrame*
308 : NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle, bool aIsRoot);
309 :
310 : nsXULScrollFrame*
311 : NS_NewXULScrollFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle,
312 : bool aIsRoot, bool aClipAllDescendants);
313 :
314 : nsIFrame*
315 : NS_NewSliderFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
316 :
317 : nsIFrame*
318 : NS_NewScrollbarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
319 :
320 : nsIFrame*
321 : NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
322 :
323 :
324 : #ifdef NOISY_FINDFRAME
325 : static int32_t FFWC_totalCount=0;
326 : static int32_t FFWC_doLoop=0;
327 : static int32_t FFWC_doSibling=0;
328 : static int32_t FFWC_recursions=0;
329 : static int32_t FFWC_nextInFlows=0;
330 : #endif
331 :
332 : #ifdef MOZ_XUL
333 :
334 : static bool
335 0 : IsXULListBox(nsIContent* aContainer)
336 : {
337 0 : return aContainer->IsXULElement(nsGkAtoms::listbox);
338 : }
339 :
340 : static
341 : nsListBoxBodyFrame*
342 0 : MaybeGetListBoxBodyFrame(nsIContent* aChild)
343 : {
344 0 : if (aChild->IsXULElement(nsGkAtoms::listitem) && aChild->GetParent() &&
345 0 : IsXULListBox(aChild->GetParent())) {
346 : RefPtr<nsXULElement> xulElement =
347 0 : nsXULElement::FromNode(aChild->GetParent());
348 0 : nsCOMPtr<nsIBoxObject> boxObject = xulElement->GetBoxObject(IgnoreErrors());
349 0 : nsCOMPtr<nsPIListBoxObject> listBoxObject = do_QueryInterface(boxObject);
350 0 : if (listBoxObject) {
351 0 : return listBoxObject->GetListBoxBody(false);
352 : }
353 : }
354 :
355 : return nullptr;
356 : }
357 : #endif // MOZ_XUL
358 :
359 : // Returns true if aFrame is an anonymous flex/grid item.
360 : static inline bool
361 0 : IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
362 : {
363 0 : const nsAtom* pseudoType = aFrame->Style()->GetPseudo();
364 0 : return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
365 0 : pseudoType == nsCSSAnonBoxes::anonymousGridItem;
366 : }
367 :
368 : // Returns true if aFrame is a flex/grid container.
369 : static inline bool
370 0 : IsFlexOrGridContainer(const nsIFrame* aFrame)
371 : {
372 0 : const LayoutFrameType t = aFrame->Type();
373 0 : return t == LayoutFrameType::FlexContainer ||
374 0 : t == LayoutFrameType::GridContainer;
375 : }
376 :
377 : // Returns true IFF the given nsIFrame is a nsFlexContainerFrame and
378 : // represents a -webkit-{inline-}box or -moz-{inline-}box container.
379 : static inline bool
380 0 : IsFlexContainerForLegacyBox(const nsIFrame* aFrame)
381 : {
382 0 : return aFrame->IsFlexContainerFrame() &&
383 0 : aFrame->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX);
384 : }
385 :
386 : #if DEBUG
387 : static void
388 0 : AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
389 : const nsIFrame* aParent)
390 : {
391 0 : MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
392 : "expected an anonymous flex or grid item child frame");
393 0 : MOZ_ASSERT(aParent, "expected a parent frame");
394 0 : const nsAtom* pseudoType = aChild->Style()->GetPseudo();
395 0 : if (pseudoType == nsCSSAnonBoxes::anonymousFlexItem) {
396 0 : MOZ_ASSERT(aParent->IsFlexContainerFrame(),
397 : "anonymous flex items should only exist as children "
398 : "of flex container frames");
399 : } else {
400 0 : MOZ_ASSERT(aParent->IsGridContainerFrame(),
401 : "anonymous grid items should only exist as children "
402 : "of grid container frames");
403 : }
404 0 : }
405 : #else
406 : #define AssertAnonymousFlexOrGridItemParent(x, y) do { /* nothing */ } while(0)
407 : #endif
408 :
409 : static inline nsContainerFrame*
410 0 : GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
411 : {
412 : // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
413 0 : nsIFrame* firstChild = aFieldsetFrame->PrincipalChildList().FirstChild();
414 0 : nsIFrame* inner = firstChild && firstChild->GetNextSibling() ? firstChild->GetNextSibling() : firstChild;
415 0 : return inner ? inner->GetContentInsertionFrame() : nullptr;
416 : }
417 :
418 : #define FCDATA_DECL(_flags, _func) \
419 : { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr }
420 : #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box) \
421 : { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS, \
422 : { (FrameCreationFunc)_func }, nullptr, &_anon_box }
423 :
424 : #define UNREACHABLE_FCDATA() \
425 : { 0, { (FrameCreationFunc)nullptr }, nullptr, nullptr }
426 : //----------------------------------------------------------------------
427 :
428 : /**
429 : * True if aFrame is an actual inline frame in the sense of non-replaced
430 : * display:inline CSS boxes. In other words, it can be affected by {ib}
431 : * splitting and can contain first-letter frames. Basically, this is either an
432 : * inline frame (positioned or otherwise) or an line frame (this last because
433 : * it can contain first-letter and because inserting blocks in the middle of it
434 : * needs to terminate it).
435 : */
436 : static bool
437 0 : IsInlineFrame(const nsIFrame* aFrame)
438 : {
439 0 : return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
440 : }
441 :
442 : /**
443 : * True for display: contents elements.
444 : */
445 : static inline bool
446 : IsDisplayContents(const Element* aElement)
447 : {
448 0 : return aElement->IsDisplayContents();
449 : }
450 :
451 : static inline bool
452 0 : IsDisplayContents(const nsIContent* aContent)
453 : {
454 0 : return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
455 : }
456 :
457 : /**
458 : * True if aFrame is an instance of an SVG frame class or is an inline/block
459 : * frame being used for SVG text.
460 : */
461 : static bool
462 0 : IsFrameForSVG(const nsIFrame* aFrame)
463 : {
464 0 : return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
465 0 : nsSVGUtils::IsInSVGTextSubtree(aFrame);
466 : }
467 :
468 : /**
469 : * Returns true iff aFrame explicitly prevents its descendants from floating
470 : * (at least, down to the level of descendants which themselves are
471 : * float-containing blocks -- those will manage the floating status of any
472 : * lower-level descendents inside them, of course).
473 : */
474 : static bool
475 0 : ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
476 : {
477 0 : return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
478 0 : aFrame->IsXULBoxFrame() ||
479 0 : ::IsFlexOrGridContainer(aFrame);
480 : }
481 :
482 : /**
483 : * If any children require a block parent, return the first such child.
484 : * Otherwise return null.
485 : */
486 : static nsIContent*
487 0 : AnyKidsNeedBlockParent(nsIFrame *aFrameList)
488 : {
489 0 : for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
490 : // Line participants, such as text and inline frames, can't be
491 : // directly inside a XUL box; they must be wrapped in an
492 : // intermediate block.
493 0 : if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
494 0 : return k->GetContent();
495 : }
496 : }
497 : return nullptr;
498 : }
499 :
500 : // Reparent a frame into a wrapper frame that is a child of its old parent.
501 : static void
502 0 : ReparentFrame(RestyleManager* aRestyleManager,
503 : nsContainerFrame* aNewParentFrame,
504 : nsIFrame* aFrame,
505 : bool aForceStyleReparent)
506 : {
507 0 : aFrame->SetParent(aNewParentFrame);
508 : // We reparent frames for two reasons: to put them inside ::first-line, and to
509 : // put them inside some wrapper anonymous boxes.
510 0 : if (aForceStyleReparent) {
511 0 : aRestyleManager->ReparentComputedStyleForFirstLine(aFrame);
512 : }
513 0 : }
514 :
515 : static void
516 0 : ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
517 : nsContainerFrame* aNewParentFrame,
518 : const nsFrameList& aFrameList,
519 : bool aForceStyleReparent)
520 : {
521 0 : RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
522 0 : for (nsIFrame* f : aFrameList) {
523 0 : ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
524 : }
525 0 : }
526 :
527 : //----------------------------------------------------------------------
528 : //
529 : // When inline frames get weird and have block frames in them, we
530 : // annotate them to help us respond to incremental content changes
531 : // more easily.
532 :
533 : static inline bool
534 0 : IsFramePartOfIBSplit(nsIFrame* aFrame)
535 : {
536 0 : bool result = (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0;
537 0 : MOZ_ASSERT(!result || static_cast<nsBlockFrame*>(do_QueryFrame(aFrame)) ||
538 : static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)),
539 : "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT");
540 0 : return result;
541 : }
542 :
543 0 : static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame)
544 : {
545 0 : MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
546 :
547 : // We only store the "ib-split sibling" annotation with the first
548 : // frame in the continuation chain. Walk back to find that frame now.
549 0 : return aFrame->FirstContinuation()->
550 0 : GetProperty(nsIFrame::IBSplitSibling());
551 : }
552 :
553 0 : static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame)
554 : {
555 0 : MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
556 :
557 : // We only store the ib-split sibling annotation with the first
558 : // frame in the continuation chain. Walk back to find that frame now.
559 0 : return aFrame->FirstContinuation()->
560 0 : GetProperty(nsIFrame::IBSplitPrevSibling());
561 : }
562 :
563 : static nsContainerFrame*
564 0 : GetLastIBSplitSibling(nsIFrame* aFrame)
565 : {
566 0 : for (nsIFrame* frame = aFrame, *next; ; frame = next) {
567 0 : next = GetIBSplitSibling(frame);
568 0 : if (!next) {
569 : return static_cast<nsContainerFrame*>(frame);
570 : }
571 : }
572 : NS_NOTREACHED("unreachable code");
573 : return nullptr;
574 : }
575 :
576 : static void
577 0 : SetFrameIsIBSplit(nsContainerFrame* aFrame, nsContainerFrame* aIBSplitSibling)
578 : {
579 0 : MOZ_ASSERT(aFrame, "bad args!");
580 :
581 : // We should be the only continuation
582 0 : NS_ASSERTION(!aFrame->GetPrevContinuation(),
583 : "assigning ib-split sibling to other than first continuation!");
584 0 : NS_ASSERTION(!aFrame->GetNextContinuation() ||
585 : IsFramePartOfIBSplit(aFrame->GetNextContinuation()),
586 : "should have no non-ib-split continuations here");
587 :
588 : // Mark the frame as ib-split.
589 0 : aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
590 :
591 0 : if (aIBSplitSibling) {
592 0 : NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),
593 : "assigning something other than the first continuation as the "
594 : "ib-split sibling");
595 :
596 : // Store the ib-split sibling (if we were given one) with the
597 : // first frame in the flow.
598 0 : aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
599 0 : aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
600 : }
601 0 : }
602 :
603 : static nsIFrame*
604 0 : GetIBContainingBlockFor(nsIFrame* aFrame)
605 : {
606 0 : MOZ_ASSERT(IsFramePartOfIBSplit(aFrame),
607 : "GetIBContainingBlockFor() should only be called on known IB frames");
608 :
609 : // Get the first "normal" ancestor of the target frame.
610 : nsIFrame* parentFrame;
611 : do {
612 0 : parentFrame = aFrame->GetParent();
613 :
614 0 : if (! parentFrame) {
615 0 : NS_ERROR("no unsplit block frame in IB hierarchy");
616 0 : return aFrame;
617 : }
618 :
619 : // Note that we ignore non-ib-split frames which have a pseudo on their
620 : // ComputedStyle -- they're not the frames we're looking for! In
621 : // particular, they may be hiding a real parent that _is_ in an ib-split.
622 0 : if (!IsFramePartOfIBSplit(parentFrame) &&
623 0 : !parentFrame->Style()->GetPseudo())
624 : break;
625 :
626 : aFrame = parentFrame;
627 : } while (1);
628 :
629 : // post-conditions
630 : NS_ASSERTION(parentFrame, "no normal ancestor found for ib-split frame "
631 : "in GetIBContainingBlockFor");
632 0 : NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt");
633 :
634 : return parentFrame;
635 : }
636 :
637 : // This is a bit slow, but sometimes we need it.
638 : static bool
639 0 : ParentIsWrapperAnonBox(nsIFrame* aParent)
640 : {
641 0 : nsIFrame* maybeAnonBox = aParent;
642 0 : if (maybeAnonBox->Style()->GetPseudo() ==
643 : nsCSSAnonBoxes::cellContent) {
644 : // The thing that would maybe be a wrapper anon box is the cell.
645 0 : maybeAnonBox = maybeAnonBox->GetParent();
646 : }
647 0 : return maybeAnonBox->Style()->IsWrapperAnonBox();
648 : }
649 :
650 : //----------------------------------------------------------------------
651 :
652 : // Block/inline frame construction logic. We maintain a few invariants here:
653 : //
654 : // 1. Block frames contain block and inline frames.
655 : //
656 : // 2. Inline frames only contain inline frames. If an inline parent has a block
657 : // child then the block child is migrated upward until it lands in a block
658 : // parent (the inline frames containing block is where it will end up).
659 :
660 : // After this function returns, aLink is pointing to the first link at or
661 : // after its starting position for which the next frame is a block. If there
662 : // is no such link, it points to the end of the list.
663 : static void
664 0 : FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink)
665 : {
666 0 : for ( ; !aLink.AtEnd(); aLink.Next()) {
667 0 : if (!aLink.NextFrame()->IsInlineOutside()) {
668 : return;
669 : }
670 : }
671 : }
672 :
673 : // This function returns a frame link enumerator pointing to the first link in
674 : // the list for which the next frame is not block. If there is no such link,
675 : // it points to the end of the list.
676 : static nsFrameList::FrameLinkEnumerator
677 0 : FindFirstNonBlock(const nsFrameList& aList)
678 : {
679 0 : nsFrameList::FrameLinkEnumerator link(aList);
680 0 : for (; !link.AtEnd(); link.Next()) {
681 0 : if (link.NextFrame()->IsInlineOutside()) {
682 : break;
683 : }
684 : }
685 0 : return link;
686 : }
687 :
688 : inline void
689 0 : SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame)
690 : {
691 0 : MOZ_ASSERT(!aFrame->GetNextSibling(), "Should be using a frame list");
692 0 : nsFrameList temp(aFrame, aFrame);
693 0 : aParent->SetInitialChildList(kPrincipalList, temp);
694 0 : }
695 :
696 : // -----------------------------------------------------------
697 :
698 : // Structure used when constructing formatting object trees.
699 0 : struct nsFrameItems : public nsFrameList
700 : {
701 : // Appends the frame to the end of the list
702 : void AddChild(nsIFrame* aChild);
703 : };
704 :
705 : void
706 0 : nsFrameItems::AddChild(nsIFrame* aChild)
707 : {
708 0 : MOZ_ASSERT(aChild, "nsFrameItems::AddChild");
709 :
710 : // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild) here,
711 : // but some of our callers put frames that have different
712 : // parents (caption, I'm looking at you) on the same framelist, and
713 : // nsFrameList asserts if you try to do that.
714 0 : if (IsEmpty()) {
715 0 : SetFrames(aChild);
716 : }
717 : else {
718 0 : NS_ASSERTION(aChild != mLastChild,
719 : "Same frame being added to frame list twice?");
720 0 : mLastChild->SetNextSibling(aChild);
721 0 : mLastChild = nsLayoutUtils::GetLastSibling(aChild);
722 : }
723 0 : }
724 :
725 : // -----------------------------------------------------------
726 :
727 : // Structure used when constructing formatting object trees. Contains
728 : // state information needed for absolutely positioned elements
729 : struct nsAbsoluteItems : nsFrameItems {
730 : // containing block for absolutely positioned elements
731 : nsContainerFrame* containingBlock;
732 :
733 : explicit nsAbsoluteItems(nsContainerFrame* aContainingBlock);
734 : #ifdef DEBUG
735 : // XXXbz Does this need a debug-only assignment operator that nulls out the
736 : // childList in the nsAbsoluteItems we're copying? Introducing a difference
737 : // between debug and non-debug behavior seems bad, so I guess not...
738 0 : ~nsAbsoluteItems() {
739 0 : NS_ASSERTION(!FirstChild(),
740 : "Dangling child list. Someone forgot to insert it?");
741 0 : }
742 : #endif
743 :
744 : // Appends the frame to the end of the list
745 : void AddChild(nsIFrame* aChild);
746 : };
747 :
748 0 : nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock)
749 0 : : containingBlock(aContainingBlock)
750 : {
751 0 : }
752 :
753 : // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
754 : void
755 0 : nsAbsoluteItems::AddChild(nsIFrame* aChild)
756 : {
757 0 : aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
758 0 : NS_ASSERTION(aChild->GetPlaceholderFrame(),
759 : "Child without placeholder being added to nsAbsoluteItems?");
760 0 : nsFrameItems::AddChild(aChild);
761 0 : }
762 :
763 : // -----------------------------------------------------------
764 :
765 : // Structure for saving the existing state when pushing/poping containing
766 : // blocks. The destructor restores the state to its previous state
767 : class MOZ_STACK_CLASS nsFrameConstructorSaveState {
768 : public:
769 : typedef nsIFrame::ChildListID ChildListID;
770 : nsFrameConstructorSaveState();
771 : ~nsFrameConstructorSaveState();
772 :
773 : private:
774 : nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
775 : nsAbsoluteItems mSavedItems; // copy of original data
776 :
777 : // The name of the child list in which our frames would belong
778 : ChildListID mChildListID;
779 : nsFrameConstructorState* mState;
780 :
781 : // State used only when we're saving the abs-pos state for a transformed
782 : // element.
783 : nsAbsoluteItems mSavedFixedItems;
784 :
785 : bool mSavedFixedPosIsAbsPos;
786 :
787 : friend class nsFrameConstructorState;
788 : };
789 :
790 : // Structure used to keep track of a list of bindings we need to call
791 : // AddToAttachedQueue on. These should be in post-order depth-first
792 : // flattened tree traversal order.
793 : struct PendingBinding : public LinkedListElement<PendingBinding>
794 : {
795 : #ifdef NS_BUILD_REFCNT_LOGGING
796 0 : PendingBinding() {
797 0 : MOZ_COUNT_CTOR(PendingBinding);
798 0 : }
799 0 : ~PendingBinding() {
800 0 : MOZ_COUNT_DTOR(PendingBinding);
801 0 : }
802 : #endif
803 :
804 : RefPtr<nsXBLBinding> mBinding;
805 : };
806 :
807 : // Structure used for maintaining state information during the
808 : // frame construction process
809 : class MOZ_STACK_CLASS nsFrameConstructorState {
810 : public:
811 : typedef nsIFrame::ChildListID ChildListID;
812 :
813 : nsPresContext *mPresContext;
814 : nsIPresShell *mPresShell;
815 : nsFrameManager *mFrameManager;
816 :
817 : #ifdef MOZ_XUL
818 : // Frames destined for the kPopupList.
819 : nsAbsoluteItems mPopupItems;
820 : #endif
821 :
822 : // Containing block information for out-of-flow frames.
823 : nsAbsoluteItems mFixedItems;
824 : nsAbsoluteItems mAbsoluteItems;
825 : nsAbsoluteItems mFloatedItems;
826 : // The containing block of a frame in the top layer is defined by the
827 : // spec: fixed-positioned frames are children of the viewport frame,
828 : // and absolutely-positioned frames are children of the initial
829 : // containing block. They would not be caught by any other containing
830 : // block, e.g. frames with transform or filter.
831 : nsAbsoluteItems mTopLayerFixedItems;
832 : nsAbsoluteItems mTopLayerAbsoluteItems;
833 :
834 : nsCOMPtr<nsILayoutHistoryState> mFrameState;
835 : // These bits will be added to the state bits of any frame we construct
836 : // using this state.
837 : nsFrameState mAdditionalStateBits;
838 :
839 : // When working with the transform and filter properties, we want to hook
840 : // the abs-pos and fixed-pos lists together, since such
841 : // elements are fixed-pos containing blocks. This flag determines
842 : // whether or not we want to wire the fixed-pos and abs-pos lists
843 : // together.
844 : bool mFixedPosIsAbsPos;
845 :
846 : // A boolean to indicate whether we have a "pending" popupgroup. That is, we
847 : // have already created the FrameConstructionItem for the root popupgroup but
848 : // we have not yet created the relevant frame.
849 : bool mHavePendingPopupgroup;
850 :
851 : // If false (which is the default) then call SetPrimaryFrame() as needed
852 : // during frame construction. If true, don't make any SetPrimaryFrame()
853 : // calls, except for generated content which doesn't have a primary frame
854 : // yet. The mCreatingExtraFrames == true mode is meant to be used for
855 : // construction of random "extra" frames for elements via normal frame
856 : // construction APIs (e.g. replication of things across pages in paginated
857 : // mode).
858 : bool mCreatingExtraFrames;
859 :
860 : nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
861 :
862 : // Constructor
863 : // Use the passed-in history state.
864 : nsFrameConstructorState(
865 : nsIPresShell* aPresShell,
866 : nsContainerFrame* aFixedContainingBlock,
867 : nsContainerFrame* aAbsoluteContainingBlock,
868 : nsContainerFrame* aFloatContainingBlock,
869 : already_AddRefed<nsILayoutHistoryState> aHistoryState);
870 : // Get the history state from the pres context's pres shell.
871 : nsFrameConstructorState(nsIPresShell* aPresShell,
872 : nsContainerFrame* aFixedContainingBlock,
873 : nsContainerFrame* aAbsoluteContainingBlock,
874 : nsContainerFrame* aFloatContainingBlock);
875 :
876 : ~nsFrameConstructorState();
877 :
878 : // Function to push the existing absolute containing block state and
879 : // create a new scope. Code that uses this function should get matching
880 : // logic in GetAbsoluteContainingBlock.
881 : // Also makes aNewAbsoluteContainingBlock the containing block for
882 : // fixed-pos elements if necessary.
883 : // aPositionedFrame is the frame whose style actually makes
884 : // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
885 : // aPositionedFrame is the element's primary frame and
886 : // aNewAbsoluteContainingBlock is the scrolled frame.
887 : void PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
888 : nsIFrame* aPositionedFrame,
889 : nsFrameConstructorSaveState& aSaveState);
890 :
891 : // Function to push the existing float containing block state and
892 : // create a new scope. Code that uses this function should get matching
893 : // logic in GetFloatContainingBlock.
894 : // Pushing a null float containing block forbids any frames from being
895 : // floated until a new float containing block is pushed.
896 : // XXX we should get rid of null float containing blocks and teach the
897 : // various frame classes to deal with floats instead.
898 : void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
899 : nsFrameConstructorSaveState& aSaveState);
900 :
901 : // Function to return the proper geometric parent for a frame with display
902 : // struct given by aStyleDisplay and parent's frame given by
903 : // aContentParentFrame.
904 : nsContainerFrame* GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
905 : nsContainerFrame* aContentParentFrame) const;
906 :
907 : /**
908 : * Function to add a new frame to the right frame list. This MUST be called
909 : * on frames before their children have been processed if the frames might
910 : * conceivably be out-of-flow; otherwise cleanup in error cases won't work
911 : * right. Also, this MUST be called on frames after they have been
912 : * initialized.
913 : * @param aNewFrame the frame to add
914 : * @param aFrameItems the list to add in-flow frames to
915 : * @param aContent the content pointer for aNewFrame
916 : * @param aParentFrame the parent frame for the content if it were in-flow
917 : * @param aCanBePositioned pass false if the frame isn't allowed to be
918 : * positioned
919 : * @param aCanBeFloated pass false if the frame isn't allowed to be
920 : * floated
921 : * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
922 : * (XUL-only)
923 : */
924 : void AddChild(nsIFrame* aNewFrame,
925 : nsFrameItems& aFrameItems,
926 : nsIContent* aContent,
927 : nsContainerFrame* aParentFrame,
928 : bool aCanBePositioned = true,
929 : bool aCanBeFloated = true,
930 : bool aIsOutOfFlowPopup = false,
931 : bool aInsertAfter = false,
932 : nsIFrame* aInsertAfterFrame = nullptr);
933 :
934 : /**
935 : * Function to return the fixed-pos element list. Normally this will just hand back the
936 : * fixed-pos element list, but in case we're dealing with a transformed element that's
937 : * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should
938 : * use this function if they want to get the list acting as the fixed-pos item parent.
939 : */
940 : nsAbsoluteItems& GetFixedItems()
941 : {
942 0 : return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
943 : }
944 : const nsAbsoluteItems& GetFixedItems() const
945 : {
946 0 : return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
947 : }
948 :
949 :
950 : /**
951 : * class to automatically push and pop a pending binding in the frame
952 : * constructor state. See nsCSSFrameConstructor::FrameConstructionItem
953 : * mPendingBinding documentation.
954 : */
955 : class PendingBindingAutoPusher;
956 : friend class PendingBindingAutoPusher;
957 : class MOZ_STACK_CLASS PendingBindingAutoPusher {
958 : public:
959 : PendingBindingAutoPusher(nsFrameConstructorState& aState,
960 : PendingBinding* aPendingBinding) :
961 : mState(aState),
962 0 : mPendingBinding(aState.mCurrentPendingBindingInsertionPoint)
963 : {
964 0 : if (aPendingBinding) {
965 0 : aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
966 : }
967 : }
968 :
969 : ~PendingBindingAutoPusher()
970 : {
971 0 : mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
972 : }
973 :
974 : private:
975 : nsFrameConstructorState& mState;
976 : PendingBinding* mPendingBinding;
977 : };
978 :
979 : /**
980 : * Add a new pending binding to the list
981 : */
982 0 : void AddPendingBinding(PendingBinding* aPendingBinding) {
983 0 : if (mCurrentPendingBindingInsertionPoint) {
984 0 : mCurrentPendingBindingInsertionPoint->setPrevious(aPendingBinding);
985 : } else {
986 0 : mPendingBindings.insertBack(aPendingBinding);
987 : }
988 0 : }
989 :
990 : protected:
991 : friend class nsFrameConstructorSaveState;
992 :
993 : /**
994 : * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
995 : * kids to the aChildListID child list of |aFrameItems.containingBlock|.
996 : */
997 : void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
998 : ChildListID aChildListID);
999 :
1000 : /**
1001 : * GetOutOfFlowFrameItems selects the out-of-flow frame list the new
1002 : * frame should be added to. If the frame shouldn't be added to any
1003 : * out-of-flow list, it returns nullptr. The corresponding type of
1004 : * placeholder is also returned via the aPlaceholderType parameter
1005 : * if this method doesn't return nullptr. The caller should check
1006 : * whether the returned list really has a containing block.
1007 : */
1008 : nsAbsoluteItems* GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
1009 : bool aCanBePositioned,
1010 : bool aCanBeFloated,
1011 : bool aIsOutOfFlowPopup,
1012 : nsFrameState* aPlaceholderType);
1013 :
1014 : void ConstructBackdropFrameFor(nsIContent* aContent, nsIFrame* aFrame);
1015 :
1016 : // Our list of all pending bindings. When we're done, we need to call
1017 : // AddToAttachedQueue on all of them, in order.
1018 : LinkedList<PendingBinding> mPendingBindings;
1019 :
1020 : PendingBinding* mCurrentPendingBindingInsertionPoint;
1021 : };
1022 :
1023 0 : nsFrameConstructorState::nsFrameConstructorState(
1024 : nsIPresShell* aPresShell,
1025 : nsContainerFrame* aFixedContainingBlock,
1026 : nsContainerFrame* aAbsoluteContainingBlock,
1027 : nsContainerFrame* aFloatContainingBlock,
1028 0 : already_AddRefed<nsILayoutHistoryState> aHistoryState)
1029 0 : : mPresContext(aPresShell->GetPresContext()),
1030 : mPresShell(aPresShell),
1031 0 : mFrameManager(aPresShell->FrameConstructor()),
1032 : #ifdef MOZ_XUL
1033 : mPopupItems(nullptr),
1034 : #endif
1035 : mFixedItems(aFixedContainingBlock),
1036 : mAbsoluteItems(aAbsoluteContainingBlock),
1037 : mFloatedItems(aFloatContainingBlock),
1038 : mTopLayerFixedItems(
1039 0 : static_cast<nsContainerFrame*>(mFrameManager->GetRootFrame())),
1040 : mTopLayerAbsoluteItems(
1041 : aPresShell->FrameConstructor()->GetDocElementContainingBlock()),
1042 : // See PushAbsoluteContaningBlock below
1043 : mFrameState(aHistoryState),
1044 : mAdditionalStateBits(nsFrameState(0)),
1045 : // If the fixed-pos containing block is equal to the abs-pos containing
1046 : // block, use the abs-pos containing block's abs-pos list for fixed-pos
1047 : // frames.
1048 0 : mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
1049 : mHavePendingPopupgroup(false),
1050 : mCreatingExtraFrames(false),
1051 0 : mCurrentPendingBindingInsertionPoint(nullptr)
1052 : {
1053 : #ifdef MOZ_XUL
1054 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
1055 0 : if (rootBox) {
1056 0 : mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
1057 : }
1058 : #endif
1059 0 : MOZ_COUNT_CTOR(nsFrameConstructorState);
1060 0 : }
1061 :
1062 0 : nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
1063 : nsContainerFrame* aFixedContainingBlock,
1064 : nsContainerFrame* aAbsoluteContainingBlock,
1065 0 : nsContainerFrame* aFloatContainingBlock)
1066 : : nsFrameConstructorState(aPresShell,
1067 : aFixedContainingBlock,
1068 : aAbsoluteContainingBlock,
1069 : aFloatContainingBlock,
1070 0 : aPresShell->GetDocument()->GetLayoutHistoryState())
1071 : {
1072 0 : }
1073 :
1074 0 : nsFrameConstructorState::~nsFrameConstructorState()
1075 : {
1076 0 : MOZ_COUNT_DTOR(nsFrameConstructorState);
1077 0 : ProcessFrameInsertions(mTopLayerFixedItems, nsIFrame::kFixedList);
1078 0 : ProcessFrameInsertions(mTopLayerAbsoluteItems, nsIFrame::kAbsoluteList);
1079 0 : ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
1080 0 : ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
1081 0 : ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
1082 : #ifdef MOZ_XUL
1083 0 : ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList);
1084 : #endif
1085 0 : for (int32_t i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
1086 0 : mGeneratedTextNodesWithInitializer[i]->
1087 0 : DeleteProperty(nsGkAtoms::genConInitializerProperty);
1088 : }
1089 0 : if (!mPendingBindings.isEmpty()) {
1090 0 : nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager();
1091 0 : do {
1092 0 : nsAutoPtr<PendingBinding> pendingBinding;
1093 0 : pendingBinding = mPendingBindings.popFirst();
1094 0 : bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
1095 0 : } while (!mPendingBindings.isEmpty());
1096 0 : mCurrentPendingBindingInsertionPoint = nullptr;
1097 : }
1098 0 : }
1099 :
1100 : static nsContainerFrame*
1101 0 : AdjustAbsoluteContainingBlock(nsContainerFrame* aContainingBlockIn)
1102 : {
1103 0 : if (!aContainingBlockIn) {
1104 : return nullptr;
1105 : }
1106 :
1107 : // Always use the container's first continuation. (Inline frames can have
1108 : // non-fluid bidi continuations...)
1109 0 : return static_cast<nsContainerFrame*>(aContainingBlockIn->FirstContinuation());
1110 : }
1111 :
1112 : void
1113 0 : nsFrameConstructorState::PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
1114 : nsIFrame* aPositionedFrame,
1115 : nsFrameConstructorSaveState& aSaveState)
1116 : {
1117 0 : aSaveState.mItems = &mAbsoluteItems;
1118 0 : aSaveState.mSavedItems = mAbsoluteItems;
1119 0 : aSaveState.mChildListID = nsIFrame::kAbsoluteList;
1120 0 : aSaveState.mState = this;
1121 0 : aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
1122 :
1123 0 : if (mFixedPosIsAbsPos) {
1124 : // Since we're going to replace mAbsoluteItems, we need to save it into
1125 : // mFixedItems now (and save the current value of mFixedItems).
1126 0 : aSaveState.mSavedFixedItems = mFixedItems;
1127 0 : mFixedItems = mAbsoluteItems;
1128 : }
1129 :
1130 0 : mAbsoluteItems =
1131 0 : nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
1132 :
1133 : /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
1134 : * we're a transformed element.
1135 : */
1136 0 : mFixedPosIsAbsPos = aPositionedFrame &&
1137 0 : aPositionedFrame->IsFixedPosContainingBlock();
1138 :
1139 0 : if (aNewAbsoluteContainingBlock) {
1140 0 : aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
1141 : }
1142 0 : }
1143 :
1144 : void
1145 0 : nsFrameConstructorState::PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
1146 : nsFrameConstructorSaveState& aSaveState)
1147 : {
1148 0 : MOZ_ASSERT(!aNewFloatContainingBlock ||
1149 : aNewFloatContainingBlock->IsFloatContainingBlock(),
1150 : "Please push a real float containing block!");
1151 0 : NS_ASSERTION(!aNewFloatContainingBlock ||
1152 : !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),
1153 : "We should not push a frame that is supposed to _suppress_ "
1154 : "floats as a float containing block!");
1155 0 : aSaveState.mItems = &mFloatedItems;
1156 0 : aSaveState.mSavedItems = mFloatedItems;
1157 0 : aSaveState.mChildListID = nsIFrame::kFloatList;
1158 0 : aSaveState.mState = this;
1159 0 : mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock);
1160 0 : }
1161 :
1162 : nsContainerFrame*
1163 0 : nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
1164 : nsContainerFrame* aContentParentFrame) const
1165 : {
1166 0 : MOZ_ASSERT(aStyleDisplay, "Must have display struct!");
1167 :
1168 : // If there is no container for a fixed, absolute, or floating root
1169 : // frame, we will ignore the positioning. This hack is originally
1170 : // brought to you by the letter T: tables, since other roots don't
1171 : // even call into this code. See bug 178855.
1172 : //
1173 : // XXX Disabling positioning in this case is a hack. If one was so inclined,
1174 : // one could support this either by (1) inserting a dummy block between the
1175 : // table and the canvas or (2) teaching the canvas how to reflow positioned
1176 : // elements. (1) has the usual problems when multiple frames share the same
1177 : // content (notice all the special cases in this file dealing with inner
1178 : // tables and table wrappers which share the same content). (2) requires some
1179 : // work and possible factoring.
1180 : //
1181 : // XXXbz couldn't we just force position to "static" on roots and
1182 : // float to "none"? That's OK per CSS 2.1, as far as I can tell.
1183 :
1184 0 : if (aContentParentFrame &&
1185 0 : nsSVGUtils::IsInSVGTextSubtree(aContentParentFrame)) {
1186 : return aContentParentFrame;
1187 : }
1188 :
1189 0 : if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) {
1190 0 : NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(),
1191 : "Absolutely positioned _and_ floating?");
1192 0 : return mFloatedItems.containingBlock;
1193 : }
1194 :
1195 0 : if (aStyleDisplay->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1196 0 : MOZ_ASSERT(aStyleDisplay->mTopLayer == NS_STYLE_TOP_LAYER_TOP,
1197 : "-moz-top-layer should be either none or top");
1198 0 : MOZ_ASSERT(aStyleDisplay->IsAbsolutelyPositionedStyle(),
1199 : "Top layer items should always be absolutely positioned");
1200 0 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED) {
1201 0 : MOZ_ASSERT(mTopLayerFixedItems.containingBlock, "No root frame?");
1202 : return mTopLayerFixedItems.containingBlock;
1203 : }
1204 0 : MOZ_ASSERT(aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE);
1205 0 : MOZ_ASSERT(mTopLayerAbsoluteItems.containingBlock);
1206 : return mTopLayerAbsoluteItems.containingBlock;
1207 : }
1208 :
1209 0 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
1210 0 : mAbsoluteItems.containingBlock) {
1211 : return mAbsoluteItems.containingBlock;
1212 : }
1213 :
1214 0 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
1215 0 : GetFixedItems().containingBlock) {
1216 0 : return GetFixedItems().containingBlock;
1217 : }
1218 :
1219 : return aContentParentFrame;
1220 : }
1221 :
1222 : nsAbsoluteItems*
1223 0 : nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
1224 : bool aCanBePositioned,
1225 : bool aCanBeFloated,
1226 : bool aIsOutOfFlowPopup,
1227 : nsFrameState* aPlaceholderType)
1228 : {
1229 : #ifdef MOZ_XUL
1230 0 : if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
1231 0 : MOZ_ASSERT(mPopupItems.containingBlock, "Must have a popup set frame!");
1232 0 : *aPlaceholderType = PLACEHOLDER_FOR_POPUP;
1233 0 : return &mPopupItems;
1234 : }
1235 : #endif // MOZ_XUL
1236 0 : if (aCanBeFloated && aNewFrame->IsFloating()) {
1237 0 : *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1238 0 : return &mFloatedItems;
1239 : }
1240 :
1241 0 : if (aCanBePositioned) {
1242 0 : const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1243 0 : if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1244 0 : *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1245 0 : if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1246 0 : *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
1247 0 : return &mTopLayerFixedItems;
1248 : }
1249 0 : *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
1250 0 : return &mTopLayerAbsoluteItems;
1251 : }
1252 0 : if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) {
1253 0 : *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1254 0 : return &mAbsoluteItems;
1255 : }
1256 0 : if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1257 0 : *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1258 : return &GetFixedItems();
1259 : }
1260 : }
1261 : return nullptr;
1262 : }
1263 :
1264 : void
1265 0 : nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent,
1266 : nsIFrame* aFrame)
1267 : {
1268 0 : MOZ_ASSERT(aFrame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1269 0 : nsContainerFrame* frame = do_QueryFrame(aFrame);
1270 0 : if (!frame) {
1271 0 : NS_WARNING("Cannot create backdrop frame for non-container frame");
1272 0 : return;
1273 : }
1274 :
1275 0 : RefPtr<ComputedStyle> style = mPresShell->StyleSet()->
1276 0 : ResolvePseudoElementStyle(aContent->AsElement(),
1277 : CSSPseudoElementType::backdrop,
1278 : /* aParentComputedStyle */ nullptr,
1279 0 : /* aPseudoElement */ nullptr);
1280 0 : MOZ_ASSERT(style->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1281 : nsContainerFrame* parentFrame =
1282 0 : GetGeometricParent(style->StyleDisplay(), nullptr);
1283 :
1284 0 : nsBackdropFrame* backdropFrame = new (mPresShell) nsBackdropFrame(style);
1285 0 : backdropFrame->Init(aContent, parentFrame, nullptr);
1286 :
1287 : nsFrameState placeholderType;
1288 : nsAbsoluteItems* frameItems = GetOutOfFlowFrameItems(backdropFrame,
1289 : true, true, false,
1290 0 : &placeholderType);
1291 0 : MOZ_ASSERT(placeholderType & PLACEHOLDER_FOR_TOPLAYER);
1292 :
1293 : nsIFrame* placeholder = nsCSSFrameConstructor::
1294 0 : CreatePlaceholderFrameFor(mPresShell, aContent, backdropFrame,
1295 0 : frame, nullptr, placeholderType);
1296 0 : nsFrameList temp(placeholder, placeholder);
1297 0 : frame->SetInitialChildList(nsIFrame::kBackdropList, temp);
1298 :
1299 0 : frameItems->AddChild(backdropFrame);
1300 : }
1301 :
1302 : void
1303 0 : nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
1304 : nsFrameItems& aFrameItems,
1305 : nsIContent* aContent,
1306 : nsContainerFrame* aParentFrame,
1307 : bool aCanBePositioned,
1308 : bool aCanBeFloated,
1309 : bool aIsOutOfFlowPopup,
1310 : bool aInsertAfter,
1311 : nsIFrame* aInsertAfterFrame)
1312 : {
1313 0 : MOZ_ASSERT(!aNewFrame->GetNextSibling(), "Shouldn't happen");
1314 :
1315 : nsFrameState placeholderType;
1316 : nsAbsoluteItems* outOfFlowFrameItems =
1317 0 : GetOutOfFlowFrameItems(aNewFrame, aCanBePositioned, aCanBeFloated,
1318 0 : aIsOutOfFlowPopup, &placeholderType);
1319 :
1320 : // The comments in GetGeometricParent regarding root table frames
1321 : // all apply here, unfortunately. Thus, we need to check whether
1322 : // the returned frame items really has containing block.
1323 : nsFrameItems* frameItems;
1324 0 : if (outOfFlowFrameItems && outOfFlowFrameItems->containingBlock) {
1325 0 : MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameItems->containingBlock,
1326 : "Parent of the frame is not the containing block?");
1327 : frameItems = outOfFlowFrameItems;
1328 : } else {
1329 0 : frameItems = &aFrameItems;
1330 0 : placeholderType = nsFrameState(0);
1331 : }
1332 :
1333 0 : if (placeholderType) {
1334 0 : NS_ASSERTION(frameItems != &aFrameItems,
1335 : "Putting frame in-flow _and_ want a placeholder?");
1336 : nsIFrame* placeholderFrame =
1337 0 : nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell,
1338 : aContent,
1339 : aNewFrame,
1340 : aParentFrame,
1341 : nullptr,
1342 0 : placeholderType);
1343 :
1344 0 : placeholderFrame->AddStateBits(mAdditionalStateBits);
1345 : // Add the placeholder frame to the flow
1346 0 : aFrameItems.AddChild(placeholderFrame);
1347 :
1348 0 : if (placeholderType & PLACEHOLDER_FOR_TOPLAYER) {
1349 0 : ConstructBackdropFrameFor(aContent, aNewFrame);
1350 : }
1351 : }
1352 : #ifdef DEBUG
1353 : else {
1354 0 : NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
1355 : "In-flow frame has wrong parent");
1356 : }
1357 : #endif
1358 :
1359 0 : if (aInsertAfter) {
1360 0 : frameItems->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1361 : } else {
1362 0 : frameItems->AddChild(aNewFrame);
1363 : }
1364 0 : }
1365 :
1366 : void
1367 0 : nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
1368 : ChildListID aChildListID)
1369 : {
1370 : #define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems && \
1371 : aChildListID == nsIFrame::kFloatList) || \
1372 : ((&aFrameItems == &mAbsoluteItems || \
1373 : &aFrameItems == &mTopLayerAbsoluteItems) && \
1374 : aChildListID == nsIFrame::kAbsoluteList) || \
1375 : ((&aFrameItems == &mFixedItems || \
1376 : &aFrameItems == &mTopLayerFixedItems) && \
1377 : aChildListID == nsIFrame::kFixedList)
1378 : #ifdef MOZ_XUL
1379 0 : MOZ_ASSERT(NS_NONXUL_LIST_TEST ||
1380 : (&aFrameItems == &mPopupItems &&
1381 : aChildListID == nsIFrame::kPopupList),
1382 : "Unexpected aFrameItems/aChildListID combination");
1383 : #else
1384 : MOZ_ASSERT(NS_NONXUL_LIST_TEST,
1385 : "Unexpected aFrameItems/aChildListID combination");
1386 : #endif
1387 :
1388 0 : if (aFrameItems.IsEmpty()) {
1389 : return;
1390 : }
1391 :
1392 0 : nsContainerFrame* containingBlock = aFrameItems.containingBlock;
1393 :
1394 0 : NS_ASSERTION(containingBlock,
1395 : "Child list without containing block?");
1396 :
1397 0 : if (aChildListID == nsIFrame::kFixedList) {
1398 : // Put this frame on the transformed-frame's abs-pos list instead, if
1399 : // it has abs-pos children instead of fixed-pos children.
1400 0 : aChildListID = containingBlock->GetAbsoluteListID();
1401 : }
1402 :
1403 : // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1404 : // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1405 : // is set) and doesn't have any frames in the aChildListID child list yet.
1406 0 : const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1407 0 : if (childList.IsEmpty() &&
1408 0 : (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1409 : // If we're injecting absolutely positioned frames, inject them on the
1410 : // absolute containing block
1411 0 : if (aChildListID == containingBlock->GetAbsoluteListID()) {
1412 : containingBlock->GetAbsoluteContainingBlock()->
1413 0 : SetInitialChildList(containingBlock, aChildListID, aFrameItems);
1414 : } else {
1415 0 : containingBlock->SetInitialChildList(aChildListID, aFrameItems);
1416 : }
1417 0 : } else if (aChildListID == nsIFrame::kFixedList ||
1418 0 : aChildListID == nsIFrame::kAbsoluteList) {
1419 : // The order is not important for abs-pos/fixed-pos frame list, just
1420 : // append the frame items to the list directly.
1421 0 : mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1422 : } else {
1423 : // Note that whether the frame construction context is doing an append or
1424 : // not is not helpful here, since it could be appending to some frame in
1425 : // the middle of the document, which means we're not necessarily
1426 : // appending to the children of the containing block.
1427 : //
1428 : // We need to make sure the 'append to the end of document' case is fast.
1429 : // So first test the last child of the containing block
1430 0 : nsIFrame* lastChild = childList.LastChild();
1431 :
1432 : // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1433 : // so this will make out-of-flows respect the ordering of placeholders,
1434 : // which is great because it takes care of anonymous content.
1435 0 : nsIFrame* firstNewFrame = aFrameItems.FirstChild();
1436 :
1437 : // Cache the ancestor chain so that we can reuse it if needed.
1438 0 : AutoTArray<nsIFrame*, 20> firstNewFrameAncestors;
1439 0 : nsIFrame* notCommonAncestor = nullptr;
1440 0 : if (lastChild) {
1441 : notCommonAncestor = nsLayoutUtils::FillAncestors(firstNewFrame,
1442 : containingBlock,
1443 0 : &firstNewFrameAncestors);
1444 : }
1445 :
1446 0 : if (!lastChild ||
1447 0 : nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame,
1448 : firstNewFrameAncestors,
1449 : notCommonAncestor ?
1450 : containingBlock : nullptr) < 0) {
1451 : // no lastChild, or lastChild comes before the new children, so just append
1452 0 : mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1453 : } else {
1454 : // Try the other children. First collect them to an array so that a
1455 : // reasonable fast binary search can be used to find the insertion point.
1456 0 : AutoTArray<nsIFrame*, 128> children;
1457 0 : for (nsIFrame* f = childList.FirstChild(); f != lastChild;
1458 0 : f = f->GetNextSibling()) {
1459 0 : children.AppendElement(f);
1460 : }
1461 :
1462 0 : nsIFrame* insertionPoint = nullptr;
1463 0 : int32_t imin = 0;
1464 0 : int32_t max = children.Length();
1465 0 : while (max > imin) {
1466 0 : int32_t imid = imin + ((max - imin) / 2);
1467 0 : nsIFrame* f = children[imid];
1468 : int32_t compare =
1469 0 : nsLayoutUtils::CompareTreePosition(f, firstNewFrame, firstNewFrameAncestors,
1470 0 : notCommonAncestor ? containingBlock : nullptr);
1471 0 : if (compare > 0) {
1472 : // f is after the new frame.
1473 0 : max = imid;
1474 0 : insertionPoint = imid > 0 ? children[imid - 1] : nullptr;
1475 0 : } else if (compare < 0) {
1476 : // f is before the new frame.
1477 0 : imin = imid + 1;
1478 0 : insertionPoint = f;
1479 : } else {
1480 : // This is for the old behavior. Should be removed once it is
1481 : // guaranteed that CompareTreePosition can't return 0!
1482 : // See bug 928645.
1483 0 : NS_WARNING("Something odd happening???");
1484 0 : insertionPoint = nullptr;
1485 0 : for (uint32_t i = 0; i < children.Length(); ++i) {
1486 0 : nsIFrame* f = children[i];
1487 0 : if (nsLayoutUtils::CompareTreePosition(f, firstNewFrame,
1488 : firstNewFrameAncestors,
1489 : notCommonAncestor ?
1490 : containingBlock : nullptr) > 0) {
1491 : break;
1492 : }
1493 0 : insertionPoint = f;
1494 : }
1495 : break;
1496 : }
1497 : }
1498 0 : mFrameManager->InsertFrames(containingBlock, aChildListID,
1499 0 : insertionPoint, aFrameItems);
1500 : }
1501 : }
1502 :
1503 0 : MOZ_ASSERT(aFrameItems.IsEmpty(), "How did that happen?");
1504 : }
1505 :
1506 :
1507 0 : nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1508 : : mItems(nullptr),
1509 : mSavedItems(nullptr),
1510 : mChildListID(kPrincipalList),
1511 : mState(nullptr),
1512 : mSavedFixedItems(nullptr),
1513 0 : mSavedFixedPosIsAbsPos(false)
1514 : {
1515 0 : }
1516 :
1517 0 : nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1518 : {
1519 : // Restore the state
1520 0 : if (mItems) {
1521 0 : NS_ASSERTION(mState, "Can't have mItems set without having a state!");
1522 0 : mState->ProcessFrameInsertions(*mItems, mChildListID);
1523 0 : *mItems = mSavedItems;
1524 : #ifdef DEBUG
1525 : // We've transferred the child list, so drop the pointer we held to it.
1526 : // Note that this only matters for the assert in ~nsAbsoluteItems.
1527 0 : mSavedItems.Clear();
1528 : #endif
1529 0 : if (mItems == &mState->mAbsoluteItems) {
1530 0 : mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
1531 0 : if (mSavedFixedPosIsAbsPos) {
1532 : // mAbsoluteItems was moved to mFixedItems, so move mFixedItems back
1533 : // and repair the old mFixedItems now.
1534 0 : mState->mAbsoluteItems = mState->mFixedItems;
1535 0 : mState->mFixedItems = mSavedFixedItems;
1536 : #ifdef DEBUG
1537 0 : mSavedFixedItems.Clear();
1538 : #endif
1539 : }
1540 : }
1541 0 : NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(),
1542 : "Something corrupted our list");
1543 : }
1544 0 : }
1545 :
1546 : /**
1547 : * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1548 : * pointer of the frames in the list, and reparents their views as needed.
1549 : * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1550 : * ancestors as needed. Then it sets the list as the initial child list
1551 : * on aNewParent, unless aNewParent either already has kids or has been
1552 : * reflowed; in that case it appends the new frames. Note that this
1553 : * method differs from ReparentFrames in that it doesn't change the kids'
1554 : * style.
1555 : */
1556 : // XXXbz Since this is only used for {ib} splits, could we just copy the view
1557 : // bits from aOldParent to aNewParent and then use the
1558 : // nsFrameList::ApplySetParent? That would still leave us doing two passes
1559 : // over the list, of course; if we really wanted to we could factor out the
1560 : // relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1561 : // views, which would make most of this function go away.
1562 : static void
1563 0 : MoveChildrenTo(nsIFrame* aOldParent,
1564 : nsContainerFrame* aNewParent,
1565 : nsFrameList& aFrameList)
1566 : {
1567 0 : bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent();
1568 :
1569 0 : if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) {
1570 : // Move the frames into the new view
1571 0 : nsContainerFrame::ReparentFrameViewList(aFrameList, aOldParent, aNewParent);
1572 : }
1573 :
1574 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
1575 0 : e.get()->SetParent(aNewParent);
1576 : }
1577 :
1578 0 : if (aNewParent->PrincipalChildList().IsEmpty() &&
1579 0 : (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1580 0 : aNewParent->SetInitialChildList(kPrincipalList, aFrameList);
1581 : } else {
1582 0 : aNewParent->AppendFrames(kPrincipalList, aFrameList);
1583 : }
1584 0 : }
1585 :
1586 : //----------------------------------------------------------------------
1587 :
1588 0 : nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument* aDocument,
1589 0 : nsIPresShell* aPresShell)
1590 : : nsFrameManager(aPresShell)
1591 : , mDocument(aDocument)
1592 : , mRootElementFrame(nullptr)
1593 : , mRootElementStyleFrame(nullptr)
1594 : , mDocElementContainingBlock(nullptr)
1595 : , mPageSequenceFrame(nullptr)
1596 : , mFirstFreeFCItem(nullptr)
1597 : , mFCItemsInUse(0)
1598 : , mCurrentDepth(0)
1599 : , mQuotesDirty(false)
1600 : , mCountersDirty(false)
1601 : , mIsDestroyingFrameTree(false)
1602 : , mHasRootAbsPosContainingBlock(false)
1603 0 : , mAlwaysCreateFramesForIgnorableWhitespace(false)
1604 : {
1605 : #ifdef DEBUG
1606 : static bool gFirstTime = true;
1607 0 : if (gFirstTime) {
1608 0 : gFirstTime = false;
1609 0 : char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1610 0 : if (flags) {
1611 : bool error = false;
1612 : for (;;) {
1613 0 : char* comma = PL_strchr(flags, ',');
1614 0 : if (comma)
1615 0 : *comma = '\0';
1616 :
1617 : bool found = false;
1618 : FrameCtorDebugFlags* flag = gFlags;
1619 : FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1620 0 : while (flag < limit) {
1621 0 : if (PL_strcasecmp(flag->name, flags) == 0) {
1622 0 : *(flag->on) = true;
1623 0 : printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag->name);
1624 0 : found = true;
1625 0 : break;
1626 : }
1627 0 : ++flag;
1628 : }
1629 :
1630 0 : if (! found)
1631 0 : error = true;
1632 :
1633 0 : if (! comma)
1634 : break;
1635 :
1636 0 : *comma = ',';
1637 0 : flags = comma + 1;
1638 0 : }
1639 :
1640 0 : if (error) {
1641 0 : printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1642 0 : FrameCtorDebugFlags* flag = gFlags;
1643 0 : FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1644 0 : while (flag < limit) {
1645 0 : printf(" %s\n", flag->name);
1646 0 : ++flag;
1647 : }
1648 0 : printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1649 : printf("names (no whitespace)\n");
1650 : }
1651 : }
1652 : }
1653 : #endif
1654 0 : }
1655 :
1656 : void
1657 0 : nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
1658 : {
1659 0 : if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
1660 0 : if (mQuoteList.DestroyNodesFor(aFrame))
1661 0 : QuotesDirty();
1662 : }
1663 :
1664 0 : if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1665 0 : mCounterManager.DestroyNodesFor(aFrame)) {
1666 : // Technically we don't need to update anything if we destroyed only
1667 : // USE nodes. However, this is unlikely to happen in the real world
1668 : // since USE nodes generally go along with INCREMENT nodes.
1669 0 : CountersDirty();
1670 : }
1671 :
1672 0 : RestyleManager()->NotifyDestroyingFrame(aFrame);
1673 0 : }
1674 :
1675 0 : struct nsGenConInitializer {
1676 : nsAutoPtr<nsGenConNode> mNode;
1677 : nsGenConList* mList;
1678 : void (nsCSSFrameConstructor::*mDirtyAll)();
1679 :
1680 : nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
1681 : void (nsCSSFrameConstructor::*aDirtyAll)())
1682 0 : : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {}
1683 : };
1684 :
1685 : already_AddRefed<nsIContent>
1686 0 : nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState,
1687 : const nsString& aString,
1688 : RefPtr<nsTextNode>* aText,
1689 : nsGenConInitializer* aInitializer)
1690 : {
1691 0 : RefPtr<nsTextNode> content = new nsTextNode(mDocument->NodeInfoManager());
1692 0 : content->SetText(aString, false);
1693 0 : if (aText) {
1694 0 : *aText = content;
1695 : }
1696 0 : if (aInitializer) {
1697 0 : content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
1698 0 : nsINode::DeleteProperty<nsGenConInitializer>);
1699 0 : aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
1700 : }
1701 0 : return content.forget();
1702 : }
1703 :
1704 : already_AddRefed<nsIContent>
1705 0 : nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
1706 : Element* aParentContent,
1707 : ComputedStyle* aComputedStyle,
1708 : uint32_t aContentIndex)
1709 : {
1710 : // Get the content value
1711 : const nsStyleContentData &data =
1712 0 : aComputedStyle->StyleContent()->ContentAt(aContentIndex);
1713 0 : nsStyleContentType type = data.GetType();
1714 :
1715 0 : switch (type) {
1716 : case eStyleContentType_Image: {
1717 0 : imgRequestProxy* image = data.GetImage();
1718 0 : if (!image) {
1719 : // CSS had something specified that couldn't be converted to an
1720 : // image object
1721 : return nullptr;
1722 : }
1723 :
1724 : // Create an image content object and pass it the image request.
1725 : // XXX Check if it's an image type we can handle...
1726 :
1727 0 : return CreateGenConImageContent(mDocument, image);
1728 : }
1729 :
1730 : case eStyleContentType_String:
1731 : return CreateGenConTextNode(aState,
1732 0 : nsDependentString(data.GetString()),
1733 0 : nullptr, nullptr);
1734 :
1735 : case eStyleContentType_Attr: {
1736 0 : const nsStyleContentAttr* attr = data.GetAttr();
1737 0 : RefPtr<nsAtom> attrName = attr->mName;
1738 0 : int32_t attrNameSpace = kNameSpaceID_None;
1739 0 : if (RefPtr<nsAtom> ns = attr->mNamespaceURL) {
1740 : nsresult rv =
1741 0 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns.forget(), attrNameSpace);
1742 0 : NS_ENSURE_SUCCESS(rv, nullptr);
1743 : }
1744 :
1745 0 : if (mDocument->IsHTMLDocument() && aParentContent->IsHTMLElement()) {
1746 0 : ToLowerCaseASCII(attrName);
1747 : }
1748 :
1749 0 : nsCOMPtr<nsIContent> content;
1750 0 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1751 0 : attrNameSpace, attrName, getter_AddRefs(content));
1752 0 : return content.forget();
1753 : }
1754 :
1755 : case eStyleContentType_Counter:
1756 : case eStyleContentType_Counters: {
1757 0 : nsStyleContentData::CounterFunction* counters = data.GetCounters();
1758 : nsCounterList* counterList =
1759 0 : mCounterManager.CounterListFor(counters->mIdent);
1760 :
1761 : nsCounterUseNode* node =
1762 : new nsCounterUseNode(counters, aContentIndex,
1763 0 : type == eStyleContentType_Counters);
1764 :
1765 : nsGenConInitializer* initializer =
1766 : new nsGenConInitializer(node, counterList,
1767 0 : &nsCSSFrameConstructor::CountersDirty);
1768 : return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1769 0 : initializer);
1770 : }
1771 :
1772 : case eStyleContentType_OpenQuote:
1773 : case eStyleContentType_CloseQuote:
1774 : case eStyleContentType_NoOpenQuote:
1775 : case eStyleContentType_NoCloseQuote: {
1776 : nsQuoteNode* node =
1777 0 : new nsQuoteNode(type, aContentIndex);
1778 :
1779 : nsGenConInitializer* initializer =
1780 : new nsGenConInitializer(node, &mQuoteList,
1781 0 : &nsCSSFrameConstructor::QuotesDirty);
1782 : return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1783 0 : initializer);
1784 : }
1785 :
1786 : case eStyleContentType_AltContent: {
1787 : // Use the "alt" attribute; if that fails and the node is an HTML
1788 : // <input>, try the value attribute and then fall back to some default
1789 : // localized text we have.
1790 : // XXX what if the 'alt' attribute is added later, how will we
1791 : // detect that and do the right thing here?
1792 0 : if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
1793 0 : nsCOMPtr<nsIContent> content;
1794 0 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1795 0 : kNameSpaceID_None, nsGkAtoms::alt, getter_AddRefs(content));
1796 0 : return content.forget();
1797 : }
1798 :
1799 0 : if (aParentContent->IsHTMLElement(nsGkAtoms::input)) {
1800 0 : if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
1801 0 : nsCOMPtr<nsIContent> content;
1802 0 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1803 0 : kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content));
1804 0 : return content.forget();
1805 : }
1806 :
1807 0 : nsAutoString temp;
1808 : nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
1809 0 : "Submit", temp);
1810 0 : return CreateGenConTextNode(aState, temp, nullptr, nullptr);
1811 : }
1812 :
1813 : break;
1814 : }
1815 :
1816 : case eStyleContentType_Uninitialized:
1817 0 : NS_NOTREACHED("uninitialized content type");
1818 : return nullptr;
1819 : }
1820 :
1821 : return nullptr;
1822 : }
1823 :
1824 : /*
1825 : * aParentFrame - the frame that should be the parent of the generated
1826 : * content. This is the frame for the corresponding content node,
1827 : * which must not be a leaf frame.
1828 : *
1829 : * Any items created are added to aItems.
1830 : *
1831 : * We create an XML element (tag _moz_generated_content_before or
1832 : * _moz_generated_content_after) representing the pseudoelement. We
1833 : * create a DOM node for each 'content' item and make those nodes the
1834 : * children of the XML element. Then we create a frame subtree for
1835 : * the XML element as if it were a regular child of
1836 : * aParentFrame/aParentContent, giving the XML element the ::before or
1837 : * ::after style.
1838 : */
1839 : void
1840 0 : nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState,
1841 : nsContainerFrame* aParentFrame,
1842 : Element* aParentContent,
1843 : ComputedStyle* aComputedStyle,
1844 : CSSPseudoElementType aPseudoElement,
1845 : FrameConstructionItemList& aItems)
1846 : {
1847 0 : MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before ||
1848 : aPseudoElement == CSSPseudoElementType::after,
1849 : "unexpected aPseudoElement");
1850 :
1851 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
1852 :
1853 : // Probe for the existence of the pseudo-element
1854 0 : RefPtr<ComputedStyle> pseudoComputedStyle;
1855 : pseudoComputedStyle =
1856 0 : styleSet->ProbePseudoElementStyle(aParentContent, aPseudoElement,
1857 0 : aComputedStyle);
1858 0 : if (!pseudoComputedStyle)
1859 0 : return;
1860 :
1861 0 : bool isBefore = aPseudoElement == CSSPseudoElementType::before;
1862 :
1863 : // |ProbePseudoStyleFor| checked the 'display' property and the
1864 : // |ContentCount()| of the 'content' property for us.
1865 0 : RefPtr<NodeInfo> nodeInfo;
1866 : nsAtom* elemName = isBefore ?
1867 0 : nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
1868 0 : nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nullptr,
1869 : kNameSpaceID_None,
1870 0 : nsINode::ELEMENT_NODE);
1871 0 : nsCOMPtr<Element> container;
1872 0 : nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1873 0 : if (NS_FAILED(rv))
1874 0 : return;
1875 :
1876 : // Cleared when the pseudo is unbound from the tree, so no need to store a
1877 : // strong reference, nor a destructor.
1878 : nsAtom* property = isBefore
1879 0 : ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
1880 0 : aParentContent->SetProperty(property, container.get());
1881 :
1882 0 : container->SetIsNativeAnonymousRoot();
1883 0 : container->SetPseudoElementType(aPseudoElement);
1884 :
1885 : // If the parent is in a shadow tree, make sure we don't
1886 : // bind with a document because shadow roots and its descendants
1887 : // are not in document.
1888 : nsIDocument* bindDocument =
1889 0 : aParentContent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
1890 0 : rv = container->BindToTree(bindDocument, aParentContent, aParentContent, true);
1891 0 : if (NS_FAILED(rv)) {
1892 0 : container->UnbindFromTree();
1893 0 : return;
1894 : }
1895 :
1896 : // Servo has already eagerly computed the style for the container, so we can
1897 : // just stick the style on the element and avoid an additional traversal.
1898 : //
1899 : // We don't do this for pseudos that may trigger animations or transitions,
1900 : // since those need to be kicked off by the traversal machinery.
1901 : bool hasServoAnimations =
1902 0 : Servo_ComputedValues_SpecifiesAnimationsOrTransitions(pseudoComputedStyle);
1903 0 : if (!hasServoAnimations) {
1904 0 : Servo_SetExplicitStyle(container, pseudoComputedStyle);
1905 : } else {
1906 : // If animations are involved, we avoid the SetExplicitStyle optimization
1907 : // above. We need to grab style with animations from the pseudo element
1908 : // and replace old one.
1909 0 : mPresShell->StyleSet()->StyleNewSubtree(container);
1910 0 : pseudoComputedStyle = styleSet->ResolveServoStyle(container);
1911 : }
1912 :
1913 0 : uint32_t contentCount = pseudoComputedStyle->StyleContent()->ContentCount();
1914 0 : for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
1915 : nsCOMPtr<nsIContent> content =
1916 0 : CreateGeneratedContent(aState, aParentContent, pseudoComputedStyle,
1917 0 : contentIndex);
1918 0 : if (content) {
1919 0 : container->AppendChildTo(content, false);
1920 0 : if (content->IsElement()) {
1921 : // If we created any children elements, Servo needs to traverse them, but
1922 : // the root is already set up.
1923 0 : mPresShell->StyleSet()->StyleNewSubtree(content->AsElement());
1924 : }
1925 : }
1926 : }
1927 :
1928 0 : AddFrameConstructionItemsInternal(aState, container, aParentFrame, true,
1929 : pseudoComputedStyle,
1930 : ITEM_IS_GENERATED_CONTENT, nullptr,
1931 0 : aItems);
1932 : }
1933 :
1934 : /****************************************************
1935 : ** BEGIN TABLE SECTION
1936 : ****************************************************/
1937 :
1938 : // The term pseudo frame is being used instead of anonymous frame, since anonymous
1939 : // frame has been used elsewhere to refer to frames that have generated content
1940 :
1941 : // Return whether the given frame is a table pseudo-frame. Note that
1942 : // cell-content and table-outer frames have pseudo-types, but are always
1943 : // created, even for non-anonymous cells and tables respectively. So for those
1944 : // we have to examine the cell or table frame to see whether it's a pseudo
1945 : // frame. In particular, a lone table caption will have a table wrapper as its
1946 : // parent, but will also trigger construction of an empty inner table, which
1947 : // will be the one we can examine to see whether the wrapper was a pseudo-frame.
1948 : static bool
1949 0 : IsTablePseudo(nsIFrame* aFrame)
1950 : {
1951 0 : nsAtom* pseudoType = aFrame->Style()->GetPseudo();
1952 0 : return pseudoType &&
1953 0 : (pseudoType == nsCSSAnonBoxes::table ||
1954 0 : pseudoType == nsCSSAnonBoxes::inlineTable ||
1955 0 : pseudoType == nsCSSAnonBoxes::tableColGroup ||
1956 0 : pseudoType == nsCSSAnonBoxes::tableRowGroup ||
1957 0 : pseudoType == nsCSSAnonBoxes::tableRow ||
1958 0 : pseudoType == nsCSSAnonBoxes::tableCell ||
1959 0 : (pseudoType == nsCSSAnonBoxes::cellContent &&
1960 0 : aFrame->GetParent()->Style()->GetPseudo() ==
1961 0 : nsCSSAnonBoxes::tableCell) ||
1962 0 : (pseudoType == nsCSSAnonBoxes::tableWrapper &&
1963 0 : (aFrame->PrincipalChildList().FirstChild()->Style()->GetPseudo() ==
1964 0 : nsCSSAnonBoxes::table ||
1965 0 : aFrame->PrincipalChildList().FirstChild()->Style()->GetPseudo() ==
1966 0 : nsCSSAnonBoxes::inlineTable)));
1967 : }
1968 :
1969 : static bool
1970 0 : IsRubyPseudo(nsIFrame* aFrame)
1971 : {
1972 0 : return RubyUtils::IsRubyPseudo(aFrame->Style()->GetPseudo());
1973 : }
1974 :
1975 : static bool
1976 0 : IsTableOrRubyPseudo(nsIFrame* aFrame)
1977 : {
1978 0 : return IsTablePseudo(aFrame) || IsRubyPseudo(aFrame);
1979 : }
1980 :
1981 : /* static */
1982 : nsCSSFrameConstructor::ParentType
1983 0 : nsCSSFrameConstructor::GetParentType(LayoutFrameType aFrameType)
1984 : {
1985 0 : if (aFrameType == LayoutFrameType::Table) {
1986 : return eTypeTable;
1987 : }
1988 0 : if (aFrameType == LayoutFrameType::TableRowGroup) {
1989 : return eTypeRowGroup;
1990 : }
1991 0 : if (aFrameType == LayoutFrameType::TableRow) {
1992 : return eTypeRow;
1993 : }
1994 0 : if (aFrameType == LayoutFrameType::TableColGroup) {
1995 : return eTypeColGroup;
1996 : }
1997 0 : if (aFrameType == LayoutFrameType::RubyBaseContainer) {
1998 : return eTypeRubyBaseContainer;
1999 : }
2000 0 : if (aFrameType == LayoutFrameType::RubyTextContainer) {
2001 : return eTypeRubyTextContainer;
2002 : }
2003 0 : if (aFrameType == LayoutFrameType::Ruby) {
2004 : return eTypeRuby;
2005 : }
2006 :
2007 0 : return eTypeBlock;
2008 : }
2009 :
2010 : static nsContainerFrame*
2011 0 : AdjustCaptionParentFrame(nsContainerFrame* aParentFrame)
2012 : {
2013 0 : if (aParentFrame->IsTableFrame()) {
2014 0 : return aParentFrame->GetParent();
2015 : }
2016 : return aParentFrame;
2017 : }
2018 :
2019 : /**
2020 : * If the parent frame is a |tableFrame| and the child is a
2021 : * |captionFrame|, then we want to insert the frames beneath the
2022 : * |tableFrame|'s parent frame. Returns |true| if the parent frame
2023 : * needed to be fixed up.
2024 : */
2025 : static bool
2026 0 : GetCaptionAdjustedParent(nsContainerFrame* aParentFrame,
2027 : const nsIFrame* aChildFrame,
2028 : nsContainerFrame** aAdjParentFrame)
2029 : {
2030 0 : *aAdjParentFrame = aParentFrame;
2031 0 : bool haveCaption = false;
2032 :
2033 0 : if (aChildFrame->IsTableCaption()) {
2034 0 : haveCaption = true;
2035 0 : *aAdjParentFrame = ::AdjustCaptionParentFrame(aParentFrame);
2036 : }
2037 0 : return haveCaption;
2038 : }
2039 :
2040 : void
2041 0 : nsCSSFrameConstructor::AdjustParentFrame(nsContainerFrame** aParentFrame,
2042 : const FrameConstructionData* aFCData,
2043 : ComputedStyle* aComputedStyle)
2044 : {
2045 0 : MOZ_ASSERT(aComputedStyle, "Must have child's style");
2046 0 : MOZ_ASSERT(aFCData, "Must have frame construction data");
2047 :
2048 0 : bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0);
2049 :
2050 0 : if (tablePart && aComputedStyle->StyleDisplay()->mDisplay ==
2051 : StyleDisplay::TableCaption) {
2052 0 : *aParentFrame = ::AdjustCaptionParentFrame(*aParentFrame);
2053 : }
2054 0 : }
2055 :
2056 : // Pull all the captions present in aItems out into aCaptions
2057 : static void
2058 0 : PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions)
2059 : {
2060 0 : nsIFrame* child = aItems.FirstChild();
2061 0 : while (child) {
2062 0 : nsIFrame* nextSibling = child->GetNextSibling();
2063 0 : if (child->IsTableCaption()) {
2064 0 : aItems.RemoveFrame(child);
2065 0 : aCaptions.AddChild(child);
2066 : }
2067 : child = nextSibling;
2068 : }
2069 0 : }
2070 :
2071 :
2072 : // Construct the outer, inner table frames and the children frames for the table.
2073 : // XXX Page break frames for pseudo table frames are not constructed to avoid the risk
2074 : // associated with revising the pseudo frame mechanism. The long term solution
2075 : // of having frames handle page-break-before/after will solve the problem.
2076 : nsIFrame*
2077 0 : nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
2078 : FrameConstructionItem& aItem,
2079 : nsContainerFrame* aParentFrame,
2080 : const nsStyleDisplay* aDisplay,
2081 : nsFrameItems& aFrameItems)
2082 : {
2083 0 : MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::Table ||
2084 : aDisplay->mDisplay == StyleDisplay::InlineTable,
2085 : "Unexpected call");
2086 :
2087 0 : nsIContent* const content = aItem.mContent;
2088 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
2089 0 : const bool isMathMLContent = content->IsMathMLElement();
2090 :
2091 : // create the pseudo SC for the table wrapper as a child of the inner SC
2092 0 : RefPtr<ComputedStyle> outerComputedStyle;
2093 0 : outerComputedStyle = mPresShell->StyleSet()->
2094 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::tableWrapper,
2095 0 : computedStyle);
2096 :
2097 : // Create the table wrapper frame which holds the caption and inner table frame
2098 : nsContainerFrame* newFrame;
2099 0 : if (isMathMLContent)
2100 0 : newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerComputedStyle);
2101 : else
2102 0 : newFrame = NS_NewTableWrapperFrame(mPresShell, outerComputedStyle);
2103 :
2104 : nsContainerFrame* geometricParent =
2105 0 : aState.GetGeometricParent(outerComputedStyle->StyleDisplay(),
2106 0 : aParentFrame);
2107 :
2108 : // Init the table wrapper frame
2109 0 : InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2110 :
2111 : // Create the inner table frame
2112 : nsContainerFrame* innerFrame;
2113 0 : if (isMathMLContent)
2114 0 : innerFrame = NS_NewMathMLmtableFrame(mPresShell, computedStyle);
2115 : else
2116 0 : innerFrame = NS_NewTableFrame(mPresShell, computedStyle);
2117 :
2118 0 : InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2119 0 : innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2120 :
2121 : // Put the newly created frames into the right child list
2122 0 : SetInitialSingleChild(newFrame, innerFrame);
2123 :
2124 0 : aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
2125 :
2126 0 : if (!mRootElementFrame) {
2127 : // The frame we're constructing will be the root element frame.
2128 : // Set mRootElementFrame before processing children.
2129 0 : mRootElementFrame = newFrame;
2130 : }
2131 :
2132 0 : nsFrameItems childItems;
2133 :
2134 : // Process children
2135 0 : nsFrameConstructorSaveState absoluteSaveState;
2136 0 : const nsStyleDisplay* display = outerComputedStyle->StyleDisplay();
2137 :
2138 : // Mark the table frame as an absolute container if needed
2139 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2140 0 : if (display->IsAbsPosContainingBlock(newFrame)) {
2141 0 : aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2142 : }
2143 0 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2144 : "nsIAnonymousContentCreator::CreateAnonymousContent "
2145 : "implementations for table frames are not currently expected "
2146 : "to output a list where the items have their own children");
2147 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2148 0 : ConstructFramesFromItemList(aState, aItem.mChildItems,
2149 : innerFrame,
2150 0 : aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
2151 0 : childItems);
2152 : } else {
2153 0 : ProcessChildren(aState, content, computedStyle, innerFrame,
2154 0 : true, childItems, false, aItem.mPendingBinding);
2155 : }
2156 :
2157 0 : nsFrameItems captionItems;
2158 0 : PullOutCaptionFrames(childItems, captionItems);
2159 :
2160 : // Set the inner table frame's initial primary list
2161 0 : innerFrame->SetInitialChildList(kPrincipalList, childItems);
2162 :
2163 : // Set the table wrapper frame's secondary childlist lists
2164 0 : if (captionItems.NotEmpty()) {
2165 0 : newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems);
2166 : }
2167 :
2168 0 : return newFrame;
2169 : }
2170 :
2171 : static void
2172 0 : MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState& aState,
2173 : const nsStyleDisplay* aDisplay,
2174 : nsFrameConstructorSaveState& aAbsSaveState,
2175 : nsContainerFrame* aFrame)
2176 : {
2177 : // If we're positioned, then we need to become an absolute containing block
2178 : // for any absolutely positioned children and register for post-reflow fixup.
2179 : //
2180 : // Note that usually if a frame type can be an absolute containing block, we
2181 : // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not.
2182 : // However, in this case flag serves the additional purpose of indicating that
2183 : // the frame was registered with its table frame. This allows us to avoid the
2184 : // overhead of unregistering the frame in most cases.
2185 0 : if (aDisplay->IsAbsPosContainingBlock(aFrame)) {
2186 0 : aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2187 0 : aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2188 0 : nsTableFrame::RegisterPositionedTablePart(aFrame);
2189 : }
2190 0 : }
2191 :
2192 : nsIFrame*
2193 0 : nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
2194 : FrameConstructionItem& aItem,
2195 : nsContainerFrame* aParentFrame,
2196 : const nsStyleDisplay* aDisplay,
2197 : nsFrameItems& aFrameItems)
2198 : {
2199 0 : MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableRow ||
2200 : aDisplay->mDisplay == StyleDisplay::TableRowGroup ||
2201 : aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
2202 : aDisplay->mDisplay == StyleDisplay::TableHeaderGroup,
2203 : "Not a row or row group");
2204 0 : MOZ_ASSERT(aItem.mComputedStyle->StyleDisplay() == aDisplay,
2205 : "Display style doesn't match style");
2206 0 : nsIContent* const content = aItem.mContent;
2207 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
2208 :
2209 : nsContainerFrame* newFrame;
2210 0 : if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2211 0 : if (content->IsMathMLElement())
2212 0 : newFrame = NS_NewMathMLmtrFrame(mPresShell, computedStyle);
2213 : else
2214 0 : newFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
2215 : } else {
2216 0 : newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
2217 : }
2218 :
2219 0 : InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2220 :
2221 0 : nsFrameConstructorSaveState absoluteSaveState;
2222 : MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2223 : absoluteSaveState,
2224 0 : newFrame);
2225 :
2226 0 : nsFrameItems childItems;
2227 0 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2228 : "nsIAnonymousContentCreator::CreateAnonymousContent "
2229 : "implementations for table frames are not currently expected "
2230 : "to output a list where the items have their own children");
2231 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2232 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
2233 0 : aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
2234 0 : childItems);
2235 : } else {
2236 0 : ProcessChildren(aState, content, computedStyle, newFrame,
2237 0 : true, childItems, false, aItem.mPendingBinding);
2238 : }
2239 :
2240 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
2241 0 : aFrameItems.AddChild(newFrame);
2242 0 : return newFrame;
2243 : }
2244 :
2245 : nsIFrame*
2246 0 : nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState& aState,
2247 : FrameConstructionItem& aItem,
2248 : nsContainerFrame* aParentFrame,
2249 : const nsStyleDisplay* aStyleDisplay,
2250 : nsFrameItems& aFrameItems)
2251 : {
2252 0 : nsIContent* const content = aItem.mContent;
2253 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
2254 :
2255 0 : nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, computedStyle);
2256 0 : InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2257 :
2258 0 : NS_ASSERTION(colFrame->Style() == computedStyle, "Unexpected style");
2259 :
2260 0 : aFrameItems.AddChild(colFrame);
2261 :
2262 : // construct additional col frames if the col frame has a span > 1
2263 0 : int32_t span = colFrame->GetSpan();
2264 0 : for (int32_t spanX = 1; spanX < span; spanX++) {
2265 0 : nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, computedStyle);
2266 0 : InitAndRestoreFrame(aState, content, aParentFrame, newCol, false);
2267 0 : aFrameItems.LastChild()->SetNextContinuation(newCol);
2268 0 : newCol->SetPrevContinuation(aFrameItems.LastChild());
2269 0 : aFrameItems.AddChild(newCol);
2270 0 : newCol->SetColType(eColAnonymousCol);
2271 : }
2272 :
2273 0 : return colFrame;
2274 : }
2275 :
2276 : nsIFrame*
2277 0 : nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState,
2278 : FrameConstructionItem& aItem,
2279 : nsContainerFrame* aParentFrame,
2280 : const nsStyleDisplay* aDisplay,
2281 : nsFrameItems& aFrameItems)
2282 : {
2283 0 : MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableCell,
2284 : "Unexpected call");
2285 :
2286 0 : nsIContent* const content = aItem.mContent;
2287 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
2288 0 : const bool isMathMLContent = content->IsMathMLElement();
2289 :
2290 : nsTableFrame* tableFrame =
2291 0 : static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2292 : nsContainerFrame* newFrame;
2293 : // <mtable> is border separate in mathml.css and the MathML code doesn't implement
2294 : // border collapse. For those users who style <mtable> with border collapse,
2295 : // give them the default non-MathML table frames that understand border collapse.
2296 : // This won't break us because MathML table frames are all subclasses of the default
2297 : // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
2298 : // What will happen is just that non-MathML frames won't understand MathML attributes
2299 : // and will therefore miss the special handling that the MathML code does.
2300 0 : if (isMathMLContent && !tableFrame->IsBorderCollapse()) {
2301 0 : newFrame = NS_NewMathMLmtdFrame(mPresShell, computedStyle, tableFrame);
2302 : } else {
2303 : // Warning: If you change this and add a wrapper frame around table cell
2304 : // frames, make sure Bug 368554 doesn't regress!
2305 : // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2306 0 : newFrame = NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
2307 : }
2308 :
2309 : // Initialize the table cell frame
2310 0 : InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2311 0 : newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2312 :
2313 : // Resolve pseudo style and initialize the body cell frame
2314 0 : RefPtr<ComputedStyle> innerPseudoStyle;
2315 0 : innerPseudoStyle = mPresShell->StyleSet()->
2316 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::cellContent,
2317 0 : computedStyle);
2318 :
2319 : // Create a block frame that will format the cell's content
2320 : bool isBlock;
2321 : nsContainerFrame* cellInnerFrame;
2322 0 : if (isMathMLContent) {
2323 0 : cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2324 0 : isBlock = false;
2325 : } else {
2326 0 : cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
2327 0 : isBlock = true;
2328 : }
2329 :
2330 0 : InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame);
2331 :
2332 0 : nsFrameConstructorSaveState absoluteSaveState;
2333 : MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2334 : absoluteSaveState,
2335 0 : newFrame);
2336 :
2337 0 : nsFrameItems childItems;
2338 0 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
2339 : "nsIAnonymousContentCreator::CreateAnonymousContent "
2340 : "implementations for table frames are not currently expected "
2341 : "to output a list where the items have their own children");
2342 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2343 : // Need to push ourselves as a float containing block.
2344 : // XXXbz it might be nice to work on getting the parent
2345 : // FrameConstructionItem down into ProcessChildren and just making use of
2346 : // the push there, but that's a bit of work.
2347 0 : nsFrameConstructorSaveState floatSaveState;
2348 0 : if (!isBlock) { /* MathML case */
2349 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
2350 : } else {
2351 0 : aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
2352 : }
2353 :
2354 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
2355 0 : aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
2356 0 : childItems);
2357 : } else {
2358 : // Process the child content
2359 0 : ProcessChildren(aState, content, computedStyle, cellInnerFrame,
2360 0 : true, childItems, isBlock, aItem.mPendingBinding);
2361 : }
2362 :
2363 0 : cellInnerFrame->SetInitialChildList(kPrincipalList, childItems);
2364 0 : SetInitialSingleChild(newFrame, cellInnerFrame);
2365 0 : aFrameItems.AddChild(newFrame);
2366 0 : return newFrame;
2367 : }
2368 :
2369 : static inline bool
2370 0 : NeedFrameFor(const nsFrameConstructorState& aState,
2371 : nsIFrame* aParentFrame,
2372 : nsIContent* aChildContent)
2373 : {
2374 : // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2375 : // Remove it once that's fixed.
2376 0 : MOZ_ASSERT(!aChildContent->GetPrimaryFrame() ||
2377 : aState.mCreatingExtraFrames ||
2378 : aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
2379 : "Why did we get called?");
2380 :
2381 : // don't create a whitespace frame if aParentFrame doesn't want it.
2382 : // always create frames for children in generated content. counter(),
2383 : // quotes, and attr() content can easily change dynamically and we don't
2384 : // want to be reconstructing frames. It's not even clear that these
2385 : // should be considered ignorable just because they evaluate to
2386 : // whitespace.
2387 :
2388 : // We could handle all this in CreateNeededPseudoContainers or some other
2389 : // place after we build our frame construction items, but that would involve
2390 : // creating frame construction items for whitespace kids of
2391 : // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2392 : // all anyway, and involve an extra walk down the frame construction item
2393 : // list.
2394 0 : if ((aParentFrame &&
2395 0 : (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
2396 0 : aParentFrame->IsGeneratedContentFrame())) ||
2397 0 : !aChildContent->IsText()) {
2398 : return true;
2399 : }
2400 :
2401 0 : aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2402 0 : NS_REFRAME_IF_WHITESPACE);
2403 0 : return !aChildContent->TextIsOnlyWhitespace();
2404 : }
2405 :
2406 : /***********************************************
2407 : * END TABLE SECTION
2408 : ***********************************************/
2409 :
2410 : nsIFrame*
2411 0 : nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocElement,
2412 : nsILayoutHistoryState* aFrameState)
2413 : {
2414 0 : MOZ_ASSERT(GetRootFrame(),
2415 : "No viewport? Someone forgot to call ConstructRootFrame!");
2416 0 : MOZ_ASSERT(!mDocElementContainingBlock,
2417 : "Shouldn't have a doc element containing block here");
2418 :
2419 : // Resolve a new style for the viewport since it may be affected by a new root
2420 : // element style (e.g. a propagated 'direction').
2421 : //
2422 : // @see ComputedStyle::ApplyStyleFixups
2423 : {
2424 0 : RefPtr<ComputedStyle> sc = mPresShell->StyleSet()->
2425 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport, nullptr);
2426 0 : GetRootFrame()->SetComputedStyleWithoutNotification(sc);
2427 : }
2428 :
2429 : // Make sure to call UpdateViewportScrollbarStylesOverride before
2430 : // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2431 : // properly.
2432 0 : DebugOnly<nsIContent*> propagatedScrollFrom;
2433 0 : if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2434 0 : propagatedScrollFrom = presContext->UpdateViewportScrollbarStylesOverride();
2435 : }
2436 :
2437 0 : SetUpDocElementContainingBlock(aDocElement);
2438 :
2439 0 : NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
2440 : nsFrameConstructorState state(mPresShell,
2441 0 : GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2442 : nullptr,
2443 0 : nullptr, do_AddRef(aFrameState));
2444 :
2445 : // XXXbz why, exactly?
2446 0 : if (!mTempFrameTreeState)
2447 0 : state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
2448 :
2449 : // --------- CREATE AREA OR BOX FRAME -------
2450 0 : ServoStyleSet* set = mPresShell->StyleSet();
2451 : // Ensure the document element is styled at this point.
2452 0 : if (!aDocElement->HasServoData()) {
2453 : // NOTE(emilio): If the root has a non-null binding, we'll stop at the
2454 : // document element and won't process any children, loading the bindings
2455 : // (or failing to do so) will take care of the rest.
2456 0 : set->StyleNewSubtree(aDocElement);
2457 : }
2458 :
2459 : RefPtr<ComputedStyle> computedStyle =
2460 0 : mPresShell->StyleSet()->ResolveServoStyle(aDocElement);
2461 :
2462 0 : const nsStyleDisplay* display = computedStyle->StyleDisplay();
2463 :
2464 : // Ensure that our XBL bindings are installed.
2465 0 : if (display->mBinding) {
2466 : // Get the XBL loader.
2467 : nsresult rv;
2468 : bool resolveStyle;
2469 :
2470 0 : nsXBLService* xblService = nsXBLService::GetInstance();
2471 0 : if (!xblService) {
2472 0 : return nullptr;
2473 : }
2474 :
2475 0 : RefPtr<nsXBLBinding> binding;
2476 0 : rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
2477 0 : display->mBinding->mExtraData->GetPrincipal(),
2478 0 : getter_AddRefs(binding), &resolveStyle);
2479 0 : if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
2480 : // Binding will load asynchronously.
2481 0 : return nullptr;
2482 : }
2483 :
2484 0 : if (binding) {
2485 : // For backwards compat, keep firing the root's constructor
2486 : // after all of its kids' constructors. So tell the binding
2487 : // manager about it right now.
2488 0 : mDocument->BindingManager()->AddToAttachedQueue(binding);
2489 : }
2490 :
2491 0 : if (resolveStyle) {
2492 0 : computedStyle = mPresShell->StyleSet()->ResolveServoStyle(aDocElement);
2493 0 : display = computedStyle->StyleDisplay();
2494 : }
2495 : }
2496 :
2497 : // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2498 :
2499 0 : NS_ASSERTION(!display->IsScrollableOverflow() ||
2500 : state.mPresContext->IsPaginated() ||
2501 : propagatedScrollFrom == aDocElement,
2502 : "Scrollbars should have been propagated to the viewport");
2503 :
2504 0 : if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
2505 : return nullptr;
2506 : }
2507 :
2508 : // Make sure to start any background image loads for the root element now.
2509 0 : computedStyle->StartBackgroundImageLoads();
2510 :
2511 0 : nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
2512 0 : if (mHasRootAbsPosContainingBlock) {
2513 : // Push the absolute containing block now so we can absolutely position
2514 : // the root element
2515 0 : mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2516 : state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2517 0 : mDocElementContainingBlock,
2518 0 : docElementContainingBlockAbsoluteSaveState);
2519 : }
2520 :
2521 : // The rules from CSS 2.1, section 9.2.4, have already been applied
2522 : // by the style system, so we can assume that display->mDisplay is
2523 : // either NONE, BLOCK, or TABLE.
2524 :
2525 : // contentFrame is the primary frame for the root element. newFrame
2526 : // is the frame that will be the child of the initial containing block.
2527 : // These are usually the same frame but they can be different, in
2528 : // particular if the root frame is positioned, in which case
2529 : // contentFrame is the out-of-flow frame and newFrame is the
2530 : // placeholder.
2531 : nsContainerFrame* contentFrame;
2532 : nsIFrame* newFrame;
2533 0 : bool processChildren = false;
2534 :
2535 0 : nsFrameConstructorSaveState absoluteSaveState;
2536 :
2537 : // Check whether we need to build a XUL box or SVG root frame
2538 : #ifdef MOZ_XUL
2539 0 : if (aDocElement->IsXULElement()) {
2540 0 : contentFrame = NS_NewDocElementBoxFrame(mPresShell, computedStyle);
2541 0 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2542 0 : contentFrame);
2543 0 : newFrame = contentFrame;
2544 0 : processChildren = true;
2545 : }
2546 : else
2547 : #endif
2548 0 : if (aDocElement->IsSVGElement()) {
2549 0 : if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2550 0 : return nullptr;
2551 : }
2552 : // We're going to call the right function ourselves, so no need to give a
2553 : // function to this FrameConstructionData.
2554 :
2555 : // XXXbz on the other hand, if we converted this whole function to
2556 : // FrameConstructionData/Item, then we'd need the right function
2557 : // here... but would probably be able to get away with less code in this
2558 : // function in general.
2559 : // Use a null PendingBinding, since our binding is not in fact pending.
2560 : static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
2561 : already_AddRefed<ComputedStyle> extraRef =
2562 0 : RefPtr<ComputedStyle>(computedStyle).forget();
2563 0 : AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
2564 0 : nullptr, extraRef, true, nullptr);
2565 :
2566 0 : nsFrameItems frameItems;
2567 0 : contentFrame = static_cast<nsContainerFrame*>(
2568 0 : ConstructOuterSVG(state, item, mDocElementContainingBlock,
2569 : computedStyle->StyleDisplay(),
2570 : frameItems));
2571 0 : newFrame = frameItems.FirstChild();
2572 0 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2573 0 : } else if (display->mDisplay == StyleDisplay::Flex ||
2574 0 : display->mDisplay == StyleDisplay::WebkitBox ||
2575 1 : (StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
2576 0 : display->mDisplay == StyleDisplay::MozBox)) {
2577 0 : contentFrame = NS_NewFlexContainerFrame(mPresShell, computedStyle);
2578 0 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2579 0 : contentFrame);
2580 0 : newFrame = contentFrame;
2581 0 : processChildren = true;
2582 :
2583 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2584 0 : if (display->IsAbsPosContainingBlock(newFrame)) {
2585 : state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2586 0 : absoluteSaveState);
2587 : }
2588 :
2589 0 : } else if (display->mDisplay == StyleDisplay::Grid) {
2590 0 : contentFrame = NS_NewGridContainerFrame(mPresShell, computedStyle);
2591 0 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2592 0 : contentFrame);
2593 0 : newFrame = contentFrame;
2594 0 : processChildren = true;
2595 :
2596 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2597 0 : if (display->IsAbsPosContainingBlock(newFrame)) {
2598 : state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2599 0 : absoluteSaveState);
2600 : }
2601 0 : } else if (display->mDisplay == StyleDisplay::Table) {
2602 : // We're going to call the right function ourselves, so no need to give a
2603 : // function to this FrameConstructionData.
2604 :
2605 : // XXXbz on the other hand, if we converted this whole function to
2606 : // FrameConstructionData/Item, then we'd need the right function
2607 : // here... but would probably be able to get away with less code in this
2608 : // function in general.
2609 : // Use a null PendingBinding, since our binding is not in fact pending.
2610 : static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
2611 : already_AddRefed<ComputedStyle> extraRef =
2612 0 : RefPtr<ComputedStyle>(computedStyle).forget();
2613 0 : AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
2614 0 : nullptr, extraRef, true, nullptr);
2615 :
2616 0 : nsFrameItems frameItems;
2617 : // if the document is a table then just populate it.
2618 0 : contentFrame = static_cast<nsContainerFrame*>(
2619 0 : ConstructTable(state, item, mDocElementContainingBlock,
2620 : computedStyle->StyleDisplay(),
2621 : frameItems));
2622 0 : newFrame = frameItems.FirstChild();
2623 0 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2624 : } else {
2625 0 : MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||
2626 : display->mDisplay == StyleDisplay::FlowRoot,
2627 : "Unhandled display type for root element");
2628 0 : contentFrame = NS_NewBlockFormattingContext(mPresShell, computedStyle);
2629 0 : nsFrameItems frameItems;
2630 : // Use a null PendingBinding, since our binding is not in fact pending.
2631 0 : ConstructBlock(state, aDocElement,
2632 : state.GetGeometricParent(display,
2633 : mDocElementContainingBlock),
2634 : mDocElementContainingBlock, computedStyle,
2635 : &contentFrame, frameItems,
2636 0 : display->IsAbsPosContainingBlock(contentFrame) ? contentFrame : nullptr,
2637 0 : nullptr);
2638 0 : newFrame = frameItems.FirstChild();
2639 0 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2640 : }
2641 :
2642 0 : MOZ_ASSERT(newFrame);
2643 0 : MOZ_ASSERT(contentFrame);
2644 :
2645 0 : NS_ASSERTION(processChildren ? !mRootElementFrame :
2646 : mRootElementFrame == contentFrame,
2647 : "unexpected mRootElementFrame");
2648 0 : mRootElementFrame = contentFrame;
2649 :
2650 : // Figure out which frame has the main style for the document element,
2651 : // assigning it to mRootElementStyleFrame.
2652 : // Backgrounds should be propagated from that frame to the viewport.
2653 0 : contentFrame->GetParentComputedStyle(&mRootElementStyleFrame);
2654 0 : bool isChild = mRootElementStyleFrame &&
2655 0 : mRootElementStyleFrame->GetParent() == contentFrame;
2656 0 : if (!isChild) {
2657 0 : mRootElementStyleFrame = mRootElementFrame;
2658 : }
2659 :
2660 0 : if (processChildren) {
2661 : // Still need to process the child content
2662 0 : nsFrameItems childItems;
2663 :
2664 0 : NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) &&
2665 : !contentFrame->IsFrameOfType(nsIFrame::eSVG),
2666 : "Only XUL frames should reach here");
2667 : // Use a null PendingBinding, since our binding is not in fact pending.
2668 0 : ProcessChildren(state, aDocElement, computedStyle, contentFrame, true,
2669 0 : childItems, false, nullptr);
2670 :
2671 : // Set the initial child lists
2672 0 : contentFrame->SetInitialChildList(kPrincipalList, childItems);
2673 : }
2674 :
2675 : // set the primary frame
2676 0 : aDocElement->SetPrimaryFrame(contentFrame);
2677 :
2678 0 : SetInitialSingleChild(mDocElementContainingBlock, newFrame);
2679 :
2680 : // Create frames for anonymous contents if there is a canvas frame.
2681 0 : if (mDocElementContainingBlock->IsCanvasFrame()) {
2682 0 : ConstructAnonymousContentForCanvas(state, mDocElementContainingBlock,
2683 0 : aDocElement);
2684 : }
2685 :
2686 : return newFrame;
2687 : }
2688 :
2689 :
2690 : nsIFrame*
2691 0 : nsCSSFrameConstructor::ConstructRootFrame()
2692 : {
2693 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
2694 :
2695 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
2696 :
2697 : // --------- BUILD VIEWPORT -----------
2698 : RefPtr<ComputedStyle> viewportPseudoStyle =
2699 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport,
2700 0 : nullptr);
2701 : ViewportFrame* viewportFrame =
2702 0 : NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2703 :
2704 : // XXXbz do we _have_ to pass a null content pointer to that frame?
2705 : // Would it really kill us to pass in the root element or something?
2706 : // What would that break?
2707 0 : viewportFrame->Init(nullptr, nullptr, nullptr);
2708 :
2709 0 : viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2710 :
2711 : // Bind the viewport frame to the root view
2712 0 : nsView* rootView = mPresShell->GetViewManager()->GetRootView();
2713 0 : viewportFrame->SetView(rootView);
2714 :
2715 0 : viewportFrame->SyncFrameViewProperties(rootView);
2716 0 : nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
2717 0 : rootView, nullptr, nsContainerFrame::SET_ASYNC);
2718 :
2719 : // Make it an absolute container for fixed-pos elements
2720 0 : viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2721 0 : viewportFrame->MarkAsAbsoluteContainingBlock();
2722 :
2723 0 : return viewportFrame;
2724 : }
2725 :
2726 : void
2727 0 : nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
2728 : {
2729 0 : MOZ_ASSERT(aDocElement, "No element?");
2730 0 : MOZ_ASSERT(!aDocElement->GetParent(), "Not root content?");
2731 0 : MOZ_ASSERT(aDocElement->GetUncomposedDoc(), "Not in a document?");
2732 0 : MOZ_ASSERT(aDocElement->GetUncomposedDoc()->GetRootElement() ==
2733 : aDocElement, "Not the root of the document?");
2734 :
2735 : /*
2736 : how the root frame hierarchy should look
2737 :
2738 : Galley presentation, non-XUL, with scrolling:
2739 :
2740 : ViewportFrame [fixed-cb]
2741 : nsHTMLScrollFrame
2742 : nsCanvasFrame [abs-cb]
2743 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2744 : nsTableWrapperFrame, nsPlaceholderFrame)
2745 :
2746 : Galley presentation, XUL
2747 :
2748 : ViewportFrame [fixed-cb]
2749 : nsRootBoxFrame
2750 : root element frame (nsDocElementBoxFrame)
2751 :
2752 : Print presentation, non-XUL
2753 :
2754 : ViewportFrame
2755 : nsSimplePageSequenceFrame
2756 : nsPageFrame
2757 : nsPageContentFrame [fixed-cb]
2758 : nsCanvasFrame [abs-cb]
2759 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2760 : nsTableWrapperFrame, nsPlaceholderFrame)
2761 :
2762 : Print-preview presentation, non-XUL
2763 :
2764 : ViewportFrame
2765 : nsHTMLScrollFrame
2766 : nsSimplePageSequenceFrame
2767 : nsPageFrame
2768 : nsPageContentFrame [fixed-cb]
2769 : nsCanvasFrame [abs-cb]
2770 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2771 : nsTableWrapperFrame, nsPlaceholderFrame)
2772 :
2773 : Print/print preview of XUL is not supported.
2774 : [fixed-cb]: the default containing block for fixed-pos content
2775 : [abs-cb]: the default containing block for abs-pos content
2776 :
2777 : Meaning of nsCSSFrameConstructor fields:
2778 : mRootElementFrame is "root element frame". This is the primary frame for
2779 : the root element.
2780 : mDocElementContainingBlock is the parent of mRootElementFrame
2781 : (i.e. nsCanvasFrame or nsRootBoxFrame)
2782 :
2783 : mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
2784 : */
2785 :
2786 : // --------- CREATE ROOT FRAME -------
2787 :
2788 :
2789 : // Create the root frame. The document element's frame is a child of the
2790 : // root frame.
2791 : //
2792 : // The root frame serves two purposes:
2793 : // - reserves space for any margins needed for the document element's frame
2794 : // - renders the document element's background. This ensures the background covers
2795 : // the entire canvas as specified by the CSS2 spec
2796 :
2797 0 : nsPresContext* presContext = mPresShell->GetPresContext();
2798 0 : bool isPaginated = presContext->IsRootPaginatedDocument();
2799 0 : nsContainerFrame* viewportFrame = static_cast<nsContainerFrame*>(GetRootFrame());
2800 0 : ComputedStyle* viewportPseudoStyle = viewportFrame->Style();
2801 :
2802 0 : nsContainerFrame* rootFrame = nullptr;
2803 : nsAtom* rootPseudo;
2804 :
2805 0 : if (!isPaginated) {
2806 : #ifdef MOZ_XUL
2807 0 : if (aDocElement->IsXULElement())
2808 : {
2809 : // pass a temporary stylecontext, the correct one will be set later
2810 0 : rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
2811 : } else
2812 : #endif
2813 : {
2814 : // pass a temporary stylecontext, the correct one will be set later
2815 0 : rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2816 0 : mHasRootAbsPosContainingBlock = true;
2817 : }
2818 :
2819 0 : rootPseudo = nsCSSAnonBoxes::canvas;
2820 0 : mDocElementContainingBlock = rootFrame;
2821 : } else {
2822 : // Create a page sequence frame
2823 0 : rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
2824 0 : mPageSequenceFrame = rootFrame;
2825 0 : rootPseudo = nsCSSAnonBoxes::pageSequence;
2826 0 : rootFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2827 : }
2828 :
2829 :
2830 : // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2831 :
2832 : // If the device supports scrolling (e.g., in galley mode on the screen and
2833 : // for print-preview, but not when printing), then create a scroll frame that
2834 : // will act as the scrolling mechanism for the viewport.
2835 : // XXX Do we even need a viewport when printing to a printer?
2836 :
2837 0 : bool isHTML = aDocElement->IsHTMLElement();
2838 0 : bool isXUL = false;
2839 :
2840 0 : if (!isHTML) {
2841 0 : isXUL = aDocElement->IsXULElement();
2842 : }
2843 :
2844 : // Never create scrollbars for XUL documents
2845 0 : bool isScrollable = isPaginated ? presContext->HasPaginatedScrolling() : !isXUL;
2846 :
2847 : // We no longer need to do overflow propagation here. It's taken care of
2848 : // when we construct frames for the element whose overflow might be
2849 : // propagated
2850 0 : NS_ASSERTION(!isScrollable || !isXUL,
2851 : "XUL documents should never be scrollable - see above");
2852 :
2853 0 : nsContainerFrame* newFrame = rootFrame;
2854 0 : RefPtr<ComputedStyle> rootPseudoStyle;
2855 : // we must create a state because if the scrollbars are GFX it needs the
2856 : // state to build the scrollbar frames.
2857 0 : nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
2858 :
2859 : // Start off with the viewport as parent; we'll adjust it as needed.
2860 0 : nsContainerFrame* parentFrame = viewportFrame;
2861 :
2862 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
2863 : // If paginated, make sure we don't put scrollbars in
2864 0 : if (!isScrollable) {
2865 : rootPseudoStyle =
2866 0 : styleSet->ResolveInheritingAnonymousBoxStyle(rootPseudo,
2867 0 : viewportPseudoStyle);
2868 : } else {
2869 0 : if (rootPseudo == nsCSSAnonBoxes::canvas) {
2870 0 : rootPseudo = nsCSSAnonBoxes::scrolledCanvas;
2871 : } else {
2872 0 : NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence,
2873 : "Unknown root pseudo");
2874 0 : rootPseudo = nsCSSAnonBoxes::scrolledPageSequence;
2875 : }
2876 :
2877 : // Build the frame. We give it the content we are wrapping which is the
2878 : // document element, the root frame, the parent view port frame, and we
2879 : // should get back the new frame and the scrollable view if one was
2880 : // created.
2881 :
2882 : // resolve a context for the scrollframe
2883 : RefPtr<ComputedStyle> computedStyle =
2884 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll,
2885 0 : viewportPseudoStyle);
2886 :
2887 : // Note that the viewport scrollframe is always built with
2888 : // overflow:auto style. This forces the scroll frame to create
2889 : // anonymous content for both scrollbars. This is necessary even
2890 : // if the HTML or BODY elements are overriding the viewport
2891 : // scroll style to 'hidden' --- dynamic style changes might put
2892 : // scrollbars back on the viewport and we don't want to have to
2893 : // reframe the viewport to create the scrollbar content.
2894 0 : newFrame = nullptr;
2895 0 : rootPseudoStyle = BeginBuildingScrollFrame( state,
2896 : aDocElement,
2897 : computedStyle,
2898 : viewportFrame,
2899 : rootPseudo,
2900 : true,
2901 0 : newFrame);
2902 0 : parentFrame = newFrame;
2903 : }
2904 :
2905 0 : rootFrame->SetComputedStyleWithoutNotification(rootPseudoStyle);
2906 0 : rootFrame->Init(aDocElement, parentFrame, nullptr);
2907 :
2908 0 : if (isScrollable) {
2909 0 : FinishBuildingScrollFrame(parentFrame, rootFrame);
2910 : }
2911 :
2912 0 : if (isPaginated) {
2913 : // Create the first page
2914 : // Set the initial child lists
2915 : nsContainerFrame* canvasFrame;
2916 : nsContainerFrame* pageFrame =
2917 0 : ConstructPageFrame(mPresShell, rootFrame, nullptr, canvasFrame);
2918 0 : pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2919 0 : SetInitialSingleChild(rootFrame, pageFrame);
2920 :
2921 : // The eventual parent of the document element frame.
2922 : // XXX should this be set for every new page (in ConstructPageFrame)?
2923 0 : mDocElementContainingBlock = canvasFrame;
2924 0 : mHasRootAbsPosContainingBlock = true;
2925 : }
2926 :
2927 0 : if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
2928 0 : SetInitialSingleChild(viewportFrame, newFrame);
2929 : } else {
2930 0 : nsFrameList newFrameList(newFrame, newFrame);
2931 0 : viewportFrame->AppendFrames(kPrincipalList, newFrameList);
2932 : }
2933 0 : }
2934 :
2935 : void
2936 0 : nsCSSFrameConstructor::ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
2937 : nsIFrame* aFrame,
2938 : nsIContent* aDocElement)
2939 : {
2940 0 : NS_ASSERTION(aFrame->IsCanvasFrame(), "aFrame should be canvas frame!");
2941 :
2942 0 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
2943 0 : GetAnonymousContent(aDocElement, aFrame, anonymousItems);
2944 0 : if (anonymousItems.IsEmpty()) {
2945 0 : return;
2946 : }
2947 :
2948 0 : AutoFrameConstructionItemList itemsToConstruct(this);
2949 0 : nsContainerFrame* frameAsContainer = do_QueryFrame(aFrame);
2950 0 : AddFCItemsForAnonymousContent(aState, frameAsContainer, anonymousItems, itemsToConstruct);
2951 :
2952 0 : nsFrameItems frameItems;
2953 : ConstructFramesFromItemList(aState, itemsToConstruct, frameAsContainer,
2954 : /* aParentIsWrapperAnonBox = */ false,
2955 0 : frameItems);
2956 0 : frameAsContainer->AppendFrames(kPrincipalList, frameItems);
2957 : }
2958 :
2959 : nsContainerFrame*
2960 0 : nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
2961 : nsContainerFrame* aParentFrame,
2962 : nsIFrame* aPrevPageFrame,
2963 : nsContainerFrame*& aCanvasFrame)
2964 : {
2965 0 : ComputedStyle* parentComputedStyle = aParentFrame->Style();
2966 0 : ServoStyleSet* styleSet = aPresShell->StyleSet();
2967 :
2968 0 : RefPtr<ComputedStyle> pagePseudoStyle;
2969 : pagePseudoStyle =
2970 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::page,
2971 0 : parentComputedStyle);
2972 :
2973 0 : nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2974 :
2975 : // Initialize the page frame and force it to have a view. This makes printing of
2976 : // the pages easier and faster.
2977 0 : pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
2978 :
2979 0 : RefPtr<ComputedStyle> pageContentPseudoStyle;
2980 : pageContentPseudoStyle =
2981 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::pageContent,
2982 0 : pagePseudoStyle);
2983 :
2984 : nsContainerFrame* pageContentFrame =
2985 0 : NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
2986 :
2987 : // Initialize the page content frame and force it to have a view. Also make it the
2988 : // containing block for fixed elements which are repeated on every page.
2989 0 : nsIFrame* prevPageContentFrame = nullptr;
2990 0 : if (aPrevPageFrame) {
2991 0 : prevPageContentFrame = aPrevPageFrame->PrincipalChildList().FirstChild();
2992 0 : NS_ASSERTION(prevPageContentFrame, "missing page content frame");
2993 : }
2994 0 : pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
2995 0 : if (!prevPageContentFrame) {
2996 0 : pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2997 : }
2998 0 : SetInitialSingleChild(pageFrame, pageContentFrame);
2999 : // Make it an absolute container for fixed-pos elements
3000 0 : pageContentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3001 0 : pageContentFrame->MarkAsAbsoluteContainingBlock();
3002 :
3003 0 : RefPtr<ComputedStyle> canvasPseudoStyle;
3004 : canvasPseudoStyle =
3005 0 : styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::canvas,
3006 0 : pageContentPseudoStyle);
3007 :
3008 0 : aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
3009 :
3010 0 : nsIFrame* prevCanvasFrame = nullptr;
3011 0 : if (prevPageContentFrame) {
3012 0 : prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
3013 0 : NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
3014 : }
3015 0 : aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
3016 0 : SetInitialSingleChild(pageContentFrame, aCanvasFrame);
3017 0 : return pageFrame;
3018 : }
3019 :
3020 : /* static */
3021 : nsIFrame*
3022 0 : nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell,
3023 : nsIContent* aContent,
3024 : nsIFrame* aFrame,
3025 : nsContainerFrame* aParentFrame,
3026 : nsIFrame* aPrevInFlow,
3027 : nsFrameState aTypeBit)
3028 : {
3029 : RefPtr<ComputedStyle> placeholderStyle = aPresShell->StyleSet()->
3030 0 : ResolveStyleForPlaceholder();
3031 :
3032 : // The placeholder frame gets a pseudo style.
3033 : nsPlaceholderFrame* placeholderFrame =
3034 0 : (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
3035 0 : aTypeBit);
3036 :
3037 0 : placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
3038 :
3039 : // Associate the placeholder/out-of-flow with each other.
3040 0 : placeholderFrame->SetOutOfFlowFrame(aFrame);
3041 0 : aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
3042 :
3043 0 : aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
3044 :
3045 0 : return placeholderFrame;
3046 : }
3047 :
3048 : // Clears any lazy bits set in the range [aStartContent, aEndContent). If
3049 : // aEndContent is null, that means to clear bits in all siblings starting with
3050 : // aStartContent. aStartContent must not be null unless aEndContent is also
3051 : // null. We do this so that when new children are inserted under elements whose
3052 : // frame is a leaf the new children don't cause us to try to construct frames
3053 : // for the existing children again.
3054 : static inline void
3055 0 : ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent)
3056 : {
3057 0 : MOZ_ASSERT(aStartContent || !aEndContent,
3058 : "Must have start child if we have an end child");
3059 :
3060 0 : for (nsIContent* cur = aStartContent; cur != aEndContent;
3061 0 : cur = cur->GetNextSibling()) {
3062 0 : cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
3063 : }
3064 0 : }
3065 :
3066 : nsIFrame*
3067 0 : nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
3068 : FrameConstructionItem& aItem,
3069 : nsContainerFrame* aParentFrame,
3070 : const nsStyleDisplay* aStyleDisplay,
3071 : nsFrameItems& aFrameItems)
3072 : {
3073 0 : nsIContent* const content = aItem.mContent;
3074 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
3075 :
3076 : // Construct a frame-based listbox or combobox
3077 0 : dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromNode(content);
3078 0 : MOZ_ASSERT(sel);
3079 0 : if (sel->IsCombobox()) {
3080 : // Construct a frame-based combo box.
3081 : // The frame-based combo box is built out of three parts. A display area, a button and
3082 : // a dropdown list. The display area and button are created through anonymous content.
3083 : // The drop-down list's frame is created explicitly. The combobox frame shares its content
3084 : // with the drop-down list.
3085 0 : nsFrameState flags = NS_BLOCK_FLOAT_MGR;
3086 : nsComboboxControlFrame* comboboxFrame =
3087 0 : NS_NewComboboxControlFrame(mPresShell, computedStyle, flags);
3088 :
3089 : // Save the history state so we don't restore during construction
3090 : // since the complete tree is required before we restore.
3091 0 : nsILayoutHistoryState *historyState = aState.mFrameState;
3092 0 : aState.mFrameState = nullptr;
3093 : // Initialize the combobox frame
3094 0 : InitAndRestoreFrame(aState, content,
3095 : aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3096 0 : comboboxFrame);
3097 :
3098 0 : comboboxFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3099 :
3100 0 : aState.AddChild(comboboxFrame, aFrameItems, content, aParentFrame);
3101 :
3102 : // Resolve pseudo element style for the dropdown list
3103 0 : RefPtr<ComputedStyle> listStyle;
3104 0 : listStyle = mPresShell->StyleSet()->
3105 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList,
3106 0 : computedStyle);
3107 :
3108 : // Create a listbox
3109 0 : nsContainerFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
3110 :
3111 : // Notify the listbox that it is being used as a dropdown list.
3112 0 : nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
3113 0 : if (listControlFrame) {
3114 0 : listControlFrame->SetComboboxFrame(comboboxFrame);
3115 : }
3116 : // Notify combobox that it should use the listbox as it's popup
3117 0 : comboboxFrame->SetDropDown(listFrame);
3118 :
3119 0 : if (!nsLayoutUtils::IsContentSelectEnabled()) {
3120 : // TODO(kuoe0) Remove this assertion when content-select is shipped.
3121 0 : NS_ASSERTION(!listFrame->IsAbsPosContainingBlock(),
3122 : "Ended up with positioned dropdown list somehow.");
3123 : }
3124 0 : NS_ASSERTION(!listFrame->IsFloating(),
3125 : "Ended up with floating dropdown list somehow.");
3126 :
3127 : // child frames of combobox frame
3128 0 : nsFrameItems childItems;
3129 :
3130 : // Initialize the scroll frame positioned. Note that it is NOT
3131 : // initialized as absolutely positioned.
3132 : nsContainerFrame* scrolledFrame =
3133 0 : NS_NewSelectsAreaFrame(mPresShell, computedStyle, flags);
3134 :
3135 0 : InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3136 : comboboxFrame, listStyle, true,
3137 0 : aItem.mPendingBinding, childItems);
3138 :
3139 0 : if (!nsLayoutUtils::IsContentSelectEnabled()) {
3140 : // TODO(kuoe0) Remove this assertion when content-select is shipped.
3141 0 : NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nullptr");
3142 : }
3143 :
3144 : // Create display and button frames from the combobox's anonymous content.
3145 : // The anonymous content is appended to existing anonymous content for this
3146 : // element (the scrollbars).
3147 : //
3148 : // nsComboboxControlFrame needs special frame creation behavior for its first
3149 : // piece of anonymous content, which means that we can't take the normal
3150 : // ProcessChildren path.
3151 0 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
3152 0 : DebugOnly<nsresult> rv = GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
3153 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
3154 0 : MOZ_ASSERT(newAnonymousItems.Length() == 2);
3155 :
3156 : // Manually create a frame for the special NAC.
3157 0 : MOZ_ASSERT(newAnonymousItems[0].mContent == comboboxFrame->GetDisplayNode());
3158 0 : newAnonymousItems.RemoveElementAt(0);
3159 0 : nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
3160 0 : MOZ_ASSERT(customFrame);
3161 0 : customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
3162 0 : childItems.AddChild(customFrame);
3163 :
3164 : // The other piece of NAC can take the normal path.
3165 0 : AutoFrameConstructionItemList fcItems(this);
3166 : AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
3167 0 : fcItems);
3168 : ConstructFramesFromItemList(aState, fcItems, comboboxFrame,
3169 : /* aParentIsWrapperAnonBox = */ false,
3170 0 : childItems);
3171 :
3172 0 : comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
3173 :
3174 0 : if (!nsLayoutUtils::IsContentSelectEnabled()) {
3175 : // Initialize the additional popup child list which contains the
3176 : // dropdown list frame.
3177 0 : nsFrameItems popupItems;
3178 0 : popupItems.AddChild(listFrame);
3179 : comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList,
3180 0 : popupItems);
3181 : }
3182 :
3183 0 : aState.mFrameState = historyState;
3184 0 : if (aState.mFrameState) {
3185 : // Restore frame state for the entire subtree of |comboboxFrame|.
3186 0 : RestoreFrameState(comboboxFrame, aState.mFrameState);
3187 : }
3188 : return comboboxFrame;
3189 : }
3190 :
3191 : // Listbox, not combobox
3192 : nsContainerFrame* listFrame =
3193 0 : NS_NewListControlFrame(mPresShell, computedStyle);
3194 :
3195 0 : nsContainerFrame* scrolledFrame = NS_NewSelectsAreaFrame(
3196 0 : mPresShell, computedStyle, NS_BLOCK_FLOAT_MGR);
3197 :
3198 : // ******* this code stolen from Initialze ScrollFrame ********
3199 : // please adjust this code to use BuildScrollFrame.
3200 :
3201 0 : InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3202 : aParentFrame, computedStyle, false,
3203 0 : aItem.mPendingBinding, aFrameItems);
3204 :
3205 0 : return listFrame;
3206 : }
3207 :
3208 : /**
3209 : * Used to be InitializeScrollFrame but now it's only used for the select tag
3210 : * But the select tag should really be fixed to use GFX scrollbars that can
3211 : * be create with BuildScrollFrame.
3212 : */
3213 : void
3214 0 : nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
3215 : nsContainerFrame* scrollFrame,
3216 : nsContainerFrame* scrolledFrame,
3217 : nsIContent* aContent,
3218 : nsContainerFrame* aParentFrame,
3219 : ComputedStyle* aComputedStyle,
3220 : bool aBuildCombobox,
3221 : PendingBinding* aPendingBinding,
3222 : nsFrameItems& aFrameItems)
3223 : {
3224 : // Initialize it
3225 : nsContainerFrame* geometricParent =
3226 0 : aState.GetGeometricParent(aComputedStyle->StyleDisplay(), aParentFrame);
3227 :
3228 : // We don't call InitAndRestoreFrame for scrollFrame because we can only
3229 : // restore the frame state after its parts have been created (in particular,
3230 : // the scrollable view). So we have to split Init and Restore.
3231 :
3232 0 : scrollFrame->Init(aContent, geometricParent, nullptr);
3233 :
3234 0 : if (!aBuildCombobox || nsLayoutUtils::IsContentSelectEnabled()) {
3235 0 : aState.AddChild(scrollFrame, aFrameItems, aContent, aParentFrame);
3236 : }
3237 :
3238 : BuildScrollFrame(aState, aContent, aComputedStyle, scrolledFrame,
3239 0 : geometricParent, scrollFrame);
3240 :
3241 0 : if (aState.mFrameState) {
3242 : // Restore frame state for the scroll frame
3243 0 : RestoreFrameStateFor(scrollFrame, aState.mFrameState);
3244 : }
3245 :
3246 : // Process children
3247 0 : nsFrameItems childItems;
3248 :
3249 : ProcessChildren(aState, aContent, aComputedStyle, scrolledFrame, false,
3250 0 : childItems, false, aPendingBinding);
3251 :
3252 : // Set the scrolled frame's initial child lists
3253 0 : scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
3254 0 : }
3255 :
3256 : nsIFrame*
3257 0 : nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
3258 : FrameConstructionItem& aItem,
3259 : nsContainerFrame* aParentFrame,
3260 : const nsStyleDisplay* aStyleDisplay,
3261 : nsFrameItems& aFrameItems)
3262 : {
3263 0 : nsIContent* const content = aItem.mContent;
3264 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
3265 :
3266 : nsContainerFrame* fieldsetFrame =
3267 0 : NS_NewFieldSetFrame(mPresShell, computedStyle);
3268 :
3269 : // Initialize it
3270 0 : InitAndRestoreFrame(aState, content,
3271 : aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3272 0 : fieldsetFrame);
3273 :
3274 0 : fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3275 :
3276 : // Resolve style and initialize the frame
3277 0 : RefPtr<ComputedStyle> fieldsetContentStyle;
3278 0 : fieldsetContentStyle = mPresShell->StyleSet()->
3279 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent,
3280 0 : computedStyle);
3281 :
3282 0 : const nsStyleDisplay* fieldsetContentDisplay = fieldsetContentStyle->StyleDisplay();
3283 0 : bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3284 0 : nsContainerFrame* scrollFrame = nullptr;
3285 0 : if (isScrollable) {
3286 : fieldsetContentStyle =
3287 0 : BeginBuildingScrollFrame(aState, content, fieldsetContentStyle,
3288 : fieldsetFrame, nsCSSAnonBoxes::scrolledContent,
3289 0 : false, scrollFrame);
3290 : }
3291 :
3292 0 : nsContainerFrame* absPosContainer = nullptr;
3293 0 : if (fieldsetFrame->IsAbsPosContainingBlock()) {
3294 0 : absPosContainer = fieldsetFrame;
3295 : }
3296 :
3297 : // Create the inner ::-moz-fieldset-content frame.
3298 : nsContainerFrame* contentFrameTop;
3299 : nsContainerFrame* contentFrame;
3300 0 : auto parent = scrollFrame ? scrollFrame : fieldsetFrame;
3301 0 : switch (fieldsetContentDisplay->mDisplay) {
3302 : case StyleDisplay::Flex:
3303 0 : contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3304 0 : InitAndRestoreFrame(aState, content, parent, contentFrame);
3305 0 : contentFrameTop = contentFrame;
3306 0 : break;
3307 : case StyleDisplay::Grid:
3308 0 : contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3309 0 : InitAndRestoreFrame(aState, content, parent, contentFrame);
3310 0 : contentFrameTop = contentFrame;
3311 0 : break;
3312 : default: {
3313 0 : MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
3314 : "bug in nsRuleNode::ComputeDisplayData?");
3315 :
3316 0 : nsContainerFrame* columnSetFrame = nullptr;
3317 0 : RefPtr<ComputedStyle> innerSC = fieldsetContentStyle;
3318 0 : const nsStyleColumn* columns = fieldsetContentStyle->StyleColumn();
3319 0 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
3320 0 : columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
3321 : columnSetFrame =
3322 0 : NS_NewColumnSetFrame(mPresShell, fieldsetContentStyle,
3323 0 : nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
3324 0 : InitAndRestoreFrame(aState, content, parent, columnSetFrame);
3325 0 : innerSC = mPresShell->StyleSet()->
3326 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
3327 0 : fieldsetContentStyle);
3328 0 : if (absPosContainer) {
3329 0 : absPosContainer = columnSetFrame;
3330 : }
3331 : }
3332 0 : contentFrame = NS_NewBlockFormattingContext(mPresShell, innerSC);
3333 0 : if (columnSetFrame) {
3334 0 : InitAndRestoreFrame(aState, content, columnSetFrame, contentFrame);
3335 0 : SetInitialSingleChild(columnSetFrame, contentFrame);
3336 0 : contentFrameTop = columnSetFrame;
3337 : } else {
3338 0 : InitAndRestoreFrame(aState, content, parent, contentFrame);
3339 0 : contentFrameTop = contentFrame;
3340 : }
3341 : break;
3342 : }
3343 : }
3344 :
3345 0 : aState.AddChild(fieldsetFrame, aFrameItems, content, aParentFrame);
3346 :
3347 : // Process children
3348 0 : nsFrameConstructorSaveState absoluteSaveState;
3349 0 : nsFrameItems childItems;
3350 :
3351 0 : contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3352 0 : if (absPosContainer) {
3353 0 : aState.PushAbsoluteContainingBlock(contentFrame, absPosContainer, absoluteSaveState);
3354 : }
3355 :
3356 0 : ProcessChildren(aState, content, computedStyle, contentFrame, true,
3357 0 : childItems, true, aItem.mPendingBinding);
3358 :
3359 0 : nsFrameItems fieldsetKids;
3360 0 : fieldsetKids.AddChild(scrollFrame ? scrollFrame : contentFrameTop);
3361 :
3362 0 : for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
3363 0 : nsIFrame* child = e.get();
3364 0 : nsContainerFrame* cif = child->GetContentInsertionFrame();
3365 0 : if (cif && cif->IsLegendFrame()) {
3366 : // We want the legend to be the first frame in the fieldset child list.
3367 : // That way the EventStateManager will do the right thing when tabbing
3368 : // from a selection point within the legend (bug 236071), which is
3369 : // used for implementing legend access keys (bug 81481).
3370 : // GetAdjustedParentFrame() below depends on this frame order.
3371 0 : childItems.RemoveFrame(child);
3372 : // Make sure to reparent the legend so it has the fieldset as the parent.
3373 0 : fieldsetKids.InsertFrame(fieldsetFrame, nullptr, child);
3374 0 : if (scrollFrame) {
3375 : StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(
3376 0 : child, contentFrame);
3377 : }
3378 : break;
3379 : }
3380 : }
3381 :
3382 0 : if (isScrollable) {
3383 0 : FinishBuildingScrollFrame(scrollFrame, contentFrameTop);
3384 : }
3385 :
3386 : // Set the inner frame's initial child lists
3387 0 : contentFrame->SetInitialChildList(kPrincipalList, childItems);
3388 :
3389 : // Set the outer frame's initial child list
3390 0 : fieldsetFrame->SetInitialChildList(kPrincipalList, fieldsetKids);
3391 :
3392 : // Our new frame returned is the outer frame, which is the fieldset frame.
3393 0 : return fieldsetFrame;
3394 : }
3395 :
3396 : nsIFrame*
3397 0 : nsCSSFrameConstructor::ConstructDetailsFrame(nsFrameConstructorState& aState,
3398 : FrameConstructionItem& aItem,
3399 : nsContainerFrame* aParentFrame,
3400 : const nsStyleDisplay* aStyleDisplay,
3401 : nsFrameItems& aFrameItems)
3402 : {
3403 0 : if (!aStyleDisplay->IsScrollableOverflow()) {
3404 : return ConstructNonScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3405 : aStyleDisplay, aFrameItems,
3406 0 : NS_NewDetailsFrame);
3407 : }
3408 :
3409 : // Build a scroll frame to wrap details frame if necessary.
3410 : return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3411 : aStyleDisplay, aFrameItems,
3412 0 : NS_NewDetailsFrame);
3413 : }
3414 :
3415 : static nsIFrame*
3416 0 : FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame)
3417 : {
3418 0 : for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3419 0 : NS_ASSERTION(f->IsGeneratedContentFrame(),
3420 : "should not have exited generated content");
3421 0 : nsAtom* pseudo = f->Style()->GetPseudo();
3422 0 : if (pseudo == nsCSSPseudoElements::before ||
3423 0 : pseudo == nsCSSPseudoElements::after)
3424 : return f;
3425 : }
3426 : return nullptr;
3427 : }
3428 :
3429 : #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3430 : #define FULL_CTOR_FCDATA(_flags, _func) \
3431 : { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nullptr }, _func, nullptr }
3432 :
3433 : /* static */
3434 : const nsCSSFrameConstructor::FrameConstructionData*
3435 0 : nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame,
3436 : nsIContent* aTextContent)
3437 : {
3438 0 : MOZ_ASSERT(aTextContent, "How?");
3439 0 : if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3440 : nsIFrame* ancestorFrame =
3441 0 : nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
3442 0 : if (!ancestorFrame || !nsSVGUtils::IsInSVGTextSubtree(ancestorFrame)) {
3443 : return nullptr;
3444 : }
3445 :
3446 : // Don't render stuff in display: contents / Shadow DOM subtrees, because
3447 : // TextCorrespondenceRecorder in the SVG text code doesn't really know how
3448 : // to deal with it. This kinda sucks. :(
3449 0 : if (aParentFrame->GetContent() != aTextContent->GetParent()) {
3450 : return nullptr;
3451 : }
3452 :
3453 : static const FrameConstructionData sSVGTextData =
3454 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT,
3455 : NS_NewTextFrame);
3456 0 : return &sSVGTextData;
3457 : }
3458 :
3459 : static const FrameConstructionData sTextData =
3460 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
3461 : return &sTextData;
3462 : }
3463 :
3464 : void
3465 0 : nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData,
3466 : nsFrameConstructorState& aState,
3467 : nsIContent* aContent,
3468 : nsContainerFrame* aParentFrame,
3469 : ComputedStyle* aComputedStyle,
3470 : nsFrameItems& aFrameItems)
3471 : {
3472 0 : MOZ_ASSERT(aData, "Must have frame construction data");
3473 :
3474 0 : nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aComputedStyle);
3475 :
3476 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3477 :
3478 : // We never need to create a view for a text frame.
3479 :
3480 0 : if (newFrame->IsGeneratedContentFrame()) {
3481 0 : nsAutoPtr<nsGenConInitializer> initializer;
3482 : initializer =
3483 : static_cast<nsGenConInitializer*>(
3484 0 : aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
3485 0 : if (initializer) {
3486 0 : if (initializer->mNode->InitTextFrame(initializer->mList,
3487 0 : FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
3488 0 : (this->*(initializer->mDirtyAll))();
3489 : }
3490 0 : initializer->mNode.forget();
3491 : }
3492 : }
3493 :
3494 : // Add the newly constructed frame to the flow
3495 0 : aFrameItems.AddChild(newFrame);
3496 :
3497 0 : if (!aState.mCreatingExtraFrames)
3498 0 : aContent->SetPrimaryFrame(newFrame);
3499 0 : }
3500 :
3501 : /* static */
3502 : const nsCSSFrameConstructor::FrameConstructionData*
3503 0 : nsCSSFrameConstructor::FindDataByInt(int32_t aInt,
3504 : Element* aElement,
3505 : ComputedStyle* aComputedStyle,
3506 : const FrameConstructionDataByInt* aDataPtr,
3507 : uint32_t aDataLength)
3508 : {
3509 0 : for (const FrameConstructionDataByInt *curData = aDataPtr,
3510 0 : *endData = aDataPtr + aDataLength;
3511 0 : curData != endData;
3512 : ++curData) {
3513 0 : if (curData->mInt == aInt) {
3514 0 : const FrameConstructionData* data = &curData->mData;
3515 0 : if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3516 0 : return data->mFunc.mDataGetter(aElement, aComputedStyle);
3517 : }
3518 :
3519 : return data;
3520 : }
3521 : }
3522 :
3523 : return nullptr;
3524 : }
3525 :
3526 : /* static */
3527 : const nsCSSFrameConstructor::FrameConstructionData*
3528 0 : nsCSSFrameConstructor::FindDataByTag(nsAtom* aTag,
3529 : Element* aElement,
3530 : ComputedStyle* aComputedStyle,
3531 : const FrameConstructionDataByTag* aDataPtr,
3532 : uint32_t aDataLength)
3533 : {
3534 0 : for (const FrameConstructionDataByTag *curData = aDataPtr,
3535 0 : *endData = aDataPtr + aDataLength;
3536 0 : curData != endData;
3537 : ++curData) {
3538 0 : if (*curData->mTag == aTag) {
3539 0 : const FrameConstructionData* data = &curData->mData;
3540 0 : if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3541 0 : return data->mFunc.mDataGetter(aElement, aComputedStyle);
3542 : }
3543 :
3544 : return data;
3545 : }
3546 : }
3547 :
3548 : return nullptr;
3549 : }
3550 :
3551 : #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nullptr)
3552 : #define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
3553 : #define SIMPLE_INT_CHAIN(_int, _func) \
3554 : { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3555 : #define COMPLEX_INT_CREATE(_int, _func) \
3556 : { _int, FULL_CTOR_FCDATA(0, _func) }
3557 :
3558 : #define SIMPLE_TAG_CREATE(_tag, _func) \
3559 : { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3560 : #define SIMPLE_TAG_CHAIN(_tag, _func) \
3561 : { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3562 : #define COMPLEX_TAG_CREATE(_tag, _func) \
3563 : { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3564 :
3565 : static bool
3566 0 : IsFrameForFieldSet(nsIFrame* aFrame)
3567 : {
3568 0 : nsAtom* pseudo = aFrame->Style()->GetPseudo();
3569 0 : if (pseudo == nsCSSAnonBoxes::fieldsetContent ||
3570 0 : pseudo == nsCSSAnonBoxes::scrolledContent ||
3571 0 : pseudo == nsCSSAnonBoxes::columnContent) {
3572 0 : return IsFrameForFieldSet(aFrame->GetParent());
3573 : }
3574 0 : return aFrame->IsFieldSetFrame();
3575 : }
3576 :
3577 : /* static */
3578 : const nsCSSFrameConstructor::FrameConstructionData*
3579 0 : nsCSSFrameConstructor::FindHTMLData(Element* aElement,
3580 : nsAtom* aTag,
3581 : int32_t aNameSpaceID,
3582 : nsIFrame* aParentFrame,
3583 : ComputedStyle* aComputedStyle)
3584 : {
3585 : // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
3586 : // a valid HTML namespace. This check must match the one in
3587 : // ShouldHaveFirstLineStyle.
3588 0 : if (aNameSpaceID != kNameSpaceID_XHTML) {
3589 : return nullptr;
3590 : }
3591 :
3592 0 : NS_ASSERTION(!aParentFrame ||
3593 : aParentFrame->Style()->GetPseudo() !=
3594 : nsCSSAnonBoxes::fieldsetContent ||
3595 : aParentFrame->GetParent()->IsFieldSetFrame(),
3596 : "Unexpected parent for fieldset content anon box");
3597 0 : if (aTag == nsGkAtoms::legend &&
3598 0 : (!aParentFrame || !IsFrameForFieldSet(aParentFrame) ||
3599 0 : aComputedStyle->StyleDisplay()->IsFloatingStyle() ||
3600 0 : aComputedStyle->StyleDisplay()->IsAbsolutelyPositionedStyle())) {
3601 : // <legend> is only special inside fieldset, we only check the frame tree
3602 : // parent because the content tree parent may not be a <fieldset> due to
3603 : // display:contents, Shadow DOM, or XBL. For floated or absolutely
3604 : // positioned legends we want to construct by display type and
3605 : // not do special legend stuff.
3606 : return nullptr;
3607 : }
3608 :
3609 : static const FrameConstructionDataByTag sHTMLData[] = {
3610 : SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
3611 : SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
3612 : nsCSSFrameConstructor::FindImgData),
3613 : { &nsGkAtoms::br,
3614 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
3615 : NS_NewBRFrame) },
3616 : SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
3617 : SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
3618 : SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
3619 : COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
3620 : SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
3621 : SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
3622 : COMPLEX_TAG_CREATE(fieldset,
3623 : &nsCSSFrameConstructor::ConstructFieldSetFrame),
3624 : { &nsGkAtoms::legend,
3625 : FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
3626 : NS_NewLegendFrame) },
3627 : SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
3628 : SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
3629 : { &nsGkAtoms::button,
3630 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_ALLOW_BLOCK_STYLES |
3631 : FCDATA_ALLOW_GRID_FLEX_COLUMNSET,
3632 : NS_NewHTMLButtonControlFrame,
3633 : nsCSSAnonBoxes::buttonContent) },
3634 : SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
3635 : SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
3636 : SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
3637 : SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
3638 : SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
3639 : COMPLEX_TAG_CREATE(details, &nsCSSFrameConstructor::ConstructDetailsFrame)
3640 : };
3641 :
3642 : return FindDataByTag(aTag, aElement, aComputedStyle, sHTMLData,
3643 0 : ArrayLength(sHTMLData));
3644 : }
3645 :
3646 : /* static */
3647 : const nsCSSFrameConstructor::FrameConstructionData*
3648 0 : nsCSSFrameConstructor::FindImgData(Element* aElement,
3649 : ComputedStyle* aComputedStyle)
3650 : {
3651 0 : if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aComputedStyle)) {
3652 : return nullptr;
3653 : }
3654 :
3655 : static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
3656 0 : return &sImgData;
3657 : }
3658 :
3659 : /* static */
3660 : const nsCSSFrameConstructor::FrameConstructionData*
3661 0 : nsCSSFrameConstructor::FindImgControlData(Element* aElement,
3662 : ComputedStyle* aComputedStyle)
3663 : {
3664 0 : if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aComputedStyle)) {
3665 : return nullptr;
3666 : }
3667 :
3668 : static const FrameConstructionData sImgControlData =
3669 : SIMPLE_FCDATA(NS_NewImageControlFrame);
3670 0 : return &sImgControlData;
3671 : }
3672 :
3673 : /* static */
3674 : const nsCSSFrameConstructor::FrameConstructionData*
3675 0 : nsCSSFrameConstructor::FindInputData(Element* aElement,
3676 : ComputedStyle* aComputedStyle)
3677 : {
3678 : static const FrameConstructionDataByInt sInputData[] = {
3679 : SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewCheckboxRadioFrame),
3680 : SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewCheckboxRadioFrame),
3681 : SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
3682 : SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
3683 : nsCSSFrameConstructor::FindImgControlData),
3684 : SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame),
3685 : SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame),
3686 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
3687 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame),
3688 : SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame),
3689 : SIMPLE_INT_CREATE(NS_FORM_INPUT_RANGE, NS_NewRangeFrame),
3690 : SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
3691 : { NS_FORM_INPUT_COLOR,
3692 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewColorControlFrame,
3693 : nsCSSAnonBoxes::buttonContent) },
3694 : // TODO: this is temporary until a frame is written: bug 635240.
3695 : SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
3696 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewDateTimeControlFrame),
3697 : SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewDateTimeControlFrame),
3698 : // TODO: this is temporary until a frame is written: bug 888320
3699 : SIMPLE_INT_CREATE(NS_FORM_INPUT_MONTH, NS_NewTextControlFrame),
3700 : // TODO: this is temporary until a frame is written: bug 888320
3701 : SIMPLE_INT_CREATE(NS_FORM_INPUT_WEEK, NS_NewTextControlFrame),
3702 : // TODO: this is temporary until a frame is written: bug 888320
3703 : SIMPLE_INT_CREATE(NS_FORM_INPUT_DATETIME_LOCAL, NS_NewTextControlFrame),
3704 : { NS_FORM_INPUT_SUBMIT,
3705 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3706 : nsCSSAnonBoxes::buttonContent) },
3707 : { NS_FORM_INPUT_RESET,
3708 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3709 : nsCSSAnonBoxes::buttonContent) },
3710 : { NS_FORM_INPUT_BUTTON,
3711 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3712 : nsCSSAnonBoxes::buttonContent) }
3713 : // Keeping hidden inputs out of here on purpose for so they get frames by
3714 : // display (in practice, none).
3715 : };
3716 :
3717 0 : nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
3718 0 : NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
3719 :
3720 0 : auto controlType = control->ControlType();
3721 :
3722 : // radio and checkbox inputs with appearance:none should be constructed
3723 : // by display type. (Note that we're not checking that appearance is
3724 : // not (respectively) NS_THEME_RADIO and NS_THEME_CHECKBOX.)
3725 0 : if ((controlType == NS_FORM_INPUT_CHECKBOX ||
3726 0 : controlType == NS_FORM_INPUT_RADIO) &&
3727 0 : aComputedStyle->StyleDisplay()->mAppearance == NS_THEME_NONE) {
3728 : return nullptr;
3729 : }
3730 :
3731 0 : return FindDataByInt(controlType, aElement, aComputedStyle,
3732 0 : sInputData, ArrayLength(sInputData));
3733 : }
3734 :
3735 : /* static */
3736 : const nsCSSFrameConstructor::FrameConstructionData*
3737 0 : nsCSSFrameConstructor::FindObjectData(Element* aElement,
3738 : ComputedStyle* aComputedStyle)
3739 : {
3740 : // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3741 : // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3742 : // we want to treat those cases as TYPE_NULL
3743 : uint32_t type;
3744 0 : if (aElement->State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
3745 : NS_EVENT_STATE_USERDISABLED |
3746 : NS_EVENT_STATE_SUPPRESSED)) {
3747 0 : type = nsIObjectLoadingContent::TYPE_NULL;
3748 : } else {
3749 0 : nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement));
3750 0 : NS_ASSERTION(objContent,
3751 : "embed and object must implement "
3752 : "nsIObjectLoadingContent!");
3753 :
3754 0 : objContent->GetDisplayedType(&type);
3755 : }
3756 :
3757 : static const FrameConstructionDataByInt sObjectData[] = {
3758 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
3759 : NS_NewEmptyFrame),
3760 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
3761 : NS_NewObjectFrame),
3762 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
3763 : NS_NewImageFrame),
3764 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
3765 : NS_NewSubDocumentFrame),
3766 : // Fake plugin handlers load as documents
3767 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_FAKE_PLUGIN,
3768 : NS_NewSubDocumentFrame)
3769 : // Nothing for TYPE_NULL so we'll construct frames by display there
3770 : };
3771 :
3772 0 : return FindDataByInt((int32_t)type, aElement, aComputedStyle,
3773 0 : sObjectData, ArrayLength(sObjectData));
3774 : }
3775 :
3776 : /* static */
3777 : const nsCSSFrameConstructor::FrameConstructionData*
3778 0 : nsCSSFrameConstructor::FindCanvasData(Element* aElement,
3779 : ComputedStyle* aComputedStyle)
3780 : {
3781 : // We want to check whether script is enabled on the document that
3782 : // could be painting to the canvas. That's the owner document of
3783 : // the canvas, except when the owner document is a static document,
3784 : // in which case it's the original document it was cloned from.
3785 0 : nsIDocument* doc = aElement->OwnerDoc();
3786 0 : if (doc->IsStaticDocument()) {
3787 0 : doc = doc->GetOriginalDocument();
3788 : }
3789 0 : if (!doc->IsScriptEnabled()) {
3790 : return nullptr;
3791 : }
3792 :
3793 : static const FrameConstructionData sCanvasData =
3794 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
3795 : nsCSSAnonBoxes::htmlCanvasContent);
3796 0 : return &sCanvasData;
3797 : }
3798 :
3799 : void
3800 0 : nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
3801 : nsFrameConstructorState& aState,
3802 : nsContainerFrame* aParentFrame,
3803 : nsFrameItems& aFrameItems)
3804 : {
3805 0 : const FrameConstructionData* data = aItem.mFCData;
3806 0 : NS_ASSERTION(data, "Must have frame construction data");
3807 :
3808 0 : uint32_t bits = data->mBits;
3809 :
3810 0 : NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
3811 : "Should have dealt with this inside the data finder");
3812 :
3813 : // Some sets of bits are not compatible with each other
3814 : #define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3815 : NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
3816 : "Only one of these bits should be set")
3817 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
3818 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
3819 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
3820 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
3821 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
3822 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3823 : FCDATA_DISALLOW_GENERATED_CONTENT);
3824 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
3825 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3826 : FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3827 0 : CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
3828 : FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3829 : #undef CHECK_ONLY_ONE_BIT
3830 0 : NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
3831 : ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
3832 : data->mFullConstructor ==
3833 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
3834 : "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
3835 0 : MOZ_ASSERT(!(bits & FCDATA_IS_WRAPPER_ANON_BOX) ||
3836 : (bits & FCDATA_USE_CHILD_ITEMS),
3837 : "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS");
3838 :
3839 : // Don't create a subdocument frame for iframes if we're creating extra frames
3840 0 : if (aState.mCreatingExtraFrames &&
3841 0 : aItem.mContent->IsHTMLElement(nsGkAtoms::iframe))
3842 : {
3843 : return;
3844 : }
3845 :
3846 0 : nsIContent* const content = aItem.mContent;
3847 : nsIFrame* newFrame;
3848 : nsIFrame* primaryFrame;
3849 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
3850 0 : const nsStyleDisplay* display = computedStyle->StyleDisplay();
3851 0 : if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
3852 0 : newFrame =
3853 0 : (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
3854 0 : display, aFrameItems);
3855 0 : MOZ_ASSERT(newFrame, "Full constructor failed");
3856 : primaryFrame = newFrame;
3857 : } else {
3858 0 : newFrame =
3859 0 : (*data->mFunc.mCreationFunc)(mPresShell, computedStyle);
3860 :
3861 0 : bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
3862 0 : bool isPopup = aItem.mIsPopup;
3863 0 : NS_ASSERTION(!isPopup ||
3864 : (aState.mPopupItems.containingBlock &&
3865 : aState.mPopupItems.containingBlock->IsPopupSetFrame()),
3866 : "Should have a containing block here!");
3867 :
3868 : nsContainerFrame* geometricParent =
3869 0 : isPopup ? aState.mPopupItems.containingBlock :
3870 0 : (allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame)
3871 0 : : aParentFrame);
3872 :
3873 : // Must init frameToAddToList to null, since it's inout
3874 0 : nsIFrame* frameToAddToList = nullptr;
3875 0 : if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
3876 : display->IsScrollableOverflow()) {
3877 0 : nsContainerFrame* scrollframe = nullptr;
3878 : BuildScrollFrame(aState, content, computedStyle, newFrame,
3879 0 : geometricParent, scrollframe);
3880 0 : frameToAddToList = scrollframe;
3881 : } else {
3882 0 : InitAndRestoreFrame(aState, content, geometricParent, newFrame);
3883 0 : frameToAddToList = newFrame;
3884 : }
3885 :
3886 : // Use frameToAddToList as the primary frame. In the non-scrollframe case
3887 : // they're equal, but in the scrollframe case newFrame is the scrolled
3888 : // frame, while frameToAddToList is the scrollframe (and should be the
3889 : // primary frame).
3890 0 : primaryFrame = frameToAddToList;
3891 :
3892 : // If we need to create a block formatting context to wrap our
3893 : // kids, do it now.
3894 0 : const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display;
3895 0 : nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
3896 0 : nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3897 0 : nsIFrame* possiblyLeafFrame = newFrame;
3898 0 : if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
3899 0 : RefPtr<ComputedStyle> outerSC = mPresShell->StyleSet()->
3900 0 : ResolveInheritingAnonymousBoxStyle(*data->mAnonBoxPseudo,
3901 0 : computedStyle);
3902 : #ifdef DEBUG
3903 0 : nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
3904 0 : MOZ_ASSERT(containerFrame);
3905 : #endif
3906 0 : nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
3907 : nsContainerFrame* outerFrame;
3908 : nsContainerFrame* innerFrame;
3909 0 : if (bits & FCDATA_ALLOW_GRID_FLEX_COLUMNSET) {
3910 0 : switch (display->mDisplay) {
3911 : case StyleDisplay::Flex:
3912 : case StyleDisplay::InlineFlex:
3913 0 : outerFrame = NS_NewFlexContainerFrame(mPresShell, outerSC);
3914 0 : InitAndRestoreFrame(aState, content, container, outerFrame);
3915 0 : innerFrame = outerFrame;
3916 0 : break;
3917 : case StyleDisplay::Grid:
3918 : case StyleDisplay::InlineGrid:
3919 0 : outerFrame = NS_NewGridContainerFrame(mPresShell, outerSC);
3920 0 : InitAndRestoreFrame(aState, content, container, outerFrame);
3921 0 : innerFrame = outerFrame;
3922 0 : break;
3923 : default: {
3924 0 : nsContainerFrame* columnSetFrame = nullptr;
3925 0 : RefPtr<ComputedStyle> innerSC = outerSC;
3926 0 : const nsStyleColumn* columns = outerSC->StyleColumn();
3927 0 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO ||
3928 0 : columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
3929 : columnSetFrame =
3930 0 : NS_NewColumnSetFrame(mPresShell, outerSC,
3931 0 : nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
3932 0 : InitAndRestoreFrame(aState, content, container, columnSetFrame);
3933 0 : innerSC = mPresShell->StyleSet()->
3934 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
3935 0 : outerSC);
3936 : }
3937 0 : innerFrame = NS_NewBlockFormattingContext(mPresShell, innerSC);
3938 0 : if (columnSetFrame) {
3939 0 : InitAndRestoreFrame(aState, content, columnSetFrame, innerFrame);
3940 0 : SetInitialSingleChild(columnSetFrame, innerFrame);
3941 0 : outerFrame = columnSetFrame;
3942 : } else {
3943 0 : InitAndRestoreFrame(aState, content, container, innerFrame);
3944 0 : outerFrame = innerFrame;
3945 : }
3946 : break;
3947 : }
3948 : }
3949 : } else {
3950 0 : innerFrame = NS_NewBlockFormattingContext(mPresShell, outerSC);
3951 0 : InitAndRestoreFrame(aState, content, container, innerFrame);
3952 0 : outerFrame = innerFrame;
3953 : }
3954 :
3955 0 : SetInitialSingleChild(container, outerFrame);
3956 :
3957 0 : container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3958 :
3959 : // Now figure out whether newFrame or outerFrame should be the
3960 : // absolute container.
3961 0 : auto outerDisplay = outerSC->StyleDisplay();
3962 0 : if (outerDisplay->IsAbsPosContainingBlock(outerFrame)) {
3963 0 : maybeAbsoluteContainingBlockDisplay = outerDisplay;
3964 0 : maybeAbsoluteContainingBlock = outerFrame;
3965 0 : maybeAbsoluteContainingBlockStyleFrame = outerFrame;
3966 0 : innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3967 : }
3968 :
3969 : // Our kids should go into the innerFrame.
3970 0 : newFrame = innerFrame;
3971 : }
3972 :
3973 0 : aState.AddChild(frameToAddToList, aFrameItems, content, aParentFrame,
3974 0 : allowOutOfFlow, allowOutOfFlow, isPopup);
3975 :
3976 0 : nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
3977 0 : if (newFrameAsContainer) {
3978 : #ifdef MOZ_XUL
3979 : // Icky XUL stuff, sadly
3980 :
3981 0 : if (aItem.mIsRootPopupgroup) {
3982 0 : NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) &&
3983 : nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
3984 : newFrame,
3985 : "Unexpected PopupSetFrame");
3986 0 : aState.mPopupItems.containingBlock = newFrameAsContainer;
3987 0 : aState.mHavePendingPopupgroup = false;
3988 : }
3989 : #endif /* MOZ_XUL */
3990 :
3991 : // Process the child content if requested
3992 0 : nsFrameItems childItems;
3993 0 : nsFrameConstructorSaveState absoluteSaveState;
3994 :
3995 0 : if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
3996 0 : aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
3997 0 : } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
3998 0 : maybeAbsoluteContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3999 : // This check is identical to nsStyleDisplay::IsAbsPosContainingBlock
4000 : // except without the assertion that the style display and frame match.
4001 : // When constructing scroll frames we intentionally use the style
4002 : // display for the outer, but make the inner the containing block.
4003 0 : if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() ||
4004 0 : maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() ||
4005 0 : maybeAbsoluteContainingBlockDisplay->IsFixedPosContainingBlock(
4006 0 : maybeAbsoluteContainingBlockStyleFrame)) &&
4007 0 : !nsSVGUtils::IsInSVGTextSubtree(maybeAbsoluteContainingBlockStyleFrame)) {
4008 : nsContainerFrame* cf = static_cast<nsContainerFrame*>(
4009 0 : maybeAbsoluteContainingBlock);
4010 0 : aState.PushAbsoluteContainingBlock(cf, cf, absoluteSaveState);
4011 : }
4012 : }
4013 :
4014 0 : if (!aItem.mAnonChildren.IsEmpty()) {
4015 0 : NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS),
4016 : "We should not have both anonymous and non-anonymous "
4017 : "children in a given FrameConstructorItem");
4018 0 : AddFCItemsForAnonymousContent(aState, newFrameAsContainer, aItem.mAnonChildren,
4019 0 : aItem.mChildItems);
4020 0 : bits |= FCDATA_USE_CHILD_ITEMS;
4021 : }
4022 :
4023 0 : if (bits & FCDATA_USE_CHILD_ITEMS) {
4024 0 : nsFrameConstructorSaveState floatSaveState;
4025 :
4026 0 : if (ShouldSuppressFloatingOfDescendants(newFrame)) {
4027 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
4028 0 : } else if (newFrame->IsFloatContainingBlock()) {
4029 0 : aState.PushFloatContainingBlock(newFrameAsContainer, floatSaveState);
4030 : }
4031 0 : ConstructFramesFromItemList(aState, aItem.mChildItems,
4032 : newFrameAsContainer,
4033 0 : bits & FCDATA_IS_WRAPPER_ANON_BOX,
4034 0 : childItems);
4035 : } else {
4036 : // Process the child frames.
4037 0 : ProcessChildren(aState, content, computedStyle, newFrameAsContainer,
4038 0 : !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
4039 : childItems,
4040 0 : (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
4041 0 : aItem.mPendingBinding, possiblyLeafFrame);
4042 : }
4043 :
4044 0 : if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) {
4045 0 : nsFrameItems newItems;
4046 : nsFrameItems currentBlockItems;
4047 : nsIFrame* f;
4048 0 : while ((f = childItems.FirstChild()) != nullptr) {
4049 0 : bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
4050 0 : if (!wrapFrame) {
4051 : FlushAccumulatedBlock(aState, content, newFrameAsContainer,
4052 0 : currentBlockItems, newItems);
4053 : }
4054 :
4055 0 : childItems.RemoveFrame(f);
4056 0 : if (wrapFrame) {
4057 0 : currentBlockItems.AddChild(f);
4058 : } else {
4059 0 : newItems.AddChild(f);
4060 : }
4061 : }
4062 : FlushAccumulatedBlock(aState, content, newFrameAsContainer,
4063 0 : currentBlockItems, newItems);
4064 :
4065 0 : if (childItems.NotEmpty()) {
4066 : // an error must have occurred, delete unprocessed frames
4067 0 : childItems.DestroyFrames();
4068 : }
4069 :
4070 0 : childItems = newItems;
4071 : }
4072 :
4073 : // Set the frame's initial child list
4074 : // Note that MathML depends on this being called even if
4075 : // childItems is empty!
4076 0 : newFrameAsContainer->SetInitialChildList(kPrincipalList, childItems);
4077 : }
4078 : }
4079 :
4080 0 : NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
4081 : ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
4082 : "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
4083 :
4084 0 : if (aItem.mIsAnonymousContentCreatorContent) {
4085 : primaryFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
4086 : }
4087 :
4088 : // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
4089 : // generated content that doesn't have one yet. Note that we have to examine
4090 : // the frame bit, because by this point mIsGeneratedContent has been cleared
4091 : // on aItem.
4092 0 : if ((!aState.mCreatingExtraFrames ||
4093 0 : (primaryFrame->HasAnyStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT |
4094 0 : NS_FRAME_GENERATED_CONTENT) &&
4095 0 : !aItem.mContent->GetPrimaryFrame())) &&
4096 0 : !(bits & FCDATA_SKIP_FRAMESET)) {
4097 0 : aItem.mContent->SetPrimaryFrame(primaryFrame);
4098 0 : ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
4099 : }
4100 : }
4101 :
4102 : static void
4103 0 : SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet)
4104 : {
4105 : #ifdef DEBUG
4106 : // Make sure that the node passed to us doesn't have any XBL children
4107 : {
4108 0 : FlattenedChildIterator iter(aNode);
4109 0 : NS_ASSERTION(!iter.XBLInvolved() || !iter.GetNextChild(),
4110 : "The node should not have any XBL children");
4111 : }
4112 : #endif
4113 :
4114 : // Set the flag on the node itself
4115 0 : aNode->SetFlags(aFlagsToSet);
4116 :
4117 : // Set the flag on all of its children recursively
4118 0 : for (nsIContent* child = aNode->GetFirstChild(); child;
4119 0 : child = child->GetNextSibling()) {
4120 0 : SetFlagsOnSubtree(child, aFlagsToSet);
4121 : }
4122 0 : }
4123 :
4124 : /**
4125 : * This function takes a tree of nsIAnonymousContentCreator::ContentInfo
4126 : * objects where the nsIContent nodes have just been created, and appends the
4127 : * nsIContent children in the tree to their parent. The leaf nsIContent objects
4128 : * are appended first to minimize the number of notifications that are sent
4129 : * out (i.e. by appending as many descendants as posible while their parent is
4130 : * not yet in the document tree).
4131 : *
4132 : * This function is used simply as a convenience so that implementations of
4133 : * nsIAnonymousContentCreator::CreateAnonymousContent don't all have to have
4134 : * their own code to connect the elements that they create.
4135 : */
4136 : static void
4137 0 : ConnectAnonymousTreeDescendants(nsIContent* aParent,
4138 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
4139 : {
4140 0 : uint32_t count = aContent.Length();
4141 0 : for (uint32_t i=0; i < count; i++) {
4142 0 : nsIContent* content = aContent[i].mContent;
4143 0 : NS_ASSERTION(content, "null anonymous content?");
4144 :
4145 0 : ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
4146 :
4147 0 : aParent->AppendChildTo(content, false);
4148 : }
4149 0 : }
4150 :
4151 : nsresult
4152 0 : nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
4153 : nsIFrame* aParentFrame,
4154 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
4155 : {
4156 0 : nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
4157 0 : if (!creator)
4158 : return NS_OK;
4159 :
4160 0 : nsresult rv = creator->CreateAnonymousContent(aContent);
4161 0 : if (NS_FAILED(rv)) {
4162 : // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
4163 : return rv;
4164 : }
4165 :
4166 0 : uint32_t count = aContent.Length();
4167 0 : for (uint32_t i=0; i < count; i++) {
4168 : // get our child's content and set its parent to our content
4169 0 : nsIContent* content = aContent[i].mContent;
4170 0 : NS_ASSERTION(content, "null anonymous content?");
4171 :
4172 0 : ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
4173 :
4174 0 : if (aParentFrame->IsSVGUseFrame()) {
4175 : // least-surprise CSS binding until we do the SVG specified
4176 : // cascading rules for <svg:use> - bug 265894
4177 0 : content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
4178 : } else {
4179 0 : content->SetIsNativeAnonymousRoot();
4180 : }
4181 :
4182 0 : bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
4183 :
4184 : // If the parent is in a shadow tree, make sure we don't
4185 : // bind with a document because shadow roots and its descendants
4186 : // are not in document.
4187 : nsIDocument* bindDocument =
4188 0 : aParent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
4189 0 : rv = content->BindToTree(bindDocument, aParent, aParent, true);
4190 : // If the anonymous content creator requested that the content should be
4191 : // editable, honor its request.
4192 : // We need to set the flag on the whole subtree, because existing
4193 : // children's flags have already been set as part of the BindToTree operation.
4194 0 : if (anonContentIsEditable) {
4195 0 : NS_ASSERTION(aParentFrame->IsTextInputFrame(),
4196 : "We only expect this for anonymous content under a text control frame");
4197 0 : SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
4198 : }
4199 0 : if (NS_FAILED(rv)) {
4200 0 : content->UnbindFromTree();
4201 0 : return rv;
4202 : }
4203 : }
4204 :
4205 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
4206 : // Eagerly compute styles for the anonymous content tree.
4207 0 : for (auto& info : aContent) {
4208 0 : if (info.mContent->IsElement()) {
4209 0 : styleSet->StyleNewSubtree(info.mContent->AsElement());
4210 : }
4211 : }
4212 :
4213 0 : return NS_OK;
4214 : }
4215 :
4216 : static
4217 0 : bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
4218 : {
4219 : // -moz-{inline-}box is XUL, unless we're emulating it with flexbox.
4220 0 : if (!StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
4221 0 : (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
4222 : aDisplay->mDisplay == StyleDisplay::MozBox)) {
4223 : return true;
4224 : }
4225 :
4226 : #ifdef MOZ_XUL
4227 0 : return (aDisplay->mDisplay == StyleDisplay::MozInlineGrid ||
4228 0 : aDisplay->mDisplay == StyleDisplay::MozInlineStack ||
4229 0 : aDisplay->mDisplay == StyleDisplay::MozGrid ||
4230 0 : aDisplay->mDisplay == StyleDisplay::MozStack ||
4231 0 : aDisplay->mDisplay == StyleDisplay::MozGridGroup ||
4232 0 : aDisplay->mDisplay == StyleDisplay::MozGridLine ||
4233 0 : aDisplay->mDisplay == StyleDisplay::MozDeck ||
4234 0 : aDisplay->mDisplay == StyleDisplay::MozPopup ||
4235 : aDisplay->mDisplay == StyleDisplay::MozGroupbox);
4236 : #else
4237 : return false;
4238 : #endif
4239 : }
4240 :
4241 :
4242 : // XUL frames are not allowed to be out of flow.
4243 : #define SIMPLE_XUL_FCDATA(_func) \
4244 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, \
4245 : _func)
4246 : #define SCROLLABLE_XUL_FCDATA(_func) \
4247 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
4248 : FCDATA_MAY_NEED_SCROLLFRAME, _func)
4249 : // .. but we allow some XUL frames to be _containers_ for out-of-flow content
4250 : // (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
4251 : #define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) \
4252 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4253 : FCDATA_MAY_NEED_SCROLLFRAME, _func)
4254 :
4255 : #define SIMPLE_XUL_CREATE(_tag, _func) \
4256 : { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
4257 : #define SCROLLABLE_XUL_CREATE(_tag, _func) \
4258 : { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
4259 : #define SIMPLE_XUL_DISPLAY_CREATE(_display, _func) \
4260 : FCDATA_FOR_DISPLAY(_display, SIMPLE_XUL_FCDATA(_func))
4261 : #define SCROLLABLE_XUL_DISPLAY_CREATE(_display, _func) \
4262 : FCDATA_FOR_DISPLAY(_display, SCROLLABLE_XUL_FCDATA(_func))
4263 : #define SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(_display, _func) \
4264 : FCDATA_FOR_DISPLAY(_display, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func))
4265 :
4266 : static
4267 0 : nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
4268 : ComputedStyle* aComputedStyle)
4269 : {
4270 0 : nsCOMPtr<nsBoxLayout> layout;
4271 0 : NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
4272 0 : return NS_NewBoxFrame(aPresShell, aComputedStyle, false, layout);
4273 : }
4274 :
4275 : /* static */
4276 : const nsCSSFrameConstructor::FrameConstructionData*
4277 0 : nsCSSFrameConstructor::FindXULTagData(Element* aElement,
4278 : nsAtom* aTag,
4279 : int32_t aNameSpaceID,
4280 : ComputedStyle* aComputedStyle)
4281 : {
4282 0 : if (aNameSpaceID != kNameSpaceID_XUL) {
4283 : return nullptr;
4284 : }
4285 :
4286 : static const FrameConstructionDataByTag sXULTagData[] = {
4287 : #ifdef MOZ_XUL
4288 : SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
4289 : SCROLLABLE_XUL_CREATE(thumb, NS_NewButtonBoxFrame),
4290 : SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
4291 : SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
4292 : SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
4293 : SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
4294 : SCROLLABLE_XUL_CREATE(toolbarpaletteitem, NS_NewBoxFrame),
4295 : SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
4296 : SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
4297 : SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
4298 : SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
4299 : SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
4300 : SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
4301 : SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
4302 : SIMPLE_TAG_CHAIN(description, nsCSSFrameConstructor::FindXULDescriptionData),
4303 : SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
4304 : SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
4305 : SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
4306 : #ifdef XP_MACOSX
4307 : SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
4308 : #else
4309 : SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
4310 : #endif /* XP_MACOSX */
4311 : SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData),
4312 : SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
4313 : SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
4314 : SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame),
4315 : SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame),
4316 : SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame),
4317 : SIMPLE_TAG_CHAIN(listboxbody,
4318 : nsCSSFrameConstructor::FindXULListBoxBodyData),
4319 : SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData),
4320 : #endif /* MOZ_XUL */
4321 : SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
4322 : SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
4323 : SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
4324 : };
4325 :
4326 : return FindDataByTag(aTag, aElement, aComputedStyle, sXULTagData,
4327 0 : ArrayLength(sXULTagData));
4328 : }
4329 :
4330 : #ifdef MOZ_XUL
4331 : /* static */
4332 : const nsCSSFrameConstructor::FrameConstructionData*
4333 0 : nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
4334 : ComputedStyle* /* unused */)
4335 : {
4336 0 : if (!aElement->IsRootOfNativeAnonymousSubtree()) {
4337 : return nullptr;
4338 : }
4339 :
4340 : static const FrameConstructionData sPopupSetData =
4341 : SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
4342 0 : return &sPopupSetData;
4343 : }
4344 :
4345 : /* static */
4346 : const nsCSSFrameConstructor::FrameConstructionData
4347 : nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
4348 :
4349 : /* static */
4350 : const nsCSSFrameConstructor::FrameConstructionData*
4351 0 : nsCSSFrameConstructor::FindXULLabelData(Element* aElement,
4352 : ComputedStyle* /* unused */)
4353 : {
4354 0 : if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4355 : return &sXULTextBoxData;
4356 : }
4357 :
4358 : static const FrameConstructionData sLabelData =
4359 : SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
4360 0 : return &sLabelData;
4361 : }
4362 :
4363 : static nsIFrame*
4364 0 : NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, ComputedStyle *aContext)
4365 : {
4366 : // XXXbz do we really need to set up the block formatting context root? If the
4367 : // parent is not a block we'll get it anyway, and if it is, do we want it?
4368 0 : return NS_NewBlockFormattingContext(aPresShell, aContext);
4369 : }
4370 :
4371 : /* static */
4372 : const nsCSSFrameConstructor::FrameConstructionData*
4373 0 : nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement,
4374 : ComputedStyle* /* unused */)
4375 : {
4376 0 : if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4377 : return &sXULTextBoxData;
4378 : }
4379 :
4380 : static const FrameConstructionData sDescriptionData =
4381 : SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame);
4382 0 : return &sDescriptionData;
4383 : }
4384 :
4385 : #ifdef XP_MACOSX
4386 : /* static */
4387 : const nsCSSFrameConstructor::FrameConstructionData*
4388 : nsCSSFrameConstructor::FindXULMenubarData(Element* aElement,
4389 : ComputedStyle* aComputedStyle)
4390 : {
4391 : nsCOMPtr<nsIDocShell> treeItem = aElement->OwnerDoc()->GetDocShell();
4392 : if (treeItem && nsIDocShellTreeItem::typeChrome == treeItem->ItemType()) {
4393 : nsCOMPtr<nsIDocShellTreeItem> parent;
4394 : treeItem->GetParent(getter_AddRefs(parent));
4395 : if (!parent) {
4396 : // This is the root. Suppress the menubar, since on Mac
4397 : // window menus are not attached to the window.
4398 : static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4399 : return &sSuppressData;
4400 : }
4401 : }
4402 :
4403 : static const FrameConstructionData sMenubarData =
4404 : SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
4405 : return &sMenubarData;
4406 : }
4407 : #endif /* XP_MACOSX */
4408 :
4409 : /* static */
4410 : const nsCSSFrameConstructor::FrameConstructionData*
4411 0 : nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
4412 : ComputedStyle* aComputedStyle)
4413 : {
4414 0 : if (aComputedStyle->StyleDisplay()->mDisplay !=
4415 : StyleDisplay::MozGridGroup) {
4416 : return nullptr;
4417 : }
4418 :
4419 : static const FrameConstructionData sListBoxBodyData =
4420 : SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame);
4421 0 : return &sListBoxBodyData;
4422 : }
4423 :
4424 : /* static */
4425 : const nsCSSFrameConstructor::FrameConstructionData*
4426 0 : nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
4427 : ComputedStyle* aComputedStyle)
4428 : {
4429 0 : if (aComputedStyle->StyleDisplay()->mDisplay != StyleDisplay::MozGridLine) {
4430 : return nullptr;
4431 : }
4432 :
4433 : static const FrameConstructionData sListItemData =
4434 : SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame);
4435 0 : return &sListItemData;
4436 : }
4437 :
4438 : #endif /* MOZ_XUL */
4439 :
4440 : /* static */
4441 : const nsCSSFrameConstructor::FrameConstructionData*
4442 0 : nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
4443 : Element* aElement,
4444 : ComputedStyle* aComputedStyle)
4445 : {
4446 : static const FrameConstructionDataByDisplay sXULDisplayData[] = {
4447 : SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozBox,
4448 : NS_NewBoxFrame),
4449 : SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineBox,
4450 : NS_NewBoxFrame),
4451 : #ifdef MOZ_XUL
4452 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGrid, NS_NewGridBoxFrame),
4453 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineGrid, NS_NewGridBoxFrame),
4454 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridGroup,
4455 : NS_NewGridRowGroupFrame),
4456 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridLine,
4457 : NS_NewGridRowLeafFrame),
4458 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozStack, NS_NewStackFrame),
4459 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineStack, NS_NewStackFrame),
4460 : SIMPLE_XUL_DISPLAY_CREATE(StyleDisplay::MozDeck, NS_NewDeckFrame),
4461 : SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGroupbox, NS_NewGroupBoxFrame),
4462 : FCDATA_FOR_DISPLAY(StyleDisplay::MozPopup,
4463 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
4464 : FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame))
4465 : #endif /* MOZ_XUL */
4466 : };
4467 :
4468 0 : if (aDisplay->mDisplay < StyleDisplay::MozBox) {
4469 : return nullptr;
4470 : }
4471 :
4472 120 : MOZ_ASSERT(aDisplay->mDisplay <= StyleDisplay::MozPopup,
4473 : "Someone added a new display value?");
4474 :
4475 120 : if (aDisplay->mDisplay == StyleDisplay::MozBox ||
4476 : aDisplay->mDisplay == StyleDisplay::MozInlineBox) {
4477 0 : if (!aElement->IsInNativeAnonymousSubtree() &&
4478 1 : aElement->OwnerDoc()->IsContentDocument()) {
4479 0 : aElement->OwnerDoc()->WarnOnceAbout(nsIDocument::eMozBoxOrInlineBoxDisplay);
4480 : }
4481 :
4482 : // If we're emulating -moz-box with flexbox, then treat it as non-XUL and
4483 : // return null (except for scrollcorners which have to be XUL becuase their
4484 : // parent reflows them with BoxReflow() which means they have to get
4485 : // actual-XUL frames).
4486 70 : if (StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
4487 0 : !aElement->IsXULElement(nsGkAtoms::scrollcorner)) {
4488 : return nullptr;
4489 : }
4490 : }
4491 :
4492 : const FrameConstructionDataByDisplay& data =
4493 120 : sXULDisplayData[size_t(aDisplay->mDisplay) - size_t(StyleDisplay::MozBox)];
4494 120 : MOZ_ASSERT(aDisplay->mDisplay == data.mDisplay,
4495 : "Did someone mess with the order?");
4496 :
4497 120 : return &data.mData;
4498 : }
4499 :
4500 : already_AddRefed<ComputedStyle>
4501 30 : nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
4502 : nsIContent* aContent,
4503 : ComputedStyle* aContentStyle,
4504 : nsContainerFrame* aParentFrame,
4505 : nsAtom* aScrolledPseudo,
4506 : bool aIsRoot,
4507 : nsContainerFrame*& aNewFrame)
4508 : {
4509 0 : nsContainerFrame* gfxScrollFrame = aNewFrame;
4510 :
4511 30 : nsFrameItems anonymousItems;
4512 :
4513 60 : RefPtr<ComputedStyle> contentStyle = aContentStyle;
4514 :
4515 0 : if (!gfxScrollFrame) {
4516 : // Build a XULScrollFrame when the child is a box, otherwise an
4517 : // HTMLScrollFrame
4518 : // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4519 : // I wonder whether we can eliminate that somehow.
4520 0 : const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay();
4521 30 : if (IsXULDisplayType(displayStyle)) {
4522 18 : gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot,
4523 0 : displayStyle->mDisplay == StyleDisplay::MozStack ||
4524 9 : displayStyle->mDisplay == StyleDisplay::MozInlineStack);
4525 : } else {
4526 42 : gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
4527 : }
4528 :
4529 30 : InitAndRestoreFrame(aState, aContent, aParentFrame, gfxScrollFrame);
4530 : }
4531 :
4532 : // if there are any anonymous children for the scroll frame, create
4533 : // frames for them.
4534 : //
4535 : // We can't take the normal ProcessChildren path, because the NAC needs to
4536 : // be parented to the scrollframe, and everything else needs to be parented
4537 : // to the scrolledframe.
4538 60 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4539 90 : DebugOnly<nsresult> rv = GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC);
4540 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
4541 30 : if (scrollNAC.Length() > 0) {
4542 10 : AutoFrameConstructionItemList items(this);
4543 0 : AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
4544 : ConstructFramesFromItemList(aState, items, gfxScrollFrame,
4545 : /* aParentIsWrapperAnonBox = */ false,
4546 5 : anonymousItems);
4547 : }
4548 :
4549 0 : aNewFrame = gfxScrollFrame;
4550 60 : gfxScrollFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4551 :
4552 : // we used the style that was passed in. So resolve another one.
4553 60 : ServoStyleSet* styleSet = mPresShell->StyleSet();
4554 : RefPtr<ComputedStyle> scrolledChildStyle =
4555 0 : styleSet->ResolveInheritingAnonymousBoxStyle(aScrolledPseudo, contentStyle);
4556 :
4557 30 : if (gfxScrollFrame) {
4558 30 : gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems);
4559 : }
4560 :
4561 60 : return scrolledChildStyle.forget();
4562 : }
4563 :
4564 : void
4565 30 : nsCSSFrameConstructor::FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
4566 : nsIFrame* aScrolledFrame)
4567 : {
4568 30 : nsFrameList scrolled(aScrolledFrame, aScrolledFrame);
4569 30 : aScrollFrame->AppendFrames(kPrincipalList, scrolled);
4570 30 : }
4571 :
4572 : /**
4573 : * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
4574 : *
4575 : * ------- for gfx scrollbars ------
4576 : *
4577 : *
4578 : * ScrollFrame
4579 : * ^
4580 : * |
4581 : * Frame (scrolled frame you passed in)
4582 : *
4583 : *
4584 : *-----------------------------------
4585 : * LEGEND:
4586 : *
4587 : * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
4588 : *
4589 : * @param aContent the content node of the child to wrap.
4590 : * @param aScrolledFrame The frame of the content to wrap. This should not be
4591 : * Initialized. This method will initialize it with a scrolled pseudo
4592 : * and no nsIContent. The content will be attached to the scrollframe
4593 : * returned.
4594 : * @param aContentStyle the style that has already been resolved for the content
4595 : * being passed in.
4596 : *
4597 : * @param aParentFrame The parent to attach the scroll frame to
4598 : *
4599 : * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
4600 : * scrolled frame you passed in. (returned)
4601 : * If this is not null, we'll just use it
4602 : * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
4603 : */
4604 : void
4605 9 : nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
4606 : nsIContent* aContent,
4607 : ComputedStyle* aContentStyle,
4608 : nsIFrame* aScrolledFrame,
4609 : nsContainerFrame* aParentFrame,
4610 : nsContainerFrame*& aNewFrame)
4611 : {
4612 : RefPtr<ComputedStyle> scrolledContentStyle =
4613 18 : BeginBuildingScrollFrame(aState, aContent, aContentStyle, aParentFrame,
4614 : nsCSSAnonBoxes::scrolledContent,
4615 0 : false, aNewFrame);
4616 :
4617 9 : aScrolledFrame->SetComputedStyleWithoutNotification(scrolledContentStyle);
4618 0 : InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4619 :
4620 9 : FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
4621 9 : }
4622 :
4623 : const nsCSSFrameConstructor::FrameConstructionData*
4624 10 : nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
4625 : Element* aElement,
4626 : ComputedStyle* aComputedStyle)
4627 : {
4628 : static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)),
4629 : "Check eParentTypeCount should not overflow");
4630 :
4631 : // The style system ensures that floated and positioned frames are
4632 : // block-level.
4633 20 : NS_ASSERTION(!(aDisplay->IsFloatingStyle() ||
4634 : aDisplay->IsAbsolutelyPositionedStyle()) ||
4635 : aDisplay->IsBlockOutsideStyle() ||
4636 : aDisplay->mDisplay == StyleDisplay::Contents,
4637 : "Style system did not apply CSS2.1 section 9.7 fixups");
4638 :
4639 : // If this is "body", try propagating its scroll style to the viewport
4640 : // Note that we need to do this even if the body is NOT scrollable;
4641 : // it might have dynamically changed from scrollable to not scrollable,
4642 : // and that might need to be propagated.
4643 : // XXXbz is this the right place to do this? If this code moves,
4644 : // make this function static.
4645 10 : bool propagatedScrollToViewport = false;
4646 10 : if (aElement->IsHTMLElement(nsGkAtoms::body)) {
4647 0 : if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4648 3 : propagatedScrollToViewport =
4649 3 : presContext->UpdateViewportScrollbarStylesOverride() == aElement;
4650 : }
4651 : }
4652 :
4653 10 : NS_ASSERTION(!propagatedScrollToViewport ||
4654 : !mPresShell->GetPresContext()->IsPaginated(),
4655 : "Shouldn't propagate scroll in paginated contexts");
4656 :
4657 0 : if (aDisplay->IsBlockInsideStyle()) {
4658 : // If the frame is a block-level frame and is scrollable, then wrap it in a
4659 : // scroll frame. Except we don't want to do that for paginated contexts for
4660 : // frames that are block-outside and aren't frames for native anonymous stuff.
4661 : // XXX Ignore tables for the time being (except caption)
4662 : const uint32_t kCaptionCtorFlags =
4663 0 : FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable);
4664 0 : bool caption = aDisplay->mDisplay == StyleDisplay::TableCaption;
4665 0 : bool suppressScrollFrame = false;
4666 0 : bool needScrollFrame = aDisplay->IsScrollableOverflow() &&
4667 10 : !propagatedScrollToViewport;
4668 10 : if (needScrollFrame) {
4669 12 : suppressScrollFrame = mPresShell->GetPresContext()->IsPaginated() &&
4670 3 : aDisplay->IsBlockOutsideStyle() &&
4671 0 : !aElement->IsInNativeAnonymousSubtree();
4672 3 : if (!suppressScrollFrame) {
4673 : static const FrameConstructionData sScrollableBlockData[2] =
4674 : { FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock),
4675 : FULL_CTOR_FCDATA(kCaptionCtorFlags,
4676 : &nsCSSFrameConstructor::ConstructScrollableBlock) };
4677 3 : return &sScrollableBlockData[caption];
4678 : }
4679 :
4680 : // If the scrollable frame would have propagated its scrolling to the
4681 : // viewport, we still want to construct a regular block rather than a
4682 : // scrollframe so that it paginates correctly, but we don't want to set
4683 : // the bit on the block that tells it to clip at paint time.
4684 0 : if (mPresShell->GetPresContext()->
4685 0 : ElementWouldPropagateScrollbarStyles(aElement)) {
4686 0 : suppressScrollFrame = false;
4687 : }
4688 : }
4689 :
4690 : // Handle various non-scrollable blocks.
4691 : static const FrameConstructionData sNonScrollableBlockData[2][2] = {
4692 : { FULL_CTOR_FCDATA(0,
4693 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4694 : FULL_CTOR_FCDATA(kCaptionCtorFlags,
4695 : &nsCSSFrameConstructor::ConstructNonScrollableBlock) },
4696 : { FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
4697 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4698 : FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK | kCaptionCtorFlags,
4699 : &nsCSSFrameConstructor::ConstructNonScrollableBlock) }
4700 : };
4701 0 : return &sNonScrollableBlockData[suppressScrollFrame][caption];
4702 : }
4703 :
4704 : // If this is for a <body> node and we've propagated the scroll-frame to the
4705 : // viewport, we need to make sure not to add another layer of scrollbars, so
4706 : // we use a different FCData struct without FCDATA_MAY_NEED_SCROLLFRAME.
4707 0 : if (propagatedScrollToViewport && aDisplay->IsScrollableOverflow()) {
4708 0 : if (aDisplay->mDisplay == StyleDisplay::Flex ||
4709 0 : aDisplay->mDisplay == StyleDisplay::WebkitBox ||
4710 0 : (StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
4711 0 : aDisplay->mDisplay == StyleDisplay::MozBox)) {
4712 : static const FrameConstructionData sNonScrollableFlexData =
4713 : FCDATA_DECL(0, NS_NewFlexContainerFrame);
4714 : return &sNonScrollableFlexData;
4715 : }
4716 0 : if (aDisplay->mDisplay == StyleDisplay::Grid) {
4717 : static const FrameConstructionData sNonScrollableGridData =
4718 : FCDATA_DECL(0, NS_NewGridContainerFrame);
4719 : return &sNonScrollableGridData;
4720 : }
4721 : }
4722 :
4723 : // NOTE: Make sure to keep this up to date with the StyleDisplay definition!
4724 : static const FrameConstructionDataByDisplay sDisplayData[] = {
4725 : FCDATA_FOR_DISPLAY(StyleDisplay::None, UNREACHABLE_FCDATA()),
4726 : FCDATA_FOR_DISPLAY(StyleDisplay::Block, UNREACHABLE_FCDATA()),
4727 : FCDATA_FOR_DISPLAY(StyleDisplay::FlowRoot, UNREACHABLE_FCDATA()),
4728 : // To keep the hash table small don't add inline frames (they're
4729 : // typically things like FONT and B), because we can quickly
4730 : // find them if we need to.
4731 : // XXXbz the "quickly" part is a bald-faced lie!
4732 : FCDATA_FOR_DISPLAY(StyleDisplay::Inline,
4733 : FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
4734 : &nsCSSFrameConstructor::ConstructInline)),
4735 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineBlock, UNREACHABLE_FCDATA()),
4736 : FCDATA_FOR_DISPLAY(StyleDisplay::ListItem, UNREACHABLE_FCDATA()),
4737 : FCDATA_FOR_DISPLAY(StyleDisplay::Table,
4738 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4739 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineTable,
4740 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4741 : // NOTE: In the unlikely event that we add another table-part here that has
4742 : // a desired-parent-type (& hence triggers table fixup), we'll need to also
4743 : // update the flexbox chunk in ComputedStyle::ApplyStyleFixups().
4744 : FCDATA_FOR_DISPLAY(StyleDisplay::TableRowGroup,
4745 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4746 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4747 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4748 : FCDATA_FOR_DISPLAY(StyleDisplay::TableColumn,
4749 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4750 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup),
4751 : &nsCSSFrameConstructor::ConstructTableCol)),
4752 : FCDATA_FOR_DISPLAY(StyleDisplay::TableColumnGroup,
4753 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4754 : FCDATA_SKIP_ABSPOS_PUSH |
4755 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4756 : NS_NewTableColGroupFrame)),
4757 : FCDATA_FOR_DISPLAY(StyleDisplay::TableHeaderGroup,
4758 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4759 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4760 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4761 : FCDATA_FOR_DISPLAY(StyleDisplay::TableFooterGroup,
4762 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4763 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4764 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4765 : FCDATA_FOR_DISPLAY(StyleDisplay::TableRow,
4766 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4767 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
4768 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4769 : FCDATA_FOR_DISPLAY(StyleDisplay::TableCell,
4770 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4771 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
4772 : &nsCSSFrameConstructor::ConstructTableCell)),
4773 : FCDATA_FOR_DISPLAY(StyleDisplay::TableCaption, UNREACHABLE_FCDATA()),
4774 : FCDATA_FOR_DISPLAY(StyleDisplay::Flex,
4775 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4776 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineFlex,
4777 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4778 : FCDATA_FOR_DISPLAY(StyleDisplay::Grid,
4779 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4780 : FCDATA_FOR_DISPLAY(StyleDisplay::InlineGrid,
4781 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4782 : FCDATA_FOR_DISPLAY(StyleDisplay::Ruby,
4783 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewRubyFrame)),
4784 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyBase,
4785 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4786 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer),
4787 : NS_NewRubyBaseFrame)),
4788 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyBaseContainer,
4789 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4790 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4791 : NS_NewRubyBaseContainerFrame)),
4792 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyText,
4793 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4794 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
4795 : NS_NewRubyTextFrame)),
4796 : FCDATA_FOR_DISPLAY(StyleDisplay::RubyTextContainer,
4797 : FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4798 : NS_NewRubyTextContainerFrame)),
4799 : FCDATA_FOR_DISPLAY(StyleDisplay::Contents, UNREACHABLE_FCDATA()),
4800 : FCDATA_FOR_DISPLAY(StyleDisplay::WebkitBox,
4801 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4802 : FCDATA_FOR_DISPLAY(StyleDisplay::WebkitInlineBox,
4803 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4804 : FCDATA_FOR_DISPLAY(StyleDisplay::MozBox,
4805 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4806 : FCDATA_FOR_DISPLAY(StyleDisplay::MozInlineBox,
4807 : FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4808 : };
4809 : static_assert(ArrayLength(sDisplayData) == size_t(StyleDisplay::MozInlineBox) + 1,
4810 : "Be sure to update sDisplayData if you touch StyleDisplay");
4811 0 : MOZ_ASSERT(StaticPrefs::layout_css_emulate_moz_box_with_flex() ||
4812 : (aDisplay->mDisplay != StyleDisplay::MozBox &&
4813 : aDisplay->mDisplay != StyleDisplay::MozInlineBox),
4814 : "-moz-{inline-}box as XUL should have already been handled");
4815 0 : MOZ_ASSERT(size_t(aDisplay->mDisplay) < ArrayLength(sDisplayData),
4816 : "XUL display data should have already been handled");
4817 :
4818 : // See the mDisplay fixup code in nsRuleNode::ComputeDisplayData.
4819 0 : MOZ_ASSERT(aDisplay->mDisplay != StyleDisplay::Contents ||
4820 : !aElement->IsRootOfNativeAnonymousSubtree(),
4821 : "display:contents on anonymous content is unsupported");
4822 :
4823 : const FrameConstructionDataByDisplay& data =
4824 0 : sDisplayData[size_t(aDisplay->mDisplay)];
4825 :
4826 0 : MOZ_ASSERT(data.mDisplay == aDisplay->mDisplay,
4827 : "Someone messed up the order in the display values");
4828 :
4829 0 : return &data.mData;
4830 : }
4831 :
4832 : nsIFrame*
4833 3 : nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState,
4834 : FrameConstructionItem& aItem,
4835 : nsContainerFrame* aParentFrame,
4836 : const nsStyleDisplay* aDisplay,
4837 : nsFrameItems& aFrameItems)
4838 : {
4839 : return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
4840 : aDisplay, aFrameItems,
4841 3 : NS_NewBlockFormattingContext);
4842 : }
4843 :
4844 : nsIFrame*
4845 3 : nsCSSFrameConstructor::ConstructScrollableBlockWithConstructor(
4846 : nsFrameConstructorState& aState,
4847 : FrameConstructionItem& aItem,
4848 : nsContainerFrame* aParentFrame,
4849 : const nsStyleDisplay* aDisplay,
4850 : nsFrameItems& aFrameItems,
4851 : BlockFrameCreationFunc aConstructor)
4852 : {
4853 3 : nsIContent* const content = aItem.mContent;
4854 6 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
4855 :
4856 3 : nsContainerFrame* newFrame = nullptr;
4857 : RefPtr<ComputedStyle> scrolledContentStyle
4858 6 : = BeginBuildingScrollFrame(aState, content, computedStyle,
4859 : aState.GetGeometricParent(aDisplay, aParentFrame),
4860 : nsCSSAnonBoxes::scrolledContent,
4861 6 : false, newFrame);
4862 :
4863 : // Create our block frame
4864 : // pass a temporary stylecontext, the correct one will be set later
4865 0 : nsContainerFrame* scrolledFrame = aConstructor(mPresShell, computedStyle);
4866 :
4867 : // Make sure to AddChild before we call ConstructBlock so that we
4868 : // end up before our descendants in fixed-pos lists as needed.
4869 0 : aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
4870 :
4871 0 : nsFrameItems blockItem;
4872 9 : ConstructBlock(aState, content, newFrame, newFrame, scrolledContentStyle,
4873 : &scrolledFrame, blockItem,
4874 3 : aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
4875 0 : aItem.mPendingBinding);
4876 :
4877 3 : MOZ_ASSERT(blockItem.OnlyChild() == scrolledFrame,
4878 : "Scrollframe's frameItems should be exactly the scrolled frame!");
4879 0 : FinishBuildingScrollFrame(newFrame, scrolledFrame);
4880 :
4881 6 : return newFrame;
4882 : }
4883 :
4884 : nsIFrame*
4885 7 : nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState& aState,
4886 : FrameConstructionItem& aItem,
4887 : nsContainerFrame* aParentFrame,
4888 : const nsStyleDisplay* aDisplay,
4889 : nsFrameItems& aFrameItems)
4890 : {
4891 : return ConstructNonScrollableBlockWithConstructor(aState, aItem, aParentFrame,
4892 : aDisplay, aFrameItems,
4893 7 : NS_NewBlockFrame);
4894 : }
4895 :
4896 : nsIFrame*
4897 7 : nsCSSFrameConstructor::ConstructNonScrollableBlockWithConstructor(
4898 : nsFrameConstructorState& aState,
4899 : FrameConstructionItem& aItem,
4900 : nsContainerFrame* aParentFrame,
4901 : const nsStyleDisplay* aDisplay,
4902 : nsFrameItems& aFrameItems,
4903 : BlockFrameCreationFunc aConstructor)
4904 : {
4905 14 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
4906 :
4907 : // We want a block formatting context root in paginated contexts for
4908 : // every block that would be scrollable in a non-paginated context.
4909 : // We mark our blocks with a bit here if this condition is true, so
4910 : // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
4911 : bool clipPaginatedOverflow =
4912 0 : (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
4913 0 : nsFrameState flags = nsFrameState(0);
4914 0 : if ((aDisplay->IsAbsolutelyPositionedStyle() ||
4915 6 : aDisplay->IsFloatingStyle() ||
4916 6 : StyleDisplay::InlineBlock == aDisplay->mDisplay ||
4917 11 : clipPaginatedOverflow) &&
4918 4 : !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
4919 0 : flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS;
4920 0 : if (clipPaginatedOverflow) {
4921 : flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
4922 : }
4923 : }
4924 :
4925 0 : nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
4926 0 : newFrame->AddStateBits(flags);
4927 0 : ConstructBlock(aState, aItem.mContent,
4928 : aState.GetGeometricParent(aDisplay, aParentFrame),
4929 : aParentFrame, computedStyle, &newFrame,
4930 : aFrameItems,
4931 7 : aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
4932 0 : aItem.mPendingBinding);
4933 7 : return newFrame;
4934 : }
4935 :
4936 :
4937 : void
4938 0 : nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
4939 : nsIContent* aContent,
4940 : nsContainerFrame* aParentFrame,
4941 : nsIFrame* aNewFrame,
4942 : bool aAllowCounters)
4943 : {
4944 0 : MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized");
4945 :
4946 : // Initialize the frame
4947 331 : aNewFrame->Init(aContent, aParentFrame, nullptr);
4948 662 : aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4949 :
4950 0 : if (aState.mFrameState) {
4951 : // Restore frame state for just the newly created frame.
4952 98 : RestoreFrameStateFor(aNewFrame, aState.mFrameState);
4953 : }
4954 :
4955 659 : if (aAllowCounters &&
4956 0 : mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
4957 0 : CountersDirty();
4958 : }
4959 331 : }
4960 :
4961 : already_AddRefed<ComputedStyle>
4962 502 : nsCSSFrameConstructor::ResolveComputedStyle(nsIContent* aContent)
4963 : {
4964 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
4965 :
4966 1004 : if (aContent->IsElement()) {
4967 459 : return styleSet->ResolveServoStyle(aContent->AsElement());
4968 : }
4969 :
4970 43 : MOZ_ASSERT(aContent->IsText(),
4971 : "shouldn't waste time creating ComputedStyles for "
4972 : "comments and processing instructions");
4973 :
4974 43 : Element* parent = aContent->GetFlattenedTreeParentElement();
4975 43 : MOZ_ASSERT(parent, "Text out of the flattened tree?");
4976 :
4977 : // FIXME(emilio): We can't use ResolveServoStyle properly because this text
4978 : // node can come from non-lazy frame construction, in which case the style we
4979 : // inherit from can indeed be out-of-date. After an eventual XBL removal, this
4980 : // can go. Note that this is not a correctness issue, since we'll restyle
4981 : // later in any case.
4982 : //
4983 : // Also, this probably doesn't need to be a strong ref...
4984 : //
4985 : // Do NOT add new callers to this function in this file, ever, or I'll find
4986 : // out.
4987 : RefPtr<ComputedStyle> parentStyle =
4988 0 : Servo_Element_GetPrimaryComputedValues(parent).Consume();
4989 43 : return styleSet->ResolveStyleForText(aContent, parentStyle);
4990 : }
4991 :
4992 : // MathML Mod - RBS
4993 : void
4994 0 : nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
4995 : nsIContent* aContent,
4996 : nsContainerFrame* aParentFrame,
4997 : nsFrameItems& aBlockItems,
4998 : nsFrameItems& aNewItems)
4999 : {
5000 0 : if (aBlockItems.IsEmpty()) {
5001 : // Nothing to do
5002 0 : return;
5003 : }
5004 :
5005 0 : nsAtom* anonPseudo = nsCSSAnonBoxes::mozMathMLAnonymousBlock;
5006 :
5007 : ComputedStyle* parentContext =
5008 : nsFrame::CorrectStyleParentFrame(aParentFrame,
5009 0 : anonPseudo)->Style();
5010 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
5011 0 : RefPtr<ComputedStyle> blockContext;
5012 : blockContext = styleSet->
5013 0 : ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
5014 :
5015 : // then, create a block frame that will wrap the child frames. Make it a
5016 : // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
5017 : // is not a suitable block.
5018 : nsContainerFrame* blockFrame =
5019 0 : NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
5020 :
5021 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
5022 0 : ReparentFrames(this, blockFrame, aBlockItems, false);
5023 : // We have to walk over aBlockItems before we hand it over to blockFrame.
5024 0 : for (nsIFrame* f : aBlockItems) {
5025 0 : f->SetParentIsWrapperAnonBox();
5026 : }
5027 : // abs-pos and floats are disabled in MathML children so we don't have to
5028 : // worry about messing up those.
5029 0 : blockFrame->SetInitialChildList(kPrincipalList, aBlockItems);
5030 0 : NS_ASSERTION(aBlockItems.IsEmpty(), "What happened?");
5031 0 : aBlockItems.Clear();
5032 0 : aNewItems.AddChild(blockFrame);
5033 : }
5034 :
5035 : // Only <math> elements can be floated or positioned. All other MathML
5036 : // should be in-flow.
5037 : #define SIMPLE_MATHML_CREATE(_tag, _func) \
5038 : { &nsGkAtoms::_tag, \
5039 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
5040 : FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
5041 : FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
5042 :
5043 : /* static */
5044 : const nsCSSFrameConstructor::FrameConstructionData*
5045 0 : nsCSSFrameConstructor::FindMathMLData(Element* aElement,
5046 : nsAtom* aTag,
5047 : int32_t aNameSpaceID,
5048 : ComputedStyle* aComputedStyle)
5049 : {
5050 : // Make sure that we remain confined in the MathML world
5051 145 : if (aNameSpaceID != kNameSpaceID_MathML)
5052 : return nullptr;
5053 :
5054 : // Handle <math> specially, because it sometimes produces inlines
5055 0 : if (aTag == nsGkAtoms::math) {
5056 : // This needs to match the test in EnsureBlockDisplay in
5057 : // nsRuleNode.cpp. Though the behavior here for the display:table
5058 : // case is pretty weird...
5059 0 : if (aComputedStyle->StyleDisplay()->IsBlockOutsideStyle()) {
5060 : static const FrameConstructionData sBlockMathData =
5061 : FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
5062 : FCDATA_WRAP_KIDS_IN_BLOCKS,
5063 : NS_NewMathMLmathBlockFrame);
5064 : return &sBlockMathData;
5065 : }
5066 :
5067 : static const FrameConstructionData sInlineMathData =
5068 : FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
5069 : FCDATA_IS_LINE_PARTICIPANT |
5070 : FCDATA_WRAP_KIDS_IN_BLOCKS,
5071 : NS_NewMathMLmathInlineFrame);
5072 0 : return &sInlineMathData;
5073 : }
5074 :
5075 :
5076 : static const FrameConstructionDataByTag sMathMLData[] = {
5077 : SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame),
5078 : SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame),
5079 : SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
5080 : SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
5081 : SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
5082 : SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
5083 : SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
5084 : SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
5085 : SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame),
5086 : SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame),
5087 : SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame),
5088 : SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
5089 : SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
5090 : SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
5091 : SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmrowFrame),
5092 : SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
5093 : SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
5094 : SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
5095 : SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
5096 : SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame),
5097 : SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame),
5098 : SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmrowFrame),
5099 : SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame),
5100 : SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame),
5101 : SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame),
5102 : SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame),
5103 : SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame),
5104 : SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame),
5105 : SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)
5106 : };
5107 :
5108 : return FindDataByTag(aTag, aElement, aComputedStyle, sMathMLData,
5109 0 : ArrayLength(sMathMLData));
5110 : }
5111 :
5112 :
5113 : nsContainerFrame*
5114 13 : nsCSSFrameConstructor::ConstructFrameWithAnonymousChild(
5115 : nsFrameConstructorState& aState,
5116 : FrameConstructionItem& aItem,
5117 : nsContainerFrame* aParentFrame,
5118 : nsFrameItems& aFrameItems,
5119 : ContainerFrameCreationFunc aConstructor,
5120 : ContainerFrameCreationFunc aInnerConstructor,
5121 : nsICSSAnonBoxPseudo* aInnerPseudo,
5122 : bool aCandidateRootFrame)
5123 : {
5124 0 : nsIContent* const content = aItem.mContent;
5125 26 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
5126 :
5127 : // Create the outer frame:
5128 13 : nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
5129 :
5130 0 : InitAndRestoreFrame(aState, content,
5131 : aCandidateRootFrame ?
5132 13 : aState.GetGeometricParent(computedStyle->StyleDisplay(),
5133 : aParentFrame) :
5134 : aParentFrame,
5135 0 : newFrame);
5136 26 : newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
5137 :
5138 : // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
5139 26 : RefPtr<ComputedStyle> scForAnon;
5140 0 : scForAnon = mPresShell->StyleSet()->
5141 13 : ResolveInheritingAnonymousBoxStyle(aInnerPseudo, computedStyle);
5142 :
5143 : // Create the anonymous inner wrapper frame
5144 13 : nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
5145 :
5146 0 : InitAndRestoreFrame(aState, content, newFrame, innerFrame);
5147 :
5148 : // Put the newly created frames into the right child list
5149 13 : SetInitialSingleChild(newFrame, innerFrame);
5150 :
5151 0 : aState.AddChild(newFrame, aFrameItems, content, aParentFrame,
5152 13 : aCandidateRootFrame, aCandidateRootFrame);
5153 :
5154 0 : if (!mRootElementFrame && aCandidateRootFrame) {
5155 : // The frame we're constructing will be the root element frame.
5156 : // Set mRootElementFrame before processing children.
5157 0 : mRootElementFrame = newFrame;
5158 : }
5159 :
5160 13 : nsFrameItems childItems;
5161 :
5162 : // Process children
5163 26 : NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
5164 : "nsIAnonymousContentCreator::CreateAnonymousContent should not "
5165 : "be implemented for frames for which we explicitly create an "
5166 : "anonymous child to wrap its child frames");
5167 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
5168 0 : ConstructFramesFromItemList(aState, aItem.mChildItems,
5169 : innerFrame,
5170 0 : aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
5171 0 : childItems);
5172 : } else {
5173 13 : ProcessChildren(aState, content, computedStyle, innerFrame,
5174 0 : true, childItems, false, aItem.mPendingBinding);
5175 : }
5176 :
5177 : // Set the inner wrapper frame's initial primary list
5178 0 : innerFrame->SetInitialChildList(kPrincipalList, childItems);
5179 :
5180 13 : return newFrame;
5181 : }
5182 :
5183 : nsIFrame*
5184 0 : nsCSSFrameConstructor::ConstructOuterSVG(nsFrameConstructorState& aState,
5185 : FrameConstructionItem& aItem,
5186 : nsContainerFrame* aParentFrame,
5187 : const nsStyleDisplay* aDisplay,
5188 : nsFrameItems& aFrameItems)
5189 : {
5190 13 : return ConstructFrameWithAnonymousChild(
5191 : aState, aItem, aParentFrame, aFrameItems,
5192 : NS_NewSVGOuterSVGFrame, NS_NewSVGOuterSVGAnonChildFrame,
5193 13 : nsCSSAnonBoxes::mozSVGOuterSVGAnonChild, true);
5194 : }
5195 :
5196 : nsIFrame*
5197 0 : nsCSSFrameConstructor::ConstructMarker(nsFrameConstructorState& aState,
5198 : FrameConstructionItem& aItem,
5199 : nsContainerFrame* aParentFrame,
5200 : const nsStyleDisplay* aDisplay,
5201 : nsFrameItems& aFrameItems)
5202 : {
5203 0 : return ConstructFrameWithAnonymousChild(
5204 : aState, aItem, aParentFrame, aFrameItems,
5205 : NS_NewSVGMarkerFrame, NS_NewSVGMarkerAnonChildFrame,
5206 0 : nsCSSAnonBoxes::mozSVGMarkerAnonChild, false);
5207 : }
5208 :
5209 : // Only outer <svg> elements can be floated or positioned. All other SVG
5210 : // should be in-flow.
5211 : #define SIMPLE_SVG_FCDATA(_func) \
5212 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
5213 : FCDATA_SKIP_ABSPOS_PUSH | \
5214 : FCDATA_DISALLOW_GENERATED_CONTENT, _func)
5215 : #define SIMPLE_SVG_CREATE(_tag, _func) \
5216 : { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
5217 :
5218 : static bool
5219 0 : IsFilterPrimitiveChildTag(const nsAtom* aTag)
5220 : {
5221 0 : return aTag == nsGkAtoms::feDistantLight ||
5222 0 : aTag == nsGkAtoms::fePointLight ||
5223 30 : aTag == nsGkAtoms::feSpotLight ||
5224 30 : aTag == nsGkAtoms::feFuncR ||
5225 30 : aTag == nsGkAtoms::feFuncG ||
5226 30 : aTag == nsGkAtoms::feFuncB ||
5227 0 : aTag == nsGkAtoms::feFuncA ||
5228 30 : aTag == nsGkAtoms::feMergeNode;
5229 : }
5230 :
5231 : /* static */
5232 : const nsCSSFrameConstructor::FrameConstructionData*
5233 145 : nsCSSFrameConstructor::FindSVGData(Element* aElement,
5234 : nsAtom* aTag,
5235 : int32_t aNameSpaceID,
5236 : nsIFrame* aParentFrame,
5237 : bool aIsWithinSVGText,
5238 : bool aAllowsTextPathChild,
5239 : ComputedStyle* aComputedStyle)
5240 : {
5241 145 : if (aNameSpaceID != kNameSpaceID_SVG) {
5242 : return nullptr;
5243 : }
5244 :
5245 : static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
5246 : static const FrameConstructionData sContainerData =
5247 : SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
5248 :
5249 15 : bool parentIsSVG = aIsWithinSVGText;
5250 : nsIContent* parentContent =
5251 30 : aParentFrame ? aParentFrame->GetContent() : nullptr;
5252 :
5253 : // XXXbz should this really be based on the tag of the parent frame's content?
5254 : // Should it not be based on the type of the parent frame (e.g. whether it's
5255 : // an SVG frame)?
5256 0 : if (parentContent) {
5257 : // It's not clear whether the SVG spec intends to allow any SVG
5258 : // content within svg:foreignObject at all (SVG 1.1, section
5259 : // 23.2), but if it does, it better be svg:svg. So given that
5260 : // we're allowing it, treat it as a non-SVG parent.
5261 : parentIsSVG =
5262 0 : parentContent->IsSVGElement() &&
5263 30 : parentContent->NodeInfo()->NameAtom() != nsGkAtoms::foreignObject;
5264 : }
5265 :
5266 30 : if ((aTag != nsGkAtoms::svg && !parentIsSVG) ||
5267 45 : (aTag == nsGkAtoms::desc || aTag == nsGkAtoms::title ||
5268 15 : aTag == nsGkAtoms::metadata)) {
5269 : // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
5270 : // svg:svg not contained within svg:svg are incorrect, although they
5271 : // don't seem to specify error handling. Ignore them, since many of
5272 : // our frame classes can't deal. It *may* be that the document
5273 : // should at that point be considered in error according to F.2, but
5274 : // it's hard to tell.
5275 : //
5276 : // Style mutation can't change this situation, so don't bother
5277 : // adding to the undisplayed content map.
5278 : //
5279 : // We don't currently handle any UI for desc/title/metadata
5280 : return &sSuppressData;
5281 : }
5282 :
5283 : // We don't need frames for animation elements
5284 15 : if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
5285 : return &sSuppressData;
5286 : }
5287 :
5288 15 : if (aTag == nsGkAtoms::svg && !parentIsSVG) {
5289 : // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
5290 : // of whether they fail conditional processing attributes, since various
5291 : // SVG frames assume that one exists. We handle the non-rendering
5292 : // of failing outer <svg> element contents like <switch> statements,
5293 : // and do the PassesConditionalProcessingTests call in
5294 : // nsSVGOuterSVGFrame::Init.
5295 : static const FrameConstructionData sOuterSVGData =
5296 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
5297 : return &sOuterSVGData;
5298 : }
5299 :
5300 0 : if (aTag == nsGkAtoms::marker) {
5301 : static const FrameConstructionData sMarkerSVGData =
5302 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructMarker);
5303 : return &sMarkerSVGData;
5304 : }
5305 :
5306 30 : nsCOMPtr<SVGTests> tests(do_QueryInterface(aElement));
5307 15 : if (tests && !tests->PassesConditionalProcessingTests()) {
5308 : // Elements with failing conditional processing attributes never get
5309 : // rendered. Note that this is not where we select which frame in a
5310 : // <switch> to render! That happens in nsSVGSwitchFrame::PaintSVG.
5311 0 : if (aIsWithinSVGText) {
5312 : // SVGTextFrame doesn't handle conditional processing attributes,
5313 : // so don't create frames for descendants of <text> with failing
5314 : // attributes. We need frames not to be created so that text layout
5315 : // is correct.
5316 : return &sSuppressData;
5317 : }
5318 : // If we're not inside <text>, create an nsSVGContainerFrame (which is a
5319 : // frame that doesn't render) so that paint servers can still be referenced,
5320 : // even if they live inside an element with failing conditional processing
5321 : // attributes.
5322 0 : return &sContainerData;
5323 : }
5324 :
5325 : // Ensure that a stop frame is a child of a gradient and that gradients
5326 : // can only have stop children.
5327 : bool parentIsGradient =
5328 30 : aParentFrame && (aParentFrame->IsSVGLinearGradientFrame() ||
5329 30 : aParentFrame->IsSVGRadialGradientFrame());
5330 15 : bool stop = (aTag == nsGkAtoms::stop);
5331 15 : if ((parentIsGradient && !stop) ||
5332 : (!parentIsGradient && stop)) {
5333 : return &sSuppressData;
5334 : }
5335 :
5336 : // Prevent bad frame types being children of filters or parents of filter
5337 : // primitives. If aParentFrame is null, we know that the frame that will
5338 : // be created will be an nsInlineFrame, so it can never be a filter.
5339 15 : bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
5340 15 : bool filterPrimitive = aElement->IsNodeOfType(nsINode::eFILTER);
5341 15 : if ((parentIsFilter && !filterPrimitive) ||
5342 : (!parentIsFilter && filterPrimitive)) {
5343 : return &sSuppressData;
5344 : }
5345 :
5346 : // Prevent bad frame types being children of filter primitives or parents of
5347 : // filter primitive children. If aParentFrame is null, we know that the frame
5348 : // that will be created will be an nsInlineFrame, so it can never be a filter
5349 : // primitive.
5350 : bool parentIsFEContainerFrame =
5351 15 : aParentFrame && aParentFrame->IsSVGFEContainerFrame();
5352 30 : if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(aTag)) ||
5353 15 : (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(aTag))) {
5354 : return &sSuppressData;
5355 : }
5356 :
5357 : // Special cases for text/tspan/textPath, because the kind of frame
5358 : // they get depends on the parent frame. We ignore 'a' elements when
5359 : // determining the parent, however.
5360 15 : if (aIsWithinSVGText) {
5361 : // If aIsWithinSVGText is true, then we know that the "SVG text uses
5362 : // CSS frames" pref was true when this SVG fragment was first constructed.
5363 :
5364 : // We don't use ConstructInline because we want different behavior
5365 : // for generated content.
5366 : static const FrameConstructionData sTSpanData =
5367 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |
5368 : FCDATA_SKIP_ABSPOS_PUSH |
5369 : FCDATA_DISALLOW_GENERATED_CONTENT |
5370 : FCDATA_IS_LINE_PARTICIPANT |
5371 : FCDATA_IS_INLINE |
5372 : FCDATA_USE_CHILD_ITEMS,
5373 : NS_NewInlineFrame);
5374 0 : if (aTag == nsGkAtoms::textPath) {
5375 0 : if (aAllowsTextPathChild) {
5376 : return &sTSpanData;
5377 : }
5378 0 : } else if (aTag == nsGkAtoms::tspan ||
5379 0 : aTag == nsGkAtoms::a) {
5380 : return &sTSpanData;
5381 : }
5382 0 : return &sSuppressData;
5383 30 : } else if (aTag == nsGkAtoms::tspan ||
5384 15 : aTag == nsGkAtoms::textPath) {
5385 : return &sSuppressData;
5386 : }
5387 :
5388 : static const FrameConstructionDataByTag sSVGData[] = {
5389 : SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
5390 : SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
5391 : SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
5392 : SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame),
5393 : SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame),
5394 : SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame),
5395 : SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame),
5396 : SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame),
5397 : SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame),
5398 : SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame),
5399 : SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame),
5400 : SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
5401 : SIMPLE_SVG_CREATE(generic_, NS_NewSVGGenericContainerFrame),
5402 : { &nsGkAtoms::text,
5403 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW |
5404 : FCDATA_ALLOW_BLOCK_STYLES,
5405 : NS_NewSVGTextFrame,
5406 : nsCSSAnonBoxes::mozSVGText) },
5407 : { &nsGkAtoms::foreignObject,
5408 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW,
5409 : NS_NewSVGForeignObjectFrame,
5410 : nsCSSAnonBoxes::mozSVGForeignContent) },
5411 : SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
5412 : SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
5413 : SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
5414 : SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
5415 : SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
5416 : SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame),
5417 : SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
5418 : SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
5419 : SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
5420 : SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
5421 : SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
5422 : SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
5423 : SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
5424 : SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
5425 : SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
5426 : SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
5427 : SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
5428 : SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
5429 : SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
5430 : SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
5431 : SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
5432 : SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
5433 : SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
5434 : SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
5435 : SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
5436 : SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
5437 : SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
5438 : SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
5439 : SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
5440 : SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
5441 : SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
5442 : SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
5443 : SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
5444 : SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
5445 : SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
5446 : SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)
5447 : };
5448 :
5449 : const FrameConstructionData* data =
5450 : FindDataByTag(aTag, aElement, aComputedStyle, sSVGData,
5451 15 : ArrayLength(sSVGData));
5452 :
5453 15 : if (!data) {
5454 0 : data = &sContainerData;
5455 : }
5456 :
5457 : return data;
5458 : }
5459 :
5460 : void
5461 0 : nsCSSFrameConstructor::AddPageBreakItem(nsIContent* aContent,
5462 : FrameConstructionItemList& aItems)
5463 : {
5464 : RefPtr<ComputedStyle> pseudoStyle =
5465 0 : mPresShell->StyleSet()->
5466 0 : ResolveNonInheritingAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak);
5467 :
5468 0 : MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,
5469 : "Unexpected display");
5470 :
5471 : static const FrameConstructionData sPageBreakData =
5472 : FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
5473 :
5474 : aItems.AppendItem(this, &sPageBreakData, aContent, nullptr,
5475 0 : pseudoStyle.forget(), true, nullptr);
5476 0 : }
5477 :
5478 : bool
5479 419 : nsCSSFrameConstructor::ShouldCreateItemsForChild(nsFrameConstructorState& aState,
5480 : nsIContent* aContent,
5481 : nsContainerFrame* aParentFrame)
5482 : {
5483 419 : aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
5484 : // XXX the GetContent() != aContent check is needed due to bug 135040.
5485 : // Remove it once that's fixed.
5486 838 : if (aContent->GetPrimaryFrame() &&
5487 419 : aContent->GetPrimaryFrame()->GetContent() == aContent &&
5488 0 : !aState.mCreatingExtraFrames) {
5489 : // This condition is known to be reachable for listitems, assert fatally
5490 : // elsewhere.
5491 0 : MOZ_ASSERT(MaybeGetListBoxBodyFrame(aContent),
5492 : "asked to create frame construction item for a node that "
5493 : "already has a frame");
5494 0 : NS_ERROR("asked to create frame construction item for a node that already "
5495 : "has a frame");
5496 0 : return false;
5497 : }
5498 :
5499 : // don't create a whitespace frame if aParent doesn't want it
5500 419 : if (!NeedFrameFor(aState, aParentFrame, aContent)) {
5501 : return false;
5502 : }
5503 :
5504 : // never create frames for comments or PIs
5505 419 : if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
5506 : return false;
5507 : }
5508 :
5509 415 : return true;
5510 : }
5511 :
5512 : void
5513 415 : nsCSSFrameConstructor::DoAddFrameConstructionItems(nsFrameConstructorState& aState,
5514 : nsIContent* aContent,
5515 : ComputedStyle* aComputedStyle,
5516 : bool aSuppressWhiteSpaceOptimizations,
5517 : nsContainerFrame* aParentFrame,
5518 : nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
5519 : FrameConstructionItemList& aItems)
5520 : {
5521 0 : uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
5522 0 : if (aParentFrame) {
5523 415 : if (nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
5524 0 : flags |= ITEM_IS_WITHIN_SVG_TEXT;
5525 : }
5526 441 : if (aParentFrame->IsBlockFrame() && aParentFrame->GetParent() &&
5527 26 : aParentFrame->GetParent()->IsSVGTextFrame()) {
5528 0 : flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
5529 : }
5530 : }
5531 415 : AddFrameConstructionItemsInternal(aState, aContent, aParentFrame,
5532 : aSuppressWhiteSpaceOptimizations,
5533 : aComputedStyle,
5534 : flags, aAnonChildren,
5535 415 : aItems);
5536 415 : }
5537 :
5538 : void
5539 0 : nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState,
5540 : nsIContent* aContent,
5541 : bool aSuppressWhiteSpaceOptimizations,
5542 : const InsertionPoint& aInsertion,
5543 : FrameConstructionItemList& aItems)
5544 : {
5545 419 : nsContainerFrame* parentFrame = aInsertion.mParentFrame;
5546 0 : if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
5547 4 : return;
5548 : }
5549 1245 : RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
5550 830 : DoAddFrameConstructionItems(aState, aContent, computedStyle,
5551 : aSuppressWhiteSpaceOptimizations, parentFrame,
5552 415 : nullptr, aItems);
5553 : }
5554 :
5555 : // Whether we should suppress frames for a child under a <select> frame.
5556 : //
5557 : // Never create frames for non-option/optgroup kids of <select> and non-option
5558 : // kids of <optgroup> inside a <select>.
5559 : // XXXbz it's not clear how this should best work with XBL.
5560 : static bool
5561 300 : ShouldSuppressFrameInSelect(const nsIContent* aParent,
5562 : const nsIContent* aChild)
5563 : {
5564 600 : if (!aParent ||
5565 300 : !aParent->IsAnyOfHTMLElements(nsGkAtoms::select, nsGkAtoms::optgroup)) {
5566 : return false;
5567 : }
5568 :
5569 : // If we're in any display: contents subtree, just suppress the frame.
5570 : //
5571 : // We can't be regular NAC, since display: contents has no frame to generate
5572 : // them off.
5573 0 : if (aChild->GetParent() != aParent) {
5574 : return true;
5575 : }
5576 :
5577 : // Option is always fine.
5578 0 : if (aChild->IsHTMLElement(nsGkAtoms::option)) {
5579 : return false;
5580 : }
5581 :
5582 : // <optgroup> is OK in <select> but not in <optgroup>.
5583 0 : if (aChild->IsHTMLElement(nsGkAtoms::optgroup) &&
5584 0 : aParent->IsHTMLElement(nsGkAtoms::select)) {
5585 : return false;
5586 : }
5587 :
5588 : // Allow native anonymous content no matter what.
5589 0 : if (aChild->IsRootOfAnonymousSubtree()) {
5590 : return false;
5591 : }
5592 :
5593 0 : return true;
5594 : }
5595 :
5596 : static bool
5597 300 : ShouldSuppressFrameInNonOpenDetails(const HTMLDetailsElement* aDetails,
5598 : const nsIContent* aChild)
5599 : {
5600 300 : if (!aDetails || aDetails->Open()) {
5601 : return false;
5602 : }
5603 :
5604 0 : if (aChild->GetParent() != aDetails) {
5605 : return true;
5606 : }
5607 :
5608 0 : auto* summary = HTMLSummaryElement::FromNode(aChild);
5609 0 : if (summary && summary->IsMainSummary()) {
5610 : return false;
5611 : }
5612 :
5613 : // Don't suppress NAC, unless it's ::before or ::after.
5614 0 : if (aChild->IsRootOfAnonymousSubtree() &&
5615 0 : !aChild->IsGeneratedContentContainerForBefore() &&
5616 0 : !aChild->IsGeneratedContentContainerForAfter()) {
5617 : return false;
5618 : }
5619 :
5620 0 : return true;
5621 : }
5622 :
5623 : void
5624 506 : nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
5625 : nsIContent* aContent,
5626 : nsContainerFrame* aParentFrame,
5627 : bool aSuppressWhiteSpaceOptimizations,
5628 : ComputedStyle* aComputedStyle,
5629 : uint32_t aFlags,
5630 : nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
5631 : FrameConstructionItemList& aItems)
5632 : {
5633 969 : MOZ_ASSERT(aContent->IsText() || aContent->IsElement(),
5634 : "Shouldn't get anything else here!");
5635 506 : MOZ_ASSERT(aContent->IsInComposedDoc());
5636 0 : MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
5637 : aContent->NodeInfo()->NameAtom() == nsGkAtoms::area);
5638 :
5639 : // The following code allows the user to specify the base tag
5640 : // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
5641 : // can then be extended arbitrarily.
5642 0 : const nsStyleDisplay* display = aComputedStyle->StyleDisplay();
5643 778 : RefPtr<ComputedStyle> computedStyle(aComputedStyle);
5644 506 : PendingBinding* pendingBinding = nullptr;
5645 0 : nsAtom* tag = aContent->NodeInfo()->NameAtom();
5646 0 : int32_t namespaceId = aContent->GetNameSpaceID();
5647 0 : if (aFlags & ITEM_ALLOW_XBL_BASE) {
5648 1004 : if (display->mBinding) {
5649 : // Ensure that our XBL bindings are installed.
5650 :
5651 0 : nsXBLService* xblService = nsXBLService::GetInstance();
5652 146 : if (!xblService)
5653 0 : return;
5654 :
5655 : bool resolveStyle;
5656 :
5657 0 : nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
5658 :
5659 584 : nsresult rv = xblService->LoadBindings(
5660 0 : aContent->AsElement(), display->mBinding->GetURI(),
5661 0 : display->mBinding->mExtraData->GetPrincipal(),
5662 438 : getter_AddRefs(newPendingBinding->mBinding), &resolveStyle);
5663 0 : if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
5664 0 : return;
5665 :
5666 0 : if (newPendingBinding->mBinding) {
5667 119 : pendingBinding = newPendingBinding;
5668 : // aState takes over owning newPendingBinding
5669 119 : aState.AddPendingBinding(newPendingBinding.forget());
5670 : }
5671 :
5672 0 : if (resolveStyle) {
5673 : computedStyle =
5674 160 : mPresShell->StyleSet()->ResolveServoStyle(aContent->AsElement());
5675 : }
5676 :
5677 0 : display = computedStyle->StyleDisplay();
5678 0 : aComputedStyle = computedStyle;
5679 0 : if (namespaceId == kNameSpaceID_XUL) {
5680 : // Only allow overriding from & to XUL.
5681 : int32_t overridenNamespace;
5682 : nsAtom* overridenTag =
5683 290 : mDocument->BindingManager()->ResolveTag(aContent, &overridenNamespace);
5684 145 : if (overridenNamespace == kNameSpaceID_XUL) {
5685 0 : tag = overridenTag;
5686 : }
5687 : }
5688 : }
5689 : }
5690 :
5691 0 : const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
5692 0 : MOZ_ASSERT(!isGeneratedContent || computedStyle->GetPseudo(),
5693 : "Generated content should be a pseudo-element");
5694 :
5695 0 : FrameConstructionItem* item = nullptr;
5696 506 : auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
5697 0 : if (isGeneratedContent && !item) {
5698 0 : MOZ_ASSERT(!IsDisplayContents(aContent),
5699 : "This would need to change if we support display: contents "
5700 : "in generated content");
5701 0 : aContent->UnbindFromTree();
5702 : }
5703 1284 : });
5704 :
5705 : // Pre-check for display "none" - if we find that, don't create
5706 : // any frame at all
5707 506 : if (display->mDisplay == StyleDisplay::None) {
5708 0 : return;
5709 : }
5710 :
5711 0 : if (display->mDisplay == StyleDisplay::Contents) {
5712 0 : CreateGeneratedContentItem(aState, aParentFrame, aContent->AsElement(),
5713 : computedStyle, CSSPseudoElementType::before,
5714 0 : aItems);
5715 :
5716 0 : FlattenedChildIterator iter(aContent);
5717 0 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
5718 0 : if (!ShouldCreateItemsForChild(aState, child, aParentFrame)) {
5719 0 : continue;
5720 : }
5721 :
5722 0 : RefPtr<ComputedStyle> childContext = ResolveComputedStyle(child);
5723 0 : DoAddFrameConstructionItems(aState, child, childContext,
5724 : aSuppressWhiteSpaceOptimizations,
5725 0 : aParentFrame, aAnonChildren, aItems);
5726 : }
5727 0 : aItems.SetParentHasNoXBLChildren(!iter.XBLInvolved());
5728 :
5729 0 : CreateGeneratedContentItem(aState, aParentFrame, aContent->AsElement(),
5730 : computedStyle, CSSPseudoElementType::after,
5731 0 : aItems);
5732 : return;
5733 : }
5734 :
5735 600 : nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
5736 300 : if (ShouldSuppressFrameInSelect(parent, aContent)) {
5737 : return;
5738 : }
5739 :
5740 : // When constructing a child of a non-open <details>, create only the frame
5741 : // for the main <summary> element, and skip other elements. This only applies
5742 : // to things that are not roots of native anonymous subtrees (except for
5743 : // ::before and ::after); we always want to create "internal" anonymous
5744 : // content.
5745 0 : auto* details = HTMLDetailsElement::FromNodeOrNull(parent);
5746 300 : if (ShouldSuppressFrameInNonOpenDetails(details, aContent)) {
5747 : return;
5748 : }
5749 :
5750 0 : bool isPopup = false;
5751 600 : const bool isText = !aContent->IsElement();
5752 : // Try to find frame construction data for this content
5753 : const FrameConstructionData* data;
5754 300 : if (isText) {
5755 0 : data = FindTextData(aParentFrame, aContent);
5756 43 : if (!data) {
5757 : // Nothing to do here; suppressed text inside SVG
5758 : return;
5759 : }
5760 : } else {
5761 0 : Element* element = aContent->AsElement();
5762 :
5763 : // Don't create frames for non-SVG element children of SVG elements.
5764 514 : if (namespaceId != kNameSpaceID_SVG &&
5765 242 : ((aParentFrame &&
5766 0 : IsFrameForSVG(aParentFrame) &&
5767 242 : !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) ||
5768 0 : (aFlags & ITEM_IS_WITHIN_SVG_TEXT))) {
5769 : return;
5770 : }
5771 :
5772 0 : data = FindHTMLData(element, tag, namespaceId, aParentFrame,
5773 : computedStyle);
5774 0 : if (!data) {
5775 0 : data = FindXULTagData(element, tag, namespaceId, computedStyle);
5776 : }
5777 0 : if (!data) {
5778 145 : data = FindMathMLData(element, tag, namespaceId, computedStyle);
5779 : }
5780 257 : if (!data) {
5781 435 : data = FindSVGData(element, tag, namespaceId, aParentFrame,
5782 0 : aFlags & ITEM_IS_WITHIN_SVG_TEXT,
5783 0 : aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
5784 : computedStyle);
5785 : }
5786 :
5787 : // Now check for XUL display types
5788 0 : if (!data) {
5789 130 : data = FindXULDisplayData(display, element, computedStyle);
5790 : }
5791 :
5792 : // And general display types
5793 0 : if (!data) {
5794 10 : data = FindDisplayData(display, element, computedStyle);
5795 : }
5796 :
5797 257 : MOZ_ASSERT(data, "Should have frame construction data now");
5798 :
5799 0 : if (data->mBits & FCDATA_SUPPRESS_FRAME) {
5800 : return;
5801 : }
5802 :
5803 : #ifdef MOZ_XUL
5804 514 : if ((data->mBits & FCDATA_IS_POPUP) &&
5805 37 : (!aParentFrame || // Parent is inline
5806 37 : !aParentFrame->IsMenuFrame())) {
5807 24 : if (!aState.mPopupItems.containingBlock &&
5808 1 : !aState.mHavePendingPopupgroup) {
5809 : return;
5810 : }
5811 :
5812 : isPopup = true;
5813 : }
5814 : #endif /* MOZ_XUL */
5815 : }
5816 :
5817 272 : uint32_t bits = data->mBits;
5818 :
5819 : // Inside colgroups, suppress everything except columns.
5820 544 : if (aParentFrame && aParentFrame->IsTableColGroupFrame() &&
5821 0 : (!(bits & FCDATA_IS_TABLE_PART) ||
5822 0 : display->mDisplay != StyleDisplay::TableColumn)) {
5823 : return;
5824 : }
5825 :
5826 : bool canHavePageBreak =
5827 0 : (aFlags & ITEM_ALLOW_PAGE_BREAK) && aState.mPresContext->IsPaginated() &&
5828 0 : !display->IsAbsolutelyPositionedStyle() &&
5829 0 : !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
5830 0 : !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
5831 :
5832 0 : if (canHavePageBreak && display->mBreakBefore) {
5833 0 : AddPageBreakItem(aContent, aItems);
5834 : }
5835 :
5836 0 : if (details && details->Open()) {
5837 0 : auto* summary = HTMLSummaryElement::FromNode(aContent);
5838 0 : if (summary && summary->IsMainSummary()) {
5839 : // If details is open, the main summary needs to be rendered as if it is
5840 : // the first child, so add the item to the front of the item list.
5841 0 : item = aItems.PrependItem(this, data, aContent, pendingBinding,
5842 0 : computedStyle.forget(),
5843 : aSuppressWhiteSpaceOptimizations,
5844 : aAnonChildren);
5845 : }
5846 : }
5847 :
5848 0 : if (!item) {
5849 0 : item = aItems.AppendItem(this, data, aContent, pendingBinding,
5850 0 : computedStyle.forget(),
5851 : aSuppressWhiteSpaceOptimizations, aAnonChildren);
5852 : }
5853 272 : item->mIsText = isText;
5854 0 : item->mIsGeneratedContent = isGeneratedContent;
5855 272 : item->mIsAnonymousContentCreatorContent =
5856 0 : aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
5857 0 : if (isGeneratedContent) {
5858 : // We need to keep this alive until the frame takes ownership.
5859 : // This corresponds to the Release in ConstructFramesFromItem.
5860 0 : item->mContent->AddRef();
5861 : }
5862 0 : item->mIsRootPopupgroup =
5863 0 : namespaceId == kNameSpaceID_XUL && tag == nsGkAtoms::popupgroup &&
5864 0 : aContent->IsRootOfNativeAnonymousSubtree();
5865 272 : if (item->mIsRootPopupgroup) {
5866 0 : aState.mHavePendingPopupgroup = true;
5867 : }
5868 272 : item->mIsPopup = isPopup;
5869 287 : item->mIsForSVGAElement = namespaceId == kNameSpaceID_SVG &&
5870 0 : tag == nsGkAtoms::a;
5871 :
5872 272 : if (canHavePageBreak && display->mBreakAfter) {
5873 0 : AddPageBreakItem(aContent, aItems);
5874 : }
5875 :
5876 0 : if (bits & FCDATA_IS_INLINE) {
5877 : // To correctly set item->mIsAllInline we need to build up our child items
5878 : // right now.
5879 0 : BuildInlineChildItems(aState, *item,
5880 0 : aFlags & ITEM_IS_WITHIN_SVG_TEXT,
5881 0 : aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD);
5882 0 : item->mHasInlineEnds = true;
5883 0 : item->mIsBlock = false;
5884 : } else {
5885 : // Compute a boolean isInline which is guaranteed to be false for blocks
5886 : // (but may also be false for some inlines).
5887 : bool isInline =
5888 : // Table-internal things are inline-outside if and only if they're kids of
5889 : // inlines, since they'll trigger construction of inline-table
5890 : // pseudos.
5891 0 : ((bits & FCDATA_IS_TABLE_PART) &&
5892 0 : (!aParentFrame || // No aParentFrame means inline
5893 272 : aParentFrame->StyleDisplay()->mDisplay == StyleDisplay::Inline)) ||
5894 : // Things that are inline-outside but aren't inline frames are inline
5895 777 : display->IsInlineOutsideStyle() ||
5896 : // Popups that are certainly out of flow.
5897 0 : isPopup;
5898 :
5899 : // Set mIsAllInline conservatively. It just might be that even an inline
5900 : // that has mIsAllInline false doesn't need an {ib} split. So this is just
5901 : // an optimization to keep from doing too much work in cases when we can
5902 : // show that mIsAllInline is true..
5903 754 : item->mIsAllInline = item->mHasInlineEnds = isInline ||
5904 : // Figure out whether we're guaranteed this item will be out of flow.
5905 : // This is not a precise test, since one of our ancestor inlines might add
5906 : // an absolute containing block (if it's relatively positioned) when there
5907 : // wasn't such a containing block before. But it's conservative in the
5908 : // sense that anything that will really end up as an in-flow non-inline
5909 : // will test false here. In other words, if this test is true we're
5910 : // guaranteed to be inline; if it's false we don't know what we'll end up
5911 : // as.
5912 : //
5913 : // If we make this test precise, we can remove some of the code dealing
5914 : // with the imprecision in ConstructInline and adjust the comments on
5915 : // mIsAllInline and mIsBlock in the header. And probably remove mIsBlock
5916 : // altogether, since then it will always be equal to !mHasInlineEnds.
5917 218 : (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
5918 8 : aState.GetGeometricParent(display, nullptr));
5919 :
5920 : // Set mIsBlock conservatively. It's OK to set it false for some real
5921 : // blocks, but not OK to set it true for things that aren't blocks. Since
5922 : // isOutOfFlow might be false even in cases when the frame will end up
5923 : // out-of-flow, we can't use it here. But we _can_ say that the frame will
5924 : // for sure end up in-flow if it's not floated or absolutely positioned.
5925 0 : item->mIsBlock = !isInline &&
5926 0 : !display->IsAbsolutelyPositionedStyle() &&
5927 0 : !display->IsFloatingStyle() &&
5928 0 : !(bits & FCDATA_IS_SVG_TEXT);
5929 : }
5930 :
5931 272 : if (item->mIsAllInline) {
5932 67 : aItems.InlineItemAdded();
5933 205 : } else if (item->mIsBlock) {
5934 205 : aItems.BlockItemAdded();
5935 : }
5936 :
5937 : // Our item should be treated as a line participant if we have the relevant
5938 : // bit and are going to be in-flow. Note that this really only matters if
5939 : // our ancestor is a box or some such, so the fact that we might have an
5940 : // inline ancestor that might become a containing block is not relevant here.
5941 560 : if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
5942 32 : ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
5943 16 : !aState.GetGeometricParent(display, nullptr))) {
5944 16 : item->mIsLineParticipant = true;
5945 16 : aItems.LineParticipantItemAdded();
5946 : }
5947 : }
5948 :
5949 : /**
5950 : * Return true if the frame construction item pointed to by aIter will
5951 : * create a frame adjacent to a line boundary in the frame tree, and that
5952 : * line boundary is induced by a content node adjacent to the frame's
5953 : * content node in the content tree. The latter condition is necessary so
5954 : * that ContentAppended/ContentInserted/ContentRemoved can easily find any
5955 : * text nodes that were suppressed here.
5956 : */
5957 : bool
5958 0 : nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter)
5959 : {
5960 0 : if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5961 : return false;
5962 : }
5963 :
5964 0 : if (aIter.AtStart()) {
5965 0 : if (aIter.List()->HasLineBoundaryAtStart() &&
5966 0 : !aIter.item().mContent->GetPreviousSibling())
5967 : return true;
5968 : } else {
5969 1 : FCItemIterator prev = aIter;
5970 1 : prev.Prev();
5971 0 : if (prev.item().IsLineBoundary() &&
5972 0 : !prev.item().mSuppressWhiteSpaceOptimizations &&
5973 0 : aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
5974 0 : return true;
5975 : }
5976 :
5977 10 : FCItemIterator next = aIter;
5978 0 : next.Next();
5979 0 : if (next.IsDone()) {
5980 0 : if (aIter.List()->HasLineBoundaryAtEnd() &&
5981 2 : !aIter.item().mContent->GetNextSibling())
5982 : return true;
5983 : } else {
5984 8 : if (next.item().IsLineBoundary() &&
5985 5 : !next.item().mSuppressWhiteSpaceOptimizations &&
5986 2 : aIter.item().mContent->GetNextSibling() == next.item().mContent)
5987 : return true;
5988 : }
5989 :
5990 : return false;
5991 : }
5992 :
5993 : void
5994 0 : nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
5995 : FCItemIterator& aIter,
5996 : nsContainerFrame* aParentFrame,
5997 : nsFrameItems& aFrameItems)
5998 : {
5999 272 : nsContainerFrame* adjParentFrame = aParentFrame;
6000 272 : FrameConstructionItem& item = aIter.item();
6001 544 : ComputedStyle* computedStyle = item.mComputedStyle;
6002 272 : AdjustParentFrame(&adjParentFrame, item.mFCData, computedStyle);
6003 :
6004 272 : if (item.mIsText) {
6005 : // If this is collapsible whitespace next to a line boundary,
6006 : // don't create a frame. item.IsWhitespace() also sets the
6007 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
6008 : // end up creating a frame, nsTextFrame::Init will clear the flag.)
6009 : // We don't do this for generated content, because some generated
6010 : // text content is empty text nodes that are about to be initialized.
6011 : // (We check mAdditionalStateBits because only the generated content
6012 : // container's frame construction item is marked with
6013 : // mIsGeneratedContent, and we might not have an aParentFrame.)
6014 : // We don't do it for content that may have XBL anonymous siblings,
6015 : // because they make it difficult to correctly create the frame
6016 : // due to dynamic changes.
6017 : // We don't do it for SVG text, since we might need to position and
6018 : // measure the white space glyphs due to x/y/dx/dy attributes.
6019 0 : if (AtLineBoundary(aIter) &&
6020 0 : !computedStyle->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
6021 0 : aIter.List()->ParentHasNoXBLChildren() &&
6022 14 : !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
6023 0 : (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
6024 6 : !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
6025 0 : !mAlwaysCreateFramesForIgnorableWhitespace &&
6026 0 : item.IsWhitespace(aState))
6027 15 : return;
6028 :
6029 9 : ConstructTextFrame(item.mFCData, aState, item.mContent,
6030 : adjParentFrame, computedStyle,
6031 0 : aFrameItems);
6032 9 : return;
6033 : }
6034 :
6035 : // Start background loads during frame construction so that we're
6036 : // guaranteed that they will be started before onload fires.
6037 0 : computedStyle->StartBackgroundImageLoads();
6038 :
6039 257 : nsFrameState savedStateBits = aState.mAdditionalStateBits;
6040 257 : if (item.mIsGeneratedContent) {
6041 : // Ensure that frames created here are all tagged with
6042 : // NS_FRAME_GENERATED_CONTENT.
6043 0 : aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
6044 : }
6045 :
6046 : // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
6047 257 : ConstructFrameFromItemInternal(item, aState, adjParentFrame, aFrameItems);
6048 :
6049 257 : if (item.mIsGeneratedContent) {
6050 : // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
6051 : // The frame owns the generated content now.
6052 4 : item.mContent->Release();
6053 :
6054 : // Now that we've passed ownership of item.mContent to the frame, unset
6055 : // our generated content flag so we don't release or unbind it ourselves.
6056 4 : item.mIsGeneratedContent = false;
6057 : }
6058 :
6059 257 : aState.mAdditionalStateBits = savedStateBits;
6060 : }
6061 :
6062 :
6063 : inline bool
6064 : IsRootBoxFrame(nsIFrame *aFrame)
6065 : {
6066 : return (aFrame->IsRootFrame());
6067 : }
6068 :
6069 : void
6070 0 : nsCSSFrameConstructor::ReconstructDocElementHierarchy(InsertionKind aInsertionKind)
6071 : {
6072 0 : Element* rootElement = mDocument->GetRootElement();
6073 0 : if (!rootElement) {
6074 : /* nothing to do */
6075 : return;
6076 : }
6077 0 : RecreateFramesForContent(rootElement, aInsertionKind);
6078 : }
6079 :
6080 : nsContainerFrame*
6081 0 : nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame,
6082 : ContainingBlockType aType)
6083 : {
6084 : // Starting with aFrame, look for a frame that is absolutely positioned or
6085 : // relatively positioned (and transformed, if aType is FIXED)
6086 498 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
6087 475 : if (frame->IsFrameOfType(nsIFrame::eMathML)) {
6088 : // If it's mathml, bail out -- no absolute positioning out from inside
6089 : // mathml frames. Note that we don't make this part of the loop
6090 : // condition because of the stuff at the end of this method...
6091 : return nullptr;
6092 : }
6093 :
6094 : // Look for the ICB.
6095 475 : if (aType == FIXED_POS) {
6096 296 : LayoutFrameType t = frame->Type();
6097 296 : if (t == LayoutFrameType::Viewport || t == LayoutFrameType::PageContent) {
6098 : return static_cast<nsContainerFrame*>(frame);
6099 : }
6100 : }
6101 :
6102 : // If the frame is positioned, we will probably return it as the containing
6103 : // block (see the exceptions below). Otherwise, we'll start looking at the
6104 : // parent frame, unless we're dealing with a scrollframe.
6105 : // Scrollframes are special since they're not positioned, but their
6106 : // scrolledframe might be. So, we need to check this special case to return
6107 : // the correct containing block (the scrolledframe) in that case.
6108 : // If we're looking for a fixed-pos containing block and the frame is
6109 : // not transformed, skip it.
6110 0 : if (!frame->IsAbsPosContainingBlock() ||
6111 0 : (aType == FIXED_POS &&
6112 0 : !frame->IsFixedPosContainingBlock())) {
6113 : continue;
6114 : }
6115 14 : nsIFrame* absPosCBCandidate = frame;
6116 0 : LayoutFrameType type = absPosCBCandidate->Type();
6117 14 : if (type == LayoutFrameType::FieldSet) {
6118 0 : absPosCBCandidate = static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
6119 0 : if (!absPosCBCandidate) {
6120 : continue;
6121 : }
6122 0 : type = absPosCBCandidate->Type();
6123 : }
6124 0 : if (type == LayoutFrameType::Scroll) {
6125 0 : nsIScrollableFrame* scrollFrame = do_QueryFrame(absPosCBCandidate);
6126 0 : absPosCBCandidate = scrollFrame->GetScrolledFrame();
6127 0 : if (!absPosCBCandidate) {
6128 : continue;
6129 : }
6130 0 : type = absPosCBCandidate->Type();
6131 : }
6132 : // Only first continuations can be containing blocks.
6133 14 : absPosCBCandidate = absPosCBCandidate->FirstContinuation();
6134 : // Is the frame really an absolute container?
6135 28 : if (!absPosCBCandidate->IsAbsoluteContainer()) {
6136 : continue;
6137 : }
6138 :
6139 : // For tables, skip the inner frame and consider the table wrapper frame.
6140 13 : if (type == LayoutFrameType::Table) {
6141 : continue;
6142 : }
6143 : // For table wrapper frames, we can just return absPosCBCandidate.
6144 13 : MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(absPosCBCandidate),
6145 : "abs.pos. containing block must be nsContainerFrame sub-class");
6146 : return static_cast<nsContainerFrame*>(absPosCBCandidate);
6147 : }
6148 :
6149 23 : MOZ_ASSERT(aType != FIXED_POS, "no ICB in this frame tree?");
6150 :
6151 : // It is possible for the search for the containing block to fail, because
6152 : // no absolute container can be found in the parent chain. In those cases,
6153 : // we fall back to the document element's containing block.
6154 23 : return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr;
6155 : }
6156 :
6157 : nsContainerFrame*
6158 0 : nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
6159 : {
6160 : // Starting with aFrame, look for a frame that is a float containing block.
6161 : // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
6162 : // frames, because they don't seem to be able to deal.
6163 : // The logic here needs to match the logic in ProcessChildren()
6164 220 : for (nsIFrame* containingBlock = aFrame;
6165 207 : containingBlock &&
6166 97 : !ShouldSuppressFloatingOfDescendants(containingBlock);
6167 : containingBlock = containingBlock->GetParent()) {
6168 73 : if (containingBlock->IsFloatContainingBlock()) {
6169 8 : MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(containingBlock),
6170 : "float containing block must be nsContainerFrame sub-class");
6171 : return static_cast<nsContainerFrame*>(containingBlock);
6172 : }
6173 : }
6174 :
6175 : // If we didn't find a containing block, then there just isn't
6176 : // one.... return null
6177 : return nullptr;
6178 : }
6179 :
6180 : /**
6181 : * This function will get the previous sibling to use for an append operation.
6182 : *
6183 : * It takes a parent frame (must not be null) and the next insertion sibling, if
6184 : * the parent content is display: contents or has ::after content (may be null).
6185 : */
6186 : static nsIFrame*
6187 0 : FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
6188 : {
6189 27 : aParentFrame->DrainSelfOverflowList();
6190 :
6191 27 : if (aNextSibling) {
6192 0 : MOZ_ASSERT(aNextSibling->GetParent() == aParentFrame, "Wrong parent");
6193 0 : return aNextSibling->GetPrevSibling();
6194 : }
6195 :
6196 27 : return aParentFrame->GetChildList(kPrincipalList).LastChild();
6197 : }
6198 :
6199 : /**
6200 : * Finds the right parent frame to append content to aParentFrame.
6201 : *
6202 : * Cannot return or receive null.
6203 : */
6204 : static nsContainerFrame*
6205 27 : ContinuationToAppendTo(nsContainerFrame* aParentFrame)
6206 : {
6207 27 : MOZ_ASSERT(aParentFrame);
6208 :
6209 27 : if (IsFramePartOfIBSplit(aParentFrame)) {
6210 : // If the frame we are manipulating is a ib-split frame (that is, one that's
6211 : // been created as a result of a block-in-inline situation) then we need to
6212 : // append to the last ib-split sibling, not to the frame itself.
6213 : //
6214 : // Always make sure to look at the last continuation of the frame for the
6215 : // {ib} case, even if that continuation is empty.
6216 : //
6217 : // We don't do this for the non-ib-split-frame case, since in the other
6218 : // cases appending to the last nonempty continuation is fine and in fact not
6219 : // doing that can confuse code that doesn't know to pull kids from
6220 : // continuations other than its next one.
6221 0 : return static_cast<nsContainerFrame*>(GetLastIBSplitSibling(aParentFrame)->LastContinuation());
6222 : }
6223 :
6224 27 : return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
6225 : }
6226 :
6227 : /**
6228 : * This function will get the next sibling for a frame insert operation given
6229 : * the parent and previous sibling. aPrevSibling may be null.
6230 : */
6231 : static nsIFrame*
6232 0 : GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
6233 : {
6234 29 : if (aPrevSibling) {
6235 9 : return aPrevSibling->GetNextSibling();
6236 : }
6237 :
6238 20 : return aParentFrame->PrincipalChildList().FirstChild();
6239 : }
6240 :
6241 : /**
6242 : * This function is called by ContentAppended() and ContentInserted() when
6243 : * appending flowed frames to a parent's principal child list. It handles the
6244 : * case where the parent is the trailing inline of an {ib} split.
6245 : */
6246 : void
6247 0 : nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aState,
6248 : nsContainerFrame* aParentFrame,
6249 : nsFrameItems& aFrameList,
6250 : nsIFrame* aPrevSibling,
6251 : bool aIsRecursiveCall)
6252 : {
6253 9 : MOZ_ASSERT(!IsFramePartOfIBSplit(aParentFrame) ||
6254 : !GetIBSplitSibling(aParentFrame) ||
6255 : !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild(),
6256 : "aParentFrame has a ib-split sibling with kids?");
6257 9 : MOZ_ASSERT(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
6258 : "Parent and prevsibling don't match");
6259 :
6260 9 : nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
6261 :
6262 9 : NS_ASSERTION(nextSibling ||
6263 : !aParentFrame->GetNextContinuation() ||
6264 : !aParentFrame->GetNextContinuation()->PrincipalChildList().FirstChild() ||
6265 : aIsRecursiveCall,
6266 : "aParentFrame has later continuations with kids?");
6267 9 : NS_ASSERTION(nextSibling ||
6268 : !IsFramePartOfIBSplit(aParentFrame) ||
6269 : (IsInlineFrame(aParentFrame) &&
6270 : !GetIBSplitSibling(aParentFrame) &&
6271 : !aParentFrame->GetNextContinuation()) ||
6272 : aIsRecursiveCall,
6273 : "aParentFrame is not last?");
6274 :
6275 : // If we're inserting a list of frames at the end of the trailing inline
6276 : // of an {ib} split, we may need to create additional {ib} siblings to parent
6277 : // them.
6278 9 : if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
6279 : // When we get here, our frame list might start with a block. If it does
6280 : // so, and aParentFrame is an inline, and it and all its previous
6281 : // continuations have no siblings, then put the initial blocks from the
6282 : // frame list into the previous block of the {ib} split. Note that we
6283 : // didn't want to stop at the block part of the split when figuring out
6284 : // initial parent, because that could screw up float parenting; it's easier
6285 : // to do this little fixup here instead.
6286 0 : if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) {
6287 : // See whether our trailing inline is empty
6288 0 : nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
6289 0 : if (firstContinuation->PrincipalChildList().IsEmpty()) {
6290 : // Our trailing inline is empty. Collect our starting blocks from
6291 : // aFrameList, get the right parent frame for them, and put them in.
6292 : nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator =
6293 0 : FindFirstNonBlock(aFrameList);
6294 0 : nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator);
6295 0 : NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
6296 :
6297 0 : nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
6298 0 : prevBlock = static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
6299 0 : NS_ASSERTION(prevBlock, "Should have previous block here");
6300 :
6301 0 : MoveChildrenTo(aParentFrame, prevBlock, blockKids);
6302 : }
6303 : }
6304 :
6305 : // We want to put some of the frames into this inline frame.
6306 0 : nsFrameList::FrameLinkEnumerator firstBlockEnumerator(aFrameList);
6307 0 : FindFirstBlock(firstBlockEnumerator);
6308 :
6309 0 : nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
6310 0 : if (!inlineKids.IsEmpty()) {
6311 0 : AppendFrames(aParentFrame, kPrincipalList, inlineKids);
6312 : }
6313 :
6314 0 : if (!aFrameList.IsEmpty()) {
6315 0 : bool positioned = aParentFrame->IsRelativelyPositioned();
6316 0 : nsFrameItems ibSiblings;
6317 0 : CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
6318 0 : ibSiblings);
6319 :
6320 : // Make sure to trigger reflow of the inline that used to be our
6321 : // last one and now isn't anymore, since its GetSkipSides() has
6322 : // changed.
6323 0 : mPresShell->FrameNeedsReflow(aParentFrame,
6324 : nsIPresShell::eTreeChange,
6325 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
6326 :
6327 : // Recurse so we create new ib siblings as needed for aParentFrame's parent
6328 0 : return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
6329 0 : aParentFrame, true);
6330 : }
6331 : return;
6332 : }
6333 :
6334 : // Insert the frames after our aPrevSibling
6335 9 : InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
6336 : }
6337 :
6338 : #define UNSET_DISPLAY static_cast<StyleDisplay>(255)
6339 :
6340 : // This gets called to see if the frames corresponding to aSibling and aContent
6341 : // should be siblings in the frame tree. Although (1) rows and cols, (2) row
6342 : // groups and col groups, (3) row groups and captions, (4) legends and content
6343 : // inside fieldsets, (5) popups and other kids of the menu are siblings from a
6344 : // content perspective, they are not considered siblings in the frame tree.
6345 : bool
6346 9 : nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
6347 : nsIContent* aContent,
6348 : StyleDisplay& aDisplay)
6349 : {
6350 0 : nsIFrame* parentFrame = aSibling->GetParent();
6351 0 : LayoutFrameType parentType = parentFrame->Type();
6352 :
6353 0 : StyleDisplay siblingDisplay = aSibling->GetDisplay();
6354 0 : if (StyleDisplay::TableColumnGroup == siblingDisplay ||
6355 9 : StyleDisplay::TableColumn == siblingDisplay ||
6356 9 : StyleDisplay::TableCaption == siblingDisplay ||
6357 0 : StyleDisplay::TableHeaderGroup == siblingDisplay ||
6358 0 : StyleDisplay::TableRowGroup == siblingDisplay ||
6359 18 : StyleDisplay::TableFooterGroup == siblingDisplay ||
6360 9 : LayoutFrameType::Menu == parentType) {
6361 : // if we haven't already, resolve a style to find the display type of
6362 : // aContent.
6363 0 : if (UNSET_DISPLAY == aDisplay) {
6364 0 : if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
6365 : // Comments and processing instructions never have frames, so we should
6366 : // not try to generate styles for them.
6367 0 : return false;
6368 : }
6369 : // FIXME(emilio): This is buggy some times, see bug 1424656.
6370 0 : RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
6371 0 : const nsStyleDisplay* display = computedStyle->StyleDisplay();
6372 0 : aDisplay = display->mDisplay;
6373 : }
6374 0 : if (LayoutFrameType::Menu == parentType) {
6375 : return
6376 0 : (StyleDisplay::MozPopup == aDisplay) ==
6377 0 : (StyleDisplay::MozPopup == siblingDisplay);
6378 : }
6379 : // To have decent performance we want to return false in cases in which
6380 : // reordering the two siblings has no effect on display. To ensure
6381 : // correctness, we MUST return false in cases where the two siblings have
6382 : // the same desired parent type and live on different display lists.
6383 : // Specificaly, columns and column groups should only consider columns and
6384 : // column groups as valid siblings. Captions should only consider other
6385 : // captions. All other things should consider each other as valid
6386 : // siblings. The restriction in the |if| above on siblingDisplay is ok,
6387 : // because for correctness the only part that really needs to happen is to
6388 : // not consider captions, column groups, and row/header/footer groups
6389 : // siblings of each other. Treating a column or colgroup as a valid
6390 : // sibling of a non-table-related frame will just mean we end up reframing.
6391 0 : if ((siblingDisplay == StyleDisplay::TableCaption) !=
6392 0 : (aDisplay == StyleDisplay::TableCaption)) {
6393 : // One's a caption and the other is not. Not valid siblings.
6394 : return false;
6395 : }
6396 :
6397 0 : if ((siblingDisplay == StyleDisplay::TableColumnGroup ||
6398 0 : siblingDisplay == StyleDisplay::TableColumn) !=
6399 0 : (aDisplay == StyleDisplay::TableColumnGroup ||
6400 : aDisplay == StyleDisplay::TableColumn)) {
6401 : // One's a column or column group and the other is not. Not valid
6402 : // siblings.
6403 : return false;
6404 : }
6405 : // Fall through; it's possible that the display type was overridden and
6406 : // a different sort of frame was constructed, so we may need to return false
6407 : // below.
6408 : }
6409 :
6410 0 : if (IsFrameForFieldSet(parentFrame)) {
6411 : // Legends can be sibling of legends but not of other content in the fieldset
6412 0 : if (nsContainerFrame* cif = aSibling->GetContentInsertionFrame()) {
6413 0 : aSibling = cif;
6414 : }
6415 0 : LayoutFrameType sibType = aSibling->Type();
6416 0 : bool legendContent = aContent->IsHTMLElement(nsGkAtoms::legend);
6417 :
6418 0 : if ((legendContent && (LayoutFrameType::Legend != sibType)) ||
6419 : (!legendContent && (LayoutFrameType::Legend == sibType)))
6420 : return false;
6421 : }
6422 :
6423 : return true;
6424 : }
6425 :
6426 : // FIXME(emilio): If we ever kill IsValidSibling() we can simplify this quite a
6427 : // bit (no need to pass aTargetContent or aTargetContentDisplay, and the
6428 : // adjust() calls can be responsibility of the caller).
6429 : template<nsCSSFrameConstructor::SiblingDirection aDirection>
6430 : nsIFrame*
6431 0 : nsCSSFrameConstructor::FindSiblingInternal(
6432 : FlattenedChildIterator& aIter,
6433 : nsIContent* aTargetContent,
6434 : StyleDisplay& aTargetContentDisplay)
6435 : {
6436 42 : auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* {
6437 42 : return AdjustSiblingFrame(
6438 0 : aPotentialSiblingFrame, aTargetContent, aTargetContentDisplay,
6439 42 : aDirection);
6440 42 : };
6441 :
6442 : auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
6443 : return aDirection == SiblingDirection::Forward
6444 0 : ? aIter.GetNextChild() : aIter.GetPreviousChild();
6445 : };
6446 :
6447 : auto getNearPseudo = [](const nsIContent* aContent) -> nsIFrame* {
6448 : return aDirection == SiblingDirection::Forward
6449 : ? nsLayoutUtils::GetBeforeFrame(aContent)
6450 0 : : nsLayoutUtils::GetAfterFrame(aContent);
6451 : };
6452 :
6453 : auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* {
6454 : return aDirection == SiblingDirection::Forward
6455 : ? nsLayoutUtils::GetAfterFrame(aContent)
6456 33 : : nsLayoutUtils::GetBeforeFrame(aContent);
6457 : };
6458 :
6459 55 : while (nsIContent* sibling = nextDomSibling(aIter)) {
6460 : // NOTE(emilio): It's important to check GetPrimaryFrame() before
6461 : // IsDisplayContents to get the correct insertion point when multiple
6462 : // siblings go from display: non-none to display: contents.
6463 22 : if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
6464 : // XXX the GetContent() == sibling check is needed due to bug 135040.
6465 : // Remove it once that's fixed.
6466 9 : if (primaryFrame->GetContent() == sibling) {
6467 0 : if (nsIFrame* frame = adjust(primaryFrame)) {
6468 : return frame;
6469 : }
6470 : }
6471 : }
6472 :
6473 0 : if (IsDisplayContents(sibling)) {
6474 0 : if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
6475 0 : return frame;
6476 : }
6477 :
6478 0 : const bool startFromBeginning = aDirection == SiblingDirection::Forward;
6479 0 : FlattenedChildIterator iter(sibling, startFromBeginning);
6480 0 : nsIFrame* sibling = FindSiblingInternal<aDirection>(
6481 0 : iter, aTargetContent, aTargetContentDisplay);
6482 0 : if (sibling) {
6483 0 : return sibling;
6484 : }
6485 : }
6486 : }
6487 :
6488 66 : return adjust(getFarPseudo(aIter.Parent()));
6489 : }
6490 :
6491 : nsIFrame*
6492 0 : nsCSSFrameConstructor::AdjustSiblingFrame(
6493 : nsIFrame* aSibling,
6494 : nsIContent* aTargetContent,
6495 : mozilla::StyleDisplay& aTargetContentDisplay,
6496 : SiblingDirection aDirection)
6497 : {
6498 0 : if (!aSibling) {
6499 : return nullptr;
6500 : }
6501 :
6502 0 : if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
6503 0 : aSibling = aSibling->GetPlaceholderFrame();
6504 0 : MOZ_ASSERT(aSibling);
6505 : }
6506 :
6507 9 : MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
6508 9 : if (aDirection == SiblingDirection::Backward) {
6509 : // The frame may be a ib-split frame (a split inline frame that contains a
6510 : // block). Get the last part of that split.
6511 0 : if (IsFramePartOfIBSplit(aSibling)) {
6512 0 : aSibling = GetLastIBSplitSibling(aSibling);
6513 : }
6514 :
6515 : // The frame may have a continuation. If so, we want the last
6516 : // non-overflow-container continuation as our previous sibling.
6517 5 : aSibling = aSibling->GetTailContinuation();
6518 : }
6519 :
6520 9 : if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
6521 : return nullptr;
6522 : }
6523 :
6524 9 : return aSibling;
6525 : }
6526 :
6527 : nsIFrame*
6528 0 : nsCSSFrameConstructor::FindPreviousSibling(const FlattenedChildIterator& aIter,
6529 : StyleDisplay& aTargetContentDisplay)
6530 : {
6531 11 : return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay);
6532 : }
6533 :
6534 : nsIFrame*
6535 0 : nsCSSFrameConstructor::FindNextSibling(const FlattenedChildIterator& aIter,
6536 : StyleDisplay& aTargetContentDisplay)
6537 : {
6538 31 : return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay);
6539 : }
6540 :
6541 : template<nsCSSFrameConstructor::SiblingDirection aDirection>
6542 : nsIFrame*
6543 0 : nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter,
6544 : StyleDisplay& aTargetContentDisplay)
6545 : {
6546 42 : nsIContent* targetContent = aIter.Get();
6547 84 : FlattenedChildIterator siblingIter = aIter;
6548 : nsIFrame* sibling = FindSiblingInternal<aDirection>(
6549 42 : siblingIter, targetContent, aTargetContentDisplay);
6550 42 : if (sibling) {
6551 : return sibling;
6552 : }
6553 :
6554 : // Our siblings (if any) do not have a frame to guide us. The frame for the
6555 : // target content should be inserted whereever a frame for the container would
6556 : // be inserted. This is needed when inserting into display: contents nodes.
6557 0 : const nsIContent* current = aIter.Parent();
6558 0 : while (IsDisplayContents(current)) {
6559 0 : const nsIContent* parent = current->GetFlattenedTreeParent();
6560 0 : MOZ_ASSERT(parent, "No display: contents on the root");
6561 :
6562 0 : FlattenedChildIterator iter(parent);
6563 0 : iter.Seek(current);
6564 0 : sibling = FindSiblingInternal<aDirection>(
6565 : iter, targetContent, aTargetContentDisplay);
6566 0 : if (sibling) {
6567 0 : return sibling;
6568 : }
6569 :
6570 0 : current = parent;
6571 : }
6572 :
6573 : return nullptr;
6574 : }
6575 :
6576 : // For fieldsets, returns the area frame, if the child is not a legend.
6577 : static nsContainerFrame*
6578 2 : GetAdjustedParentFrame(nsContainerFrame* aParentFrame,
6579 : nsIContent* aChildContent)
6580 : {
6581 2 : MOZ_ASSERT(!aParentFrame->IsTableWrapperFrame(), "Shouldn't be happening!");
6582 :
6583 0 : nsContainerFrame* newParent = nullptr;
6584 :
6585 2 : if (aParentFrame->IsFieldSetFrame()) {
6586 : // If the parent is a fieldSet, use the fieldSet's area frame as the
6587 : // parent unless the new content is a legend.
6588 0 : if (!aChildContent->IsHTMLElement(nsGkAtoms::legend)) {
6589 0 : newParent = GetFieldSetBlockFrame(aParentFrame);
6590 : }
6591 : }
6592 2 : return newParent ? newParent : aParentFrame;
6593 : }
6594 :
6595 : nsIFrame*
6596 11 : nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
6597 : nsIContent* aChild,
6598 : bool* aIsAppend,
6599 : bool* aIsRangeInsertSafe,
6600 : nsIContent* aStartSkipChild,
6601 : nsIContent* aEndSkipChild)
6602 : {
6603 11 : MOZ_ASSERT(aInsertion->mParentFrame, "Must have parent frame to start with");
6604 :
6605 0 : *aIsAppend = false;
6606 :
6607 : // Find the frame that precedes the insertion point. Walk backwards
6608 : // from the parent frame to get the parent content, because if an
6609 : // XBL insertion point is involved, we'll need to use _that_ to find
6610 : // the preceding frame.
6611 22 : FlattenedChildIterator iter(aInsertion->mContainer);
6612 0 : bool xblCase = iter.XBLInvolved() ||
6613 0 : aInsertion->mParentFrame->GetContent() != aInsertion->mContainer;
6614 11 : if (xblCase || !aChild->IsRootOfAnonymousSubtree()) {
6615 : // The check for IsRootOfAnonymousSubtree() is because editor is
6616 : // severely broken and calls us directly for native anonymous
6617 : // nodes that it creates.
6618 11 : if (aStartSkipChild) {
6619 0 : iter.Seek(aStartSkipChild);
6620 : } else {
6621 11 : iter.Seek(aChild);
6622 : }
6623 : } else {
6624 : // Prime the iterator for the call to FindPreviousSibling.
6625 0 : iter.GetNextChild();
6626 0 : MOZ_ASSERT(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
6627 : "Someone passed native anonymous content directly into frame "
6628 : "construction. Stop doing that!");
6629 : }
6630 :
6631 : // Note that FindPreviousSibling is passed the iterator by value, so that
6632 : // the later usage of the iterator starts from the same place.
6633 0 : StyleDisplay childDisplay = UNSET_DISPLAY;
6634 0 : nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
6635 :
6636 : // Now, find the geometric parent so that we can handle
6637 : // continuations properly. Use the prev sibling if we have it;
6638 : // otherwise use the next sibling.
6639 0 : if (prevSibling) {
6640 0 : aInsertion->mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
6641 : } else {
6642 : // If there is no previous sibling, then find the frame that follows
6643 : //
6644 : // FIXME(emilio): This is really complex and probably shouldn't be.
6645 6 : if (aEndSkipChild) {
6646 0 : iter.Seek(aEndSkipChild);
6647 0 : iter.GetPreviousChild();
6648 : }
6649 0 : if (nsIFrame* nextSibling = FindNextSibling(iter, childDisplay)) {
6650 4 : aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
6651 : } else {
6652 : // No previous or next sibling, so treat this like an appended frame.
6653 0 : *aIsAppend = true;
6654 0 : aInsertion->mParentFrame =
6655 2 : ::ContinuationToAppendTo(aInsertion->mParentFrame);
6656 :
6657 : // Deal with fieldsets.
6658 0 : aInsertion->mParentFrame =
6659 0 : ::GetAdjustedParentFrame(aInsertion->mParentFrame, aChild);
6660 2 : prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr);
6661 : }
6662 : }
6663 :
6664 11 : *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
6665 22 : return prevSibling;
6666 : }
6667 :
6668 : nsContainerFrame*
6669 90 : nsCSSFrameConstructor::GetContentInsertionFrameFor(nsIContent* aContent)
6670 : {
6671 : nsIFrame* frame;
6672 0 : while (!(frame = aContent->GetPrimaryFrame())) {
6673 32 : if (!IsDisplayContents(aContent)) {
6674 : return nullptr;
6675 : }
6676 :
6677 0 : aContent = aContent->GetFlattenedTreeParent();
6678 0 : if (!aContent) {
6679 : return nullptr;
6680 : }
6681 : }
6682 :
6683 : // If the content of the frame is not the desired content then this is not
6684 : // really a frame for the desired content.
6685 : // XXX This check is needed due to bug 135040. Remove it once that's fixed.
6686 0 : if (frame->GetContent() != aContent) {
6687 : return nullptr;
6688 : }
6689 :
6690 58 : nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
6691 :
6692 58 : NS_ASSERTION(!insertionFrame || insertionFrame == frame || !frame->IsLeaf(),
6693 : "The insertion frame is the primary frame or the primary frame isn't a leaf");
6694 :
6695 : return insertionFrame;
6696 : }
6697 :
6698 : static bool
6699 0 : IsSpecialFramesetChild(nsIContent* aContent)
6700 : {
6701 : // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
6702 0 : return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
6703 : }
6704 :
6705 : static void
6706 : InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
6707 :
6708 : void
6709 0 : nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState& aState,
6710 : const InsertionPoint& aInsertion,
6711 : nsIContent* aPossibleTextContent,
6712 : FrameConstructionItemList& aItems)
6713 : {
6714 27 : MOZ_ASSERT(aPossibleTextContent, "Must have node");
6715 54 : if (!aPossibleTextContent->IsText() ||
6716 27 : !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
6717 0 : aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
6718 : // Not text, or not suppressed due to being all-whitespace (if it were being
6719 : // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
6720 : // going to be reframed anyway.
6721 : return;
6722 : }
6723 0 : MOZ_ASSERT(!aPossibleTextContent->GetPrimaryFrame(),
6724 : "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6725 : AddFrameConstructionItems(aState, aPossibleTextContent, false,
6726 0 : aInsertion, aItems);
6727 : }
6728 :
6729 : void
6730 0 : nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aContent)
6731 : {
6732 0 : if (!aContent->IsText() ||
6733 0 : !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
6734 0 : aContent->HasFlag(NODE_NEEDS_FRAME)) {
6735 : // Not text, or not suppressed due to being all-whitespace (if it were being
6736 : // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
6737 : // going to be reframed anyway.
6738 : return;
6739 : }
6740 0 : MOZ_ASSERT(!aContent->GetPrimaryFrame(),
6741 : "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6742 0 : ContentInserted(aContent, nullptr, InsertionKind::Async);
6743 : }
6744 :
6745 : #ifdef DEBUG
6746 : void
6747 22 : nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(nsIContent* aParent)
6748 : {
6749 : // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
6750 : // we want to assert, but leaf frames that process their own children and may
6751 : // ignore anonymous children (eg framesets) make this complicated. So we set
6752 : // these two booleans if we encounter these situations and unset them if we
6753 : // hit a node with a leaf frame.
6754 : //
6755 : // It's fine if one of node without primary frame is in a display:none
6756 : // subtree.
6757 : //
6758 : // Also, it's fine if one of the nodes without primary frame is a display:
6759 : // contents node.
6760 22 : bool noPrimaryFrame = false;
6761 0 : bool needsFrameBitSet = false;
6762 0 : nsIContent* content = aParent;
6763 84 : while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6764 0 : if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
6765 1 : noPrimaryFrame = needsFrameBitSet = false;
6766 : }
6767 31 : if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
6768 0 : noPrimaryFrame = !IsDisplayContents(content);
6769 : }
6770 0 : if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
6771 0 : needsFrameBitSet = true;
6772 : }
6773 :
6774 0 : content = content->GetFlattenedTreeParent();
6775 : }
6776 0 : if (content && content->GetPrimaryFrame() &&
6777 4 : content->GetPrimaryFrame()->IsLeaf()) {
6778 0 : noPrimaryFrame = needsFrameBitSet = false;
6779 : }
6780 22 : MOZ_ASSERT(!noPrimaryFrame, "Ancestors of nodes with frames to be "
6781 : "constructed lazily should have frames");
6782 22 : MOZ_ASSERT(!needsFrameBitSet, "Ancestors of nodes with frames to be "
6783 : "constructed lazily should not have NEEDS_FRAME bit set");
6784 22 : }
6785 : #endif
6786 :
6787 : // Returns true if this operation can be lazy, false if not.
6788 : //
6789 : // FIXME(emilio, bug 1410020): This function assumes that the flattened tree
6790 : // parent of all the appended children is the same, which, afaict, is not
6791 : // necessarily true.
6792 : //
6793 : // NOTE(emilio): The IsXULElement checks are pretty unfortunate, but there's
6794 : // tons of browser chrome code that rely on XBL bindings getting synchronously
6795 : // loaded as soon as the elements get inserted in the DOM.
6796 : bool
6797 0 : nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
6798 : nsIContent* aChild)
6799 : {
6800 33 : MOZ_ASSERT(aChild->GetParent());
6801 0 : if (aOperation == CONTENTINSERT) {
6802 4 : MOZ_ASSERT(!aChild->IsRootOfAnonymousSubtree());
6803 0 : if (aChild->IsXULElement()) {
6804 : return false;
6805 : }
6806 : } else { // CONTENTAPPEND
6807 29 : MOZ_ASSERT(aOperation == CONTENTAPPEND,
6808 : "operation should be either insert or append");
6809 81 : for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6810 33 : MOZ_ASSERT(!child->IsRootOfAnonymousSubtree());
6811 33 : if (child->IsXULElement()) {
6812 : return false;
6813 : }
6814 : }
6815 : }
6816 :
6817 : // We can construct lazily; just need to set suitable bits in the content
6818 : // tree.
6819 0 : Element* parent = aChild->GetFlattenedTreeParentElement();
6820 22 : if (!parent) {
6821 : // Not part of the flat tree, nothing to do.
6822 : return true;
6823 : }
6824 :
6825 22 : if (Servo_Element_IsDisplayNone(parent)) {
6826 : // Nothing to do either.
6827 : //
6828 : // FIXME(emilio): This should be an assert, except for weird <frameset>
6829 : // stuff that does its own frame construction. Such an assert would fire in
6830 : // layout/style/crashtests/1411478.html, for example.
6831 : return true;
6832 : }
6833 :
6834 : // Set NODE_NEEDS_FRAME on the new nodes.
6835 22 : if (aOperation == CONTENTINSERT) {
6836 0 : NS_ASSERTION(!aChild->GetPrimaryFrame() ||
6837 : aChild->GetPrimaryFrame()->GetContent() != aChild,
6838 : //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
6839 : // check is needed due to bug 135040. Remove it once that's
6840 : // fixed.
6841 : "setting NEEDS_FRAME on a node that already has a frame?");
6842 0 : aChild->SetFlags(NODE_NEEDS_FRAME);
6843 : } else { // CONTENTAPPEND
6844 74 : for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6845 0 : NS_ASSERTION(!child->GetPrimaryFrame() ||
6846 : child->GetPrimaryFrame()->GetContent() != child,
6847 : //XXX the child->GetPrimaryFrame()->GetContent() != child
6848 : // check is needed due to bug 135040. Remove it once that's
6849 : // fixed.
6850 : "setting NEEDS_FRAME on a node that already has a frame?");
6851 26 : child->SetFlags(NODE_NEEDS_FRAME);
6852 : }
6853 : }
6854 :
6855 22 : CheckBitsForLazyFrameConstruction(parent);
6856 22 : parent->NoteDescendantsNeedFramesForServo();
6857 :
6858 22 : return true;
6859 : }
6860 :
6861 :
6862 : void
6863 0 : nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aStartChild,
6864 : nsIContent* aEndChild,
6865 : InsertionKind aInsertionKind)
6866 : {
6867 6 : for (nsIContent* child = aStartChild;
6868 0 : child != aEndChild;
6869 0 : child = child->GetNextSibling()) {
6870 : // listboxes suck.
6871 0 : MOZ_ASSERT(MaybeGetListBoxBodyFrame(child) || !child->GetPrimaryFrame());
6872 :
6873 : // Call ContentRangeInserted with this node.
6874 0 : ContentRangeInserted(child, child->GetNextSibling(),
6875 3 : mTempFrameTreeState, aInsertionKind);
6876 : }
6877 3 : }
6878 :
6879 : bool
6880 63 : nsCSSFrameConstructor::InsertionPoint::IsMultiple() const
6881 : {
6882 0 : if (!mParentFrame) {
6883 : return false;
6884 : }
6885 :
6886 : // Fieldset frames have multiple normal flow child frame lists so handle it
6887 : // the same as if it had multiple content insertion points.
6888 0 : if (mParentFrame->IsFieldSetFrame()) {
6889 : return true;
6890 : }
6891 :
6892 : // A details frame moves the first summary frame to be its first child, so we
6893 : // treat it as if it has multiple content insertion points.
6894 47 : if (mParentFrame->IsDetailsFrame()) {
6895 : return true;
6896 : }
6897 :
6898 47 : return false;
6899 : }
6900 :
6901 : nsCSSFrameConstructor::InsertionPoint
6902 66 : nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
6903 : nsIContent* aEndChild,
6904 : InsertionKind aInsertionKind)
6905 : {
6906 66 : MOZ_ASSERT(aStartChild);
6907 66 : MOZ_ASSERT(aStartChild->GetParent());
6908 :
6909 0 : nsIContent* parent = aStartChild->GetParent();
6910 :
6911 : // If the children of the container may be distributed to different insertion
6912 : // points, insert them separately and bail out, letting ContentInserted handle
6913 : // the mess.
6914 66 : if (parent->GetShadowRoot() || parent->GetXBLBinding()) {
6915 0 : IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
6916 0 : return { };
6917 : }
6918 :
6919 : #ifdef DEBUG
6920 : {
6921 63 : nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
6922 75 : for (nsIContent* child = aStartChild->GetNextSibling(); child;
6923 12 : child = child->GetNextSibling()) {
6924 12 : MOZ_ASSERT(child->GetFlattenedTreeParent() == expectedParent);
6925 : }
6926 : }
6927 : #endif
6928 :
6929 : // Now the flattened tree parent of all the siblings is the same, just use the
6930 : // same insertion point and take the fast path, unless it's a multiple
6931 : // insertion point.
6932 0 : InsertionPoint ip = GetInsertionPoint(aStartChild);
6933 63 : if (ip.IsMultiple()) {
6934 0 : IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
6935 0 : return { };
6936 : }
6937 :
6938 63 : return ip;
6939 : }
6940 :
6941 : bool
6942 0 : nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
6943 : nsIContent* aStartChild,
6944 : nsIContent* aEndChild)
6945 : {
6946 36 : if (aParentFrame->IsFrameSetFrame()) {
6947 : // Check whether we have any kids we care about.
6948 0 : for (nsIContent* cur = aStartChild;
6949 0 : cur != aEndChild;
6950 0 : cur = cur->GetNextSibling()) {
6951 0 : if (IsSpecialFramesetChild(cur)) {
6952 : // Just reframe the parent, since framesets are weird like that.
6953 0 : RecreateFramesForContent(aParentFrame->GetContent(),
6954 0 : InsertionKind::Async);
6955 0 : return true;
6956 : }
6957 : }
6958 : }
6959 : return false;
6960 : }
6961 :
6962 : void
6963 0 : nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
6964 : nsIContent* aEndChild)
6965 : {
6966 0 : for (nsIContent* child = aStartChild; child != aEndChild;
6967 48 : child = child->GetNextSibling()) {
6968 96 : if (child->IsElement()) {
6969 28 : child->AsElement()->NoteDirtyForServo();
6970 : }
6971 : }
6972 0 : }
6973 :
6974 : #ifdef DEBUG
6975 : static bool
6976 0 : IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild)
6977 : {
6978 22 : FlattenedChildIterator iter(aParent);
6979 83 : for (nsIContent* node = iter.GetNextChild();
6980 83 : node;
6981 : node = iter.GetNextChild()) {
6982 83 : if (node == aChild) {
6983 : return true;
6984 : }
6985 : }
6986 : return false;
6987 : }
6988 : #endif
6989 :
6990 : void
6991 0 : nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
6992 : nsIContent* aEndChild)
6993 : {
6994 22 : ServoStyleSet* styleSet = mPresShell->StyleSet();
6995 :
6996 0 : for (nsIContent* child = aStartChild; child != aEndChild;
6997 11 : child = child->GetNextSibling()) {
6998 22 : if (!child->IsElement()) {
6999 : continue;
7000 : }
7001 :
7002 11 : Element* childElement = child->AsElement();
7003 :
7004 : // We only come in here from non-lazy frame construction, so the children
7005 : // should be unstyled.
7006 11 : MOZ_ASSERT(!childElement->HasServoData());
7007 :
7008 : #ifdef DEBUG
7009 : {
7010 : // Furthermore, all of them should have the same flattened tree parent
7011 : // (GetRangeInsertionPoint ensures it). And that parent should be styled,
7012 : // otherwise we would've never found an insertion point at all.
7013 11 : Element* parent = childElement->GetFlattenedTreeParentElement();
7014 11 : MOZ_ASSERT(parent);
7015 0 : MOZ_ASSERT(parent->HasServoData());
7016 11 : MOZ_ASSERT(IsFlattenedTreeChild(parent, child),
7017 : "GetFlattenedTreeParent and ChildIterator don't agree, fix this!");
7018 : }
7019 : #endif
7020 :
7021 11 : styleSet->StyleNewSubtree(childElement);
7022 : }
7023 0 : }
7024 :
7025 : nsIFrame*
7026 0 : nsCSSFrameConstructor::FindNextSiblingForAppend(const InsertionPoint& aInsertion)
7027 : {
7028 0 : auto SlowPath = [&]() -> nsIFrame* {
7029 25 : FlattenedChildIterator iter(aInsertion.mContainer,
7030 0 : /* aStartAtBeginning = */ false);
7031 0 : iter.GetPreviousChild(); // Prime the iterator.
7032 0 : StyleDisplay unused = UNSET_DISPLAY;
7033 75 : return FindNextSibling(iter, unused);
7034 25 : };
7035 :
7036 0 : if (!IsDisplayContents(aInsertion.mContainer) &&
7037 25 : !nsLayoutUtils::GetAfterFrame(aInsertion.mContainer)) {
7038 25 : MOZ_ASSERT(!SlowPath());
7039 : return nullptr;
7040 : }
7041 :
7042 0 : return SlowPath();
7043 : }
7044 :
7045 : void
7046 0 : nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
7047 : InsertionKind aInsertionKind)
7048 : {
7049 0 : MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
7050 : !RestyleManager()->IsInStyleRefresh());
7051 :
7052 157 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7053 :
7054 : #ifdef DEBUG
7055 1 : if (gNoisyContentUpdates) {
7056 0 : printf("nsCSSFrameConstructor::ContentAppended container=%p "
7057 : "first-child=%p lazy=%d\n",
7058 : aFirstNewContent->GetParent(),
7059 : aFirstNewContent,
7060 0 : aInsertionKind == InsertionKind::Async);
7061 0 : if (gReallyNoisyContentUpdates && aFirstNewContent->GetParent()) {
7062 0 : aFirstNewContent->GetParent()->List(stdout, 0);
7063 : }
7064 : }
7065 :
7066 78 : for (nsIContent* child = aFirstNewContent;
7067 144 : child;
7068 78 : child = child->GetNextSibling()) {
7069 : // XXX the GetContent() != child check is needed due to bug 135040.
7070 : // Remove it once that's fixed.
7071 0 : MOZ_ASSERT(!child->GetPrimaryFrame() ||
7072 : child->GetPrimaryFrame()->GetContent() != child,
7073 : "asked to construct a frame for a node that already has a frame");
7074 : }
7075 : #endif
7076 :
7077 66 : LAYOUT_PHASE_TEMP_EXIT();
7078 : InsertionPoint insertion =
7079 66 : GetRangeInsertionPoint(aFirstNewContent, nullptr, aInsertionKind);
7080 66 : nsContainerFrame*& parentFrame = insertion.mParentFrame;
7081 0 : LAYOUT_PHASE_TEMP_REENTER();
7082 0 : if (!parentFrame) {
7083 : // We're punting on frame construction because there's no container frame.
7084 : // The Servo-backed style system handles this case like the lazy frame
7085 : // construction case, except when we're already constructing frames, in
7086 : // which case we shouldn't need to do anything else.
7087 0 : if (aInsertionKind == InsertionKind::Async) {
7088 0 : LazilyStyleNewChildRange(aFirstNewContent, nullptr);
7089 : }
7090 0 : return;
7091 : }
7092 :
7093 47 : if (aInsertionKind == InsertionKind::Async) {
7094 29 : if (MaybeConstructLazily(CONTENTAPPEND, aFirstNewContent)) {
7095 0 : LazilyStyleNewChildRange(aFirstNewContent, nullptr);
7096 22 : return;
7097 : }
7098 : // We couldn't construct lazily. Make Servo eagerly traverse the new content
7099 : // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
7100 : // styles are up-to-date already).
7101 0 : StyleNewChildRange(aFirstNewContent, nullptr);
7102 : }
7103 :
7104 :
7105 25 : LAYOUT_PHASE_TEMP_EXIT();
7106 0 : if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
7107 0 : LAYOUT_PHASE_TEMP_REENTER();
7108 0 : return;
7109 : }
7110 0 : LAYOUT_PHASE_TEMP_REENTER();
7111 :
7112 25 : if (parentFrame->IsLeaf()) {
7113 : // Nothing to do here; we shouldn't be constructing kids of leaves
7114 : // Clear lazy bits so we don't try to construct again.
7115 0 : ClearLazyBits(aFirstNewContent, nullptr);
7116 0 : return;
7117 : }
7118 :
7119 25 : if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7120 0 : LAYOUT_PHASE_TEMP_EXIT();
7121 0 : RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
7122 0 : LAYOUT_PHASE_TEMP_REENTER();
7123 0 : return;
7124 : }
7125 :
7126 : #ifdef DEBUG
7127 25 : if (gNoisyContentUpdates && IsFramePartOfIBSplit(parentFrame)) {
7128 0 : printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
7129 0 : nsFrame::ListTag(stdout, parentFrame);
7130 : printf(" is ib-split\n");
7131 : }
7132 : #endif
7133 :
7134 : // We should never get here with fieldsets or details, since they have
7135 : // multiple insertion points.
7136 25 : MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
7137 : "Parent frame should not be fieldset or details!");
7138 :
7139 25 : nsIFrame* nextSibling = FindNextSiblingForAppend(insertion);
7140 25 : if (nextSibling) {
7141 0 : parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7142 : } else {
7143 25 : parentFrame =
7144 25 : ::ContinuationToAppendTo(parentFrame);
7145 : }
7146 :
7147 25 : nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
7148 :
7149 : // See if the containing block has :first-letter style applied.
7150 : const bool haveFirstLetterStyle =
7151 25 : containingBlock && HasFirstLetterStyle(containingBlock);
7152 :
7153 : const bool haveFirstLineStyle =
7154 32 : containingBlock &&
7155 21 : ShouldHaveFirstLineStyle(containingBlock->GetContent(),
7156 0 : containingBlock->Style());
7157 :
7158 25 : if (haveFirstLetterStyle) {
7159 0 : AutoWeakFrame wf(nextSibling);
7160 :
7161 : // Before we get going, remove the current letter frames
7162 0 : RemoveLetterFrames(mPresShell, containingBlock);
7163 :
7164 : // Reget nextSibling, since we may have killed it.
7165 : //
7166 : // FIXME(emilio): This kinda sucks! :(
7167 0 : if (nextSibling && !wf) {
7168 0 : nextSibling = FindNextSiblingForAppend(insertion);
7169 0 : if (nextSibling) {
7170 0 : parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7171 0 : containingBlock = GetFloatContainingBlock(parentFrame);
7172 : }
7173 : }
7174 : }
7175 :
7176 : // Create some new frames
7177 : nsFrameConstructorState state(mPresShell,
7178 : GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
7179 : GetAbsoluteContainingBlock(parentFrame, ABS_POS),
7180 50 : containingBlock);
7181 :
7182 0 : LayoutFrameType frameType = parentFrame->Type();
7183 :
7184 50 : FlattenedChildIterator iter(insertion.mContainer);
7185 25 : const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
7186 :
7187 50 : AutoFrameConstructionItemList items(this);
7188 68 : if (aFirstNewContent->GetPreviousSibling() &&
7189 43 : GetParentType(frameType) == eTypeBlock &&
7190 : haveNoXBLChildren) {
7191 : // If there's a text node in the normal content list just before the new
7192 : // items, and it has no frame, make a frame construction item for it. If it
7193 : // doesn't need a frame, ConstructFramesFromItemList below won't give it
7194 : // one. No need to do all this if our parent type is not block, though,
7195 : // since WipeContainingBlock already handles that situation.
7196 : //
7197 : // Because we're appending, we don't need to worry about any text
7198 : // after the appended content; there can only be XBL anonymous content
7199 : // (text in an XBL binding is not suppressed) or generated content
7200 : // (and bare text nodes are not generated). Native anonymous content
7201 : // generated by frames never participates in inline layout.
7202 0 : AddTextItemIfNeeded(state,
7203 : insertion,
7204 : aFirstNewContent->GetPreviousSibling(),
7205 18 : items);
7206 : }
7207 0 : for (nsIContent* child = aFirstNewContent;
7208 58 : child;
7209 33 : child = child->GetNextSibling()) {
7210 33 : AddFrameConstructionItems(state, child, false, insertion, items);
7211 : }
7212 :
7213 0 : nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, nextSibling);
7214 :
7215 : // Perform special check for diddling around with the frames in
7216 : // a ib-split inline frame.
7217 : // If we're appending before :after content, then we're not really
7218 : // appending, so let WipeContainingBlock know that.
7219 0 : LAYOUT_PHASE_TEMP_EXIT();
7220 25 : if (WipeContainingBlock(state, containingBlock, parentFrame, items,
7221 : true, prevSibling)) {
7222 0 : LAYOUT_PHASE_TEMP_REENTER();
7223 0 : return;
7224 : }
7225 0 : LAYOUT_PHASE_TEMP_REENTER();
7226 :
7227 : // If the parent is a block frame, and we're not in a special case
7228 : // where frames can be moved around, determine if the list is for the
7229 : // start or end of the block.
7230 57 : if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
7231 32 : !haveFirstLineStyle && !IsFramePartOfIBSplit(parentFrame)) {
7232 7 : items.SetLineBoundaryAtStart(!prevSibling ||
7233 0 : !prevSibling->IsInlineOutside() ||
7234 0 : prevSibling->IsBrFrame());
7235 : // :after content can't be <br> so no need to check it
7236 : //
7237 : // FIXME(emilio): A display: contents sibling could! Write a test-case and
7238 : // fix.
7239 7 : items.SetLineBoundaryAtEnd(
7240 0 : !nextSibling || !nextSibling->IsInlineOutside());
7241 : }
7242 : // To suppress whitespace-only text frames, we have to verify that
7243 : // our container's DOM child list matches its flattened tree child list.
7244 50 : items.SetParentHasNoXBLChildren(haveNoXBLChildren);
7245 :
7246 0 : nsFrameItems frameItems;
7247 0 : ConstructFramesFromItemList(state, items, parentFrame,
7248 25 : ParentIsWrapperAnonBox(parentFrame),
7249 25 : frameItems);
7250 :
7251 58 : for (nsIContent* child = aFirstNewContent;
7252 58 : child;
7253 0 : child = child->GetNextSibling()) {
7254 : // Invalidate now instead of before the WipeContainingBlock call, just in
7255 : // case we do wipe; in that case we don't need to do this walk at all.
7256 : // XXXbz does that matter? Would it make more sense to save some virtual
7257 : // GetChildAt_Deprecated calls instead and do this during construction of
7258 : // our FrameConstructionItemList?
7259 0 : InvalidateCanvasIfNeeded(mPresShell, child);
7260 : }
7261 :
7262 : // If the container is a table and a caption was appended, it needs to be put
7263 : // in the table wrapper frame's additional child list.
7264 25 : nsFrameItems captionItems;
7265 25 : if (LayoutFrameType::Table == frameType) {
7266 : // Pull out the captions. Note that we don't want to do that as we go,
7267 : // because processing a single caption can add a whole bunch of things to
7268 : // the frame items due to pseudoframe processing. So we'd have to pull
7269 : // captions from a list anyway; might as well do that here.
7270 : // XXXbz this is no longer true; we could pull captions directly out of the
7271 : // FrameConstructionItemList now.
7272 0 : PullOutCaptionFrames(frameItems, captionItems);
7273 : }
7274 :
7275 25 : if (haveFirstLineStyle && parentFrame == containingBlock) {
7276 : // It's possible that some of the new frames go into a
7277 : // first-line frame. Look at them and see...
7278 0 : AppendFirstLineFrames(state, containingBlock->GetContent(),
7279 0 : containingBlock, frameItems);
7280 : // That moved things into line frames as needed, reparenting their
7281 : // styles. Nothing else needs to be done.
7282 75 : } else if (parentFrame->Style()->HasPseudoElementData()) {
7283 : // parentFrame might be inside a ::first-line frame. Check whether it is,
7284 : // and if so fix up our styles.
7285 0 : CheckForFirstLineInsertion(parentFrame, frameItems);
7286 0 : CheckForFirstLineInsertion(parentFrame, captionItems);
7287 : }
7288 :
7289 : // Notify the parent frame passing it the list of new frames
7290 : // Append the flowed frames to the principal child list; captions
7291 : // need special treatment
7292 0 : if (captionItems.NotEmpty()) { // append the caption to the table wrapper
7293 0 : NS_ASSERTION(LayoutFrameType::Table == frameType, "how did that happen?");
7294 0 : nsContainerFrame* outerTable = parentFrame->GetParent();
7295 0 : AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7296 : }
7297 :
7298 0 : if (frameItems.NotEmpty()) { // append the in-flow kids
7299 8 : AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
7300 : }
7301 :
7302 : // Recover first-letter frames
7303 1 : if (haveFirstLetterStyle) {
7304 0 : RecoverLetterFrames(containingBlock);
7305 : }
7306 :
7307 : #ifdef DEBUG
7308 25 : if (gReallyNoisyContentUpdates) {
7309 0 : printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
7310 0 : parentFrame->List(stdout, 0);
7311 : }
7312 : #endif
7313 :
7314 : #ifdef ACCESSIBILITY
7315 25 : if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7316 0 : accService->ContentRangeInserted(mPresShell, aFirstNewContent, nullptr);
7317 : }
7318 : #endif
7319 : }
7320 :
7321 : #ifdef MOZ_XUL
7322 :
7323 : enum content_operation
7324 : {
7325 : CONTENT_INSERTED,
7326 : CONTENT_REMOVED
7327 : };
7328 :
7329 : // Helper function to lookup the listbox body frame and send a notification
7330 : // for insertion or removal of content
7331 : static bool
7332 12 : NotifyListBoxBody(nsPresContext* aPresContext,
7333 : nsIContent* aChild,
7334 : // Only used for the removed notification
7335 : nsIContent* aOldNextSibling,
7336 : nsIFrame* aChildFrame,
7337 : content_operation aOperation)
7338 : {
7339 0 : nsListBoxBodyFrame* listBoxBodyFrame = MaybeGetListBoxBodyFrame(aChild);
7340 0 : if (listBoxBodyFrame) {
7341 0 : if (aOperation == CONTENT_REMOVED) {
7342 : // Except if we have an aChildFrame and its parent is not the right
7343 : // thing, then we don't do this. Pseudo frames are so much fun....
7344 0 : if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) {
7345 0 : listBoxBodyFrame->OnContentRemoved(aPresContext, aChild->GetParent(),
7346 0 : aChildFrame, aOldNextSibling);
7347 0 : return true;
7348 : }
7349 : } else {
7350 0 : listBoxBodyFrame->OnContentInserted(aChild);
7351 0 : return true;
7352 : }
7353 : }
7354 :
7355 : return false;
7356 : }
7357 : #endif // MOZ_XUL
7358 :
7359 : void
7360 23 : nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
7361 : nsILayoutHistoryState* aFrameState,
7362 : InsertionKind aInsertionKind)
7363 : {
7364 23 : ContentRangeInserted(aChild,
7365 : aChild->GetNextSibling(),
7366 : aFrameState,
7367 23 : aInsertionKind);
7368 23 : }
7369 :
7370 : // ContentRangeInserted handles creating frames for a range of nodes that
7371 : // aren't at the end of their childlist. ContentRangeInserted isn't a real
7372 : // content notification, but rather it handles regular ContentInserted calls
7373 : // for a single node as well as the lazy construction of frames for a range of
7374 : // nodes when called from CreateNeededFrames. For a range of nodes to be
7375 : // suitable to have its frames constructed all at once they must meet the same
7376 : // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
7377 : // these), plus more. Namely when finding the insertion prevsibling we must not
7378 : // need to consult something specific to any one node in the range, so that the
7379 : // insertion prevsibling would be the same for each node in the range. So we
7380 : // pass the first node in the range to GetInsertionPrevSibling, and if
7381 : // IsValidSibling (the only place GetInsertionPrevSibling might look at the
7382 : // passed in node itself) needs to resolve style on the node we record this and
7383 : // return that this range needs to be split up and inserted separately. Table
7384 : // captions need extra attention as we need to determine where to insert them
7385 : // in the caption list, while skipping any nodes in the range being inserted
7386 : // (because when we treat the caption frames the other nodes have had their
7387 : // frames constructed but not yet inserted into the frame tree).
7388 : void
7389 33 : nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
7390 : nsIContent* aEndChild,
7391 : nsILayoutHistoryState* aFrameState,
7392 : InsertionKind aInsertionKind)
7393 : {
7394 33 : MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
7395 : !RestyleManager()->IsInStyleRefresh());
7396 :
7397 1 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7398 :
7399 33 : MOZ_ASSERT(aStartChild, "must always pass a child");
7400 :
7401 : #ifdef DEBUG
7402 1 : if (gNoisyContentUpdates) {
7403 0 : printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
7404 : "start-child=%p end-child=%p lazy=%d\n",
7405 : aStartChild->GetParent(),
7406 : aStartChild,
7407 : aEndChild,
7408 0 : aInsertionKind == InsertionKind::Async);
7409 0 : if (gReallyNoisyContentUpdates) {
7410 0 : if (aStartChild->GetParent()) {
7411 0 : aStartChild->GetParent()->List(stdout,0);
7412 : } else {
7413 0 : aStartChild->List(stdout, 0);
7414 : }
7415 : }
7416 : }
7417 :
7418 33 : for (nsIContent* child = aStartChild;
7419 66 : child != aEndChild;
7420 33 : child = child->GetNextSibling()) {
7421 : // XXX the GetContent() != child check is needed due to bug 135040.
7422 : // Remove it once that's fixed.
7423 33 : NS_ASSERTION(!child->GetPrimaryFrame() ||
7424 : child->GetPrimaryFrame()->GetContent() != child,
7425 : "asked to construct a frame for a node that already has a frame");
7426 : }
7427 : #endif
7428 :
7429 :
7430 33 : bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
7431 33 : NS_ASSERTION(isSingleInsert ||
7432 : aInsertionKind == InsertionKind::Sync,
7433 : "range insert shouldn't be lazy");
7434 33 : NS_ASSERTION(isSingleInsert || aEndChild,
7435 : "range should not include all nodes after aStartChild");
7436 :
7437 : #ifdef MOZ_XUL
7438 33 : if (aStartChild->GetParent() && IsXULListBox(aStartChild->GetParent())) {
7439 0 : if (isSingleInsert) {
7440 : // The insert case in NotifyListBoxBody doesn't use "old next sibling".
7441 0 : if (NotifyListBoxBody(mPresShell->GetPresContext(),
7442 : aStartChild, nullptr, nullptr, CONTENT_INSERTED)) {
7443 1 : return;
7444 : }
7445 : } else {
7446 : // We don't handle a range insert to a listbox parent, issue single
7447 : // ContertInserted calls for each node inserted.
7448 0 : LAYOUT_PHASE_TEMP_EXIT();
7449 0 : IssueSingleInsertNofications(aStartChild, aEndChild, InsertionKind::Sync);
7450 0 : LAYOUT_PHASE_TEMP_REENTER();
7451 0 : return;
7452 : }
7453 : }
7454 : #endif // MOZ_XUL
7455 :
7456 : // If we have a null parent, then this must be the document element being
7457 : // inserted, or some other child of the document in the DOM (might be a PI,
7458 : // say).
7459 33 : if (!aStartChild->GetParent()) {
7460 19 : MOZ_ASSERT(isSingleInsert,
7461 : "root node insertion should be a single insertion");
7462 19 : Element* docElement = mDocument->GetRootElement();
7463 :
7464 19 : if (aStartChild != docElement) {
7465 : // Not the root element; just bail out
7466 : return;
7467 : }
7468 :
7469 0 : MOZ_ASSERT(!mRootElementFrame, "root element frame already created");
7470 :
7471 : // Create frames for the document element and its child elements
7472 1 : if (ConstructDocElementFrame(docElement, aFrameState)) {
7473 19 : InvalidateCanvasIfNeeded(mPresShell, aStartChild);
7474 : #ifdef DEBUG
7475 19 : if (gReallyNoisyContentUpdates) {
7476 : printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
7477 0 : "model:\n");
7478 0 : mRootElementFrame->List(stdout, 0);
7479 : }
7480 : #endif
7481 : }
7482 :
7483 19 : if (aFrameState) {
7484 : // Restore frame state for the root scroll frame if there is one
7485 0 : if (nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame()) {
7486 0 : RestoreFrameStateFor(rootScrollFrame, aFrameState);
7487 : }
7488 : }
7489 :
7490 : #ifdef ACCESSIBILITY
7491 19 : if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7492 0 : accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
7493 : }
7494 : #endif
7495 :
7496 : return;
7497 : }
7498 :
7499 14 : InsertionPoint insertion;
7500 14 : if (isSingleInsert) {
7501 : // See if we have an XBL insertion point. If so, then that's our
7502 : // real parent frame; if not, then the frame hasn't been built yet
7503 : // and we just bail.
7504 0 : insertion = GetInsertionPoint(aStartChild);
7505 : } else {
7506 : // Get our insertion point. If we need to issue single ContentInserteds
7507 : // GetRangeInsertionPoint will take care of that for us.
7508 0 : LAYOUT_PHASE_TEMP_EXIT();
7509 0 : insertion = GetRangeInsertionPoint(aStartChild, aEndChild, aInsertionKind);
7510 0 : LAYOUT_PHASE_TEMP_REENTER();
7511 : }
7512 :
7513 0 : if (!insertion.mParentFrame) {
7514 : // We're punting on frame construction because there's no container frame.
7515 : // The Servo-backed style system handles this case like the lazy frame
7516 : // construction case, except when we're already constructing frames, in
7517 : // which case we shouldn't need to do anything else.
7518 0 : if (aInsertionKind == InsertionKind::Async) {
7519 0 : LazilyStyleNewChildRange(aStartChild, aEndChild);
7520 : }
7521 : return;
7522 : }
7523 :
7524 11 : if (aInsertionKind == InsertionKind::Async) {
7525 4 : if (MaybeConstructLazily(CONTENTINSERT, aStartChild)) {
7526 0 : LazilyStyleNewChildRange(aStartChild, aEndChild);
7527 0 : return;
7528 : }
7529 : // We couldn't construct lazily. Make Servo eagerly traverse the new content
7530 : // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
7531 : // styles are up-to-date already).
7532 4 : StyleNewChildRange(aStartChild, aEndChild);
7533 : }
7534 :
7535 : bool isAppend, isRangeInsertSafe;
7536 : nsIFrame* prevSibling = GetInsertionPrevSibling(&insertion, aStartChild,
7537 0 : &isAppend, &isRangeInsertSafe);
7538 :
7539 : // check if range insert is safe
7540 11 : if (!isSingleInsert && !isRangeInsertSafe) {
7541 : // must fall back to a single ContertInserted for each child in the range
7542 0 : LAYOUT_PHASE_TEMP_EXIT();
7543 0 : IssueSingleInsertNofications(aStartChild, aEndChild, InsertionKind::Sync);
7544 0 : LAYOUT_PHASE_TEMP_REENTER();
7545 0 : return;
7546 : }
7547 :
7548 0 : LayoutFrameType frameType = insertion.mParentFrame->Type();
7549 11 : LAYOUT_PHASE_TEMP_EXIT();
7550 11 : if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild)) {
7551 0 : LAYOUT_PHASE_TEMP_REENTER();
7552 0 : return;
7553 : }
7554 0 : LAYOUT_PHASE_TEMP_REENTER();
7555 :
7556 : // We should only get here with fieldsets when doing a single insert, because
7557 : // fieldsets have multiple insertion points.
7558 11 : NS_ASSERTION(isSingleInsert || frameType != LayoutFrameType::FieldSet,
7559 : "Unexpected parent");
7560 11 : if (IsFrameForFieldSet(insertion.mParentFrame) &&
7561 0 : aStartChild->NodeInfo()->NameAtom() == nsGkAtoms::legend) {
7562 : // Just reframe the parent, since figuring out whether this
7563 : // should be the new legend and then handling it is too complex.
7564 : // We could do a little better here --- check if the fieldset already
7565 : // has a legend which occurs earlier in its child list than this node,
7566 : // and if so, proceed. But we'd have to extend nsFieldSetFrame
7567 : // to locate this legend in the inserted frames and extract it.
7568 0 : LAYOUT_PHASE_TEMP_EXIT();
7569 0 : RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7570 0 : InsertionKind::Async);
7571 0 : LAYOUT_PHASE_TEMP_REENTER();
7572 0 : return;
7573 : }
7574 :
7575 : // We should only get here with details when doing a single insertion because
7576 : // we treat details frame as if it has multiple insertion points.
7577 0 : MOZ_ASSERT(isSingleInsert || frameType != LayoutFrameType::Details);
7578 0 : if (frameType == LayoutFrameType::Details) {
7579 : // When inserting an element into <details>, just reframe the details frame
7580 : // and let it figure out where the element should be laid out. It might seem
7581 : // expensive to recreate the entire details frame, but it's the simplest way
7582 : // to handle the insertion.
7583 0 : LAYOUT_PHASE_TEMP_EXIT();
7584 0 : RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7585 0 : InsertionKind::Async);
7586 0 : LAYOUT_PHASE_TEMP_REENTER();
7587 0 : return;
7588 : }
7589 :
7590 : // Don't construct kids of leaves
7591 11 : if (insertion.mParentFrame->IsLeaf()) {
7592 : // Clear lazy bits so we don't try to construct again.
7593 0 : ClearLazyBits(aStartChild, aEndChild);
7594 0 : return;
7595 : }
7596 :
7597 : // FIXME(emilio): This looks terribly inefficient if you insert elements deep
7598 : // in a MathML subtree.
7599 11 : if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7600 0 : LAYOUT_PHASE_TEMP_EXIT();
7601 0 : RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7602 0 : InsertionKind::Async);
7603 0 : LAYOUT_PHASE_TEMP_REENTER();
7604 0 : return;
7605 : }
7606 :
7607 : nsFrameConstructorState state(mPresShell,
7608 11 : GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
7609 11 : GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
7610 11 : GetFloatContainingBlock(insertion.mParentFrame),
7611 55 : do_AddRef(aFrameState));
7612 :
7613 : // Recover state for the containing block - we need to know if
7614 : // it has :first-letter or :first-line style applied to it. The
7615 : // reason we care is that the internal structure in these cases
7616 : // is not the normal structure and requires custom updating
7617 : // logic.
7618 11 : nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
7619 11 : bool haveFirstLetterStyle = false;
7620 0 : bool haveFirstLineStyle = false;
7621 :
7622 : // In order to shave off some cycles, we only dig up the
7623 : // containing block haveFirst* flags if the parent frame where
7624 : // the insertion/append is occurring is an inline or block
7625 : // container. For other types of containers this isn't relevant.
7626 0 : StyleDisplay parentDisplay = insertion.mParentFrame->GetDisplay();
7627 :
7628 : // Examine the insertion.mParentFrame where the insertion is taking
7629 : // place. If it's a certain kind of container then some special
7630 : // processing is done.
7631 0 : if ((StyleDisplay::Block == parentDisplay) ||
7632 11 : (StyleDisplay::ListItem == parentDisplay) ||
7633 0 : (StyleDisplay::Inline == parentDisplay) ||
7634 : (StyleDisplay::InlineBlock == parentDisplay)) {
7635 : // Recover the special style flags for the containing block
7636 3 : if (containingBlock) {
7637 0 : haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
7638 : haveFirstLineStyle =
7639 0 : ShouldHaveFirstLineStyle(containingBlock->GetContent(),
7640 0 : containingBlock->Style());
7641 : }
7642 :
7643 0 : if (haveFirstLetterStyle) {
7644 : // If our current insertion.mParentFrame is a Letter frame, use its parent as our
7645 : // new parent hint
7646 0 : if (insertion.mParentFrame->IsLetterFrame()) {
7647 : // If insertion.mParentFrame is out of flow, then we actually want the parent of
7648 : // the placeholder frame.
7649 0 : if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7650 : nsPlaceholderFrame* placeholderFrame =
7651 0 : insertion.mParentFrame->GetPlaceholderFrame();
7652 0 : NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
7653 0 : insertion.mParentFrame = placeholderFrame->GetParent();
7654 : } else {
7655 0 : insertion.mParentFrame = insertion.mParentFrame->GetParent();
7656 : }
7657 : }
7658 :
7659 : // Remove the old letter frames before doing the insertion
7660 0 : RemoveLetterFrames(mPresShell, state.mFloatedItems.containingBlock);
7661 :
7662 : // Removing the letterframes messes around with the frame tree, removing
7663 : // and creating frames. We need to reget our prevsibling, parent frame,
7664 : // etc.
7665 : prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend,
7666 0 : &isRangeInsertSafe);
7667 :
7668 : // Need check whether a range insert is still safe.
7669 0 : if (!isSingleInsert && !isRangeInsertSafe) {
7670 : // Need to recover the letter frames first.
7671 0 : RecoverLetterFrames(state.mFloatedItems.containingBlock);
7672 :
7673 : // must fall back to a single ContertInserted for each child in the range
7674 0 : LAYOUT_PHASE_TEMP_EXIT();
7675 0 : IssueSingleInsertNofications(aStartChild, aEndChild, InsertionKind::Sync);
7676 0 : LAYOUT_PHASE_TEMP_REENTER();
7677 0 : return;
7678 : }
7679 :
7680 0 : frameType = insertion.mParentFrame->Type();
7681 : }
7682 : }
7683 :
7684 22 : AutoFrameConstructionItemList items(this);
7685 11 : ParentType parentType = GetParentType(frameType);
7686 22 : FlattenedChildIterator iter(insertion.mContainer);
7687 11 : bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
7688 22 : if (aStartChild->GetPreviousSibling() &&
7689 0 : parentType == eTypeBlock && haveNoXBLChildren) {
7690 : // If there's a text node in the normal content list just before the
7691 : // new nodes, and it has no frame, make a frame construction item for
7692 : // it, because it might need a frame now. No need to do this if our
7693 : // parent type is not block, though, since WipeContainingBlock
7694 : // already handles that sitation.
7695 0 : AddTextItemIfNeeded(state, insertion, aStartChild->GetPreviousSibling(),
7696 0 : items);
7697 : }
7698 :
7699 0 : if (isSingleInsert) {
7700 0 : AddFrameConstructionItems(state, aStartChild,
7701 0 : aStartChild->IsRootOfAnonymousSubtree(),
7702 11 : insertion, items);
7703 : } else {
7704 0 : for (nsIContent* child = aStartChild;
7705 0 : child != aEndChild;
7706 0 : child = child->GetNextSibling()){
7707 0 : AddFrameConstructionItems(state, child, false, insertion, items);
7708 : }
7709 : }
7710 :
7711 0 : if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) {
7712 : // If there's a text node in the normal content list just after the
7713 : // new nodes, and it has no frame, make a frame construction item for
7714 : // it, because it might need a frame now. No need to do this if our
7715 : // parent type is not block, though, since WipeContainingBlock
7716 : // already handles that sitation.
7717 5 : AddTextItemIfNeeded(state, insertion, aEndChild, items);
7718 : }
7719 :
7720 : // Perform special check for diddling around with the frames in
7721 : // a special inline frame.
7722 : // If we're appending before :after content, then we're not really
7723 : // appending, so let WipeContainingBlock know that.
7724 0 : LAYOUT_PHASE_TEMP_EXIT();
7725 11 : if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
7726 : isAppend, prevSibling)) {
7727 0 : LAYOUT_PHASE_TEMP_REENTER();
7728 0 : return;
7729 : }
7730 0 : LAYOUT_PHASE_TEMP_REENTER();
7731 :
7732 : // If the container is a table and a caption will be appended, it needs to be
7733 : // put in the table wrapper frame's additional child list.
7734 : // We make no attempt here to set flags to indicate whether the list
7735 : // will be at the start or end of a block. It doesn't seem worthwhile.
7736 0 : nsFrameItems frameItems, captionItems;
7737 0 : ConstructFramesFromItemList(state, items, insertion.mParentFrame,
7738 0 : ParentIsWrapperAnonBox(insertion.mParentFrame),
7739 0 : frameItems);
7740 :
7741 11 : if (frameItems.NotEmpty()) {
7742 0 : for (nsIContent* child = aStartChild;
7743 0 : child != aEndChild;
7744 0 : child = child->GetNextSibling()){
7745 9 : InvalidateCanvasIfNeeded(mPresShell, child);
7746 : }
7747 :
7748 0 : if (LayoutFrameType::Table == frameType ||
7749 9 : LayoutFrameType::TableWrapper == frameType) {
7750 0 : PullOutCaptionFrames(frameItems, captionItems);
7751 : }
7752 : }
7753 :
7754 0 : if (haveFirstLineStyle && insertion.mParentFrame == containingBlock && isAppend) {
7755 : // It's possible that the new frame goes into a first-line
7756 : // frame. Look at it and see...
7757 0 : AppendFirstLineFrames(state, containingBlock->GetContent(),
7758 0 : containingBlock, frameItems);
7759 33 : } else if (insertion.mParentFrame->Style()->HasPseudoElementData()) {
7760 0 : CheckForFirstLineInsertion(insertion.mParentFrame, frameItems);
7761 0 : CheckForFirstLineInsertion(insertion.mParentFrame, captionItems);
7762 : }
7763 :
7764 : // We might have captions; put them into the caption list of the
7765 : // table wrapper frame.
7766 11 : if (captionItems.NotEmpty()) {
7767 0 : NS_ASSERTION(LayoutFrameType::Table == frameType ||
7768 : LayoutFrameType::TableWrapper == frameType,
7769 : "parent for caption is not table?");
7770 : // We need to determine where to put the caption items; start with the
7771 : // the parent frame that has already been determined and get the insertion
7772 : // prevsibling of the first caption item.
7773 : bool captionIsAppend;
7774 0 : nsIFrame* captionPrevSibling = nullptr;
7775 :
7776 : // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
7777 : bool ignored;
7778 0 : InsertionPoint captionInsertion(insertion.mParentFrame, insertion.mContainer);
7779 0 : if (isSingleInsert) {
7780 : captionPrevSibling =
7781 : GetInsertionPrevSibling(&captionInsertion, aStartChild,
7782 0 : &captionIsAppend, &ignored);
7783 : } else {
7784 0 : nsIContent* firstCaption = captionItems.FirstChild()->GetContent();
7785 : // It is very important here that we skip the children in
7786 : // [aStartChild,aEndChild) when looking for a
7787 : // prevsibling.
7788 : captionPrevSibling =
7789 : GetInsertionPrevSibling(&captionInsertion, firstCaption,
7790 : &captionIsAppend, &ignored,
7791 0 : aStartChild, aEndChild);
7792 : }
7793 :
7794 0 : nsContainerFrame* outerTable = nullptr;
7795 0 : if (GetCaptionAdjustedParent(captionInsertion.mParentFrame,
7796 0 : captionItems.FirstChild(),
7797 : &outerTable)) {
7798 : // If the parent is not a table wrapper frame we will try to add frames
7799 : // to a named child list that the parent does not honor and the frames
7800 : // will get lost.
7801 0 : NS_ASSERTION(outerTable->IsTableWrapperFrame(),
7802 : "Pseudo frame construction failure; "
7803 : "a caption can be only a child of a table wrapper frame");
7804 :
7805 : // If the parent of our current prevSibling is different from the frame
7806 : // we'll actually use as the parent, then the calculated insertion
7807 : // point is now invalid (bug 341382).
7808 0 : if (captionPrevSibling &&
7809 0 : captionPrevSibling->GetParent() != outerTable) {
7810 0 : captionPrevSibling = nullptr;
7811 : }
7812 0 : if (captionIsAppend) {
7813 0 : AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7814 : } else {
7815 0 : InsertFrames(outerTable, nsIFrame::kCaptionList,
7816 0 : captionPrevSibling, captionItems);
7817 : }
7818 : }
7819 : }
7820 :
7821 11 : if (frameItems.NotEmpty()) {
7822 : // Notify the parent frame
7823 9 : if (isAppend) {
7824 0 : AppendFramesToParent(state, insertion.mParentFrame, frameItems, prevSibling);
7825 : } else {
7826 8 : InsertFrames(insertion.mParentFrame, kPrincipalList, prevSibling, frameItems);
7827 : }
7828 : }
7829 :
7830 11 : if (haveFirstLetterStyle) {
7831 : // Recover the letter frames for the containing block when
7832 : // it has first-letter style.
7833 0 : RecoverLetterFrames(state.mFloatedItems.containingBlock);
7834 : }
7835 :
7836 : #ifdef DEBUG
7837 11 : if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
7838 0 : printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
7839 0 : insertion.mParentFrame->List(stdout, 0);
7840 : }
7841 : #endif
7842 :
7843 : #ifdef ACCESSIBILITY
7844 11 : if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7845 0 : accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
7846 : }
7847 : #endif
7848 : }
7849 :
7850 : bool
7851 12 : nsCSSFrameConstructor::ContentRemoved(nsIContent* aChild,
7852 : nsIContent* aOldNextSibling,
7853 : RemoveFlags aFlags)
7854 : {
7855 12 : MOZ_ASSERT(aChild);
7856 12 : MOZ_ASSERT(!aChild->IsRootOfAnonymousSubtree() || !aOldNextSibling,
7857 : "Anonymous roots don't have siblings");
7858 36 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7859 24 : nsPresContext* presContext = mPresShell->GetPresContext();
7860 12 : MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
7861 :
7862 : // We want to detect when the viewport override element stored in the
7863 : // prescontext is in the subtree being removed. Except in fullscreen cases
7864 : // (which are handled in Element::UnbindFromTree and do not get stored on the
7865 : // prescontext), the override element is always either the root element or a
7866 : // <body> child of the root element. So we can only be removing the stored
7867 : // override element if the thing being removed is either the override element
7868 : // itself or the root element (which can be a parent of the override element).
7869 36 : if (aChild == presContext->GetViewportScrollbarStylesOverrideElement() ||
7870 35 : (aChild->IsElement() && !aChild->GetParent())) {
7871 : // We might be removing the element that we propagated viewport scrollbar
7872 : // styles from. Recompute those. (This clause covers two of the three
7873 : // possible scrollbar-propagation sources: the <body> [as aChild or a
7874 : // descendant] and the root node. The other possible scrollbar-propagation
7875 : // source is a fullscreen element, and we have code elsewhere to update
7876 : // scrollbars after fullscreen elements are removed -- specifically, it's
7877 : // part of the fullscreen cleanup code called by Element::UnbindFromTree.
7878 : // We don't handle the fullscreen case here, because it doesn't change the
7879 : // scrollbar styles override element stored on the prescontext.)
7880 : Element* newOverrideElement =
7881 0 : presContext->UpdateViewportScrollbarStylesOverride();
7882 :
7883 : // If aChild is the root, then we don't need to do any reframing of
7884 : // newOverrideElement, because we're about to tear down the whole frame tree
7885 : // anyway. And we need to make sure we don't do any such reframing, because
7886 : // reframing the <body> can trigger a reframe of the <html> and then reenter
7887 : // here.
7888 : //
7889 : // But if aChild is not the root, and if newOverrideElement is not
7890 : // the root and isn't aChild (which it could be if all we're doing
7891 : // here is reframing the current override element), it needs
7892 : // reframing. In particular, it used to have a scrollframe
7893 : // (because its overflow was not "visible"), but now it will
7894 : // propagate its overflow to the viewport, so it should not need a
7895 : // scrollframe anymore.
7896 0 : if (aChild->GetParent() && newOverrideElement &&
7897 0 : newOverrideElement->GetParent() && newOverrideElement != aChild) {
7898 0 : LAYOUT_PHASE_TEMP_EXIT();
7899 0 : RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
7900 0 : LAYOUT_PHASE_TEMP_REENTER();
7901 : }
7902 : }
7903 :
7904 : #ifdef DEBUG
7905 1 : if (gNoisyContentUpdates) {
7906 0 : printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
7907 : "old-next-sibling=%p\n",
7908 : aChild->GetParent(),
7909 : aChild,
7910 0 : aOldNextSibling);
7911 0 : if (gReallyNoisyContentUpdates) {
7912 0 : aChild->GetParent()->List(stdout, 0);
7913 : }
7914 : }
7915 : #endif
7916 :
7917 12 : nsIFrame* childFrame = aChild->GetPrimaryFrame();
7918 21 : if (!childFrame || childFrame->GetContent() != aChild) {
7919 : // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7920 : // Remove it once that's fixed.
7921 3 : childFrame = nullptr;
7922 : }
7923 :
7924 : #ifdef MOZ_XUL
7925 12 : if (NotifyListBoxBody(presContext, aChild, aOldNextSibling,
7926 : childFrame, CONTENT_REMOVED)) {
7927 : return false;
7928 : }
7929 : #endif // MOZ_XUL
7930 :
7931 : // If we're removing the root, then make sure to remove things starting at
7932 : // the viewport's child instead of the primary frame (which might even be
7933 : // null if the root had an XBL binding or display:none, even though the
7934 : // frames above it got created). Detecting removal of a root is a little
7935 : // exciting; in particular, having no parent is necessary but NOT sufficient.
7936 : // Due to how we process reframes, the content node might not even be in our
7937 : // document by now. So explicitly check whether the viewport's first kid's
7938 : // content node is aChild.
7939 : //
7940 : // FIXME(emilio): I think the "might not be in our document" bit is impossible
7941 : // now.
7942 0 : bool isRoot = false;
7943 0 : if (!aChild->GetParent()) {
7944 0 : if (nsIFrame* viewport = GetRootFrame()) {
7945 0 : nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
7946 0 : if (firstChild && firstChild->GetContent() == aChild) {
7947 0 : isRoot = true;
7948 0 : childFrame = firstChild;
7949 0 : NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
7950 : }
7951 : }
7952 : }
7953 :
7954 : // We need to be conservative about when to determine whether something has
7955 : // display: contents or not because at this point our actual display may be
7956 : // different.
7957 : //
7958 : // Consider the case of:
7959 : //
7960 : // <div id="A" style="display: contents"><div id="B"></div></div>
7961 : //
7962 : // If we reconstruct A because its display changed to "none", we still need to
7963 : // cleanup the frame on B, but A's display is now "none", so we can't poke at
7964 : // the style of it.
7965 : //
7966 : // FIXME(emilio, bug 1450366): We can make this faster without adding much
7967 : // complexity for the display: none -> other case, which right now
7968 : // unnecessarily walks the content tree down.
7969 3 : auto CouldHaveBeenDisplayContents = [aFlags](nsIContent* aContent) -> bool {
7970 3 : return aFlags == REMOVE_FOR_RECONSTRUCTION || IsDisplayContents(aContent);
7971 0 : };
7972 :
7973 0 : if (!childFrame && CouldHaveBeenDisplayContents(aChild)) {
7974 : // NOTE(emilio): We may iterate through ::before and ::after here and they
7975 : // may be gone after the respective ContentRemoved call. Right now
7976 : // StyleChildrenIterator handles that properly, so it's not an issue.
7977 0 : StyleChildrenIterator iter(aChild);
7978 0 : for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
7979 0 : if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(aChild)) {
7980 0 : LAYOUT_PHASE_TEMP_EXIT();
7981 : bool didReconstruct =
7982 0 : ContentRemoved(c, nullptr, REMOVE_FOR_RECONSTRUCTION);
7983 0 : LAYOUT_PHASE_TEMP_REENTER();
7984 0 : if (didReconstruct) {
7985 : return true;
7986 : }
7987 : }
7988 : }
7989 : return false;
7990 : }
7991 :
7992 :
7993 0 : if (childFrame) {
7994 0 : InvalidateCanvasIfNeeded(mPresShell, aChild);
7995 :
7996 : // See whether we need to remove more than just childFrame
7997 9 : LAYOUT_PHASE_TEMP_EXIT();
7998 9 : if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
7999 0 : LAYOUT_PHASE_TEMP_REENTER();
8000 0 : return true;
8001 : }
8002 0 : LAYOUT_PHASE_TEMP_REENTER();
8003 :
8004 : // Get the childFrame's parent frame
8005 0 : nsIFrame* parentFrame = childFrame->GetParent();
8006 0 : LayoutFrameType parentType = parentFrame->Type();
8007 :
8008 0 : if (parentType == LayoutFrameType::FrameSet &&
8009 0 : IsSpecialFramesetChild(aChild)) {
8010 : // Just reframe the parent, since framesets are weird like that.
8011 0 : LAYOUT_PHASE_TEMP_EXIT();
8012 0 : RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
8013 0 : LAYOUT_PHASE_TEMP_REENTER();
8014 0 : return true;
8015 : }
8016 :
8017 : // If we're a child of MathML, then we should reframe the MathML content.
8018 : // If we're non-MathML, then we would be wrapped in a block so we need to
8019 : // check our grandparent in that case.
8020 : nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
8021 0 : ? parentFrame->GetParent()
8022 9 : : parentFrame;
8023 9 : if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
8024 0 : LAYOUT_PHASE_TEMP_EXIT();
8025 0 : RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
8026 0 : LAYOUT_PHASE_TEMP_REENTER();
8027 0 : return true;
8028 : }
8029 :
8030 : // Undo XUL wrapping if it's no longer needed.
8031 : // (If we're in the XUL block-wrapping situation, parentFrame is the
8032 : // wrapper frame.)
8033 0 : nsIFrame* grandparentFrame = parentFrame->GetParent();
8034 0 : if (grandparentFrame && grandparentFrame->IsXULBoxFrame() &&
8035 0 : (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
8036 : // check if this frame is the only one needing wrapping
8037 0 : aChild == AnyKidsNeedBlockParent(parentFrame->PrincipalChildList().FirstChild()) &&
8038 0 : !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
8039 0 : LAYOUT_PHASE_TEMP_EXIT();
8040 0 : RecreateFramesForContent(grandparentFrame->GetContent(),
8041 0 : InsertionKind::Async);
8042 0 : LAYOUT_PHASE_TEMP_REENTER();
8043 0 : return true;
8044 : }
8045 :
8046 : #ifdef ACCESSIBILITY
8047 9 : if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
8048 0 : accService->ContentRemoved(mPresShell, aChild);
8049 : }
8050 : #endif
8051 :
8052 : // Examine the containing-block for the removed content and see if
8053 : // :first-letter style applies.
8054 0 : nsIFrame* inflowChild = childFrame;
8055 0 : if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8056 0 : inflowChild = childFrame->GetPlaceholderFrame();
8057 0 : NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
8058 : }
8059 : nsContainerFrame* containingBlock =
8060 9 : GetFloatContainingBlock(inflowChild->GetParent());
8061 9 : bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
8062 9 : if (haveFLS) {
8063 : // Trap out to special routine that handles adjusting a blocks
8064 : // frame tree when first-letter style is present.
8065 : #ifdef NOISY_FIRST_LETTER
8066 : printf("ContentRemoved: containingBlock=");
8067 : nsFrame::ListTag(stdout, containingBlock);
8068 : printf(" parentFrame=");
8069 : nsFrame::ListTag(stdout, parentFrame);
8070 : printf(" childFrame=");
8071 : nsFrame::ListTag(stdout, childFrame);
8072 : printf("\n");
8073 : #endif
8074 :
8075 : // First update the containing blocks structure by removing the
8076 : // existing letter frames. This makes the subsequent logic
8077 : // simpler.
8078 0 : RemoveLetterFrames(mPresShell, containingBlock);
8079 :
8080 : // Recover childFrame and parentFrame
8081 0 : childFrame = aChild->GetPrimaryFrame();
8082 0 : if (!childFrame || childFrame->GetContent() != aChild) {
8083 : // XXXbz the GetContent() != aChild check is needed due to bug 135040.
8084 : // Remove it once that's fixed.
8085 : return false;
8086 : }
8087 0 : parentFrame = childFrame->GetParent();
8088 0 : parentType = parentFrame->Type();
8089 :
8090 : #ifdef NOISY_FIRST_LETTER
8091 : printf(" ==> revised parentFrame=");
8092 : nsFrame::ListTag(stdout, parentFrame);
8093 : printf(" childFrame=");
8094 : nsFrame::ListTag(stdout, childFrame);
8095 : printf("\n");
8096 : #endif
8097 : }
8098 :
8099 : #ifdef DEBUG
8100 9 : if (gReallyNoisyContentUpdates) {
8101 0 : printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
8102 0 : nsFrame::ListTag(stdout, childFrame);
8103 0 : putchar('\n');
8104 0 : parentFrame->List(stdout, 0);
8105 : }
8106 : #endif
8107 :
8108 : // Notify the parent frame that it should delete the frame
8109 0 : if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8110 0 : childFrame = childFrame->GetPlaceholderFrame();
8111 0 : NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
8112 0 : parentFrame = childFrame->GetParent();
8113 : }
8114 :
8115 0 : RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
8116 :
8117 : // NOTE(emilio): aChild could be dead here already if it is a ::before or
8118 : // ::after pseudo-element (since in that case it was owned by childFrame,
8119 : // which we just destroyed).
8120 :
8121 9 : if (isRoot) {
8122 0 : mRootElementFrame = nullptr;
8123 0 : mRootElementStyleFrame = nullptr;
8124 0 : mDocElementContainingBlock = nullptr;
8125 0 : mPageSequenceFrame = nullptr;
8126 0 : mHasRootAbsPosContainingBlock = false;
8127 : }
8128 :
8129 9 : if (haveFLS && mRootElementFrame) {
8130 0 : RecoverLetterFrames(containingBlock);
8131 : }
8132 :
8133 : // If we're just reconstructing frames for the element, then the
8134 : // following ContentInserted notification on the element will
8135 : // take care of fixing up any adjacent text nodes. We don't need
8136 : // to do this if the table parent type of our parent type is not
8137 : // eTypeBlock, though, because in that case the whitespace isn't
8138 : // being suppressed due to us anyway.
8139 9 : if (aOldNextSibling && aFlags == REMOVE_CONTENT &&
8140 0 : GetParentType(parentType) == eTypeBlock) {
8141 0 : MOZ_ASSERT(aChild->GetParentNode(),
8142 : "How did we have a sibling without a parent?");
8143 : // Adjacent whitespace-only text nodes might have been suppressed if
8144 : // this node does not have inline ends. Create frames for them now
8145 : // if necessary.
8146 : // Reframe any text node just before the node being removed, if there is
8147 : // one, and if it's not the last child or the first child. If a whitespace
8148 : // textframe was being suppressed and it's now the last child or first
8149 : // child then it can stay suppressed since the parent must be a block
8150 : // and hence it's adjacent to a block end.
8151 : // If aOldNextSibling is null, then the text node before the node being
8152 : // removed is the last node, and we don't need to worry about it.
8153 : //
8154 : // FIXME(emilio): This should probably use the lazy frame construction
8155 : // bits if possible instead of reframing it in place.
8156 0 : nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
8157 0 : if (prevSibling && prevSibling->GetPreviousSibling()) {
8158 0 : LAYOUT_PHASE_TEMP_EXIT();
8159 0 : ReframeTextIfNeeded(prevSibling);
8160 0 : LAYOUT_PHASE_TEMP_REENTER();
8161 : }
8162 : // Reframe any text node just after the node being removed, if there is
8163 : // one, and if it's not the last child or the first child.
8164 0 : if (aOldNextSibling->GetNextSibling() &&
8165 0 : aOldNextSibling->GetPreviousSibling()) {
8166 0 : LAYOUT_PHASE_TEMP_EXIT();
8167 0 : ReframeTextIfNeeded(aOldNextSibling);
8168 0 : LAYOUT_PHASE_TEMP_REENTER();
8169 : }
8170 : }
8171 :
8172 : #ifdef DEBUG
8173 9 : if (gReallyNoisyContentUpdates && parentFrame) {
8174 0 : printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
8175 0 : parentFrame->List(stdout, 0);
8176 : }
8177 : #endif
8178 : }
8179 :
8180 : return false;
8181 : }
8182 :
8183 : /**
8184 : * This method invalidates the canvas when frames are removed or added for a
8185 : * node that might have its background propagated to the canvas, i.e., a
8186 : * document root node or an HTML BODY which is a child of the root node.
8187 : *
8188 : * @param aFrame a frame for a content node about to be removed or a frame that
8189 : * was just created for a content node that was inserted.
8190 : */
8191 : static void
8192 70 : InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node)
8193 : {
8194 0 : MOZ_ASSERT(presShell->GetRootFrame(), "What happened here?");
8195 0 : MOZ_ASSERT(presShell->GetPresContext(), "Say what?");
8196 :
8197 : // Note that both in ContentRemoved and ContentInserted the content node
8198 : // will still have the right parent pointer, so looking at that is ok.
8199 :
8200 70 : nsIContent* parent = node->GetParent();
8201 70 : if (parent) {
8202 : // Has a parent; might not be what we want
8203 51 : nsIContent* grandParent = parent->GetParent();
8204 0 : if (grandParent) {
8205 : // Has a grandparent, so not what we want
8206 : return;
8207 : }
8208 :
8209 : // Check whether it's an HTML body
8210 19 : if (!node->IsHTMLElement(nsGkAtoms::body)) {
8211 : return;
8212 : }
8213 : }
8214 :
8215 : // At this point the node has no parent or it's an HTML <body> child of the
8216 : // root. We might not need to invalidate in this case (eg we might be in
8217 : // XHTML or something), but chances are we want to. Play it safe.
8218 : // Invalidate the viewport.
8219 :
8220 38 : nsIFrame* rootFrame = presShell->GetRootFrame();
8221 19 : rootFrame->InvalidateFrameSubtree();
8222 : }
8223 :
8224 : bool
8225 0 : nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
8226 : CharacterData* aContent)
8227 : {
8228 0 : if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
8229 : return false;
8230 : }
8231 :
8232 0 : if (mAlwaysCreateFramesForIgnorableWhitespace) {
8233 : return false;
8234 : }
8235 :
8236 : // Text frame may have been suppressed. Disable suppression and signal that a
8237 : // flush should be performed. We do this on a document-wide basis so that
8238 : // pages that repeatedly query metrics for collapsed-whitespace text nodes
8239 : // don't trigger pathological behavior.
8240 0 : mAlwaysCreateFramesForIgnorableWhitespace = true;
8241 0 : Element* root = mDocument->GetRootElement();
8242 0 : if (!root) {
8243 : return false;
8244 : }
8245 :
8246 0 : RestyleManager()->PostRestyleEvent(
8247 0 : root, nsRestyleHint(0), nsChangeHint_ReconstructFrame);
8248 0 : return true;
8249 : }
8250 :
8251 : void
8252 0 : nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
8253 : const CharacterDataChangeInfo& aInfo)
8254 : {
8255 6 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
8256 :
8257 0 : if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
8258 4 : !aContent->TextIsOnlyWhitespace()) ||
8259 2 : (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
8260 0 : aContent->TextIsOnlyWhitespace())) {
8261 : #ifdef DEBUG
8262 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
8263 0 : NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
8264 : "Bit should never be set on generated content");
8265 : #endif
8266 0 : LAYOUT_PHASE_TEMP_EXIT();
8267 0 : RecreateFramesForContent(aContent, InsertionKind::Async);
8268 0 : LAYOUT_PHASE_TEMP_REENTER();
8269 0 : return;
8270 : }
8271 :
8272 :
8273 : // It's possible the frame whose content changed isn't inserted into the
8274 : // frame hierarchy yet, or that there is no frame that maps the content
8275 2 : if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
8276 : #if 0
8277 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
8278 : ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
8279 : aContent, ContentTag(aContent, 0),
8280 : aSubContent, frame));
8281 : #endif
8282 :
8283 : // Special check for text content that is a child of a letter frame. If
8284 : // this happens, we should remove the letter frame, do whatever we're
8285 : // planning to do with this notification, then put the letter frame back.
8286 : // Note that this is basically what RecreateFramesForContent ends up doing;
8287 : // the reason we dont' want to call that here is that our text content
8288 : // could be native anonymous, in which case RecreateFramesForContent would
8289 : // completely barf on it. And recreating the non-anonymous ancestor would
8290 : // just lead us to come back into this notification (e.g. if quotes or
8291 : // counters are involved), leading to a loop.
8292 0 : nsContainerFrame* block = GetFloatContainingBlock(frame);
8293 0 : bool haveFirstLetterStyle = false;
8294 0 : if (block) {
8295 : // See if the block has first-letter style applied to it.
8296 0 : haveFirstLetterStyle = HasFirstLetterStyle(block);
8297 0 : if (haveFirstLetterStyle) {
8298 0 : RemoveLetterFrames(mPresShell, block);
8299 : // Reget |frame|, since we might have killed it.
8300 : // Do we really need to call CharacterDataChanged in this case, though?
8301 0 : frame = aContent->GetPrimaryFrame();
8302 0 : NS_ASSERTION(frame, "Should have frame here!");
8303 : }
8304 : }
8305 :
8306 : // Notify the first frame that maps the content. It will generate a reflow
8307 : // command
8308 0 : frame->CharacterDataChanged(aInfo);
8309 :
8310 0 : if (haveFirstLetterStyle) {
8311 0 : RecoverLetterFrames(block);
8312 : }
8313 : }
8314 : }
8315 :
8316 : void
8317 0 : nsCSSFrameConstructor::RecalcQuotesAndCounters()
8318 : {
8319 159 : nsAutoScriptBlocker scriptBlocker;
8320 :
8321 0 : if (mQuotesDirty) {
8322 0 : mQuotesDirty = false;
8323 0 : mQuoteList.RecalcAll();
8324 : }
8325 :
8326 0 : if (mCountersDirty) {
8327 0 : mCountersDirty = false;
8328 0 : mCounterManager.RecalcAll();
8329 : }
8330 :
8331 53 : NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
8332 0 : NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
8333 0 : }
8334 :
8335 : void
8336 0 : nsCSSFrameConstructor::NotifyCounterStylesAreDirty()
8337 : {
8338 0 : mCounterManager.SetAllDirty();
8339 0 : CountersDirty();
8340 0 : }
8341 :
8342 : void
8343 0 : nsCSSFrameConstructor::WillDestroyFrameTree()
8344 : {
8345 : #if defined(DEBUG_dbaron_off)
8346 : mCounterManager.Dump();
8347 : #endif
8348 :
8349 0 : mIsDestroyingFrameTree = true;
8350 :
8351 : // Prevent frame tree destruction from being O(N^2)
8352 8 : mQuoteList.Clear();
8353 16 : mCounterManager.Clear();
8354 8 : nsFrameManager::Destroy();
8355 8 : }
8356 :
8357 : //STATIC
8358 :
8359 : // XXXbz I'd really like this method to go away. Once we have inline-block and
8360 : // I can just use that for sized broken images, that can happen, maybe.
8361 : void
8362 0 : nsCSSFrameConstructor::GetAlternateTextFor(Element* aElement,
8363 : nsAtom* aTag,
8364 : nsAString& aAltText)
8365 : {
8366 : // The "alt" attribute specifies alternate text that is rendered
8367 : // when the image can not be displayed.
8368 0 : if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText)) {
8369 : return;
8370 : }
8371 :
8372 0 : if (nsGkAtoms::input == aTag) {
8373 : // If there's no "alt" attribute, and aContent is an input element, then use
8374 : // the value of the "value" attribute
8375 0 : if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
8376 : return;
8377 : }
8378 :
8379 : // If there's no "value" attribute either, then use the localized string for
8380 : // "Submit" as the alternate text.
8381 : nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
8382 0 : "Submit", aAltText);
8383 : }
8384 : }
8385 :
8386 : nsIFrame*
8387 0 : nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
8388 : nsPresContext* aPresContext,
8389 : nsIFrame* aFrame,
8390 : nsContainerFrame* aParentFrame,
8391 : nsIContent* aContent,
8392 : ComputedStyle* aComputedStyle)
8393 : {
8394 0 : nsTableWrapperFrame* newFrame = NS_NewTableWrapperFrame(aPresShell, aComputedStyle);
8395 :
8396 0 : newFrame->Init(aContent, aParentFrame, aFrame);
8397 :
8398 : // Create a continuing inner table frame, and if there's a caption then
8399 : // replicate the caption
8400 0 : nsFrameItems newChildFrames;
8401 :
8402 0 : nsIFrame* childFrame = aFrame->PrincipalChildList().FirstChild();
8403 0 : if (childFrame) {
8404 : nsIFrame* continuingTableFrame =
8405 0 : CreateContinuingFrame(aPresContext, childFrame, newFrame);
8406 0 : newChildFrames.AddChild(continuingTableFrame);
8407 :
8408 0 : NS_ASSERTION(!childFrame->GetNextSibling(),"there can be only one inner table frame");
8409 : }
8410 :
8411 : // Set the table wrapper's initial child list
8412 0 : newFrame->SetInitialChildList(kPrincipalList, newChildFrames);
8413 :
8414 0 : return newFrame;
8415 : }
8416 :
8417 : nsIFrame*
8418 0 : nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
8419 : nsIFrame* aFrame,
8420 : nsContainerFrame* aParentFrame,
8421 : nsIContent* aContent,
8422 : ComputedStyle* aComputedStyle)
8423 : {
8424 0 : nsTableFrame* newFrame = NS_NewTableFrame(aPresShell, aComputedStyle);
8425 :
8426 0 : newFrame->Init(aContent, aParentFrame, aFrame);
8427 :
8428 : // Replicate any header/footer frames
8429 0 : nsFrameItems childFrames;
8430 0 : for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
8431 : // See if it's a header/footer, possibly wrapped in a scroll frame.
8432 : nsTableRowGroupFrame* rowGroupFrame =
8433 0 : static_cast<nsTableRowGroupFrame*>(childFrame);
8434 : // If the row group was continued, then don't replicate it.
8435 0 : nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
8436 0 : if (rgNextInFlow) {
8437 0 : rowGroupFrame->SetRepeatable(false);
8438 : }
8439 0 : else if (rowGroupFrame->IsRepeatable()) {
8440 : // Replicate the header/footer frame.
8441 : nsTableRowGroupFrame* headerFooterFrame;
8442 0 : nsFrameItems childItems;
8443 :
8444 : nsFrameConstructorState state(mPresShell,
8445 : GetAbsoluteContainingBlock(newFrame, FIXED_POS),
8446 : GetAbsoluteContainingBlock(newFrame, ABS_POS),
8447 0 : nullptr);
8448 0 : state.mCreatingExtraFrames = true;
8449 :
8450 0 : ComputedStyle* const headerFooterComputedStyle = rowGroupFrame->Style();
8451 : headerFooterFrame = static_cast<nsTableRowGroupFrame*>
8452 0 : (NS_NewTableRowGroupFrame(aPresShell, headerFooterComputedStyle));
8453 :
8454 0 : nsIContent* headerFooter = rowGroupFrame->GetContent();
8455 0 : headerFooterFrame->Init(headerFooter, newFrame, nullptr);
8456 :
8457 0 : nsFrameConstructorSaveState absoluteSaveState;
8458 0 : MakeTablePartAbsoluteContainingBlockIfNeeded(state,
8459 : headerFooterComputedStyle->StyleDisplay(),
8460 : absoluteSaveState,
8461 0 : headerFooterFrame);
8462 :
8463 0 : ProcessChildren(state, headerFooter, rowGroupFrame->Style(),
8464 : headerFooterFrame, true, childItems, false,
8465 0 : nullptr);
8466 0 : NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
8467 0 : headerFooterFrame->SetInitialChildList(kPrincipalList, childItems);
8468 0 : headerFooterFrame->SetRepeatable(true);
8469 :
8470 : // Table specific initialization
8471 0 : headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
8472 :
8473 : // XXX Deal with absolute and fixed frames...
8474 0 : childFrames.AddChild(headerFooterFrame);
8475 : }
8476 : }
8477 :
8478 : // Set the table frame's initial child list
8479 0 : newFrame->SetInitialChildList(kPrincipalList, childFrames);
8480 :
8481 0 : return newFrame;
8482 : }
8483 :
8484 : nsIFrame*
8485 0 : nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
8486 : nsIFrame* aFrame,
8487 : nsContainerFrame* aParentFrame,
8488 : bool aIsFluid)
8489 : {
8490 0 : nsIPresShell* shell = aPresContext->PresShell();
8491 0 : ComputedStyle* computedStyle = aFrame->Style();
8492 0 : nsIFrame* newFrame = nullptr;
8493 0 : nsIFrame* nextContinuation = aFrame->GetNextContinuation();
8494 0 : nsIFrame* nextInFlow = aFrame->GetNextInFlow();
8495 :
8496 : // Use the frame type to determine what type of frame to create
8497 0 : LayoutFrameType frameType = aFrame->Type();
8498 0 : nsIContent* content = aFrame->GetContent();
8499 :
8500 0 : NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE,
8501 : "why CreateContinuingFrame for a non-splittable frame?");
8502 :
8503 0 : if (LayoutFrameType::Text == frameType) {
8504 0 : newFrame = NS_NewContinuingTextFrame(shell, computedStyle);
8505 0 : newFrame->Init(content, aParentFrame, aFrame);
8506 0 : } else if (LayoutFrameType::Inline == frameType) {
8507 0 : newFrame = NS_NewInlineFrame(shell, computedStyle);
8508 0 : newFrame->Init(content, aParentFrame, aFrame);
8509 0 : } else if (LayoutFrameType::Block == frameType) {
8510 0 : MOZ_ASSERT(!aFrame->IsTableCaption(),
8511 : "no support for fragmenting table captions yet");
8512 0 : newFrame = NS_NewBlockFrame(shell, computedStyle);
8513 0 : newFrame->Init(content, aParentFrame, aFrame);
8514 : #ifdef MOZ_XUL
8515 0 : } else if (LayoutFrameType::XULLabel == frameType) {
8516 0 : newFrame = NS_NewXULLabelFrame(shell, computedStyle);
8517 0 : newFrame->Init(content, aParentFrame, aFrame);
8518 : #endif
8519 0 : } else if (LayoutFrameType::ColumnSet == frameType) {
8520 0 : MOZ_ASSERT(!aFrame->IsTableCaption(),
8521 : "no support for fragmenting table captions yet");
8522 0 : newFrame = NS_NewColumnSetFrame(shell, computedStyle, nsFrameState(0));
8523 0 : newFrame->Init(content, aParentFrame, aFrame);
8524 0 : } else if (LayoutFrameType::Page == frameType) {
8525 : nsContainerFrame* canvasFrame;
8526 0 : newFrame = ConstructPageFrame(shell, aParentFrame, aFrame, canvasFrame);
8527 0 : } else if (LayoutFrameType::TableWrapper == frameType) {
8528 : newFrame =
8529 : CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
8530 0 : content, computedStyle);
8531 :
8532 0 : } else if (LayoutFrameType::Table == frameType) {
8533 : newFrame =
8534 : CreateContinuingTableFrame(shell, aFrame, aParentFrame,
8535 0 : content, computedStyle);
8536 :
8537 0 : } else if (LayoutFrameType::TableRowGroup == frameType) {
8538 0 : newFrame = NS_NewTableRowGroupFrame(shell, computedStyle);
8539 0 : newFrame->Init(content, aParentFrame, aFrame);
8540 0 : if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8541 0 : nsTableFrame::RegisterPositionedTablePart(newFrame);
8542 : }
8543 0 : } else if (LayoutFrameType::TableRow == frameType) {
8544 0 : nsTableRowFrame* rowFrame = NS_NewTableRowFrame(shell, computedStyle);
8545 :
8546 0 : rowFrame->Init(content, aParentFrame, aFrame);
8547 0 : if (rowFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8548 0 : nsTableFrame::RegisterPositionedTablePart(rowFrame);
8549 : }
8550 :
8551 : // Create a continuing frame for each table cell frame
8552 0 : nsFrameItems newChildList;
8553 0 : nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
8554 0 : while (cellFrame) {
8555 : // See if it's a table cell frame
8556 0 : if (IS_TABLE_CELL(cellFrame->Type())) {
8557 : nsIFrame* continuingCellFrame =
8558 0 : CreateContinuingFrame(aPresContext, cellFrame, rowFrame);
8559 0 : newChildList.AddChild(continuingCellFrame);
8560 : }
8561 0 : cellFrame = cellFrame->GetNextSibling();
8562 : }
8563 :
8564 0 : rowFrame->SetInitialChildList(kPrincipalList, newChildList);
8565 0 : newFrame = rowFrame;
8566 :
8567 0 : } else if (IS_TABLE_CELL(frameType)) {
8568 : // Warning: If you change this and add a wrapper frame around table cell
8569 : // frames, make sure Bug 368554 doesn't regress!
8570 : // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
8571 : nsTableFrame* tableFrame =
8572 0 : static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
8573 : nsTableCellFrame* cellFrame =
8574 0 : NS_NewTableCellFrame(shell, computedStyle, tableFrame);
8575 :
8576 0 : cellFrame->Init(content, aParentFrame, aFrame);
8577 0 : if (cellFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8578 0 : nsTableFrame::RegisterPositionedTablePart(cellFrame);
8579 : }
8580 :
8581 : // Create a continuing area frame
8582 0 : nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
8583 : nsIFrame* continuingBlockFrame =
8584 : CreateContinuingFrame(aPresContext, blockFrame,
8585 0 : static_cast<nsContainerFrame*>(cellFrame));
8586 :
8587 0 : SetInitialSingleChild(cellFrame, continuingBlockFrame);
8588 0 : newFrame = cellFrame;
8589 0 : } else if (LayoutFrameType::Line == frameType) {
8590 0 : newFrame = NS_NewFirstLineFrame(shell, computedStyle);
8591 0 : newFrame->Init(content, aParentFrame, aFrame);
8592 0 : } else if (LayoutFrameType::Letter == frameType) {
8593 0 : newFrame = NS_NewFirstLetterFrame(shell, computedStyle);
8594 0 : newFrame->Init(content, aParentFrame, aFrame);
8595 0 : } else if (LayoutFrameType::Image == frameType) {
8596 0 : newFrame = NS_NewImageFrame(shell, computedStyle);
8597 0 : newFrame->Init(content, aParentFrame, aFrame);
8598 0 : } else if (LayoutFrameType::ImageControl == frameType) {
8599 0 : newFrame = NS_NewImageControlFrame(shell, computedStyle);
8600 0 : newFrame->Init(content, aParentFrame, aFrame);
8601 0 : } else if (LayoutFrameType::Placeholder == frameType) {
8602 : // create a continuing out of flow frame
8603 0 : nsIFrame* oofFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
8604 : nsIFrame* oofContFrame =
8605 0 : CreateContinuingFrame(aPresContext, oofFrame, aParentFrame);
8606 : newFrame =
8607 0 : CreatePlaceholderFrameFor(shell, content, oofContFrame,
8608 : aParentFrame, aFrame,
8609 0 : aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK);
8610 0 : } else if (LayoutFrameType::FieldSet == frameType) {
8611 0 : nsContainerFrame* fieldset = NS_NewFieldSetFrame(shell, computedStyle);
8612 :
8613 0 : fieldset->Init(content, aParentFrame, aFrame);
8614 :
8615 : // Create a continuing area frame
8616 : // XXXbz we really shouldn't have to do this by hand!
8617 0 : nsContainerFrame* blockFrame = GetFieldSetBlockFrame(aFrame);
8618 0 : if (blockFrame) {
8619 : nsIFrame* continuingBlockFrame =
8620 0 : CreateContinuingFrame(aPresContext, blockFrame, fieldset);
8621 : // Set the fieldset's initial child list
8622 0 : SetInitialSingleChild(fieldset, continuingBlockFrame);
8623 : } else {
8624 0 : MOZ_ASSERT(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
8625 : "FieldSet block may only be null for overflow containers");
8626 : }
8627 : newFrame = fieldset;
8628 0 : } else if (LayoutFrameType::Legend == frameType) {
8629 0 : newFrame = NS_NewLegendFrame(shell, computedStyle);
8630 0 : newFrame->Init(content, aParentFrame, aFrame);
8631 0 : } else if (LayoutFrameType::FlexContainer == frameType) {
8632 0 : newFrame = NS_NewFlexContainerFrame(shell, computedStyle);
8633 0 : newFrame->Init(content, aParentFrame, aFrame);
8634 0 : } else if (LayoutFrameType::GridContainer == frameType) {
8635 0 : newFrame = NS_NewGridContainerFrame(shell, computedStyle);
8636 0 : newFrame->Init(content, aParentFrame, aFrame);
8637 0 : } else if (LayoutFrameType::Ruby == frameType) {
8638 0 : newFrame = NS_NewRubyFrame(shell, computedStyle);
8639 0 : newFrame->Init(content, aParentFrame, aFrame);
8640 0 : } else if (LayoutFrameType::RubyBaseContainer == frameType) {
8641 0 : newFrame = NS_NewRubyBaseContainerFrame(shell, computedStyle);
8642 0 : newFrame->Init(content, aParentFrame, aFrame);
8643 0 : } else if (LayoutFrameType::RubyTextContainer == frameType) {
8644 0 : newFrame = NS_NewRubyTextContainerFrame(shell, computedStyle);
8645 0 : newFrame->Init(content, aParentFrame, aFrame);
8646 0 : } else if (LayoutFrameType::Details == frameType) {
8647 0 : newFrame = NS_NewDetailsFrame(shell, computedStyle);
8648 0 : newFrame->Init(content, aParentFrame, aFrame);
8649 : } else {
8650 0 : MOZ_CRASH("unexpected frame type");
8651 : }
8652 :
8653 : // Init() set newFrame to be a fluid continuation of aFrame.
8654 : // If we want a non-fluid continuation, we need to call SetPrevContinuation()
8655 : // to reset NS_FRAME_IS_FLUID_CONTINUATION.
8656 0 : if (!aIsFluid) {
8657 0 : newFrame->SetPrevContinuation(aFrame);
8658 : }
8659 :
8660 : // A continuation of generated content is also generated content
8661 0 : if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
8662 : newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
8663 : }
8664 :
8665 : // A continuation of nsIAnonymousContentCreator content is also
8666 : // nsIAnonymousContentCreator created content
8667 0 : if (aFrame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
8668 : newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
8669 : }
8670 :
8671 : // A continuation of an out-of-flow is also an out-of-flow
8672 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8673 : newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
8674 : }
8675 :
8676 0 : if (nextInFlow) {
8677 0 : nextInFlow->SetPrevInFlow(newFrame);
8678 0 : newFrame->SetNextInFlow(nextInFlow);
8679 0 : } else if (nextContinuation) {
8680 0 : nextContinuation->SetPrevContinuation(newFrame);
8681 0 : newFrame->SetNextContinuation(nextContinuation);
8682 : }
8683 :
8684 0 : MOZ_ASSERT(!newFrame->GetNextSibling(), "unexpected sibling");
8685 0 : return newFrame;
8686 : }
8687 :
8688 : nsresult
8689 0 : nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
8690 : {
8691 : // Now deal with fixed-pos things.... They should appear on all pages,
8692 : // so we want to move over the placeholders when processing the child
8693 : // of the pageContentFrame.
8694 :
8695 0 : nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
8696 0 : if (!prevPageContentFrame) {
8697 : return NS_OK;
8698 : }
8699 : nsContainerFrame* canvasFrame =
8700 0 : do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
8701 0 : nsIFrame* prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
8702 0 : if (!canvasFrame || !prevCanvasFrame) {
8703 : // document's root element frame missing
8704 : return NS_ERROR_UNEXPECTED;
8705 : }
8706 :
8707 0 : nsFrameItems fixedPlaceholders;
8708 0 : nsIFrame* firstFixed = prevPageContentFrame->GetChildList(nsIFrame::kFixedList).FirstChild();
8709 0 : if (!firstFixed) {
8710 : return NS_OK;
8711 : }
8712 :
8713 : // Don't allow abs-pos descendants of the fixed content to escape the content.
8714 : // This should not normally be possible (because fixed-pos elements should
8715 : // be absolute containers) but fixed-pos tables currently aren't abs-pos
8716 : // containers.
8717 : nsFrameConstructorState state(mPresShell,
8718 : aParentFrame,
8719 : nullptr,
8720 0 : mRootElementFrame);
8721 0 : state.mCreatingExtraFrames = true;
8722 :
8723 : // We can't use an ancestor filter here, because we're not going to
8724 : // be usefully recurring down the tree. This means that other
8725 : // places in frame construction can't assume a filter is
8726 : // initialized!
8727 :
8728 : // Iterate across fixed frames and replicate each whose placeholder is a
8729 : // descendant of aFrame. (We don't want to explicitly copy placeholders that
8730 : // are within fixed frames, because that would cause duplicates on the new
8731 : // page - bug 389619)
8732 0 : for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
8733 0 : nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
8734 0 : if (prevPlaceholder &&
8735 0 : nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
8736 : // We want to use the same style as the primary style frame for
8737 : // our content
8738 0 : nsIContent* content = fixed->GetContent();
8739 : ComputedStyle* computedStyle =
8740 0 : nsLayoutUtils::GetStyleFrame(content)->Style();
8741 0 : AutoFrameConstructionItemList items(this);
8742 : AddFrameConstructionItemsInternal(state, content, canvasFrame,
8743 : true,
8744 : computedStyle,
8745 : ITEM_ALLOW_XBL_BASE |
8746 : ITEM_ALLOW_PAGE_BREAK,
8747 0 : nullptr, items);
8748 : ConstructFramesFromItemList(state, items, canvasFrame,
8749 : /* aParentIsWrapperAnonBox = */ false,
8750 0 : fixedPlaceholders);
8751 : }
8752 : }
8753 :
8754 : // Add the placeholders to our primary child list.
8755 : // XXXbz this is a little screwed up, since the fixed frames will have
8756 : // broken auto-positioning. Oh, well.
8757 0 : NS_ASSERTION(!canvasFrame->PrincipalChildList().FirstChild(),
8758 : "leaking frames; doc root continuation must be empty");
8759 0 : canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders);
8760 : return NS_OK;
8761 : }
8762 :
8763 : nsCSSFrameConstructor::InsertionPoint
8764 90 : nsCSSFrameConstructor::GetInsertionPoint(nsIContent* aChild)
8765 : {
8766 90 : MOZ_ASSERT(aChild);
8767 90 : nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
8768 0 : if (!insertionElement) {
8769 : // The element doesn't belong in the flattened tree, and thus we don't want
8770 : // to render it.
8771 0 : return { };
8772 : }
8773 :
8774 0 : return { GetContentInsertionFrameFor(insertionElement), insertionElement };
8775 : }
8776 :
8777 : // Capture state for the frame tree rooted at the frame associated with the
8778 : // content object, aContent
8779 : void
8780 0 : nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
8781 : nsILayoutHistoryState* aHistoryState)
8782 : {
8783 7 : if (!aHistoryState) {
8784 : return;
8785 : }
8786 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
8787 7 : if (frame == mRootElementFrame) {
8788 0 : frame = mRootElementFrame ?
8789 : GetAbsoluteContainingBlock(mRootElementFrame, FIXED_POS) :
8790 0 : GetRootFrame();
8791 : }
8792 21 : for ( ; frame;
8793 : frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
8794 0 : CaptureFrameState(frame, aHistoryState);
8795 : }
8796 : }
8797 :
8798 :
8799 : static bool
8800 12 : IsWhitespaceFrame(nsIFrame* aFrame)
8801 : {
8802 12 : MOZ_ASSERT(aFrame, "invalid argument");
8803 0 : return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
8804 : }
8805 :
8806 : static nsIFrame*
8807 0 : FindFirstNonWhitespaceChild(nsIFrame* aParentFrame)
8808 : {
8809 0 : nsIFrame* f = aParentFrame->PrincipalChildList().FirstChild();
8810 0 : while (f && IsWhitespaceFrame(f)) {
8811 0 : f = f->GetNextSibling();
8812 : }
8813 0 : return f;
8814 : }
8815 :
8816 : static nsIFrame*
8817 0 : FindNextNonWhitespaceSibling(nsIFrame* aFrame)
8818 : {
8819 16 : nsIFrame* f = aFrame;
8820 16 : do {
8821 0 : f = f->GetNextSibling();
8822 16 : } while (f && IsWhitespaceFrame(f));
8823 0 : return f;
8824 : }
8825 :
8826 : static nsIFrame*
8827 0 : FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
8828 : {
8829 0 : nsIFrame* f = aFrame;
8830 0 : do {
8831 0 : f = f->GetPrevSibling();
8832 0 : } while (f && IsWhitespaceFrame(f));
8833 0 : return f;
8834 : }
8835 :
8836 : bool
8837 16 : nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
8838 : {
8839 16 : MOZ_ASSERT(aFrame, "Must have a frame");
8840 16 : MOZ_ASSERT(aFrame->GetParent(), "Frame shouldn't be root");
8841 16 : MOZ_ASSERT(aFrame == aFrame->FirstContinuation(),
8842 : "aFrame not the result of GetPrimaryFrame()?");
8843 :
8844 1 : if (IsFramePartOfIBSplit(aFrame)) {
8845 : // The removal functions can't handle removal of an {ib} split directly; we
8846 : // need to rebuild the containing block.
8847 : #ifdef DEBUG
8848 0 : if (gNoisyContentUpdates) {
8849 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8850 0 : "frame=");
8851 0 : nsFrame::ListTag(stdout, aFrame);
8852 : printf(" is ib-split\n");
8853 : }
8854 : #endif
8855 :
8856 0 : ReframeContainingBlock(aFrame);
8857 0 : return true;
8858 : }
8859 :
8860 16 : nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
8861 16 : if (insertionFrame && insertionFrame->IsLegendFrame() &&
8862 0 : aFrame->GetParent()->IsFieldSetFrame()) {
8863 0 : RecreateFramesForContent(aFrame->GetParent()->GetContent(),
8864 0 : InsertionKind::Async);
8865 0 : return true;
8866 : }
8867 :
8868 : nsIFrame* inFlowFrame =
8869 32 : (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
8870 0 : aFrame->GetPlaceholderFrame() : aFrame;
8871 16 : MOZ_ASSERT(inFlowFrame, "How did that happen?");
8872 0 : MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
8873 : "placeholder for primary frame has previous continuations?");
8874 16 : nsIFrame* parent = inFlowFrame->GetParent();
8875 :
8876 16 : if (parent && parent->IsDetailsFrame()) {
8877 : HTMLSummaryElement* summary =
8878 0 : HTMLSummaryElement::FromNode(aFrame->GetContent());
8879 0 : DetailsFrame* detailsFrame = static_cast<DetailsFrame*>(parent);
8880 :
8881 : // Unlike adding summary element cases, we need to check children of the
8882 : // parent details frame since at this moment the summary element has been
8883 : // already removed from the parent details element's child list.
8884 0 : if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) {
8885 : // When removing a summary, we should reframe the parent details frame to
8886 : // ensure that another summary is used or the default summary is
8887 : // generated.
8888 0 : RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8889 0 : return true;
8890 : }
8891 : }
8892 :
8893 : // Now check for possibly needing to reconstruct due to a pseudo parent
8894 : // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
8895 : // need to be checked here, since all other types of parent will be catched
8896 : // by "Check ruby containers" section below.
8897 0 : if (IsTableOrRubyPseudo(parent)) {
8898 0 : if (FindFirstNonWhitespaceChild(parent) == inFlowFrame ||
8899 0 : !FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()) ||
8900 : // If it is a whitespace, and is the only child of the parent, the
8901 : // pseudo parent was created for the space, and should now be removed.
8902 0 : (IsWhitespaceFrame(aFrame) &&
8903 0 : parent->PrincipalChildList().OnlyChild()) ||
8904 : // If we're a table-column-group, then the OnlyChild check above is
8905 : // not going to catch cases when we're the first child.
8906 0 : (inFlowFrame->IsTableColGroupFrame() &&
8907 0 : parent->GetChildList(nsIFrame::kColGroupList).FirstChild() == inFlowFrame) ||
8908 : // Similar if we're a table-caption.
8909 0 : (inFlowFrame->IsTableCaption() &&
8910 0 : parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
8911 0 : RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8912 0 : return true;
8913 : }
8914 : }
8915 :
8916 : // Might need to reconstruct things if this frame's nextSibling is a table
8917 : // or ruby pseudo, since removal of this frame might mean that this pseudo
8918 : // needs to get merged with the frame's prevSibling if that's also a table
8919 : // or ruby pseudo.
8920 : nsIFrame* nextSibling =
8921 0 : FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
8922 0 : NS_ASSERTION(!IsTableOrRubyPseudo(inFlowFrame), "Shouldn't happen here");
8923 : // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
8924 : // need to be checked here, since all other types of such frames will have
8925 : // a ruby container parent, and be catched by "Check ruby containers" below.
8926 1 : if (nextSibling && IsTableOrRubyPseudo(nextSibling)) {
8927 0 : nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
8928 0 : if (prevSibling && IsTableOrRubyPseudo(prevSibling)) {
8929 : #ifdef DEBUG
8930 0 : if (gNoisyContentUpdates) {
8931 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8932 0 : "frame=");
8933 0 : nsFrame::ListTag(stdout, aFrame);
8934 : printf(" has a table pseudo next sibling of different type and a "
8935 : "table pseudo prevsibling\n");
8936 : }
8937 : #endif
8938 : // Good enough to recreate frames for aFrame's parent's content; even if
8939 : // aFrame's parent is a pseudo, that'll be the right content node.
8940 0 : RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8941 0 : return true;
8942 : }
8943 : }
8944 :
8945 : // Check ruby containers
8946 16 : LayoutFrameType parentType = parent->Type();
8947 32 : if (parentType == LayoutFrameType::Ruby ||
8948 16 : RubyUtils::IsRubyContainerBox(parentType)) {
8949 : // In ruby containers, pseudo frames may be created from
8950 : // whitespaces or even nothing. There are two cases we actually
8951 : // need to handle here, but hard to check exactly:
8952 : // 1. Status of spaces beside the frame may vary, and related
8953 : // frames may be constructed or destroyed accordingly.
8954 : // 2. The type of the first child of a ruby frame determines
8955 : // whether a pseudo ruby base container should exist.
8956 0 : RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8957 0 : return true;
8958 : }
8959 :
8960 : // Might need to reconstruct things if the removed frame's nextSibling is an
8961 : // anonymous flex item. The removed frame might've been what divided two
8962 : // runs of inline content into two anonymous flex items, which would now
8963 : // need to be merged.
8964 : // NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
8965 : // we're only interested in anonymous flex items here, and those can never
8966 : // be adjacent to whitespace, since they absorb contiguous runs of inline
8967 : // non-replaced content (including whitespace).
8968 1 : if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
8969 0 : AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
8970 : #ifdef DEBUG
8971 0 : if (gNoisyContentUpdates) {
8972 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8973 0 : "frame=");
8974 0 : nsFrame::ListTag(stdout, aFrame);
8975 : printf(" has an anonymous flex item as its next sibling\n");
8976 : }
8977 : #endif // DEBUG
8978 : // Recreate frames for the flex container (the removed frame's parent)
8979 0 : RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8980 0 : return true;
8981 : }
8982 :
8983 : // Might need to reconstruct things if the removed frame's nextSibling is
8984 : // null and its parent is an anonymous flex item. (This might be the last
8985 : // remaining child of that anonymous flex item, which can then go away.)
8986 1 : if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
8987 0 : AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
8988 : #ifdef DEBUG
8989 0 : if (gNoisyContentUpdates) {
8990 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8991 0 : "frame=");
8992 0 : nsFrame::ListTag(stdout, aFrame);
8993 : printf(" has an anonymous flex item as its parent\n");
8994 : }
8995 : #endif // DEBUG
8996 : // Recreate frames for the flex container (the removed frame's grandparent)
8997 0 : RecreateFramesForContent(parent->GetParent()->GetContent(),
8998 0 : InsertionKind::Async);
8999 0 : return true;
9000 : }
9001 :
9002 : #ifdef MOZ_XUL
9003 16 : if (aFrame->IsPopupSetFrame()) {
9004 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
9005 0 : if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
9006 0 : ReconstructDocElementHierarchy(InsertionKind::Async);
9007 0 : return true;
9008 : }
9009 : }
9010 : #endif
9011 :
9012 : // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
9013 : // a non-fluid continuation, i.e. it was split by bidi resolution
9014 38 : if (!inFlowFrame->GetPrevSibling() &&
9015 20 : !inFlowFrame->GetNextSibling() &&
9016 8 : ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
9017 4 : (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
9018 0 : RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
9019 0 : return true;
9020 : }
9021 :
9022 : // We might still need to reconstruct things if the parent of inFlowFrame is
9023 : // ib-split, since in that case the removal of aFrame might affect the
9024 : // splitting of its parent.
9025 0 : if (!IsFramePartOfIBSplit(parent)) {
9026 : return false;
9027 : }
9028 :
9029 : // If inFlowFrame is not the only in-flow child of |parent|, then removing
9030 : // it will change nothing about the {ib} split.
9031 0 : if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
9032 0 : inFlowFrame->LastContinuation()->GetNextSibling()) {
9033 : return false;
9034 : }
9035 :
9036 : // If the parent is the first or last part of the {ib} split, then
9037 : // removing one of its kids will have no effect on the splitting.
9038 : // Get the first continuation up front so we don't have to do it twice.
9039 0 : nsIFrame* parentFirstContinuation = parent->FirstContinuation();
9040 0 : if (!GetIBSplitSibling(parentFirstContinuation) ||
9041 0 : !GetIBSplitPrevSibling(parentFirstContinuation)) {
9042 : return false;
9043 : }
9044 :
9045 : #ifdef DEBUG
9046 0 : if (gNoisyContentUpdates) {
9047 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9048 0 : "frame=");
9049 0 : nsFrame::ListTag(stdout, parent);
9050 : printf(" is ib-split\n");
9051 : }
9052 : #endif
9053 :
9054 0 : ReframeContainingBlock(parent);
9055 0 : return true;
9056 : }
9057 :
9058 : void
9059 0 : nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent)
9060 : {
9061 0 : nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
9062 :
9063 : // It's possible that this warning could fire if some other style change
9064 : // simultaneously changes the 'display' of the element and makes it no
9065 : // longer be a table cell.
9066 0 : NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!");
9067 :
9068 0 : if (cellFrame) {
9069 0 : cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
9070 : }
9071 0 : }
9072 :
9073 : static nsIContent*
9074 0 : GetTopmostMathMLElement(nsIContent* aMathMLContent)
9075 : {
9076 0 : MOZ_ASSERT(aMathMLContent->IsMathMLElement());
9077 0 : MOZ_ASSERT(aMathMLContent->GetPrimaryFrame());
9078 0 : MOZ_ASSERT(aMathMLContent->GetPrimaryFrame()->IsFrameOfType(nsIFrame::eMathML));
9079 0 : nsIContent* root = aMathMLContent;
9080 :
9081 0 : for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent();
9082 0 : parent;
9083 : parent = parent->GetFlattenedTreeParent()) {
9084 0 : nsIFrame* frame = parent->GetPrimaryFrame();
9085 0 : if (!frame || !frame->IsFrameOfType(nsIFrame::eMathML)) {
9086 : break;
9087 : }
9088 0 : root = parent;
9089 : }
9090 :
9091 0 : return root;
9092 : }
9093 :
9094 : void
9095 7 : nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
9096 : InsertionKind aInsertionKind)
9097 : {
9098 7 : MOZ_ASSERT(aContent);
9099 :
9100 : // If there is no document, we don't want to recreate frames for it. (You
9101 : // shouldn't generally be giving this method content without a document
9102 : // anyway).
9103 : // Rebuilding the frame tree can have bad effects, especially if it's the
9104 : // frame tree for chrome (see bug 157322).
9105 7 : if (NS_WARN_IF(!aContent->GetComposedDoc())) {
9106 : return;
9107 : }
9108 :
9109 : // Is the frame ib-split? If so, we need to reframe the containing
9110 : // block *here*, rather than trying to remove and re-insert the
9111 : // content (which would otherwise result in *two* nested reframe
9112 : // containing block from ContentRemoved() and ContentInserted(),
9113 : // below!). We'd really like to optimize away one of those
9114 : // containing block reframes, hence the code here.
9115 :
9116 7 : nsIFrame* frame = aContent->GetPrimaryFrame();
9117 7 : if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
9118 : // Reframe the topmost MathML element to prevent exponential blowup
9119 : // (see bug 397518).
9120 0 : aContent = GetTopmostMathMLElement(aContent);
9121 0 : frame = aContent->GetPrimaryFrame();
9122 : }
9123 :
9124 7 : if (frame) {
9125 0 : nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
9126 7 : if (nonGeneratedAncestor->GetContent() != aContent) {
9127 0 : return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
9128 0 : InsertionKind::Async);
9129 : }
9130 :
9131 0 : if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
9132 : // Recreate the frames for the entire nsIAnonymousContentCreator tree
9133 : // since |frame| or one of its descendants may need an ComputedStyle
9134 : // that associates it to a CSS pseudo-element, and only the
9135 : // nsIAnonymousContentCreator that created this content knows how to make
9136 : // that happen.
9137 0 : nsIAnonymousContentCreator* acc = nullptr;
9138 0 : nsIFrame* ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
9139 0 : while (!(acc = do_QueryFrame(ancestor))) {
9140 0 : ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(ancestor);
9141 : }
9142 : NS_ASSERTION(acc, "Where is the nsIAnonymousContentCreator? We may fail "
9143 : "to recreate its content correctly");
9144 : // nsSVGUseFrame is special, and we know this is unnecessary for it.
9145 0 : if (!ancestor->IsSVGUseFrame()) {
9146 0 : NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
9147 : "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
9148 0 : return RecreateFramesForContent(ancestor->GetContent(),
9149 0 : InsertionKind::Async);
9150 : }
9151 : }
9152 :
9153 7 : nsIFrame* parent = frame->GetParent();
9154 0 : nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
9155 : // If the parent frame is a leaf then the subsequent insert will fail to
9156 : // create a frame, so we need to recreate the parent content. This happens
9157 : // with native anonymous content from the editor.
9158 0 : if (parent && parent->IsLeaf() && parentContent &&
9159 : parentContent != aContent) {
9160 0 : return RecreateFramesForContent(parentContent, InsertionKind::Async);
9161 : }
9162 : }
9163 :
9164 7 : if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
9165 : return;
9166 : }
9167 :
9168 7 : MOZ_ASSERT(aContent->GetParentNode());
9169 :
9170 : // Before removing the frames associated with the content object,
9171 : // ask them to save their state onto a temporary state object.
9172 0 : CaptureStateForFramesOf(aContent, mTempFrameTreeState);
9173 :
9174 : // Remove the frames associated with the content object.
9175 0 : nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ?
9176 11 : nullptr : aContent->GetNextSibling();
9177 : bool didReconstruct =
9178 7 : ContentRemoved(aContent, nextSibling, REMOVE_FOR_RECONSTRUCTION);
9179 :
9180 7 : if (!didReconstruct) {
9181 7 : if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
9182 : // FIXME(emilio, bug 1397239): There's nothing removing the frame state
9183 : // for elements that go away before we come back to the frame
9184 : // constructor.
9185 : //
9186 : // Also, it'd be nice to just use the `ContentRangeInserted` path for
9187 : // both elements and non-elements, but we need to make lazy frame
9188 : // construction to apply to all elements first.
9189 0 : RestyleManager()->PostRestyleEvent(aContent->AsElement(),
9190 : nsRestyleHint(0),
9191 0 : nsChangeHint_ReconstructFrame);
9192 : } else {
9193 : // Now, recreate the frames associated with this content object. If
9194 : // ContentRemoved triggered reconstruction, then we don't need to do this
9195 : // because the frames will already have been built.
9196 14 : ContentRangeInserted(aContent,
9197 : aContent->GetNextSibling(),
9198 : mTempFrameTreeState,
9199 0 : aInsertionKind);
9200 : }
9201 : }
9202 : }
9203 :
9204 : bool
9205 0 : nsCSSFrameConstructor::DestroyFramesFor(Element* aElement)
9206 : {
9207 0 : MOZ_ASSERT(aElement && aElement->GetParentNode());
9208 :
9209 : nsIContent* nextSibling =
9210 0 : aElement->IsRootOfAnonymousSubtree() ? nullptr : aElement->GetNextSibling();
9211 :
9212 0 : CaptureStateForFramesOf(aElement, mTempFrameTreeState);
9213 : return ContentRemoved(aElement,
9214 : nextSibling,
9215 0 : REMOVE_FOR_RECONSTRUCTION);
9216 : }
9217 :
9218 : //////////////////////////////////////////////////////////////////////
9219 :
9220 : // Block frame construction code
9221 :
9222 : already_AddRefed<ComputedStyle>
9223 0 : nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
9224 : ComputedStyle* aComputedStyle)
9225 : {
9226 0 : if (aContent) {
9227 0 : return mPresShell->StyleSet()->
9228 : ResolvePseudoElementStyle(aContent->AsElement(),
9229 : CSSPseudoElementType::firstLetter,
9230 : aComputedStyle,
9231 0 : nullptr);
9232 : }
9233 : return nullptr;
9234 : }
9235 :
9236 : already_AddRefed<ComputedStyle>
9237 0 : nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
9238 : ComputedStyle* aComputedStyle)
9239 : {
9240 0 : if (aContent) {
9241 0 : return mPresShell->StyleSet()->
9242 : ResolvePseudoElementStyle(aContent->AsElement(),
9243 : CSSPseudoElementType::firstLine,
9244 : aComputedStyle,
9245 0 : nullptr);
9246 : }
9247 : return nullptr;
9248 : }
9249 :
9250 : // Predicate to see if a given content (block element) has
9251 : // first-letter style applied to it.
9252 : bool
9253 15 : nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
9254 : ComputedStyle* aComputedStyle)
9255 : {
9256 0 : return nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
9257 : CSSPseudoElementType::firstLetter,
9258 0 : mPresShell->GetPresContext());
9259 : }
9260 :
9261 : bool
9262 0 : nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame)
9263 : {
9264 8 : MOZ_ASSERT(aBlockFrame, "Need a frame");
9265 8 : NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
9266 : "Not a block frame?");
9267 :
9268 16 : return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0;
9269 : }
9270 :
9271 : bool
9272 0 : nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
9273 : ComputedStyle* aComputedStyle)
9274 : {
9275 : bool hasFirstLine =
9276 22 : nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
9277 : CSSPseudoElementType::firstLine,
9278 44 : mPresShell->GetPresContext());
9279 22 : return hasFirstLine && !aContent->IsHTMLElement(nsGkAtoms::fieldset);
9280 : }
9281 :
9282 : void
9283 0 : nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent* aContent,
9284 : ComputedStyle* aComputedStyle,
9285 : bool* aHaveFirstLetterStyle,
9286 : bool* aHaveFirstLineStyle)
9287 : {
9288 15 : *aHaveFirstLetterStyle =
9289 15 : ShouldHaveFirstLetterStyle(aContent, aComputedStyle);
9290 15 : *aHaveFirstLineStyle =
9291 15 : ShouldHaveFirstLineStyle(aContent, aComputedStyle);
9292 15 : }
9293 :
9294 : /* static */
9295 : const nsCSSFrameConstructor::PseudoParentData
9296 : nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
9297 : { // Cell
9298 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9299 : FCDATA_USE_CHILD_ITEMS |
9300 : FCDATA_IS_WRAPPER_ANON_BOX |
9301 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
9302 : &nsCSSFrameConstructor::ConstructTableCell),
9303 : &nsCSSAnonBoxes::tableCell
9304 : },
9305 : { // Row
9306 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9307 : FCDATA_USE_CHILD_ITEMS |
9308 : FCDATA_IS_WRAPPER_ANON_BOX |
9309 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
9310 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
9311 : &nsCSSAnonBoxes::tableRow
9312 : },
9313 : { // Row group
9314 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9315 : FCDATA_USE_CHILD_ITEMS |
9316 : FCDATA_IS_WRAPPER_ANON_BOX |
9317 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9318 : &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
9319 : &nsCSSAnonBoxes::tableRowGroup
9320 : },
9321 : { // Column group
9322 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9323 : FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
9324 : FCDATA_SKIP_ABSPOS_PUSH |
9325 : // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
9326 : // restyle these: they have non-inheriting styles.
9327 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9328 : NS_NewTableColGroupFrame),
9329 : &nsCSSAnonBoxes::tableColGroup
9330 : },
9331 : { // Table
9332 : FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
9333 : FCDATA_IS_WRAPPER_ANON_BOX,
9334 : &nsCSSFrameConstructor::ConstructTable),
9335 : &nsCSSAnonBoxes::table
9336 : },
9337 : { // Ruby
9338 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
9339 : FCDATA_USE_CHILD_ITEMS |
9340 : FCDATA_IS_WRAPPER_ANON_BOX |
9341 : FCDATA_SKIP_FRAMESET,
9342 : NS_NewRubyFrame),
9343 : &nsCSSAnonBoxes::ruby
9344 : },
9345 : { // Ruby Base
9346 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9347 : FCDATA_IS_LINE_PARTICIPANT |
9348 : FCDATA_IS_WRAPPER_ANON_BOX |
9349 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
9350 : FCDATA_SKIP_FRAMESET,
9351 : NS_NewRubyBaseFrame),
9352 : &nsCSSAnonBoxes::rubyBase
9353 : },
9354 : { // Ruby Base Container
9355 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9356 : FCDATA_IS_LINE_PARTICIPANT |
9357 : FCDATA_IS_WRAPPER_ANON_BOX |
9358 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
9359 : FCDATA_SKIP_FRAMESET,
9360 : NS_NewRubyBaseContainerFrame),
9361 : &nsCSSAnonBoxes::rubyBaseContainer
9362 : },
9363 : { // Ruby Text
9364 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9365 : FCDATA_IS_LINE_PARTICIPANT |
9366 : FCDATA_IS_WRAPPER_ANON_BOX |
9367 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
9368 : FCDATA_SKIP_FRAMESET,
9369 : NS_NewRubyTextFrame),
9370 : &nsCSSAnonBoxes::rubyText
9371 : },
9372 : { // Ruby Text Container
9373 : FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9374 : FCDATA_IS_WRAPPER_ANON_BOX |
9375 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
9376 : FCDATA_SKIP_FRAMESET,
9377 : NS_NewRubyTextContainerFrame),
9378 : &nsCSSAnonBoxes::rubyTextContainer
9379 : }
9380 : };
9381 :
9382 : void
9383 0 : nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
9384 : nsFrameConstructorState& aState,
9385 : FrameConstructionItemList& aItems,
9386 : nsIFrame* aParentFrame)
9387 : {
9388 0 : if (aItems.IsEmpty() || !::IsFlexOrGridContainer(aParentFrame)) {
9389 273 : return;
9390 : }
9391 :
9392 0 : const bool isLegacyBox = IsFlexContainerForLegacyBox(aParentFrame);
9393 0 : FCItemIterator iter(aItems);
9394 0 : do {
9395 : // Advance iter past children that don't want to be wrapped
9396 0 : if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
9397 : // Hit the end of the items without finding any remaining children that
9398 : // need to be wrapped. We're finished!
9399 0 : return;
9400 : }
9401 :
9402 : // If our next potentially-wrappable child is whitespace, then see if
9403 : // there's anything wrappable immediately after it. If not, we just drop
9404 : // the whitespace and move on. (We're not supposed to create any anonymous
9405 : // flex/grid items that _only_ contain whitespace).
9406 : // (BUT if this is generated content, then we don't give whitespace nodes
9407 : // any special treatment, because they're probably not really whitespace --
9408 : // they're just temporarily empty, waiting for their generated text.)
9409 : // XXXdholbert If this node's generated text will *actually end up being
9410 : // entirely whitespace*, then we technically should still skip over it, per
9411 : // the CSS grid & flexbox specs. I'm not bothering with that at this point,
9412 : // since it's a pretty extreme edge case.
9413 0 : if (!aParentFrame->IsGeneratedContentFrame() &&
9414 0 : iter.item().IsWhitespace(aState)) {
9415 0 : FCItemIterator afterWhitespaceIter(iter);
9416 0 : bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
9417 : bool nextChildNeedsAnonItem =
9418 0 : !hitEnd &&
9419 0 : afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox);
9420 :
9421 0 : if (!nextChildNeedsAnonItem) {
9422 : // There's nothing after the whitespace that we need to wrap, so we
9423 : // just drop this run of whitespace.
9424 0 : iter.DeleteItemsTo(this, afterWhitespaceIter);
9425 0 : if (hitEnd) {
9426 : // Nothing left to do -- we're finished!
9427 0 : return;
9428 : }
9429 : // else, we have a next child and it does not want to be wrapped. So,
9430 : // we jump back to the beginning of the loop to skip over that child
9431 : // (and anything else non-wrappable after it)
9432 0 : MOZ_ASSERT(!iter.IsDone() &&
9433 : !iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox),
9434 : "hitEnd and/or nextChildNeedsAnonItem lied");
9435 0 : continue;
9436 : }
9437 : }
9438 :
9439 : // Now |iter| points to the first child that needs to be wrapped in an
9440 : // anonymous flex/grid item. Now we see how many children after it also want
9441 : // to be wrapped in an anonymous flex/grid item.
9442 0 : FCItemIterator endIter(iter); // iterator to find the end of the group
9443 0 : endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox);
9444 :
9445 0 : NS_ASSERTION(iter != endIter,
9446 : "Should've had at least one wrappable child to seek past");
9447 :
9448 : // Now, we create the anonymous flex or grid item to contain the children
9449 : // between |iter| and |endIter|.
9450 0 : nsAtom* pseudoType = (aParentFrame->IsFlexContainerFrame())
9451 : ? nsCSSAnonBoxes::anonymousFlexItem
9452 0 : : nsCSSAnonBoxes::anonymousGridItem;
9453 0 : ComputedStyle* parentStyle = aParentFrame->Style();
9454 0 : nsIContent* parentContent = aParentFrame->GetContent();
9455 : already_AddRefed<ComputedStyle> wrapperStyle =
9456 0 : mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
9457 0 : parentStyle);
9458 :
9459 : static const FrameConstructionData sBlockFormattingContextFCData =
9460 : FCDATA_DECL(FCDATA_SKIP_FRAMESET |
9461 : FCDATA_USE_CHILD_ITEMS |
9462 : FCDATA_IS_WRAPPER_ANON_BOX,
9463 : NS_NewBlockFormattingContext);
9464 :
9465 : FrameConstructionItem* newItem =
9466 : new (this) FrameConstructionItem(&sBlockFormattingContextFCData,
9467 : // Use the content of our parent frame
9468 : parentContent,
9469 : // no pending binding
9470 : nullptr,
9471 : wrapperStyle,
9472 0 : true, nullptr);
9473 :
9474 0 : newItem->mIsAllInline = newItem->mHasInlineEnds =
9475 0 : newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
9476 0 : newItem->mIsBlock = !newItem->mIsAllInline;
9477 :
9478 0 : MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,
9479 : "expecting anonymous flex/grid items to be block-level "
9480 : "(this will make a difference when we encounter "
9481 : "'align-items: baseline')");
9482 :
9483 : // Anonymous flex and grid items induce line boundaries around their
9484 : // contents.
9485 0 : newItem->mChildItems.SetLineBoundaryAtStart(true);
9486 0 : newItem->mChildItems.SetLineBoundaryAtEnd(true);
9487 : // The parent of the items in aItems is also the parent of the items
9488 : // in mChildItems
9489 0 : newItem->mChildItems.SetParentHasNoXBLChildren(
9490 0 : aItems.ParentHasNoXBLChildren());
9491 :
9492 : // Eat up all items between |iter| and |endIter| and put them in our
9493 : // wrapper. This advances |iter| to point to |endIter|.
9494 0 : iter.AppendItemsToList(this, endIter, newItem->mChildItems);
9495 :
9496 0 : iter.InsertItem(newItem);
9497 0 : } while (!iter.IsDone());
9498 : }
9499 :
9500 : /* static */ nsCSSFrameConstructor::RubyWhitespaceType
9501 0 : nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
9502 : StyleDisplay aNextDisplay)
9503 : {
9504 0 : MOZ_ASSERT(nsStyleDisplay::IsRubyDisplayType(aPrevDisplay) &&
9505 : nsStyleDisplay::IsRubyDisplayType(aNextDisplay));
9506 0 : if (aPrevDisplay == aNextDisplay &&
9507 0 : (aPrevDisplay == StyleDisplay::RubyBase ||
9508 0 : aPrevDisplay == StyleDisplay::RubyText)) {
9509 : return eRubyInterLeafWhitespace;
9510 : }
9511 0 : if (aNextDisplay == StyleDisplay::RubyText ||
9512 : aNextDisplay == StyleDisplay::RubyTextContainer) {
9513 : return eRubyInterLevelWhitespace;
9514 : }
9515 0 : return eRubyInterSegmentWhitespace;
9516 : }
9517 :
9518 : /**
9519 : * This function checks the content from |aStartIter| to |aEndIter|,
9520 : * determines whether it contains only whitespace, and if yes,
9521 : * interprets the type of whitespace. This method does not change
9522 : * any of the iters.
9523 : */
9524 : /* static */ nsCSSFrameConstructor::RubyWhitespaceType
9525 0 : nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
9526 : const FCItemIterator& aStartIter,
9527 : const FCItemIterator& aEndIter)
9528 : {
9529 0 : if (!aStartIter.item().IsWhitespace(aState)) {
9530 : return eRubyNotWhitespace;
9531 : }
9532 :
9533 0 : FCItemIterator spaceEndIter(aStartIter);
9534 0 : spaceEndIter.SkipWhitespace(aState);
9535 0 : if (spaceEndIter != aEndIter) {
9536 : return eRubyNotWhitespace;
9537 : }
9538 :
9539 : // Any leading or trailing whitespace in non-pseudo ruby box
9540 : // should have been trimmed, hence there should not be any
9541 : // whitespace at the start or the end.
9542 0 : MOZ_ASSERT(!aStartIter.AtStart() && !aEndIter.IsDone());
9543 0 : FCItemIterator prevIter(aStartIter);
9544 0 : prevIter.Prev();
9545 : return ComputeRubyWhitespaceType(
9546 0 : prevIter.item().mComputedStyle->StyleDisplay()->mDisplay,
9547 0 : aEndIter.item().mComputedStyle->StyleDisplay()->mDisplay);
9548 : }
9549 :
9550 :
9551 : /**
9552 : * This function eats up consecutive items which do not want the current
9553 : * parent into either a ruby base box or a ruby text box. When it
9554 : * returns, |aIter| points to the first item it doesn't wrap.
9555 : */
9556 : void
9557 0 : nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
9558 : FCItemIterator& aIter,
9559 : ComputedStyle* aParentStyle, nsIContent* aParentContent)
9560 : {
9561 0 : StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
9562 : ParentType parentType, wrapperType;
9563 0 : if (parentDisplay == StyleDisplay::RubyTextContainer) {
9564 : parentType = eTypeRubyTextContainer;
9565 : wrapperType = eTypeRubyText;
9566 : } else {
9567 0 : MOZ_ASSERT(parentDisplay == StyleDisplay::RubyBaseContainer);
9568 : parentType = eTypeRubyBaseContainer;
9569 : wrapperType = eTypeRubyBase;
9570 : }
9571 :
9572 0 : MOZ_ASSERT(aIter.item().DesiredParentType() != parentType,
9573 : "Should point to something needs to be wrapped.");
9574 :
9575 0 : FCItemIterator endIter(aIter);
9576 0 : endIter.SkipItemsNotWantingParentType(parentType);
9577 :
9578 : WrapItemsInPseudoParent(aParentContent, aParentStyle,
9579 0 : wrapperType, aIter, endIter);
9580 0 : }
9581 :
9582 : /**
9583 : * This function eats up consecutive items into a ruby level container.
9584 : * It may create zero or one level container. When it returns, |aIter|
9585 : * points to the first item it doesn't wrap.
9586 : */
9587 : void
9588 0 : nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
9589 : nsFrameConstructorState& aState, FCItemIterator& aIter,
9590 : ComputedStyle* aParentStyle, nsIContent* aParentContent)
9591 : {
9592 0 : MOZ_ASSERT(aIter.item().DesiredParentType() != eTypeRuby,
9593 : "Pointing to a level container?");
9594 :
9595 0 : FrameConstructionItem& firstItem = aIter.item();
9596 0 : ParentType wrapperType = firstItem.DesiredParentType();
9597 0 : if (wrapperType != eTypeRubyTextContainer) {
9598 : // If the first item is not ruby text,
9599 : // it should be in a base container.
9600 0 : wrapperType = eTypeRubyBaseContainer;
9601 : }
9602 :
9603 : FCItemIterator endIter(aIter);
9604 0 : do {
9605 0 : if (endIter.SkipItemsWantingParentType(wrapperType) ||
9606 : // If the skipping above stops at some item which wants a
9607 : // different ruby parent, then we have finished.
9608 0 : IsRubyParentType(endIter.item().DesiredParentType())) {
9609 : // No more items need to be wrapped in this level container.
9610 : break;
9611 : }
9612 :
9613 0 : FCItemIterator contentEndIter(endIter);
9614 0 : contentEndIter.SkipItemsNotWantingRubyParent();
9615 : // endIter must be on something doesn't want a ruby parent.
9616 0 : MOZ_ASSERT(contentEndIter != endIter);
9617 :
9618 : // InterpretRubyWhitespace depends on the fact that any leading or
9619 : // trailing whitespace described in the spec have been trimmed at
9620 : // this point. With this precondition, it is safe not to check
9621 : // whether contentEndIter has been done.
9622 : RubyWhitespaceType whitespaceType =
9623 0 : InterpretRubyWhitespace(aState, endIter, contentEndIter);
9624 0 : if (whitespaceType == eRubyInterLevelWhitespace) {
9625 : // Remove inter-level whitespace.
9626 0 : bool atStart = (aIter == endIter);
9627 0 : endIter.DeleteItemsTo(this, contentEndIter);
9628 0 : if (atStart) {
9629 0 : aIter = endIter;
9630 : }
9631 0 : } else if (whitespaceType == eRubyInterSegmentWhitespace) {
9632 : // If this level container starts with inter-segment whitespaces,
9633 : // wrap them. Break at contentEndIter. Otherwise, leave it here.
9634 : // Break at endIter. They will be wrapped when we are here again.
9635 0 : if (aIter == endIter) {
9636 0 : MOZ_ASSERT(wrapperType == eTypeRubyBaseContainer,
9637 : "Inter-segment whitespace should be wrapped in rbc");
9638 0 : endIter = contentEndIter;
9639 : }
9640 : break;
9641 0 : } else if (wrapperType == eTypeRubyTextContainer &&
9642 0 : whitespaceType != eRubyInterLeafWhitespace) {
9643 : // Misparented inline content that's not inter-annotation
9644 : // whitespace doesn't belong in a pseudo ruby text container.
9645 : // Break at endIter.
9646 : break;
9647 : } else {
9648 0 : endIter = contentEndIter;
9649 : }
9650 0 : } while (!endIter.IsDone());
9651 :
9652 : // It is possible that everything our parent wants us to wrap is
9653 : // simply an inter-level whitespace, which has been trimmed, or
9654 : // an inter-segment whitespace, which will be wrapped later.
9655 : // In those cases, don't create anything.
9656 0 : if (aIter != endIter) {
9657 : WrapItemsInPseudoParent(aParentContent, aParentStyle,
9658 0 : wrapperType, aIter, endIter);
9659 : }
9660 0 : }
9661 :
9662 : /**
9663 : * This function trims leading and trailing whitespaces
9664 : * in the given item list.
9665 : */
9666 : void
9667 0 : nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
9668 : nsFrameConstructorState& aState,
9669 : FrameConstructionItemList& aItems)
9670 : {
9671 0 : FCItemIterator iter(aItems);
9672 0 : if (!iter.IsDone() &&
9673 0 : iter.item().IsWhitespace(aState)) {
9674 0 : FCItemIterator spaceEndIter(iter);
9675 0 : spaceEndIter.SkipWhitespace(aState);
9676 0 : iter.DeleteItemsTo(this, spaceEndIter);
9677 : }
9678 :
9679 0 : iter.SetToEnd();
9680 0 : if (!iter.AtStart()) {
9681 : FCItemIterator spaceEndIter(iter);
9682 0 : do {
9683 0 : iter.Prev();
9684 0 : if (iter.AtStart()) {
9685 : // It's fine to not check the first item, because we
9686 : // should have trimmed leading whitespaces above.
9687 : break;
9688 : }
9689 0 : } while (iter.item().IsWhitespace(aState));
9690 0 : iter.Next();
9691 0 : if (iter != spaceEndIter) {
9692 0 : iter.DeleteItemsTo(this, spaceEndIter);
9693 : }
9694 : }
9695 0 : }
9696 :
9697 : /**
9698 : * This function walks through the child list (aItems) and creates
9699 : * needed pseudo ruby boxes to wrap misparented children.
9700 : */
9701 : void
9702 0 : nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
9703 : nsFrameConstructorState& aState,
9704 : FrameConstructionItemList& aItems,
9705 : nsIFrame* aParentFrame)
9706 : {
9707 0 : const ParentType ourParentType = GetParentType(aParentFrame);
9708 273 : if (!IsRubyParentType(ourParentType) ||
9709 0 : aItems.AllWantParentType(ourParentType)) {
9710 273 : return;
9711 : }
9712 :
9713 0 : if (!IsRubyPseudo(aParentFrame)) {
9714 : // Normally, ruby pseudo frames start from and end at some elements,
9715 : // which means they don't have leading and trailing whitespaces at
9716 : // all. But there are two cases where they do actually have leading
9717 : // or trailing whitespaces:
9718 : // 1. It is an inter-segment whitespace which in an individual ruby
9719 : // base container.
9720 : // 2. The pseudo frame starts from or ends at consecutive inline
9721 : // content, which is not pure whitespace, but includes some.
9722 : // In either case, the whitespaces are not the leading or trailing
9723 : // whitespaces defined in the spec, and thus should not be trimmed.
9724 0 : TrimLeadingAndTrailingWhitespaces(aState, aItems);
9725 : }
9726 :
9727 0 : FCItemIterator iter(aItems);
9728 0 : nsIContent* parentContent = aParentFrame->GetContent();
9729 0 : ComputedStyle* parentStyle = aParentFrame->Style();
9730 0 : while (!iter.IsDone()) {
9731 0 : if (!iter.SkipItemsWantingParentType(ourParentType)) {
9732 0 : if (ourParentType == eTypeRuby) {
9733 : WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
9734 0 : parentContent);
9735 : } else {
9736 0 : WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
9737 : }
9738 : }
9739 : }
9740 : }
9741 :
9742 : /*
9743 : * This function works as follows: we walk through the child list (aItems) and
9744 : * find items that cannot have aParentFrame as their parent. We wrap
9745 : * continuous runs of such items into a FrameConstructionItem for a frame that
9746 : * gets them closer to their desired parents. For example, a run of non-row
9747 : * children of a row-group will get wrapped in a row. When we later construct
9748 : * the frame for this wrapper (in this case for the row), it'll be the correct
9749 : * parent for the cells in the set of items we wrapped or we'll wrap cells
9750 : * around everything else. At the end of this method, aItems is guaranteed to
9751 : * contain only items for frames that can be direct kids of aParentFrame.
9752 : */
9753 : void
9754 0 : nsCSSFrameConstructor::CreateNeededPseudoContainers(
9755 : nsFrameConstructorState& aState,
9756 : FrameConstructionItemList& aItems,
9757 : nsIFrame* aParentFrame)
9758 : {
9759 273 : ParentType ourParentType = GetParentType(aParentFrame);
9760 0 : if (IsRubyParentType(ourParentType) ||
9761 0 : aItems.AllWantParentType(ourParentType)) {
9762 : // Nothing to do here
9763 273 : return;
9764 : }
9765 :
9766 0 : FCItemIterator iter(aItems);
9767 0 : do {
9768 0 : if (iter.SkipItemsWantingParentType(ourParentType)) {
9769 : // Nothing else to do here; we're finished
9770 0 : return;
9771 : }
9772 :
9773 : // Now we're pointing to the first child that wants a different parent
9774 : // type.
9775 :
9776 : // Now try to figure out what kids we can group together. We can generally
9777 : // group everything that has a different desired parent type from us. Two
9778 : // exceptions to this:
9779 : // 1) If our parent type is table, we can't group columns with anything
9780 : // else other than whitespace.
9781 : // 2) Whitespace that lies between two things we can group which both want
9782 : // a non-block parent should be dropped, even if we can't group them
9783 : // with each other and even if the whitespace wants a parent of
9784 : // ourParentType. Ends of the list count as things that don't want a
9785 : // block parent (so that for example we'll drop a whitespace-only list).
9786 :
9787 0 : FCItemIterator endIter(iter); /* iterator to find the end of the group */
9788 0 : ParentType groupingParentType = endIter.item().DesiredParentType();
9789 0 : if (aItems.AllWantParentType(groupingParentType) &&
9790 : groupingParentType != eTypeBlock) {
9791 : // Just group them all and be done with it. We need the check for
9792 : // eTypeBlock here to catch the "all the items are whitespace" case
9793 : // described above.
9794 0 : endIter.SetToEnd();
9795 : } else {
9796 : // Locate the end of the group.
9797 :
9798 : // Keep track of the type the previous item wanted, in case we have to
9799 : // deal with whitespace. Start it off with ourParentType, since that's
9800 : // the last thing |iter| would have skipped over.
9801 : ParentType prevParentType = ourParentType;
9802 0 : do {
9803 : // Walk an iterator past any whitespace that we might be able to drop
9804 : // from the list
9805 0 : FCItemIterator spaceEndIter(endIter);
9806 0 : if (prevParentType != eTypeBlock &&
9807 0 : !aParentFrame->IsGeneratedContentFrame() &&
9808 0 : spaceEndIter.item().IsWhitespace(aState)) {
9809 0 : bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
9810 :
9811 : // We drop the whitespace in the following cases:
9812 : // 1) If these are not trailing spaces and the next item wants a table
9813 : // or table-part parent
9814 : // 2) If these are trailing spaces and aParentFrame is a
9815 : // tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
9816 : // (Being a tabular container pretty much means ourParentType is
9817 : // not eTypeBlock besides the eTypeColGroup case, which won't
9818 : // reach here.)
9819 0 : if ((!trailingSpaces &&
9820 0 : IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
9821 0 : (trailingSpaces && ourParentType != eTypeBlock)) {
9822 0 : bool updateStart = (iter == endIter);
9823 0 : endIter.DeleteItemsTo(this, spaceEndIter);
9824 0 : NS_ASSERTION(trailingSpaces == endIter.IsDone(),
9825 : "These should match");
9826 :
9827 0 : if (updateStart) {
9828 0 : iter = endIter;
9829 : }
9830 :
9831 0 : if (trailingSpaces) {
9832 : break; /* Found group end */
9833 : }
9834 :
9835 0 : if (updateStart) {
9836 : // Update groupingParentType, since it might have been eTypeBlock
9837 : // just because of the whitespace.
9838 0 : groupingParentType = iter.item().DesiredParentType();
9839 : }
9840 : }
9841 : }
9842 :
9843 : // Now endIter points to a non-whitespace item or a non-droppable
9844 : // whitespace item. In the latter case, if this is the end of the group
9845 : // we'll traverse this whitespace again. But it'll all just be quick
9846 : // DesiredParentType() checks which will match ourParentType (that's
9847 : // what it means that this is the group end), so it's OK.
9848 : // However, when we are grouping a ruby parent, and endIter points to
9849 : // a non-droppable whitespace, if the next non-whitespace item also
9850 : // wants a ruby parent, the whitespace should also be included into
9851 : // the current ruby container.
9852 0 : prevParentType = endIter.item().DesiredParentType();
9853 0 : if (prevParentType == ourParentType &&
9854 0 : (endIter == spaceEndIter ||
9855 0 : spaceEndIter.IsDone() ||
9856 0 : !IsRubyParentType(groupingParentType) ||
9857 0 : !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
9858 : // End the group at endIter.
9859 : break;
9860 : }
9861 :
9862 0 : if (ourParentType == eTypeTable &&
9863 0 : (prevParentType == eTypeColGroup) !=
9864 : (groupingParentType == eTypeColGroup)) {
9865 : // Either we started with columns and now found something else, or vice
9866 : // versa. In any case, end the grouping.
9867 : break;
9868 : }
9869 :
9870 : // If we have some whitespace that we were not able to drop and there is
9871 : // an item after the whitespace that is already properly parented, then
9872 : // make sure to include the spaces in our group but stop the group after
9873 : // that.
9874 0 : if (spaceEndIter != endIter &&
9875 0 : !spaceEndIter.IsDone() &&
9876 0 : ourParentType == spaceEndIter.item().DesiredParentType()) {
9877 0 : endIter = spaceEndIter;
9878 0 : break;
9879 : }
9880 :
9881 : // Include the whitespace we didn't drop (if any) in the group.
9882 0 : endIter = spaceEndIter;
9883 0 : prevParentType = endIter.item().DesiredParentType();
9884 :
9885 0 : endIter.Next();
9886 0 : } while (!endIter.IsDone());
9887 : }
9888 :
9889 0 : if (iter == endIter) {
9890 : // Nothing to wrap here; just skipped some whitespace
9891 0 : continue;
9892 : }
9893 :
9894 : // Now group together all the items between iter and endIter. The right
9895 : // parent type to use depends on ourParentType.
9896 : ParentType wrapperType;
9897 0 : switch (ourParentType) {
9898 : case eTypeRow:
9899 : // The parent type for a cell is eTypeBlock, since that's what a cell
9900 : // looks like to its kids.
9901 : wrapperType = eTypeBlock;
9902 : break;
9903 : case eTypeRowGroup:
9904 0 : wrapperType = eTypeRow;
9905 0 : break;
9906 : case eTypeTable:
9907 : // Either colgroup or rowgroup, depending on what we're grouping.
9908 0 : wrapperType = groupingParentType == eTypeColGroup ?
9909 : eTypeColGroup : eTypeRowGroup;
9910 : break;
9911 : case eTypeColGroup:
9912 0 : MOZ_CRASH("Colgroups should be suppresing non-col child items");
9913 : default:
9914 0 : NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type");
9915 0 : if (IsRubyParentType(groupingParentType)) {
9916 : wrapperType = eTypeRuby;
9917 : } else {
9918 0 : NS_ASSERTION(IsTableParentType(groupingParentType),
9919 : "groupingParentType should be either Ruby or table");
9920 : wrapperType = eTypeTable;
9921 : }
9922 : }
9923 :
9924 0 : ComputedStyle* parentStyle = aParentFrame->Style();
9925 0 : WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
9926 0 : wrapperType, iter, endIter);
9927 :
9928 : // Now |iter| points to the item that was the first one we didn't wrap;
9929 : // loop and see whether we need to skip it or wrap it in something
9930 : // different.
9931 0 : } while (!iter.IsDone());
9932 : }
9933 :
9934 : /**
9935 : * This method wraps frame construction item from |aIter| to
9936 : * |aEndIter|. After it returns, aIter points to the first item
9937 : * after the wrapper.
9938 : */
9939 : void
9940 0 : nsCSSFrameConstructor::WrapItemsInPseudoParent(nsIContent* aParentContent,
9941 : ComputedStyle* aParentStyle,
9942 : ParentType aWrapperType,
9943 : FCItemIterator& aIter,
9944 : const FCItemIterator& aEndIter)
9945 : {
9946 0 : const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
9947 0 : nsAtom* pseudoType = *pseudoData.mPseudoType;
9948 0 : StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
9949 :
9950 0 : if (pseudoType == nsCSSAnonBoxes::table &&
9951 0 : (parentDisplay == StyleDisplay::Inline ||
9952 0 : parentDisplay == StyleDisplay::RubyBase ||
9953 : parentDisplay == StyleDisplay::RubyText)) {
9954 0 : pseudoType = nsCSSAnonBoxes::inlineTable;
9955 : }
9956 :
9957 0 : already_AddRefed<ComputedStyle> wrapperStyle;
9958 0 : if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX) {
9959 : wrapperStyle =
9960 0 : mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
9961 0 : aParentStyle);
9962 : } else {
9963 : wrapperStyle =
9964 0 : mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(pseudoType);
9965 : }
9966 :
9967 : FrameConstructionItem* newItem =
9968 : new (this) FrameConstructionItem(&pseudoData.mFCData,
9969 : // Use the content of our parent frame
9970 : aParentContent,
9971 : // no pending binding
9972 : nullptr,
9973 : wrapperStyle,
9974 0 : true, nullptr);
9975 :
9976 0 : const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
9977 : // Here we're cheating a tad... technically, table-internal items should be
9978 : // inline if aParentFrame is inline, but they'll get wrapped in an
9979 : // inline-table in the end, so it'll all work out. In any case, arguably
9980 : // we don't need to maintain this state at this point... but it's better
9981 : // to, I guess.
9982 0 : newItem->mIsAllInline = newItem->mHasInlineEnds =
9983 : disp->IsInlineOutsideStyle();
9984 :
9985 0 : bool isRuby = disp->IsRubyDisplayType();
9986 : // All types of ruby frames need a block frame to provide line layout,
9987 : // hence they are always line participant.
9988 0 : newItem->mIsLineParticipant = isRuby;
9989 :
9990 0 : if (!isRuby) {
9991 : // Table pseudo frames always induce line boundaries around their
9992 : // contents.
9993 0 : newItem->mChildItems.SetLineBoundaryAtStart(true);
9994 0 : newItem->mChildItems.SetLineBoundaryAtEnd(true);
9995 : }
9996 : // The parent of the items in aItems is also the parent of the items
9997 : // in mChildItems
9998 0 : newItem->mChildItems.SetParentHasNoXBLChildren(
9999 0 : aIter.List()->ParentHasNoXBLChildren());
10000 :
10001 : // Eat up all items between |aIter| and |aEndIter| and put them in our
10002 : // wrapper Advances |aIter| to point to |aEndIter|.
10003 0 : aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
10004 :
10005 0 : aIter.InsertItem(newItem);
10006 0 : }
10007 :
10008 : void
10009 0 : nsCSSFrameConstructor::CreateNeededPseudoSiblings(
10010 : nsFrameConstructorState& aState,
10011 : FrameConstructionItemList& aItems,
10012 : nsIFrame* aParentFrame)
10013 : {
10014 0 : if (aItems.IsEmpty() ||
10015 0 : GetParentType(aParentFrame) != eTypeRuby) {
10016 273 : return;
10017 : }
10018 :
10019 0 : FCItemIterator iter(aItems);
10020 0 : StyleDisplay firstDisplay = iter.item().mComputedStyle->StyleDisplay()->mDisplay;
10021 0 : if (firstDisplay == StyleDisplay::RubyBaseContainer) {
10022 : return;
10023 : }
10024 0 : NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,
10025 : "Child of ruby frame should either a rbc or a rtc");
10026 :
10027 : const PseudoParentData& pseudoData =
10028 0 : sPseudoParentData[eTypeRubyBaseContainer];
10029 0 : already_AddRefed<ComputedStyle> pseudoStyle = mPresShell->StyleSet()->
10030 : ResolveInheritingAnonymousBoxStyle(*pseudoData.mPseudoType,
10031 0 : aParentFrame->Style());
10032 : FrameConstructionItem* newItem =
10033 : new (this) FrameConstructionItem(&pseudoData.mFCData,
10034 : // Use the content of the parent frame
10035 0 : aParentFrame->GetContent(),
10036 : // no pending binding
10037 : nullptr,
10038 : pseudoStyle,
10039 0 : true, nullptr);
10040 0 : newItem->mIsAllInline = true;
10041 0 : newItem->mChildItems.SetParentHasNoXBLChildren(true);
10042 0 : iter.InsertItem(newItem);
10043 : }
10044 :
10045 : #ifdef DEBUG
10046 : /**
10047 : * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
10048 : * rather than being a direct child of aContainerFrame.
10049 : *
10050 : * NOTE: aContainerFrame must be a flex or grid container - this function is
10051 : * purely for sanity-checking the children of these container types.
10052 : * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
10053 : * logic (which operates a bit earlier, on FCData instead of frames).
10054 : */
10055 : static bool
10056 0 : FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
10057 : const nsIFrame* aFrame)
10058 : {
10059 0 : MOZ_ASSERT(::IsFlexOrGridContainer(aContainerFrame));
10060 :
10061 : // Any line-participant frames (e.g. text) definitely want to be wrapped in
10062 : // an anonymous flex/grid item.
10063 0 : if (aFrame->IsFrameOfType(nsIFrame::eLineParticipant)) {
10064 : return true;
10065 : }
10066 :
10067 : // If the container is a -webkit-{inline-}box or -moz-{inline-}box container,
10068 : // then placeholders also need to be wrapped, for compatibility.
10069 0 : if (IsFlexContainerForLegacyBox(aContainerFrame) &&
10070 0 : aFrame->IsPlaceholderFrame()) {
10071 : return true;
10072 : }
10073 :
10074 0 : return false;
10075 : }
10076 : #endif
10077 :
10078 : static void
10079 273 : VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
10080 : const nsFrameList& aChildren)
10081 : {
10082 : #ifdef DEBUG
10083 0 : if (!::IsFlexOrGridContainer(aParentFrame)) {
10084 : return;
10085 : }
10086 :
10087 0 : bool prevChildWasAnonItem = false;
10088 0 : for (const nsIFrame* child : aChildren) {
10089 0 : MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(aParentFrame, child),
10090 : "frame wants to be inside an anonymous item, but it isn't");
10091 0 : if (IsAnonymousFlexOrGridItem(child)) {
10092 0 : AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
10093 0 : MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row");
10094 0 : nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
10095 0 : MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty");
10096 : prevChildWasAnonItem = true;
10097 : } else {
10098 : prevChildWasAnonItem = false;
10099 : }
10100 : }
10101 : #endif
10102 : }
10103 :
10104 : inline void
10105 273 : nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState,
10106 : FrameConstructionItemList& aItems,
10107 : nsContainerFrame* aParentFrame,
10108 : bool aParentIsWrapperAnonBox,
10109 : nsFrameItems& aFrameItems)
10110 : {
10111 : // Ensure aParentIsWrapperAnonBox is correct. We _could_ compute it directly,
10112 : // but it would be a bit slow, which is why we pass it from callers, who have
10113 : // that information offhand in many cases.
10114 273 : MOZ_ASSERT(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox);
10115 :
10116 0 : CreateNeededPseudoContainers(aState, aItems, aParentFrame);
10117 273 : CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
10118 0 : CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
10119 273 : CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
10120 :
10121 0 : for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
10122 0 : NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
10123 : "Needed pseudos didn't get created; expect bad things");
10124 272 : ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
10125 : }
10126 :
10127 0 : VerifyGridFlexContainerChildren(aParentFrame, aFrameItems);
10128 273 : NS_ASSERTION(!aState.mHavePendingPopupgroup,
10129 : "Should have proccessed it by now");
10130 :
10131 273 : if (aParentIsWrapperAnonBox) {
10132 0 : for (nsIFrame* f : aFrameItems) {
10133 0 : f->SetParentIsWrapperAnonBox();
10134 : }
10135 : }
10136 273 : }
10137 :
10138 : void
10139 237 : nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
10140 : nsFrameConstructorState& aState,
10141 : nsContainerFrame* aFrame,
10142 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
10143 : FrameConstructionItemList& aItemsToConstruct,
10144 : uint32_t aExtraFlags)
10145 : {
10146 648 : for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) {
10147 0 : nsIContent* content = aAnonymousItems[i].mContent;
10148 : // Gecko-styled nodes should have no pending restyle flags.
10149 : // Assert some things about this content
10150 87 : MOZ_ASSERT(!(content->GetFlags() &
10151 : (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
10152 : "Should not be marked as needing frames");
10153 87 : MOZ_ASSERT(!content->GetPrimaryFrame(),
10154 : "Should have no existing frame");
10155 87 : MOZ_ASSERT(!content->IsComment() && !content->IsProcessingInstruction(),
10156 : "Why is someone creating garbage anonymous content");
10157 :
10158 : // Make sure we eagerly performed the servo cascade when the anonymous
10159 : // nodes were created.
10160 0 : MOZ_ASSERT(!content->IsElement() || content->AsElement()->HasServoData());
10161 :
10162 261 : RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(content);
10163 :
10164 0 : nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
10165 261 : if (!aAnonymousItems[i].mChildren.IsEmpty()) {
10166 0 : anonChildren = &aAnonymousItems[i].mChildren;
10167 : }
10168 :
10169 : uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK |
10170 0 : ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags;
10171 :
10172 87 : AddFrameConstructionItemsInternal(aState, content, aFrame,
10173 : true, computedStyle, flags,
10174 87 : anonChildren, aItemsToConstruct);
10175 : }
10176 237 : }
10177 :
10178 : void
10179 214 : nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
10180 : nsIContent* aContent,
10181 : ComputedStyle* aComputedStyle,
10182 : nsContainerFrame* aFrame,
10183 : const bool aCanHaveGeneratedContent,
10184 : nsFrameItems& aFrameItems,
10185 : const bool aAllowBlockStyles,
10186 : PendingBinding* aPendingBinding,
10187 : nsIFrame* aPossiblyLeafFrame)
10188 : {
10189 214 : MOZ_ASSERT(aFrame, "Must have parent frame here");
10190 0 : MOZ_ASSERT(aFrame->GetContentInsertionFrame() == aFrame,
10191 : "Parent frame in ProcessChildren should be its own "
10192 : "content insertion frame");
10193 :
10194 214 : const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
10195 : static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
10196 0 : AutoRestore<uint16_t> savedDepth(mCurrentDepth);
10197 214 : if (mCurrentDepth != UINT16_MAX) {
10198 214 : ++mCurrentDepth;
10199 : }
10200 :
10201 214 : if (!aPossiblyLeafFrame) {
10202 29 : aPossiblyLeafFrame = aFrame;
10203 : }
10204 :
10205 : // XXXbz ideally, this would do all the pushing of various
10206 : // containing blocks as needed, so callers don't have to do it...
10207 :
10208 : // Check that our parent frame is a block before allowing ::first-letter/line.
10209 : // E.g. <button style="display:grid"> should not allow it.
10210 229 : const bool allowFirstPseudos = aAllowBlockStyles &&
10211 229 : nsLayoutUtils::GetAsBlock(aFrame);
10212 0 : bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
10213 214 : if (allowFirstPseudos) {
10214 : ShouldHaveSpecialBlockStyle(aContent, aComputedStyle, &haveFirstLetterStyle,
10215 15 : &haveFirstLineStyle);
10216 : }
10217 :
10218 0 : const bool isFlexOrGridContainer = ::IsFlexOrGridContainer(aFrame);
10219 : // The logic here needs to match the logic in GetFloatContainingBlock()
10220 : // (Since we already have isFlexOrGridContainer, we check that eagerly instead
10221 : // of letting ShouldSuppressFloatingOfDescendants look it up redundantly.)
10222 428 : nsFrameConstructorSaveState floatSaveState;
10223 428 : if (isFlexOrGridContainer ||
10224 214 : ShouldSuppressFloatingOfDescendants(aFrame)) {
10225 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
10226 38 : } else if (aFrame->IsFloatContainingBlock()) {
10227 0 : aState.PushFloatContainingBlock(aFrame, floatSaveState);
10228 : }
10229 :
10230 : nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
10231 0 : aPendingBinding);
10232 :
10233 428 : AutoFrameConstructionItemList itemsToConstruct(this);
10234 :
10235 : // If we have first-letter or first-line style then frames can get
10236 : // moved around so don't set these flags.
10237 214 : if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
10238 15 : itemsToConstruct.SetLineBoundaryAtStart(true);
10239 : itemsToConstruct.SetLineBoundaryAtEnd(true);
10240 : }
10241 :
10242 : // Create any anonymous frames we need here. This must happen before the
10243 : // non-anonymous children are processed to ensure that popups are never
10244 : // constructed before the popupset.
10245 428 : AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
10246 214 : GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
10247 : #ifdef DEBUG
10248 0 : for (uint32_t i = 0; i < anonymousItems.Length(); ++i) {
10249 108 : MOZ_ASSERT(anonymousItems[i].mContent->IsRootOfAnonymousSubtree(),
10250 : "Content should know it's an anonymous subtree");
10251 : }
10252 : #endif
10253 : AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
10254 214 : itemsToConstruct);
10255 :
10256 214 : if (!aPossiblyLeafFrame->IsLeaf()) {
10257 : // :before/:after content should have the same style parent as normal kids.
10258 : //
10259 : // Note that we don't use this style for looking up things like special
10260 : // block styles because in some cases involving table pseudo-frames it has
10261 : // nothing to do with the parent frame's desired behavior.
10262 : ComputedStyle* computedStyle;
10263 :
10264 0 : if (aCanHaveGeneratedContent) {
10265 : computedStyle =
10266 342 : nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->Style();
10267 : // Probe for generated content before
10268 0 : CreateGeneratedContentItem(aState, aFrame, aContent->AsElement(),
10269 : computedStyle, CSSPseudoElementType::before,
10270 171 : itemsToConstruct);
10271 : }
10272 :
10273 0 : const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
10274 0 : if (!addChildItems) {
10275 0 : NS_WARNING("ProcessChildren max depth exceeded");
10276 : }
10277 :
10278 342 : InsertionPoint insertion(aFrame, nullptr);
10279 342 : FlattenedChildIterator iter(aContent);
10280 0 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
10281 : // Get the parent of the content and check if it is a XBL children element
10282 : // (if the content is a children element then parent != aContent because the
10283 : // FlattenedChildIterator will transitively iterate through <xbl:children>
10284 : // for default content). Push the children element as an ancestor here because
10285 : // it does not have a frame and would not otherwise be pushed as an ancestor.
10286 0 : insertion.mContainer = aContent;
10287 :
10288 :
10289 : // FIXME(emilio): This code can go away, child->GetFlattenedTreeParent()
10290 : // is always aContent, wtf.
10291 375 : nsIContent* parent = child->GetParent();
10292 0 : MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
10293 0 : if (parent != aContent && parent->IsElement()) {
10294 0 : insertion.mContainer = child->GetFlattenedTreeParent();
10295 13 : MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(child).mContainer);
10296 : }
10297 :
10298 375 : if (addChildItems) {
10299 0 : AddFrameConstructionItems(aState, child, iter.XBLInvolved(), insertion,
10300 375 : itemsToConstruct);
10301 : } else {
10302 0 : ClearLazyBits(child, child->GetNextSibling());
10303 : }
10304 : }
10305 0 : itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
10306 :
10307 171 : if (aCanHaveGeneratedContent) {
10308 : // Probe for generated content after
10309 171 : CreateGeneratedContentItem(aState, aFrame, aContent->AsElement(),
10310 : computedStyle, CSSPseudoElementType::after,
10311 171 : itemsToConstruct);
10312 : }
10313 : } else {
10314 43 : ClearLazyBits(aContent->GetFirstChild(), nullptr);
10315 : }
10316 :
10317 : ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
10318 : /* aParentIsWrapperAnonBox = */ false,
10319 0 : aFrameItems);
10320 :
10321 0 : NS_ASSERTION(!allowFirstPseudos || !aFrame->IsXULBoxFrame(),
10322 : "can't be both block and box");
10323 :
10324 214 : if (haveFirstLetterStyle) {
10325 0 : WrapFramesInFirstLetterFrame(aFrame, aFrameItems);
10326 : }
10327 214 : if (haveFirstLineStyle) {
10328 : WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr,
10329 0 : aFrameItems);
10330 : }
10331 :
10332 : // We might end up with first-line frames that change
10333 : // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
10334 : // should never happen for cases whan aFrame->IsXULBoxFrame().
10335 214 : NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsXULBoxFrame(),
10336 : "Shouldn't have first-line style if we're a box");
10337 390 : NS_ASSERTION(!aFrame->IsXULBoxFrame() ||
10338 : itemsToConstruct.AnyItemsNeedBlockParent() ==
10339 : (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr),
10340 : "Something went awry in our block parent calculations");
10341 :
10342 0 : if (aFrame->IsXULBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
10343 : // XXXbz we could do this on the FrameConstructionItemList level,
10344 : // no? And if we cared we could look through the item list
10345 : // instead of groveling through the framelist here..
10346 0 : ComputedStyle *frameComputedStyle = aFrame->Style();
10347 : // Report a warning for non-GC frames, for chrome:
10348 0 : if (!aFrame->IsGeneratedContentFrame() &&
10349 0 : mPresShell->GetPresContext()->IsChrome()) {
10350 0 : nsIContent *badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild());
10351 0 : nsDependentAtomString parentTag(aContent->NodeInfo()->NameAtom()),
10352 0 : kidTag(badKid->NodeInfo()->NameAtom());
10353 0 : const char16_t* params[] = { parentTag.get(), kidTag.get() };
10354 0 : const nsStyleDisplay *display = frameComputedStyle->StyleDisplay();
10355 : const char *message =
10356 0 : (display->mDisplay == StyleDisplay::MozInlineBox)
10357 0 : ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
10358 0 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
10359 0 : NS_LITERAL_CSTRING("Layout: FrameConstructor"),
10360 0 : mDocument,
10361 : nsContentUtils::eXUL_PROPERTIES,
10362 : message,
10363 0 : params, ArrayLength(params));
10364 : }
10365 :
10366 3 : RefPtr<ComputedStyle> blockSC = mPresShell->StyleSet()->
10367 9 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock,
10368 0 : frameComputedStyle);
10369 3 : nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10370 : // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
10371 : // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
10372 : // a real block placed here wouldn't get those set on it.
10373 :
10374 0 : InitAndRestoreFrame(aState, aContent, aFrame, blockFrame, false);
10375 :
10376 0 : NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
10377 3 : ReparentFrames(this, blockFrame, aFrameItems, false);
10378 :
10379 0 : blockFrame->SetInitialChildList(kPrincipalList, aFrameItems);
10380 3 : NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?");
10381 0 : aFrameItems.Clear();
10382 3 : aFrameItems.AddChild(blockFrame);
10383 :
10384 6 : aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
10385 3 : MOZ_ASSERT(!aFrame->IsLeaf(),
10386 : "Why do we have an nsLeafBoxFrame here?");
10387 6 : aFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
10388 : }
10389 214 : }
10390 :
10391 : //----------------------------------------------------------------------
10392 :
10393 : // Support for :first-line style
10394 :
10395 : // Special routine to handle placing a list of frames into a block
10396 : // frame that has first-line style. The routine ensures that the first
10397 : // collection of inline frames end up in a first-line frame.
10398 : // NOTE: aState may have containing block information related to a
10399 : // different part of the frame tree than where the first line occurs.
10400 : // In particular aState may be set up for where ContentInserted or
10401 : // ContentAppended is inserting content, which may be some
10402 : // non-first-in-flow continuation of the block to which the first-line
10403 : // belongs. So this function needs to be careful about how it uses
10404 : // aState.
10405 : void
10406 0 : nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
10407 : nsFrameConstructorState& aState,
10408 : nsIContent* aBlockContent,
10409 : nsContainerFrame* aBlockFrame,
10410 : nsFirstLineFrame* aLineFrame,
10411 : nsFrameItems& aFrameItems)
10412 : {
10413 : // Find the part of aFrameItems that we want to put in the first-line
10414 0 : nsFrameList::FrameLinkEnumerator link(aFrameItems);
10415 0 : while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) {
10416 0 : link.Next();
10417 : }
10418 :
10419 0 : nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
10420 :
10421 0 : if (firstLineChildren.IsEmpty()) {
10422 : // Nothing is supposed to go into the first-line; nothing to do
10423 0 : return;
10424 : }
10425 :
10426 0 : if (!aLineFrame) {
10427 : // Create line frame
10428 : ComputedStyle* parentStyle =
10429 : nsFrame::CorrectStyleParentFrame(aBlockFrame,
10430 : nsCSSPseudoElements::firstLine)->
10431 0 : Style();
10432 0 : RefPtr<ComputedStyle> firstLineStyle = GetFirstLineStyle(aBlockContent,
10433 0 : parentStyle);
10434 :
10435 0 : aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
10436 :
10437 : // Initialize the line frame
10438 0 : InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
10439 :
10440 : // The lineFrame will be the block's first child; the rest of the
10441 : // frame list (after lastInlineFrame) will be the second and
10442 : // subsequent children; insert lineFrame into aFrameItems.
10443 0 : aFrameItems.InsertFrame(nullptr, nullptr, aLineFrame);
10444 :
10445 0 : NS_ASSERTION(aLineFrame->Style() == firstLineStyle,
10446 : "Bogus style on line frame");
10447 : }
10448 :
10449 : // Give the inline frames to the lineFrame <b>after</b> reparenting them
10450 0 : ReparentFrames(this, aLineFrame, firstLineChildren, true);
10451 0 : if (aLineFrame->PrincipalChildList().IsEmpty() &&
10452 0 : (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
10453 0 : aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren);
10454 : } else {
10455 0 : AppendFrames(aLineFrame, kPrincipalList, firstLineChildren);
10456 : }
10457 : }
10458 :
10459 : // Special routine to handle appending a new frame to a block frame's
10460 : // child list. Takes care of placing the new frame into the right
10461 : // place when first-line style is present.
10462 : void
10463 0 : nsCSSFrameConstructor::AppendFirstLineFrames(
10464 : nsFrameConstructorState& aState,
10465 : nsIContent* aBlockContent,
10466 : nsContainerFrame* aBlockFrame,
10467 : nsFrameItems& aFrameItems)
10468 : {
10469 : // It's possible that aBlockFrame needs to have a first-line frame
10470 : // created because it doesn't currently have any children.
10471 0 : const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
10472 0 : if (blockKids.IsEmpty()) {
10473 : WrapFramesInFirstLineFrame(aState, aBlockContent,
10474 0 : aBlockFrame, nullptr, aFrameItems);
10475 0 : return;
10476 : }
10477 :
10478 : // Examine the last block child - if it's a first-line frame then
10479 : // appended frames need special treatment.
10480 0 : nsIFrame* lastBlockKid = blockKids.LastChild();
10481 0 : if (!lastBlockKid->IsLineFrame()) {
10482 : // No first-line frame at the end of the list, therefore there is
10483 : // an intervening block between any first-line frame the frames
10484 : // we are appending. Therefore, we don't need any special
10485 : // treatment of the appended frames.
10486 : return;
10487 : }
10488 :
10489 0 : nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
10490 : WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame,
10491 0 : lineFrame, aFrameItems);
10492 : }
10493 :
10494 : void
10495 0 : nsCSSFrameConstructor::CheckForFirstLineInsertion(nsIFrame* aParentFrame,
10496 : nsFrameItems& aFrameItems)
10497 : {
10498 0 : MOZ_ASSERT(aParentFrame->Style()->HasPseudoElementData(),
10499 : "Why were we called?");
10500 :
10501 0 : if (aFrameItems.IsEmpty()) {
10502 : // Happens often enough, with the caption stuff. No need to do the ancestor
10503 : // walk here.
10504 : return;
10505 : }
10506 :
10507 0 : class RestyleManager* restyleManager = RestyleManager();
10508 :
10509 : // Check whether there's a ::first-line on the path up from aParentFrame.
10510 : // Note that we can't stop until we've run out of ancestors with
10511 : // pseudo-element data, because the first-letter might be somewhere way up the
10512 : // tree; in particular it might be past our containing block.
10513 0 : nsIFrame* ancestor = aParentFrame;
10514 0 : while (ancestor) {
10515 0 : if (!ancestor->Style()->HasPseudoElementData()) {
10516 : // We know we won't find a ::first-line now.
10517 : return;
10518 : }
10519 :
10520 0 : if (!ancestor->IsLineFrame()) {
10521 0 : ancestor = ancestor->GetParent();
10522 : continue;
10523 : }
10524 :
10525 0 : if (!ancestor->Style()->IsPseudoElement()) {
10526 : // This is a continuation lineframe, not the first line; no need to do
10527 : // anything to the styles.
10528 : return;
10529 : }
10530 :
10531 : // Fix up the styles of aFrameItems for ::first-line.
10532 0 : for (nsIFrame* f : aFrameItems) {
10533 0 : restyleManager->ReparentComputedStyleForFirstLine(f);
10534 : }
10535 0 : return;
10536 : }
10537 : }
10538 :
10539 : //----------------------------------------------------------------------
10540 :
10541 : // First-letter support
10542 :
10543 : // Determine how many characters in the text fragment apply to the
10544 : // first letter
10545 : static int32_t
10546 0 : FirstLetterCount(const nsTextFragment* aFragment)
10547 : {
10548 0 : int32_t count = 0;
10549 0 : int32_t firstLetterLength = 0;
10550 :
10551 0 : int32_t i, n = aFragment->GetLength();
10552 0 : for (i = 0; i < n; i++) {
10553 0 : char16_t ch = aFragment->CharAt(i);
10554 : // FIXME: take content language into account when deciding whitespace.
10555 0 : if (dom::IsSpaceCharacter(ch)) {
10556 0 : if (firstLetterLength) {
10557 : break;
10558 : }
10559 0 : count++;
10560 0 : continue;
10561 : }
10562 : // XXX I18n
10563 0 : if ((ch == '\'') || (ch == '\"')) {
10564 0 : if (firstLetterLength) {
10565 : break;
10566 : }
10567 : // keep looping
10568 : firstLetterLength = 1;
10569 : }
10570 : else {
10571 0 : count++;
10572 0 : break;
10573 : }
10574 : }
10575 :
10576 0 : return count;
10577 : }
10578 :
10579 : static bool
10580 0 : NeedFirstLetterContinuation(nsIContent* aContent)
10581 : {
10582 0 : MOZ_ASSERT(aContent, "null ptr");
10583 :
10584 0 : bool result = false;
10585 0 : if (aContent) {
10586 0 : const nsTextFragment* frag = aContent->GetText();
10587 0 : if (frag) {
10588 0 : int32_t flc = FirstLetterCount(frag);
10589 0 : int32_t tl = frag->GetLength();
10590 0 : if (flc < tl) {
10591 0 : result = true;
10592 : }
10593 : }
10594 : }
10595 0 : return result;
10596 : }
10597 :
10598 0 : static bool IsFirstLetterContent(nsIContent* aContent)
10599 : {
10600 0 : return aContent->TextLength() &&
10601 0 : !aContent->TextIsOnlyWhitespace();
10602 : }
10603 :
10604 : /**
10605 : * Create a letter frame, only make it a floating frame.
10606 : */
10607 : nsFirstLetterFrame*
10608 0 : nsCSSFrameConstructor::CreateFloatingLetterFrame(
10609 : nsFrameConstructorState& aState,
10610 : nsIContent* aTextContent,
10611 : nsIFrame* aTextFrame,
10612 : nsContainerFrame* aParentFrame,
10613 : ComputedStyle* aParentComputedStyle,
10614 : ComputedStyle* aComputedStyle,
10615 : nsFrameItems& aResult)
10616 : {
10617 0 : MOZ_ASSERT(aParentComputedStyle);
10618 :
10619 : nsFirstLetterFrame* letterFrame =
10620 0 : NS_NewFirstLetterFrame(mPresShell, aComputedStyle);
10621 : // We don't want to use a text content for a non-text frame (because we want
10622 : // its primary frame to be a text frame).
10623 0 : nsIContent* letterContent = aParentFrame->GetContent();
10624 0 : nsContainerFrame* containingBlock = aState.GetGeometricParent(
10625 0 : aComputedStyle->StyleDisplay(), aParentFrame);
10626 0 : InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
10627 :
10628 : // Init the text frame to refer to the letter frame.
10629 : //
10630 : // Make sure we get a proper style for it (the one passed in is for the letter
10631 : // frame and will have the float property set on it; the text frame shouldn't
10632 : // have that set).
10633 0 : ServoStyleSet* styleSet = mPresShell->StyleSet();
10634 : RefPtr<ComputedStyle> textSC = styleSet->
10635 0 : ResolveStyleForText(aTextContent, aComputedStyle);
10636 0 : aTextFrame->SetComputedStyleWithoutNotification(textSC);
10637 0 : InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
10638 :
10639 : // And then give the text frame to the letter frame
10640 0 : SetInitialSingleChild(letterFrame, aTextFrame);
10641 :
10642 : // See if we will need to continue the text frame (does it contain
10643 : // more than just the first-letter text or not?) If it does, then we
10644 : // create (in advance) a continuation frame for it.
10645 0 : nsIFrame* nextTextFrame = nullptr;
10646 0 : if (NeedFirstLetterContinuation(aTextContent)) {
10647 : // Create continuation
10648 : nextTextFrame =
10649 0 : CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame);
10650 : RefPtr<ComputedStyle> newSC = styleSet->
10651 0 : ResolveStyleForText(aTextContent, aParentComputedStyle);
10652 0 : nextTextFrame->SetComputedStyle(newSC);
10653 : }
10654 :
10655 0 : NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
10656 : // Put the new float before any of the floats in the block we're doing
10657 : // first-letter for, that is, before any floats whose parent is
10658 : // containingBlock.
10659 0 : nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
10660 0 : while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) {
10661 0 : link.Next();
10662 : }
10663 :
10664 0 : aState.AddChild(letterFrame, aResult, letterContent, aParentFrame,
10665 0 : false, true, false, true, link.PrevFrame());
10666 :
10667 0 : if (nextTextFrame) {
10668 0 : aResult.AddChild(nextTextFrame);
10669 : }
10670 :
10671 0 : return letterFrame;
10672 : }
10673 :
10674 : /**
10675 : * Create a new letter frame for aTextFrame. The letter frame will be
10676 : * a child of aParentFrame.
10677 : */
10678 : void
10679 0 : nsCSSFrameConstructor::CreateLetterFrame(nsContainerFrame* aBlockFrame,
10680 : nsContainerFrame* aBlockContinuation,
10681 : nsIContent* aTextContent,
10682 : nsContainerFrame* aParentFrame,
10683 : nsFrameItems& aResult)
10684 : {
10685 0 : MOZ_ASSERT(aTextContent->IsText(), "aTextContent isn't text");
10686 0 : NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
10687 : "Not a block frame?");
10688 :
10689 : // Get a ComputedStyle for the first-letter-frame.
10690 : //
10691 : // Keep this in sync with nsBlockFrame::UpdatePseudoElementStyles.
10692 : nsIFrame* parentFrame =
10693 0 : nsFrame::CorrectStyleParentFrame(aParentFrame,
10694 0 : nsCSSPseudoElements::firstLetter);
10695 :
10696 0 : ComputedStyle* parentComputedStyle = parentFrame->Style();
10697 :
10698 : // Use content from containing block so that we can actually
10699 : // find a matching style rule.
10700 0 : nsIContent* blockContent = aBlockFrame->GetContent();
10701 :
10702 : // Create first-letter style rule
10703 : RefPtr<ComputedStyle> sc =
10704 0 : GetFirstLetterStyle(blockContent, parentComputedStyle);
10705 :
10706 0 : if (sc) {
10707 0 : if (parentFrame->IsLineFrame()) {
10708 : nsIFrame* parentIgnoringFirstLine =
10709 0 : nsFrame::CorrectStyleParentFrame(aBlockFrame,
10710 0 : nsCSSPseudoElements::firstLetter);
10711 :
10712 : sc =
10713 0 : mPresShell->StyleSet()->ReparentComputedStyle(
10714 : sc,
10715 : parentComputedStyle,
10716 : parentIgnoringFirstLine->Style(),
10717 : parentComputedStyle,
10718 0 : blockContent->AsElement());
10719 : }
10720 :
10721 0 : RefPtr<ComputedStyle> textSC = mPresShell->StyleSet()->
10722 0 : ResolveStyleForText(aTextContent, sc);
10723 :
10724 : // Create a new text frame (the original one will be discarded)
10725 : // pass a temporary stylecontext, the correct one will be set
10726 : // later. Start off by unsetting the primary frame for
10727 : // aTextContent, so it's no longer pointing to the to-be-destroyed
10728 : // frame.
10729 : // XXXbz it would be really nice to destroy the old frame _first_,
10730 : // then create the new one, so we could avoid this hack.
10731 0 : aTextContent->SetPrimaryFrame(nullptr);
10732 0 : nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
10733 :
10734 0 : NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
10735 : "Containing block is confused");
10736 : nsFrameConstructorState state(mPresShell,
10737 : GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
10738 : GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
10739 0 : aBlockContinuation);
10740 :
10741 : // Create the right type of first-letter frame
10742 0 : const nsStyleDisplay* display = sc->StyleDisplay();
10743 : nsFirstLetterFrame* letterFrame;
10744 0 : if (display->IsFloatingStyle() &&
10745 0 : !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
10746 : // Make a floating first-letter frame
10747 0 : letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
10748 : aParentFrame, parentComputedStyle,
10749 0 : sc, aResult);
10750 : }
10751 : else {
10752 : // Make an inflow first-letter frame
10753 0 : letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
10754 :
10755 : // Initialize the first-letter-frame. We don't want to use a text
10756 : // content for a non-text frame (because we want its primary frame to
10757 : // be a text frame).
10758 0 : nsIContent* letterContent = aParentFrame->GetContent();
10759 0 : letterFrame->Init(letterContent, aParentFrame, nullptr);
10760 :
10761 0 : InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
10762 :
10763 0 : SetInitialSingleChild(letterFrame, textFrame);
10764 0 : aResult.Clear();
10765 0 : aResult.AddChild(letterFrame);
10766 0 : NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
10767 : "should have the first continuation here");
10768 0 : aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
10769 : }
10770 0 : MOZ_ASSERT(!aBlockFrame->GetPrevContinuation(),
10771 : "Setting up a first-letter frame on a non-first block continuation?");
10772 0 : auto parent = static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
10773 0 : parent->SetHasFirstLetterChild();
10774 0 : aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
10775 0 : letterFrame);
10776 0 : aTextContent->SetPrimaryFrame(textFrame);
10777 : }
10778 0 : }
10779 :
10780 : void
10781 0 : nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10782 : nsContainerFrame* aBlockFrame,
10783 : nsFrameItems& aBlockFrames)
10784 : {
10785 0 : aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
10786 :
10787 0 : nsContainerFrame* parentFrame = nullptr;
10788 0 : nsIFrame* textFrame = nullptr;
10789 0 : nsIFrame* prevFrame = nullptr;
10790 0 : nsFrameItems letterFrames;
10791 0 : bool stopLooking = false;
10792 0 : WrapFramesInFirstLetterFrame(aBlockFrame, aBlockFrame, aBlockFrame,
10793 : aBlockFrames.FirstChild(),
10794 : &parentFrame, &textFrame, &prevFrame,
10795 0 : letterFrames, &stopLooking);
10796 0 : if (parentFrame) {
10797 0 : if (parentFrame == aBlockFrame) {
10798 : // Take textFrame out of the block's frame list and substitute the
10799 : // letter frame(s) instead.
10800 0 : aBlockFrames.DestroyFrame(textFrame);
10801 0 : aBlockFrames.InsertFrames(nullptr, prevFrame, letterFrames);
10802 : }
10803 : else {
10804 : // Take the old textFrame out of the inline parent's child list
10805 0 : RemoveFrame(kPrincipalList, textFrame);
10806 :
10807 : // Insert in the letter frame(s)
10808 0 : parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
10809 : }
10810 : }
10811 0 : }
10812 :
10813 : void
10814 0 : nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10815 : nsContainerFrame* aBlockFrame,
10816 : nsContainerFrame* aBlockContinuation,
10817 : nsContainerFrame* aParentFrame,
10818 : nsIFrame* aParentFrameList,
10819 : nsContainerFrame** aModifiedParent,
10820 : nsIFrame** aTextFrame,
10821 : nsIFrame** aPrevFrame,
10822 : nsFrameItems& aLetterFrames,
10823 : bool* aStopLooking)
10824 : {
10825 0 : nsIFrame* prevFrame = nullptr;
10826 0 : nsIFrame* frame = aParentFrameList;
10827 :
10828 0 : while (frame) {
10829 0 : nsIFrame* nextFrame = frame->GetNextSibling();
10830 :
10831 0 : LayoutFrameType frameType = frame->Type();
10832 0 : if (LayoutFrameType::Text == frameType) {
10833 : // Wrap up first-letter content in a letter frame
10834 0 : nsIContent* textContent = frame->GetContent();
10835 0 : if (IsFirstLetterContent(textContent)) {
10836 : // Create letter frame to wrap up the text
10837 : CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
10838 0 : aParentFrame, aLetterFrames);
10839 :
10840 : // Provide adjustment information for parent
10841 0 : *aModifiedParent = aParentFrame;
10842 0 : *aTextFrame = frame;
10843 0 : *aPrevFrame = prevFrame;
10844 0 : *aStopLooking = true;
10845 0 : return;
10846 : }
10847 0 : } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
10848 0 : nsIFrame* kids = frame->PrincipalChildList().FirstChild();
10849 : WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
10850 : static_cast<nsContainerFrame*>(frame),
10851 : kids, aModifiedParent, aTextFrame,
10852 0 : aPrevFrame, aLetterFrames, aStopLooking);
10853 0 : if (*aStopLooking) {
10854 : return;
10855 : }
10856 : }
10857 : else {
10858 : // This will stop us looking to create more letter frames. For
10859 : // example, maybe the frame-type is "letterFrame" or
10860 : // "placeholderFrame". This keeps us from creating extra letter
10861 : // frames, and also prevents us from creating letter frames when
10862 : // the first real content child of a block is not text (e.g. an
10863 : // image, hr, etc.)
10864 0 : *aStopLooking = true;
10865 0 : break;
10866 : }
10867 :
10868 : prevFrame = frame;
10869 : frame = nextFrame;
10870 : }
10871 : }
10872 :
10873 : static nsIFrame*
10874 0 : FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID)
10875 : {
10876 0 : nsFrameList list = aFrame->GetChildList(aListID);
10877 0 : for (nsFrameList::Enumerator e(list); !e.AtEnd(); e.Next()) {
10878 0 : if (e.get()->IsLetterFrame()) {
10879 0 : return e.get();
10880 : }
10881 : }
10882 0 : return nullptr;
10883 : }
10884 :
10885 : void
10886 0 : nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
10887 : nsIPresShell* aPresShell,
10888 : nsIFrame* aBlockFrame)
10889 : {
10890 : // Look for the first letter frame on the kFloatList, then kPushedFloatsList.
10891 : nsIFrame* floatFrame =
10892 0 : ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kFloatList);
10893 0 : if (!floatFrame) {
10894 : floatFrame =
10895 0 : ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList);
10896 0 : if (!floatFrame) {
10897 0 : return;
10898 : }
10899 : }
10900 :
10901 : // Take the text frame away from the letter frame (so it isn't
10902 : // destroyed when we destroy the letter frame).
10903 0 : nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
10904 0 : if (!textFrame) {
10905 : return;
10906 : }
10907 :
10908 : // Discover the placeholder frame for the letter frame
10909 0 : nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
10910 0 : if (!placeholderFrame) {
10911 : // Somethings really wrong
10912 : return;
10913 : }
10914 0 : nsContainerFrame* parentFrame = placeholderFrame->GetParent();
10915 0 : if (!parentFrame) {
10916 : // Somethings really wrong
10917 : return;
10918 : }
10919 0 : static_cast<nsContainerFrame*>(parentFrame->FirstContinuation())->
10920 0 : ClearHasFirstLetterChild();
10921 :
10922 : // Create a new text frame with the right style that maps all of the content
10923 : // that was previously part of the letter frame (and probably continued
10924 : // elsewhere).
10925 0 : ComputedStyle* parentSC = parentFrame->Style();
10926 0 : nsIContent* textContent = textFrame->GetContent();
10927 0 : if (!textContent) {
10928 : return;
10929 : }
10930 : RefPtr<ComputedStyle> newSC = aPresShell->StyleSet()->
10931 0 : ResolveStyleForText(textContent, parentSC);
10932 0 : nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
10933 0 : newTextFrame->Init(textContent, parentFrame, nullptr);
10934 :
10935 : // Destroy the old text frame's continuations (the old text frame
10936 : // will be destroyed when its letter frame is destroyed).
10937 0 : nsIFrame* frameToDelete = textFrame->LastContinuation();
10938 0 : while (frameToDelete != textFrame) {
10939 0 : nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
10940 0 : RemoveFrame(kPrincipalList, frameToDelete);
10941 0 : frameToDelete = nextFrameToDelete;
10942 : }
10943 :
10944 0 : nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
10945 :
10946 : // Now that everything is set...
10947 : #ifdef NOISY_FIRST_LETTER
10948 : printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
10949 : textContent.get(), textFrame, newTextFrame);
10950 : #endif
10951 :
10952 : // Remove placeholder frame and the float
10953 0 : RemoveFrame(kPrincipalList, placeholderFrame);
10954 :
10955 : // Now that the old frames are gone, we can start pointing to our
10956 : // new primary frame.
10957 0 : textContent->SetPrimaryFrame(newTextFrame);
10958 :
10959 : // Wallpaper bug 822910.
10960 0 : bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
10961 0 : if (offsetsNeedFixing) {
10962 : prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
10963 : }
10964 :
10965 : // Insert text frame in its place
10966 0 : nsFrameList textList(newTextFrame, newTextFrame);
10967 0 : InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
10968 :
10969 0 : if (offsetsNeedFixing) {
10970 : prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
10971 : }
10972 : }
10973 :
10974 : void
10975 0 : nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell,
10976 : nsContainerFrame* aFrame,
10977 : nsContainerFrame* aBlockFrame,
10978 : bool* aStopLooking)
10979 : {
10980 0 : nsIFrame* prevSibling = nullptr;
10981 0 : nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
10982 :
10983 0 : while (kid) {
10984 0 : if (kid->IsLetterFrame()) {
10985 : // Bingo. Found it. First steal away the text frame.
10986 0 : static_cast<nsContainerFrame*>(aFrame->FirstContinuation())->
10987 0 : ClearHasFirstLetterChild();
10988 0 : nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
10989 0 : if (!textFrame) {
10990 : break;
10991 : }
10992 :
10993 : // Create a new textframe
10994 0 : ComputedStyle* parentSC = aFrame->Style();
10995 0 : if (!parentSC) {
10996 : break;
10997 : }
10998 0 : nsIContent* textContent = textFrame->GetContent();
10999 0 : if (!textContent) {
11000 : break;
11001 : }
11002 : RefPtr<ComputedStyle> newSC = aPresShell->StyleSet()->
11003 0 : ResolveStyleForText(textContent, parentSC);
11004 0 : textFrame = NS_NewTextFrame(aPresShell, newSC);
11005 0 : textFrame->Init(textContent, aFrame, nullptr);
11006 :
11007 : // Next rip out the kid and replace it with the text frame
11008 0 : RemoveFrame(kPrincipalList, kid);
11009 :
11010 : // Now that the old frames are gone, we can start pointing to our
11011 : // new primary frame.
11012 0 : textContent->SetPrimaryFrame(textFrame);
11013 :
11014 : // Wallpaper bug 822910.
11015 0 : bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
11016 0 : if (offsetsNeedFixing) {
11017 : prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
11018 : }
11019 :
11020 : // Insert text frame in its place
11021 0 : nsFrameList textList(textFrame, textFrame);
11022 0 : InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
11023 :
11024 0 : if (offsetsNeedFixing) {
11025 : prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
11026 : }
11027 :
11028 0 : *aStopLooking = true;
11029 0 : NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
11030 : "should have the first continuation here");
11031 0 : aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
11032 : break;
11033 : }
11034 0 : else if (IsInlineFrame(kid)) {
11035 0 : nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
11036 0 : if (kidAsContainerFrame) {
11037 : // Look inside child inline frame for the letter frame.
11038 : RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame,
11039 0 : aBlockFrame, aStopLooking);
11040 0 : if (*aStopLooking) {
11041 : break;
11042 : }
11043 : }
11044 : }
11045 0 : prevSibling = kid;
11046 0 : kid = kid->GetNextSibling();
11047 : }
11048 0 : }
11049 :
11050 : void
11051 0 : nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
11052 : nsContainerFrame* aBlockFrame)
11053 : {
11054 : aBlockFrame =
11055 0 : static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
11056 0 : aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
11057 0 : nsContainerFrame* continuation = aBlockFrame;
11058 :
11059 0 : bool stopLooking = false;
11060 : do {
11061 0 : RemoveFloatingFirstLetterFrames(aPresShell, continuation);
11062 : RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
11063 0 : &stopLooking);
11064 0 : if (stopLooking) {
11065 : break;
11066 : }
11067 : continuation =
11068 0 : static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
11069 0 : } while (continuation);
11070 0 : }
11071 :
11072 : // Fixup the letter frame situation for the given block
11073 : void
11074 0 : nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame)
11075 : {
11076 : aBlockFrame =
11077 0 : static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
11078 0 : nsContainerFrame* continuation = aBlockFrame;
11079 :
11080 0 : nsContainerFrame* parentFrame = nullptr;
11081 0 : nsIFrame* textFrame = nullptr;
11082 0 : nsIFrame* prevFrame = nullptr;
11083 0 : nsFrameItems letterFrames;
11084 0 : bool stopLooking = false;
11085 : do {
11086 : // XXX shouldn't this bit be set already (bug 408493), assert instead?
11087 0 : continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
11088 0 : WrapFramesInFirstLetterFrame(aBlockFrame, continuation, continuation,
11089 0 : continuation->PrincipalChildList().FirstChild(),
11090 : &parentFrame, &textFrame, &prevFrame,
11091 0 : letterFrames, &stopLooking);
11092 0 : if (stopLooking) {
11093 : break;
11094 : }
11095 : continuation =
11096 0 : static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
11097 0 : } while (continuation);
11098 :
11099 0 : if (parentFrame) {
11100 : // Take the old textFrame out of the parent's child list
11101 0 : RemoveFrame(kPrincipalList, textFrame);
11102 :
11103 : // Insert in the letter frame(s)
11104 0 : parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
11105 : }
11106 0 : }
11107 :
11108 : //----------------------------------------------------------------------
11109 :
11110 : // listbox Widget Routines
11111 :
11112 : void
11113 0 : nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
11114 : nsIFrame* aPrevFrame,
11115 : nsIContent* aChild,
11116 : nsIFrame** aNewFrame,
11117 : bool aIsAppend)
11118 : {
11119 : #ifdef MOZ_XUL
11120 : // Construct a new frame
11121 0 : if (aParentFrame) {
11122 0 : nsFrameItems frameItems;
11123 : nsFrameConstructorState state(mPresShell,
11124 : GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
11125 : GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
11126 : GetFloatContainingBlock(aParentFrame),
11127 0 : do_AddRef(mTempFrameTreeState));
11128 :
11129 0 : if (aChild->IsElement() && !aChild->AsElement()->HasServoData()) {
11130 0 : mPresShell->StyleSet()->StyleNewSubtree(aChild->AsElement());
11131 : }
11132 :
11133 0 : RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aChild);
11134 :
11135 : // Pre-check for display "none" - only if we find that, do we create
11136 : // any frame at all
11137 0 : const nsStyleDisplay* display = computedStyle->StyleDisplay();
11138 :
11139 0 : if (StyleDisplay::None == display->mDisplay) {
11140 0 : *aNewFrame = nullptr;
11141 0 : return;
11142 : }
11143 :
11144 0 : AutoFrameConstructionItemList items(this);
11145 0 : AddFrameConstructionItemsInternal(state, aChild, aParentFrame,
11146 : true, computedStyle,
11147 0 : ITEM_ALLOW_XBL_BASE, nullptr, items);
11148 : ConstructFramesFromItemList(state, items, aParentFrame,
11149 : /* aParentIsWrapperAnonBox = */ false,
11150 0 : frameItems);
11151 :
11152 0 : nsIFrame* newFrame = frameItems.FirstChild();
11153 0 : *aNewFrame = newFrame;
11154 :
11155 0 : if (newFrame) {
11156 : // Notify the parent frame
11157 0 : if (aIsAppend)
11158 0 : ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
11159 : else
11160 0 : ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
11161 : }
11162 :
11163 : #ifdef ACCESSIBILITY
11164 0 : if (newFrame) {
11165 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
11166 0 : if (accService) {
11167 0 : accService->ContentRangeInserted(mPresShell,
11168 : aChild,
11169 0 : aChild->GetNextSibling());
11170 : }
11171 : }
11172 : #endif
11173 : }
11174 : #endif
11175 : }
11176 :
11177 : //----------------------------------------
11178 :
11179 : void
11180 15 : nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
11181 : nsIContent* aContent,
11182 : nsContainerFrame* aParentFrame,
11183 : nsContainerFrame* aContentParentFrame,
11184 : ComputedStyle* aComputedStyle,
11185 : nsContainerFrame** aNewFrame,
11186 : nsFrameItems& aFrameItems,
11187 : nsIFrame* aPositionedFrameForAbsPosContainer,
11188 : PendingBinding* aPendingBinding)
11189 : {
11190 : // Create column wrapper if necessary
11191 15 : nsContainerFrame* blockFrame = *aNewFrame;
11192 0 : NS_ASSERTION((blockFrame->IsBlockFrame() || blockFrame->IsDetailsFrame()),
11193 : "not a block frame nor a details frame?");
11194 15 : nsContainerFrame* parent = aParentFrame;
11195 0 : RefPtr<ComputedStyle> blockStyle = aComputedStyle;
11196 0 : const nsStyleColumn* columns = aComputedStyle->StyleColumn();
11197 :
11198 0 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO
11199 0 : || columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
11200 : nsContainerFrame* columnSetFrame =
11201 0 : NS_NewColumnSetFrame(mPresShell, aComputedStyle,
11202 0 : nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
11203 :
11204 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
11205 0 : blockStyle = mPresShell->StyleSet()->
11206 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
11207 0 : aComputedStyle);
11208 0 : parent = columnSetFrame;
11209 0 : *aNewFrame = columnSetFrame;
11210 0 : if (aPositionedFrameForAbsPosContainer == blockFrame) {
11211 0 : aPositionedFrameForAbsPosContainer = columnSetFrame;
11212 : }
11213 :
11214 0 : SetInitialSingleChild(columnSetFrame, blockFrame);
11215 : }
11216 :
11217 0 : blockFrame->SetComputedStyleWithoutNotification(blockStyle);
11218 15 : InitAndRestoreFrame(aState, aContent, parent, blockFrame);
11219 :
11220 0 : aState.AddChild(*aNewFrame, aFrameItems, aContent,
11221 : aContentParentFrame ? aContentParentFrame :
11222 15 : aParentFrame);
11223 15 : if (!mRootElementFrame) {
11224 : // The frame we're constructing will be the root element frame.
11225 : // Set mRootElementFrame before processing children.
11226 5 : mRootElementFrame = *aNewFrame;
11227 : }
11228 :
11229 : // We should make the outer frame be the absolute containing block,
11230 : // if one is required. We have to do this because absolute
11231 : // positioning must be computed with respect to the CSS dimensions
11232 : // of the element, which are the dimensions of the outer block. But
11233 : // we can't really do that because only blocks can have absolute
11234 : // children. So use the block and try to compensate with hacks
11235 : // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
11236 30 : nsFrameConstructorSaveState absoluteSaveState;
11237 30 : (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11238 0 : if (aPositionedFrameForAbsPosContainer) {
11239 : // NS_ASSERTION(aRelPos, "should have made area frame for this");
11240 0 : aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
11241 : }
11242 :
11243 : // Process the child content
11244 0 : nsFrameItems childItems;
11245 : ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true,
11246 15 : childItems, true, aPendingBinding);
11247 :
11248 : // Set the frame's initial child list
11249 15 : blockFrame->SetInitialChildList(kPrincipalList, childItems);
11250 15 : }
11251 :
11252 : nsIFrame*
11253 0 : nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
11254 : FrameConstructionItem& aItem,
11255 : nsContainerFrame* aParentFrame,
11256 : const nsStyleDisplay* aDisplay,
11257 : nsFrameItems& aFrameItems)
11258 : {
11259 : // If an inline frame has non-inline kids, then we chop up the child list
11260 : // into runs of blocks and runs of inlines, create anonymous block frames to
11261 : // contain the runs of blocks, inline frames with our style for the runs of
11262 : // inlines, and put all these frames, in order, into aFrameItems.
11263 : //
11264 : // We return the the first one. The whole setup is called an {ib}
11265 : // split; in what follows "frames in the split" refers to the anonymous blocks
11266 : // and inlines that contain our children.
11267 : //
11268 : // {ib} splits maintain the following invariants:
11269 : // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
11270 : // set.
11271 : // 2) Each frame in the split has the nsIFrame::IBSplitSibling
11272 : // property pointing to the next frame in the split, except for the last
11273 : // one, which does not have it set.
11274 : // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
11275 : // property pointing to the previous frame in the split, except for the
11276 : // first one, which does not have it set.
11277 : // 4) The first and last frame in the split are always inlines.
11278 : //
11279 : // An invariant that is NOT maintained is that the wrappers are actually
11280 : // linked via GetNextSibling linkage. A simple example is an inline
11281 : // containing an inline that contains a block. The three parts of the inner
11282 : // inline end up with three different parents.
11283 : //
11284 : // For example, this HTML:
11285 : // <span>
11286 : // <div>a</div>
11287 : // <span>
11288 : // b
11289 : // <div>c</div>
11290 : // </span>
11291 : // d
11292 : // <div>e</div>
11293 : // f
11294 : // </span>
11295 : // Gives the following frame tree:
11296 : //
11297 : // Inline (outer span)
11298 : // Block (anonymous, outer span)
11299 : // Block (div)
11300 : // Text("a")
11301 : // Inline (outer span)
11302 : // Inline (inner span)
11303 : // Text("b")
11304 : // Block (anonymous, outer span)
11305 : // Block (anonymous, inner span)
11306 : // Block (div)
11307 : // Text("c")
11308 : // Inline (outer span)
11309 : // Inline (inner span)
11310 : // Text("d")
11311 : // Block (anonymous, outer span)
11312 : // Block (div)
11313 : // Text("e")
11314 : // Inline (outer span)
11315 : // Text("f")
11316 :
11317 0 : nsIContent* const content = aItem.mContent;
11318 0 : ComputedStyle* const computedStyle = aItem.mComputedStyle;
11319 :
11320 : bool positioned =
11321 0 : StyleDisplay::Inline == aDisplay->mDisplay &&
11322 0 : aDisplay->IsRelativelyPositionedStyle() &&
11323 0 : !nsSVGUtils::IsInSVGTextSubtree(aParentFrame);
11324 :
11325 0 : nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
11326 :
11327 : // Initialize the frame
11328 0 : InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
11329 :
11330 0 : nsFrameConstructorSaveState absoluteSaveState; // definition cannot be inside next block
11331 : // because the object's destructor is significant
11332 : // this is part of the fix for bug 42372
11333 :
11334 0 : newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11335 0 : if (positioned) {
11336 : // Relatively positioned frames becomes a container for child
11337 : // frames that are positioned
11338 0 : aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
11339 : }
11340 :
11341 : // Process the child content
11342 0 : nsFrameItems childItems;
11343 0 : ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
11344 : /* aParentIsWrapperAnonBox = */ false,
11345 0 : childItems);
11346 :
11347 0 : nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
11348 0 : if (!aItem.mIsAllInline) {
11349 0 : FindFirstBlock(firstBlockEnumerator);
11350 : }
11351 :
11352 0 : if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) {
11353 : // This part is easy. We either already know we have no non-inline kids,
11354 : // or haven't found any when constructing actual frames (the latter can
11355 : // happen only if out-of-flows that we thought had no containing block
11356 : // acquired one when ancestor inline frames and {ib} splits got
11357 : // constructed). Just put all the kids into the single inline frame and
11358 : // bail.
11359 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
11360 0 : aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
11361 0 : return newFrame;
11362 : }
11363 :
11364 : // This inline frame contains several types of children. Therefore this frame
11365 : // has to be chopped into several pieces, as described above.
11366 :
11367 : // Grab the first inline's kids
11368 0 : nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
11369 0 : newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
11370 :
11371 0 : aFrameItems.AddChild(newFrame);
11372 :
11373 0 : newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
11374 0 : CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
11375 :
11376 0 : return newFrame;
11377 : }
11378 :
11379 : void
11380 0 : nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
11381 : nsContainerFrame* aInitialInline,
11382 : bool aIsPositioned,
11383 : nsFrameItems& aChildItems,
11384 : nsFrameItems& aSiblings)
11385 : {
11386 0 : nsIContent* content = aInitialInline->GetContent();
11387 0 : ComputedStyle* computedStyle = aInitialInline->Style();
11388 0 : nsContainerFrame* parentFrame = aInitialInline->GetParent();
11389 :
11390 : // Resolve the right style for our anonymous blocks.
11391 : //
11392 : // The distinction in styles is needed because of CSS 2.1, section
11393 : // 9.2.1.1, which says:
11394 : //
11395 : // When such an inline box is affected by relative positioning, any
11396 : // resulting translation also affects the block-level box contained
11397 : // in the inline box.
11398 0 : RefPtr<ComputedStyle> blockSC = mPresShell->StyleSet()->
11399 0 : ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
11400 0 : computedStyle);
11401 :
11402 : nsContainerFrame* lastNewInline =
11403 0 : static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
11404 0 : do {
11405 : // On entry to this loop aChildItems is not empty and the first frame in it
11406 : // is block-level.
11407 0 : MOZ_ASSERT(aChildItems.NotEmpty(), "Should have child items");
11408 0 : MOZ_ASSERT(!aChildItems.FirstChild()->IsInlineOutside(),
11409 : "Must have list starting with block");
11410 :
11411 : // The initial run of blocks belongs to an anonymous block that we create
11412 : // right now. The anonymous block will be the parent of these block
11413 : // children of the inline.
11414 0 : nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
11415 0 : InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
11416 :
11417 : // Find the first non-block child which defines the end of our block kids
11418 : // and the start of our next inline's kids
11419 : nsFrameList::FrameLinkEnumerator firstNonBlock =
11420 0 : FindFirstNonBlock(aChildItems);
11421 0 : nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock);
11422 :
11423 0 : MoveChildrenTo(aInitialInline, blockFrame, blockKids);
11424 :
11425 0 : SetFrameIsIBSplit(lastNewInline, blockFrame);
11426 0 : aSiblings.AddChild(blockFrame);
11427 :
11428 : // Now grab the initial inlines in aChildItems and put them into an inline
11429 : // frame.
11430 0 : nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
11431 0 : InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
11432 0 : inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11433 0 : if (aIsPositioned) {
11434 0 : inlineFrame->MarkAsAbsoluteContainingBlock();
11435 : }
11436 :
11437 0 : if (aChildItems.NotEmpty()) {
11438 0 : nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
11439 0 : FindFirstBlock(firstBlock);
11440 0 : nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
11441 :
11442 0 : MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
11443 : }
11444 :
11445 0 : SetFrameIsIBSplit(blockFrame, inlineFrame);
11446 0 : aSiblings.AddChild(inlineFrame);
11447 0 : lastNewInline = inlineFrame;
11448 0 : } while (aChildItems.NotEmpty());
11449 :
11450 0 : SetFrameIsIBSplit(lastNewInline, nullptr);
11451 0 : }
11452 :
11453 : void
11454 0 : nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
11455 : FrameConstructionItem& aParentItem,
11456 : bool aItemIsWithinSVGText,
11457 : bool aItemAllowsTextPathChild)
11458 : {
11459 : // XXXbz should we preallocate aParentItem.mChildItems to some sane
11460 : // length? Maybe even to parentContent->GetChildCount()?
11461 : nsFrameConstructorState::PendingBindingAutoPusher
11462 0 : pusher(aState, aParentItem.mPendingBinding);
11463 :
11464 0 : ComputedStyle* const parentComputedStyle = aParentItem.mComputedStyle;
11465 0 : nsIContent* const parentContent = aParentItem.mContent;
11466 :
11467 0 : if (!aItemIsWithinSVGText) {
11468 : // Probe for generated content before
11469 0 : CreateGeneratedContentItem(aState, nullptr, parentContent->AsElement(),
11470 : parentComputedStyle, CSSPseudoElementType::before,
11471 0 : aParentItem.mChildItems);
11472 : }
11473 :
11474 0 : uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
11475 0 : if (aItemIsWithinSVGText) {
11476 0 : flags |= ITEM_IS_WITHIN_SVG_TEXT;
11477 : }
11478 0 : if (aItemAllowsTextPathChild && aParentItem.mIsForSVGAElement) {
11479 0 : flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
11480 : }
11481 :
11482 0 : if (!aParentItem.mAnonChildren.IsEmpty()) {
11483 : // Use the anon-children list instead of the content tree child list so that
11484 : // we use any special style that should be associated with the children, and
11485 : // so that we won't try to construct grandchildren frame constructor items
11486 : // before the frame is available for their parent.
11487 0 : AddFCItemsForAnonymousContent(aState, nullptr, aParentItem.mAnonChildren,
11488 0 : aParentItem.mChildItems, flags);
11489 : } else {
11490 : // Use the content tree child list:
11491 0 : FlattenedChildIterator iter(parentContent);
11492 0 : for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
11493 : // Manually check for comments/PIs, since we don't have a frame to pass to
11494 : // AddFrameConstructionItems. We know our parent is a non-replaced inline,
11495 : // so there is no need to do the NeedFrameFor check.
11496 0 : content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
11497 0 : if (content->IsComment() || content->IsProcessingInstruction()) {
11498 0 : continue;
11499 : }
11500 :
11501 0 : RefPtr<ComputedStyle> childContext = ResolveComputedStyle(content);
11502 0 : AddFrameConstructionItemsInternal(aState, content, nullptr,
11503 0 : iter.XBLInvolved(), childContext,
11504 : flags, nullptr,
11505 0 : aParentItem.mChildItems);
11506 : }
11507 : }
11508 :
11509 0 : if (!aItemIsWithinSVGText) {
11510 : // Probe for generated content after
11511 0 : CreateGeneratedContentItem(aState, nullptr, parentContent->AsElement(),
11512 : parentComputedStyle,
11513 : CSSPseudoElementType::after,
11514 0 : aParentItem.mChildItems);
11515 : }
11516 :
11517 0 : aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
11518 0 : }
11519 :
11520 : // return whether it's ok to append (in the AppendFrames sense) to
11521 : // aParentFrame if our nextSibling is aNextSibling. aParentFrame must
11522 : // be an ib-split inline.
11523 : static bool
11524 0 : IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
11525 : {
11526 0 : MOZ_ASSERT(IsInlineFrame(aParentFrame), "Must have an inline parent here");
11527 :
11528 0 : do {
11529 0 : NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),
11530 : "How is this not part of an ib-split?");
11531 0 : if (aNextSibling || aParentFrame->GetNextContinuation() ||
11532 0 : GetIBSplitSibling(aParentFrame)) {
11533 : return false;
11534 : }
11535 :
11536 0 : aNextSibling = aParentFrame->GetNextSibling();
11537 0 : aParentFrame = aParentFrame->GetParent();
11538 : } while (IsInlineFrame(aParentFrame));
11539 :
11540 : return true;
11541 : }
11542 :
11543 : bool
11544 36 : nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
11545 : nsIFrame* aContainingBlock,
11546 : nsIFrame* aFrame,
11547 : FrameConstructionItemList& aItems,
11548 : bool aIsAppend,
11549 : nsIFrame* aPrevSibling)
11550 : {
11551 36 : if (aItems.IsEmpty()) {
11552 : return false;
11553 : }
11554 :
11555 : // Before we go and append the frames, we must check for several
11556 : // special situations.
11557 :
11558 : // Situation #1 is a XUL frame that contains frames that are required
11559 : // to be wrapped in blocks.
11560 51 : if (aFrame->IsXULBoxFrame() &&
11561 0 : !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
11562 11 : aItems.AnyItemsNeedBlockParent()) {
11563 0 : RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11564 0 : return true;
11565 : }
11566 :
11567 0 : nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
11568 :
11569 : // Situation #2 is a flex or grid container frame into which we're inserting
11570 : // new inline non-replaced children, adjacent to an existing anonymous
11571 : // flex or grid item.
11572 20 : LayoutFrameType frameType = aFrame->Type();
11573 0 : if (frameType == LayoutFrameType::FlexContainer ||
11574 0 : frameType == LayoutFrameType::GridContainer) {
11575 0 : FCItemIterator iter(aItems);
11576 :
11577 : // Check if we're adding to-be-wrapped content right *after* an existing
11578 : // anonymous flex or grid item (which would need to absorb this content).
11579 0 : const bool isLegacyBox = IsFlexContainerForLegacyBox(aFrame);
11580 0 : if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
11581 0 : iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
11582 0 : RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11583 0 : return true;
11584 : }
11585 :
11586 : // Check if we're adding to-be-wrapped content right *before* an existing
11587 : // anonymous flex or grid item (which would need to absorb this content).
11588 0 : if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
11589 : // Jump to the last entry in the list
11590 0 : iter.SetToEnd();
11591 0 : iter.Prev();
11592 0 : if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
11593 0 : RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11594 0 : return true;
11595 : }
11596 : }
11597 : }
11598 :
11599 : // Situation #3 is an anonymous flex or grid item that's getting new children
11600 : // who don't want to be wrapped.
11601 20 : if (IsAnonymousFlexOrGridItem(aFrame)) {
11602 0 : AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
11603 :
11604 : // We need to push a null float containing block to be sure that
11605 : // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
11606 : // inserted content. (In particular, this is necessary in order for
11607 : // its "GetGeometricParent" call to return the correct result.)
11608 : // We're not honoring floats on this content because it has the
11609 : // _flex/grid container_ as its parent in the content tree.
11610 0 : nsFrameConstructorSaveState floatSaveState;
11611 0 : aState.PushFloatContainingBlock(nullptr, floatSaveState);
11612 :
11613 0 : FCItemIterator iter(aItems);
11614 : // Skip over things that _do_ need an anonymous flex item, because
11615 : // they're perfectly happy to go here -- they won't cause a reframe.
11616 0 : nsIFrame* containerFrame = aFrame->GetParent();
11617 0 : const bool isLegacyBox = IsFlexContainerForLegacyBox(containerFrame);
11618 0 : if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
11619 : // We hit something that _doesn't_ need an anonymous flex item!
11620 : // Rebuild the flex container to bust it out.
11621 0 : RecreateFramesForContent(containerFrame->GetContent(), InsertionKind::Async);
11622 0 : return true;
11623 : }
11624 :
11625 : // If we get here, then everything in |aItems| needs to be wrapped in
11626 : // an anonymous flex or grid item. That's where it's already going - good!
11627 : }
11628 :
11629 : // Situation #4 is a ruby-related frame that's getting new children.
11630 : // The situation for ruby is complex, especially when interacting with
11631 : // spaces. It containes these two special cases apart from tables:
11632 : // 1) There are effectively three types of white spaces in ruby frames
11633 : // we handle differently: leading/tailing/inter-level space,
11634 : // inter-base/inter-annotation space, and inter-segment space.
11635 : // These three types of spaces can be converted to each other when
11636 : // their sibling changes.
11637 : // 2) The first effective child of a ruby frame must always be a ruby
11638 : // base container. It should be created or destroyed accordingly.
11639 0 : if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
11640 20 : RubyUtils::IsRubyContainerBox(frameType)) {
11641 : // We want to optimize it better, and avoid reframing as much as
11642 : // possible. But given the cases above, and the fact that a ruby
11643 : // usually won't be very large, it should be fine to reframe it.
11644 0 : RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11645 0 : return true;
11646 : }
11647 :
11648 : // Situation #5 is a case when table pseudo-frames don't work out right
11649 20 : ParentType parentType = GetParentType(aFrame);
11650 : // If all the kids want a parent of the type that aFrame is, then we're all
11651 : // set to go. Indeed, there won't be any table pseudo-frames created between
11652 : // aFrame and the kids, so those won't need to be merged with any table
11653 : // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
11654 : // table pseudo-frame, then all the kids in this list would have wanted a
11655 : // frame of that type wrapping them anyway, so putting them inside it is ok.
11656 20 : if (!aItems.AllWantParentType(parentType)) {
11657 : // Don't give up yet. If parentType is not eTypeBlock and the parent is
11658 : // not a generated content frame, then try filtering whitespace out of the
11659 : // list.
11660 0 : if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
11661 : // For leading whitespace followed by a kid that wants our parent type,
11662 : // there are four cases:
11663 : // 1) We have a previous sibling which is not a table pseudo. That means
11664 : // that previous sibling wanted a (non-block) parent of the type we're
11665 : // looking at. Then the whitespace comes between two table-internal
11666 : // elements, so should be collapsed out.
11667 : // 2) We have a previous sibling which is a table pseudo. It might have
11668 : // kids who want this whitespace, so we need to reframe.
11669 : // 3) We have no previous sibling and our parent frame is not a table
11670 : // pseudo. That means that we'll be at the beginning of our actual
11671 : // non-block-type parent, and the whitespace is OK to collapse out.
11672 : // If something is ever inserted before us, it'll find our own parent
11673 : // as its parent and if it's something that would care about the
11674 : // whitespace it'll want a block parent, so it'll trigger a reframe at
11675 : // that point.
11676 : // 4) We have no previous sibling and our parent frame is a table pseudo.
11677 : // Need to reframe.
11678 : // All that is predicated on finding the correct previous sibling. We
11679 : // might have to walk backwards along continuations from aFrame to do so.
11680 : //
11681 : // It's always OK to drop whitespace between any two items that want a
11682 : // parent of type parentType.
11683 : //
11684 : // For trailing whitespace preceded by a kid that wants our parent type,
11685 : // there are four cases:
11686 : // 1) We have a next sibling which is not a table pseudo. That means
11687 : // that next sibling wanted a (non-block) parent of the type we're
11688 : // looking at. Then the whitespace comes between two table-internal
11689 : // elements, so should be collapsed out.
11690 : // 2) We have a next sibling which is a table pseudo. It might have
11691 : // kids who want this whitespace, so we need to reframe.
11692 : // 3) We have no next sibling and our parent frame is not a table
11693 : // pseudo. That means that we'll be at the end of our actual
11694 : // non-block-type parent, and the whitespace is OK to collapse out.
11695 : // If something is ever inserted after us, it'll find our own parent
11696 : // as its parent and if it's something that would care about the
11697 : // whitespace it'll want a block parent, so it'll trigger a reframe at
11698 : // that point.
11699 : // 4) We have no next sibling and our parent frame is a table pseudo.
11700 : // Need to reframe.
11701 : // All that is predicated on finding the correct next sibling. We might
11702 : // have to walk forward along continuations from aFrame to do so. That
11703 : // said, in the case when nextSibling is null at this point and aIsAppend
11704 : // is true, we know we're in case 3. Furthermore, in that case we don't
11705 : // even have to worry about the table pseudo situation; we know our
11706 : // parent is not a table pseudo there.
11707 0 : FCItemIterator iter(aItems);
11708 : FCItemIterator start(iter);
11709 0 : do {
11710 0 : if (iter.SkipItemsWantingParentType(parentType)) {
11711 : break;
11712 : }
11713 :
11714 : // iter points to an item that wants a different parent. If it's not
11715 : // whitespace, we're done; no more point scanning the list.
11716 0 : if (!iter.item().IsWhitespace(aState)) {
11717 : break;
11718 : }
11719 :
11720 0 : if (iter == start) {
11721 : // Leading whitespace. How to handle this depends on our
11722 : // previous sibling and aFrame. See the long comment above.
11723 0 : nsIFrame* prevSibling = aPrevSibling;
11724 0 : if (!prevSibling) {
11725 : // Try to find one after all
11726 0 : nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
11727 0 : while (parentPrevCont) {
11728 0 : prevSibling = parentPrevCont->GetChildList(kPrincipalList).LastChild();
11729 0 : if (prevSibling) {
11730 : break;
11731 : }
11732 0 : parentPrevCont = parentPrevCont->GetPrevContinuation();
11733 : }
11734 : };
11735 0 : if (prevSibling) {
11736 0 : if (IsTablePseudo(prevSibling)) {
11737 : // need to reframe
11738 : break;
11739 : }
11740 0 : } else if (IsTablePseudo(aFrame)) {
11741 : // need to reframe
11742 : break;
11743 : }
11744 : }
11745 :
11746 0 : FCItemIterator spaceEndIter(iter);
11747 : // Advance spaceEndIter past any whitespace
11748 0 : bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
11749 :
11750 : bool okToDrop;
11751 0 : if (trailingSpaces) {
11752 : // Trailing whitespace. How to handle this depeds on aIsAppend, our
11753 : // next sibling and aFrame. See the long comment above.
11754 0 : okToDrop = aIsAppend && !nextSibling;
11755 0 : if (!okToDrop) {
11756 0 : if (!nextSibling) {
11757 : // Try to find one after all
11758 0 : nsIFrame* parentNextCont = aFrame->GetNextContinuation();
11759 0 : while (parentNextCont) {
11760 0 : nextSibling = parentNextCont->PrincipalChildList().FirstChild();
11761 0 : if (nextSibling) {
11762 : break;
11763 : }
11764 0 : parentNextCont = parentNextCont->GetNextContinuation();
11765 : }
11766 : }
11767 :
11768 0 : okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
11769 0 : (!nextSibling && !IsTablePseudo(aFrame));
11770 : }
11771 : #ifdef DEBUG
11772 : else {
11773 0 : NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
11774 : }
11775 : #endif
11776 : } else {
11777 0 : okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
11778 : }
11779 :
11780 0 : if (okToDrop) {
11781 0 : iter.DeleteItemsTo(this, spaceEndIter);
11782 : } else {
11783 : // We're done: we don't want to drop the whitespace, and it has the
11784 : // wrong parent type.
11785 : break;
11786 : }
11787 :
11788 : // Now loop, since |iter| points to item right after the whitespace we
11789 : // removed.
11790 0 : } while (!iter.IsDone());
11791 : }
11792 :
11793 : // We might be able to figure out some sort of optimizations here, but they
11794 : // would have to depend on having a correct aPrevSibling and a correct next
11795 : // sibling. For example, we can probably avoid reframing if none of
11796 : // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
11797 : // doesn't seem worth it to worry about that for now, especially since we
11798 : // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11799 : // this method.
11800 :
11801 : // aItems might have changed, so recheck the parent type thing. In fact,
11802 : // it might be empty, so recheck that too.
11803 0 : if (aItems.IsEmpty()) {
11804 : return false;
11805 : }
11806 :
11807 0 : if (!aItems.AllWantParentType(parentType)) {
11808 : // Reframing aFrame->GetContent() is good enough, since the content of
11809 : // table pseudo-frames is the ancestor content.
11810 0 : RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11811 0 : return true;
11812 : }
11813 : }
11814 :
11815 : // Now we have several cases involving {ib} splits. Put them all in a
11816 : // do/while with breaks to take us to the "go and reconstruct" code.
11817 : do {
11818 0 : if (IsInlineFrame(aFrame)) {
11819 0 : if (aItems.AreAllItemsInline()) {
11820 : // We can just put the kids in.
11821 : return false;
11822 : }
11823 :
11824 0 : if (!IsFramePartOfIBSplit(aFrame)) {
11825 : // Need to go ahead and reconstruct.
11826 : break;
11827 : }
11828 :
11829 : // Now we're adding kids including some blocks to an inline part of an
11830 : // {ib} split. If we plan to call AppendFrames, and don't have a next
11831 : // sibling for the new frames, and our parent is the last continuation of
11832 : // the last part of the {ib} split, and the same is true of all our
11833 : // ancestor inlines (they have no following continuations and they're the
11834 : // last part of their {ib} splits and we'd be adding to the end for all
11835 : // of them), then AppendFrames will handle things for us. Bail out in
11836 : // that case.
11837 0 : if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
11838 : return false;
11839 : }
11840 :
11841 : // Need to reconstruct.
11842 : break;
11843 : }
11844 :
11845 : // Now we know we have a block parent. If it's not part of an
11846 : // ib-split, we're all set.
11847 0 : if (!IsFramePartOfIBSplit(aFrame)) {
11848 : return false;
11849 : }
11850 :
11851 : // We're adding some kids to a block part of an {ib} split. If all the
11852 : // kids are blocks, we don't need to reconstruct.
11853 0 : if (aItems.AreAllItemsBlock()) {
11854 : return false;
11855 : }
11856 :
11857 : // We might have some inline kids for this block. Just fall out of the
11858 : // loop and reconstruct.
11859 : } while (0);
11860 :
11861 : // If we don't have a containing block, start with aFrame and look for one.
11862 0 : if (!aContainingBlock) {
11863 0 : aContainingBlock = aFrame;
11864 : }
11865 :
11866 : // To find the right block to reframe, just walk up the tree until we find a
11867 : // frame that is:
11868 : // 1) Not part of an IB split
11869 : // 2) Not a pseudo-frame
11870 : // 3) Not an inline frame
11871 : // We're guaranteed to find one, since ComputedStyle::ApplyStyleFixups
11872 : // enforces that the root is display:none, display:table, or display:block.
11873 : // Note that walking up "too far" is OK in terms of correctness, even if it
11874 : // might be a little inefficient. This is why we walk out of all
11875 : // pseudo-frames -- telling which ones are or are not OK to walk out of is
11876 : // too hard (and I suspect that we do in fact need to walk out of all of
11877 : // them).
11878 0 : while (IsFramePartOfIBSplit(aContainingBlock) ||
11879 0 : aContainingBlock->IsInlineOutside() ||
11880 0 : aContainingBlock->Style()->GetPseudo()) {
11881 0 : aContainingBlock = aContainingBlock->GetParent();
11882 0 : NS_ASSERTION(aContainingBlock,
11883 : "Must have non-inline, non-ib-split, non-pseudo frame as "
11884 : "root (or child of root, for a table root)!");
11885 : }
11886 :
11887 : // Tell parent of the containing block to reformulate the
11888 : // entire block. This is painful and definitely not optimal
11889 : // but it will *always* get the right answer.
11890 :
11891 0 : nsIContent* blockContent = aContainingBlock->GetContent();
11892 : #ifdef DEBUG
11893 0 : if (gNoisyContentUpdates) {
11894 : printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
11895 : blockContent);
11896 : }
11897 : #endif
11898 0 : RecreateFramesForContent(blockContent, InsertionKind::Async);
11899 0 : return true;
11900 : }
11901 :
11902 : void
11903 0 : nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
11904 : {
11905 :
11906 : #ifdef DEBUG
11907 : // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
11908 : // so I want to see when it is happening! Unfortunately, it is happening way to often because
11909 : // so much content on the web causes block-in-inline frame situations and we handle them
11910 : // very poorly
11911 0 : if (gNoisyContentUpdates) {
11912 : printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
11913 : aFrame);
11914 : }
11915 : #endif
11916 :
11917 : // XXXbz how exactly would we get here while isReflowing anyway? Should this
11918 : // whole test be ifdef DEBUG?
11919 0 : if (mPresShell->IsReflowLocked()) {
11920 : // don't ReframeContainingBlock, this will result in a crash
11921 : // if we remove a tree that's in reflow - see bug 121368 for testcase
11922 0 : NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
11923 : return;
11924 : }
11925 :
11926 : // Get the first "normal" ancestor of the target frame.
11927 0 : nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
11928 0 : if (containingBlock) {
11929 : // From here we look for the containing block in case the target
11930 : // frame is already a block (which can happen when an inline frame
11931 : // wraps some of its content in an anonymous block; see
11932 : // ConstructInline)
11933 :
11934 : // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
11935 : // GetIBContainingBlock works much better and provides the correct container in all cases
11936 : // so GetFloatContainingBlock(aFrame) has been removed
11937 :
11938 : // And get the containingBlock's content
11939 0 : if (nsIContent* blockContent = containingBlock->GetContent()) {
11940 : #ifdef DEBUG
11941 0 : if (gNoisyContentUpdates) {
11942 : printf(" ==> blockContent=%p\n", blockContent);
11943 : }
11944 : #endif
11945 0 : RecreateFramesForContent(blockContent->AsElement(), InsertionKind::Async);
11946 0 : return;
11947 : }
11948 : }
11949 :
11950 : // If we get here, we're screwed!
11951 0 : RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11952 0 : InsertionKind::Async);
11953 : }
11954 :
11955 : void
11956 0 : nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
11957 : {
11958 : {
11959 0 : nsAutoScriptBlocker scriptBlocker;
11960 0 : nsFrameItems childItems;
11961 0 : nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
11962 : // We don't have a parent frame with a pending binding constructor here,
11963 : // so no need to worry about ordering of the kids' constructors with it.
11964 : // Pass null for the PendingBinding.
11965 0 : ProcessChildren(state, aFrame->GetContent(), aFrame->Style(),
11966 : aFrame, false, childItems, false,
11967 0 : nullptr);
11968 :
11969 0 : aFrame->SetInitialChildList(kPrincipalList, childItems);
11970 : }
11971 :
11972 : #ifdef ACCESSIBILITY
11973 0 : if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
11974 0 : if (nsIContent* child = aFrame->GetContent()->GetFirstChild()) {
11975 0 : accService->ContentRangeInserted(mPresShell, child, nullptr);
11976 : }
11977 : }
11978 : #endif
11979 :
11980 : // call XBL constructors after the frames are created
11981 0 : mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
11982 0 : }
11983 :
11984 : //////////////////////////////////////////////////////////
11985 : // nsCSSFrameConstructor::FrameConstructionItem methods //
11986 : //////////////////////////////////////////////////////////
11987 : bool
11988 6 : nsCSSFrameConstructor::
11989 : FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const
11990 : {
11991 0 : MOZ_ASSERT(aState.mCreatingExtraFrames ||
11992 : !mContent->GetPrimaryFrame(), "How did that happen?");
11993 6 : if (!mIsText) {
11994 : return false;
11995 : }
11996 6 : mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11997 6 : NS_REFRAME_IF_WHITESPACE);
11998 6 : return mContent->TextIsOnlyWhitespace();
11999 : }
12000 :
12001 : //////////////////////////////////////////////////////////////
12002 : // nsCSSFrameConstructor::FrameConstructionItemList methods //
12003 : //////////////////////////////////////////////////////////////
12004 : void
12005 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12006 : AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta)
12007 : {
12008 0 : MOZ_ASSERT(aDelta == 1 || aDelta == -1, "Unexpected delta");
12009 0 : mItemCount += aDelta;
12010 0 : if (aItem->mIsAllInline) {
12011 0 : mInlineCount += aDelta;
12012 : }
12013 0 : if (aItem->mIsBlock) {
12014 0 : mBlockCount += aDelta;
12015 : }
12016 0 : if (aItem->mIsLineParticipant) {
12017 0 : mLineParticipantCount += aDelta;
12018 : }
12019 0 : mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
12020 0 : }
12021 :
12022 : ////////////////////////////////////////////////////////////////////////
12023 : // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
12024 : ////////////////////////////////////////////////////////////////////////
12025 : inline bool
12026 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12027 : Iterator::SkipItemsWantingParentType(ParentType aParentType)
12028 : {
12029 0 : MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
12030 0 : while (item().DesiredParentType() == aParentType) {
12031 0 : Next();
12032 0 : if (IsDone()) {
12033 : return true;
12034 : }
12035 : }
12036 : return false;
12037 : }
12038 :
12039 : inline bool
12040 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12041 : Iterator::SkipItemsNotWantingParentType(ParentType aParentType)
12042 : {
12043 0 : MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
12044 0 : while (item().DesiredParentType() != aParentType) {
12045 0 : Next();
12046 0 : if (IsDone()) {
12047 : return true;
12048 : }
12049 : }
12050 : return false;
12051 : }
12052 :
12053 : // Note: we implement -webkit-{inline-}box (and optionally -moz-{inline-}box)
12054 : // using nsFlexContainerFrame, but we use different rules for what gets wrapped
12055 : // in an anonymous flex item.
12056 : bool
12057 0 : nsCSSFrameConstructor::FrameConstructionItem::
12058 : NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
12059 : bool aIsLegacyBox)
12060 : {
12061 0 : if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
12062 : // This will be an inline non-replaced box.
12063 : return true;
12064 : }
12065 :
12066 0 : if (aIsLegacyBox) {
12067 0 : if (mComputedStyle->StyleDisplay()->IsInlineOutsideStyle()) {
12068 : // In an emulated legacy box, all inline-level content gets wrapped in an
12069 : // anonymous flex item.
12070 : return true;
12071 : }
12072 0 : if (mIsPopup ||
12073 0 : (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
12074 0 : aState.GetGeometricParent(mComputedStyle->StyleDisplay(), nullptr))) {
12075 : // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
12076 : // placeholder which (because our container is an emulated legacy box)
12077 : // we'll need to wrap in an anonymous flex item. So, we just treat
12078 : // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
12079 : // and then when we spawn the placeholder, it'll end up in the right
12080 : // spot.
12081 : return true;
12082 : }
12083 : }
12084 :
12085 : return false;
12086 : }
12087 :
12088 : inline bool
12089 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12090 : Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
12091 : const nsFrameConstructorState& aState,
12092 : bool aIsLegacyBox)
12093 : {
12094 0 : MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
12095 0 : while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyBox)) {
12096 0 : Next();
12097 0 : if (IsDone()) {
12098 : return true;
12099 : }
12100 : }
12101 : return false;
12102 : }
12103 :
12104 : inline bool
12105 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12106 : Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
12107 : const nsFrameConstructorState& aState,
12108 : bool aIsLegacyBox)
12109 : {
12110 0 : MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
12111 0 : while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyBox))) {
12112 0 : Next();
12113 0 : if (IsDone()) {
12114 : return true;
12115 : }
12116 : }
12117 : return false;
12118 : }
12119 :
12120 : inline bool
12121 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12122 : Iterator::SkipItemsNotWantingRubyParent()
12123 : {
12124 0 : MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
12125 0 : while (!IsRubyParentType(item().DesiredParentType())) {
12126 0 : Next();
12127 0 : if (IsDone()) {
12128 : return true;
12129 : }
12130 : }
12131 : return false;
12132 : }
12133 :
12134 : inline bool
12135 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12136 : Iterator::SkipWhitespace(nsFrameConstructorState& aState)
12137 : {
12138 0 : MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
12139 0 : MOZ_ASSERT(item().IsWhitespace(aState), "Not pointing to whitespace?");
12140 0 : do {
12141 0 : Next();
12142 0 : if (IsDone()) {
12143 : return true;
12144 : }
12145 0 : } while (item().IsWhitespace(aState));
12146 :
12147 : return false;
12148 : }
12149 :
12150 : void
12151 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12152 : Iterator::AppendItemToList(FrameConstructionItemList& aTargetList)
12153 : {
12154 0 : NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
12155 0 : MOZ_ASSERT(!IsDone(), "should not be done");
12156 :
12157 0 : FrameConstructionItem* item = mCurrent;
12158 0 : Next();
12159 0 : item->remove();
12160 0 : aTargetList.mItems.insertBack(item);
12161 :
12162 0 : mList.AdjustCountsForItem(item, -1);
12163 0 : aTargetList.AdjustCountsForItem(item, 1);
12164 0 : }
12165 :
12166 : void
12167 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12168 : Iterator::AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
12169 : FrameConstructionItemList& aTargetList)
12170 : {
12171 0 : NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
12172 0 : MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?");
12173 :
12174 : // We can't just move our guts to the other list if it already has
12175 : // some information or if we're not moving our entire list.
12176 0 : if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
12177 0 : do {
12178 0 : AppendItemToList(aTargetList);
12179 : } while (*this != aEnd);
12180 : return;
12181 : }
12182 :
12183 : // Move our entire list of items into the empty target list.
12184 0 : aTargetList.mItems = std::move(mList.mItems);
12185 :
12186 : // Copy over the various counters
12187 0 : aTargetList.mInlineCount = mList.mInlineCount;
12188 0 : aTargetList.mBlockCount = mList.mBlockCount;
12189 0 : aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
12190 0 : aTargetList.mItemCount = mList.mItemCount;
12191 0 : memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
12192 0 : sizeof(aTargetList.mDesiredParentCounts));
12193 :
12194 : // reset mList
12195 0 : mList.Reset(aFCtor);
12196 :
12197 : // Point ourselves to aEnd, as advertised
12198 0 : SetToEnd();
12199 0 : MOZ_ASSERT(*this == aEnd, "How did that happen?");
12200 : }
12201 :
12202 : void
12203 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12204 : Iterator::InsertItem(FrameConstructionItem* aItem)
12205 : {
12206 0 : if (IsDone()) {
12207 0 : mList.mItems.insertBack(aItem);
12208 : } else {
12209 : // Just insert the item before us. There's no magic here.
12210 0 : mCurrent->setPrevious(aItem);
12211 : }
12212 0 : mList.AdjustCountsForItem(aItem, 1);
12213 :
12214 0 : MOZ_ASSERT(aItem->getNext() == mCurrent, "How did that happen?");
12215 0 : }
12216 :
12217 : void
12218 0 : nsCSSFrameConstructor::FrameConstructionItemList::
12219 : Iterator::DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd)
12220 : {
12221 0 : MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?");
12222 0 : MOZ_ASSERT(*this != aEnd, "Shouldn't be at aEnd yet");
12223 :
12224 0 : do {
12225 0 : NS_ASSERTION(!IsDone(), "Ran off end of list?");
12226 0 : FrameConstructionItem* item = mCurrent;
12227 0 : Next();
12228 0 : item->remove();
12229 0 : mList.AdjustCountsForItem(item, -1);
12230 0 : item->Delete(aFCtor);
12231 : } while (*this != aEnd);
12232 0 : }
12233 :
12234 : void
12235 0 : nsCSSFrameConstructor::QuotesDirty()
12236 : {
12237 0 : mQuotesDirty = true;
12238 0 : mPresShell->SetNeedLayoutFlush();
12239 0 : }
12240 :
12241 : void
12242 0 : nsCSSFrameConstructor::CountersDirty()
12243 : {
12244 0 : mCountersDirty = true;
12245 0 : mPresShell->SetNeedLayoutFlush();
12246 0 : }
12247 :
12248 : void*
12249 285 : nsCSSFrameConstructor::AllocateFCItem()
12250 : {
12251 : void* item;
12252 0 : if (mFirstFreeFCItem) {
12253 0 : item = mFirstFreeFCItem;
12254 147 : mFirstFreeFCItem = mFirstFreeFCItem->mNext;
12255 : } else {
12256 138 : item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
12257 : }
12258 285 : ++mFCItemsInUse;
12259 0 : return item;
12260 : }
12261 :
12262 : void
12263 0 : nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem)
12264 : {
12265 285 : MOZ_ASSERT(mFCItemsInUse != 0);
12266 0 : if (--mFCItemsInUse == 0) {
12267 : // The arena is now unused - clear it but retain one chunk.
12268 0 : mFirstFreeFCItem = nullptr;
12269 42 : mFCItemPool.Clear();
12270 : } else {
12271 : // Prepend it to the list of free items.
12272 243 : FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
12273 0 : item->mNext = mFirstFreeFCItem;
12274 243 : mFirstFreeFCItem = item;
12275 : }
12276 0 : }
12277 :
12278 : void
12279 13 : nsCSSFrameConstructor::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
12280 : {
12281 13 : if (nsIFrame* rootFrame = GetRootFrame()) {
12282 0 : rootFrame->AddSizeOfExcludingThisForTree(aSizes);
12283 : }
12284 :
12285 : // This must be done after measuring from the frame tree, since frame
12286 : // manager will measure sizes of staled computed values and style
12287 : // structs, which only make sense after we know what are being used.
12288 13 : nsFrameManager::AddSizeOfIncludingThis(aSizes);
12289 :
12290 : // Measurement of the following members may be added later if DMD finds it
12291 : // is worthwhile:
12292 : // - mFCItemPool
12293 : // - mQuoteList
12294 : // - mCounterManager
12295 : }
|