Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/base/nsCSSFrameConstructor.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/*
8
 * construction of a frame tree that is nearly isomorphic to the content
9
 * tree and updating of that tree in response to dynamic changes
10
 */
11
12
#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/GeneratedImageContent.h"
19
#include "mozilla/dom/HTMLDetailsElement.h"
20
#include "mozilla/dom/HTMLSelectElement.h"
21
#include "mozilla/dom/HTMLSummaryElement.h"
22
#include "mozilla/EventStates.h"
23
#include "mozilla/Likely.h"
24
#include "mozilla/LinkedList.h"
25
#include "mozilla/MemoryReporting.h"
26
#include "mozilla/PresShell.h"
27
#include "mozilla/ServoBindings.h"
28
#include "mozilla/ServoStyleSetInlines.h"
29
#include "mozilla/StaticPrefs.h"
30
#include "nsAbsoluteContainingBlock.h"
31
#include "nsCSSPseudoElements.h"
32
#include "nsAtom.h"
33
#include "nsIFrameInlines.h"
34
#include "nsGkAtoms.h"
35
#include "nsPresContext.h"
36
#include "nsIDocument.h"
37
#include "nsIDocumentInlines.h"
38
#include "nsTableFrame.h"
39
#include "nsTableColFrame.h"
40
#include "nsTableRowFrame.h"
41
#include "nsTableCellFrame.h"
42
#include "nsHTMLParts.h"
43
#include "nsIPresShell.h"
44
#include "nsUnicharUtils.h"
45
#include "nsViewManager.h"
46
#include "nsStyleConsts.h"
47
#ifdef MOZ_XUL
48
#include "nsXULElement.h"
49
#include "mozilla/dom/BoxObject.h"
50
#endif // MOZ_XUL
51
#include "nsContainerFrame.h"
52
#include "nsNameSpaceManager.h"
53
#include "nsIComboboxControlFrame.h"
54
#include "nsComboboxControlFrame.h"
55
#include "nsIListControlFrame.h"
56
#include "nsPlaceholderFrame.h"
57
#include "nsTableRowGroupFrame.h"
58
#include "nsIFormControl.h"
59
#include "nsCSSAnonBoxes.h"
60
#include "nsTextFragment.h"
61
#include "nsIAnonymousContentCreator.h"
62
#include "nsBindingManager.h"
63
#include "nsXBLBinding.h"
64
#include "nsContentUtils.h"
65
#include "nsIScriptError.h"
66
#ifdef XP_MACOSX
67
#include "nsIDocShell.h"
68
#endif
69
#include "ChildIterator.h"
70
#include "nsError.h"
71
#include "nsLayoutUtils.h"
72
#include "nsAutoPtr.h"
73
#include "nsBoxFrame.h"
74
#include "nsBoxLayout.h"
75
#include "nsFlexContainerFrame.h"
76
#include "nsGridContainerFrame.h"
77
#include "RubyUtils.h"
78
#include "nsRubyFrame.h"
79
#include "nsRubyBaseFrame.h"
80
#include "nsRubyBaseContainerFrame.h"
81
#include "nsRubyTextFrame.h"
82
#include "nsRubyTextContainerFrame.h"
83
#include "nsImageFrame.h"
84
#include "nsIObjectLoadingContent.h"
85
#include "nsTArray.h"
86
#include "mozilla/dom/CharacterData.h"
87
#include "mozilla/dom/Element.h"
88
#include "mozilla/dom/ElementInlines.h"
89
#include "mozilla/dom/HTMLInputElement.h"
90
#include "nsAutoLayoutPhase.h"
91
#include "nsStyleStructInlines.h"
92
#include "nsPageContentFrame.h"
93
#include "mozilla/RestyleManager.h"
94
#include "StickyScrollContainer.h"
95
#include "nsFieldSetFrame.h"
96
#include "nsInlineFrame.h"
97
#include "nsBlockFrame.h"
98
#include "nsCanvasFrame.h"
99
#include "nsFirstLetterFrame.h"
100
#include "nsGfxScrollFrame.h"
101
#include "nsPageFrame.h"
102
#include "nsSimplePageSequenceFrame.h"
103
#include "nsTableWrapperFrame.h"
104
#include "nsIScrollableFrame.h"
105
#include "nsBackdropFrame.h"
106
#include "nsTransitionManager.h"
107
#include "DetailsFrame.h"
108
#include "nsStyleConsts.h"
109
110
#ifdef MOZ_XUL
111
#include "nsIPopupContainer.h"
112
#endif
113
#ifdef ACCESSIBILITY
114
#include "nsAccessibilityService.h"
115
#endif
116
117
#include "nsXBLService.h"
118
119
#undef NOISY_FIRST_LETTER
120
121
#include "nsMathMLParts.h"
122
#include "mozilla/dom/SVGTests.h"
123
#include "nsSVGUtils.h"
124
125
#include "nsRefreshDriver.h"
126
#include "nsTextNode.h"
127
#include "ActiveLayerTracker.h"
128
#include "nsIPresShellInlines.h"
129
130
using namespace mozilla;
131
using namespace mozilla::dom;
132
133
// An alias for convenience.
134
static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
135
136
nsIFrame*
137
NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
138
139
nsIFrame*
140
NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
141
142
nsContainerFrame*
143
NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
144
nsContainerFrame*
145
NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
146
nsIFrame*
147
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
148
nsIFrame*
149
NS_NewSVGGeometryFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
150
nsIFrame*
151
NS_NewSVGGFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
152
nsIFrame*
153
NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
154
nsContainerFrame*
155
NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
156
nsIFrame*
157
NS_NewSVGAFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
158
nsIFrame*
159
NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
160
nsIFrame*
161
NS_NewSVGSymbolFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
162
nsIFrame*
163
NS_NewSVGTextFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
164
nsIFrame*
165
NS_NewSVGContainerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
166
nsIFrame*
167
NS_NewSVGUseFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
168
nsIFrame*
169
NS_NewSVGViewFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
170
extern nsIFrame*
171
NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
172
extern nsIFrame*
173
NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
174
extern nsIFrame*
175
NS_NewSVGStopFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
176
nsContainerFrame*
177
NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
178
nsContainerFrame*
179
NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
180
extern nsIFrame*
181
NS_NewSVGImageFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
182
nsIFrame*
183
NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
184
nsIFrame*
185
NS_NewSVGFilterFrame(nsIPresShell *aPresShell, ComputedStyle* aStyle);
186
nsIFrame*
187
NS_NewSVGPatternFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
188
nsIFrame*
189
NS_NewSVGMaskFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
190
nsIFrame*
191
NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
192
nsIFrame*
193
NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
194
nsIFrame*
195
NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
196
nsIFrame*
197
NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
198
199
#include "mozilla/dom/NodeInfo.h"
200
#include "prenv.h"
201
#include "nsNodeInfoManager.h"
202
#include "nsContentCreatorFunctions.h"
203
204
#ifdef DEBUG
205
// Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
206
// more of the following flags (comma separated) for handy debug
207
// output.
208
static bool gNoisyContentUpdates = false;
209
static bool gReallyNoisyContentUpdates = false;
210
static bool gNoisyInlineConstruction = false;
211
212
struct FrameCtorDebugFlags {
213
  const char* name;
214
  bool* on;
215
};
216
217
static FrameCtorDebugFlags gFlags[] = {
218
  { "content-updates",              &gNoisyContentUpdates },
219
  { "really-noisy-content-updates", &gReallyNoisyContentUpdates },
220
  { "noisy-inline",                 &gNoisyInlineConstruction }
221
};
222
223
#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
224
#endif
225
226
227
#ifdef MOZ_XUL
228
#include "nsMenuFrame.h"
229
#include "nsPopupSetFrame.h"
230
#include "nsTreeColFrame.h"
231
#include "nsIBoxObject.h"
232
#include "nsXULLabelFrame.h"
233
234
//------------------------------------------------------------------
235
236
nsContainerFrame*
237
NS_NewRootBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
238
239
nsContainerFrame*
240
NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
241
242
nsIFrame*
243
NS_NewDeckFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
244
245
nsIFrame*
246
NS_NewLeafBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
247
248
nsIFrame*
249
NS_NewStackFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
250
251
nsIFrame*
252
NS_NewProgressMeterFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
253
254
nsIFrame*
255
NS_NewRangeFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
256
257
nsIFrame*
258
NS_NewImageBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
259
260
nsIFrame*
261
NS_NewTextBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
262
263
nsIFrame*
264
NS_NewGroupBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
265
266
nsIFrame*
267
NS_NewButtonBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
268
269
nsIFrame*
270
NS_NewSplitterFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
271
272
nsIFrame*
273
NS_NewMenuPopupFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
274
275
nsIFrame*
276
NS_NewPopupSetFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
277
278
nsIFrame*
279
NS_NewMenuFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle, uint32_t aFlags);
280
281
nsIFrame*
282
NS_NewMenuBarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
283
284
nsIFrame*
285
NS_NewTreeBodyFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
286
287
// grid
288
nsresult
289
NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsBoxLayout** aNewLayout );
290
nsIFrame*
291
NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
292
nsIFrame*
293
NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
294
295
// end grid
296
297
nsIFrame*
298
NS_NewTitleBarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
299
300
nsIFrame*
301
NS_NewResizerFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
302
303
304
#endif
305
306
nsHTMLScrollFrame*
307
NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle, bool aIsRoot);
308
309
nsXULScrollFrame*
310
NS_NewXULScrollFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle,
311
                     bool aIsRoot, bool aClipAllDescendants);
312
313
nsIFrame*
314
NS_NewSliderFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
315
316
nsIFrame*
317
NS_NewScrollbarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
318
319
nsIFrame*
320
NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
321
322
nsIFrame*
323
NS_NewImageFrameForContentProperty(nsIPresShell*, ComputedStyle*);
324
325
nsIFrame*
326
NS_NewImageFrameForGeneratedContentIndex(nsIPresShell*, ComputedStyle*);
327
328
329
#ifdef NOISY_FINDFRAME
330
static int32_t FFWC_totalCount=0;
331
static int32_t FFWC_doLoop=0;
332
static int32_t FFWC_doSibling=0;
333
static int32_t FFWC_recursions=0;
334
static int32_t FFWC_nextInFlows=0;
335
#endif
336
337
// Returns true if aFrame is an anonymous flex/grid item.
338
static inline bool
339
IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
340
0
{
341
0
  const nsAtom* pseudoType = aFrame->Style()->GetPseudo();
342
0
  return pseudoType == nsCSSAnonBoxes::anonymousFlexItem() ||
343
0
         pseudoType == nsCSSAnonBoxes::anonymousGridItem();
344
0
}
345
346
// Returns true if aFrame is a flex/grid container.
347
static inline bool
348
IsFlexOrGridContainer(const nsIFrame* aFrame)
349
0
{
350
0
  const LayoutFrameType t = aFrame->Type();
351
0
  return t == LayoutFrameType::FlexContainer ||
352
0
         t == LayoutFrameType::GridContainer;
353
0
}
354
355
// Returns true IFF the given nsIFrame is a nsFlexContainerFrame and
356
// represents a -webkit-{inline-}box or -moz-{inline-}box container.
357
static inline bool
358
IsFlexContainerForLegacyBox(const nsIFrame* aFrame)
359
0
{
360
0
  return aFrame->IsFlexContainerFrame() &&
361
0
         aFrame->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX);
362
0
}
363
364
#if DEBUG
365
static void
366
AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
367
                                    const nsIFrame* aParent)
368
{
369
  MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
370
             "expected an anonymous flex or grid item child frame");
371
  MOZ_ASSERT(aParent, "expected a parent frame");
372
  const nsAtom* pseudoType = aChild->Style()->GetPseudo();
373
  if (pseudoType == nsCSSAnonBoxes::anonymousFlexItem()) {
374
    MOZ_ASSERT(aParent->IsFlexContainerFrame(),
375
               "anonymous flex items should only exist as children "
376
               "of flex container frames");
377
  } else {
378
    MOZ_ASSERT(aParent->IsGridContainerFrame(),
379
               "anonymous grid items should only exist as children "
380
               "of grid container frames");
381
  }
382
}
383
#else
384
0
#define AssertAnonymousFlexOrGridItemParent(x, y) do { /* nothing */ } while(0)
385
#endif
386
387
static inline nsContainerFrame*
388
GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
389
0
{
390
0
  // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
391
0
  nsIFrame* firstChild = aFieldsetFrame->PrincipalChildList().FirstChild();
392
0
  nsIFrame* inner = firstChild && firstChild->GetNextSibling() ? firstChild->GetNextSibling() : firstChild;
393
0
  return inner ? inner->GetContentInsertionFrame() : nullptr;
394
0
}
395
396
#define FCDATA_DECL(_flags, _func)                            \
397
0
  { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr }
398
#define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box)  \
399
0
  { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS,        \
400
0
      { (FrameCreationFunc)_func }, nullptr, &_anon_box }
401
402
#define UNREACHABLE_FCDATA()                                  \
403
  { 0, { (FrameCreationFunc)nullptr }, nullptr, nullptr }
404
//----------------------------------------------------------------------
405
406
/**
407
 * True if aFrame is an actual inline frame in the sense of non-replaced
408
 * display:inline CSS boxes.  In other words, it can be affected by {ib}
409
 * splitting and can contain first-letter frames.  Basically, this is either an
410
 * inline frame (positioned or otherwise) or an line frame (this last because
411
 * it can contain first-letter and because inserting blocks in the middle of it
412
 * needs to terminate it).
413
 */
414
static bool
415
IsInlineFrame(const nsIFrame* aFrame)
416
0
{
417
0
  return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
418
0
}
419
420
/**
421
 * True for display: contents elements.
422
 */
423
static inline bool
424
IsDisplayContents(const Element* aElement)
425
0
{
426
0
  return aElement->IsDisplayContents();
427
0
}
428
429
static inline bool
430
IsDisplayContents(const nsIContent* aContent)
431
0
{
432
0
  return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
433
0
}
434
435
/**
436
 * True if aFrame is an instance of an SVG frame class or is an inline/block
437
 * frame being used for SVG text.
438
 */
439
static bool
440
IsFrameForSVG(const nsIFrame* aFrame)
441
0
{
442
0
  return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
443
0
         nsSVGUtils::IsInSVGTextSubtree(aFrame);
444
0
}
445
446
/**
447
 * Returns true iff aFrame explicitly prevents its descendants from floating
448
 * (at least, down to the level of descendants which themselves are
449
 * float-containing blocks -- those will manage the floating status of any
450
 * lower-level descendents inside them, of course).
451
 */
452
static bool
453
ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
454
0
{
455
0
  return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
456
0
    aFrame->IsXULBoxFrame() ||
457
0
    ::IsFlexOrGridContainer(aFrame);
458
0
}
459
460
/**
461
 * If any children require a block parent, return the first such child.
462
 * Otherwise return null.
463
 */
464
static nsIContent*
465
AnyKidsNeedBlockParent(nsIFrame *aFrameList)
466
0
{
467
0
  for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
468
0
    // Line participants, such as text and inline frames, can't be
469
0
    // directly inside a XUL box; they must be wrapped in an
470
0
    // intermediate block.
471
0
    if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
472
0
      return k->GetContent();
473
0
    }
474
0
  }
475
0
  return nullptr;
476
0
}
477
478
// Reparent a frame into a wrapper frame that is a child of its old parent.
479
static void
480
ReparentFrame(RestyleManager* aRestyleManager,
481
              nsContainerFrame* aNewParentFrame,
482
              nsIFrame* aFrame,
483
              bool aForceStyleReparent)
484
0
{
485
0
  aFrame->SetParent(aNewParentFrame);
486
0
  // We reparent frames for two reasons: to put them inside ::first-line, and to
487
0
  // put them inside some wrapper anonymous boxes.
488
0
  if (aForceStyleReparent) {
489
0
    aRestyleManager->ReparentComputedStyleForFirstLine(aFrame);
490
0
  }
491
0
}
492
493
static void
494
ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
495
               nsContainerFrame* aNewParentFrame,
496
               const nsFrameList& aFrameList,
497
               bool aForceStyleReparent)
498
0
{
499
0
  RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
500
0
  for (nsIFrame* f : aFrameList) {
501
0
    ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
502
0
  }
503
0
}
504
505
//----------------------------------------------------------------------
506
//
507
// When inline frames get weird and have block frames in them, we
508
// annotate them to help us respond to incremental content changes
509
// more easily.
510
511
static inline bool
512
IsFramePartOfIBSplit(nsIFrame* aFrame)
513
0
{
514
0
  bool result = (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0;
515
0
  MOZ_ASSERT(!result || static_cast<nsBlockFrame*>(do_QueryFrame(aFrame)) ||
516
0
                        static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)),
517
0
             "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT");
518
0
  return result;
519
0
}
520
521
static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame)
522
0
{
523
0
  MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
524
0
525
0
  // We only store the "ib-split sibling" annotation with the first
526
0
  // frame in the continuation chain. Walk back to find that frame now.
527
0
  return aFrame->FirstContinuation()->
528
0
           GetProperty(nsIFrame::IBSplitSibling());
529
0
}
530
531
static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame)
532
0
{
533
0
  MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this");
534
0
535
0
  // We only store the ib-split sibling annotation with the first
536
0
  // frame in the continuation chain. Walk back to find that frame now.
537
0
  return aFrame->FirstContinuation()->
538
0
           GetProperty(nsIFrame::IBSplitPrevSibling());
539
0
}
540
541
static nsContainerFrame*
542
GetLastIBSplitSibling(nsIFrame* aFrame)
543
0
{
544
0
  for (nsIFrame* frame = aFrame, *next; ; frame = next) {
545
0
    next = GetIBSplitSibling(frame);
546
0
    if (!next) {
547
0
      return static_cast<nsContainerFrame*>(frame);
548
0
    }
549
0
  }
550
0
  MOZ_ASSERT_UNREACHABLE("unreachable code");
551
0
  return nullptr;
552
0
}
553
554
static void
555
SetFrameIsIBSplit(nsContainerFrame* aFrame, nsContainerFrame* aIBSplitSibling)
556
0
{
557
0
  MOZ_ASSERT(aFrame, "bad args!");
558
0
559
0
  // We should be the only continuation
560
0
  NS_ASSERTION(!aFrame->GetPrevContinuation(),
561
0
               "assigning ib-split sibling to other than first continuation!");
562
0
  NS_ASSERTION(!aFrame->GetNextContinuation() ||
563
0
               IsFramePartOfIBSplit(aFrame->GetNextContinuation()),
564
0
               "should have no non-ib-split continuations here");
565
0
566
0
  // Mark the frame as ib-split.
567
0
  aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
568
0
569
0
  if (aIBSplitSibling) {
570
0
    NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),
571
0
                 "assigning something other than the first continuation as the "
572
0
                 "ib-split sibling");
573
0
574
0
    // Store the ib-split sibling (if we were given one) with the
575
0
    // first frame in the flow.
576
0
    aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
577
0
    aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
578
0
  }
579
0
}
580
581
static nsIFrame*
582
GetIBContainingBlockFor(nsIFrame* aFrame)
583
0
{
584
0
  MOZ_ASSERT(IsFramePartOfIBSplit(aFrame),
585
0
             "GetIBContainingBlockFor() should only be called on known IB frames");
586
0
587
0
  // Get the first "normal" ancestor of the target frame.
588
0
  nsIFrame* parentFrame;
589
0
  do {
590
0
    parentFrame = aFrame->GetParent();
591
0
592
0
    if (! parentFrame) {
593
0
      NS_ERROR("no unsplit block frame in IB hierarchy");
594
0
      return aFrame;
595
0
    }
596
0
597
0
    // Note that we ignore non-ib-split frames which have a pseudo on their
598
0
    // ComputedStyle -- they're not the frames we're looking for!  In
599
0
    // particular, they may be hiding a real parent that _is_ in an ib-split.
600
0
    if (!IsFramePartOfIBSplit(parentFrame) &&
601
0
        !parentFrame->Style()->GetPseudo())
602
0
      break;
603
0
604
0
    aFrame = parentFrame;
605
0
  } while (1);
606
0
607
0
  // post-conditions
608
0
  NS_ASSERTION(parentFrame, "no normal ancestor found for ib-split frame "
609
0
                            "in GetIBContainingBlockFor");
610
0
  NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt");
611
0
612
0
  return parentFrame;
613
0
}
614
615
// This is a bit slow, but sometimes we need it.
616
static bool
617
ParentIsWrapperAnonBox(nsIFrame* aParent)
618
0
{
619
0
  nsIFrame* maybeAnonBox = aParent;
620
0
  if (maybeAnonBox->Style()->GetPseudo() ==
621
0
        nsCSSAnonBoxes::cellContent()) {
622
0
    // The thing that would maybe be a wrapper anon box is the cell.
623
0
    maybeAnonBox = maybeAnonBox->GetParent();
624
0
  }
625
0
  return maybeAnonBox->Style()->IsWrapperAnonBox();
626
0
}
627
628
//----------------------------------------------------------------------
629
630
// Block/inline frame construction logic. We maintain a few invariants here:
631
//
632
// 1. Block frames contain block and inline frames.
633
//
634
// 2. Inline frames only contain inline frames. If an inline parent has a block
635
// child then the block child is migrated upward until it lands in a block
636
// parent (the inline frames containing block is where it will end up).
637
638
inline void
639
SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame)
640
0
{
641
0
  MOZ_ASSERT(!aFrame->GetNextSibling(), "Should be using a frame list");
642
0
  nsFrameList temp(aFrame, aFrame);
643
0
  aParent->SetInitialChildList(kPrincipalList, temp);
644
0
}
645
646
// -----------------------------------------------------------
647
648
// Structure used when constructing formatting object trees.
649
struct nsFrameItems : public nsFrameList
650
{
651
  // Appends the frame to the end of the list
652
  void AddChild(nsIFrame* aChild);
653
};
654
655
void
656
nsFrameItems::AddChild(nsIFrame* aChild)
657
0
{
658
0
  MOZ_ASSERT(aChild, "nsFrameItems::AddChild");
659
0
  MOZ_ASSERT(!aChild->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) ||
660
0
             aChild->GetPlaceholderFrame(),
661
0
             "An out-of-flow child without a placeholder frame?");
662
0
663
0
  // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild) here,
664
0
  // but some of our callers put frames that have different
665
0
  // parents (caption, I'm looking at you) on the same framelist, and
666
0
  // nsFrameList asserts if you try to do that.
667
0
  if (IsEmpty()) {
668
0
    SetFrames(aChild);
669
0
  }
670
0
  else {
671
0
    NS_ASSERTION(aChild != mLastChild,
672
0
                 "Same frame being added to frame list twice?");
673
0
    mLastChild->SetNextSibling(aChild);
674
0
    mLastChild = nsLayoutUtils::GetLastSibling(aChild);
675
0
  }
676
0
}
677
678
// -----------------------------------------------------------
679
680
// Structure used when constructing formatting object trees. Contains
681
// state information needed for absolutely positioned elements
682
struct nsAbsoluteItems : nsFrameItems {
683
  // containing block for absolutely positioned elements
684
  nsContainerFrame* containingBlock;
685
686
  explicit nsAbsoluteItems(nsContainerFrame* aContainingBlock);
687
#ifdef DEBUG
688
  // XXXbz Does this need a debug-only assignment operator that nulls out the
689
  // childList in the nsAbsoluteItems we're copying?  Introducing a difference
690
  // between debug and non-debug behavior seems bad, so I guess not...
691
  ~nsAbsoluteItems() {
692
    NS_ASSERTION(!FirstChild(),
693
                 "Dangling child list.  Someone forgot to insert it?");
694
  }
695
#endif
696
};
697
698
nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock)
699
  : containingBlock(aContainingBlock)
700
0
{
701
0
}
702
703
// -----------------------------------------------------------
704
705
// Structure for saving the existing state when pushing/poping containing
706
// blocks. The destructor restores the state to its previous state
707
class MOZ_STACK_CLASS nsFrameConstructorSaveState {
708
public:
709
  typedef nsIFrame::ChildListID ChildListID;
710
  nsFrameConstructorSaveState();
711
  ~nsFrameConstructorSaveState();
712
713
private:
714
  nsAbsoluteItems* mItems;      // pointer to struct whose data we save/restore
715
  nsAbsoluteItems  mSavedItems; // copy of original data
716
717
  // The name of the child list in which our frames would belong
718
  ChildListID mChildListID;
719
  nsFrameConstructorState* mState;
720
721
  // State used only when we're saving the abs-pos state for a transformed
722
  // element.
723
  nsAbsoluteItems mSavedFixedItems;
724
725
  bool mSavedFixedPosIsAbsPos;
726
727
  friend class nsFrameConstructorState;
728
};
729
730
// Structure used to keep track of a list of bindings we need to call
731
// AddToAttachedQueue on.  These should be in post-order depth-first
732
// flattened tree traversal order.
733
struct PendingBinding : public LinkedListElement<PendingBinding>
734
{
735
#ifdef NS_BUILD_REFCNT_LOGGING
736
  PendingBinding() {
737
    MOZ_COUNT_CTOR(PendingBinding);
738
  }
739
  ~PendingBinding() {
740
    MOZ_COUNT_DTOR(PendingBinding);
741
  }
742
#endif
743
744
  RefPtr<nsXBLBinding> mBinding;
745
};
746
747
// Structure used for maintaining state information during the
748
// frame construction process
749
class MOZ_STACK_CLASS nsFrameConstructorState {
750
public:
751
  typedef nsIFrame::ChildListID ChildListID;
752
753
  nsPresContext            *mPresContext;
754
  nsIPresShell             *mPresShell;
755
  nsFrameManager           *mFrameManager;
756
757
#ifdef MOZ_XUL
758
  // Frames destined for the kPopupList.
759
  nsAbsoluteItems           mPopupItems;
760
#endif
761
762
  // Containing block information for out-of-flow frames.
763
  nsAbsoluteItems           mFixedItems;
764
  nsAbsoluteItems           mAbsoluteItems;
765
  nsAbsoluteItems           mFloatedItems;
766
  // The containing block of a frame in the top layer is defined by the
767
  // spec: fixed-positioned frames are children of the viewport frame,
768
  // and absolutely-positioned frames are children of the initial
769
  // containing block. They would not be caught by any other containing
770
  // block, e.g. frames with transform or filter.
771
  nsAbsoluteItems           mTopLayerFixedItems;
772
  nsAbsoluteItems           mTopLayerAbsoluteItems;
773
774
  nsCOMPtr<nsILayoutHistoryState> mFrameState;
775
  // These bits will be added to the state bits of any frame we construct
776
  // using this state.
777
  nsFrameState              mAdditionalStateBits;
778
779
  // When working with the transform and filter properties, we want to hook
780
  // the abs-pos and fixed-pos lists together, since such
781
  // elements are fixed-pos containing blocks.  This flag determines
782
  // whether or not we want to wire the fixed-pos and abs-pos lists
783
  // together.
784
  bool                      mFixedPosIsAbsPos;
785
786
  // A boolean to indicate whether we have a "pending" popupgroup.  That is, we
787
  // have already created the FrameConstructionItem for the root popupgroup but
788
  // we have not yet created the relevant frame.
789
  bool                      mHavePendingPopupgroup;
790
791
  // If false (which is the default) then call SetPrimaryFrame() as needed
792
  // during frame construction.  If true, don't make any SetPrimaryFrame()
793
  // calls, except for generated content which doesn't have a primary frame
794
  // yet.  The mCreatingExtraFrames == true mode is meant to be used for
795
  // construction of random "extra" frames for elements via normal frame
796
  // construction APIs (e.g. replication of things across pages in paginated
797
  // mode).
798
  bool                      mCreatingExtraFrames;
799
800
  nsCOMArray<nsIContent>    mGeneratedTextNodesWithInitializer;
801
802
  // Constructor
803
  // Use the passed-in history state.
804
  nsFrameConstructorState(
805
    nsIPresShell* aPresShell,
806
    nsContainerFrame* aFixedContainingBlock,
807
    nsContainerFrame* aAbsoluteContainingBlock,
808
    nsContainerFrame* aFloatContainingBlock,
809
    already_AddRefed<nsILayoutHistoryState> aHistoryState);
810
  // Get the history state from the pres context's pres shell.
811
  nsFrameConstructorState(nsIPresShell* aPresShell,
812
                          nsContainerFrame* aFixedContainingBlock,
813
                          nsContainerFrame* aAbsoluteContainingBlock,
814
                          nsContainerFrame* aFloatContainingBlock);
815
816
  ~nsFrameConstructorState();
817
818
  // Function to push the existing absolute containing block state and
819
  // create a new scope. Code that uses this function should get matching
820
  // logic in GetAbsoluteContainingBlock.
821
  // Also makes aNewAbsoluteContainingBlock the containing block for
822
  // fixed-pos elements if necessary.
823
  // aPositionedFrame is the frame whose style actually makes
824
  // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
825
  // aPositionedFrame is the element's primary frame and
826
  // aNewAbsoluteContainingBlock is the scrolled frame.
827
  void PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
828
                                   nsIFrame* aPositionedFrame,
829
                                   nsFrameConstructorSaveState& aSaveState);
830
831
  // Function to push the existing float containing block state and
832
  // create a new scope. Code that uses this function should get matching
833
  // logic in GetFloatContainingBlock.
834
  // Pushing a null float containing block forbids any frames from being
835
  // floated until a new float containing block is pushed.
836
  // XXX we should get rid of null float containing blocks and teach the
837
  // various frame classes to deal with floats instead.
838
  void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
839
                                nsFrameConstructorSaveState& aSaveState);
840
841
  // Function to return the proper geometric parent for a frame with display
842
  // struct given by aStyleDisplay and parent's frame given by
843
  // aContentParentFrame.
844
  nsContainerFrame* GetGeometricParent(const nsStyleDisplay& aStyleDisplay,
845
                                       nsContainerFrame* aContentParentFrame) const;
846
847
  /**
848
   * Function to add a new frame to the right frame list.  This MUST be called
849
   * on frames before their children have been processed if the frames might
850
   * conceivably be out-of-flow; otherwise cleanup in error cases won't work
851
   * right.  Also, this MUST be called on frames after they have been
852
   * initialized.
853
   * @param aNewFrame the frame to add
854
   * @param aFrameItems the list to add in-flow frames to
855
   * @param aContent the content pointer for aNewFrame
856
   * @param aParentFrame the parent frame for the content if it were in-flow
857
   * @param aCanBePositioned pass false if the frame isn't allowed to be
858
   *        positioned
859
   * @param aCanBeFloated pass false if the frame isn't allowed to be
860
   *        floated
861
   * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
862
   *        (XUL-only)
863
   */
864
  void AddChild(nsIFrame* aNewFrame,
865
                nsFrameItems& aFrameItems,
866
                nsIContent* aContent,
867
                nsContainerFrame* aParentFrame,
868
                bool aCanBePositioned = true,
869
                bool aCanBeFloated = true,
870
                bool aIsOutOfFlowPopup = false,
871
                bool aInsertAfter = false,
872
                nsIFrame* aInsertAfterFrame = nullptr);
873
874
  /**
875
   * Function to return the fixed-pos element list.  Normally this will just hand back the
876
   * fixed-pos element list, but in case we're dealing with a transformed element that's
877
   * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list.  Callers should
878
   * use this function if they want to get the list acting as the fixed-pos item parent.
879
   */
880
  nsAbsoluteItems& GetFixedItems()
881
0
  {
882
0
    return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
883
0
  }
884
  const nsAbsoluteItems& GetFixedItems() const
885
0
  {
886
0
    return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
887
0
  }
888
889
890
  /**
891
   * class to automatically push and pop a pending binding in the frame
892
   * constructor state.  See nsCSSFrameConstructor::FrameConstructionItem
893
   * mPendingBinding documentation.
894
   */
895
  class PendingBindingAutoPusher;
896
  friend class PendingBindingAutoPusher;
897
  class MOZ_STACK_CLASS PendingBindingAutoPusher {
898
  public:
899
    PendingBindingAutoPusher(nsFrameConstructorState& aState,
900
                             PendingBinding* aPendingBinding) :
901
      mState(aState),
902
      mPendingBinding(aState.mCurrentPendingBindingInsertionPoint)
903
0
        {
904
0
          if (aPendingBinding) {
905
0
            aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
906
0
          }
907
0
        }
908
909
    ~PendingBindingAutoPusher()
910
0
      {
911
0
        mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
912
0
      }
913
914
  private:
915
    nsFrameConstructorState& mState;
916
    PendingBinding* mPendingBinding;
917
  };
918
919
  /**
920
   * Add a new pending binding to the list
921
   */
922
  void AddPendingBinding(UniquePtr<PendingBinding> aPendingBinding)
923
0
  {
924
0
    if (mCurrentPendingBindingInsertionPoint) {
925
0
      mCurrentPendingBindingInsertionPoint->setPrevious(aPendingBinding.release());
926
0
    } else {
927
0
      mPendingBindings.insertBack(aPendingBinding.release());
928
0
    }
929
0
  }
930
931
protected:
932
  friend class nsFrameConstructorSaveState;
933
934
  /**
935
   * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
936
   * kids to the aChildListID child list of |aFrameItems.containingBlock|.
937
   */
938
  void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
939
                              ChildListID aChildListID);
940
941
  /**
942
   * GetOutOfFlowFrameItems selects the out-of-flow frame list the new
943
   * frame should be added to. If the frame shouldn't be added to any
944
   * out-of-flow list, it returns nullptr. The corresponding type of
945
   * placeholder is also returned via the aPlaceholderType parameter
946
   * if this method doesn't return nullptr. The caller should check
947
   * whether the returned list really has a containing block.
948
   */
949
  nsAbsoluteItems* GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
950
                                          bool aCanBePositioned,
951
                                          bool aCanBeFloated,
952
                                          bool aIsOutOfFlowPopup,
953
                                          nsFrameState* aPlaceholderType);
954
955
  void ConstructBackdropFrameFor(nsIContent* aContent, nsIFrame* aFrame);
956
957
  // Our list of all pending bindings.  When we're done, we need to call
958
  // AddToAttachedQueue on all of them, in order.
959
  LinkedList<PendingBinding> mPendingBindings;
960
961
  PendingBinding* mCurrentPendingBindingInsertionPoint;
962
};
963
964
nsFrameConstructorState::nsFrameConstructorState(
965
  nsIPresShell* aPresShell,
966
  nsContainerFrame* aFixedContainingBlock,
967
  nsContainerFrame* aAbsoluteContainingBlock,
968
  nsContainerFrame* aFloatContainingBlock,
969
  already_AddRefed<nsILayoutHistoryState> aHistoryState)
970
  : mPresContext(aPresShell->GetPresContext()),
971
    mPresShell(aPresShell),
972
    mFrameManager(aPresShell->FrameConstructor()),
973
#ifdef MOZ_XUL
974
    mPopupItems(nullptr),
975
#endif
976
    mFixedItems(aFixedContainingBlock),
977
    mAbsoluteItems(aAbsoluteContainingBlock),
978
    mFloatedItems(aFloatContainingBlock),
979
    mTopLayerFixedItems(
980
      static_cast<nsContainerFrame*>(mFrameManager->GetRootFrame())),
981
    mTopLayerAbsoluteItems(
982
      aPresShell->FrameConstructor()->GetDocElementContainingBlock()),
983
    // See PushAbsoluteContaningBlock below
984
    mFrameState(aHistoryState),
985
    mAdditionalStateBits(nsFrameState(0)),
986
    // If the fixed-pos containing block is equal to the abs-pos containing
987
    // block, use the abs-pos containing block's abs-pos list for fixed-pos
988
    // frames.
989
    mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
990
    mHavePendingPopupgroup(false),
991
    mCreatingExtraFrames(false),
992
    mCurrentPendingBindingInsertionPoint(nullptr)
993
0
{
994
0
#ifdef MOZ_XUL
995
0
  nsIPopupContainer* popupContainer =
996
0
    nsIPopupContainer::GetPopupContainer(aPresShell);
997
0
  if (popupContainer) {
998
0
    mPopupItems.containingBlock = popupContainer->GetPopupSetFrame();
999
0
  }
1000
0
#endif
1001
0
  MOZ_COUNT_CTOR(nsFrameConstructorState);
1002
0
}
1003
1004
nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
1005
                                                 nsContainerFrame* aFixedContainingBlock,
1006
                                                 nsContainerFrame* aAbsoluteContainingBlock,
1007
                                                 nsContainerFrame* aFloatContainingBlock)
1008
  : nsFrameConstructorState(aPresShell,
1009
                            aFixedContainingBlock,
1010
                            aAbsoluteContainingBlock,
1011
                            aFloatContainingBlock,
1012
                            aPresShell->GetDocument()->GetLayoutHistoryState())
1013
0
{
1014
0
}
1015
1016
nsFrameConstructorState::~nsFrameConstructorState()
1017
0
{
1018
0
  MOZ_COUNT_DTOR(nsFrameConstructorState);
1019
0
  ProcessFrameInsertions(mTopLayerFixedItems, nsIFrame::kFixedList);
1020
0
  ProcessFrameInsertions(mTopLayerAbsoluteItems, nsIFrame::kAbsoluteList);
1021
0
  ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
1022
0
  ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
1023
0
  ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
1024
0
#ifdef MOZ_XUL
1025
0
  ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList);
1026
0
#endif
1027
0
  for (int32_t i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
1028
0
    mGeneratedTextNodesWithInitializer[i]->
1029
0
      DeleteProperty(nsGkAtoms::genConInitializerProperty);
1030
0
  }
1031
0
  if (!mPendingBindings.isEmpty()) {
1032
0
    nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager();
1033
0
    do {
1034
0
      nsAutoPtr<PendingBinding> pendingBinding;
1035
0
      pendingBinding = mPendingBindings.popFirst();
1036
0
      bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
1037
0
    } while (!mPendingBindings.isEmpty());
1038
0
    mCurrentPendingBindingInsertionPoint = nullptr;
1039
0
  }
1040
0
}
1041
1042
static nsContainerFrame*
1043
AdjustAbsoluteContainingBlock(nsContainerFrame* aContainingBlockIn)
1044
0
{
1045
0
  if (!aContainingBlockIn) {
1046
0
    return nullptr;
1047
0
  }
1048
0
1049
0
  // Always use the container's first continuation. (Inline frames can have
1050
0
  // non-fluid bidi continuations...)
1051
0
  return static_cast<nsContainerFrame*>(aContainingBlockIn->FirstContinuation());
1052
0
}
1053
1054
void
1055
nsFrameConstructorState::PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
1056
                                                     nsIFrame* aPositionedFrame,
1057
                                                     nsFrameConstructorSaveState& aSaveState)
1058
0
{
1059
0
  aSaveState.mItems = &mAbsoluteItems;
1060
0
  aSaveState.mSavedItems = mAbsoluteItems;
1061
0
  aSaveState.mChildListID = nsIFrame::kAbsoluteList;
1062
0
  aSaveState.mState = this;
1063
0
  aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
1064
0
1065
0
  if (mFixedPosIsAbsPos) {
1066
0
    // Since we're going to replace mAbsoluteItems, we need to save it into
1067
0
    // mFixedItems now (and save the current value of mFixedItems).
1068
0
    aSaveState.mSavedFixedItems = mFixedItems;
1069
0
    mFixedItems = mAbsoluteItems;
1070
0
  }
1071
0
1072
0
  mAbsoluteItems =
1073
0
    nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
1074
0
1075
0
  /* See if we're wiring the fixed-pos and abs-pos lists together.  This happens iff
1076
0
   * we're a transformed element.
1077
0
   */
1078
0
  mFixedPosIsAbsPos = aPositionedFrame &&
1079
0
      aPositionedFrame->IsFixedPosContainingBlock();
1080
0
1081
0
  if (aNewAbsoluteContainingBlock) {
1082
0
    aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
1083
0
  }
1084
0
}
1085
1086
void
1087
nsFrameConstructorState::PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
1088
                                                  nsFrameConstructorSaveState& aSaveState)
1089
0
{
1090
0
  MOZ_ASSERT(!aNewFloatContainingBlock ||
1091
0
             aNewFloatContainingBlock->IsFloatContainingBlock(),
1092
0
             "Please push a real float containing block!");
1093
0
  NS_ASSERTION(!aNewFloatContainingBlock ||
1094
0
               !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),
1095
0
               "We should not push a frame that is supposed to _suppress_ "
1096
0
               "floats as a float containing block!");
1097
0
  aSaveState.mItems = &mFloatedItems;
1098
0
  aSaveState.mSavedItems = mFloatedItems;
1099
0
  aSaveState.mChildListID = nsIFrame::kFloatList;
1100
0
  aSaveState.mState = this;
1101
0
  mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock);
1102
0
}
1103
1104
nsContainerFrame*
1105
nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay& aStyleDisplay,
1106
                                            nsContainerFrame* aContentParentFrame) const
1107
0
{
1108
0
  // If there is no container for a fixed, absolute, or floating root
1109
0
  // frame, we will ignore the positioning.  This hack is originally
1110
0
  // brought to you by the letter T: tables, since other roots don't
1111
0
  // even call into this code.  See bug 178855.
1112
0
  //
1113
0
  // XXX Disabling positioning in this case is a hack.  If one was so inclined,
1114
0
  // one could support this either by (1) inserting a dummy block between the
1115
0
  // table and the canvas or (2) teaching the canvas how to reflow positioned
1116
0
  // elements. (1) has the usual problems when multiple frames share the same
1117
0
  // content (notice all the special cases in this file dealing with inner
1118
0
  // tables and table wrappers which share the same content). (2) requires some
1119
0
  // work and possible factoring.
1120
0
  //
1121
0
  // XXXbz couldn't we just force position to "static" on roots and
1122
0
  // float to "none"?  That's OK per CSS 2.1, as far as I can tell.
1123
0
1124
0
  if (aContentParentFrame &&
1125
0
      nsSVGUtils::IsInSVGTextSubtree(aContentParentFrame)) {
1126
0
    return aContentParentFrame;
1127
0
  }
1128
0
1129
0
  if (aStyleDisplay.IsFloatingStyle() && mFloatedItems.containingBlock) {
1130
0
    NS_ASSERTION(!aStyleDisplay.IsAbsolutelyPositionedStyle(),
1131
0
                 "Absolutely positioned _and_ floating?");
1132
0
    return mFloatedItems.containingBlock;
1133
0
  }
1134
0
1135
0
  if (aStyleDisplay.mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1136
0
    MOZ_ASSERT(aStyleDisplay.mTopLayer == NS_STYLE_TOP_LAYER_TOP,
1137
0
               "-moz-top-layer should be either none or top");
1138
0
    MOZ_ASSERT(aStyleDisplay.IsAbsolutelyPositionedStyle(),
1139
0
               "Top layer items should always be absolutely positioned");
1140
0
    if (aStyleDisplay.mPosition == NS_STYLE_POSITION_FIXED) {
1141
0
      MOZ_ASSERT(mTopLayerFixedItems.containingBlock, "No root frame?");
1142
0
      return mTopLayerFixedItems.containingBlock;
1143
0
    }
1144
0
    MOZ_ASSERT(aStyleDisplay.mPosition == NS_STYLE_POSITION_ABSOLUTE);
1145
0
    MOZ_ASSERT(mTopLayerAbsoluteItems.containingBlock);
1146
0
    return mTopLayerAbsoluteItems.containingBlock;
1147
0
  }
1148
0
1149
0
  if (aStyleDisplay.mPosition == NS_STYLE_POSITION_ABSOLUTE &&
1150
0
      mAbsoluteItems.containingBlock) {
1151
0
    return mAbsoluteItems.containingBlock;
1152
0
  }
1153
0
1154
0
  if (aStyleDisplay.mPosition == NS_STYLE_POSITION_FIXED &&
1155
0
      GetFixedItems().containingBlock) {
1156
0
    return GetFixedItems().containingBlock;
1157
0
  }
1158
0
1159
0
  return aContentParentFrame;
1160
0
}
1161
1162
nsAbsoluteItems*
1163
nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
1164
                                                bool aCanBePositioned,
1165
                                                bool aCanBeFloated,
1166
                                                bool aIsOutOfFlowPopup,
1167
                                                nsFrameState* aPlaceholderType)
1168
0
{
1169
0
#ifdef MOZ_XUL
1170
0
  if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
1171
0
    MOZ_ASSERT(mPopupItems.containingBlock, "Must have a popup set frame!");
1172
0
    *aPlaceholderType = PLACEHOLDER_FOR_POPUP;
1173
0
    return &mPopupItems;
1174
0
  }
1175
0
#endif // MOZ_XUL
1176
0
  if (aCanBeFloated && aNewFrame->IsFloating()) {
1177
0
    *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1178
0
    return &mFloatedItems;
1179
0
  }
1180
0
1181
0
  if (aCanBePositioned) {
1182
0
    const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1183
0
    if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
1184
0
      *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1185
0
      if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1186
0
        *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
1187
0
        return &mTopLayerFixedItems;
1188
0
      }
1189
0
      *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
1190
0
      return &mTopLayerAbsoluteItems;
1191
0
    }
1192
0
    if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) {
1193
0
      *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1194
0
      return &mAbsoluteItems;
1195
0
    }
1196
0
    if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
1197
0
      *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1198
0
      return &GetFixedItems();
1199
0
    }
1200
0
  }
1201
0
  return nullptr;
1202
0
}
1203
1204
void
1205
nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent,
1206
                                                   nsIFrame* aFrame)
1207
0
{
1208
0
  MOZ_ASSERT(aFrame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1209
0
  nsContainerFrame* frame = do_QueryFrame(aFrame);
1210
0
  if (!frame) {
1211
0
    NS_WARNING("Cannot create backdrop frame for non-container frame");
1212
0
    return;
1213
0
  }
1214
0
1215
0
  RefPtr<ComputedStyle> style = mPresShell->StyleSet()->
1216
0
    ResolvePseudoElementStyle(aContent->AsElement(),
1217
0
                              CSSPseudoElementType::backdrop,
1218
0
                              /* aParentComputedStyle */ nullptr,
1219
0
                              /* aPseudoElement */ nullptr);
1220
0
  MOZ_ASSERT(style->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
1221
0
  nsContainerFrame* parentFrame =
1222
0
    GetGeometricParent(*style->StyleDisplay(), nullptr);
1223
0
1224
0
  nsBackdropFrame* backdropFrame = new (mPresShell) nsBackdropFrame(style);
1225
0
  backdropFrame->Init(aContent, parentFrame, nullptr);
1226
0
1227
0
  nsFrameState placeholderType;
1228
0
  nsAbsoluteItems* frameItems = GetOutOfFlowFrameItems(backdropFrame,
1229
0
                                                       true, true, false,
1230
0
                                                       &placeholderType);
1231
0
  MOZ_ASSERT(placeholderType & PLACEHOLDER_FOR_TOPLAYER);
1232
0
1233
0
  nsIFrame* placeholder = nsCSSFrameConstructor::
1234
0
    CreatePlaceholderFrameFor(mPresShell, aContent, backdropFrame,
1235
0
                              frame, nullptr, placeholderType);
1236
0
  nsFrameList temp(placeholder, placeholder);
1237
0
  frame->SetInitialChildList(nsIFrame::kBackdropList, temp);
1238
0
1239
0
  frameItems->AddChild(backdropFrame);
1240
0
}
1241
1242
void
1243
nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
1244
                                  nsFrameItems& aFrameItems,
1245
                                  nsIContent* aContent,
1246
                                  nsContainerFrame* aParentFrame,
1247
                                  bool aCanBePositioned,
1248
                                  bool aCanBeFloated,
1249
                                  bool aIsOutOfFlowPopup,
1250
                                  bool aInsertAfter,
1251
                                  nsIFrame* aInsertAfterFrame)
1252
0
{
1253
0
  MOZ_ASSERT(!aNewFrame->GetNextSibling(), "Shouldn't happen");
1254
0
1255
0
  nsFrameState placeholderType;
1256
0
  nsAbsoluteItems* outOfFlowFrameItems =
1257
0
    GetOutOfFlowFrameItems(aNewFrame, aCanBePositioned, aCanBeFloated,
1258
0
                           aIsOutOfFlowPopup, &placeholderType);
1259
0
1260
0
  // The comments in GetGeometricParent regarding root table frames
1261
0
  // all apply here, unfortunately. Thus, we need to check whether
1262
0
  // the returned frame items really has containing block.
1263
0
  nsFrameItems* frameItems;
1264
0
  if (outOfFlowFrameItems && outOfFlowFrameItems->containingBlock) {
1265
0
    MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameItems->containingBlock,
1266
0
               "Parent of the frame is not the containing block?");
1267
0
    frameItems = outOfFlowFrameItems;
1268
0
  } else {
1269
0
    frameItems = &aFrameItems;
1270
0
    placeholderType = nsFrameState(0);
1271
0
  }
1272
0
1273
0
  if (placeholderType) {
1274
0
    NS_ASSERTION(frameItems != &aFrameItems,
1275
0
                 "Putting frame in-flow _and_ want a placeholder?");
1276
0
    nsIFrame* placeholderFrame =
1277
0
      nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell,
1278
0
                                                       aContent,
1279
0
                                                       aNewFrame,
1280
0
                                                       aParentFrame,
1281
0
                                                       nullptr,
1282
0
                                                       placeholderType);
1283
0
1284
0
    placeholderFrame->AddStateBits(mAdditionalStateBits);
1285
0
    // Add the placeholder frame to the flow
1286
0
    aFrameItems.AddChild(placeholderFrame);
1287
0
1288
0
    if (placeholderType & PLACEHOLDER_FOR_TOPLAYER) {
1289
0
      ConstructBackdropFrameFor(aContent, aNewFrame);
1290
0
    }
1291
0
  }
1292
#ifdef DEBUG
1293
  else {
1294
    NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
1295
                 "In-flow frame has wrong parent");
1296
  }
1297
#endif
1298
1299
0
  if (aInsertAfter) {
1300
0
    frameItems->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1301
0
  } else {
1302
0
    frameItems->AddChild(aNewFrame);
1303
0
  }
1304
0
}
1305
1306
void
1307
nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
1308
                                                ChildListID aChildListID)
1309
0
{
1310
0
#define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems &&            \
1311
0
                             aChildListID == nsIFrame::kFloatList)    ||  \
1312
0
                            ((&aFrameItems == &mAbsoluteItems ||          \
1313
0
                              &aFrameItems == &mTopLayerAbsoluteItems) && \
1314
0
                             aChildListID == nsIFrame::kAbsoluteList) ||  \
1315
0
                            ((&aFrameItems == &mFixedItems ||             \
1316
0
                              &aFrameItems == &mTopLayerFixedItems) &&    \
1317
0
                             aChildListID == nsIFrame::kFixedList)
1318
0
#ifdef MOZ_XUL
1319
0
  MOZ_ASSERT(NS_NONXUL_LIST_TEST ||
1320
0
             (&aFrameItems == &mPopupItems &&
1321
0
              aChildListID == nsIFrame::kPopupList),
1322
0
             "Unexpected aFrameItems/aChildListID combination");
1323
#else
1324
  MOZ_ASSERT(NS_NONXUL_LIST_TEST,
1325
             "Unexpected aFrameItems/aChildListID combination");
1326
#endif
1327
1328
0
  if (aFrameItems.IsEmpty()) {
1329
0
    return;
1330
0
  }
1331
0
1332
0
  nsContainerFrame* containingBlock = aFrameItems.containingBlock;
1333
0
1334
0
  NS_ASSERTION(containingBlock,
1335
0
               "Child list without containing block?");
1336
0
1337
0
  if (aChildListID == nsIFrame::kFixedList) {
1338
0
    // Put this frame on the transformed-frame's abs-pos list instead, if
1339
0
    // it has abs-pos children instead of fixed-pos children.
1340
0
    aChildListID = containingBlock->GetAbsoluteListID();
1341
0
  }
1342
0
1343
0
  // Insert the frames hanging out in aItems.  We can use SetInitialChildList()
1344
0
  // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1345
0
  // is set) and doesn't have any frames in the aChildListID child list yet.
1346
0
  const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1347
0
  if (childList.IsEmpty() &&
1348
0
      (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1349
0
    // If we're injecting absolutely positioned frames, inject them on the
1350
0
    // absolute containing block
1351
0
    if (aChildListID == containingBlock->GetAbsoluteListID()) {
1352
0
      containingBlock->GetAbsoluteContainingBlock()->
1353
0
        SetInitialChildList(containingBlock, aChildListID, aFrameItems);
1354
0
    } else {
1355
0
      containingBlock->SetInitialChildList(aChildListID, aFrameItems);
1356
0
    }
1357
0
  } else if (aChildListID == nsIFrame::kFixedList ||
1358
0
             aChildListID == nsIFrame::kAbsoluteList) {
1359
0
    // The order is not important for abs-pos/fixed-pos frame list, just
1360
0
    // append the frame items to the list directly.
1361
0
    mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1362
0
  } else {
1363
0
    // Note that whether the frame construction context is doing an append or
1364
0
    // not is not helpful here, since it could be appending to some frame in
1365
0
    // the middle of the document, which means we're not necessarily
1366
0
    // appending to the children of the containing block.
1367
0
    //
1368
0
    // We need to make sure the 'append to the end of document' case is fast.
1369
0
    // So first test the last child of the containing block
1370
0
    nsIFrame* lastChild = childList.LastChild();
1371
0
1372
0
    // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1373
0
    // so this will make out-of-flows respect the ordering of placeholders,
1374
0
    // which is great because it takes care of anonymous content.
1375
0
    nsIFrame* firstNewFrame = aFrameItems.FirstChild();
1376
0
1377
0
    // Cache the ancestor chain so that we can reuse it if needed.
1378
0
    AutoTArray<nsIFrame*, 20> firstNewFrameAncestors;
1379
0
    nsIFrame* notCommonAncestor = nullptr;
1380
0
    if (lastChild) {
1381
0
      notCommonAncestor = nsLayoutUtils::FillAncestors(firstNewFrame,
1382
0
                                                       containingBlock,
1383
0
                                                       &firstNewFrameAncestors);
1384
0
    }
1385
0
1386
0
    if (!lastChild ||
1387
0
        nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame,
1388
0
                                           firstNewFrameAncestors,
1389
0
                                           notCommonAncestor ?
1390
0
                                             containingBlock : nullptr) < 0) {
1391
0
      // no lastChild, or lastChild comes before the new children, so just append
1392
0
      mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1393
0
    } else {
1394
0
      // Try the other children. First collect them to an array so that a
1395
0
      // reasonable fast binary search can be used to find the insertion point.
1396
0
      AutoTArray<nsIFrame*, 128> children;
1397
0
      for (nsIFrame* f = childList.FirstChild(); f != lastChild;
1398
0
           f = f->GetNextSibling()) {
1399
0
        children.AppendElement(f);
1400
0
      }
1401
0
1402
0
      nsIFrame* insertionPoint = nullptr;
1403
0
      int32_t imin = 0;
1404
0
      int32_t max = children.Length();
1405
0
      while (max > imin) {
1406
0
        int32_t imid = imin + ((max - imin) / 2);
1407
0
        nsIFrame* f = children[imid];
1408
0
        int32_t compare =
1409
0
          nsLayoutUtils::CompareTreePosition(f, firstNewFrame, firstNewFrameAncestors,
1410
0
                                             notCommonAncestor ? containingBlock : nullptr);
1411
0
        if (compare > 0) {
1412
0
          // f is after the new frame.
1413
0
          max = imid;
1414
0
          insertionPoint = imid > 0 ? children[imid - 1] : nullptr;
1415
0
        } else if (compare < 0) {
1416
0
          // f is before the new frame.
1417
0
          imin = imid + 1;
1418
0
          insertionPoint = f;
1419
0
        } else {
1420
0
          // This is for the old behavior. Should be removed once it is
1421
0
          // guaranteed that CompareTreePosition can't return 0!
1422
0
          // See bug 928645.
1423
0
          NS_WARNING("Something odd happening???");
1424
0
          insertionPoint = nullptr;
1425
0
          for (uint32_t i = 0; i < children.Length(); ++i) {
1426
0
            nsIFrame* f = children[i];
1427
0
            if (nsLayoutUtils::CompareTreePosition(f, firstNewFrame,
1428
0
                                                   firstNewFrameAncestors,
1429
0
                                                   notCommonAncestor ?
1430
0
                                                     containingBlock : nullptr) > 0) {
1431
0
              break;
1432
0
            }
1433
0
            insertionPoint = f;
1434
0
          }
1435
0
          break;
1436
0
        }
1437
0
      }
1438
0
      mFrameManager->InsertFrames(containingBlock, aChildListID,
1439
0
                                  insertionPoint, aFrameItems);
1440
0
    }
1441
0
  }
1442
0
1443
0
  MOZ_ASSERT(aFrameItems.IsEmpty(), "How did that happen?");
1444
0
}
1445
1446
1447
nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1448
  : mItems(nullptr),
1449
    mSavedItems(nullptr),
1450
    mChildListID(kPrincipalList),
1451
    mState(nullptr),
1452
    mSavedFixedItems(nullptr),
1453
    mSavedFixedPosIsAbsPos(false)
1454
0
{
1455
0
}
1456
1457
nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1458
0
{
1459
0
  // Restore the state
1460
0
  if (mItems) {
1461
0
    NS_ASSERTION(mState, "Can't have mItems set without having a state!");
1462
0
    mState->ProcessFrameInsertions(*mItems, mChildListID);
1463
0
    *mItems = mSavedItems;
1464
#ifdef DEBUG
1465
    // We've transferred the child list, so drop the pointer we held to it.
1466
    // Note that this only matters for the assert in ~nsAbsoluteItems.
1467
    mSavedItems.Clear();
1468
#endif
1469
0
    if (mItems == &mState->mAbsoluteItems) {
1470
0
      mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
1471
0
      if (mSavedFixedPosIsAbsPos) {
1472
0
        // mAbsoluteItems was moved to mFixedItems, so move mFixedItems back
1473
0
        // and repair the old mFixedItems now.
1474
0
        mState->mAbsoluteItems = mState->mFixedItems;
1475
0
        mState->mFixedItems = mSavedFixedItems;
1476
#ifdef DEBUG
1477
        mSavedFixedItems.Clear();
1478
#endif
1479
      }
1480
0
    }
1481
0
    NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(),
1482
0
                 "Something corrupted our list");
1483
0
  }
1484
0
}
1485
1486
/**
1487
 * Moves aFrameList from aOldParent to aNewParent.  This updates the parent
1488
 * pointer of the frames in the list, and reparents their views as needed.
1489
 * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1490
 * ancestors as needed. Then it sets the list as the initial child list
1491
 * on aNewParent, unless aNewParent either already has kids or has been
1492
 * reflowed; in that case it appends the new frames.  Note that this
1493
 * method differs from ReparentFrames in that it doesn't change the kids'
1494
 * style.
1495
 */
1496
// XXXbz Since this is only used for {ib} splits, could we just copy the view
1497
// bits from aOldParent to aNewParent and then use the
1498
// nsFrameList::ApplySetParent?  That would still leave us doing two passes
1499
// over the list, of course; if we really wanted to we could factor out the
1500
// relevant part of ReparentFrameViewList, I suppose...  Or just get rid of
1501
// views, which would make most of this function go away.
1502
static void
1503
MoveChildrenTo(nsIFrame* aOldParent,
1504
               nsContainerFrame* aNewParent,
1505
               nsFrameList& aFrameList)
1506
0
{
1507
0
  bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent();
1508
0
1509
0
  if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) {
1510
0
    // Move the frames into the new view
1511
0
    nsContainerFrame::ReparentFrameViewList(aFrameList, aOldParent, aNewParent);
1512
0
  }
1513
0
1514
0
  for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
1515
0
    e.get()->SetParent(aNewParent);
1516
0
  }
1517
0
1518
0
  if (aNewParent->PrincipalChildList().IsEmpty() &&
1519
0
      (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1520
0
    aNewParent->SetInitialChildList(kPrincipalList, aFrameList);
1521
0
  } else {
1522
0
    aNewParent->AppendFrames(kPrincipalList, aFrameList);
1523
0
  }
1524
0
}
1525
1526
static bool
1527
ShouldCreateImageFrameForContent(const Element& aElement, ComputedStyle& aStyle)
1528
0
{
1529
0
  if (aElement.IsRootOfNativeAnonymousSubtree()) {
1530
0
    return false;
1531
0
  }
1532
0
1533
0
  auto& content = *aStyle.StyleContent();
1534
0
  if (content.ContentCount() != 1) {
1535
0
    return false;
1536
0
  }
1537
0
1538
0
  return content.ContentAt(0).GetType() == StyleContentType::Image;
1539
0
}
1540
1541
//----------------------------------------------------------------------
1542
1543
nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument* aDocument,
1544
                                             nsIPresShell* aPresShell)
1545
  : nsFrameManager(aPresShell)
1546
  , mDocument(aDocument)
1547
  , mRootElementFrame(nullptr)
1548
  , mRootElementStyleFrame(nullptr)
1549
  , mDocElementContainingBlock(nullptr)
1550
  , mPageSequenceFrame(nullptr)
1551
  , mFirstFreeFCItem(nullptr)
1552
  , mFCItemsInUse(0)
1553
  , mCurrentDepth(0)
1554
  , mQuotesDirty(false)
1555
  , mCountersDirty(false)
1556
  , mIsDestroyingFrameTree(false)
1557
  , mHasRootAbsPosContainingBlock(false)
1558
  , mAlwaysCreateFramesForIgnorableWhitespace(false)
1559
0
{
1560
#ifdef DEBUG
1561
  static bool gFirstTime = true;
1562
  if (gFirstTime) {
1563
    gFirstTime = false;
1564
    char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1565
    if (flags) {
1566
      bool error = false;
1567
      for (;;) {
1568
        char* comma = PL_strchr(flags, ',');
1569
        if (comma)
1570
          *comma = '\0';
1571
1572
        bool found = false;
1573
        FrameCtorDebugFlags* flag = gFlags;
1574
        FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1575
        while (flag < limit) {
1576
          if (PL_strcasecmp(flag->name, flags) == 0) {
1577
            *(flag->on) = true;
1578
            printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag->name);
1579
            found = true;
1580
            break;
1581
          }
1582
          ++flag;
1583
        }
1584
1585
        if (! found)
1586
          error = true;
1587
1588
        if (! comma)
1589
          break;
1590
1591
        *comma = ',';
1592
        flags = comma + 1;
1593
      }
1594
1595
      if (error) {
1596
        printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1597
        FrameCtorDebugFlags* flag = gFlags;
1598
        FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1599
        while (flag < limit) {
1600
          printf("  %s\n", flag->name);
1601
          ++flag;
1602
        }
1603
        printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1604
        printf("names (no whitespace)\n");
1605
      }
1606
    }
1607
  }
1608
#endif
1609
}
1610
1611
void
1612
nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
1613
0
{
1614
0
  if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
1615
0
    if (mQuoteList.DestroyNodesFor(aFrame))
1616
0
      QuotesDirty();
1617
0
  }
1618
0
1619
0
  if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1620
0
      mCounterManager.DestroyNodesFor(aFrame)) {
1621
0
    // Technically we don't need to update anything if we destroyed only
1622
0
    // USE nodes.  However, this is unlikely to happen in the real world
1623
0
    // since USE nodes generally go along with INCREMENT nodes.
1624
0
    CountersDirty();
1625
0
  }
1626
0
1627
0
  RestyleManager()->NotifyDestroyingFrame(aFrame);
1628
0
}
1629
1630
struct nsGenConInitializer {
1631
  nsAutoPtr<nsGenConNode> mNode;
1632
  nsGenConList*           mList;
1633
  void (nsCSSFrameConstructor::*mDirtyAll)();
1634
1635
  nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
1636
                      void (nsCSSFrameConstructor::*aDirtyAll)())
1637
0
    : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {}
1638
};
1639
1640
already_AddRefed<nsIContent>
1641
nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState,
1642
                                            const nsString& aString,
1643
                                            RefPtr<nsTextNode>* aText,
1644
                                            nsGenConInitializer* aInitializer)
1645
0
{
1646
0
  RefPtr<nsTextNode> content = new nsTextNode(mDocument->NodeInfoManager());
1647
0
  content->SetText(aString, false);
1648
0
  if (aText) {
1649
0
    *aText = content;
1650
0
  }
1651
0
  if (aInitializer) {
1652
0
    content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
1653
0
                         nsINode::DeleteProperty<nsGenConInitializer>);
1654
0
    aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
1655
0
  }
1656
0
  return content.forget();
1657
0
}
1658
1659
already_AddRefed<nsIContent>
1660
nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
1661
                                              const Element& aOriginatingElement,
1662
                                              ComputedStyle& aPseudoStyle,
1663
                                              uint32_t aContentIndex)
1664
0
{
1665
0
  // Get the content value
1666
0
  const nsStyleContentData& data =
1667
0
    aPseudoStyle.StyleContent()->ContentAt(aContentIndex);
1668
0
  const StyleContentType type = data.GetType();
1669
0
1670
0
  switch (type) {
1671
0
    case StyleContentType::Image:
1672
0
      return GeneratedImageContent::Create(*mDocument, aContentIndex);
1673
0
1674
0
    case StyleContentType::String:
1675
0
      return CreateGenConTextNode(aState,
1676
0
                                  nsDependentString(data.GetString()),
1677
0
                                  nullptr, nullptr);
1678
0
1679
0
    case StyleContentType::Attr: {
1680
0
      const nsStyleContentAttr* attr = data.GetAttr();
1681
0
      RefPtr<nsAtom> attrName = attr->mName;
1682
0
      int32_t attrNameSpace = kNameSpaceID_None;
1683
0
      if (RefPtr<nsAtom> ns = attr->mNamespaceURL) {
1684
0
        nsresult rv =
1685
0
          nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns.forget(), attrNameSpace);
1686
0
        NS_ENSURE_SUCCESS(rv, nullptr);
1687
0
      }
1688
0
1689
0
      if (mDocument->IsHTMLDocument() && aOriginatingElement.IsHTMLElement()) {
1690
0
        ToLowerCaseASCII(attrName);
1691
0
      }
1692
0
1693
0
      nsCOMPtr<nsIContent> content;
1694
0
      NS_NewAttributeContent(mDocument->NodeInfoManager(),
1695
0
                             attrNameSpace,
1696
0
                             attrName,
1697
0
                             getter_AddRefs(content));
1698
0
      return content.forget();
1699
0
    }
1700
0
1701
0
    case StyleContentType::Counter:
1702
0
    case StyleContentType::Counters: {
1703
0
      nsStyleContentData::CounterFunction* counters = data.GetCounters();
1704
0
      nsCounterList* counterList =
1705
0
        mCounterManager.CounterListFor(counters->mIdent);
1706
0
1707
0
      nsCounterUseNode* node =
1708
0
        new nsCounterUseNode(counters, aContentIndex,
1709
0
                             type == StyleContentType::Counters);
1710
0
1711
0
      nsGenConInitializer* initializer =
1712
0
        new nsGenConInitializer(node, counterList,
1713
0
                                &nsCSSFrameConstructor::CountersDirty);
1714
0
      return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1715
0
                                  initializer);
1716
0
    }
1717
0
1718
0
    case StyleContentType::OpenQuote:
1719
0
    case StyleContentType::CloseQuote:
1720
0
    case StyleContentType::NoOpenQuote:
1721
0
    case StyleContentType::NoCloseQuote: {
1722
0
      nsQuoteNode* node =
1723
0
        new nsQuoteNode(type, aContentIndex);
1724
0
1725
0
      nsGenConInitializer* initializer =
1726
0
        new nsGenConInitializer(node, &mQuoteList,
1727
0
                                &nsCSSFrameConstructor::QuotesDirty);
1728
0
      return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1729
0
                                  initializer);
1730
0
    }
1731
0
1732
0
    case StyleContentType::AltContent: {
1733
0
      // Use the "alt" attribute; if that fails and the node is an HTML
1734
0
      // <input>, try the value attribute and then fall back to some default
1735
0
      // localized text we have.
1736
0
      // XXX what if the 'alt' attribute is added later, how will we
1737
0
      // detect that and do the right thing here?
1738
0
      if (aOriginatingElement.HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
1739
0
        nsCOMPtr<nsIContent> content;
1740
0
        NS_NewAttributeContent(mDocument->NodeInfoManager(),
1741
0
                               kNameSpaceID_None,
1742
0
                               nsGkAtoms::alt,
1743
0
                               getter_AddRefs(content));
1744
0
        return content.forget();
1745
0
      }
1746
0
1747
0
      if (aOriginatingElement.IsHTMLElement(nsGkAtoms::input)) {
1748
0
        if (aOriginatingElement.HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
1749
0
          nsCOMPtr<nsIContent> content;
1750
0
          NS_NewAttributeContent(mDocument->NodeInfoManager(),
1751
0
                                 kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content));
1752
0
          return content.forget();
1753
0
        }
1754
0
1755
0
        nsAutoString temp;
1756
0
        nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
1757
0
                                           "Submit", temp);
1758
0
        return CreateGenConTextNode(aState, temp, nullptr, nullptr);
1759
0
      }
1760
0
1761
0
      break;
1762
0
    }
1763
0
1764
0
    case StyleContentType::Uninitialized:
1765
0
      MOZ_ASSERT_UNREACHABLE("uninitialized content type");
1766
0
      return nullptr;
1767
0
  }
1768
0
1769
0
  return nullptr;
1770
0
}
1771
1772
/*
1773
 * aParentFrame - the frame that should be the parent of the generated
1774
 *   content.  This is the frame for the corresponding content node,
1775
 *   which must not be a leaf frame.
1776
 *
1777
 * Any items created are added to aItems.
1778
 *
1779
 * We create an XML element (tag _moz_generated_content_before or
1780
 * _moz_generated_content_after) representing the pseudoelement. We
1781
 * create a DOM node for each 'content' item and make those nodes the
1782
 * children of the XML element. Then we create a frame subtree for
1783
 * the XML element as if it were a regular child of
1784
 * aParentFrame/aParentContent, giving the XML element the ::before or
1785
 * ::after style.
1786
 */
1787
void
1788
nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState,
1789
                                                  nsContainerFrame* aParentFrame,
1790
                                                  Element& aOriginatingElement,
1791
                                                  ComputedStyle& aStyle,
1792
                                                  CSSPseudoElementType aPseudoElement,
1793
                                                  FrameConstructionItemList& aItems)
1794
0
{
1795
0
  MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before ||
1796
0
             aPseudoElement == CSSPseudoElementType::after,
1797
0
             "unexpected aPseudoElement");
1798
0
1799
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
1800
0
1801
0
  // Probe for the existence of the pseudo-element
1802
0
  RefPtr<ComputedStyle> pseudoStyle =
1803
0
    styleSet->ProbePseudoElementStyle(aOriginatingElement, aPseudoElement, &aStyle);
1804
0
  if (!pseudoStyle) {
1805
0
    return;
1806
0
  }
1807
0
1808
0
  bool isBefore = aPseudoElement == CSSPseudoElementType::before;
1809
0
1810
0
  // |ProbePseudoStyleFor| checked the 'display' property and the
1811
0
  // |ContentCount()| of the 'content' property for us.
1812
0
  nsAtom* elemName = isBefore ?
1813
0
    nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
1814
0
  RefPtr<NodeInfo> nodeInfo =
1815
0
    mDocument->NodeInfoManager()->GetNodeInfo(elemName,
1816
0
                                              nullptr,
1817
0
                                              kNameSpaceID_None,
1818
0
                                              nsINode::ELEMENT_NODE);
1819
0
  RefPtr<Element> container;
1820
0
  nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1821
0
  if (NS_FAILED(rv)) {
1822
0
    return;
1823
0
  }
1824
0
1825
0
  // Cleared when the pseudo is unbound from the tree, so no need to store a
1826
0
  // strong reference, nor a destructor.
1827
0
  nsAtom* property = isBefore
1828
0
    ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
1829
0
  aOriginatingElement.SetProperty(property, container.get());
1830
0
1831
0
  container->SetIsNativeAnonymousRoot();
1832
0
  container->SetPseudoElementType(aPseudoElement);
1833
0
1834
0
  // If the parent is in a shadow tree, make sure we don't
1835
0
  // bind with a document because shadow roots and its descendants
1836
0
  // are not in document.
1837
0
  nsIDocument* bindDocument =
1838
0
    aOriginatingElement.HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
1839
0
  rv = container->BindToTree(bindDocument,
1840
0
                             &aOriginatingElement,
1841
0
                             &aOriginatingElement);
1842
0
  if (NS_FAILED(rv)) {
1843
0
    container->UnbindFromTree();
1844
0
    return;
1845
0
  }
1846
0
1847
0
  // Servo has already eagerly computed the style for the container, so we can
1848
0
  // just stick the style on the element and avoid an additional traversal.
1849
0
  //
1850
0
  // We don't do this for pseudos that may trigger animations or transitions,
1851
0
  // since those need to be kicked off by the traversal machinery.
1852
0
  if (!Servo_ComputedValues_SpecifiesAnimationsOrTransitions(pseudoStyle)) {
1853
0
    Servo_SetExplicitStyle(container, pseudoStyle);
1854
0
  } else {
1855
0
    // If animations are involved, we avoid the SetExplicitStyle optimization
1856
0
    // above. We need to grab style with animations from the pseudo element and
1857
0
    // replace old one.
1858
0
    mPresShell->StyleSet()->StyleNewSubtree(container);
1859
0
    pseudoStyle = styleSet->ResolveServoStyle(*container);
1860
0
  }
1861
0
1862
0
  uint32_t contentCount = pseudoStyle->StyleContent()->ContentCount();
1863
0
  for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
1864
0
    nsCOMPtr<nsIContent> content =
1865
0
      CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, contentIndex);
1866
0
    if (!content) {
1867
0
      continue;
1868
0
    }
1869
0
    // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
1870
0
    // here; it would get set under AppendChildTo.  But AppendChildTo might
1871
0
    // think that we're going from not being anonymous to being anonymous and
1872
0
    // do some extra work; setting the flag here avoids that.
1873
0
    content->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1874
0
    container->AppendChildTo(content, false);
1875
0
    if (auto* element = Element::FromNode(content)) {
1876
0
      // If we created any children elements, Servo needs to traverse them, but
1877
0
      // the root is already set up.
1878
0
      mPresShell->StyleSet()->StyleNewSubtree(element);
1879
0
    }
1880
0
  }
1881
0
1882
0
  AddFrameConstructionItemsInternal(aState,
1883
0
                                    container,
1884
0
                                    aParentFrame,
1885
0
                                    true,
1886
0
                                    pseudoStyle,
1887
0
                                    ITEM_IS_GENERATED_CONTENT,
1888
0
                                    aItems);
1889
0
}
1890
1891
/****************************************************
1892
 **  BEGIN TABLE SECTION
1893
 ****************************************************/
1894
1895
// The term pseudo frame is being used instead of anonymous frame, since anonymous
1896
// frame has been used elsewhere to refer to frames that have generated content
1897
1898
// Return whether the given frame is a table pseudo-frame. Note that
1899
// cell-content and table-outer frames have pseudo-types, but are always
1900
// created, even for non-anonymous cells and tables respectively.  So for those
1901
// we have to examine the cell or table frame to see whether it's a pseudo
1902
// frame. In particular, a lone table caption will have a table wrapper as its
1903
// parent, but will also trigger construction of an empty inner table, which
1904
// will be the one we can examine to see whether the wrapper was a pseudo-frame.
1905
static bool
1906
IsTablePseudo(nsIFrame* aFrame)
1907
0
{
1908
0
  nsAtom* pseudoType = aFrame->Style()->GetPseudo();
1909
0
  return pseudoType &&
1910
0
    (pseudoType == nsCSSAnonBoxes::table() ||
1911
0
     pseudoType == nsCSSAnonBoxes::inlineTable() ||
1912
0
     pseudoType == nsCSSAnonBoxes::tableColGroup() ||
1913
0
     pseudoType == nsCSSAnonBoxes::tableRowGroup() ||
1914
0
     pseudoType == nsCSSAnonBoxes::tableRow() ||
1915
0
     pseudoType == nsCSSAnonBoxes::tableCell() ||
1916
0
     (pseudoType == nsCSSAnonBoxes::cellContent() &&
1917
0
      aFrame->GetParent()->Style()->GetPseudo() ==
1918
0
        nsCSSAnonBoxes::tableCell()) ||
1919
0
     (pseudoType == nsCSSAnonBoxes::tableWrapper() &&
1920
0
      (aFrame->PrincipalChildList().FirstChild()->Style()->GetPseudo() ==
1921
0
         nsCSSAnonBoxes::table() ||
1922
0
       aFrame->PrincipalChildList().FirstChild()->Style()->GetPseudo() ==
1923
0
         nsCSSAnonBoxes::inlineTable())));
1924
0
}
1925
1926
static bool
1927
IsRubyPseudo(nsIFrame* aFrame)
1928
0
{
1929
0
  return RubyUtils::IsRubyPseudo(aFrame->Style()->GetPseudo());
1930
0
}
1931
1932
static bool
1933
IsTableOrRubyPseudo(nsIFrame* aFrame)
1934
0
{
1935
0
  return IsTablePseudo(aFrame) || IsRubyPseudo(aFrame);
1936
0
}
1937
1938
/* static */
1939
nsCSSFrameConstructor::ParentType
1940
nsCSSFrameConstructor::GetParentType(LayoutFrameType aFrameType)
1941
0
{
1942
0
  if (aFrameType == LayoutFrameType::Table) {
1943
0
    return eTypeTable;
1944
0
  }
1945
0
  if (aFrameType == LayoutFrameType::TableRowGroup) {
1946
0
    return eTypeRowGroup;
1947
0
  }
1948
0
  if (aFrameType == LayoutFrameType::TableRow) {
1949
0
    return eTypeRow;
1950
0
  }
1951
0
  if (aFrameType == LayoutFrameType::TableColGroup) {
1952
0
    return eTypeColGroup;
1953
0
  }
1954
0
  if (aFrameType == LayoutFrameType::RubyBaseContainer) {
1955
0
    return eTypeRubyBaseContainer;
1956
0
  }
1957
0
  if (aFrameType == LayoutFrameType::RubyTextContainer) {
1958
0
    return eTypeRubyTextContainer;
1959
0
  }
1960
0
  if (aFrameType == LayoutFrameType::Ruby) {
1961
0
    return eTypeRuby;
1962
0
  }
1963
0
1964
0
  return eTypeBlock;
1965
0
}
1966
1967
static nsContainerFrame*
1968
AdjustCaptionParentFrame(nsContainerFrame* aParentFrame)
1969
0
{
1970
0
  if (aParentFrame->IsTableFrame()) {
1971
0
    return aParentFrame->GetParent();
1972
0
  }
1973
0
  return aParentFrame;
1974
0
}
1975
1976
/**
1977
 * If the parent frame is a |tableFrame| and the child is a
1978
 * |captionFrame|, then we want to insert the frames beneath the
1979
 * |tableFrame|'s parent frame. Returns |true| if the parent frame
1980
 * needed to be fixed up.
1981
 */
1982
static bool
1983
GetCaptionAdjustedParent(nsContainerFrame*  aParentFrame,
1984
                         const nsIFrame*    aChildFrame,
1985
                         nsContainerFrame** aAdjParentFrame)
1986
0
{
1987
0
  *aAdjParentFrame = aParentFrame;
1988
0
  bool haveCaption = false;
1989
0
1990
0
  if (aChildFrame->IsTableCaption()) {
1991
0
    haveCaption = true;
1992
0
    *aAdjParentFrame = ::AdjustCaptionParentFrame(aParentFrame);
1993
0
  }
1994
0
  return haveCaption;
1995
0
}
1996
1997
void
1998
nsCSSFrameConstructor::AdjustParentFrame(nsContainerFrame**           aParentFrame,
1999
                                         const FrameConstructionData* aFCData,
2000
                                         ComputedStyle*              aComputedStyle)
2001
0
{
2002
0
  MOZ_ASSERT(aComputedStyle, "Must have child's style");
2003
0
  MOZ_ASSERT(aFCData, "Must have frame construction data");
2004
0
2005
0
  bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0);
2006
0
2007
0
  if (tablePart && aComputedStyle->StyleDisplay()->mDisplay ==
2008
0
      StyleDisplay::TableCaption) {
2009
0
    *aParentFrame = ::AdjustCaptionParentFrame(*aParentFrame);
2010
0
  }
2011
0
}
2012
2013
// Pull all the captions present in aItems out  into aCaptions
2014
static void
2015
PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions)
2016
0
{
2017
0
  nsIFrame* child = aItems.FirstChild();
2018
0
  while (child) {
2019
0
    nsIFrame* nextSibling = child->GetNextSibling();
2020
0
    if (child->IsTableCaption()) {
2021
0
      aItems.RemoveFrame(child);
2022
0
      aCaptions.AddChild(child);
2023
0
    }
2024
0
    child = nextSibling;
2025
0
  }
2026
0
}
2027
2028
2029
// Construct the outer, inner table frames and the children frames for the table.
2030
// XXX Page break frames for pseudo table frames are not constructed to avoid the risk
2031
// associated with revising the pseudo frame mechanism. The long term solution
2032
// of having frames handle page-break-before/after will solve the problem.
2033
nsIFrame*
2034
nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
2035
                                      FrameConstructionItem&   aItem,
2036
                                      nsContainerFrame*        aParentFrame,
2037
                                      const nsStyleDisplay*    aDisplay,
2038
                                      nsFrameItems&            aFrameItems)
2039
0
{
2040
0
  MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::Table ||
2041
0
             aDisplay->mDisplay == StyleDisplay::InlineTable,
2042
0
             "Unexpected call");
2043
0
2044
0
  nsIContent* const content = aItem.mContent;
2045
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
2046
0
  const bool isMathMLContent = content->IsMathMLElement();
2047
0
2048
0
  // create the pseudo SC for the table wrapper as a child of the inner SC
2049
0
  RefPtr<ComputedStyle> outerComputedStyle;
2050
0
  outerComputedStyle = mPresShell->StyleSet()->
2051
0
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::tableWrapper(),
2052
0
                                       computedStyle);
2053
0
2054
0
  // Create the table wrapper frame which holds the caption and inner table frame
2055
0
  nsContainerFrame* newFrame;
2056
0
  if (isMathMLContent)
2057
0
    newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerComputedStyle);
2058
0
  else
2059
0
    newFrame = NS_NewTableWrapperFrame(mPresShell, outerComputedStyle);
2060
0
2061
0
  nsContainerFrame* geometricParent =
2062
0
    aState.GetGeometricParent(*outerComputedStyle->StyleDisplay(),
2063
0
                              aParentFrame);
2064
0
2065
0
  // Init the table wrapper frame
2066
0
  InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2067
0
2068
0
  // Create the inner table frame
2069
0
  nsContainerFrame* innerFrame;
2070
0
  if (isMathMLContent)
2071
0
    innerFrame = NS_NewMathMLmtableFrame(mPresShell, computedStyle);
2072
0
  else
2073
0
    innerFrame = NS_NewTableFrame(mPresShell, computedStyle);
2074
0
2075
0
  InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2076
0
  innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2077
0
2078
0
  // Put the newly created frames into the right child list
2079
0
  SetInitialSingleChild(newFrame, innerFrame);
2080
0
2081
0
  aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
2082
0
2083
0
  if (!mRootElementFrame) {
2084
0
    // The frame we're constructing will be the root element frame.
2085
0
    // Set mRootElementFrame before processing children.
2086
0
    mRootElementFrame = newFrame;
2087
0
  }
2088
0
2089
0
  nsFrameItems childItems;
2090
0
2091
0
  // Process children
2092
0
  nsFrameConstructorSaveState absoluteSaveState;
2093
0
  const nsStyleDisplay* display = outerComputedStyle->StyleDisplay();
2094
0
2095
0
  // Mark the table frame as an absolute container if needed
2096
0
  newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2097
0
  if (display->IsAbsPosContainingBlock(newFrame)) {
2098
0
    aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2099
0
  }
2100
0
  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2101
0
    ConstructFramesFromItemList(aState, aItem.mChildItems,
2102
0
                                innerFrame,
2103
0
                                aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
2104
0
                                childItems);
2105
0
  } else {
2106
0
    ProcessChildren(aState, content, computedStyle, innerFrame,
2107
0
                    true, childItems, false, aItem.mPendingBinding);
2108
0
  }
2109
0
2110
0
  nsFrameItems captionItems;
2111
0
  PullOutCaptionFrames(childItems, captionItems);
2112
0
2113
0
  // Set the inner table frame's initial primary list
2114
0
  innerFrame->SetInitialChildList(kPrincipalList, childItems);
2115
0
2116
0
  // Set the table wrapper frame's secondary childlist lists
2117
0
  if (captionItems.NotEmpty()) {
2118
0
    newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems);
2119
0
  }
2120
0
2121
0
  return newFrame;
2122
0
}
2123
2124
static void
2125
MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState&     aState,
2126
                                             const nsStyleDisplay*        aDisplay,
2127
                                             nsFrameConstructorSaveState& aAbsSaveState,
2128
                                             nsContainerFrame*            aFrame)
2129
0
{
2130
0
  // If we're positioned, then we need to become an absolute containing block
2131
0
  // for any absolutely positioned children and register for post-reflow fixup.
2132
0
  //
2133
0
  // Note that usually if a frame type can be an absolute containing block, we
2134
0
  // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not.
2135
0
  // However, in this case flag serves the additional purpose of indicating that
2136
0
  // the frame was registered with its table frame. This allows us to avoid the
2137
0
  // overhead of unregistering the frame in most cases.
2138
0
  if (aDisplay->IsAbsPosContainingBlock(aFrame)) {
2139
0
    aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2140
0
    aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2141
0
    nsTableFrame::RegisterPositionedTablePart(aFrame);
2142
0
  }
2143
0
}
2144
2145
nsIFrame*
2146
nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
2147
                                                   FrameConstructionItem&   aItem,
2148
                                                   nsContainerFrame*        aParentFrame,
2149
                                                   const nsStyleDisplay*    aDisplay,
2150
                                                   nsFrameItems&            aFrameItems)
2151
0
{
2152
0
  MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableRow ||
2153
0
             aDisplay->mDisplay == StyleDisplay::TableRowGroup ||
2154
0
             aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
2155
0
             aDisplay->mDisplay == StyleDisplay::TableHeaderGroup,
2156
0
             "Not a row or row group");
2157
0
  MOZ_ASSERT(aItem.mComputedStyle->StyleDisplay() == aDisplay,
2158
0
             "Display style doesn't match style");
2159
0
  nsIContent* const content = aItem.mContent;
2160
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
2161
0
2162
0
  nsContainerFrame* newFrame;
2163
0
  if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2164
0
    if (content->IsMathMLElement())
2165
0
      newFrame = NS_NewMathMLmtrFrame(mPresShell, computedStyle);
2166
0
    else
2167
0
      newFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
2168
0
  } else {
2169
0
    newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
2170
0
  }
2171
0
2172
0
  InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2173
0
2174
0
  nsFrameConstructorSaveState absoluteSaveState;
2175
0
  MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2176
0
                                               absoluteSaveState,
2177
0
                                               newFrame);
2178
0
2179
0
  nsFrameItems childItems;
2180
0
  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2181
0
    ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
2182
0
                                aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
2183
0
                                childItems);
2184
0
  } else {
2185
0
    ProcessChildren(aState, content, computedStyle, newFrame,
2186
0
                    true, childItems, false, aItem.mPendingBinding);
2187
0
  }
2188
0
2189
0
  newFrame->SetInitialChildList(kPrincipalList, childItems);
2190
0
  aFrameItems.AddChild(newFrame);
2191
0
  return newFrame;
2192
0
}
2193
2194
nsIFrame*
2195
nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState& aState,
2196
                                         FrameConstructionItem&   aItem,
2197
                                         nsContainerFrame*        aParentFrame,
2198
                                         const nsStyleDisplay*    aStyleDisplay,
2199
                                         nsFrameItems&            aFrameItems)
2200
0
{
2201
0
  nsIContent* const content = aItem.mContent;
2202
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
2203
0
2204
0
  nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, computedStyle);
2205
0
  InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2206
0
2207
0
  NS_ASSERTION(colFrame->Style() == computedStyle, "Unexpected style");
2208
0
2209
0
  aFrameItems.AddChild(colFrame);
2210
0
2211
0
  // construct additional col frames if the col frame has a span > 1
2212
0
  int32_t span = colFrame->GetSpan();
2213
0
  for (int32_t spanX = 1; spanX < span; spanX++) {
2214
0
    nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, computedStyle);
2215
0
    InitAndRestoreFrame(aState, content, aParentFrame, newCol, false);
2216
0
    aFrameItems.LastChild()->SetNextContinuation(newCol);
2217
0
    newCol->SetPrevContinuation(aFrameItems.LastChild());
2218
0
    aFrameItems.AddChild(newCol);
2219
0
    newCol->SetColType(eColAnonymousCol);
2220
0
  }
2221
0
2222
0
  return colFrame;
2223
0
}
2224
2225
nsIFrame*
2226
nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState,
2227
                                          FrameConstructionItem&   aItem,
2228
                                          nsContainerFrame*        aParentFrame,
2229
                                          const nsStyleDisplay*    aDisplay,
2230
                                          nsFrameItems&            aFrameItems)
2231
0
{
2232
0
  MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableCell,
2233
0
             "Unexpected call");
2234
0
2235
0
  nsIContent* const content = aItem.mContent;
2236
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
2237
0
  const bool isMathMLContent = content->IsMathMLElement();
2238
0
2239
0
  nsTableFrame* tableFrame =
2240
0
    static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2241
0
  nsContainerFrame* newFrame;
2242
0
  // <mtable> is border separate in mathml.css and the MathML code doesn't implement
2243
0
  // border collapse. For those users who style <mtable> with border collapse,
2244
0
  // give them the default non-MathML table frames that understand border collapse.
2245
0
  // This won't break us because MathML table frames are all subclasses of the default
2246
0
  // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
2247
0
  // What will happen is just that non-MathML frames won't understand MathML attributes
2248
0
  // and will therefore miss the special handling that the MathML code does.
2249
0
  if (isMathMLContent && !tableFrame->IsBorderCollapse()) {
2250
0
    newFrame = NS_NewMathMLmtdFrame(mPresShell, computedStyle, tableFrame);
2251
0
  } else {
2252
0
    // Warning: If you change this and add a wrapper frame around table cell
2253
0
    // frames, make sure Bug 368554 doesn't regress!
2254
0
    // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2255
0
    newFrame = NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
2256
0
  }
2257
0
2258
0
  // Initialize the table cell frame
2259
0
  InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2260
0
  newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2261
0
2262
0
  // Resolve pseudo style and initialize the body cell frame
2263
0
  RefPtr<ComputedStyle> innerPseudoStyle;
2264
0
  innerPseudoStyle = mPresShell->StyleSet()->
2265
0
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::cellContent(),
2266
0
                                       computedStyle);
2267
0
2268
0
  // Create a block frame that will format the cell's content
2269
0
  bool isBlock;
2270
0
  nsContainerFrame* cellInnerFrame;
2271
0
  if (isMathMLContent) {
2272
0
    cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2273
0
    isBlock = false;
2274
0
  } else {
2275
0
    cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
2276
0
    isBlock = true;
2277
0
  }
2278
0
2279
0
  InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame);
2280
0
2281
0
  nsFrameConstructorSaveState absoluteSaveState;
2282
0
  MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
2283
0
                                               absoluteSaveState,
2284
0
                                               newFrame);
2285
0
2286
0
  nsFrameItems childItems;
2287
0
  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2288
0
    // Need to push ourselves as a float containing block.
2289
0
    // XXXbz it might be nice to work on getting the parent
2290
0
    // FrameConstructionItem down into ProcessChildren and just making use of
2291
0
    // the push there, but that's a bit of work.
2292
0
    nsFrameConstructorSaveState floatSaveState;
2293
0
    if (!isBlock) { /* MathML case */
2294
0
      aState.PushFloatContainingBlock(nullptr, floatSaveState);
2295
0
    } else {
2296
0
      aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
2297
0
    }
2298
0
2299
0
    ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
2300
0
                                aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
2301
0
                                childItems);
2302
0
  } else {
2303
0
    // Process the child content
2304
0
    ProcessChildren(aState, content, computedStyle, cellInnerFrame,
2305
0
                    true, childItems, isBlock, aItem.mPendingBinding);
2306
0
  }
2307
0
2308
0
  cellInnerFrame->SetInitialChildList(kPrincipalList, childItems);
2309
0
  SetInitialSingleChild(newFrame, cellInnerFrame);
2310
0
  aFrameItems.AddChild(newFrame);
2311
0
  return newFrame;
2312
0
}
2313
2314
static inline bool
2315
NeedFrameFor(const nsFrameConstructorState& aState,
2316
             nsIFrame*   aParentFrame,
2317
             nsIContent* aChildContent)
2318
0
{
2319
0
  // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2320
0
  // Remove it once that's fixed.
2321
0
  MOZ_ASSERT(!aChildContent->GetPrimaryFrame() ||
2322
0
             aState.mCreatingExtraFrames ||
2323
0
             aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
2324
0
             "Why did we get called?");
2325
0
2326
0
  // don't create a whitespace frame if aParentFrame doesn't want it.
2327
0
  // always create frames for children in generated content. counter(),
2328
0
  // quotes, and attr() content can easily change dynamically and we don't
2329
0
  // want to be reconstructing frames. It's not even clear that these
2330
0
  // should be considered ignorable just because they evaluate to
2331
0
  // whitespace.
2332
0
2333
0
  // We could handle all this in CreateNeededPseudoContainers or some other
2334
0
  // place after we build our frame construction items, but that would involve
2335
0
  // creating frame construction items for whitespace kids of
2336
0
  // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2337
0
  // all anyway, and involve an extra walk down the frame construction item
2338
0
  // list.
2339
0
  if ((aParentFrame &&
2340
0
       (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
2341
0
        aParentFrame->IsGeneratedContentFrame())) ||
2342
0
      !aChildContent->IsText()) {
2343
0
    return true;
2344
0
  }
2345
0
2346
0
  aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2347
0
                          NS_REFRAME_IF_WHITESPACE);
2348
0
  return !aChildContent->TextIsOnlyWhitespace();
2349
0
}
2350
2351
/***********************************************
2352
 * END TABLE SECTION
2353
 ***********************************************/
2354
2355
nsIFrame*
2356
nsCSSFrameConstructor::ConstructDocElementFrame(Element*                 aDocElement,
2357
                                                nsILayoutHistoryState*   aFrameState)
2358
0
{
2359
0
  MOZ_ASSERT(GetRootFrame(),
2360
0
             "No viewport?  Someone forgot to call ConstructRootFrame!");
2361
0
  MOZ_ASSERT(!mDocElementContainingBlock,
2362
0
             "Shouldn't have a doc element containing block here");
2363
0
2364
0
  // Resolve a new style for the viewport since it may be affected by a new root
2365
0
  // element style (e.g. a propagated 'direction').
2366
0
  //
2367
0
  // @see ComputedStyle::ApplyStyleFixups
2368
0
  {
2369
0
    RefPtr<ComputedStyle> sc = mPresShell->StyleSet()->
2370
0
      ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport(), nullptr);
2371
0
    GetRootFrame()->SetComputedStyleWithoutNotification(sc);
2372
0
  }
2373
0
2374
0
  // Make sure to call UpdateViewportScrollStylesOverride before
2375
0
  // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2376
0
  // properly.
2377
0
  DebugOnly<nsIContent*> propagatedScrollFrom;
2378
0
  if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2379
0
    propagatedScrollFrom = presContext->UpdateViewportScrollStylesOverride();
2380
0
  }
2381
0
2382
0
  SetUpDocElementContainingBlock(aDocElement);
2383
0
2384
0
  NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
2385
0
  nsFrameConstructorState state(mPresShell,
2386
0
                                GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2387
0
                                nullptr,
2388
0
                                nullptr, do_AddRef(aFrameState));
2389
0
2390
0
  // XXXbz why, exactly?
2391
0
  if (!mTempFrameTreeState)
2392
0
    state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
2393
0
2394
0
  // --------- CREATE AREA OR BOX FRAME -------
2395
0
  ServoStyleSet* set = mPresShell->StyleSet();
2396
0
  // Ensure the document element is styled at this point.
2397
0
  if (!aDocElement->HasServoData()) {
2398
0
    // NOTE(emilio): If the root has a non-null binding, we'll stop at the
2399
0
    // document element and won't process any children, loading the bindings
2400
0
    // (or failing to do so) will take care of the rest.
2401
0
    set->StyleNewSubtree(aDocElement);
2402
0
  }
2403
0
2404
0
  RefPtr<ComputedStyle> computedStyle =
2405
0
    mPresShell->StyleSet()->ResolveServoStyle(*aDocElement);
2406
0
2407
0
  const nsStyleDisplay* display = computedStyle->StyleDisplay();
2408
0
2409
0
  // Ensure that our XBL bindings are installed.
2410
0
  //
2411
0
  // FIXME(emilio): Can we remove support for bindings on the root?
2412
0
  if (display->mBinding) {
2413
0
    // Get the XBL loader.
2414
0
    nsresult rv;
2415
0
    bool resolveStyle;
2416
0
2417
0
    nsXBLService* xblService = nsXBLService::GetInstance();
2418
0
    if (!xblService) {
2419
0
      return nullptr;
2420
0
    }
2421
0
2422
0
    RefPtr<nsXBLBinding> binding;
2423
0
    rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
2424
0
                                  display->mBinding->mExtraData->GetPrincipal(),
2425
0
                                  getter_AddRefs(binding), &resolveStyle);
2426
0
    if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
2427
0
      // Binding will load asynchronously.
2428
0
      return nullptr;
2429
0
    }
2430
0
2431
0
    if (binding) {
2432
0
      // For backwards compat, keep firing the root's constructor
2433
0
      // after all of its kids' constructors.  So tell the binding
2434
0
      // manager about it right now.
2435
0
      mDocument->BindingManager()->AddToAttachedQueue(binding);
2436
0
    }
2437
0
2438
0
    if (resolveStyle) {
2439
0
      computedStyle = mPresShell->StyleSet()->ResolveServoStyle(*aDocElement);
2440
0
      display = computedStyle->StyleDisplay();
2441
0
    }
2442
0
  }
2443
0
2444
0
  // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2445
0
2446
0
  NS_ASSERTION(!display->IsScrollableOverflow() ||
2447
0
               state.mPresContext->IsPaginated() ||
2448
0
               propagatedScrollFrom == aDocElement,
2449
0
               "Scrollbars should have been propagated to the viewport");
2450
0
2451
0
  if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
2452
0
    return nullptr;
2453
0
  }
2454
0
2455
0
  // Make sure to start any background image loads for the root element now.
2456
0
  computedStyle->StartBackgroundImageLoads();
2457
0
2458
0
  nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
2459
0
  if (mHasRootAbsPosContainingBlock) {
2460
0
    // Push the absolute containing block now so we can absolutely position
2461
0
    // the root element
2462
0
    mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2463
0
    state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2464
0
                                      mDocElementContainingBlock,
2465
0
                                      docElementContainingBlockAbsoluteSaveState);
2466
0
  }
2467
0
2468
0
  // The rules from CSS 2.1, section 9.2.4, have already been applied
2469
0
  // by the style system, so we can assume that display->mDisplay is
2470
0
  // either NONE, BLOCK, or TABLE.
2471
0
2472
0
  // contentFrame is the primary frame for the root element. newFrame
2473
0
  // is the frame that will be the child of the initial containing block.
2474
0
  // These are usually the same frame but they can be different, in
2475
0
  // particular if the root frame is positioned, in which case
2476
0
  // contentFrame is the out-of-flow frame and newFrame is the
2477
0
  // placeholder.
2478
0
  nsContainerFrame* contentFrame;
2479
0
  nsIFrame* newFrame;
2480
0
  bool processChildren = false;
2481
0
2482
0
  nsFrameConstructorSaveState absoluteSaveState;
2483
0
2484
0
  // Check whether we need to build a XUL box or SVG root frame
2485
0
#ifdef MOZ_XUL
2486
0
  if (aDocElement->IsXULElement()) {
2487
0
    contentFrame = NS_NewDocElementBoxFrame(mPresShell, computedStyle);
2488
0
    InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2489
0
                        contentFrame);
2490
0
    newFrame = contentFrame;
2491
0
    processChildren = true;
2492
0
  }
2493
0
  else
2494
0
#endif
2495
0
  if (aDocElement->IsSVGElement()) {
2496
0
    if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2497
0
      return nullptr;
2498
0
    }
2499
0
    // We're going to call the right function ourselves, so no need to give a
2500
0
    // function to this FrameConstructionData.
2501
0
2502
0
    // XXXbz on the other hand, if we converted this whole function to
2503
0
    // FrameConstructionData/Item, then we'd need the right function
2504
0
    // here... but would probably be able to get away with less code in this
2505
0
    // function in general.
2506
0
    // Use a null PendingBinding, since our binding is not in fact pending.
2507
0
    static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
2508
0
    AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
2509
0
                                   nullptr, do_AddRef(computedStyle), true);
2510
0
2511
0
    nsFrameItems frameItems;
2512
0
    contentFrame = static_cast<nsContainerFrame*>(
2513
0
      ConstructOuterSVG(state, item, mDocElementContainingBlock,
2514
0
                        computedStyle->StyleDisplay(),
2515
0
                        frameItems));
2516
0
    newFrame = frameItems.FirstChild();
2517
0
    NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2518
0
  } else if (display->mDisplay == StyleDisplay::Flex ||
2519
0
             display->mDisplay == StyleDisplay::WebkitBox ||
2520
0
             (StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
2521
0
              display->mDisplay == StyleDisplay::MozBox)) {
2522
0
    contentFrame = NS_NewFlexContainerFrame(mPresShell, computedStyle);
2523
0
    InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2524
0
                        contentFrame);
2525
0
    newFrame = contentFrame;
2526
0
    processChildren = true;
2527
0
2528
0
    newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2529
0
    if (display->IsAbsPosContainingBlock(newFrame)) {
2530
0
      state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2531
0
                                        absoluteSaveState);
2532
0
    }
2533
0
2534
0
  } else if (display->mDisplay == StyleDisplay::Grid) {
2535
0
    contentFrame = NS_NewGridContainerFrame(mPresShell, computedStyle);
2536
0
    InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
2537
0
                        contentFrame);
2538
0
    newFrame = contentFrame;
2539
0
    processChildren = true;
2540
0
2541
0
    newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2542
0
    if (display->IsAbsPosContainingBlock(newFrame)) {
2543
0
      state.PushAbsoluteContainingBlock(contentFrame, newFrame,
2544
0
                                        absoluteSaveState);
2545
0
    }
2546
0
  } else if (display->mDisplay == StyleDisplay::Table) {
2547
0
    // We're going to call the right function ourselves, so no need to give a
2548
0
    // function to this FrameConstructionData.
2549
0
2550
0
    // XXXbz on the other hand, if we converted this whole function to
2551
0
    // FrameConstructionData/Item, then we'd need the right function
2552
0
    // here... but would probably be able to get away with less code in this
2553
0
    // function in general.
2554
0
    // Use a null PendingBinding, since our binding is not in fact pending.
2555
0
    static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
2556
0
    AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
2557
0
                                   nullptr, do_AddRef(computedStyle), true);
2558
0
2559
0
    nsFrameItems frameItems;
2560
0
    // if the document is a table then just populate it.
2561
0
    contentFrame = static_cast<nsContainerFrame*>(
2562
0
      ConstructTable(state, item, mDocElementContainingBlock,
2563
0
                     computedStyle->StyleDisplay(),
2564
0
                     frameItems));
2565
0
    newFrame = frameItems.FirstChild();
2566
0
    NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2567
0
  } else {
2568
0
    MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||
2569
0
               display->mDisplay == StyleDisplay::FlowRoot,
2570
0
               "Unhandled display type for root element");
2571
0
    contentFrame = NS_NewBlockFormattingContext(mPresShell, computedStyle);
2572
0
    nsFrameItems frameItems;
2573
0
    // Use a null PendingBinding, since our binding is not in fact pending.
2574
0
    ConstructBlock(state, aDocElement,
2575
0
                   state.GetGeometricParent(*display,
2576
0
                                            mDocElementContainingBlock),
2577
0
                   mDocElementContainingBlock, computedStyle,
2578
0
                   &contentFrame, frameItems,
2579
0
                   display->IsAbsPosContainingBlock(contentFrame) ? contentFrame : nullptr,
2580
0
                   nullptr);
2581
0
    newFrame = frameItems.FirstChild();
2582
0
    NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2583
0
  }
2584
0
2585
0
  MOZ_ASSERT(newFrame);
2586
0
  MOZ_ASSERT(contentFrame);
2587
0
2588
0
  NS_ASSERTION(processChildren ? !mRootElementFrame :
2589
0
                 mRootElementFrame == contentFrame,
2590
0
               "unexpected mRootElementFrame");
2591
0
  mRootElementFrame = contentFrame;
2592
0
2593
0
  // Figure out which frame has the main style for the document element,
2594
0
  // assigning it to mRootElementStyleFrame.
2595
0
  // Backgrounds should be propagated from that frame to the viewport.
2596
0
  contentFrame->GetParentComputedStyle(&mRootElementStyleFrame);
2597
0
  bool isChild = mRootElementStyleFrame &&
2598
0
                 mRootElementStyleFrame->GetParent() == contentFrame;
2599
0
  if (!isChild) {
2600
0
    mRootElementStyleFrame = mRootElementFrame;
2601
0
  }
2602
0
2603
0
  if (processChildren) {
2604
0
    // Still need to process the child content
2605
0
    nsFrameItems childItems;
2606
0
2607
0
    NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) &&
2608
0
                 !contentFrame->IsFrameOfType(nsIFrame::eSVG),
2609
0
                 "Only XUL frames should reach here");
2610
0
    // Use a null PendingBinding, since our binding is not in fact pending.
2611
0
    ProcessChildren(state, aDocElement, computedStyle, contentFrame, true,
2612
0
                    childItems, false, nullptr);
2613
0
2614
0
    // Set the initial child lists
2615
0
    contentFrame->SetInitialChildList(kPrincipalList, childItems);
2616
0
  }
2617
0
2618
0
  // set the primary frame
2619
0
  aDocElement->SetPrimaryFrame(contentFrame);
2620
0
2621
0
  SetInitialSingleChild(mDocElementContainingBlock, newFrame);
2622
0
2623
0
  // Create frames for anonymous contents if there is a canvas frame.
2624
0
  if (mDocElementContainingBlock->IsCanvasFrame()) {
2625
0
    ConstructAnonymousContentForCanvas(state, mDocElementContainingBlock,
2626
0
                                       aDocElement);
2627
0
  }
2628
0
2629
0
  return newFrame;
2630
0
}
2631
2632
2633
nsIFrame*
2634
nsCSSFrameConstructor::ConstructRootFrame()
2635
0
{
2636
0
  AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ConstructRootFrame", LAYOUT);
2637
0
  AUTO_PROFILER_TRACING("Frame Construction", "ConstructRootFrame");
2638
0
  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
2639
0
2640
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
2641
0
2642
0
  // --------- BUILD VIEWPORT -----------
2643
0
  RefPtr<ComputedStyle> viewportPseudoStyle =
2644
0
    styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewport(),
2645
0
                                                 nullptr);
2646
0
  ViewportFrame* viewportFrame =
2647
0
    NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2648
0
2649
0
  // XXXbz do we _have_ to pass a null content pointer to that frame?
2650
0
  // Would it really kill us to pass in the root element or something?
2651
0
  // What would that break?
2652
0
  viewportFrame->Init(nullptr, nullptr, nullptr);
2653
0
2654
0
  viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2655
0
2656
0
  // Bind the viewport frame to the root view
2657
0
  nsView* rootView = mPresShell->GetViewManager()->GetRootView();
2658
0
  viewportFrame->SetView(rootView);
2659
0
2660
0
  viewportFrame->SyncFrameViewProperties(rootView);
2661
0
  nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
2662
0
                                         rootView, nullptr, nsContainerFrame::SET_ASYNC);
2663
0
2664
0
  // Make it an absolute container for fixed-pos elements
2665
0
  viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2666
0
  viewportFrame->MarkAsAbsoluteContainingBlock();
2667
0
2668
0
  return viewportFrame;
2669
0
}
2670
2671
void
2672
nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
2673
0
{
2674
0
  MOZ_ASSERT(aDocElement, "No element?");
2675
0
  MOZ_ASSERT(!aDocElement->GetParent(), "Not root content?");
2676
0
  MOZ_ASSERT(aDocElement->GetUncomposedDoc(), "Not in a document?");
2677
0
  MOZ_ASSERT(aDocElement->GetUncomposedDoc()->GetRootElement() ==
2678
0
                  aDocElement, "Not the root of the document?");
2679
0
2680
0
  /*
2681
0
    how the root frame hierarchy should look
2682
0
2683
0
  Galley presentation, non-XUL, with scrolling:
2684
0
2685
0
      ViewportFrame [fixed-cb]
2686
0
        nsHTMLScrollFrame
2687
0
          nsCanvasFrame [abs-cb]
2688
0
            root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2689
0
                                nsTableWrapperFrame, nsPlaceholderFrame)
2690
0
2691
0
  Galley presentation, XUL
2692
0
2693
0
      ViewportFrame [fixed-cb]
2694
0
        nsRootBoxFrame
2695
0
          root element frame (nsDocElementBoxFrame)
2696
0
2697
0
  Print presentation, non-XUL
2698
0
2699
0
      ViewportFrame
2700
0
        nsSimplePageSequenceFrame
2701
0
          nsPageFrame
2702
0
            nsPageContentFrame [fixed-cb]
2703
0
              nsCanvasFrame [abs-cb]
2704
0
                root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2705
0
                                    nsTableWrapperFrame, nsPlaceholderFrame)
2706
0
2707
0
  Print-preview presentation, non-XUL
2708
0
2709
0
      ViewportFrame
2710
0
        nsHTMLScrollFrame
2711
0
          nsSimplePageSequenceFrame
2712
0
            nsPageFrame
2713
0
              nsPageContentFrame [fixed-cb]
2714
0
                nsCanvasFrame [abs-cb]
2715
0
                  root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2716
0
                                      nsTableWrapperFrame, nsPlaceholderFrame)
2717
0
2718
0
  Print/print preview of XUL is not supported.
2719
0
  [fixed-cb]: the default containing block for fixed-pos content
2720
0
  [abs-cb]: the default containing block for abs-pos content
2721
0
2722
0
  Meaning of nsCSSFrameConstructor fields:
2723
0
    mRootElementFrame is "root element frame".  This is the primary frame for
2724
0
      the root element.
2725
0
    mDocElementContainingBlock is the parent of mRootElementFrame
2726
0
      (i.e. nsCanvasFrame or nsRootBoxFrame)
2727
0
2728
0
    mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
2729
0
  */
2730
0
2731
0
  // --------- CREATE ROOT FRAME -------
2732
0
2733
0
2734
0
  // Create the root frame. The document element's frame is a child of the
2735
0
  // root frame.
2736
0
  //
2737
0
  // The root frame serves two purposes:
2738
0
  // - reserves space for any margins needed for the document element's frame
2739
0
  // - renders the document element's background. This ensures the background covers
2740
0
  //   the entire canvas as specified by the CSS2 spec
2741
0
2742
0
  nsPresContext* presContext = mPresShell->GetPresContext();
2743
0
  bool isPaginated = presContext->IsRootPaginatedDocument();
2744
0
  nsContainerFrame* viewportFrame = static_cast<nsContainerFrame*>(GetRootFrame());
2745
0
  ComputedStyle* viewportPseudoStyle = viewportFrame->Style();
2746
0
2747
0
  nsContainerFrame* rootFrame = nullptr;
2748
0
  nsAtom* rootPseudo;
2749
0
2750
0
  if (!isPaginated) {
2751
0
#ifdef MOZ_XUL
2752
0
    if (aDocElement->IsXULElement())
2753
0
    {
2754
0
      // pass a temporary stylecontext, the correct one will be set later
2755
0
      rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
2756
0
    } else
2757
0
#endif
2758
0
    {
2759
0
      // pass a temporary stylecontext, the correct one will be set later
2760
0
      rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2761
0
      mHasRootAbsPosContainingBlock = true;
2762
0
    }
2763
0
2764
0
    rootPseudo = nsCSSAnonBoxes::canvas();
2765
0
    mDocElementContainingBlock = rootFrame;
2766
0
  } else {
2767
0
    // Create a page sequence frame
2768
0
    rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
2769
0
    mPageSequenceFrame = rootFrame;
2770
0
    rootPseudo = nsCSSAnonBoxes::pageSequence();
2771
0
    rootFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2772
0
  }
2773
0
2774
0
2775
0
  // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2776
0
2777
0
  // If the device supports scrolling (e.g., in galley mode on the screen and
2778
0
  // for print-preview, but not when printing), then create a scroll frame that
2779
0
  // will act as the scrolling mechanism for the viewport.
2780
0
  // XXX Do we even need a viewport when printing to a printer?
2781
0
2782
0
  bool isHTML = aDocElement->IsHTMLElement();
2783
0
  bool isXUL = false;
2784
0
2785
0
  if (!isHTML) {
2786
0
    isXUL = aDocElement->IsXULElement();
2787
0
  }
2788
0
2789
0
  // Never create scrollbars for XUL documents
2790
0
  bool isScrollable = isPaginated ? presContext->HasPaginatedScrolling() : !isXUL;
2791
0
2792
0
  // We no longer need to do overflow propagation here. It's taken care of
2793
0
  // when we construct frames for the element whose overflow might be
2794
0
  // propagated
2795
0
  NS_ASSERTION(!isScrollable || !isXUL,
2796
0
               "XUL documents should never be scrollable - see above");
2797
0
2798
0
  nsContainerFrame* newFrame = rootFrame;
2799
0
  RefPtr<ComputedStyle> rootPseudoStyle;
2800
0
  // we must create a state because if the scrollbars are GFX it needs the
2801
0
  // state to build the scrollbar frames.
2802
0
  nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
2803
0
2804
0
  // Start off with the viewport as parent; we'll adjust it as needed.
2805
0
  nsContainerFrame* parentFrame = viewportFrame;
2806
0
2807
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
2808
0
  // If paginated, make sure we don't put scrollbars in
2809
0
  if (!isScrollable) {
2810
0
    rootPseudoStyle =
2811
0
      styleSet->ResolveInheritingAnonymousBoxStyle(rootPseudo,
2812
0
                                                   viewportPseudoStyle);
2813
0
  } else {
2814
0
      if (rootPseudo == nsCSSAnonBoxes::canvas()) {
2815
0
        rootPseudo = nsCSSAnonBoxes::scrolledCanvas();
2816
0
      } else {
2817
0
        NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence(),
2818
0
                     "Unknown root pseudo");
2819
0
        rootPseudo = nsCSSAnonBoxes::scrolledPageSequence();
2820
0
      }
2821
0
2822
0
      // Build the frame. We give it the content we are wrapping which is the
2823
0
      // document element, the root frame, the parent view port frame, and we
2824
0
      // should get back the new frame and the scrollable view if one was
2825
0
      // created.
2826
0
2827
0
      // resolve a context for the scrollframe
2828
0
      RefPtr<ComputedStyle>  computedStyle =
2829
0
        styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll(),
2830
0
                                                     viewportPseudoStyle);
2831
0
2832
0
      // Note that the viewport scrollframe is always built with
2833
0
      // overflow:auto style. This forces the scroll frame to create
2834
0
      // anonymous content for both scrollbars. This is necessary even
2835
0
      // if the HTML or BODY elements are overriding the viewport
2836
0
      // scroll style to 'hidden' --- dynamic style changes might put
2837
0
      // scrollbars back on the viewport and we don't want to have to
2838
0
      // reframe the viewport to create the scrollbar content.
2839
0
      newFrame = nullptr;
2840
0
      rootPseudoStyle = BeginBuildingScrollFrame( state,
2841
0
                                                  aDocElement,
2842
0
                                                  computedStyle,
2843
0
                                                  viewportFrame,
2844
0
                                                  rootPseudo,
2845
0
                                                  true,
2846
0
                                                  newFrame);
2847
0
      parentFrame = newFrame;
2848
0
  }
2849
0
2850
0
  rootFrame->SetComputedStyleWithoutNotification(rootPseudoStyle);
2851
0
  rootFrame->Init(aDocElement, parentFrame, nullptr);
2852
0
2853
0
  if (isScrollable) {
2854
0
    FinishBuildingScrollFrame(parentFrame, rootFrame);
2855
0
  }
2856
0
2857
0
  if (isPaginated) {
2858
0
    // Create the first page
2859
0
    // Set the initial child lists
2860
0
    nsContainerFrame* canvasFrame;
2861
0
    nsContainerFrame* pageFrame =
2862
0
      ConstructPageFrame(mPresShell, rootFrame, nullptr, canvasFrame);
2863
0
    pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2864
0
    SetInitialSingleChild(rootFrame, pageFrame);
2865
0
2866
0
    // The eventual parent of the document element frame.
2867
0
    // XXX should this be set for every new page (in ConstructPageFrame)?
2868
0
    mDocElementContainingBlock = canvasFrame;
2869
0
    mHasRootAbsPosContainingBlock = true;
2870
0
  }
2871
0
2872
0
  if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
2873
0
    SetInitialSingleChild(viewportFrame, newFrame);
2874
0
  } else {
2875
0
    nsFrameList newFrameList(newFrame, newFrame);
2876
0
    viewportFrame->AppendFrames(kPrincipalList, newFrameList);
2877
0
  }
2878
0
}
2879
2880
void
2881
nsCSSFrameConstructor::ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
2882
                                                          nsIFrame* aFrame,
2883
                                                          nsIContent* aDocElement)
2884
0
{
2885
0
  NS_ASSERTION(aFrame->IsCanvasFrame(), "aFrame should be canvas frame!");
2886
0
2887
0
  AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
2888
0
  GetAnonymousContent(aDocElement, aFrame, anonymousItems);
2889
0
  if (anonymousItems.IsEmpty()) {
2890
0
    return;
2891
0
  }
2892
0
2893
0
  AutoFrameConstructionItemList itemsToConstruct(this);
2894
0
  nsContainerFrame* frameAsContainer = do_QueryFrame(aFrame);
2895
0
  AddFCItemsForAnonymousContent(aState, frameAsContainer, anonymousItems, itemsToConstruct);
2896
0
2897
0
  nsFrameItems frameItems;
2898
0
  ConstructFramesFromItemList(aState, itemsToConstruct, frameAsContainer,
2899
0
                              /* aParentIsWrapperAnonBox = */ false,
2900
0
                              frameItems);
2901
0
  frameAsContainer->AppendFrames(kPrincipalList, frameItems);
2902
0
}
2903
2904
nsContainerFrame*
2905
nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell*  aPresShell,
2906
                                          nsContainerFrame* aParentFrame,
2907
                                          nsIFrame*      aPrevPageFrame,
2908
                                          nsContainerFrame*& aCanvasFrame)
2909
0
{
2910
0
  ComputedStyle* parentComputedStyle = aParentFrame->Style();
2911
0
  ServoStyleSet* styleSet = aPresShell->StyleSet();
2912
0
2913
0
  RefPtr<ComputedStyle> pagePseudoStyle;
2914
0
  pagePseudoStyle =
2915
0
    styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::page(),
2916
0
                                                 parentComputedStyle);
2917
0
2918
0
  nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2919
0
2920
0
  // Initialize the page frame and force it to have a view. This makes printing of
2921
0
  // the pages easier and faster.
2922
0
  pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
2923
0
2924
0
  RefPtr<ComputedStyle> pageContentPseudoStyle;
2925
0
  pageContentPseudoStyle =
2926
0
    styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::pageContent(),
2927
0
                                                 pagePseudoStyle);
2928
0
2929
0
  nsContainerFrame* pageContentFrame =
2930
0
    NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
2931
0
2932
0
  // Initialize the page content frame and force it to have a view. Also make it the
2933
0
  // containing block for fixed elements which are repeated on every page.
2934
0
  nsIFrame* prevPageContentFrame = nullptr;
2935
0
  if (aPrevPageFrame) {
2936
0
    prevPageContentFrame = aPrevPageFrame->PrincipalChildList().FirstChild();
2937
0
    NS_ASSERTION(prevPageContentFrame, "missing page content frame");
2938
0
  }
2939
0
  pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
2940
0
  if (!prevPageContentFrame) {
2941
0
    pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2942
0
  }
2943
0
  SetInitialSingleChild(pageFrame, pageContentFrame);
2944
0
  // Make it an absolute container for fixed-pos elements
2945
0
  pageContentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2946
0
  pageContentFrame->MarkAsAbsoluteContainingBlock();
2947
0
2948
0
  RefPtr<ComputedStyle> canvasPseudoStyle;
2949
0
  canvasPseudoStyle =
2950
0
    styleSet->ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::canvas(),
2951
0
                                                 pageContentPseudoStyle);
2952
0
2953
0
  aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
2954
0
2955
0
  nsIFrame* prevCanvasFrame = nullptr;
2956
0
  if (prevPageContentFrame) {
2957
0
    prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
2958
0
    NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
2959
0
  }
2960
0
  aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
2961
0
  SetInitialSingleChild(pageContentFrame, aCanvasFrame);
2962
0
  return pageFrame;
2963
0
}
2964
2965
/* static */
2966
nsIFrame*
2967
nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell*     aPresShell,
2968
                                                 nsIContent*       aContent,
2969
                                                 nsIFrame*         aFrame,
2970
                                                 nsContainerFrame* aParentFrame,
2971
                                                 nsIFrame*         aPrevInFlow,
2972
                                                 nsFrameState      aTypeBit)
2973
0
{
2974
0
  RefPtr<ComputedStyle> placeholderStyle = aPresShell->StyleSet()->
2975
0
    ResolveStyleForPlaceholder();
2976
0
2977
0
  // The placeholder frame gets a pseudo style.
2978
0
  nsPlaceholderFrame* placeholderFrame =
2979
0
    NS_NewPlaceholderFrame(aPresShell, placeholderStyle, aTypeBit);
2980
0
2981
0
  placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
2982
0
2983
0
  // Associate the placeholder/out-of-flow with each other.
2984
0
  placeholderFrame->SetOutOfFlowFrame(aFrame);
2985
0
  aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
2986
0
2987
0
  aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
2988
0
2989
0
  return placeholderFrame;
2990
0
}
2991
2992
// Clears any lazy bits set in the range [aStartContent, aEndContent).  If
2993
// aEndContent is null, that means to clear bits in all siblings starting with
2994
// aStartContent.  aStartContent must not be null unless aEndContent is also
2995
// null.  We do this so that when new children are inserted under elements whose
2996
// frame is a leaf the new children don't cause us to try to construct frames
2997
// for the existing children again.
2998
static inline void
2999
ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent)
3000
0
{
3001
0
  MOZ_ASSERT(aStartContent || !aEndContent,
3002
0
             "Must have start child if we have an end child");
3003
0
3004
0
  for (nsIContent* cur = aStartContent; cur != aEndContent;
3005
0
       cur = cur->GetNextSibling()) {
3006
0
    cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
3007
0
  }
3008
0
}
3009
3010
nsIFrame*
3011
nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
3012
                                            FrameConstructionItem&   aItem,
3013
                                            nsContainerFrame*        aParentFrame,
3014
                                            const nsStyleDisplay*    aStyleDisplay,
3015
                                            nsFrameItems&            aFrameItems)
3016
0
{
3017
0
  nsIContent* const content = aItem.mContent;
3018
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
3019
0
3020
0
  // Construct a frame-based listbox or combobox
3021
0
  dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromNode(content);
3022
0
  MOZ_ASSERT(sel);
3023
0
  if (sel->IsCombobox()) {
3024
0
    // Construct a frame-based combo box.
3025
0
    // The frame-based combo box is built out of three parts. A display area, a button and
3026
0
    // a dropdown list. The display area and button are created through anonymous content.
3027
0
    // The drop-down list's frame is created explicitly. The combobox frame shares its content
3028
0
    // with the drop-down list.
3029
0
    nsFrameState flags = NS_BLOCK_FLOAT_MGR;
3030
0
    nsComboboxControlFrame* comboboxFrame =
3031
0
      NS_NewComboboxControlFrame(mPresShell, computedStyle, flags);
3032
0
3033
0
    // Save the history state so we don't restore during construction
3034
0
    // since the complete tree is required before we restore.
3035
0
    nsILayoutHistoryState *historyState = aState.mFrameState;
3036
0
    aState.mFrameState = nullptr;
3037
0
    // Initialize the combobox frame
3038
0
    InitAndRestoreFrame(aState, content,
3039
0
                        aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3040
0
                        comboboxFrame);
3041
0
3042
0
    comboboxFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3043
0
3044
0
    aState.AddChild(comboboxFrame, aFrameItems, content, aParentFrame);
3045
0
3046
0
    // Resolve pseudo element style for the dropdown list
3047
0
    RefPtr<ComputedStyle> listStyle;
3048
0
    listStyle = mPresShell->StyleSet()->
3049
0
      ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList(),
3050
0
                                         computedStyle);
3051
0
3052
0
    // Create a listbox
3053
0
    nsContainerFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
3054
0
3055
0
    // Notify the listbox that it is being used as a dropdown list.
3056
0
    nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
3057
0
    if (listControlFrame) {
3058
0
      listControlFrame->SetComboboxFrame(comboboxFrame);
3059
0
    }
3060
0
    // Notify combobox that it should use the listbox as it's popup
3061
0
    comboboxFrame->SetDropDown(listFrame);
3062
0
3063
0
    if (!nsLayoutUtils::IsContentSelectEnabled()) {
3064
0
      // TODO(kuoe0) Remove this assertion when content-select is shipped.
3065
0
      NS_ASSERTION(!listFrame->IsAbsPosContainingBlock(),
3066
0
                   "Ended up with positioned dropdown list somehow.");
3067
0
    }
3068
0
    NS_ASSERTION(!listFrame->IsFloating(),
3069
0
                 "Ended up with floating dropdown list somehow.");
3070
0
3071
0
    // child frames of combobox frame
3072
0
    nsFrameItems childItems;
3073
0
3074
0
    // Initialize the scroll frame positioned. Note that it is NOT
3075
0
    // initialized as absolutely positioned.
3076
0
    nsContainerFrame* scrolledFrame =
3077
0
      NS_NewSelectsAreaFrame(mPresShell, computedStyle, flags);
3078
0
3079
0
    InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3080
0
                          comboboxFrame, listStyle, true,
3081
0
                          aItem.mPendingBinding, childItems);
3082
0
3083
0
    if (!nsLayoutUtils::IsContentSelectEnabled()) {
3084
0
      // TODO(kuoe0) Remove this assertion when content-select is shipped.
3085
0
      NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nullptr");
3086
0
    }
3087
0
3088
0
    // Create display and button frames from the combobox's anonymous content.
3089
0
    // The anonymous content is appended to existing anonymous content for this
3090
0
    // element (the scrollbars).
3091
0
    //
3092
0
    // nsComboboxControlFrame needs special frame creation behavior for its first
3093
0
    // piece of anonymous content, which means that we can't take the normal
3094
0
    // ProcessChildren path.
3095
0
    AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
3096
0
    DebugOnly<nsresult> rv = GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
3097
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3098
0
    MOZ_ASSERT(newAnonymousItems.Length() == 2);
3099
0
3100
0
    // Manually create a frame for the special NAC.
3101
0
    MOZ_ASSERT(newAnonymousItems[0].mContent == comboboxFrame->GetDisplayNode());
3102
0
    newAnonymousItems.RemoveElementAt(0);
3103
0
    nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
3104
0
    MOZ_ASSERT(customFrame);
3105
0
    customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
3106
0
    childItems.AddChild(customFrame);
3107
0
3108
0
    // The other piece of NAC can take the normal path.
3109
0
    AutoFrameConstructionItemList fcItems(this);
3110
0
    AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
3111
0
                                  fcItems);
3112
0
    ConstructFramesFromItemList(aState, fcItems, comboboxFrame,
3113
0
                                /* aParentIsWrapperAnonBox = */ false,
3114
0
                                childItems);
3115
0
3116
0
    comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
3117
0
3118
0
    if (!nsLayoutUtils::IsContentSelectEnabled()) {
3119
0
      // Initialize the additional popup child list which contains the
3120
0
      // dropdown list frame.
3121
0
      nsFrameItems popupItems;
3122
0
      popupItems.AddChild(listFrame);
3123
0
      comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList,
3124
0
                                         popupItems);
3125
0
    }
3126
0
3127
0
    aState.mFrameState = historyState;
3128
0
    if (aState.mFrameState) {
3129
0
      // Restore frame state for the entire subtree of |comboboxFrame|.
3130
0
      RestoreFrameState(comboboxFrame, aState.mFrameState);
3131
0
    }
3132
0
    return comboboxFrame;
3133
0
  }
3134
0
3135
0
  // Listbox, not combobox
3136
0
  nsContainerFrame* listFrame =
3137
0
    NS_NewListControlFrame(mPresShell, computedStyle);
3138
0
3139
0
  nsContainerFrame* scrolledFrame = NS_NewSelectsAreaFrame(
3140
0
      mPresShell, computedStyle, NS_BLOCK_FLOAT_MGR);
3141
0
3142
0
  // ******* this code stolen from Initialze ScrollFrame ********
3143
0
  // please adjust this code to use BuildScrollFrame.
3144
0
3145
0
  InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3146
0
                        aParentFrame, computedStyle, false,
3147
0
                        aItem.mPendingBinding, aFrameItems);
3148
0
3149
0
  return listFrame;
3150
0
}
3151
3152
/**
3153
 * Used to be InitializeScrollFrame but now it's only used for the select tag
3154
 * But the select tag should really be fixed to use GFX scrollbars that can
3155
 * be create with BuildScrollFrame.
3156
 */
3157
void
3158
nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
3159
                                             nsContainerFrame*        scrollFrame,
3160
                                             nsContainerFrame*        scrolledFrame,
3161
                                             nsIContent*              aContent,
3162
                                             nsContainerFrame*        aParentFrame,
3163
                                             ComputedStyle*          aComputedStyle,
3164
                                             bool                     aBuildCombobox,
3165
                                             PendingBinding*          aPendingBinding,
3166
                                             nsFrameItems&            aFrameItems)
3167
0
{
3168
0
  // Initialize it
3169
0
  nsContainerFrame* geometricParent =
3170
0
    aState.GetGeometricParent(*aComputedStyle->StyleDisplay(), aParentFrame);
3171
0
3172
0
  // We don't call InitAndRestoreFrame for scrollFrame because we can only
3173
0
  // restore the frame state after its parts have been created (in particular,
3174
0
  // the scrollable view). So we have to split Init and Restore.
3175
0
3176
0
  scrollFrame->Init(aContent, geometricParent, nullptr);
3177
0
3178
0
  if (!aBuildCombobox || nsLayoutUtils::IsContentSelectEnabled()) {
3179
0
    aState.AddChild(scrollFrame, aFrameItems, aContent, aParentFrame);
3180
0
  }
3181
0
3182
0
  BuildScrollFrame(aState, aContent, aComputedStyle, scrolledFrame,
3183
0
                   geometricParent, scrollFrame);
3184
0
3185
0
  if (aState.mFrameState) {
3186
0
    // Restore frame state for the scroll frame
3187
0
    RestoreFrameStateFor(scrollFrame, aState.mFrameState);
3188
0
  }
3189
0
3190
0
  // Process children
3191
0
  nsFrameItems                childItems;
3192
0
3193
0
  ProcessChildren(aState, aContent, aComputedStyle, scrolledFrame, false,
3194
0
                  childItems, false, aPendingBinding);
3195
0
3196
0
  // Set the scrolled frame's initial child lists
3197
0
  scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
3198
0
}
3199
3200
nsIFrame*
3201
nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
3202
                                              FrameConstructionItem&   aItem,
3203
                                              nsContainerFrame*        aParentFrame,
3204
                                              const nsStyleDisplay*    aStyleDisplay,
3205
                                              nsFrameItems&            aFrameItems)
3206
0
{
3207
0
  nsIContent* const content = aItem.mContent;
3208
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
3209
0
3210
0
  nsContainerFrame* fieldsetFrame =
3211
0
    NS_NewFieldSetFrame(mPresShell, computedStyle);
3212
0
3213
0
  // Initialize it
3214
0
  InitAndRestoreFrame(aState, content,
3215
0
                      aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3216
0
                      fieldsetFrame);
3217
0
3218
0
  fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3219
0
3220
0
  // Resolve style and initialize the frame
3221
0
  RefPtr<ComputedStyle> fieldsetContentStyle;
3222
0
  fieldsetContentStyle = mPresShell->StyleSet()->
3223
0
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent(),
3224
0
                                       computedStyle);
3225
0
3226
0
  const nsStyleDisplay* fieldsetContentDisplay = fieldsetContentStyle->StyleDisplay();
3227
0
  bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3228
0
  nsContainerFrame* scrollFrame = nullptr;
3229
0
  if (isScrollable) {
3230
0
    fieldsetContentStyle =
3231
0
      BeginBuildingScrollFrame(aState, content, fieldsetContentStyle,
3232
0
                               fieldsetFrame, nsCSSAnonBoxes::scrolledContent(),
3233
0
                               false, scrollFrame);
3234
0
  }
3235
0
3236
0
  nsContainerFrame* absPosContainer = nullptr;
3237
0
  if (fieldsetFrame->IsAbsPosContainingBlock()) {
3238
0
    absPosContainer = fieldsetFrame;
3239
0
  }
3240
0
3241
0
  // Create the inner ::-moz-fieldset-content frame.
3242
0
  nsContainerFrame* contentFrameTop;
3243
0
  nsContainerFrame* contentFrame;
3244
0
  auto parent = scrollFrame ? scrollFrame : fieldsetFrame;
3245
0
  switch (fieldsetContentDisplay->mDisplay) {
3246
0
    case StyleDisplay::Flex:
3247
0
      contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3248
0
      InitAndRestoreFrame(aState, content, parent, contentFrame);
3249
0
      contentFrameTop = contentFrame;
3250
0
      break;
3251
0
    case StyleDisplay::Grid:
3252
0
      contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3253
0
      InitAndRestoreFrame(aState, content, parent, contentFrame);
3254
0
      contentFrameTop = contentFrame;
3255
0
      break;
3256
0
    default: {
3257
0
      MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
3258
0
                 "bug in StyleAdjuster::adjust_for_fieldset_content?");
3259
0
3260
0
      contentFrame = NS_NewBlockFormattingContext(mPresShell, fieldsetContentStyle);
3261
0
      contentFrameTop =
3262
0
        InitAndWrapInColumnSetFrameIfNeeded(aState, content, parent,
3263
0
                                            contentFrame, fieldsetContentStyle);
3264
0
      if (contentFrame != contentFrameTop) {
3265
0
        // contentFrame is wrapped in nsColumnSetFrame.
3266
0
        if (absPosContainer) {
3267
0
          absPosContainer = contentFrameTop;
3268
0
        }
3269
0
      }
3270
0
3271
0
      break;
3272
0
    }
3273
0
  }
3274
0
3275
0
  aState.AddChild(fieldsetFrame, aFrameItems, content, aParentFrame);
3276
0
3277
0
  // Process children
3278
0
  nsFrameConstructorSaveState absoluteSaveState;
3279
0
  nsFrameItems                childItems;
3280
0
3281
0
  contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3282
0
  if (absPosContainer) {
3283
0
    aState.PushAbsoluteContainingBlock(contentFrame, absPosContainer, absoluteSaveState);
3284
0
  }
3285
0
3286
0
  ProcessChildren(aState, content, computedStyle, contentFrame, true,
3287
0
                  childItems, true, aItem.mPendingBinding);
3288
0
3289
0
  nsFrameItems fieldsetKids;
3290
0
  fieldsetKids.AddChild(scrollFrame ? scrollFrame : contentFrameTop);
3291
0
3292
0
  for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
3293
0
    nsIFrame* child = e.get();
3294
0
    nsContainerFrame* cif = child->GetContentInsertionFrame();
3295
0
    if (cif && cif->IsLegendFrame()) {
3296
0
      // We want the legend to be the first frame in the fieldset child list.
3297
0
      // That way the EventStateManager will do the right thing when tabbing
3298
0
      // from a selection point within the legend (bug 236071), which is
3299
0
      // used for implementing legend access keys (bug 81481).
3300
0
      // GetAdjustedParentFrame() below depends on this frame order.
3301
0
      childItems.RemoveFrame(child);
3302
0
      // Make sure to reparent the legend so it has the fieldset as the parent.
3303
0
      fieldsetKids.InsertFrame(fieldsetFrame, nullptr, child);
3304
0
      if (scrollFrame) {
3305
0
        StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(
3306
0
            child, contentFrame);
3307
0
      }
3308
0
      break;
3309
0
    }
3310
0
  }
3311
0
3312
0
  if (isScrollable) {
3313
0
    FinishBuildingScrollFrame(scrollFrame, contentFrameTop);
3314
0
  }
3315
0
3316
0
  // Set the inner frame's initial child lists
3317
0
  contentFrame->SetInitialChildList(kPrincipalList, childItems);
3318
0
3319
0
  // Set the outer frame's initial child list
3320
0
  fieldsetFrame->SetInitialChildList(kPrincipalList, fieldsetKids);
3321
0
3322
0
  // Our new frame returned is the outer frame, which is the fieldset frame.
3323
0
  return fieldsetFrame;
3324
0
}
3325
3326
nsIFrame*
3327
nsCSSFrameConstructor::ConstructDetailsFrame(nsFrameConstructorState& aState,
3328
                                             FrameConstructionItem& aItem,
3329
                                             nsContainerFrame* aParentFrame,
3330
                                             const nsStyleDisplay* aStyleDisplay,
3331
                                             nsFrameItems& aFrameItems)
3332
0
{
3333
0
  if (!aStyleDisplay->IsScrollableOverflow()) {
3334
0
    return ConstructNonScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3335
0
                                                      aStyleDisplay, aFrameItems,
3336
0
                                                      NS_NewDetailsFrame);
3337
0
  }
3338
0
3339
0
  // Build a scroll frame to wrap details frame if necessary.
3340
0
  return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
3341
0
                                                 aStyleDisplay, aFrameItems,
3342
0
                                                 NS_NewDetailsFrame);
3343
0
}
3344
3345
static nsIFrame*
3346
FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame)
3347
0
{
3348
0
  for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3349
0
    NS_ASSERTION(f->IsGeneratedContentFrame(),
3350
0
                 "should not have exited generated content");
3351
0
    nsAtom* pseudo = f->Style()->GetPseudo();
3352
0
    if (pseudo == nsCSSPseudoElements::before() ||
3353
0
        pseudo == nsCSSPseudoElements::after())
3354
0
      return f;
3355
0
  }
3356
0
  return nullptr;
3357
0
}
3358
3359
0
#define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3360
#define FULL_CTOR_FCDATA(_flags, _func)                             \
3361
0
  { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nullptr }, _func, nullptr }
3362
3363
/* static */
3364
const nsCSSFrameConstructor::FrameConstructionData*
3365
nsCSSFrameConstructor::FindTextData(const Text& aTextContent,
3366
                                    nsIFrame* aParentFrame)
3367
0
{
3368
0
  if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3369
0
    nsIFrame* ancestorFrame =
3370
0
      nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
3371
0
    if (!ancestorFrame || !nsSVGUtils::IsInSVGTextSubtree(ancestorFrame)) {
3372
0
      return nullptr;
3373
0
    }
3374
0
3375
0
    // Don't render stuff in display: contents / Shadow DOM subtrees, because
3376
0
    // TextCorrespondenceRecorder in the SVG text code doesn't really know how
3377
0
    // to deal with it. This kinda sucks. :(
3378
0
    if (aParentFrame->GetContent() != aTextContent.GetParent()) {
3379
0
      return nullptr;
3380
0
    }
3381
0
3382
0
    static const FrameConstructionData sSVGTextData =
3383
0
      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT,
3384
0
                  NS_NewTextFrame);
3385
0
    return &sSVGTextData;
3386
0
  }
3387
0
3388
0
  static const FrameConstructionData sTextData =
3389
0
    FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
3390
0
  return &sTextData;
3391
0
}
3392
3393
void
3394
nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData,
3395
                                          nsFrameConstructorState& aState,
3396
                                          nsIContent*              aContent,
3397
                                          nsContainerFrame*        aParentFrame,
3398
                                          ComputedStyle*          aComputedStyle,
3399
                                          nsFrameItems&            aFrameItems)
3400
0
{
3401
0
  MOZ_ASSERT(aData, "Must have frame construction data");
3402
0
3403
0
  nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aComputedStyle);
3404
0
3405
0
  InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3406
0
3407
0
  // We never need to create a view for a text frame.
3408
0
3409
0
  if (newFrame->IsGeneratedContentFrame()) {
3410
0
    nsAutoPtr<nsGenConInitializer> initializer;
3411
0
    initializer =
3412
0
      static_cast<nsGenConInitializer*>(
3413
0
        aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
3414
0
    if (initializer) {
3415
0
      if (initializer->mNode->InitTextFrame(initializer->mList,
3416
0
              FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
3417
0
        (this->*(initializer->mDirtyAll))();
3418
0
      }
3419
0
      initializer->mNode.forget();
3420
0
    }
3421
0
  }
3422
0
3423
0
  // Add the newly constructed frame to the flow
3424
0
  aFrameItems.AddChild(newFrame);
3425
0
3426
0
  if (!aState.mCreatingExtraFrames)
3427
0
    aContent->SetPrimaryFrame(newFrame);
3428
0
}
3429
3430
/* static */
3431
const nsCSSFrameConstructor::FrameConstructionData*
3432
nsCSSFrameConstructor::FindDataByInt(int32_t aInt,
3433
                                     const Element& aElement,
3434
                                     ComputedStyle& aComputedStyle,
3435
                                     const FrameConstructionDataByInt* aDataPtr,
3436
                                     uint32_t aDataLength)
3437
0
{
3438
0
  for (const FrameConstructionDataByInt *curData = aDataPtr,
3439
0
         *endData = aDataPtr + aDataLength;
3440
0
       curData != endData;
3441
0
       ++curData) {
3442
0
    if (curData->mInt == aInt) {
3443
0
      const FrameConstructionData* data = &curData->mData;
3444
0
      if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3445
0
        return data->mFunc.mDataGetter(aElement, aComputedStyle);
3446
0
      }
3447
0
3448
0
      return data;
3449
0
    }
3450
0
  }
3451
0
3452
0
  return nullptr;
3453
0
}
3454
3455
/* static */
3456
const nsCSSFrameConstructor::FrameConstructionData*
3457
nsCSSFrameConstructor::FindDataByTag(nsAtom* aTag,
3458
                                     const Element& aElement,
3459
                                     ComputedStyle& aStyle,
3460
                                     const FrameConstructionDataByTag* aDataPtr,
3461
                                     uint32_t aDataLength)
3462
0
{
3463
0
  for (const FrameConstructionDataByTag *curData = aDataPtr,
3464
0
         *endData = aDataPtr + aDataLength;
3465
0
       curData != endData;
3466
0
       ++curData) {
3467
0
    if (*curData->mTag == aTag) {
3468
0
      const FrameConstructionData* data = &curData->mData;
3469
0
      if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3470
0
        return data->mFunc.mDataGetter(aElement, aStyle);
3471
0
      }
3472
0
3473
0
      return data;
3474
0
    }
3475
0
  }
3476
0
3477
0
  return nullptr;
3478
0
}
3479
3480
0
#define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nullptr)
3481
0
#define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
3482
#define SIMPLE_INT_CHAIN(_int, _func)                       \
3483
0
  { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3484
#define COMPLEX_INT_CREATE(_int, _func)         \
3485
  { _int, FULL_CTOR_FCDATA(0, _func) }
3486
3487
#define SIMPLE_TAG_CREATE(_tag, _func)          \
3488
0
  { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3489
#define SIMPLE_TAG_CHAIN(_tag, _func)                                   \
3490
0
  { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER,  _func) }
3491
#define COMPLEX_TAG_CREATE(_tag, _func)             \
3492
0
  { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3493
3494
static bool
3495
IsFrameForFieldSet(nsIFrame* aFrame)
3496
0
{
3497
0
  nsAtom* pseudo = aFrame->Style()->GetPseudo();
3498
0
  if (pseudo == nsCSSAnonBoxes::fieldsetContent() ||
3499
0
      pseudo == nsCSSAnonBoxes::scrolledContent() ||
3500
0
      pseudo == nsCSSAnonBoxes::columnContent()) {
3501
0
    return IsFrameForFieldSet(aFrame->GetParent());
3502
0
  }
3503
0
  return aFrame->IsFieldSetFrame();
3504
0
}
3505
3506
/* static */
3507
const nsCSSFrameConstructor::FrameConstructionData*
3508
nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
3509
                                    nsIFrame* aParentFrame,
3510
                                    ComputedStyle& aStyle)
3511
0
{
3512
0
  MOZ_ASSERT(aElement.IsHTMLElement());
3513
0
3514
0
  nsAtom* tag = aElement.NodeInfo()->NameAtom();
3515
0
  NS_ASSERTION(!aParentFrame ||
3516
0
               aParentFrame->Style()->GetPseudo() !=
3517
0
                 nsCSSAnonBoxes::fieldsetContent() ||
3518
0
               aParentFrame->GetParent()->IsFieldSetFrame(),
3519
0
               "Unexpected parent for fieldset content anon box");
3520
0
  if (tag == nsGkAtoms::legend &&
3521
0
      (!aParentFrame || !IsFrameForFieldSet(aParentFrame) ||
3522
0
       aStyle.StyleDisplay()->IsFloatingStyle() ||
3523
0
       aStyle.StyleDisplay()->IsAbsolutelyPositionedStyle())) {
3524
0
    // <legend> is only special inside fieldset, we only check the frame tree
3525
0
    // parent because the content tree parent may not be a <fieldset> due to
3526
0
    // display:contents, Shadow DOM, or XBL. For floated or absolutely
3527
0
    // positioned legends we want to construct by display type and
3528
0
    // not do special legend stuff.
3529
0
    return nullptr;
3530
0
  }
3531
0
3532
0
  static const FrameConstructionDataByTag sHTMLData[] = {
3533
0
    SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
3534
0
    SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
3535
0
                     nsCSSFrameConstructor::FindGeneratedImageData),
3536
0
    { &nsGkAtoms::br,
3537
0
      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
3538
0
                  NS_NewBRFrame) },
3539
0
    SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
3540
0
    SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
3541
0
    SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
3542
0
    COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
3543
0
    SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
3544
0
    SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
3545
0
    COMPLEX_TAG_CREATE(fieldset,
3546
0
                       &nsCSSFrameConstructor::ConstructFieldSetFrame),
3547
0
    { &nsGkAtoms::legend,
3548
0
      FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
3549
0
                  NS_NewLegendFrame) },
3550
0
    SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
3551
0
    SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
3552
0
    { &nsGkAtoms::button,
3553
0
      FCDATA_WITH_WRAPPING_BLOCK(FCDATA_ALLOW_BLOCK_STYLES |
3554
0
                                 FCDATA_ALLOW_GRID_FLEX_COLUMNSET,
3555
0
                                 NS_NewHTMLButtonControlFrame,
3556
0
                                 nsCSSAnonBoxes::buttonContent()) },
3557
0
    SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
3558
0
    SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
3559
0
    SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
3560
0
    SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
3561
0
    SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
3562
0
    COMPLEX_TAG_CREATE(details, &nsCSSFrameConstructor::ConstructDetailsFrame)
3563
0
  };
3564
0
3565
0
  return FindDataByTag(tag, aElement, aStyle, sHTMLData, ArrayLength(sHTMLData));
3566
0
}
3567
3568
/* static */
3569
const nsCSSFrameConstructor::FrameConstructionData*
3570
nsCSSFrameConstructor::FindGeneratedImageData(const Element& aElement,
3571
                                              ComputedStyle&)
3572
0
{
3573
0
  if (!aElement.IsInNativeAnonymousSubtree()) {
3574
0
    return nullptr;
3575
0
  }
3576
0
3577
0
  static const FrameConstructionData sImgData =
3578
0
    SIMPLE_FCDATA(NS_NewImageFrameForGeneratedContentIndex);
3579
0
  return &sImgData;
3580
0
}
3581
3582
/* static */
3583
const nsCSSFrameConstructor::FrameConstructionData*
3584
nsCSSFrameConstructor::FindImgData(const Element& aElement,
3585
                                   ComputedStyle& aStyle)
3586
0
{
3587
0
  if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyle)) {
3588
0
    return nullptr;
3589
0
  }
3590
0
3591
0
  static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
3592
0
  return &sImgData;
3593
0
}
3594
3595
/* static */
3596
const nsCSSFrameConstructor::FrameConstructionData*
3597
nsCSSFrameConstructor::FindImgControlData(const Element& aElement,
3598
                                          ComputedStyle& aStyle)
3599
0
{
3600
0
  if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyle)) {
3601
0
    return nullptr;
3602
0
  }
3603
0
3604
0
  static const FrameConstructionData sImgControlData =
3605
0
    SIMPLE_FCDATA(NS_NewImageControlFrame);
3606
0
  return &sImgControlData;
3607
0
}
3608
3609
/* static */
3610
const nsCSSFrameConstructor::FrameConstructionData*
3611
nsCSSFrameConstructor::FindInputData(const Element& aElement,
3612
                                     ComputedStyle& aStyle)
3613
0
{
3614
0
  static const FrameConstructionDataByInt sInputData[] = {
3615
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewCheckboxRadioFrame),
3616
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewCheckboxRadioFrame),
3617
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
3618
0
    SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
3619
0
                     nsCSSFrameConstructor::FindImgControlData),
3620
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame),
3621
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame),
3622
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
3623
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame),
3624
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame),
3625
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_RANGE, NS_NewRangeFrame),
3626
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
3627
0
    { NS_FORM_INPUT_COLOR,
3628
0
      FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewColorControlFrame,
3629
0
                                 nsCSSAnonBoxes::buttonContent()) },
3630
0
    // TODO: this is temporary until a frame is written: bug 635240.
3631
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
3632
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewDateTimeControlFrame),
3633
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewDateTimeControlFrame),
3634
0
    // TODO: this is temporary until a frame is written: bug 888320
3635
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_MONTH, NS_NewTextControlFrame),
3636
0
    // TODO: this is temporary until a frame is written: bug 888320
3637
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_WEEK, NS_NewTextControlFrame),
3638
0
    // TODO: this is temporary until a frame is written: bug 888320
3639
0
    SIMPLE_INT_CREATE(NS_FORM_INPUT_DATETIME_LOCAL, NS_NewTextControlFrame),
3640
0
    { NS_FORM_INPUT_SUBMIT,
3641
0
      FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3642
0
                                 nsCSSAnonBoxes::buttonContent()) },
3643
0
    { NS_FORM_INPUT_RESET,
3644
0
      FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3645
0
                                 nsCSSAnonBoxes::buttonContent()) },
3646
0
    { NS_FORM_INPUT_BUTTON,
3647
0
      FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3648
0
                                 nsCSSAnonBoxes::buttonContent()) }
3649
0
    // Keeping hidden inputs out of here on purpose for so they get frames by
3650
0
    // display (in practice, none).
3651
0
  };
3652
0
3653
0
3654
0
  auto controlType = HTMLInputElement::FromNode(aElement)->ControlType();
3655
0
3656
0
  // radio and checkbox inputs with appearance:none should be constructed
3657
0
  // by display type.  (Note that we're not checking that appearance is
3658
0
  // not (respectively) StyleAppearance::Radio and StyleAppearance::Checkbox.)
3659
0
  if ((controlType == NS_FORM_INPUT_CHECKBOX ||
3660
0
       controlType == NS_FORM_INPUT_RADIO) &&
3661
0
      !aStyle.StyleDisplay()->HasAppearance()) {
3662
0
    return nullptr;
3663
0
  }
3664
0
3665
0
  return FindDataByInt(controlType, aElement, aStyle,
3666
0
                       sInputData, ArrayLength(sInputData));
3667
0
}
3668
3669
/* static */
3670
const nsCSSFrameConstructor::FrameConstructionData*
3671
nsCSSFrameConstructor::FindObjectData(const Element& aElement,
3672
                                      ComputedStyle& aStyle)
3673
0
{
3674
0
  // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3675
0
  // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3676
0
  // we want to treat those cases as TYPE_NULL
3677
0
  uint32_t type;
3678
0
  if (aElement.State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
3679
0
                                             NS_EVENT_STATE_USERDISABLED |
3680
0
                                             NS_EVENT_STATE_SUPPRESSED)) {
3681
0
    type = nsIObjectLoadingContent::TYPE_NULL;
3682
0
  } else {
3683
0
    nsCOMPtr<nsIObjectLoadingContent> objContent =
3684
0
      do_QueryInterface(const_cast<Element*>(&aElement));
3685
0
    NS_ASSERTION(objContent,
3686
0
                 "embed and object must implement "
3687
0
                 "nsIObjectLoadingContent!");
3688
0
3689
0
    objContent->GetDisplayedType(&type);
3690
0
  }
3691
0
3692
0
  static const FrameConstructionDataByInt sObjectData[] = {
3693
0
    SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
3694
0
                      NS_NewEmptyFrame),
3695
0
    SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
3696
0
                      NS_NewObjectFrame),
3697
0
    SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
3698
0
                      NS_NewImageFrame),
3699
0
    SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
3700
0
                      NS_NewSubDocumentFrame),
3701
0
    // Fake plugin handlers load as documents
3702
0
    SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_FAKE_PLUGIN,
3703
0
                      NS_NewSubDocumentFrame)
3704
0
    // Nothing for TYPE_NULL so we'll construct frames by display there
3705
0
  };
3706
0
3707
0
  return FindDataByInt((int32_t)type, aElement, aStyle,
3708
0
                       sObjectData, ArrayLength(sObjectData));
3709
0
}
3710
3711
/* static */
3712
const nsCSSFrameConstructor::FrameConstructionData*
3713
nsCSSFrameConstructor::FindCanvasData(const Element& aElement,
3714
                                      ComputedStyle& aStyle)
3715
0
{
3716
0
  // We want to check whether script is enabled on the document that
3717
0
  // could be painting to the canvas.  That's the owner document of
3718
0
  // the canvas, except when the owner document is a static document,
3719
0
  // in which case it's the original document it was cloned from.
3720
0
  nsIDocument* doc = aElement.OwnerDoc();
3721
0
  if (doc->IsStaticDocument()) {
3722
0
    doc = doc->GetOriginalDocument();
3723
0
  }
3724
0
  if (!doc->IsScriptEnabled()) {
3725
0
    return nullptr;
3726
0
  }
3727
0
3728
0
  static const FrameConstructionData sCanvasData =
3729
0
    FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
3730
0
                               nsCSSAnonBoxes::htmlCanvasContent());
3731
0
  return &sCanvasData;
3732
0
}
3733
3734
void
3735
nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
3736
                                                      nsFrameConstructorState& aState,
3737
                                                      nsContainerFrame* aParentFrame,
3738
                                                      nsFrameItems& aFrameItems)
3739
0
{
3740
0
  const FrameConstructionData* data = aItem.mFCData;
3741
0
  NS_ASSERTION(data, "Must have frame construction data");
3742
0
3743
0
  uint32_t bits = data->mBits;
3744
0
3745
0
  NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
3746
0
               "Should have dealt with this inside the data finder");
3747
0
3748
0
  // Some sets of bits are not compatible with each other
3749
0
#define CHECK_ONLY_ONE_BIT(_bit1, _bit2)               \
3750
0
  NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2),     \
3751
0
               "Only one of these bits should be set")
3752
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
3753
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
3754
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
3755
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
3756
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
3757
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3758
0
                     FCDATA_DISALLOW_GENERATED_CONTENT);
3759
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
3760
0
  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3761
0
                     FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3762
0
  CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
3763
0
                     FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3764
0
#undef CHECK_ONLY_ONE_BIT
3765
0
  NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
3766
0
               ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
3767
0
                data->mFullConstructor ==
3768
0
                  &nsCSSFrameConstructor::ConstructNonScrollableBlock),
3769
0
               "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
3770
0
  MOZ_ASSERT(!(bits & FCDATA_IS_WRAPPER_ANON_BOX) ||
3771
0
             (bits & FCDATA_USE_CHILD_ITEMS),
3772
0
             "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS");
3773
0
3774
0
  // Don't create a subdocument frame for iframes if we're creating extra frames
3775
0
  if (aState.mCreatingExtraFrames &&
3776
0
      aItem.mContent->IsHTMLElement(nsGkAtoms::iframe))
3777
0
  {
3778
0
    return;
3779
0
  }
3780
0
3781
0
  nsIContent* const content = aItem.mContent;
3782
0
  nsIFrame* newFrame;
3783
0
  nsIFrame* primaryFrame;
3784
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
3785
0
  const nsStyleDisplay* display = computedStyle->StyleDisplay();
3786
0
  if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
3787
0
    newFrame =
3788
0
      (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
3789
0
                                        display, aFrameItems);
3790
0
    MOZ_ASSERT(newFrame, "Full constructor failed");
3791
0
    primaryFrame = newFrame;
3792
0
  } else {
3793
0
    newFrame =
3794
0
      (*data->mFunc.mCreationFunc)(mPresShell, computedStyle);
3795
0
3796
0
    bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
3797
0
    bool isPopup = aItem.mIsPopup;
3798
0
    NS_ASSERTION(!isPopup ||
3799
0
                 (aState.mPopupItems.containingBlock &&
3800
0
                  aState.mPopupItems.containingBlock->IsPopupSetFrame()),
3801
0
                 "Should have a containing block here!");
3802
0
3803
0
    nsContainerFrame* geometricParent =
3804
0
      isPopup ? aState.mPopupItems.containingBlock :
3805
0
      (allowOutOfFlow ? aState.GetGeometricParent(*display, aParentFrame)
3806
0
                      : aParentFrame);
3807
0
3808
0
    // Must init frameToAddToList to null, since it's inout
3809
0
    nsIFrame* frameToAddToList = nullptr;
3810
0
    if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
3811
0
        display->IsScrollableOverflow()) {
3812
0
      nsContainerFrame* scrollframe = nullptr;
3813
0
      BuildScrollFrame(aState, content, computedStyle, newFrame,
3814
0
                       geometricParent, scrollframe);
3815
0
      frameToAddToList = scrollframe;
3816
0
    } else {
3817
0
      InitAndRestoreFrame(aState, content, geometricParent, newFrame);
3818
0
      frameToAddToList = newFrame;
3819
0
    }
3820
0
3821
0
    // Use frameToAddToList as the primary frame.  In the non-scrollframe case
3822
0
    // they're equal, but in the scrollframe case newFrame is the scrolled
3823
0
    // frame, while frameToAddToList is the scrollframe (and should be the
3824
0
    // primary frame).
3825
0
    primaryFrame = frameToAddToList;
3826
0
3827
0
    // If we need to create a block formatting context to wrap our
3828
0
    // kids, do it now.
3829
0
    const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display;
3830
0
    nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
3831
0
    nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3832
0
    nsIFrame* possiblyLeafFrame = newFrame;
3833
0
    if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
3834
0
      RefPtr<ComputedStyle> outerSC = mPresShell->StyleSet()->
3835
0
        ResolveInheritingAnonymousBoxStyle(*data->mAnonBoxPseudo,
3836
0
                                           computedStyle);
3837
#ifdef DEBUG
3838
      nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
3839
      MOZ_ASSERT(containerFrame);
3840
#endif
3841
      nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
3842
0
      nsContainerFrame* outerFrame;
3843
0
      nsContainerFrame* innerFrame;
3844
0
      if (bits & FCDATA_ALLOW_GRID_FLEX_COLUMNSET) {
3845
0
        switch (display->mDisplay) {
3846
0
          case StyleDisplay::Flex:
3847
0
          case StyleDisplay::InlineFlex:
3848
0
            outerFrame = NS_NewFlexContainerFrame(mPresShell, outerSC);
3849
0
            InitAndRestoreFrame(aState, content, container, outerFrame);
3850
0
            innerFrame = outerFrame;
3851
0
            break;
3852
0
          case StyleDisplay::Grid:
3853
0
          case StyleDisplay::InlineGrid:
3854
0
            outerFrame = NS_NewGridContainerFrame(mPresShell, outerSC);
3855
0
            InitAndRestoreFrame(aState, content, container, outerFrame);
3856
0
            innerFrame = outerFrame;
3857
0
            break;
3858
0
          default: {
3859
0
            innerFrame = NS_NewBlockFormattingContext(mPresShell, outerSC);
3860
0
            outerFrame =
3861
0
              InitAndWrapInColumnSetFrameIfNeeded(aState, content, container,
3862
0
                                                  innerFrame, outerSC);
3863
0
            break;
3864
0
          }
3865
0
        }
3866
0
      } else {
3867
0
        innerFrame = NS_NewBlockFormattingContext(mPresShell, outerSC);
3868
0
        InitAndRestoreFrame(aState, content, container, innerFrame);
3869
0
        outerFrame = innerFrame;
3870
0
      }
3871
0
3872
0
      SetInitialSingleChild(container, outerFrame);
3873
0
3874
0
      container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3875
0
3876
0
      // Now figure out whether newFrame or outerFrame should be the
3877
0
      // absolute container.
3878
0
      auto outerDisplay = outerSC->StyleDisplay();
3879
0
      if (outerDisplay->IsAbsPosContainingBlock(outerFrame)) {
3880
0
        maybeAbsoluteContainingBlockDisplay = outerDisplay;
3881
0
        maybeAbsoluteContainingBlock = outerFrame;
3882
0
        maybeAbsoluteContainingBlockStyleFrame = outerFrame;
3883
0
        innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3884
0
      }
3885
0
3886
0
      // Our kids should go into the innerFrame.
3887
0
      newFrame = innerFrame;
3888
0
    }
3889
0
3890
0
    aState.AddChild(frameToAddToList, aFrameItems, content, aParentFrame,
3891
0
                    allowOutOfFlow, allowOutOfFlow, isPopup);
3892
0
3893
0
    nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
3894
0
    if (newFrameAsContainer) {
3895
0
#ifdef MOZ_XUL
3896
0
      // Icky XUL stuff, sadly
3897
0
3898
0
      if (aItem.mIsRootPopupgroup) {
3899
0
        NS_ASSERTION(nsIPopupContainer::GetPopupContainer(mPresShell) &&
3900
0
                     nsIPopupContainer::GetPopupContainer(mPresShell)->
3901
0
                      GetPopupSetFrame() == newFrame,
3902
0
                     "Unexpected PopupSetFrame");
3903
0
        aState.mPopupItems.containingBlock = newFrameAsContainer;
3904
0
        aState.mHavePendingPopupgroup = false;
3905
0
      }
3906
0
#endif /* MOZ_XUL */
3907
0
3908
0
      // Process the child content if requested
3909
0
      nsFrameItems childItems;
3910
0
      nsFrameConstructorSaveState absoluteSaveState;
3911
0
3912
0
      if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
3913
0
        aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
3914
0
      } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
3915
0
        maybeAbsoluteContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3916
0
        // This check is identical to nsStyleDisplay::IsAbsPosContainingBlock
3917
0
        // except without the assertion that the style display and frame match.
3918
0
        // When constructing scroll frames we intentionally use the style
3919
0
        // display for the outer, but make the inner the containing block.
3920
0
        if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() ||
3921
0
             maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() ||
3922
0
             maybeAbsoluteContainingBlockDisplay->IsFixedPosContainingBlock(
3923
0
                 maybeAbsoluteContainingBlockStyleFrame)) &&
3924
0
            !nsSVGUtils::IsInSVGTextSubtree(maybeAbsoluteContainingBlockStyleFrame)) {
3925
0
          nsContainerFrame* cf = static_cast<nsContainerFrame*>(
3926
0
              maybeAbsoluteContainingBlock);
3927
0
          aState.PushAbsoluteContainingBlock(cf, cf, absoluteSaveState);
3928
0
        }
3929
0
      }
3930
0
3931
0
      if (bits & FCDATA_USE_CHILD_ITEMS) {
3932
0
        nsFrameConstructorSaveState floatSaveState;
3933
0
3934
0
        if (ShouldSuppressFloatingOfDescendants(newFrame)) {
3935
0
          aState.PushFloatContainingBlock(nullptr, floatSaveState);
3936
0
        } else if (newFrame->IsFloatContainingBlock()) {
3937
0
          aState.PushFloatContainingBlock(newFrameAsContainer, floatSaveState);
3938
0
        }
3939
0
        ConstructFramesFromItemList(aState, aItem.mChildItems,
3940
0
                                    newFrameAsContainer,
3941
0
                                    bits & FCDATA_IS_WRAPPER_ANON_BOX,
3942
0
                                    childItems);
3943
0
      } else {
3944
0
        // Process the child frames.
3945
0
        ProcessChildren(aState, content, computedStyle, newFrameAsContainer,
3946
0
                        !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
3947
0
                        childItems,
3948
0
                        (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
3949
0
                        aItem.mPendingBinding, possiblyLeafFrame);
3950
0
      }
3951
0
3952
0
      if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) {
3953
0
        nsFrameItems newItems;
3954
0
        nsFrameItems currentBlockItems;
3955
0
        nsIFrame* f;
3956
0
        while ((f = childItems.FirstChild()) != nullptr) {
3957
0
          bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
3958
0
          if (!wrapFrame) {
3959
0
            FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3960
0
                                  currentBlockItems, newItems);
3961
0
          }
3962
0
3963
0
          childItems.RemoveFrame(f);
3964
0
          if (wrapFrame) {
3965
0
            currentBlockItems.AddChild(f);
3966
0
          } else {
3967
0
            newItems.AddChild(f);
3968
0
          }
3969
0
        }
3970
0
        FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3971
0
                              currentBlockItems, newItems);
3972
0
3973
0
        if (childItems.NotEmpty()) {
3974
0
          // an error must have occurred, delete unprocessed frames
3975
0
          childItems.DestroyFrames();
3976
0
        }
3977
0
3978
0
        childItems = newItems;
3979
0
      }
3980
0
3981
0
      // Set the frame's initial child list
3982
0
      // Note that MathML depends on this being called even if
3983
0
      // childItems is empty!
3984
0
      newFrameAsContainer->SetInitialChildList(kPrincipalList, childItems);
3985
0
    }
3986
0
  }
3987
0
3988
0
  NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
3989
0
               ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
3990
0
               "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
3991
0
3992
0
  if (aItem.mIsAnonymousContentCreatorContent) {
3993
0
    primaryFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
3994
0
  }
3995
0
3996
0
  // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
3997
0
  // generated content that doesn't have one yet.  Note that we have to examine
3998
0
  // the frame bit, because by this point mIsGeneratedContent has been cleared
3999
0
  // on aItem.
4000
0
  if ((!aState.mCreatingExtraFrames ||
4001
0
       (primaryFrame->HasAnyStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT |
4002
0
                                      NS_FRAME_GENERATED_CONTENT) &&
4003
0
        !aItem.mContent->GetPrimaryFrame())) &&
4004
0
       !(bits & FCDATA_SKIP_FRAMESET)) {
4005
0
    aItem.mContent->SetPrimaryFrame(primaryFrame);
4006
0
    ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
4007
0
  }
4008
0
}
4009
4010
static void
4011
SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet)
4012
0
{
4013
#ifdef DEBUG
4014
  // Make sure that the node passed to us doesn't have any XBL children
4015
  {
4016
    FlattenedChildIterator iter(aNode);
4017
    NS_ASSERTION(!iter.XBLInvolved() || !iter.GetNextChild(),
4018
                 "The node should not have any XBL children");
4019
  }
4020
#endif
4021
4022
0
  // Set the flag on the node itself
4023
0
  aNode->SetFlags(aFlagsToSet);
4024
0
4025
0
  // Set the flag on all of its children recursively
4026
0
  for (nsIContent* child = aNode->GetFirstChild(); child;
4027
0
       child = child->GetNextSibling()) {
4028
0
    SetFlagsOnSubtree(child, aFlagsToSet);
4029
0
  }
4030
0
}
4031
4032
nsresult
4033
nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
4034
                                           nsIFrame* aParentFrame,
4035
                                           nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
4036
0
{
4037
0
  nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
4038
0
  if (!creator)
4039
0
    return NS_OK;
4040
0
4041
0
  nsresult rv = creator->CreateAnonymousContent(aContent);
4042
0
  if (NS_FAILED(rv)) {
4043
0
    // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
4044
0
    return rv;
4045
0
  }
4046
0
4047
0
  for (const auto& info : aContent) {
4048
0
    // get our child's content and set its parent to our content
4049
0
    nsIContent* content = info.mContent;
4050
0
    content->SetIsNativeAnonymousRoot();
4051
0
4052
0
    bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
4053
0
4054
0
    // If the parent is in a shadow tree, make sure we don't
4055
0
    // bind with a document because shadow roots and its descendants
4056
0
    // are not in document.
4057
0
    nsIDocument* bindDocument =
4058
0
      aParent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
4059
0
    rv = content->BindToTree(bindDocument, aParent, aParent);
4060
0
    // If the anonymous content creator requested that the content should be
4061
0
    // editable, honor its request.
4062
0
    // We need to set the flag on the whole subtree, because existing
4063
0
    // children's flags have already been set as part of the BindToTree operation.
4064
0
    if (anonContentIsEditable) {
4065
0
      NS_ASSERTION(aParentFrame->IsTextInputFrame(),
4066
0
                   "We only expect this for anonymous content under a text control frame");
4067
0
      SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
4068
0
    }
4069
0
    if (NS_FAILED(rv)) {
4070
0
      content->UnbindFromTree();
4071
0
      return rv;
4072
0
    }
4073
0
  }
4074
0
4075
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
4076
0
  // Eagerly compute styles for the anonymous content tree.
4077
0
  for (auto& info : aContent) {
4078
0
    if (info.mContent->IsElement()) {
4079
0
      styleSet->StyleNewSubtree(info.mContent->AsElement());
4080
0
    }
4081
0
  }
4082
0
4083
0
  return NS_OK;
4084
0
}
4085
4086
static
4087
bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
4088
0
{
4089
0
  // -moz-{inline-}box is XUL, unless we're emulating it with flexbox.
4090
0
  if (!StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
4091
0
      (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
4092
0
       aDisplay->mDisplay == StyleDisplay::MozBox)) {
4093
0
    return true;
4094
0
  }
4095
0
4096
0
#ifdef MOZ_XUL
4097
0
  return (aDisplay->mDisplay == StyleDisplay::MozInlineGrid ||
4098
0
          aDisplay->mDisplay == StyleDisplay::MozInlineStack ||
4099
0
          aDisplay->mDisplay == StyleDisplay::MozGrid ||
4100
0
          aDisplay->mDisplay == StyleDisplay::MozStack ||
4101
0
          aDisplay->mDisplay == StyleDisplay::MozGridGroup ||
4102
0
          aDisplay->mDisplay == StyleDisplay::MozGridLine ||
4103
0
          aDisplay->mDisplay == StyleDisplay::MozDeck ||
4104
0
          aDisplay->mDisplay == StyleDisplay::MozPopup ||
4105
0
          aDisplay->mDisplay == StyleDisplay::MozGroupbox);
4106
#else
4107
  return false;
4108
#endif
4109
}
4110
4111
4112
// XUL frames are not allowed to be out of flow.
4113
#define SIMPLE_XUL_FCDATA(_func)                                        \
4114
0
  FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH,    \
4115
0
              _func)
4116
#define SCROLLABLE_XUL_FCDATA(_func)                                    \
4117
0
  FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |   \
4118
0
              FCDATA_MAY_NEED_SCROLLFRAME, _func)
4119
// .. but we allow some XUL frames to be _containers_ for out-of-flow content
4120
// (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
4121
#define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func)                   \
4122
  FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                             \
4123
              FCDATA_MAY_NEED_SCROLLFRAME, _func)
4124
4125
#define SIMPLE_XUL_CREATE(_tag, _func)            \
4126
0
  { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
4127
#define SCROLLABLE_XUL_CREATE(_tag, _func)            \
4128
0
  { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
4129
#define SIMPLE_XUL_DISPLAY_CREATE(_display, _func)      \
4130
0
  FCDATA_FOR_DISPLAY(_display, SIMPLE_XUL_FCDATA(_func))
4131
#define SCROLLABLE_XUL_DISPLAY_CREATE(_display, _func)                          \
4132
0
  FCDATA_FOR_DISPLAY(_display, SCROLLABLE_XUL_FCDATA(_func))
4133
#define SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(_display, _func)         \
4134
0
  FCDATA_FOR_DISPLAY(_display, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func))
4135
4136
static
4137
nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
4138
                             ComputedStyle* aComputedStyle)
4139
0
{
4140
0
  nsCOMPtr<nsBoxLayout> layout;
4141
0
  NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
4142
0
  return NS_NewBoxFrame(aPresShell, aComputedStyle, false, layout);
4143
0
}
4144
4145
/* static */
4146
const nsCSSFrameConstructor::FrameConstructionData*
4147
nsCSSFrameConstructor::FindXULTagData(const Element& aElement,
4148
                                      nsAtom* aTag,
4149
                                      ComputedStyle& aStyle)
4150
0
{
4151
0
  MOZ_ASSERT(aElement.IsXULElement());
4152
0
4153
0
  static const FrameConstructionDataByTag sXULTagData[] = {
4154
0
#ifdef MOZ_XUL
4155
0
    SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
4156
0
    SCROLLABLE_XUL_CREATE(thumb, NS_NewButtonBoxFrame),
4157
0
    SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
4158
0
    SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
4159
0
    SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
4160
0
    SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
4161
0
    SCROLLABLE_XUL_CREATE(toolbarpaletteitem, NS_NewBoxFrame),
4162
0
    SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
4163
0
    SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
4164
0
    SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
4165
0
    SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
4166
0
    SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
4167
0
    SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
4168
0
    SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
4169
0
    SIMPLE_TAG_CHAIN(description, nsCSSFrameConstructor::FindXULDescriptionData),
4170
0
    SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
4171
0
    SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
4172
0
    SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
4173
#ifdef XP_MACOSX
4174
    SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
4175
#else
4176
0
    SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
4177
0
#endif /* XP_MACOSX */
4178
0
    SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData),
4179
0
    SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
4180
0
    SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
4181
0
    SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame),
4182
0
    SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame),
4183
0
    SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame),
4184
0
#endif /* MOZ_XUL */
4185
0
    SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
4186
0
    SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
4187
0
    SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
4188
0
  };
4189
0
4190
0
  return FindDataByTag(aTag, aElement, aStyle, sXULTagData,
4191
0
                       ArrayLength(sXULTagData));
4192
0
}
4193
4194
#ifdef MOZ_XUL
4195
/* static */
4196
const nsCSSFrameConstructor::FrameConstructionData*
4197
nsCSSFrameConstructor::FindPopupGroupData(const Element& aElement, ComputedStyle&)
4198
0
{
4199
0
  if (!aElement.IsRootOfNativeAnonymousSubtree()) {
4200
0
    return nullptr;
4201
0
  }
4202
0
4203
0
  static const FrameConstructionData sPopupSetData =
4204
0
    SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
4205
0
  return &sPopupSetData;
4206
0
}
4207
4208
/* static */
4209
const nsCSSFrameConstructor::FrameConstructionData
4210
nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
4211
4212
/* static */
4213
const nsCSSFrameConstructor::FrameConstructionData*
4214
nsCSSFrameConstructor::FindXULLabelData(const Element& aElement, ComputedStyle&)
4215
0
{
4216
0
  if (aElement.HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4217
0
    return &sXULTextBoxData;
4218
0
  }
4219
0
4220
0
  static const FrameConstructionData sLabelData =
4221
0
    SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
4222
0
  return &sLabelData;
4223
0
}
4224
4225
static nsIFrame*
4226
NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, ComputedStyle *aContext)
4227
0
{
4228
0
  // XXXbz do we really need to set up the block formatting context root? If the
4229
0
  // parent is not a block we'll get it anyway, and if it is, do we want it?
4230
0
  return NS_NewBlockFormattingContext(aPresShell, aContext);
4231
0
}
4232
4233
/* static */
4234
const nsCSSFrameConstructor::FrameConstructionData*
4235
nsCSSFrameConstructor::FindXULDescriptionData(const Element& aElement,
4236
                                              ComputedStyle&)
4237
0
{
4238
0
  if (aElement.HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4239
0
    return &sXULTextBoxData;
4240
0
  }
4241
0
4242
0
  static const FrameConstructionData sDescriptionData =
4243
0
    SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame);
4244
0
  return &sDescriptionData;
4245
0
}
4246
4247
#ifdef XP_MACOSX
4248
/* static */
4249
const nsCSSFrameConstructor::FrameConstructionData*
4250
nsCSSFrameConstructor::FindXULMenubarData(const Element& aElement,
4251
                                          ComputedStyle&)
4252
{
4253
  nsCOMPtr<nsIDocShell> treeItem = aElement.OwnerDoc()->GetDocShell();
4254
  if (treeItem && nsIDocShellTreeItem::typeChrome == treeItem->ItemType()) {
4255
    nsCOMPtr<nsIDocShellTreeItem> parent;
4256
    treeItem->GetParent(getter_AddRefs(parent));
4257
    if (!parent) {
4258
      // This is the root.  Suppress the menubar, since on Mac
4259
      // window menus are not attached to the window.
4260
      static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4261
      return &sSuppressData;
4262
    }
4263
  }
4264
4265
  static const FrameConstructionData sMenubarData =
4266
    SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
4267
  return &sMenubarData;
4268
}
4269
#endif /* XP_MACOSX */
4270
4271
#endif /* MOZ_XUL */
4272
4273
/* static */
4274
const nsCSSFrameConstructor::FrameConstructionData*
4275
nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay& aDisplay,
4276
                                          const Element& aElement)
4277
0
{
4278
0
  static const FrameConstructionDataByDisplay sXULDisplayData[] = {
4279
0
    SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozBox,
4280
0
                                                   NS_NewBoxFrame),
4281
0
    SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineBox,
4282
0
                                                   NS_NewBoxFrame),
4283
0
#ifdef MOZ_XUL
4284
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGrid, NS_NewGridBoxFrame),
4285
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineGrid, NS_NewGridBoxFrame),
4286
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridGroup,
4287
0
                                  NS_NewGridRowGroupFrame),
4288
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridLine,
4289
0
                                  NS_NewGridRowLeafFrame),
4290
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozStack, NS_NewStackFrame),
4291
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineStack, NS_NewStackFrame),
4292
0
    SIMPLE_XUL_DISPLAY_CREATE(StyleDisplay::MozDeck, NS_NewDeckFrame),
4293
0
    SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGroupbox, NS_NewGroupBoxFrame),
4294
0
    FCDATA_FOR_DISPLAY(StyleDisplay::MozPopup,
4295
0
      FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
4296
0
                  FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame))
4297
0
#endif /* MOZ_XUL */
4298
0
  };
4299
0
4300
0
  if (aDisplay.mDisplay < StyleDisplay::MozBox) {
4301
0
    return nullptr;
4302
0
  }
4303
0
4304
0
  MOZ_ASSERT(aDisplay.mDisplay <= StyleDisplay::MozPopup,
4305
0
             "Someone added a new display value?");
4306
0
4307
0
  if (aDisplay.mDisplay == StyleDisplay::MozBox ||
4308
0
      aDisplay.mDisplay == StyleDisplay::MozInlineBox) {
4309
0
    if (!aElement.IsInNativeAnonymousSubtree() &&
4310
0
        aElement.OwnerDoc()->IsContentDocument()) {
4311
0
      aElement.OwnerDoc()->WarnOnceAbout(nsIDocument::eMozBoxOrInlineBoxDisplay);
4312
0
    }
4313
0
4314
0
    // If we're emulating -moz-box with flexbox, then treat it as non-XUL and
4315
0
    // return null (except for scrollcorners which have to be XUL becuase their
4316
0
    // parent reflows them with BoxReflow() which means they have to get
4317
0
    // actual-XUL frames).
4318
0
    if (StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
4319
0
        !aElement.IsXULElement(nsGkAtoms::scrollcorner)) {
4320
0
      return nullptr;
4321
0
    }
4322
0
  }
4323
0
4324
0
  const FrameConstructionDataByDisplay& data =
4325
0
    sXULDisplayData[size_t(aDisplay.mDisplay) - size_t(StyleDisplay::MozBox)];
4326
0
  MOZ_ASSERT(aDisplay.mDisplay == data.mDisplay,
4327
0
             "Did someone mess with the order?");
4328
0
4329
0
  return &data.mData;
4330
0
}
4331
4332
already_AddRefed<ComputedStyle>
4333
nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
4334
                                                nsIContent*              aContent,
4335
                                                ComputedStyle*           aContentStyle,
4336
                                                nsContainerFrame*        aParentFrame,
4337
                                                nsAtom*                  aScrolledPseudo,
4338
                                                bool                     aIsRoot,
4339
                                                nsContainerFrame*&       aNewFrame)
4340
0
{
4341
0
  nsContainerFrame* gfxScrollFrame = aNewFrame;
4342
0
4343
0
  nsFrameItems anonymousItems;
4344
0
4345
0
  RefPtr<ComputedStyle> contentStyle = aContentStyle;
4346
0
4347
0
  if (!gfxScrollFrame) {
4348
0
    // Build a XULScrollFrame when the child is a box, otherwise an
4349
0
    // HTMLScrollFrame
4350
0
    // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4351
0
    // I wonder whether we can eliminate that somehow.
4352
0
    const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay();
4353
0
    if (IsXULDisplayType(displayStyle)) {
4354
0
      gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot,
4355
0
          displayStyle->mDisplay == StyleDisplay::MozStack ||
4356
0
          displayStyle->mDisplay == StyleDisplay::MozInlineStack);
4357
0
    } else {
4358
0
      gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
4359
0
    }
4360
0
4361
0
    InitAndRestoreFrame(aState, aContent, aParentFrame, gfxScrollFrame);
4362
0
  }
4363
0
4364
0
  // if there are any anonymous children for the scroll frame, create
4365
0
  // frames for them.
4366
0
  //
4367
0
  // We can't take the normal ProcessChildren path, because the NAC needs to
4368
0
  // be parented to the scrollframe, and everything else needs to be parented
4369
0
  // to the scrolledframe.
4370
0
  AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4371
0
  DebugOnly<nsresult> rv = GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC);
4372
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
4373
0
  if (scrollNAC.Length() > 0) {
4374
0
    AutoFrameConstructionItemList items(this);
4375
0
    AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
4376
0
    ConstructFramesFromItemList(aState, items, gfxScrollFrame,
4377
0
                                /* aParentIsWrapperAnonBox = */ false,
4378
0
                                anonymousItems);
4379
0
  }
4380
0
4381
0
  aNewFrame = gfxScrollFrame;
4382
0
  gfxScrollFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4383
0
4384
0
  // we used the style that was passed in. So resolve another one.
4385
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
4386
0
  RefPtr<ComputedStyle> scrolledChildStyle =
4387
0
    styleSet->ResolveInheritingAnonymousBoxStyle(aScrolledPseudo, contentStyle);
4388
0
4389
0
  if (gfxScrollFrame) {
4390
0
     gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems);
4391
0
  }
4392
0
4393
0
  return scrolledChildStyle.forget();
4394
0
}
4395
4396
void
4397
nsCSSFrameConstructor::FinishBuildingScrollFrame(nsContainerFrame* aScrollFrame,
4398
                                                 nsIFrame* aScrolledFrame)
4399
0
{
4400
0
  nsFrameList scrolled(aScrolledFrame, aScrolledFrame);
4401
0
  aScrollFrame->AppendFrames(kPrincipalList, scrolled);
4402
0
}
4403
4404
/**
4405
 * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
4406
 *
4407
 * ------- for gfx scrollbars ------
4408
 *
4409
 *
4410
 *            ScrollFrame
4411
 *                 ^
4412
 *                 |
4413
 *               Frame (scrolled frame you passed in)
4414
 *
4415
 *
4416
 *-----------------------------------
4417
 * LEGEND:
4418
 *
4419
 * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
4420
 *
4421
 * @param aContent the content node of the child to wrap.
4422
 * @param aScrolledFrame The frame of the content to wrap. This should not be
4423
 *                    Initialized. This method will initialize it with a scrolled pseudo
4424
 *                    and no nsIContent. The content will be attached to the scrollframe
4425
 *                    returned.
4426
 * @param aContentStyle the style that has already been resolved for the content
4427
 *                      being passed in.
4428
 *
4429
 * @param aParentFrame The parent to attach the scroll frame to
4430
 *
4431
 * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
4432
 *                  scrolled frame you passed in. (returned)
4433
 *                  If this is not null, we'll just use it
4434
 * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
4435
 */
4436
void
4437
nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
4438
                                        nsIContent*              aContent,
4439
                                        ComputedStyle*           aContentStyle,
4440
                                        nsIFrame*                aScrolledFrame,
4441
                                        nsContainerFrame*        aParentFrame,
4442
                                        nsContainerFrame*&       aNewFrame)
4443
0
{
4444
0
  RefPtr<ComputedStyle> scrolledContentStyle =
4445
0
    BeginBuildingScrollFrame(aState, aContent, aContentStyle, aParentFrame,
4446
0
                             nsCSSAnonBoxes::scrolledContent(),
4447
0
                             false, aNewFrame);
4448
0
4449
0
  aScrolledFrame->SetComputedStyleWithoutNotification(scrolledContentStyle);
4450
0
  InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4451
0
4452
0
  FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
4453
0
}
4454
4455
const nsCSSFrameConstructor::FrameConstructionData*
4456
nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
4457
                                       const Element& aElement)
4458
0
{
4459
0
  static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)),
4460
0
                "Check eParentTypeCount should not overflow");
4461
0
4462
0
  // The style system ensures that floated and positioned frames are
4463
0
  // block-level.
4464
0
  NS_ASSERTION(!(aDisplay.IsFloatingStyle() ||
4465
0
                 aDisplay.IsAbsolutelyPositionedStyle()) ||
4466
0
               aDisplay.IsBlockOutsideStyle() ||
4467
0
               aDisplay.mDisplay == StyleDisplay::Contents,
4468
0
               "Style system did not apply CSS2.1 section 9.7 fixups");
4469
0
4470
0
  // If this is "body", try propagating its scroll style to the viewport
4471
0
  // Note that we need to do this even if the body is NOT scrollable;
4472
0
  // it might have dynamically changed from scrollable to not scrollable,
4473
0
  // and that might need to be propagated.
4474
0
  // XXXbz is this the right place to do this?  If this code moves,
4475
0
  // make this function static.
4476
0
  bool propagatedScrollToViewport = false;
4477
0
  if (aElement.IsHTMLElement(nsGkAtoms::body)) {
4478
0
    if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4479
0
      propagatedScrollToViewport =
4480
0
        presContext->UpdateViewportScrollStylesOverride() == &aElement;
4481
0
    }
4482
0
  }
4483
0
4484
0
  NS_ASSERTION(!propagatedScrollToViewport ||
4485
0
               !mPresShell->GetPresContext()->IsPaginated(),
4486
0
               "Shouldn't propagate scroll in paginated contexts");
4487
0
4488
0
  if (aDisplay.IsBlockInsideStyle()) {
4489
0
    // If the frame is a block-level frame and is scrollable, then wrap it in a
4490
0
    // scroll frame.  Except we don't want to do that for paginated contexts for
4491
0
    // frames that are block-outside and aren't frames for native anonymous stuff.
4492
0
    // XXX Ignore tables for the time being (except caption)
4493
0
    const uint32_t kCaptionCtorFlags =
4494
0
      FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable);
4495
0
    bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
4496
0
    bool suppressScrollFrame = false;
4497
0
    bool needScrollFrame = aDisplay.IsScrollableOverflow() &&
4498
0
                           !propagatedScrollToViewport;
4499
0
    if (needScrollFrame) {
4500
0
      suppressScrollFrame = mPresShell->GetPresContext()->IsPaginated() &&
4501
0
                            aDisplay.IsBlockOutsideStyle() &&
4502
0
                            !aElement.IsInNativeAnonymousSubtree();
4503
0
      if (!suppressScrollFrame) {
4504
0
        static const FrameConstructionData sScrollableBlockData[2] =
4505
0
          { FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock),
4506
0
            FULL_CTOR_FCDATA(kCaptionCtorFlags,
4507
0
                             &nsCSSFrameConstructor::ConstructScrollableBlock) };
4508
0
        return &sScrollableBlockData[caption];
4509
0
      }
4510
0
4511
0
      // If the scrollable frame would have propagated its scrolling to the
4512
0
      // viewport, we still want to construct a regular block rather than a
4513
0
      // scrollframe so that it paginates correctly, but we don't want to set
4514
0
      // the bit on the block that tells it to clip at paint time.
4515
0
      if (mPresShell->GetPresContext()->
4516
0
            ElementWouldPropagateScrollStyles(aElement)) {
4517
0
        suppressScrollFrame = false;
4518
0
      }
4519
0
    }
4520
0
4521
0
    // Handle various non-scrollable blocks.
4522
0
    static const FrameConstructionData sNonScrollableBlockData[2][2] = {
4523
0
      { FULL_CTOR_FCDATA(0,
4524
0
                         &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4525
0
        FULL_CTOR_FCDATA(kCaptionCtorFlags,
4526
0
                         &nsCSSFrameConstructor::ConstructNonScrollableBlock) },
4527
0
      { FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
4528
0
                         &nsCSSFrameConstructor::ConstructNonScrollableBlock),
4529
0
        FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK | kCaptionCtorFlags,
4530
0
                         &nsCSSFrameConstructor::ConstructNonScrollableBlock) }
4531
0
    };
4532
0
    return &sNonScrollableBlockData[suppressScrollFrame][caption];
4533
0
  }
4534
0
4535
0
  // If this is for a <body> node and we've propagated the scroll-frame to the
4536
0
  // viewport, we need to make sure not to add another layer of scrollbars, so
4537
0
  // we use a different FCData struct without FCDATA_MAY_NEED_SCROLLFRAME.
4538
0
  if (propagatedScrollToViewport && aDisplay.IsScrollableOverflow()) {
4539
0
    if (aDisplay.mDisplay == StyleDisplay::Flex ||
4540
0
        aDisplay.mDisplay == StyleDisplay::WebkitBox ||
4541
0
        (StaticPrefs::layout_css_emulate_moz_box_with_flex() &&
4542
0
         aDisplay.mDisplay == StyleDisplay::MozBox)) {
4543
0
      static const FrameConstructionData sNonScrollableFlexData =
4544
0
        FCDATA_DECL(0, NS_NewFlexContainerFrame);
4545
0
      return &sNonScrollableFlexData;
4546
0
    }
4547
0
    if (aDisplay.mDisplay == StyleDisplay::Grid) {
4548
0
      static const FrameConstructionData sNonScrollableGridData =
4549
0
        FCDATA_DECL(0, NS_NewGridContainerFrame);
4550
0
      return &sNonScrollableGridData;
4551
0
    }
4552
0
  }
4553
0
4554
0
  // NOTE: Make sure to keep this up to date with the StyleDisplay definition!
4555
0
  static const FrameConstructionDataByDisplay sDisplayData[] = {
4556
0
    FCDATA_FOR_DISPLAY(StyleDisplay::None, UNREACHABLE_FCDATA()),
4557
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Block, UNREACHABLE_FCDATA()),
4558
0
    FCDATA_FOR_DISPLAY(StyleDisplay::FlowRoot, UNREACHABLE_FCDATA()),
4559
0
    // To keep the hash table small don't add inline frames (they're
4560
0
    // typically things like FONT and B), because we can quickly
4561
0
    // find them if we need to.
4562
0
    // XXXbz the "quickly" part is a bald-faced lie!
4563
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Inline,
4564
0
      FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
4565
0
                       &nsCSSFrameConstructor::ConstructInline)),
4566
0
    FCDATA_FOR_DISPLAY(StyleDisplay::InlineBlock, UNREACHABLE_FCDATA()),
4567
0
    FCDATA_FOR_DISPLAY(StyleDisplay::ListItem, UNREACHABLE_FCDATA()),
4568
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Table,
4569
0
      FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4570
0
    FCDATA_FOR_DISPLAY(StyleDisplay::InlineTable,
4571
0
      FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable)),
4572
0
    // NOTE: In the unlikely event that we add another table-part here that has
4573
0
    // a desired-parent-type (& hence triggers table fixup), we'll need to also
4574
0
    // update the flexbox chunk in ComputedStyle::ApplyStyleFixups().
4575
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableRowGroup,
4576
0
      FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4577
0
                       FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4578
0
                       &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4579
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableColumn,
4580
0
      FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4581
0
                       FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup),
4582
0
                       &nsCSSFrameConstructor::ConstructTableCol)),
4583
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableColumnGroup,
4584
0
      FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4585
0
                  FCDATA_SKIP_ABSPOS_PUSH |
4586
0
                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4587
0
                  NS_NewTableColGroupFrame)),
4588
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableHeaderGroup,
4589
0
      FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4590
0
                       FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4591
0
                       &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4592
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableFooterGroup,
4593
0
      FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4594
0
                       FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4595
0
                       &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4596
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableRow,
4597
0
      FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4598
0
                       FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
4599
0
                       &nsCSSFrameConstructor::ConstructTableRowOrRowGroup)),
4600
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableCell,
4601
0
      FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4602
0
                       FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
4603
0
                       &nsCSSFrameConstructor::ConstructTableCell)),
4604
0
    FCDATA_FOR_DISPLAY(StyleDisplay::TableCaption, UNREACHABLE_FCDATA()),
4605
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Flex,
4606
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4607
0
    FCDATA_FOR_DISPLAY(StyleDisplay::InlineFlex,
4608
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4609
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Grid,
4610
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4611
0
    FCDATA_FOR_DISPLAY(StyleDisplay::InlineGrid,
4612
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame)),
4613
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Ruby,
4614
0
      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewRubyFrame)),
4615
0
    FCDATA_FOR_DISPLAY(StyleDisplay::RubyBase,
4616
0
      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4617
0
                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer),
4618
0
                  NS_NewRubyBaseFrame)),
4619
0
    FCDATA_FOR_DISPLAY(StyleDisplay::RubyBaseContainer,
4620
0
      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4621
0
                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4622
0
                  NS_NewRubyBaseContainerFrame)),
4623
0
    FCDATA_FOR_DISPLAY(StyleDisplay::RubyText,
4624
0
      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
4625
0
                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
4626
0
                  NS_NewRubyTextFrame)),
4627
0
    FCDATA_FOR_DISPLAY(StyleDisplay::RubyTextContainer,
4628
0
      FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
4629
0
                  NS_NewRubyTextContainerFrame)),
4630
0
    FCDATA_FOR_DISPLAY(StyleDisplay::Contents, UNREACHABLE_FCDATA()),
4631
0
    FCDATA_FOR_DISPLAY(StyleDisplay::WebkitBox,
4632
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4633
0
    FCDATA_FOR_DISPLAY(StyleDisplay::WebkitInlineBox,
4634
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4635
0
    FCDATA_FOR_DISPLAY(StyleDisplay::MozBox,
4636
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4637
0
    FCDATA_FOR_DISPLAY(StyleDisplay::MozInlineBox,
4638
0
      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
4639
0
  };
4640
0
  static_assert(ArrayLength(sDisplayData) == size_t(StyleDisplay::MozInlineBox) + 1,
4641
0
                "Be sure to update sDisplayData if you touch StyleDisplay");
4642
0
  MOZ_ASSERT(StaticPrefs::layout_css_emulate_moz_box_with_flex() ||
4643
0
             (aDisplay.mDisplay != StyleDisplay::MozBox &&
4644
0
              aDisplay.mDisplay != StyleDisplay::MozInlineBox),
4645
0
             "-moz-{inline-}box as XUL should have already been handled");
4646
0
  MOZ_ASSERT(size_t(aDisplay.mDisplay) < ArrayLength(sDisplayData),
4647
0
             "XUL display data should have already been handled");
4648
0
4649
0
  // See the mDisplay fixup code in StyleAdjuster::adjust.
4650
0
  MOZ_ASSERT(aDisplay.mDisplay != StyleDisplay::Contents ||
4651
0
             !aElement.IsRootOfNativeAnonymousSubtree(),
4652
0
             "display:contents on anonymous content is unsupported");
4653
0
4654
0
  const FrameConstructionDataByDisplay& data =
4655
0
    sDisplayData[size_t(aDisplay.mDisplay)];
4656
0
4657
0
  MOZ_ASSERT(data.mDisplay == aDisplay.mDisplay,
4658
0
             "Someone messed up the order in the display values");
4659
0
4660
0
  return &data.mData;
4661
0
}
4662
4663
nsIFrame*
4664
nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState,
4665
                                                FrameConstructionItem&   aItem,
4666
                                                nsContainerFrame*        aParentFrame,
4667
                                                const nsStyleDisplay*    aDisplay,
4668
                                                nsFrameItems&            aFrameItems)
4669
0
{
4670
0
  return ConstructScrollableBlockWithConstructor(aState, aItem, aParentFrame,
4671
0
                                                 aDisplay, aFrameItems,
4672
0
                                                 NS_NewBlockFormattingContext);
4673
0
}
4674
4675
nsIFrame*
4676
nsCSSFrameConstructor::ConstructScrollableBlockWithConstructor(
4677
  nsFrameConstructorState& aState,
4678
  FrameConstructionItem& aItem,
4679
  nsContainerFrame* aParentFrame,
4680
  const nsStyleDisplay* aDisplay,
4681
  nsFrameItems& aFrameItems,
4682
  BlockFrameCreationFunc aConstructor)
4683
0
{
4684
0
  nsIContent* const content = aItem.mContent;
4685
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
4686
0
4687
0
  nsContainerFrame* newFrame = nullptr;
4688
0
  RefPtr<ComputedStyle> scrolledContentStyle
4689
0
    = BeginBuildingScrollFrame(aState, content, computedStyle,
4690
0
                               aState.GetGeometricParent(*aDisplay, aParentFrame),
4691
0
                               nsCSSAnonBoxes::scrolledContent(),
4692
0
                               false, newFrame);
4693
0
4694
0
  // Create our block frame
4695
0
  // pass a temporary stylecontext, the correct one will be set later
4696
0
  nsContainerFrame* scrolledFrame = aConstructor(mPresShell, computedStyle);
4697
0
4698
0
  // Make sure to AddChild before we call ConstructBlock so that we
4699
0
  // end up before our descendants in fixed-pos lists as needed.
4700
0
  aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
4701
0
4702
0
  nsFrameItems blockItem;
4703
0
  ConstructBlock(aState, content, newFrame, newFrame, scrolledContentStyle,
4704
0
                 &scrolledFrame, blockItem,
4705
0
                 aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
4706
0
                 aItem.mPendingBinding);
4707
0
4708
0
  MOZ_ASSERT(blockItem.OnlyChild() == scrolledFrame,
4709
0
             "Scrollframe's frameItems should be exactly the scrolled frame!");
4710
0
  FinishBuildingScrollFrame(newFrame, scrolledFrame);
4711
0
4712
0
  return newFrame;
4713
0
}
4714
4715
nsIFrame*
4716
nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState& aState,
4717
                                                   FrameConstructionItem&   aItem,
4718
                                                   nsContainerFrame*        aParentFrame,
4719
                                                   const nsStyleDisplay*    aDisplay,
4720
                                                   nsFrameItems&            aFrameItems)
4721
0
{
4722
0
  return ConstructNonScrollableBlockWithConstructor(aState, aItem, aParentFrame,
4723
0
                                                    aDisplay, aFrameItems,
4724
0
                                                    NS_NewBlockFrame);
4725
0
}
4726
4727
nsIFrame*
4728
nsCSSFrameConstructor::ConstructNonScrollableBlockWithConstructor(
4729
  nsFrameConstructorState& aState,
4730
  FrameConstructionItem& aItem,
4731
  nsContainerFrame* aParentFrame,
4732
  const nsStyleDisplay* aDisplay,
4733
  nsFrameItems& aFrameItems,
4734
  BlockFrameCreationFunc aConstructor)
4735
0
{
4736
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
4737
0
4738
0
  // We want a block formatting context root in paginated contexts for
4739
0
  // every block that would be scrollable in a non-paginated context.
4740
0
  // We mark our blocks with a bit here if this condition is true, so
4741
0
  // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
4742
0
  bool clipPaginatedOverflow =
4743
0
    (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
4744
0
  nsFrameState flags = nsFrameState(0);
4745
0
  if ((aDisplay->IsAbsolutelyPositionedStyle() ||
4746
0
       aDisplay->IsFloatingStyle() ||
4747
0
       StyleDisplay::InlineBlock == aDisplay->mDisplay ||
4748
0
       clipPaginatedOverflow) &&
4749
0
      !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
4750
0
    flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS;
4751
0
    if (clipPaginatedOverflow) {
4752
0
      flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
4753
0
    }
4754
0
  }
4755
0
4756
0
  nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
4757
0
  newFrame->AddStateBits(flags);
4758
0
  ConstructBlock(aState, aItem.mContent,
4759
0
                 aState.GetGeometricParent(*aDisplay, aParentFrame),
4760
0
                 aParentFrame, computedStyle, &newFrame,
4761
0
                 aFrameItems,
4762
0
                 aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr,
4763
0
                 aItem.mPendingBinding);
4764
0
  return newFrame;
4765
0
}
4766
4767
4768
void
4769
nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
4770
                                           nsIContent*              aContent,
4771
                                           nsContainerFrame*        aParentFrame,
4772
                                           nsIFrame*                aNewFrame,
4773
                                           bool                     aAllowCounters)
4774
0
{
4775
0
  MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized");
4776
0
4777
0
  // Initialize the frame
4778
0
  aNewFrame->Init(aContent, aParentFrame, nullptr);
4779
0
  aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4780
0
4781
0
  if (aState.mFrameState) {
4782
0
    // Restore frame state for just the newly created frame.
4783
0
    RestoreFrameStateFor(aNewFrame, aState.mFrameState);
4784
0
  }
4785
0
4786
0
  if (aAllowCounters &&
4787
0
      mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
4788
0
    CountersDirty();
4789
0
  }
4790
0
}
4791
4792
already_AddRefed<ComputedStyle>
4793
nsCSSFrameConstructor::ResolveComputedStyle(nsIContent* aContent)
4794
0
{
4795
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
4796
0
4797
0
  if (auto* element = Element::FromNode(aContent)) {
4798
0
    return styleSet->ResolveServoStyle(*element);
4799
0
  }
4800
0
4801
0
  MOZ_ASSERT(aContent->IsText(),
4802
0
             "shouldn't waste time creating ComputedStyles for "
4803
0
             "comments and processing instructions");
4804
0
4805
0
  Element* parent = aContent->GetFlattenedTreeParentElement();
4806
0
  MOZ_ASSERT(parent, "Text out of the flattened tree?");
4807
0
4808
0
  // FIXME(emilio): We can't use ResolveServoStyle properly because this text
4809
0
  // node can come from non-lazy frame construction, in which case the style we
4810
0
  // inherit from can indeed be out-of-date. After an eventual XBL removal, this
4811
0
  // can go. Note that this is not a correctness issue, since we'll restyle
4812
0
  // later in any case.
4813
0
  //
4814
0
  // Also, this probably doesn't need to be a strong ref...
4815
0
  //
4816
0
  // Do NOT add new callers to this function in this file, ever, or I'll find
4817
0
  // out.
4818
0
  RefPtr<ComputedStyle> parentStyle =
4819
0
    Servo_Element_GetPrimaryComputedValues(parent).Consume();
4820
0
  return styleSet->ResolveStyleForText(aContent, parentStyle);
4821
0
}
4822
4823
// MathML Mod - RBS
4824
void
4825
nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
4826
                                             nsIContent* aContent,
4827
                                             nsContainerFrame* aParentFrame,
4828
                                             nsFrameItems& aBlockItems,
4829
                                             nsFrameItems& aNewItems)
4830
0
{
4831
0
  if (aBlockItems.IsEmpty()) {
4832
0
    // Nothing to do
4833
0
    return;
4834
0
  }
4835
0
4836
0
  nsAtom* anonPseudo = nsCSSAnonBoxes::mozMathMLAnonymousBlock();
4837
0
4838
0
  ComputedStyle* parentContext =
4839
0
    nsFrame::CorrectStyleParentFrame(aParentFrame,
4840
0
                                     anonPseudo)->Style();
4841
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
4842
0
  RefPtr<ComputedStyle> blockContext;
4843
0
  blockContext = styleSet->
4844
0
    ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
4845
0
4846
0
  // then, create a block frame that will wrap the child frames. Make it a
4847
0
  // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4848
0
  // is not a suitable block.
4849
0
  nsContainerFrame* blockFrame =
4850
0
    NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
4851
0
4852
0
  InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
4853
0
  ReparentFrames(this, blockFrame, aBlockItems, false);
4854
0
  // We have to walk over aBlockItems before we hand it over to blockFrame.
4855
0
  for (nsIFrame* f : aBlockItems) {
4856
0
    f->SetParentIsWrapperAnonBox();
4857
0
  }
4858
0
  // abs-pos and floats are disabled in MathML children so we don't have to
4859
0
  // worry about messing up those.
4860
0
  blockFrame->SetInitialChildList(kPrincipalList, aBlockItems);
4861
0
  NS_ASSERTION(aBlockItems.IsEmpty(), "What happened?");
4862
0
  aBlockItems.Clear();
4863
0
  aNewItems.AddChild(blockFrame);
4864
0
}
4865
4866
// Only <math> elements can be floated or positioned.  All other MathML
4867
// should be in-flow.
4868
#define SIMPLE_MATHML_CREATE(_tag, _func)                               \
4869
0
  { &nsGkAtoms::_tag,                                                   \
4870
0
      FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                         \
4871
0
                  FCDATA_FORCE_NULL_ABSPOS_CONTAINER |                  \
4872
0
                  FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
4873
4874
/* static */
4875
const nsCSSFrameConstructor::FrameConstructionData*
4876
nsCSSFrameConstructor::FindMathMLData(const Element& aElement,
4877
                                      ComputedStyle& aStyle)
4878
0
{
4879
0
  MOZ_ASSERT(aElement.IsMathMLElement());
4880
0
4881
0
  nsAtom* tag = aElement.NodeInfo()->NameAtom();
4882
0
4883
0
  // Handle <math> specially, because it sometimes produces inlines
4884
0
  if (tag == nsGkAtoms::math) {
4885
0
    // The IsBlockOutsideStyle() check must match what
4886
0
    // specified::Display::equivalent_block_display is checking for
4887
0
    // already-block-outside things. Though the behavior here for the
4888
0
    // display:table case is pretty weird...
4889
0
    if (aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
4890
0
      static const FrameConstructionData sBlockMathData =
4891
0
        FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
4892
0
                    FCDATA_WRAP_KIDS_IN_BLOCKS,
4893
0
                    NS_NewMathMLmathBlockFrame);
4894
0
      return &sBlockMathData;
4895
0
    }
4896
0
4897
0
    static const FrameConstructionData sInlineMathData =
4898
0
      FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
4899
0
                  FCDATA_IS_LINE_PARTICIPANT |
4900
0
                  FCDATA_WRAP_KIDS_IN_BLOCKS,
4901
0
                  NS_NewMathMLmathInlineFrame);
4902
0
    return &sInlineMathData;
4903
0
  }
4904
0
4905
0
4906
0
  static const FrameConstructionDataByTag sMathMLData[] = {
4907
0
    SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame),
4908
0
    SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame),
4909
0
    SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
4910
0
    SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
4911
0
    SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
4912
0
    SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
4913
0
    SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
4914
0
    SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
4915
0
    SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame),
4916
0
    SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame),
4917
0
    SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame),
4918
0
    SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
4919
0
    SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
4920
0
    SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
4921
0
    SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmrowFrame),
4922
0
    SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
4923
0
    SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
4924
0
    SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
4925
0
    SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
4926
0
    SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame),
4927
0
    SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame),
4928
0
    SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmrowFrame),
4929
0
    SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame),
4930
0
    SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame),
4931
0
    SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame),
4932
0
    SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame),
4933
0
    SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame),
4934
0
    SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame),
4935
0
    SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)
4936
0
  };
4937
0
4938
0
  return FindDataByTag(tag, aElement, aStyle, sMathMLData,
4939
0
                       ArrayLength(sMathMLData));
4940
0
}
4941
4942
4943
nsContainerFrame*
4944
nsCSSFrameConstructor::ConstructFrameWithAnonymousChild(
4945
                                   nsFrameConstructorState& aState,
4946
                                   FrameConstructionItem&   aItem,
4947
                                   nsContainerFrame*        aParentFrame,
4948
                                   nsFrameItems&            aFrameItems,
4949
                                   ContainerFrameCreationFunc aConstructor,
4950
                                   ContainerFrameCreationFunc aInnerConstructor,
4951
                                   nsICSSAnonBoxPseudo*     aInnerPseudo,
4952
                                   bool                     aCandidateRootFrame)
4953
0
{
4954
0
  nsIContent* const content = aItem.mContent;
4955
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
4956
0
4957
0
  // Create the outer frame:
4958
0
  nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
4959
0
4960
0
  InitAndRestoreFrame(aState, content,
4961
0
                      aCandidateRootFrame ?
4962
0
                        aState.GetGeometricParent(*computedStyle->StyleDisplay(),
4963
0
                                                  aParentFrame) :
4964
0
                        aParentFrame,
4965
0
                      newFrame);
4966
0
  newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4967
0
4968
0
  // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
4969
0
  RefPtr<ComputedStyle> scForAnon;
4970
0
  scForAnon = mPresShell->StyleSet()->
4971
0
    ResolveInheritingAnonymousBoxStyle(aInnerPseudo, computedStyle);
4972
0
4973
0
  // Create the anonymous inner wrapper frame
4974
0
  nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
4975
0
4976
0
  InitAndRestoreFrame(aState, content, newFrame, innerFrame);
4977
0
4978
0
  // Put the newly created frames into the right child list
4979
0
  SetInitialSingleChild(newFrame, innerFrame);
4980
0
4981
0
  aState.AddChild(newFrame, aFrameItems, content, aParentFrame,
4982
0
                  aCandidateRootFrame, aCandidateRootFrame);
4983
0
4984
0
  if (!mRootElementFrame && aCandidateRootFrame) {
4985
0
    // The frame we're constructing will be the root element frame.
4986
0
    // Set mRootElementFrame before processing children.
4987
0
    mRootElementFrame = newFrame;
4988
0
  }
4989
0
4990
0
  nsFrameItems childItems;
4991
0
4992
0
  // Process children
4993
0
  if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
4994
0
    ConstructFramesFromItemList(aState, aItem.mChildItems,
4995
0
                                innerFrame,
4996
0
                                aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX,
4997
0
                                childItems);
4998
0
  } else {
4999
0
    ProcessChildren(aState, content, computedStyle, innerFrame,
5000
0
                    true, childItems, false, aItem.mPendingBinding);
5001
0
  }
5002
0
5003
0
  // Set the inner wrapper frame's initial primary list
5004
0
  innerFrame->SetInitialChildList(kPrincipalList, childItems);
5005
0
5006
0
  return newFrame;
5007
0
}
5008
5009
nsIFrame*
5010
nsCSSFrameConstructor::ConstructOuterSVG(nsFrameConstructorState& aState,
5011
                                         FrameConstructionItem&   aItem,
5012
                                         nsContainerFrame*        aParentFrame,
5013
                                         const nsStyleDisplay*    aDisplay,
5014
                                         nsFrameItems&            aFrameItems)
5015
0
{
5016
0
  return ConstructFrameWithAnonymousChild(
5017
0
      aState, aItem, aParentFrame, aFrameItems,
5018
0
      NS_NewSVGOuterSVGFrame, NS_NewSVGOuterSVGAnonChildFrame,
5019
0
      nsCSSAnonBoxes::mozSVGOuterSVGAnonChild(), true);
5020
0
}
5021
5022
nsIFrame*
5023
nsCSSFrameConstructor::ConstructMarker(nsFrameConstructorState& aState,
5024
                                       FrameConstructionItem&   aItem,
5025
                                       nsContainerFrame*        aParentFrame,
5026
                                       const nsStyleDisplay*    aDisplay,
5027
                                       nsFrameItems&            aFrameItems)
5028
0
{
5029
0
  return ConstructFrameWithAnonymousChild(
5030
0
      aState, aItem, aParentFrame, aFrameItems,
5031
0
      NS_NewSVGMarkerFrame, NS_NewSVGMarkerAnonChildFrame,
5032
0
      nsCSSAnonBoxes::mozSVGMarkerAnonChild(), false);
5033
0
}
5034
5035
// Only outer <svg> elements can be floated or positioned.  All other SVG
5036
// should be in-flow.
5037
#define SIMPLE_SVG_FCDATA(_func)                                        \
5038
0
  FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                             \
5039
0
              FCDATA_SKIP_ABSPOS_PUSH |                                 \
5040
0
              FCDATA_DISALLOW_GENERATED_CONTENT,  _func)
5041
#define SIMPLE_SVG_CREATE(_tag, _func)            \
5042
0
  { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
5043
5044
static bool
5045
IsFilterPrimitiveChildTag(const nsAtom* aTag)
5046
0
{
5047
0
  return aTag == nsGkAtoms::feDistantLight ||
5048
0
         aTag == nsGkAtoms::fePointLight ||
5049
0
         aTag == nsGkAtoms::feSpotLight ||
5050
0
         aTag == nsGkAtoms::feFuncR ||
5051
0
         aTag == nsGkAtoms::feFuncG ||
5052
0
         aTag == nsGkAtoms::feFuncB ||
5053
0
         aTag == nsGkAtoms::feFuncA ||
5054
0
         aTag == nsGkAtoms::feMergeNode;
5055
0
}
5056
5057
/* static */
5058
const nsCSSFrameConstructor::FrameConstructionData*
5059
nsCSSFrameConstructor::FindSVGData(const Element& aElement,
5060
                                   nsIFrame* aParentFrame,
5061
                                   bool aIsWithinSVGText,
5062
                                   bool aAllowsTextPathChild,
5063
                                   ComputedStyle& aStyle)
5064
0
{
5065
0
  MOZ_ASSERT(aElement.IsSVGElement());
5066
0
5067
0
  static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
5068
0
  static const FrameConstructionData sContainerData =
5069
0
    SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
5070
0
5071
0
  bool parentIsSVG = aIsWithinSVGText;
5072
0
  nsIContent* parentContent =
5073
0
    aParentFrame ? aParentFrame->GetContent() : nullptr;
5074
0
5075
0
  nsAtom* tag = aElement.NodeInfo()->NameAtom();
5076
0
5077
0
  // XXXbz should this really be based on the tag of the parent frame's content?
5078
0
  // Should it not be based on the type of the parent frame (e.g. whether it's
5079
0
  // an SVG frame)?
5080
0
  if (parentContent) {
5081
0
    // It's not clear whether the SVG spec intends to allow any SVG
5082
0
    // content within svg:foreignObject at all (SVG 1.1, section
5083
0
    // 23.2), but if it does, it better be svg:svg.  So given that
5084
0
    // we're allowing it, treat it as a non-SVG parent.
5085
0
    parentIsSVG =
5086
0
      parentContent->IsSVGElement() &&
5087
0
      parentContent->NodeInfo()->NameAtom() != nsGkAtoms::foreignObject;
5088
0
  }
5089
0
5090
0
  if ((tag != nsGkAtoms::svg && !parentIsSVG) ||
5091
0
      (tag == nsGkAtoms::desc || tag == nsGkAtoms::title ||
5092
0
       tag == nsGkAtoms::metadata)) {
5093
0
    // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
5094
0
    // svg:svg not contained within svg:svg are incorrect, although they
5095
0
    // don't seem to specify error handling.  Ignore them, since many of
5096
0
    // our frame classes can't deal.  It *may* be that the document
5097
0
    // should at that point be considered in error according to F.2, but
5098
0
    // it's hard to tell.
5099
0
    //
5100
0
    // Style mutation can't change this situation, so don't bother
5101
0
    // adding to the undisplayed content map.
5102
0
    //
5103
0
    // We don't currently handle any UI for desc/title/metadata
5104
0
    return &sSuppressData;
5105
0
  }
5106
0
5107
0
  // We don't need frames for animation elements
5108
0
  if (aElement.IsNodeOfType(nsINode::eANIMATION)) {
5109
0
    return &sSuppressData;
5110
0
  }
5111
0
5112
0
  if (tag == nsGkAtoms::svg && !parentIsSVG) {
5113
0
    // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
5114
0
    // of whether they fail conditional processing attributes, since various
5115
0
    // SVG frames assume that one exists.  We handle the non-rendering
5116
0
    // of failing outer <svg> element contents like <switch> statements,
5117
0
    // and do the PassesConditionalProcessingTests call in
5118
0
    // nsSVGOuterSVGFrame::Init.
5119
0
    static const FrameConstructionData sOuterSVGData =
5120
0
      FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
5121
0
    return &sOuterSVGData;
5122
0
  }
5123
0
5124
0
  if (tag == nsGkAtoms::marker) {
5125
0
    static const FrameConstructionData sMarkerSVGData =
5126
0
      FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructMarker);
5127
0
    return &sMarkerSVGData;
5128
0
  }
5129
0
5130
0
  nsCOMPtr<SVGTests> tests =
5131
0
    do_QueryInterface(const_cast<Element*>(&aElement));
5132
0
  if (tests && !tests->PassesConditionalProcessingTests()) {
5133
0
    // Elements with failing conditional processing attributes never get
5134
0
    // rendered.  Note that this is not where we select which frame in a
5135
0
    // <switch> to render!  That happens in nsSVGSwitchFrame::PaintSVG.
5136
0
    if (aIsWithinSVGText) {
5137
0
      // SVGTextFrame doesn't handle conditional processing attributes,
5138
0
      // so don't create frames for descendants of <text> with failing
5139
0
      // attributes.  We need frames not to be created so that text layout
5140
0
      // is correct.
5141
0
      return &sSuppressData;
5142
0
    }
5143
0
    // If we're not inside <text>, create an nsSVGContainerFrame (which is a
5144
0
    // frame that doesn't render) so that paint servers can still be referenced,
5145
0
    // even if they live inside an element with failing conditional processing
5146
0
    // attributes.
5147
0
    return &sContainerData;
5148
0
  }
5149
0
5150
0
  // Ensure that a stop frame is a child of a gradient and that gradients
5151
0
  // can only have stop children.
5152
0
  bool parentIsGradient =
5153
0
    aParentFrame && (aParentFrame->IsSVGLinearGradientFrame() ||
5154
0
                     aParentFrame->IsSVGRadialGradientFrame());
5155
0
  bool stop = (tag == nsGkAtoms::stop);
5156
0
  if ((parentIsGradient && !stop) || (!parentIsGradient && stop)) {
5157
0
    return &sSuppressData;
5158
0
  }
5159
0
5160
0
  // Prevent bad frame types being children of filters or parents of filter
5161
0
  // primitives.  If aParentFrame is null, we know that the frame that will
5162
0
  // be created will be an nsInlineFrame, so it can never be a filter.
5163
0
  bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
5164
0
  bool filterPrimitive = aElement.IsNodeOfType(nsINode::eFILTER);
5165
0
  if ((parentIsFilter && !filterPrimitive) ||
5166
0
      (!parentIsFilter && filterPrimitive)) {
5167
0
    return &sSuppressData;
5168
0
  }
5169
0
5170
0
  // Prevent bad frame types being children of filter primitives or parents of
5171
0
  // filter primitive children.  If aParentFrame is null, we know that the frame
5172
0
  // that will be created will be an nsInlineFrame, so it can never be a filter
5173
0
  // primitive.
5174
0
  bool parentIsFEContainerFrame =
5175
0
    aParentFrame && aParentFrame->IsSVGFEContainerFrame();
5176
0
  if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(tag)) ||
5177
0
      (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(tag))) {
5178
0
    return &sSuppressData;
5179
0
  }
5180
0
5181
0
  // Special cases for text/tspan/textPath, because the kind of frame
5182
0
  // they get depends on the parent frame.  We ignore 'a' elements when
5183
0
  // determining the parent, however.
5184
0
  if (aIsWithinSVGText) {
5185
0
    // If aIsWithinSVGText is true, then we know that the "SVG text uses
5186
0
    // CSS frames" pref was true when this SVG fragment was first constructed.
5187
0
5188
0
    // We don't use ConstructInline because we want different behavior
5189
0
    // for generated content.
5190
0
    static const FrameConstructionData sTSpanData =
5191
0
      FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |
5192
0
                  FCDATA_SKIP_ABSPOS_PUSH |
5193
0
                  FCDATA_DISALLOW_GENERATED_CONTENT |
5194
0
                  FCDATA_IS_LINE_PARTICIPANT |
5195
0
                  FCDATA_IS_INLINE |
5196
0
                  FCDATA_USE_CHILD_ITEMS,
5197
0
                  NS_NewInlineFrame);
5198
0
    if (tag == nsGkAtoms::textPath) {
5199
0
      if (aAllowsTextPathChild) {
5200
0
        return &sTSpanData;
5201
0
      }
5202
0
    } else if (tag == nsGkAtoms::tspan ||
5203
0
               tag == nsGkAtoms::a) {
5204
0
      return &sTSpanData;
5205
0
    }
5206
0
    return &sSuppressData;
5207
0
  } else if (tag == nsGkAtoms::tspan ||
5208
0
             tag == nsGkAtoms::textPath) {
5209
0
    return &sSuppressData;
5210
0
  }
5211
0
5212
0
  static const FrameConstructionDataByTag sSVGData[] = {
5213
0
    SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
5214
0
    SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
5215
0
    SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
5216
0
    SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame),
5217
0
    SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame),
5218
0
    SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame),
5219
0
    SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame),
5220
0
    SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame),
5221
0
    SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame),
5222
0
    SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame),
5223
0
    SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame),
5224
0
    SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
5225
0
    SIMPLE_SVG_CREATE(generic_, NS_NewSVGGenericContainerFrame),
5226
0
    { &nsGkAtoms::text,
5227
0
      FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW |
5228
0
                                 FCDATA_ALLOW_BLOCK_STYLES,
5229
0
                                 NS_NewSVGTextFrame,
5230
0
                                 nsCSSAnonBoxes::mozSVGText()) },
5231
0
    { &nsGkAtoms::foreignObject,
5232
0
      FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW,
5233
0
                                 NS_NewSVGForeignObjectFrame,
5234
0
                                 nsCSSAnonBoxes::mozSVGForeignContent()) },
5235
0
    SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
5236
0
    SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
5237
0
    SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
5238
0
    SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
5239
0
    SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
5240
0
    SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame),
5241
0
    SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
5242
0
    SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
5243
0
    SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
5244
0
    SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
5245
0
    SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
5246
0
    SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
5247
0
    SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
5248
0
    SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
5249
0
    SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
5250
0
    SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
5251
0
    SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
5252
0
    SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
5253
0
    SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
5254
0
    SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
5255
0
    SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
5256
0
    SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
5257
0
    SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
5258
0
    SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
5259
0
    SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
5260
0
    SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
5261
0
    SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
5262
0
    SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
5263
0
    SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
5264
0
    SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
5265
0
    SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
5266
0
    SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
5267
0
    SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
5268
0
    SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
5269
0
    SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
5270
0
    SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)
5271
0
  };
5272
0
5273
0
  const FrameConstructionData* data =
5274
0
    FindDataByTag(tag, aElement, aStyle, sSVGData, ArrayLength(sSVGData));
5275
0
5276
0
  if (!data) {
5277
0
    data = &sContainerData;
5278
0
  }
5279
0
5280
0
  return data;
5281
0
}
5282
5283
void
5284
nsCSSFrameConstructor::AddPageBreakItem(nsIContent* aContent,
5285
                                        FrameConstructionItemList& aItems)
5286
0
{
5287
0
  RefPtr<ComputedStyle> pseudoStyle =
5288
0
    mPresShell->StyleSet()->
5289
0
      ResolveNonInheritingAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak());
5290
0
5291
0
  MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,
5292
0
             "Unexpected display");
5293
0
5294
0
  static const FrameConstructionData sPageBreakData =
5295
0
    FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
5296
0
5297
0
  aItems.AppendItem(this, &sPageBreakData, aContent, nullptr,
5298
0
                    pseudoStyle.forget(), true);
5299
0
}
5300
5301
bool
5302
nsCSSFrameConstructor::ShouldCreateItemsForChild(nsFrameConstructorState& aState,
5303
                                                 nsIContent* aContent,
5304
                                                 nsContainerFrame* aParentFrame)
5305
0
{
5306
0
  aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
5307
0
  // XXX the GetContent() != aContent check is needed due to bug 135040.
5308
0
  // Remove it once that's fixed.
5309
0
  if (aContent->GetPrimaryFrame() &&
5310
0
      aContent->GetPrimaryFrame()->GetContent() == aContent &&
5311
0
      !aState.mCreatingExtraFrames) {
5312
0
    MOZ_ASSERT(false,
5313
0
               "asked to create frame construction item for a node that "
5314
0
               "already has a frame");
5315
0
    return false;
5316
0
  }
5317
0
5318
0
  // don't create a whitespace frame if aParent doesn't want it
5319
0
  if (!NeedFrameFor(aState, aParentFrame, aContent)) {
5320
0
    return false;
5321
0
  }
5322
0
5323
0
  // never create frames for comments or PIs
5324
0
  if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
5325
0
    return false;
5326
0
  }
5327
0
5328
0
  return true;
5329
0
}
5330
5331
void
5332
nsCSSFrameConstructor::DoAddFrameConstructionItems(nsFrameConstructorState& aState,
5333
                                                   nsIContent* aContent,
5334
                                                   ComputedStyle* aComputedStyle,
5335
                                                   bool aSuppressWhiteSpaceOptimizations,
5336
                                                   nsContainerFrame* aParentFrame,
5337
                                                   FrameConstructionItemList& aItems)
5338
0
{
5339
0
  uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
5340
0
  if (aParentFrame) {
5341
0
    if (nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
5342
0
      flags |= ITEM_IS_WITHIN_SVG_TEXT;
5343
0
    }
5344
0
    if (aParentFrame->IsBlockFrame() && aParentFrame->GetParent() &&
5345
0
        aParentFrame->GetParent()->IsSVGTextFrame()) {
5346
0
      flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
5347
0
    }
5348
0
  }
5349
0
  AddFrameConstructionItemsInternal(aState, aContent, aParentFrame,
5350
0
                                    aSuppressWhiteSpaceOptimizations,
5351
0
                                    aComputedStyle,
5352
0
                                    flags, aItems);
5353
0
}
5354
5355
void
5356
nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState,
5357
                                                 nsIContent* aContent,
5358
                                                 bool aSuppressWhiteSpaceOptimizations,
5359
                                                 const InsertionPoint& aInsertion,
5360
                                                 FrameConstructionItemList& aItems)
5361
0
{
5362
0
  nsContainerFrame* parentFrame = aInsertion.mParentFrame;
5363
0
  if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
5364
0
    return;
5365
0
  }
5366
0
  RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
5367
0
  DoAddFrameConstructionItems(aState, aContent, computedStyle,
5368
0
                              aSuppressWhiteSpaceOptimizations, parentFrame,
5369
0
                              aItems);
5370
0
}
5371
5372
// Whether we should suppress frames for a child under a <select> frame.
5373
//
5374
// Never create frames for non-option/optgroup kids of <select> and non-option
5375
// kids of <optgroup> inside a <select>.
5376
// XXXbz it's not clear how this should best work with XBL.
5377
static bool
5378
ShouldSuppressFrameInSelect(const nsIContent* aParent,
5379
                            const nsIContent& aChild)
5380
0
{
5381
0
  if (!aParent ||
5382
0
      !aParent->IsAnyOfHTMLElements(nsGkAtoms::select, nsGkAtoms::optgroup)) {
5383
0
    return false;
5384
0
  }
5385
0
5386
0
  // If we're in any display: contents subtree, just suppress the frame.
5387
0
  //
5388
0
  // We can't be regular NAC, since display: contents has no frame to generate
5389
0
  // them off.
5390
0
  if (aChild.GetParent() != aParent) {
5391
0
    return true;
5392
0
  }
5393
0
5394
0
  // Option is always fine.
5395
0
  if (aChild.IsHTMLElement(nsGkAtoms::option)) {
5396
0
    return false;
5397
0
  }
5398
0
5399
0
  // <optgroup> is OK in <select> but not in <optgroup>.
5400
0
  if (aChild.IsHTMLElement(nsGkAtoms::optgroup) &&
5401
0
      aParent->IsHTMLElement(nsGkAtoms::select)) {
5402
0
    return false;
5403
0
  }
5404
0
5405
0
  // Allow native anonymous content no matter what.
5406
0
  if (aChild.IsRootOfAnonymousSubtree()) {
5407
0
    return false;
5408
0
  }
5409
0
5410
0
  return true;
5411
0
}
5412
5413
static bool
5414
ShouldSuppressFrameInNonOpenDetails(const HTMLDetailsElement* aDetails,
5415
                                    const nsIContent& aChild)
5416
0
{
5417
0
  if (!aDetails || aDetails->Open()) {
5418
0
    return false;
5419
0
  }
5420
0
5421
0
  if (aChild.GetParent() != aDetails) {
5422
0
    return true;
5423
0
  }
5424
0
5425
0
  auto* summary = HTMLSummaryElement::FromNode(aChild);
5426
0
  if (summary && summary->IsMainSummary()) {
5427
0
    return false;
5428
0
  }
5429
0
5430
0
  // Don't suppress NAC, unless it's ::before or ::after.
5431
0
  if (aChild.IsRootOfAnonymousSubtree() &&
5432
0
      !aChild.IsGeneratedContentContainerForBefore() &&
5433
0
      !aChild.IsGeneratedContentContainerForAfter()) {
5434
0
    return false;
5435
0
  }
5436
0
5437
0
  return true;
5438
0
}
5439
5440
const nsCSSFrameConstructor::FrameConstructionData*
5441
nsCSSFrameConstructor::FindDataForContent(nsIContent& aContent,
5442
                                          ComputedStyle& aStyle,
5443
                                          nsIFrame* aParentFrame,
5444
                                          nsAtom* aTag,
5445
                                          uint32_t aFlags)
5446
0
{
5447
0
  MOZ_ASSERT(aStyle.StyleDisplay()->mDisplay != StyleDisplay::None &&
5448
0
             aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents,
5449
0
             "These two special display values should be handled earlier");
5450
0
5451
0
  if (auto* text = Text::FromNode(aContent)) {
5452
0
    return FindTextData(*text, aParentFrame);
5453
0
  }
5454
0
5455
0
  return FindElementData(*aContent.AsElement(),
5456
0
                         aStyle,
5457
0
                         aParentFrame,
5458
0
                         aTag,
5459
0
                         aFlags);
5460
0
}
5461
5462
const nsCSSFrameConstructor::FrameConstructionData*
5463
nsCSSFrameConstructor::FindElementData(const Element& aElement,
5464
                                       ComputedStyle& aStyle,
5465
                                       nsIFrame* aParentFrame,
5466
                                       nsAtom* aTag,
5467
                                       uint32_t aFlags)
5468
0
{
5469
0
  // Don't create frames for non-SVG element children of SVG elements.
5470
0
  if (!aElement.IsSVGElement()) {
5471
0
    if (aParentFrame && IsFrameForSVG(aParentFrame) &&
5472
0
        !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) {
5473
0
      return nullptr;
5474
0
    }
5475
0
    if (aFlags & ITEM_IS_WITHIN_SVG_TEXT) {
5476
0
      return nullptr;
5477
0
    }
5478
0
  }
5479
0
5480
0
  if (auto* data = FindElementTagData(aElement, aStyle, aParentFrame, aTag, aFlags)) {
5481
0
    return data;
5482
0
  }
5483
0
5484
0
  // Check for 'content: <image-url>' on the element (which makes us ignore
5485
0
  // 'display' values other than 'none' or 'contents').
5486
0
  if (ShouldCreateImageFrameForContent(aElement, aStyle)) {
5487
0
    static const FrameConstructionData sImgData =
5488
0
      SIMPLE_FCDATA(NS_NewImageFrameForContentProperty);
5489
0
    return &sImgData;
5490
0
  }
5491
0
5492
0
  const auto& display = *aStyle.StyleDisplay();
5493
0
  if (auto* data = FindXULDisplayData(display, aElement)) {
5494
0
    return data;
5495
0
  }
5496
0
5497
0
  return FindDisplayData(display, aElement);
5498
0
}
5499
5500
const nsCSSFrameConstructor::FrameConstructionData*
5501
nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
5502
                                          ComputedStyle& aStyle,
5503
                                          nsIFrame* aParentFrame,
5504
                                          nsAtom* aTag,
5505
                                          uint32_t aFlags)
5506
0
{
5507
0
  switch (aElement.GetNameSpaceID()) {
5508
0
    case kNameSpaceID_XHTML:
5509
0
      return FindHTMLData(aElement, aParentFrame, aStyle);
5510
0
    case kNameSpaceID_MathML:
5511
0
      return FindMathMLData(aElement, aStyle);
5512
0
    case kNameSpaceID_SVG:
5513
0
      return FindSVGData(aElement,
5514
0
                         aParentFrame,
5515
0
                         aFlags & ITEM_IS_WITHIN_SVG_TEXT,
5516
0
                         aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
5517
0
                         aStyle);
5518
0
    case kNameSpaceID_XUL:
5519
0
      return FindXULTagData(aElement, aTag, aStyle);
5520
0
    default:
5521
0
      return nullptr;
5522
0
  }
5523
0
}
5524
5525
nsCSSFrameConstructor::XBLBindingLoadInfo::XBLBindingLoadInfo(
5526
  already_AddRefed<ComputedStyle>&& aStyle,
5527
  mozilla::UniquePtr<PendingBinding> aPendingBinding,
5528
  nsAtom* aTag)
5529
  : mStyle(std::move(aStyle))
5530
  , mPendingBinding(std::move(aPendingBinding))
5531
  , mTag(aTag)
5532
0
{
5533
0
  MOZ_ASSERT(mTag);
5534
0
  MOZ_ASSERT(mStyle);
5535
0
}
5536
5537
nsCSSFrameConstructor::XBLBindingLoadInfo::XBLBindingLoadInfo(nsIContent& aContent,
5538
                                                              ComputedStyle& aStyle)
5539
  : mStyle(&aStyle)
5540
  , mPendingBinding(nullptr)
5541
  , mTag(aContent.NodeInfo()->NameAtom())
5542
0
{
5543
0
}
5544
5545
0
nsCSSFrameConstructor::XBLBindingLoadInfo::XBLBindingLoadInfo() = default;
5546
5547
nsCSSFrameConstructor::XBLBindingLoadInfo
5548
nsCSSFrameConstructor::LoadXBLBindingIfNeeded(nsIContent& aContent,
5549
                                              ComputedStyle& aStyle,
5550
                                              uint32_t aFlags)
5551
0
{
5552
0
  if (!(aFlags & ITEM_ALLOW_XBL_BASE)) {
5553
0
    return { aContent, aStyle };
5554
0
  }
5555
0
  css::URLValue* binding = aStyle.StyleDisplay()->mBinding;
5556
0
  if (!binding) {
5557
0
    return { aContent, aStyle };
5558
0
  }
5559
0
5560
0
  nsXBLService* xblService = nsXBLService::GetInstance();
5561
0
  if (!xblService) {
5562
0
    return { };
5563
0
  }
5564
0
5565
0
  auto newPendingBinding = MakeUnique<PendingBinding>();
5566
0
5567
0
  bool resolveStyle;
5568
0
  nsresult rv = xblService->LoadBindings(aContent.AsElement(),
5569
0
                                         binding->GetURI(),
5570
0
                                         binding->mExtraData->GetPrincipal(),
5571
0
                                         getter_AddRefs(newPendingBinding->mBinding),
5572
0
                                         &resolveStyle);
5573
0
  if (NS_FAILED(rv)) {
5574
0
    if (rv == NS_ERROR_XBL_BLOCKED) {
5575
0
      return { aContent, aStyle };
5576
0
    }
5577
0
    return { };
5578
0
  }
5579
0
5580
0
  RefPtr<ComputedStyle> style = resolveStyle
5581
0
    ? mPresShell->StyleSet()->ResolveServoStyle(*aContent.AsElement())
5582
0
    : do_AddRef(&aStyle);
5583
0
5584
0
  nsAtom* tag = aContent.NodeInfo()->NameAtom();
5585
0
  if (aContent.IsXULElement()) {
5586
0
    int32_t overridenNamespace;
5587
0
    nsAtom* overridenTag =
5588
0
      mDocument->BindingManager()->ResolveTag(&aContent, &overridenNamespace);
5589
0
    // Only allow overriding from & to XUL.
5590
0
    if (overridenNamespace == kNameSpaceID_XUL) {
5591
0
      tag = overridenTag;
5592
0
    }
5593
0
  }
5594
0
5595
0
  return { style.forget(), std::move(newPendingBinding), tag };
5596
0
}
5597
5598
5599
void
5600
nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
5601
                                                         nsIContent* aContent,
5602
                                                         nsContainerFrame* aParentFrame,
5603
                                                         bool aSuppressWhiteSpaceOptimizations,
5604
                                                         ComputedStyle* aComputedStyle,
5605
                                                         uint32_t aFlags,
5606
                                                         FrameConstructionItemList& aItems)
5607
0
{
5608
0
  MOZ_ASSERT(aContent->IsText() || aContent->IsElement(),
5609
0
             "Shouldn't get anything else here!");
5610
0
  MOZ_ASSERT(aContent->IsInComposedDoc());
5611
0
  MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
5612
0
             aContent->NodeInfo()->NameAtom() == nsGkAtoms::area);
5613
0
5614
0
  PendingBinding* pendingBinding = nullptr;
5615
0
  RefPtr<ComputedStyle> style;
5616
0
  nsAtom* tag;
5617
0
  {
5618
0
    XBLBindingLoadInfo xblInfo =
5619
0
      LoadXBLBindingIfNeeded(*aContent, *aComputedStyle, aFlags);
5620
0
    if (!xblInfo.mTag) {
5621
0
      return;
5622
0
    }
5623
0
5624
0
    if (xblInfo.mPendingBinding && xblInfo.mPendingBinding->mBinding) {
5625
0
      pendingBinding = xblInfo.mPendingBinding.get();
5626
0
      aState.AddPendingBinding(std::move(xblInfo.mPendingBinding));
5627
0
    }
5628
0
5629
0
    style = xblInfo.mStyle.forget();
5630
0
    aComputedStyle = style.get();
5631
0
5632
0
    tag = xblInfo.mTag;
5633
0
  }
5634
0
5635
0
  const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
5636
0
  MOZ_ASSERT(!isGeneratedContent || style->GetPseudo(),
5637
0
             "Generated content should be a pseudo-element");
5638
0
5639
0
  FrameConstructionItem* item = nullptr;
5640
0
  auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
5641
0
    if (isGeneratedContent && !item) {
5642
0
      MOZ_ASSERT(!IsDisplayContents(aContent),
5643
0
                 "This would need to change if we support display: contents "
5644
0
                 "in generated content");
5645
0
      aContent->UnbindFromTree();
5646
0
    }
5647
0
  });
5648
0
5649
0
  const nsStyleDisplay& display = *style->StyleDisplay();
5650
0
5651
0
  // Pre-check for display "none" - if we find that, don't create
5652
0
  // any frame at all
5653
0
  if (display.mDisplay == StyleDisplay::None) {
5654
0
    return;
5655
0
  }
5656
0
5657
0
  if (display.mDisplay == StyleDisplay::Contents) {
5658
0
    CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5659
0
                               *style, CSSPseudoElementType::before, aItems);
5660
0
5661
0
    FlattenedChildIterator iter(aContent);
5662
0
    InsertionPoint insertion(aParentFrame, aContent);
5663
0
    for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
5664
0
      AddFrameConstructionItems(aState,
5665
0
                                child,
5666
0
                                aSuppressWhiteSpaceOptimizations,
5667
0
                                insertion,
5668
0
                                aItems);
5669
0
    }
5670
0
    aItems.SetParentHasNoXBLChildren(!iter.XBLInvolved());
5671
0
5672
0
    CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5673
0
                               *style, CSSPseudoElementType::after, aItems);
5674
0
    return;
5675
0
  }
5676
0
5677
0
5678
0
  nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
5679
0
  if (ShouldSuppressFrameInSelect(parent, *aContent)) {
5680
0
    return;
5681
0
  }
5682
0
5683
0
  // When constructing a child of a non-open <details>, create only the frame
5684
0
  // for the main <summary> element, and skip other elements.  This only applies
5685
0
  // to things that are not roots of native anonymous subtrees (except for
5686
0
  // ::before and ::after); we always want to create "internal" anonymous
5687
0
  // content.
5688
0
  auto* details = HTMLDetailsElement::FromNodeOrNull(parent);
5689
0
  if (ShouldSuppressFrameInNonOpenDetails(details, *aContent)) {
5690
0
    return;
5691
0
  }
5692
0
5693
0
  const FrameConstructionData* data =
5694
0
    FindDataForContent(*aContent, *style, aParentFrame, tag, aFlags);
5695
0
  if (!data || data->mBits & FCDATA_SUPPRESS_FRAME) {
5696
0
    return;
5697
0
  }
5698
0
5699
0
  bool isPopup = false;
5700
0
5701
0
#ifdef MOZ_XUL
5702
0
  if ((data->mBits & FCDATA_IS_POPUP) &&
5703
0
      (!aParentFrame || // Parent is inline
5704
0
       !aParentFrame->IsMenuFrame())) {
5705
0
    if (!aState.mPopupItems.containingBlock &&
5706
0
        !aState.mHavePendingPopupgroup) {
5707
0
      return;
5708
0
    }
5709
0
5710
0
    isPopup = true;
5711
0
  }
5712
0
#endif /* MOZ_XUL */
5713
0
5714
0
  uint32_t bits = data->mBits;
5715
0
5716
0
  // Inside colgroups, suppress everything except columns.
5717
0
  if (aParentFrame && aParentFrame->IsTableColGroupFrame() &&
5718
0
      (!(bits & FCDATA_IS_TABLE_PART) ||
5719
0
       display.mDisplay != StyleDisplay::TableColumn)) {
5720
0
    return;
5721
0
  }
5722
0
5723
0
  bool canHavePageBreak =
5724
0
    (aFlags & ITEM_ALLOW_PAGE_BREAK) && aState.mPresContext->IsPaginated() &&
5725
0
    !display.IsAbsolutelyPositionedStyle() &&
5726
0
    !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
5727
0
    !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
5728
0
5729
0
  if (canHavePageBreak && display.mBreakBefore) {
5730
0
    AddPageBreakItem(aContent, aItems);
5731
0
  }
5732
0
5733
0
  if (details && details->Open()) {
5734
0
    auto* summary = HTMLSummaryElement::FromNode(aContent);
5735
0
    if (summary && summary->IsMainSummary()) {
5736
0
      // If details is open, the main summary needs to be rendered as if it is
5737
0
      // the first child, so add the item to the front of the item list.
5738
0
      item = aItems.PrependItem(this, data, aContent, pendingBinding,
5739
0
                                style.forget(),
5740
0
                                aSuppressWhiteSpaceOptimizations);
5741
0
    }
5742
0
  }
5743
0
5744
0
  if (!item) {
5745
0
    item = aItems.AppendItem(this, data, aContent, pendingBinding,
5746
0
                             style.forget(),
5747
0
                             aSuppressWhiteSpaceOptimizations);
5748
0
  }
5749
0
  item->mIsText = !aContent->IsElement();
5750
0
  item->mIsGeneratedContent = isGeneratedContent;
5751
0
  item->mIsAnonymousContentCreatorContent =
5752
0
    aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
5753
0
  if (isGeneratedContent) {
5754
0
    // We need to keep this alive until the frame takes ownership.
5755
0
    // This corresponds to the Release in ConstructFramesFromItem.
5756
0
    item->mContent->AddRef();
5757
0
  }
5758
0
  item->mIsRootPopupgroup =
5759
0
    aContent->IsRootOfNativeAnonymousSubtree() &&
5760
0
    aContent->IsXULElement() &&
5761
0
    tag == nsGkAtoms::popupgroup;
5762
0
  if (item->mIsRootPopupgroup) {
5763
0
    aState.mHavePendingPopupgroup = true;
5764
0
  }
5765
0
  item->mIsPopup = isPopup;
5766
0
5767
0
  if (canHavePageBreak && display.mBreakAfter) {
5768
0
    AddPageBreakItem(aContent, aItems);
5769
0
  }
5770
0
5771
0
  if (bits & FCDATA_IS_INLINE) {
5772
0
    // To correctly set item->mIsAllInline we need to build up our child items
5773
0
    // right now.
5774
0
    BuildInlineChildItems(aState, *item,
5775
0
                          aFlags & ITEM_IS_WITHIN_SVG_TEXT,
5776
0
                          aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD);
5777
0
    item->mIsBlock = false;
5778
0
  } else {
5779
0
    // Compute a boolean isInline which is guaranteed to be false for blocks
5780
0
    // (but may also be false for some inlines).
5781
0
    bool isInline =
5782
0
      // Table-internal things are inline-outside if and only if they're kids of
5783
0
      // inlines, since they'll trigger construction of inline-table
5784
0
      // pseudos.
5785
0
      ((bits & FCDATA_IS_TABLE_PART) &&
5786
0
       (!aParentFrame || // No aParentFrame means inline
5787
0
        aParentFrame->StyleDisplay()->mDisplay == StyleDisplay::Inline)) ||
5788
0
      // Things that are inline-outside but aren't inline frames are inline
5789
0
      display.IsInlineOutsideStyle() ||
5790
0
      // Popups that are certainly out of flow.
5791
0
      isPopup;
5792
0
5793
0
    // Set mIsAllInline conservatively.  It just might be that even an inline
5794
0
    // that has mIsAllInline false doesn't need an {ib} split.  So this is just
5795
0
    // an optimization to keep from doing too much work in cases when we can
5796
0
    // show that mIsAllInline is true..
5797
0
    item->mIsAllInline = isInline ||
5798
0
      // Figure out whether we're guaranteed this item will be out of flow.
5799
0
      // This is not a precise test, since one of our ancestor inlines might add
5800
0
      // an absolute containing block (if it's relatively positioned) when there
5801
0
      // wasn't such a containing block before.  But it's conservative in the
5802
0
      // sense that anything that will really end up as an in-flow non-inline
5803
0
      // will test false here.  In other words, if this test is true we're
5804
0
      // guaranteed to be inline; if it's false we don't know what we'll end up
5805
0
      // as.
5806
0
      //
5807
0
      // If we make this test precise, we can remove some of the code dealing
5808
0
      // with the imprecision in ConstructInline and adjust the comments on
5809
0
      // mIsAllInline and mIsBlock in the header.
5810
0
      (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
5811
0
       aState.GetGeometricParent(display, nullptr));
5812
0
5813
0
    // Set mIsBlock conservatively.  It's OK to set it false for some real
5814
0
    // blocks, but not OK to set it true for things that aren't blocks.  Since
5815
0
    // isOutOfFlow might be false even in cases when the frame will end up
5816
0
    // out-of-flow, we can't use it here.  But we _can_ say that the frame will
5817
0
    // for sure end up in-flow if it's not floated or absolutely positioned.
5818
0
    item->mIsBlock = !isInline &&
5819
0
                     !display.IsAbsolutelyPositionedStyle() &&
5820
0
                     !display.IsFloatingStyle() &&
5821
0
                     !(bits & FCDATA_IS_SVG_TEXT);
5822
0
  }
5823
0
5824
0
  if (item->mIsAllInline) {
5825
0
    aItems.InlineItemAdded();
5826
0
  } else if (item->mIsBlock) {
5827
0
    aItems.BlockItemAdded();
5828
0
  }
5829
0
5830
0
  // Our item should be treated as a line participant if we have the relevant
5831
0
  // bit and are going to be in-flow.  Note that this really only matters if
5832
0
  // our ancestor is a box or some such, so the fact that we might have an
5833
0
  // inline ancestor that might become a containing block is not relevant here.
5834
0
  if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
5835
0
      ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
5836
0
       !aState.GetGeometricParent(display, nullptr))) {
5837
0
    item->mIsLineParticipant = true;
5838
0
    aItems.LineParticipantItemAdded();
5839
0
  }
5840
0
}
5841
5842
/**
5843
 * Return true if the frame construction item pointed to by aIter will
5844
 * create a frame adjacent to a line boundary in the frame tree, and that
5845
 * line boundary is induced by a content node adjacent to the frame's
5846
 * content node in the content tree. The latter condition is necessary so
5847
 * that ContentAppended/ContentInserted/ContentRemoved can easily find any
5848
 * text nodes that were suppressed here.
5849
 */
5850
bool
5851
nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter)
5852
0
{
5853
0
  if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5854
0
    return false;
5855
0
  }
5856
0
5857
0
  if (aIter.AtStart()) {
5858
0
    if (aIter.List()->HasLineBoundaryAtStart() &&
5859
0
        !aIter.item().mContent->GetPreviousSibling())
5860
0
      return true;
5861
0
  } else {
5862
0
    FCItemIterator prev = aIter;
5863
0
    prev.Prev();
5864
0
    if (prev.item().IsLineBoundary() &&
5865
0
        !prev.item().mSuppressWhiteSpaceOptimizations &&
5866
0
        aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
5867
0
      return true;
5868
0
  }
5869
0
5870
0
  FCItemIterator next = aIter;
5871
0
  next.Next();
5872
0
  if (next.IsDone()) {
5873
0
    if (aIter.List()->HasLineBoundaryAtEnd() &&
5874
0
        !aIter.item().mContent->GetNextSibling())
5875
0
      return true;
5876
0
  } else {
5877
0
    if (next.item().IsLineBoundary() &&
5878
0
        !next.item().mSuppressWhiteSpaceOptimizations &&
5879
0
        aIter.item().mContent->GetNextSibling() == next.item().mContent)
5880
0
      return true;
5881
0
  }
5882
0
5883
0
  return false;
5884
0
}
5885
5886
void
5887
nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
5888
                                               FCItemIterator& aIter,
5889
                                               nsContainerFrame* aParentFrame,
5890
                                               nsFrameItems& aFrameItems)
5891
0
{
5892
0
  nsContainerFrame* adjParentFrame = aParentFrame;
5893
0
  FrameConstructionItem& item = aIter.item();
5894
0
  ComputedStyle* computedStyle = item.mComputedStyle;
5895
0
  AdjustParentFrame(&adjParentFrame, item.mFCData, computedStyle);
5896
0
5897
0
  if (item.mIsText) {
5898
0
    // If this is collapsible whitespace next to a line boundary,
5899
0
    // don't create a frame. item.IsWhitespace() also sets the
5900
0
    // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5901
0
    // end up creating a frame, nsTextFrame::Init will clear the flag.)
5902
0
    // We don't do this for generated content, because some generated
5903
0
    // text content is empty text nodes that are about to be initialized.
5904
0
    // (We check mAdditionalStateBits because only the generated content
5905
0
    // container's frame construction item is marked with
5906
0
    // mIsGeneratedContent, and we might not have an aParentFrame.)
5907
0
    // We don't do it for content that may have XBL anonymous siblings,
5908
0
    // because they make it difficult to correctly create the frame
5909
0
    // due to dynamic changes.
5910
0
    // We don't do it for SVG text, since we might need to position and
5911
0
    // measure the white space glyphs due to x/y/dx/dy attributes.
5912
0
    if (AtLineBoundary(aIter) &&
5913
0
        !computedStyle->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
5914
0
        aIter.List()->ParentHasNoXBLChildren() &&
5915
0
        !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
5916
0
        (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
5917
0
        !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
5918
0
        !mAlwaysCreateFramesForIgnorableWhitespace &&
5919
0
        item.IsWhitespace(aState))
5920
0
      return;
5921
0
5922
0
    ConstructTextFrame(item.mFCData, aState, item.mContent,
5923
0
                       adjParentFrame, computedStyle,
5924
0
                       aFrameItems);
5925
0
    return;
5926
0
  }
5927
0
5928
0
  // Start background loads during frame construction so that we're
5929
0
  // guaranteed that they will be started before onload fires.
5930
0
  computedStyle->StartBackgroundImageLoads();
5931
0
5932
0
  AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
5933
0
  if (item.mIsGeneratedContent) {
5934
0
    // Ensure that frames created here are all tagged with
5935
0
    // NS_FRAME_GENERATED_CONTENT.
5936
0
    aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
5937
0
  }
5938
0
5939
0
  // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5940
0
  ConstructFrameFromItemInternal(item, aState, adjParentFrame, aFrameItems);
5941
0
5942
0
  if (item.mIsGeneratedContent) {
5943
0
    // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
5944
0
    // The frame owns the generated content now.
5945
0
    item.mContent->Release();
5946
0
5947
0
    // Now that we've passed ownership of item.mContent to the frame, unset
5948
0
    // our generated content flag so we don't release or unbind it ourselves.
5949
0
    item.mIsGeneratedContent = false;
5950
0
  }
5951
0
}
5952
5953
5954
inline bool
5955
IsRootBoxFrame(nsIFrame *aFrame)
5956
0
{
5957
0
  return (aFrame->IsRootFrame());
5958
0
}
5959
5960
void
5961
nsCSSFrameConstructor::ReconstructDocElementHierarchy(InsertionKind aInsertionKind)
5962
0
{
5963
0
  Element* rootElement = mDocument->GetRootElement();
5964
0
  if (!rootElement) {
5965
0
    /* nothing to do */
5966
0
    return;
5967
0
  }
5968
0
  RecreateFramesForContent(rootElement, aInsertionKind);
5969
0
}
5970
5971
nsContainerFrame*
5972
nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame,
5973
                                                  ContainingBlockType aType)
5974
0
{
5975
0
  // Starting with aFrame, look for a frame that is absolutely positioned or
5976
0
  // relatively positioned (and transformed, if aType is FIXED)
5977
0
  for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
5978
0
    if (frame->IsFrameOfType(nsIFrame::eMathML)) {
5979
0
      // If it's mathml, bail out -- no absolute positioning out from inside
5980
0
      // mathml frames.  Note that we don't make this part of the loop
5981
0
      // condition because of the stuff at the end of this method...
5982
0
      return nullptr;
5983
0
    }
5984
0
5985
0
    // Look for the ICB.
5986
0
    if (aType == FIXED_POS) {
5987
0
      LayoutFrameType t = frame->Type();
5988
0
      if (t == LayoutFrameType::Viewport || t == LayoutFrameType::PageContent) {
5989
0
        return static_cast<nsContainerFrame*>(frame);
5990
0
      }
5991
0
    }
5992
0
5993
0
    // If the frame is positioned, we will probably return it as the containing
5994
0
    // block (see the exceptions below).  Otherwise, we'll start looking at the
5995
0
    // parent frame, unless we're dealing with a scrollframe.
5996
0
    // Scrollframes are special since they're not positioned, but their
5997
0
    // scrolledframe might be.  So, we need to check this special case to return
5998
0
    // the correct containing block (the scrolledframe) in that case.
5999
0
    // If we're looking for a fixed-pos containing block and the frame is
6000
0
    // not transformed, skip it.
6001
0
    if (!frame->IsAbsPosContainingBlock() ||
6002
0
        (aType == FIXED_POS &&
6003
0
         !frame->IsFixedPosContainingBlock())) {
6004
0
      continue;
6005
0
    }
6006
0
    nsIFrame* absPosCBCandidate = frame;
6007
0
    LayoutFrameType type = absPosCBCandidate->Type();
6008
0
    if (type == LayoutFrameType::FieldSet) {
6009
0
      absPosCBCandidate = static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
6010
0
      if (!absPosCBCandidate) {
6011
0
        continue;
6012
0
      }
6013
0
      type = absPosCBCandidate->Type();
6014
0
    }
6015
0
    if (type == LayoutFrameType::Scroll) {
6016
0
      nsIScrollableFrame* scrollFrame = do_QueryFrame(absPosCBCandidate);
6017
0
      absPosCBCandidate = scrollFrame->GetScrolledFrame();
6018
0
      if (!absPosCBCandidate) {
6019
0
        continue;
6020
0
      }
6021
0
      type = absPosCBCandidate->Type();
6022
0
    }
6023
0
    // Only first continuations can be containing blocks.
6024
0
    absPosCBCandidate = absPosCBCandidate->FirstContinuation();
6025
0
    // Is the frame really an absolute container?
6026
0
    if (!absPosCBCandidate->IsAbsoluteContainer()) {
6027
0
      continue;
6028
0
    }
6029
0
6030
0
    // For tables, skip the inner frame and consider the table wrapper frame.
6031
0
    if (type == LayoutFrameType::Table) {
6032
0
      continue;
6033
0
    }
6034
0
    // For table wrapper frames, we can just return absPosCBCandidate.
6035
0
    MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(absPosCBCandidate),
6036
0
               "abs.pos. containing block must be nsContainerFrame sub-class");
6037
0
    return static_cast<nsContainerFrame*>(absPosCBCandidate);
6038
0
  }
6039
0
6040
0
  MOZ_ASSERT(aType != FIXED_POS, "no ICB in this frame tree?");
6041
0
6042
0
  // It is possible for the search for the containing block to fail, because
6043
0
  // no absolute container can be found in the parent chain.  In those cases,
6044
0
  // we fall back to the document element's containing block.
6045
0
  return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr;
6046
0
}
6047
6048
nsContainerFrame*
6049
nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
6050
0
{
6051
0
  // Starting with aFrame, look for a frame that is a float containing block.
6052
0
  // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
6053
0
  // frames, because they don't seem to be able to deal.
6054
0
  // The logic here needs to match the logic in ProcessChildren()
6055
0
  for (nsIFrame* containingBlock = aFrame;
6056
0
       containingBlock &&
6057
0
         !ShouldSuppressFloatingOfDescendants(containingBlock);
6058
0
       containingBlock = containingBlock->GetParent()) {
6059
0
    if (containingBlock->IsFloatContainingBlock()) {
6060
0
      MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(containingBlock),
6061
0
                 "float containing block must be nsContainerFrame sub-class");
6062
0
      return static_cast<nsContainerFrame*>(containingBlock);
6063
0
    }
6064
0
  }
6065
0
6066
0
  // If we didn't find a containing block, then there just isn't
6067
0
  // one.... return null
6068
0
  return nullptr;
6069
0
}
6070
6071
/**
6072
 * This function will get the previous sibling to use for an append operation.
6073
 *
6074
 * It takes a parent frame (must not be null) and the next insertion sibling, if
6075
 * the parent content is display: contents or has ::after content (may be null).
6076
 */
6077
static nsIFrame*
6078
FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
6079
0
{
6080
0
  aParentFrame->DrainSelfOverflowList();
6081
0
6082
0
  if (aNextSibling) {
6083
0
    MOZ_ASSERT(aNextSibling->GetParent() == aParentFrame, "Wrong parent");
6084
0
    return aNextSibling->GetPrevSibling();
6085
0
  }
6086
0
6087
0
  return aParentFrame->GetChildList(kPrincipalList).LastChild();
6088
0
}
6089
6090
/**
6091
 * Finds the right parent frame to append content to aParentFrame.
6092
 *
6093
 * Cannot return or receive null.
6094
 */
6095
static nsContainerFrame*
6096
ContinuationToAppendTo(nsContainerFrame* aParentFrame)
6097
0
{
6098
0
  MOZ_ASSERT(aParentFrame);
6099
0
6100
0
  if (IsFramePartOfIBSplit(aParentFrame)) {
6101
0
    // If the frame we are manipulating is a ib-split frame (that is, one that's
6102
0
    // been created as a result of a block-in-inline situation) then we need to
6103
0
    // append to the last ib-split sibling, not to the frame itself.
6104
0
    //
6105
0
    // Always make sure to look at the last continuation of the frame for the
6106
0
    // {ib} case, even if that continuation is empty.
6107
0
    //
6108
0
    // We don't do this for the non-ib-split-frame case, since in the other
6109
0
    // cases appending to the last nonempty continuation is fine and in fact not
6110
0
    // doing that can confuse code that doesn't know to pull kids from
6111
0
    // continuations other than its next one.
6112
0
    return static_cast<nsContainerFrame*>(GetLastIBSplitSibling(aParentFrame)->LastContinuation());
6113
0
  }
6114
0
6115
0
  return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
6116
0
}
6117
6118
/**
6119
 * This function will get the next sibling for a frame insert operation given
6120
 * the parent and previous sibling.  aPrevSibling may be null.
6121
 */
6122
static nsIFrame*
6123
GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
6124
0
{
6125
0
  if (aPrevSibling) {
6126
0
    return aPrevSibling->GetNextSibling();
6127
0
  }
6128
0
6129
0
  return aParentFrame->PrincipalChildList().FirstChild();
6130
0
}
6131
6132
/**
6133
 * This function is called by ContentAppended() and ContentInserted() when
6134
 * appending flowed frames to a parent's principal child list. It handles the
6135
 * case where the parent is the trailing inline of an {ib} split.
6136
 */
6137
void
6138
nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState&       aState,
6139
                                            nsContainerFrame*              aParentFrame,
6140
                                            nsFrameItems&                  aFrameList,
6141
                                            nsIFrame*                      aPrevSibling,
6142
                                            bool                           aIsRecursiveCall)
6143
0
{
6144
0
  MOZ_ASSERT(!IsFramePartOfIBSplit(aParentFrame) ||
6145
0
             !GetIBSplitSibling(aParentFrame) ||
6146
0
             !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild(),
6147
0
             "aParentFrame has a ib-split sibling with kids?");
6148
0
  MOZ_ASSERT(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
6149
0
             "Parent and prevsibling don't match");
6150
0
6151
0
  nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
6152
0
6153
0
  NS_ASSERTION(nextSibling ||
6154
0
               !aParentFrame->GetNextContinuation() ||
6155
0
               !aParentFrame->GetNextContinuation()->PrincipalChildList().FirstChild() ||
6156
0
               aIsRecursiveCall,
6157
0
               "aParentFrame has later continuations with kids?");
6158
0
  NS_ASSERTION(nextSibling ||
6159
0
               !IsFramePartOfIBSplit(aParentFrame) ||
6160
0
               (IsInlineFrame(aParentFrame) &&
6161
0
                !GetIBSplitSibling(aParentFrame) &&
6162
0
                !aParentFrame->GetNextContinuation()) ||
6163
0
               aIsRecursiveCall,
6164
0
               "aParentFrame is not last?");
6165
0
6166
0
  // If we're inserting a list of frames at the end of the trailing inline
6167
0
  // of an {ib} split, we may need to create additional {ib} siblings to parent
6168
0
  // them.
6169
0
  if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
6170
0
    // When we get here, our frame list might start with a block.  If it does
6171
0
    // so, and aParentFrame is an inline, and it and all its previous
6172
0
    // continuations have no siblings, then put the initial blocks from the
6173
0
    // frame list into the previous block of the {ib} split.  Note that we
6174
0
    // didn't want to stop at the block part of the split when figuring out
6175
0
    // initial parent, because that could screw up float parenting; it's easier
6176
0
    // to do this little fixup here instead.
6177
0
    if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) {
6178
0
      // See whether our trailing inline is empty
6179
0
      nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
6180
0
      if (firstContinuation->PrincipalChildList().IsEmpty()) {
6181
0
        // Our trailing inline is empty.  Collect our starting blocks from
6182
0
        // aFrameList, get the right parent frame for them, and put them in.
6183
0
        nsFrameList blockKids =
6184
0
          aFrameList.Split([](nsIFrame* f) { return f->IsInlineOutside();} );
6185
0
        NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
6186
0
6187
0
        nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
6188
0
        prevBlock = static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
6189
0
        NS_ASSERTION(prevBlock, "Should have previous block here");
6190
0
6191
0
        MoveChildrenTo(aParentFrame, prevBlock, blockKids);
6192
0
      }
6193
0
    }
6194
0
6195
0
    // We want to put some of the frames into this inline frame.
6196
0
    nsFrameList inlineKids =
6197
0
      aFrameList.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
6198
0
6199
0
    if (!inlineKids.IsEmpty()) {
6200
0
      AppendFrames(aParentFrame, kPrincipalList, inlineKids);
6201
0
    }
6202
0
6203
0
    if (!aFrameList.IsEmpty()) {
6204
0
      nsFrameItems ibSiblings;
6205
0
      CreateIBSiblings(aState, aParentFrame,
6206
0
                       aParentFrame->IsAbsPosContainingBlock(), aFrameList,
6207
0
                       ibSiblings);
6208
0
6209
0
      // Make sure to trigger reflow of the inline that used to be our
6210
0
      // last one and now isn't anymore, since its GetSkipSides() has
6211
0
      // changed.
6212
0
      mPresShell->FrameNeedsReflow(aParentFrame,
6213
0
                                   nsIPresShell::eTreeChange,
6214
0
                                   NS_FRAME_HAS_DIRTY_CHILDREN);
6215
0
6216
0
      // Recurse so we create new ib siblings as needed for aParentFrame's parent
6217
0
      return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
6218
0
                                   aParentFrame, true);
6219
0
    }
6220
0
    return;
6221
0
  }
6222
0
6223
0
  // Insert the frames after our aPrevSibling
6224
0
  InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
6225
0
}
6226
6227
// This gets called to see if the frames corresponding to aSibling and aContent
6228
// should be siblings in the frame tree. Although (1) rows and cols, (2) row
6229
// groups and col groups, (3) row groups and captions, (4) legends and content
6230
// inside fieldsets, (5) popups and other kids of the menu are siblings from a
6231
// content perspective, they are not considered siblings in the frame tree.
6232
bool
6233
nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
6234
                                      nsIContent* aContent,
6235
                                      Maybe<StyleDisplay>& aDisplay)
6236
0
{
6237
0
  nsIFrame* parentFrame = aSibling->GetParent();
6238
0
  LayoutFrameType parentType = parentFrame->Type();
6239
0
6240
0
  StyleDisplay siblingDisplay = aSibling->GetDisplay();
6241
0
  if (StyleDisplay::TableColumnGroup == siblingDisplay ||
6242
0
      StyleDisplay::TableColumn      == siblingDisplay ||
6243
0
      StyleDisplay::TableCaption     == siblingDisplay ||
6244
0
      StyleDisplay::TableHeaderGroup == siblingDisplay ||
6245
0
      StyleDisplay::TableRowGroup    == siblingDisplay ||
6246
0
      StyleDisplay::TableFooterGroup == siblingDisplay ||
6247
0
      LayoutFrameType::Menu == parentType) {
6248
0
    // if we haven't already, resolve a style to find the display type of
6249
0
    // aContent.
6250
0
    if (aDisplay.isNothing()) {
6251
0
      if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
6252
0
        // Comments and processing instructions never have frames, so we should
6253
0
        // not try to generate styles for them.
6254
0
        return false;
6255
0
      }
6256
0
      // FIXME(emilio): This is buggy some times, see bug 1424656.
6257
0
      RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
6258
0
      const nsStyleDisplay* display = computedStyle->StyleDisplay();
6259
0
      aDisplay.emplace(display->mDisplay);
6260
0
    }
6261
0
6262
0
    StyleDisplay display = aDisplay.value();
6263
0
    if (LayoutFrameType::Menu == parentType) {
6264
0
      return
6265
0
        (StyleDisplay::MozPopup == display) ==
6266
0
        (StyleDisplay::MozPopup == siblingDisplay);
6267
0
    }
6268
0
    // To have decent performance we want to return false in cases in which
6269
0
    // reordering the two siblings has no effect on display.  To ensure
6270
0
    // correctness, we MUST return false in cases where the two siblings have
6271
0
    // the same desired parent type and live on different display lists.
6272
0
    // Specificaly, columns and column groups should only consider columns and
6273
0
    // column groups as valid siblings.  Captions should only consider other
6274
0
    // captions.  All other things should consider each other as valid
6275
0
    // siblings.  The restriction in the |if| above on siblingDisplay is ok,
6276
0
    // because for correctness the only part that really needs to happen is to
6277
0
    // not consider captions, column groups, and row/header/footer groups
6278
0
    // siblings of each other.  Treating a column or colgroup as a valid
6279
0
    // sibling of a non-table-related frame will just mean we end up reframing.
6280
0
    if ((siblingDisplay == StyleDisplay::TableCaption) !=
6281
0
        (display == StyleDisplay::TableCaption)) {
6282
0
      // One's a caption and the other is not.  Not valid siblings.
6283
0
      return false;
6284
0
    }
6285
0
6286
0
    if ((siblingDisplay == StyleDisplay::TableColumnGroup ||
6287
0
         siblingDisplay == StyleDisplay::TableColumn) !=
6288
0
        (display == StyleDisplay::TableColumnGroup ||
6289
0
         display == StyleDisplay::TableColumn)) {
6290
0
      // One's a column or column group and the other is not.  Not valid
6291
0
      // siblings.
6292
0
      return false;
6293
0
    }
6294
0
    // Fall through; it's possible that the display type was overridden and
6295
0
    // a different sort of frame was constructed, so we may need to return false
6296
0
    // below.
6297
0
  }
6298
0
6299
0
  if (IsFrameForFieldSet(parentFrame)) {
6300
0
    // Legends can be sibling of legends but not of other content in the fieldset
6301
0
    if (nsContainerFrame* cif = aSibling->GetContentInsertionFrame()) {
6302
0
      aSibling = cif;
6303
0
    }
6304
0
    LayoutFrameType sibType = aSibling->Type();
6305
0
    bool legendContent = aContent->IsHTMLElement(nsGkAtoms::legend);
6306
0
6307
0
    if ((legendContent && (LayoutFrameType::Legend != sibType)) ||
6308
0
        (!legendContent && (LayoutFrameType::Legend == sibType)))
6309
0
      return false;
6310
0
  }
6311
0
6312
0
  return true;
6313
0
}
6314
6315
// FIXME(emilio): If we ever kill IsValidSibling() we can simplify this quite a
6316
// bit (no need to pass aTargetContent or aTargetContentDisplay, and the
6317
// adjust() calls can be responsibility of the caller).
6318
template<nsCSSFrameConstructor::SiblingDirection aDirection>
6319
nsIFrame*
6320
nsCSSFrameConstructor::FindSiblingInternal(
6321
  FlattenedChildIterator& aIter,
6322
  nsIContent* aTargetContent,
6323
  Maybe<StyleDisplay>& aTargetContentDisplay)
6324
0
{
6325
0
  auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* {
6326
0
    return AdjustSiblingFrame(
6327
0
      aPotentialSiblingFrame, aTargetContent, aTargetContentDisplay,
6328
0
      aDirection);
6329
0
  };
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)1>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(nsIFrame*)#1}::operator()(nsIFrame*) const
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)0>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(nsIFrame*)#1}::operator()(nsIFrame*) const
6330
0
6331
0
  auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
6332
0
    return aDirection == SiblingDirection::Forward
6333
0
      ? aIter.GetNextChild() : aIter.GetPreviousChild();
6334
0
  };
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)1>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(mozilla::dom::FlattenedChildIterator&)#1}::operator()(mozilla::dom::FlattenedChildIterator&) const
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)0>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(mozilla::dom::FlattenedChildIterator&)#1}::operator()(mozilla::dom::FlattenedChildIterator&) const
6335
0
6336
0
  auto getNearPseudo = [](const nsIContent* aContent) -> nsIFrame* {
6337
0
    return aDirection == SiblingDirection::Forward
6338
0
      ? nsLayoutUtils::GetBeforeFrame(aContent)
6339
0
      : nsLayoutUtils::GetAfterFrame(aContent);
6340
0
  };
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)1>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(nsIContent const*)#1}::operator()(nsIContent const*) const
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)0>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(nsIContent const*)#1}::operator()(nsIContent const*) const
6341
0
6342
0
  auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* {
6343
0
    return aDirection == SiblingDirection::Forward
6344
0
      ? nsLayoutUtils::GetAfterFrame(aContent)
6345
0
      : nsLayoutUtils::GetBeforeFrame(aContent);
6346
0
  };
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)1>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(nsIContent const*)#2}::operator()(nsIContent const*) const
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)0>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)::{lambda(nsIContent const*)#2}::operator()(nsIContent const*) const
6347
0
6348
0
  while (nsIContent* sibling = nextDomSibling(aIter)) {
6349
0
    // NOTE(emilio): It's important to check GetPrimaryFrame() before
6350
0
    // IsDisplayContents to get the correct insertion point when multiple
6351
0
    // siblings go from display: non-none to display: contents.
6352
0
    if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
6353
0
      // XXX the GetContent() == sibling check is needed due to bug 135040.
6354
0
      // Remove it once that's fixed.
6355
0
      if (primaryFrame->GetContent() == sibling) {
6356
0
        if (nsIFrame* frame = adjust(primaryFrame)) {
6357
0
          return frame;
6358
0
        }
6359
0
      }
6360
0
    }
6361
0
6362
0
    if (IsDisplayContents(sibling)) {
6363
0
      if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
6364
0
        return frame;
6365
0
      }
6366
0
6367
0
      const bool startFromBeginning = aDirection == SiblingDirection::Forward;
6368
0
      FlattenedChildIterator iter(sibling, startFromBeginning);
6369
0
      nsIFrame* sibling = FindSiblingInternal<aDirection>(
6370
0
        iter, aTargetContent, aTargetContentDisplay);
6371
0
      if (sibling) {
6372
0
        return sibling;
6373
0
      }
6374
0
    }
6375
0
  }
6376
0
6377
0
  return adjust(getFarPseudo(aIter.Parent()));
6378
0
}
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)1>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSiblingInternal<(nsCSSFrameConstructor::SiblingDirection)0>(mozilla::dom::FlattenedChildIterator&, nsIContent*, mozilla::Maybe<mozilla::StyleDisplay>&)
6379
6380
nsIFrame*
6381
nsCSSFrameConstructor::AdjustSiblingFrame(
6382
  nsIFrame* aSibling,
6383
  nsIContent* aTargetContent,
6384
  Maybe<StyleDisplay>& aTargetContentDisplay,
6385
  SiblingDirection aDirection)
6386
0
{
6387
0
  if (!aSibling) {
6388
0
    return nullptr;
6389
0
  }
6390
0
6391
0
  if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
6392
0
    aSibling = aSibling->GetPlaceholderFrame();
6393
0
    MOZ_ASSERT(aSibling);
6394
0
  }
6395
0
6396
0
  MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
6397
0
  if (aDirection == SiblingDirection::Backward) {
6398
0
    // The frame may be a ib-split frame (a split inline frame that contains a
6399
0
    // block).  Get the last part of that split.
6400
0
    if (IsFramePartOfIBSplit(aSibling)) {
6401
0
      aSibling = GetLastIBSplitSibling(aSibling);
6402
0
    }
6403
0
6404
0
    // The frame may have a continuation. If so, we want the last
6405
0
    // non-overflow-container continuation as our previous sibling.
6406
0
    aSibling = aSibling->GetTailContinuation();
6407
0
  }
6408
0
6409
0
  if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
6410
0
    return nullptr;
6411
0
  }
6412
0
6413
0
  return aSibling;
6414
0
}
6415
6416
nsIFrame*
6417
nsCSSFrameConstructor::FindPreviousSibling(const FlattenedChildIterator& aIter,
6418
                                           Maybe<StyleDisplay>& aTargetContentDisplay)
6419
0
{
6420
0
  return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay);
6421
0
}
6422
6423
nsIFrame*
6424
nsCSSFrameConstructor::FindNextSibling(const FlattenedChildIterator& aIter,
6425
                                       Maybe<StyleDisplay>& aTargetContentDisplay)
6426
0
{
6427
0
  return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay);
6428
0
}
6429
6430
template<nsCSSFrameConstructor::SiblingDirection aDirection>
6431
nsIFrame*
6432
nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter,
6433
                                   Maybe<StyleDisplay>& aTargetContentDisplay)
6434
0
{
6435
0
  nsIContent* targetContent = aIter.Get();
6436
0
  FlattenedChildIterator siblingIter = aIter;
6437
0
  nsIFrame* sibling = FindSiblingInternal<aDirection>(
6438
0
    siblingIter, targetContent, aTargetContentDisplay);
6439
0
  if (sibling) {
6440
0
    return sibling;
6441
0
  }
6442
0
6443
0
  // Our siblings (if any) do not have a frame to guide us. The frame for the
6444
0
  // target content should be inserted whereever a frame for the container would
6445
0
  // be inserted. This is needed when inserting into display: contents nodes.
6446
0
  const nsIContent* current = aIter.Parent();
6447
0
  while (IsDisplayContents(current)) {
6448
0
    const nsIContent* parent = current->GetFlattenedTreeParent();
6449
0
    MOZ_ASSERT(parent, "No display: contents on the root");
6450
0
6451
0
    FlattenedChildIterator iter(parent);
6452
0
    iter.Seek(current);
6453
0
    sibling = FindSiblingInternal<aDirection>(
6454
0
        iter, targetContent, aTargetContentDisplay);
6455
0
    if (sibling) {
6456
0
      return sibling;
6457
0
    }
6458
0
6459
0
    current = parent;
6460
0
  }
6461
0
6462
0
  return nullptr;
6463
0
}
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSibling<(nsCSSFrameConstructor::SiblingDirection)1>(mozilla::dom::FlattenedChildIterator const&, mozilla::Maybe<mozilla::StyleDisplay>&)
Unexecuted instantiation: nsIFrame* nsCSSFrameConstructor::FindSibling<(nsCSSFrameConstructor::SiblingDirection)0>(mozilla::dom::FlattenedChildIterator const&, mozilla::Maybe<mozilla::StyleDisplay>&)
6464
6465
// For fieldsets, returns the area frame, if the child is not a legend.
6466
static nsContainerFrame*
6467
GetAdjustedParentFrame(nsContainerFrame* aParentFrame,
6468
                       nsIContent* aChildContent)
6469
0
{
6470
0
  MOZ_ASSERT(!aParentFrame->IsTableWrapperFrame(), "Shouldn't be happening!");
6471
0
6472
0
  nsContainerFrame* newParent = nullptr;
6473
0
6474
0
  if (aParentFrame->IsFieldSetFrame()) {
6475
0
    // If the parent is a fieldSet, use the fieldSet's area frame as the
6476
0
    // parent unless the new content is a legend.
6477
0
    if (!aChildContent->IsHTMLElement(nsGkAtoms::legend)) {
6478
0
      newParent = GetFieldSetBlockFrame(aParentFrame);
6479
0
    }
6480
0
  }
6481
0
  return newParent ? newParent : aParentFrame;
6482
0
}
6483
6484
nsIFrame*
6485
nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
6486
                                               nsIContent* aChild,
6487
                                               bool*       aIsAppend,
6488
                                               bool*       aIsRangeInsertSafe,
6489
                                               nsIContent* aStartSkipChild,
6490
                                               nsIContent* aEndSkipChild)
6491
0
{
6492
0
  MOZ_ASSERT(aInsertion->mParentFrame, "Must have parent frame to start with");
6493
0
6494
0
  *aIsAppend = false;
6495
0
6496
0
  // Find the frame that precedes the insertion point. Walk backwards
6497
0
  // from the parent frame to get the parent content, because if an
6498
0
  // XBL insertion point is involved, we'll need to use _that_ to find
6499
0
  // the preceding frame.
6500
0
  FlattenedChildIterator iter(aInsertion->mContainer);
6501
0
  bool xblCase = iter.XBLInvolved() ||
6502
0
         aInsertion->mParentFrame->GetContent() != aInsertion->mContainer;
6503
0
  if (xblCase || !aChild->IsRootOfAnonymousSubtree()) {
6504
0
    // The check for IsRootOfAnonymousSubtree() is because editor is
6505
0
    // severely broken and calls us directly for native anonymous
6506
0
    // nodes that it creates.
6507
0
    if (aStartSkipChild) {
6508
0
      iter.Seek(aStartSkipChild);
6509
0
    } else {
6510
0
      iter.Seek(aChild);
6511
0
    }
6512
0
  } else {
6513
0
    // Prime the iterator for the call to FindPreviousSibling.
6514
0
    iter.GetNextChild();
6515
0
    MOZ_ASSERT(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
6516
0
               "Someone passed native anonymous content directly into frame "
6517
0
               "construction.  Stop doing that!");
6518
0
  }
6519
0
6520
0
  // Note that FindPreviousSibling is passed the iterator by value, so that
6521
0
  // the later usage of the iterator starts from the same place.
6522
0
  Maybe<StyleDisplay> childDisplay;
6523
0
  nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
6524
0
6525
0
  // Now, find the geometric parent so that we can handle
6526
0
  // continuations properly. Use the prev sibling if we have it;
6527
0
  // otherwise use the next sibling.
6528
0
  if (prevSibling) {
6529
0
    aInsertion->mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
6530
0
  } else {
6531
0
    // If there is no previous sibling, then find the frame that follows
6532
0
    //
6533
0
    // FIXME(emilio): This is really complex and probably shouldn't be.
6534
0
    if (aEndSkipChild) {
6535
0
      iter.Seek(aEndSkipChild);
6536
0
      iter.GetPreviousChild();
6537
0
    }
6538
0
    if (nsIFrame* nextSibling = FindNextSibling(iter, childDisplay)) {
6539
0
      aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
6540
0
    } else {
6541
0
      // No previous or next sibling, so treat this like an appended frame.
6542
0
      *aIsAppend = true;
6543
0
      aInsertion->mParentFrame =
6544
0
        ::ContinuationToAppendTo(aInsertion->mParentFrame);
6545
0
6546
0
      // Deal with fieldsets.
6547
0
      aInsertion->mParentFrame =
6548
0
        ::GetAdjustedParentFrame(aInsertion->mParentFrame, aChild);
6549
0
      prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr);
6550
0
    }
6551
0
  }
6552
0
6553
0
  *aIsRangeInsertSafe = childDisplay.isNothing();
6554
0
  return prevSibling;
6555
0
}
6556
6557
nsContainerFrame*
6558
nsCSSFrameConstructor::GetContentInsertionFrameFor(nsIContent* aContent)
6559
0
{
6560
0
  nsIFrame* frame;
6561
0
  while (!(frame = aContent->GetPrimaryFrame())) {
6562
0
    if (!IsDisplayContents(aContent)) {
6563
0
      return nullptr;
6564
0
    }
6565
0
6566
0
    aContent = aContent->GetFlattenedTreeParent();
6567
0
    if (!aContent) {
6568
0
      return nullptr;
6569
0
    }
6570
0
  }
6571
0
6572
0
  // If the content of the frame is not the desired content then this is not
6573
0
  // really a frame for the desired content.
6574
0
  // XXX This check is needed due to bug 135040. Remove it once that's fixed.
6575
0
  if (frame->GetContent() != aContent) {
6576
0
    return nullptr;
6577
0
  }
6578
0
6579
0
  nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
6580
0
6581
0
  NS_ASSERTION(!insertionFrame || insertionFrame == frame || !frame->IsLeaf(),
6582
0
    "The insertion frame is the primary frame or the primary frame isn't a leaf");
6583
0
6584
0
  return insertionFrame;
6585
0
}
6586
6587
static bool
6588
IsSpecialFramesetChild(nsIContent* aContent)
6589
0
{
6590
0
  // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
6591
0
  return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
6592
0
}
6593
6594
static void
6595
InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
6596
6597
void
6598
nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState& aState,
6599
                                           const InsertionPoint& aInsertion,
6600
                                           nsIContent* aPossibleTextContent,
6601
                                           FrameConstructionItemList& aItems)
6602
0
{
6603
0
  MOZ_ASSERT(aPossibleTextContent, "Must have node");
6604
0
  if (!aPossibleTextContent->IsText() ||
6605
0
      !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
6606
0
      aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
6607
0
    // Not text, or not suppressed due to being all-whitespace (if it were being
6608
0
    // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
6609
0
    // going to be reframed anyway.
6610
0
    return;
6611
0
  }
6612
0
  MOZ_ASSERT(!aPossibleTextContent->GetPrimaryFrame(),
6613
0
             "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6614
0
  AddFrameConstructionItems(aState, aPossibleTextContent, false,
6615
0
                            aInsertion, aItems);
6616
0
}
6617
6618
void
6619
nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aContent)
6620
0
{
6621
0
  if (!aContent->IsText() ||
6622
0
      !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
6623
0
      aContent->HasFlag(NODE_NEEDS_FRAME)) {
6624
0
    // Not text, or not suppressed due to being all-whitespace (if it were being
6625
0
    // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
6626
0
    // going to be reframed anyway.
6627
0
    return;
6628
0
  }
6629
0
  MOZ_ASSERT(!aContent->GetPrimaryFrame(),
6630
0
             "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6631
0
  ContentInserted(aContent, nullptr, InsertionKind::Async);
6632
0
}
6633
6634
#ifdef DEBUG
6635
void
6636
nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(nsIContent* aParent)
6637
{
6638
  // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
6639
  // we want to assert, but leaf frames that process their own children and may
6640
  // ignore anonymous children (eg framesets) make this complicated. So we set
6641
  // these two booleans if we encounter these situations and unset them if we
6642
  // hit a node with a leaf frame.
6643
  //
6644
  // It's fine if one of node without primary frame is in a display:none
6645
  // subtree.
6646
  //
6647
  // Also, it's fine if one of the nodes without primary frame is a display:
6648
  // contents node.
6649
  bool noPrimaryFrame = false;
6650
  bool needsFrameBitSet = false;
6651
  nsIContent* content = aParent;
6652
  while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6653
    if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
6654
      noPrimaryFrame = needsFrameBitSet = false;
6655
    }
6656
    if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
6657
      noPrimaryFrame = !IsDisplayContents(content);
6658
    }
6659
    if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
6660
      needsFrameBitSet = true;
6661
    }
6662
6663
    content = content->GetFlattenedTreeParent();
6664
  }
6665
  if (content && content->GetPrimaryFrame() &&
6666
      content->GetPrimaryFrame()->IsLeaf()) {
6667
    noPrimaryFrame = needsFrameBitSet = false;
6668
  }
6669
  MOZ_ASSERT(!noPrimaryFrame, "Ancestors of nodes with frames to be "
6670
    "constructed lazily should have frames");
6671
  MOZ_ASSERT(!needsFrameBitSet, "Ancestors of nodes with frames to be "
6672
    "constructed lazily should not have NEEDS_FRAME bit set");
6673
}
6674
#endif
6675
6676
// Returns true if this operation can be lazy, false if not.
6677
//
6678
// FIXME(emilio, bug 1410020): This function assumes that the flattened tree
6679
// parent of all the appended children is the same, which, afaict, is not
6680
// necessarily true.
6681
//
6682
// NOTE(emilio): The IsXULElement checks are pretty unfortunate, but there's
6683
// tons of browser chrome code that rely on XBL bindings getting synchronously
6684
// loaded as soon as the elements get inserted in the DOM.
6685
bool
6686
nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
6687
                                            nsIContent* aChild)
6688
0
{
6689
0
  MOZ_ASSERT(aChild->GetParent());
6690
0
  if (aOperation == CONTENTINSERT) {
6691
0
    MOZ_ASSERT(!aChild->IsRootOfAnonymousSubtree());
6692
0
    if (aChild->IsXULElement()) {
6693
0
      return false;
6694
0
    }
6695
0
  } else { // CONTENTAPPEND
6696
0
    MOZ_ASSERT(aOperation == CONTENTAPPEND,
6697
0
               "operation should be either insert or append");
6698
0
    for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6699
0
      MOZ_ASSERT(!child->IsRootOfAnonymousSubtree());
6700
0
      if (child->IsXULElement()) {
6701
0
        return false;
6702
0
      }
6703
0
    }
6704
0
  }
6705
0
6706
0
  // We can construct lazily; just need to set suitable bits in the content
6707
0
  // tree.
6708
0
  Element* parent = aChild->GetFlattenedTreeParentElement();
6709
0
  if (!parent) {
6710
0
    // Not part of the flat tree, nothing to do.
6711
0
    return true;
6712
0
  }
6713
0
6714
0
  if (Servo_Element_IsDisplayNone(parent)) {
6715
0
    // Nothing to do either.
6716
0
    //
6717
0
    // FIXME(emilio): This should be an assert, except for weird <frameset>
6718
0
    // stuff that does its own frame construction. Such an assert would fire in
6719
0
    // layout/style/crashtests/1411478.html, for example.
6720
0
    return true;
6721
0
  }
6722
0
6723
0
  // Set NODE_NEEDS_FRAME on the new nodes.
6724
0
  if (aOperation == CONTENTINSERT) {
6725
0
    NS_ASSERTION(!aChild->GetPrimaryFrame() ||
6726
0
                 aChild->GetPrimaryFrame()->GetContent() != aChild,
6727
0
                 //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
6728
0
                 // check is needed due to bug 135040. Remove it once that's
6729
0
                 // fixed.
6730
0
                 "setting NEEDS_FRAME on a node that already has a frame?");
6731
0
    aChild->SetFlags(NODE_NEEDS_FRAME);
6732
0
  } else { // CONTENTAPPEND
6733
0
    for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6734
0
      NS_ASSERTION(!child->GetPrimaryFrame() ||
6735
0
                   child->GetPrimaryFrame()->GetContent() != child,
6736
0
                   //XXX the child->GetPrimaryFrame()->GetContent() != child
6737
0
                   // check is needed due to bug 135040. Remove it once that's
6738
0
                   // fixed.
6739
0
                   "setting NEEDS_FRAME on a node that already has a frame?");
6740
0
      child->SetFlags(NODE_NEEDS_FRAME);
6741
0
    }
6742
0
  }
6743
0
6744
0
  CheckBitsForLazyFrameConstruction(parent);
6745
0
  parent->NoteDescendantsNeedFramesForServo();
6746
0
6747
0
  return true;
6748
0
}
6749
6750
6751
void
6752
nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aStartChild,
6753
                                                    nsIContent* aEndChild,
6754
                                                    InsertionKind aInsertionKind)
6755
0
{
6756
0
  for (nsIContent* child = aStartChild;
6757
0
       child != aEndChild;
6758
0
       child = child->GetNextSibling()) {
6759
0
    MOZ_ASSERT(!child->GetPrimaryFrame());
6760
0
6761
0
    // Call ContentRangeInserted with this node.
6762
0
    ContentRangeInserted(child, child->GetNextSibling(),
6763
0
                         mTempFrameTreeState, aInsertionKind);
6764
0
  }
6765
0
}
6766
6767
bool
6768
nsCSSFrameConstructor::InsertionPoint::IsMultiple() const
6769
0
{
6770
0
  if (!mParentFrame) {
6771
0
    return false;
6772
0
  }
6773
0
6774
0
  // Fieldset frames have multiple normal flow child frame lists so handle it
6775
0
  // the same as if it had multiple content insertion points.
6776
0
  if (mParentFrame->IsFieldSetFrame()) {
6777
0
    return true;
6778
0
  }
6779
0
6780
0
  // A details frame moves the first summary frame to be its first child, so we
6781
0
  // treat it as if it has multiple content insertion points.
6782
0
  if (mParentFrame->IsDetailsFrame()) {
6783
0
    return true;
6784
0
  }
6785
0
6786
0
  return false;
6787
0
}
6788
6789
nsCSSFrameConstructor::InsertionPoint
6790
nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
6791
                                              nsIContent* aEndChild,
6792
                                              InsertionKind aInsertionKind)
6793
0
{
6794
0
  MOZ_ASSERT(aStartChild);
6795
0
  MOZ_ASSERT(aStartChild->GetParent());
6796
0
6797
0
  nsIContent* parent = aStartChild->GetParent();
6798
0
6799
0
  // If the children of the container may be distributed to different insertion
6800
0
  // points, insert them separately and bail out, letting ContentInserted handle
6801
0
  // the mess.
6802
0
  if (parent->GetShadowRoot() || parent->GetXBLBinding()) {
6803
0
    IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
6804
0
    return { };
6805
0
  }
6806
0
6807
#ifdef DEBUG
6808
  {
6809
    nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
6810
    for (nsIContent* child = aStartChild->GetNextSibling(); child;
6811
         child = child->GetNextSibling()) {
6812
      MOZ_ASSERT(child->GetFlattenedTreeParent() == expectedParent);
6813
    }
6814
  }
6815
#endif
6816
6817
0
  // Now the flattened tree parent of all the siblings is the same, just use the
6818
0
  // same insertion point and take the fast path, unless it's a multiple
6819
0
  // insertion point.
6820
0
  InsertionPoint ip = GetInsertionPoint(aStartChild);
6821
0
  if (ip.IsMultiple()) {
6822
0
    IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
6823
0
    return { };
6824
0
  }
6825
0
6826
0
  return ip;
6827
0
}
6828
6829
bool
6830
nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
6831
                                                nsIContent* aStartChild,
6832
                                                nsIContent* aEndChild)
6833
0
{
6834
0
  if (aParentFrame->IsFrameSetFrame()) {
6835
0
    // Check whether we have any kids we care about.
6836
0
    for (nsIContent* cur = aStartChild;
6837
0
         cur != aEndChild;
6838
0
         cur = cur->GetNextSibling()) {
6839
0
      if (IsSpecialFramesetChild(cur)) {
6840
0
        // Just reframe the parent, since framesets are weird like that.
6841
0
        RecreateFramesForContent(aParentFrame->GetContent(),
6842
0
                                 InsertionKind::Async);
6843
0
        return true;
6844
0
      }
6845
0
    }
6846
0
  }
6847
0
  return false;
6848
0
}
6849
6850
void
6851
nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
6852
                                                nsIContent* aEndChild)
6853
0
{
6854
0
  for (nsIContent* child = aStartChild; child != aEndChild;
6855
0
       child = child->GetNextSibling()) {
6856
0
    if (child->IsElement()) {
6857
0
      child->AsElement()->NoteDirtyForServo();
6858
0
    }
6859
0
  }
6860
0
}
6861
6862
#ifdef DEBUG
6863
static bool
6864
IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild)
6865
{
6866
  FlattenedChildIterator iter(aParent);
6867
  for (nsIContent* node = iter.GetNextChild();
6868
       node;
6869
       node = iter.GetNextChild()) {
6870
    if (node == aChild) {
6871
      return true;
6872
    }
6873
  }
6874
  return false;
6875
}
6876
#endif
6877
6878
void
6879
nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
6880
                                          nsIContent* aEndChild)
6881
0
{
6882
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
6883
0
6884
0
  for (nsIContent* child = aStartChild; child != aEndChild;
6885
0
       child = child->GetNextSibling()) {
6886
0
    if (!child->IsElement()) {
6887
0
      continue;
6888
0
    }
6889
0
6890
0
    Element* childElement = child->AsElement();
6891
0
6892
0
    // We only come in here from non-lazy frame construction, so the children
6893
0
    // should be unstyled.
6894
0
    MOZ_ASSERT(!childElement->HasServoData());
6895
0
6896
#ifdef DEBUG
6897
    {
6898
      // Furthermore, all of them should have the same flattened tree parent
6899
      // (GetRangeInsertionPoint ensures it). And that parent should be styled,
6900
      // otherwise we would've never found an insertion point at all.
6901
      Element* parent = childElement->GetFlattenedTreeParentElement();
6902
      MOZ_ASSERT(parent);
6903
      MOZ_ASSERT(parent->HasServoData());
6904
      MOZ_ASSERT(IsFlattenedTreeChild(parent, child),
6905
                 "GetFlattenedTreeParent and ChildIterator don't agree, fix this!");
6906
    }
6907
#endif
6908
6909
0
    styleSet->StyleNewSubtree(childElement);
6910
0
  }
6911
0
}
6912
6913
nsIFrame*
6914
nsCSSFrameConstructor::FindNextSiblingForAppend(const InsertionPoint& aInsertion)
6915
0
{
6916
0
  auto SlowPath = [&]() -> nsIFrame* {
6917
0
    FlattenedChildIterator iter(aInsertion.mContainer,
6918
0
                                /* aStartAtBeginning = */ false);
6919
0
    iter.GetPreviousChild(); // Prime the iterator.
6920
0
    Maybe<StyleDisplay> unused;
6921
0
    return FindNextSibling(iter, unused);
6922
0
  };
6923
0
6924
0
  if (!IsDisplayContents(aInsertion.mContainer) &&
6925
0
      !nsLayoutUtils::GetAfterFrame(aInsertion.mContainer)) {
6926
0
    MOZ_ASSERT(!SlowPath());
6927
0
    return nullptr;
6928
0
  }
6929
0
6930
0
  return SlowPath();
6931
0
}
6932
6933
void
6934
nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
6935
                                       InsertionKind aInsertionKind)
6936
0
{
6937
0
  MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
6938
0
             !RestyleManager()->IsInStyleRefresh());
6939
0
6940
0
  AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ContentAppended", LAYOUT);
6941
0
  AUTO_PROFILER_TRACING("Frame Construction", "ContentAppended");
6942
0
  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
6943
0
6944
#ifdef DEBUG
6945
  if (gNoisyContentUpdates) {
6946
    printf("nsCSSFrameConstructor::ContentAppended container=%p "
6947
           "first-child=%p lazy=%d\n",
6948
           aFirstNewContent->GetParent(),
6949
           aFirstNewContent,
6950
           aInsertionKind == InsertionKind::Async);
6951
    if (gReallyNoisyContentUpdates && aFirstNewContent->GetParent()) {
6952
      aFirstNewContent->GetParent()->List(stdout, 0);
6953
    }
6954
  }
6955
6956
  for (nsIContent* child = aFirstNewContent;
6957
       child;
6958
       child = child->GetNextSibling()) {
6959
    // XXX the GetContent() != child check is needed due to bug 135040.
6960
    // Remove it once that's fixed.
6961
    MOZ_ASSERT(!child->GetPrimaryFrame() ||
6962
               child->GetPrimaryFrame()->GetContent() != child,
6963
               "asked to construct a frame for a node that already has a frame");
6964
  }
6965
#endif
6966
6967
0
  LAYOUT_PHASE_TEMP_EXIT();
6968
0
  InsertionPoint insertion =
6969
0
    GetRangeInsertionPoint(aFirstNewContent, nullptr, aInsertionKind);
6970
0
  nsContainerFrame*& parentFrame = insertion.mParentFrame;
6971
0
  LAYOUT_PHASE_TEMP_REENTER();
6972
0
  if (!parentFrame) {
6973
0
    // We're punting on frame construction because there's no container frame.
6974
0
    // The Servo-backed style system handles this case like the lazy frame
6975
0
    // construction case, except when we're already constructing frames, in
6976
0
    // which case we shouldn't need to do anything else.
6977
0
    if (aInsertionKind == InsertionKind::Async) {
6978
0
      LazilyStyleNewChildRange(aFirstNewContent, nullptr);
6979
0
    }
6980
0
    return;
6981
0
  }
6982
0
6983
0
  if (aInsertionKind == InsertionKind::Async) {
6984
0
    if (MaybeConstructLazily(CONTENTAPPEND, aFirstNewContent)) {
6985
0
      LazilyStyleNewChildRange(aFirstNewContent, nullptr);
6986
0
      return;
6987
0
    }
6988
0
    // We couldn't construct lazily. Make Servo eagerly traverse the new content
6989
0
    // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
6990
0
    // styles are up-to-date already).
6991
0
    StyleNewChildRange(aFirstNewContent, nullptr);
6992
0
  }
6993
0
6994
0
6995
0
  LAYOUT_PHASE_TEMP_EXIT();
6996
0
  if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
6997
0
    LAYOUT_PHASE_TEMP_REENTER();
6998
0
    return;
6999
0
  }
7000
0
  LAYOUT_PHASE_TEMP_REENTER();
7001
0
7002
0
  if (parentFrame->IsLeaf()) {
7003
0
    // Nothing to do here; we shouldn't be constructing kids of leaves
7004
0
    // Clear lazy bits so we don't try to construct again.
7005
0
    ClearLazyBits(aFirstNewContent, nullptr);
7006
0
    return;
7007
0
  }
7008
0
7009
0
  if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7010
0
    LAYOUT_PHASE_TEMP_EXIT();
7011
0
    RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
7012
0
    LAYOUT_PHASE_TEMP_REENTER();
7013
0
    return;
7014
0
  }
7015
0
7016
#ifdef DEBUG
7017
  if (gNoisyContentUpdates && IsFramePartOfIBSplit(parentFrame)) {
7018
    printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
7019
    nsFrame::ListTag(stdout, parentFrame);
7020
    printf(" is ib-split\n");
7021
  }
7022
#endif
7023
7024
0
  // We should never get here with fieldsets or details, since they have
7025
0
  // multiple insertion points.
7026
0
  MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
7027
0
             "Parent frame should not be fieldset or details!");
7028
0
7029
0
  nsIFrame* nextSibling = FindNextSiblingForAppend(insertion);
7030
0
  if (nextSibling) {
7031
0
    parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7032
0
  } else {
7033
0
    parentFrame =
7034
0
      ::ContinuationToAppendTo(parentFrame);
7035
0
  }
7036
0
7037
0
  nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
7038
0
7039
0
  // See if the containing block has :first-letter style applied.
7040
0
  const bool haveFirstLetterStyle =
7041
0
    containingBlock && HasFirstLetterStyle(containingBlock);
7042
0
7043
0
  const bool haveFirstLineStyle =
7044
0
    containingBlock &&
7045
0
    ShouldHaveFirstLineStyle(containingBlock->GetContent(),
7046
0
                             containingBlock->Style());
7047
0
7048
0
  if (haveFirstLetterStyle) {
7049
0
    AutoWeakFrame wf(nextSibling);
7050
0
7051
0
    // Before we get going, remove the current letter frames
7052
0
    RemoveLetterFrames(mPresShell, containingBlock);
7053
0
7054
0
    // Reget nextSibling, since we may have killed it.
7055
0
    //
7056
0
    // FIXME(emilio): This kinda sucks! :(
7057
0
    if (nextSibling && !wf) {
7058
0
      nextSibling = FindNextSiblingForAppend(insertion);
7059
0
      if (nextSibling) {
7060
0
        parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
7061
0
        containingBlock = GetFloatContainingBlock(parentFrame);
7062
0
      }
7063
0
    }
7064
0
  }
7065
0
7066
0
  // Create some new frames
7067
0
  nsFrameConstructorState state(mPresShell,
7068
0
                                GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
7069
0
                                GetAbsoluteContainingBlock(parentFrame, ABS_POS),
7070
0
                                containingBlock);
7071
0
7072
0
  LayoutFrameType frameType = parentFrame->Type();
7073
0
7074
0
  FlattenedChildIterator iter(insertion.mContainer);
7075
0
  const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
7076
0
7077
0
  AutoFrameConstructionItemList items(this);
7078
0
  if (aFirstNewContent->GetPreviousSibling() &&
7079
0
      GetParentType(frameType) == eTypeBlock &&
7080
0
      haveNoXBLChildren) {
7081
0
    // If there's a text node in the normal content list just before the new
7082
0
    // items, and it has no frame, make a frame construction item for it. If it
7083
0
    // doesn't need a frame, ConstructFramesFromItemList below won't give it
7084
0
    // one.  No need to do all this if our parent type is not block, though,
7085
0
    // since WipeContainingBlock already handles that situation.
7086
0
    //
7087
0
    // Because we're appending, we don't need to worry about any text
7088
0
    // after the appended content; there can only be XBL anonymous content
7089
0
    // (text in an XBL binding is not suppressed) or generated content
7090
0
    // (and bare text nodes are not generated). Native anonymous content
7091
0
    // generated by frames never participates in inline layout.
7092
0
    AddTextItemIfNeeded(state,
7093
0
                        insertion,
7094
0
                        aFirstNewContent->GetPreviousSibling(),
7095
0
                        items);
7096
0
  }
7097
0
  for (nsIContent* child = aFirstNewContent;
7098
0
       child;
7099
0
       child = child->GetNextSibling()) {
7100
0
    AddFrameConstructionItems(state, child, false, insertion, items);
7101
0
  }
7102
0
7103
0
  nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, nextSibling);
7104
0
7105
0
  // Perform special check for diddling around with the frames in
7106
0
  // a ib-split inline frame.
7107
0
  // If we're appending before :after content, then we're not really
7108
0
  // appending, so let WipeContainingBlock know that.
7109
0
  LAYOUT_PHASE_TEMP_EXIT();
7110
0
  if (WipeContainingBlock(state, containingBlock, parentFrame, items,
7111
0
                          true, prevSibling)) {
7112
0
    LAYOUT_PHASE_TEMP_REENTER();
7113
0
    return;
7114
0
  }
7115
0
  LAYOUT_PHASE_TEMP_REENTER();
7116
0
7117
0
  // If the parent is a block frame, and we're not in a special case
7118
0
  // where frames can be moved around, determine if the list is for the
7119
0
  // start or end of the block.
7120
0
  if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
7121
0
      !haveFirstLineStyle && !IsFramePartOfIBSplit(parentFrame)) {
7122
0
    items.SetLineBoundaryAtStart(!prevSibling ||
7123
0
                                 !prevSibling->IsInlineOutside() ||
7124
0
                                 prevSibling->IsBrFrame());
7125
0
    // :after content can't be <br> so no need to check it
7126
0
    //
7127
0
    // FIXME(emilio): A display: contents sibling could! Write a test-case and
7128
0
    // fix.
7129
0
    items.SetLineBoundaryAtEnd(
7130
0
        !nextSibling || !nextSibling->IsInlineOutside());
7131
0
  }
7132
0
  // To suppress whitespace-only text frames, we have to verify that
7133
0
  // our container's DOM child list matches its flattened tree child list.
7134
0
  items.SetParentHasNoXBLChildren(haveNoXBLChildren);
7135
0
7136
0
  nsFrameItems frameItems;
7137
0
  ConstructFramesFromItemList(state, items, parentFrame,
7138
0
                              ParentIsWrapperAnonBox(parentFrame),
7139
0
                              frameItems);
7140
0
7141
0
  for (nsIContent* child = aFirstNewContent;
7142
0
       child;
7143
0
       child = child->GetNextSibling()) {
7144
0
    // Invalidate now instead of before the WipeContainingBlock call, just in
7145
0
    // case we do wipe; in that case we don't need to do this walk at all.
7146
0
    // XXXbz does that matter?  Would it make more sense to save some virtual
7147
0
    // GetChildAt_Deprecated calls instead and do this during construction of
7148
0
    // our FrameConstructionItemList?
7149
0
    InvalidateCanvasIfNeeded(mPresShell, child);
7150
0
  }
7151
0
7152
0
  // If the container is a table and a caption was appended, it needs to be put
7153
0
  // in the table wrapper frame's additional child list.
7154
0
  nsFrameItems captionItems;
7155
0
  if (LayoutFrameType::Table == frameType) {
7156
0
    // Pull out the captions.  Note that we don't want to do that as we go,
7157
0
    // because processing a single caption can add a whole bunch of things to
7158
0
    // the frame items due to pseudoframe processing.  So we'd have to pull
7159
0
    // captions from a list anyway; might as well do that here.
7160
0
    // XXXbz this is no longer true; we could pull captions directly out of the
7161
0
    // FrameConstructionItemList now.
7162
0
    PullOutCaptionFrames(frameItems, captionItems);
7163
0
  }
7164
0
7165
0
  if (haveFirstLineStyle && parentFrame == containingBlock) {
7166
0
    // It's possible that some of the new frames go into a
7167
0
    // first-line frame. Look at them and see...
7168
0
    AppendFirstLineFrames(state, containingBlock->GetContent(),
7169
0
                          containingBlock, frameItems);
7170
0
    // That moved things into line frames as needed, reparenting their
7171
0
    // styles.  Nothing else needs to be done.
7172
0
  } else if (parentFrame->Style()->HasPseudoElementData()) {
7173
0
    // parentFrame might be inside a ::first-line frame.  Check whether it is,
7174
0
    // and if so fix up our styles.
7175
0
    CheckForFirstLineInsertion(parentFrame, frameItems);
7176
0
    CheckForFirstLineInsertion(parentFrame, captionItems);
7177
0
  }
7178
0
7179
0
  // Notify the parent frame passing it the list of new frames
7180
0
  // Append the flowed frames to the principal child list; captions
7181
0
  // need special treatment
7182
0
  if (captionItems.NotEmpty()) { // append the caption to the table wrapper
7183
0
    NS_ASSERTION(LayoutFrameType::Table == frameType, "how did that happen?");
7184
0
    nsContainerFrame* outerTable = parentFrame->GetParent();
7185
0
    AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7186
0
  }
7187
0
7188
0
  if (frameItems.NotEmpty()) { // append the in-flow kids
7189
0
    AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
7190
0
  }
7191
0
7192
0
  // Recover first-letter frames
7193
0
  if (haveFirstLetterStyle) {
7194
0
    RecoverLetterFrames(containingBlock);
7195
0
  }
7196
0
7197
#ifdef DEBUG
7198
  if (gReallyNoisyContentUpdates) {
7199
    printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
7200
    parentFrame->List(stdout, 0);
7201
  }
7202
#endif
7203
7204
0
#ifdef ACCESSIBILITY
7205
0
  if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7206
0
    accService->ContentRangeInserted(mPresShell, aFirstNewContent, nullptr);
7207
0
  }
7208
0
#endif
7209
0
}
7210
7211
void
7212
nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
7213
                                       nsILayoutHistoryState* aFrameState,
7214
                                       InsertionKind aInsertionKind)
7215
0
{
7216
0
  ContentRangeInserted(aChild,
7217
0
                       aChild->GetNextSibling(),
7218
0
                       aFrameState,
7219
0
                       aInsertionKind);
7220
0
}
7221
7222
// ContentRangeInserted handles creating frames for a range of nodes that
7223
// aren't at the end of their childlist. ContentRangeInserted isn't a real
7224
// content notification, but rather it handles regular ContentInserted calls
7225
// for a single node as well as the lazy construction of frames for a range of
7226
// nodes when called from CreateNeededFrames. For a range of nodes to be
7227
// suitable to have its frames constructed all at once they must meet the same
7228
// conditions that ContentAppended imposes (GetRangeInsertionPoint checks
7229
// these), plus more. Namely when finding the insertion prevsibling we must not
7230
// need to consult something specific to any one node in the range, so that the
7231
// insertion prevsibling would be the same for each node in the range. So we
7232
// pass the first node in the range to GetInsertionPrevSibling, and if
7233
// IsValidSibling (the only place GetInsertionPrevSibling might look at the
7234
// passed in node itself) needs to resolve style on the node we record this and
7235
// return that this range needs to be split up and inserted separately. Table
7236
// captions need extra attention as we need to determine where to insert them
7237
// in the caption list, while skipping any nodes in the range being inserted
7238
// (because when we treat the caption frames the other nodes have had their
7239
// frames constructed but not yet inserted into the frame tree).
7240
void
7241
nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
7242
                                            nsIContent* aEndChild,
7243
                                            nsILayoutHistoryState* aFrameState,
7244
                                            InsertionKind aInsertionKind)
7245
0
{
7246
0
  MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
7247
0
             !RestyleManager()->IsInStyleRefresh());
7248
0
7249
0
  AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ContentRangeInserted", LAYOUT);
7250
0
  AUTO_PROFILER_TRACING("Frame Construction", "ContentRangeInserted");
7251
0
  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7252
0
7253
0
  MOZ_ASSERT(aStartChild, "must always pass a child");
7254
0
7255
#ifdef DEBUG
7256
  if (gNoisyContentUpdates) {
7257
    printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
7258
           "start-child=%p end-child=%p lazy=%d\n",
7259
           aStartChild->GetParent(),
7260
           aStartChild,
7261
           aEndChild,
7262
           aInsertionKind == InsertionKind::Async);
7263
    if (gReallyNoisyContentUpdates) {
7264
      if (aStartChild->GetParent()) {
7265
        aStartChild->GetParent()->List(stdout,0);
7266
      } else {
7267
        aStartChild->List(stdout, 0);
7268
      }
7269
    }
7270
  }
7271
7272
  for (nsIContent* child = aStartChild;
7273
       child != aEndChild;
7274
       child = child->GetNextSibling()) {
7275
    // XXX the GetContent() != child check is needed due to bug 135040.
7276
    // Remove it once that's fixed.
7277
    NS_ASSERTION(!child->GetPrimaryFrame() ||
7278
                 child->GetPrimaryFrame()->GetContent() != child,
7279
                 "asked to construct a frame for a node that already has a frame");
7280
  }
7281
#endif
7282
7283
0
7284
0
  bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
7285
0
  NS_ASSERTION(isSingleInsert ||
7286
0
               aInsertionKind == InsertionKind::Sync,
7287
0
               "range insert shouldn't be lazy");
7288
0
  NS_ASSERTION(isSingleInsert || aEndChild,
7289
0
               "range should not include all nodes after aStartChild");
7290
0
7291
0
  // If we have a null parent, then this must be the document element being
7292
0
  // inserted, or some other child of the document in the DOM (might be a PI,
7293
0
  // say).
7294
0
  if (!aStartChild->GetParent()) {
7295
0
    MOZ_ASSERT(isSingleInsert,
7296
0
               "root node insertion should be a single insertion");
7297
0
    Element* docElement = mDocument->GetRootElement();
7298
0
7299
0
    if (aStartChild != docElement) {
7300
0
      // Not the root element; just bail out
7301
0
      return;
7302
0
    }
7303
0
7304
0
    MOZ_ASSERT(!mRootElementFrame, "root element frame already created");
7305
0
7306
0
    // Create frames for the document element and its child elements
7307
0
    if (ConstructDocElementFrame(docElement, aFrameState)) {
7308
0
      InvalidateCanvasIfNeeded(mPresShell, aStartChild);
7309
#ifdef DEBUG
7310
      if (gReallyNoisyContentUpdates) {
7311
        printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
7312
               "model:\n");
7313
        mRootElementFrame->List(stdout, 0);
7314
      }
7315
#endif
7316
    }
7317
0
7318
0
    if (aFrameState) {
7319
0
      // Restore frame state for the root scroll frame if there is one
7320
0
      if (nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame()) {
7321
0
        RestoreFrameStateFor(rootScrollFrame, aFrameState);
7322
0
      }
7323
0
    }
7324
0
7325
0
#ifdef ACCESSIBILITY
7326
0
    if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7327
0
      accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
7328
0
    }
7329
0
#endif
7330
0
7331
0
    return;
7332
0
  }
7333
0
7334
0
  InsertionPoint insertion;
7335
0
  if (isSingleInsert) {
7336
0
    // See if we have an XBL insertion point. If so, then that's our
7337
0
    // real parent frame; if not, then the frame hasn't been built yet
7338
0
    // and we just bail.
7339
0
    insertion = GetInsertionPoint(aStartChild);
7340
0
  } else {
7341
0
    // Get our insertion point. If we need to issue single ContentInserteds
7342
0
    // GetRangeInsertionPoint will take care of that for us.
7343
0
    LAYOUT_PHASE_TEMP_EXIT();
7344
0
    insertion = GetRangeInsertionPoint(aStartChild, aEndChild, aInsertionKind);
7345
0
    LAYOUT_PHASE_TEMP_REENTER();
7346
0
  }
7347
0
7348
0
  if (!insertion.mParentFrame) {
7349
0
    // We're punting on frame construction because there's no container frame.
7350
0
    // The Servo-backed style system handles this case like the lazy frame
7351
0
    // construction case, except when we're already constructing frames, in
7352
0
    // which case we shouldn't need to do anything else.
7353
0
    if (aInsertionKind == InsertionKind::Async) {
7354
0
      LazilyStyleNewChildRange(aStartChild, aEndChild);
7355
0
    }
7356
0
    return;
7357
0
  }
7358
0
7359
0
  if (aInsertionKind == InsertionKind::Async) {
7360
0
    if (MaybeConstructLazily(CONTENTINSERT, aStartChild)) {
7361
0
      LazilyStyleNewChildRange(aStartChild, aEndChild);
7362
0
      return;
7363
0
    }
7364
0
    // We couldn't construct lazily. Make Servo eagerly traverse the new content
7365
0
    // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
7366
0
    // styles are up-to-date already).
7367
0
    StyleNewChildRange(aStartChild, aEndChild);
7368
0
  }
7369
0
7370
0
  bool isAppend, isRangeInsertSafe;
7371
0
  nsIFrame* prevSibling = GetInsertionPrevSibling(&insertion, aStartChild,
7372
0
                                                  &isAppend, &isRangeInsertSafe);
7373
0
7374
0
  // check if range insert is safe
7375
0
  if (!isSingleInsert && !isRangeInsertSafe) {
7376
0
    // must fall back to a single ContertInserted for each child in the range
7377
0
    LAYOUT_PHASE_TEMP_EXIT();
7378
0
    IssueSingleInsertNofications(aStartChild, aEndChild, InsertionKind::Sync);
7379
0
    LAYOUT_PHASE_TEMP_REENTER();
7380
0
    return;
7381
0
  }
7382
0
7383
0
  LayoutFrameType frameType = insertion.mParentFrame->Type();
7384
0
  LAYOUT_PHASE_TEMP_EXIT();
7385
0
  if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild)) {
7386
0
    LAYOUT_PHASE_TEMP_REENTER();
7387
0
    return;
7388
0
  }
7389
0
  LAYOUT_PHASE_TEMP_REENTER();
7390
0
7391
0
  // We should only get here with fieldsets when doing a single insert, because
7392
0
  // fieldsets have multiple insertion points.
7393
0
  NS_ASSERTION(isSingleInsert || frameType != LayoutFrameType::FieldSet,
7394
0
               "Unexpected parent");
7395
0
  if (IsFrameForFieldSet(insertion.mParentFrame) &&
7396
0
      aStartChild->NodeInfo()->NameAtom() == nsGkAtoms::legend) {
7397
0
    // Just reframe the parent, since figuring out whether this
7398
0
    // should be the new legend and then handling it is too complex.
7399
0
    // We could do a little better here --- check if the fieldset already
7400
0
    // has a legend which occurs earlier in its child list than this node,
7401
0
    // and if so, proceed. But we'd have to extend nsFieldSetFrame
7402
0
    // to locate this legend in the inserted frames and extract it.
7403
0
    LAYOUT_PHASE_TEMP_EXIT();
7404
0
    RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7405
0
                             InsertionKind::Async);
7406
0
    LAYOUT_PHASE_TEMP_REENTER();
7407
0
    return;
7408
0
  }
7409
0
7410
0
  // We should only get here with details when doing a single insertion because
7411
0
  // we treat details frame as if it has multiple insertion points.
7412
0
  MOZ_ASSERT(isSingleInsert || frameType != LayoutFrameType::Details);
7413
0
  if (frameType == LayoutFrameType::Details) {
7414
0
    // When inserting an element into <details>, just reframe the details frame
7415
0
    // and let it figure out where the element should be laid out. It might seem
7416
0
    // expensive to recreate the entire details frame, but it's the simplest way
7417
0
    // to handle the insertion.
7418
0
    LAYOUT_PHASE_TEMP_EXIT();
7419
0
    RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7420
0
                             InsertionKind::Async);
7421
0
    LAYOUT_PHASE_TEMP_REENTER();
7422
0
    return;
7423
0
  }
7424
0
7425
0
  // Don't construct kids of leaves
7426
0
  if (insertion.mParentFrame->IsLeaf()) {
7427
0
    // Clear lazy bits so we don't try to construct again.
7428
0
    ClearLazyBits(aStartChild, aEndChild);
7429
0
    return;
7430
0
  }
7431
0
7432
0
  // FIXME(emilio): This looks terribly inefficient if you insert elements deep
7433
0
  // in a MathML subtree.
7434
0
  if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
7435
0
    LAYOUT_PHASE_TEMP_EXIT();
7436
0
    RecreateFramesForContent(insertion.mParentFrame->GetContent(),
7437
0
                             InsertionKind::Async);
7438
0
    LAYOUT_PHASE_TEMP_REENTER();
7439
0
    return;
7440
0
  }
7441
0
7442
0
  nsFrameConstructorState state(mPresShell,
7443
0
                                GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
7444
0
                                GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
7445
0
                                GetFloatContainingBlock(insertion.mParentFrame),
7446
0
                                do_AddRef(aFrameState));
7447
0
7448
0
  // Recover state for the containing block - we need to know if
7449
0
  // it has :first-letter or :first-line style applied to it. The
7450
0
  // reason we care is that the internal structure in these cases
7451
0
  // is not the normal structure and requires custom updating
7452
0
  // logic.
7453
0
  nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
7454
0
  bool haveFirstLetterStyle = false;
7455
0
  bool haveFirstLineStyle = false;
7456
0
7457
0
  // In order to shave off some cycles, we only dig up the
7458
0
  // containing block haveFirst* flags if the parent frame where
7459
0
  // the insertion/append is occurring is an inline or block
7460
0
  // container. For other types of containers this isn't relevant.
7461
0
  StyleDisplay parentDisplay = insertion.mParentFrame->GetDisplay();
7462
0
7463
0
  // Examine the insertion.mParentFrame where the insertion is taking
7464
0
  // place. If it's a certain kind of container then some special
7465
0
  // processing is done.
7466
0
  if ((StyleDisplay::Block == parentDisplay) ||
7467
0
      (StyleDisplay::ListItem == parentDisplay) ||
7468
0
      (StyleDisplay::Inline == parentDisplay) ||
7469
0
      (StyleDisplay::InlineBlock == parentDisplay)) {
7470
0
    // Recover the special style flags for the containing block
7471
0
    if (containingBlock) {
7472
0
      haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
7473
0
      haveFirstLineStyle =
7474
0
        ShouldHaveFirstLineStyle(containingBlock->GetContent(),
7475
0
                                 containingBlock->Style());
7476
0
    }
7477
0
7478
0
    if (haveFirstLetterStyle) {
7479
0
      // If our current insertion.mParentFrame is a Letter frame, use its parent as our
7480
0
      // new parent hint
7481
0
      if (insertion.mParentFrame->IsLetterFrame()) {
7482
0
        // If insertion.mParentFrame is out of flow, then we actually want the parent of
7483
0
        // the placeholder frame.
7484
0
        if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7485
0
          nsPlaceholderFrame* placeholderFrame =
7486
0
            insertion.mParentFrame->GetPlaceholderFrame();
7487
0
          NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
7488
0
          insertion.mParentFrame = placeholderFrame->GetParent();
7489
0
        } else {
7490
0
          insertion.mParentFrame = insertion.mParentFrame->GetParent();
7491
0
        }
7492
0
      }
7493
0
7494
0
      // Remove the old letter frames before doing the insertion
7495
0
      RemoveLetterFrames(mPresShell, state.mFloatedItems.containingBlock);
7496
0
7497
0
      // Removing the letterframes messes around with the frame tree, removing
7498
0
      // and creating frames.  We need to reget our prevsibling, parent frame,
7499
0
      // etc.
7500
0
      prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend,
7501
0
                                            &isRangeInsertSafe);
7502
0
7503
0
      // Need check whether a range insert is still safe.
7504
0
      if (!isSingleInsert && !isRangeInsertSafe) {
7505
0
        // Need to recover the letter frames first.
7506
0
        RecoverLetterFrames(state.mFloatedItems.containingBlock);
7507
0
7508
0
        // must fall back to a single ContertInserted for each child in the range
7509
0
        LAYOUT_PHASE_TEMP_EXIT();
7510
0
        IssueSingleInsertNofications(aStartChild, aEndChild, InsertionKind::Sync);
7511
0
        LAYOUT_PHASE_TEMP_REENTER();
7512
0
        return;
7513
0
      }
7514
0
7515
0
      frameType = insertion.mParentFrame->Type();
7516
0
    }
7517
0
  }
7518
0
7519
0
  AutoFrameConstructionItemList items(this);
7520
0
  ParentType parentType = GetParentType(frameType);
7521
0
  FlattenedChildIterator iter(insertion.mContainer);
7522
0
  bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
7523
0
  if (aStartChild->GetPreviousSibling() &&
7524
0
      parentType == eTypeBlock && haveNoXBLChildren) {
7525
0
    // If there's a text node in the normal content list just before the
7526
0
    // new nodes, and it has no frame, make a frame construction item for
7527
0
    // it, because it might need a frame now.  No need to do this if our
7528
0
    // parent type is not block, though, since WipeContainingBlock
7529
0
    // already handles that situation.
7530
0
    AddTextItemIfNeeded(state, insertion, aStartChild->GetPreviousSibling(),
7531
0
                        items);
7532
0
  }
7533
0
7534
0
  if (isSingleInsert) {
7535
0
    AddFrameConstructionItems(state, aStartChild,
7536
0
                              aStartChild->IsRootOfAnonymousSubtree(),
7537
0
                              insertion, items);
7538
0
  } else {
7539
0
    for (nsIContent* child = aStartChild;
7540
0
         child != aEndChild;
7541
0
         child = child->GetNextSibling()){
7542
0
      AddFrameConstructionItems(state, child, false, insertion, items);
7543
0
    }
7544
0
  }
7545
0
7546
0
  if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) {
7547
0
    // If there's a text node in the normal content list just after the
7548
0
    // new nodes, and it has no frame, make a frame construction item for
7549
0
    // it, because it might need a frame now.  No need to do this if our
7550
0
    // parent type is not block, though, since WipeContainingBlock
7551
0
    // already handles that situation.
7552
0
    AddTextItemIfNeeded(state, insertion, aEndChild, items);
7553
0
  }
7554
0
7555
0
  // Perform special check for diddling around with the frames in
7556
0
  // a special inline frame.
7557
0
  // If we're appending before :after content, then we're not really
7558
0
  // appending, so let WipeContainingBlock know that.
7559
0
  LAYOUT_PHASE_TEMP_EXIT();
7560
0
  if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
7561
0
                          isAppend, prevSibling)) {
7562
0
    LAYOUT_PHASE_TEMP_REENTER();
7563
0
    return;
7564
0
  }
7565
0
  LAYOUT_PHASE_TEMP_REENTER();
7566
0
7567
0
  // If the container is a table and a caption will be appended, it needs to be
7568
0
  // put in the table wrapper frame's additional child list.
7569
0
  // We make no attempt here to set flags to indicate whether the list
7570
0
  // will be at the start or end of a block. It doesn't seem worthwhile.
7571
0
  nsFrameItems frameItems, captionItems;
7572
0
  ConstructFramesFromItemList(state, items, insertion.mParentFrame,
7573
0
                              ParentIsWrapperAnonBox(insertion.mParentFrame),
7574
0
                              frameItems);
7575
0
7576
0
  if (frameItems.NotEmpty()) {
7577
0
    for (nsIContent* child = aStartChild;
7578
0
         child != aEndChild;
7579
0
         child = child->GetNextSibling()){
7580
0
      InvalidateCanvasIfNeeded(mPresShell, child);
7581
0
    }
7582
0
7583
0
    if (LayoutFrameType::Table == frameType ||
7584
0
        LayoutFrameType::TableWrapper == frameType) {
7585
0
      PullOutCaptionFrames(frameItems, captionItems);
7586
0
    }
7587
0
  }
7588
0
7589
0
  if (haveFirstLineStyle && insertion.mParentFrame == containingBlock && isAppend) {
7590
0
    // It's possible that the new frame goes into a first-line
7591
0
    // frame. Look at it and see...
7592
0
    AppendFirstLineFrames(state, containingBlock->GetContent(),
7593
0
                          containingBlock, frameItems);
7594
0
  } else if (insertion.mParentFrame->Style()->HasPseudoElementData()) {
7595
0
    CheckForFirstLineInsertion(insertion.mParentFrame, frameItems);
7596
0
    CheckForFirstLineInsertion(insertion.mParentFrame, captionItems);
7597
0
  }
7598
0
7599
0
  // We might have captions; put them into the caption list of the
7600
0
  // table wrapper frame.
7601
0
  if (captionItems.NotEmpty()) {
7602
0
    NS_ASSERTION(LayoutFrameType::Table == frameType ||
7603
0
                 LayoutFrameType::TableWrapper == frameType,
7604
0
                 "parent for caption is not table?");
7605
0
    // We need to determine where to put the caption items; start with the
7606
0
    // the parent frame that has already been determined and get the insertion
7607
0
    // prevsibling of the first caption item.
7608
0
    bool captionIsAppend;
7609
0
    nsIFrame* captionPrevSibling = nullptr;
7610
0
7611
0
    // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
7612
0
    bool ignored;
7613
0
    InsertionPoint captionInsertion(insertion.mParentFrame, insertion.mContainer);
7614
0
    if (isSingleInsert) {
7615
0
      captionPrevSibling =
7616
0
        GetInsertionPrevSibling(&captionInsertion, aStartChild,
7617
0
                                &captionIsAppend, &ignored);
7618
0
    } else {
7619
0
      nsIContent* firstCaption = captionItems.FirstChild()->GetContent();
7620
0
      // It is very important here that we skip the children in
7621
0
      // [aStartChild,aEndChild) when looking for a
7622
0
      // prevsibling.
7623
0
      captionPrevSibling =
7624
0
        GetInsertionPrevSibling(&captionInsertion, firstCaption,
7625
0
                                &captionIsAppend, &ignored,
7626
0
                                aStartChild, aEndChild);
7627
0
    }
7628
0
7629
0
    nsContainerFrame* outerTable = nullptr;
7630
0
    if (GetCaptionAdjustedParent(captionInsertion.mParentFrame,
7631
0
                                 captionItems.FirstChild(),
7632
0
                                 &outerTable)) {
7633
0
      // If the parent is not a table wrapper frame we will try to add frames
7634
0
      // to a named child list that the parent does not honor and the frames
7635
0
      // will get lost.
7636
0
      NS_ASSERTION(outerTable->IsTableWrapperFrame(),
7637
0
                   "Pseudo frame construction failure; "
7638
0
                   "a caption can be only a child of a table wrapper frame");
7639
0
7640
0
      // If the parent of our current prevSibling is different from the frame
7641
0
      // we'll actually use as the parent, then the calculated insertion
7642
0
      // point is now invalid (bug 341382).
7643
0
      if (captionPrevSibling &&
7644
0
          captionPrevSibling->GetParent() != outerTable) {
7645
0
          captionPrevSibling = nullptr;
7646
0
      }
7647
0
      if (captionIsAppend) {
7648
0
        AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7649
0
      } else {
7650
0
        InsertFrames(outerTable, nsIFrame::kCaptionList,
7651
0
                     captionPrevSibling, captionItems);
7652
0
      }
7653
0
    }
7654
0
  }
7655
0
7656
0
  if (frameItems.NotEmpty()) {
7657
0
    // Notify the parent frame
7658
0
    if (isAppend) {
7659
0
      AppendFramesToParent(state, insertion.mParentFrame, frameItems, prevSibling);
7660
0
    } else {
7661
0
      InsertFrames(insertion.mParentFrame, kPrincipalList, prevSibling, frameItems);
7662
0
    }
7663
0
  }
7664
0
7665
0
  if (haveFirstLetterStyle) {
7666
0
    // Recover the letter frames for the containing block when
7667
0
    // it has first-letter style.
7668
0
    RecoverLetterFrames(state.mFloatedItems.containingBlock);
7669
0
  }
7670
0
7671
#ifdef DEBUG
7672
  if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
7673
    printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
7674
    insertion.mParentFrame->List(stdout, 0);
7675
  }
7676
#endif
7677
7678
0
#ifdef ACCESSIBILITY
7679
0
  if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7680
0
    accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
7681
0
  }
7682
0
#endif
7683
0
}
7684
7685
bool
7686
nsCSSFrameConstructor::ContentRemoved(nsIContent* aChild,
7687
                                      nsIContent* aOldNextSibling,
7688
                                      RemoveFlags aFlags)
7689
0
{
7690
0
  MOZ_ASSERT(aChild);
7691
0
  MOZ_ASSERT(!aChild->IsRootOfAnonymousSubtree() || !aOldNextSibling,
7692
0
             "Anonymous roots don't have siblings");
7693
0
  AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ContentRemoved", LAYOUT);
7694
0
  AUTO_PROFILER_TRACING("Frame Construction", "ContentRemoved");
7695
0
  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7696
0
  nsPresContext* presContext = mPresShell->GetPresContext();
7697
0
  MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
7698
0
7699
0
  // We want to detect when the viewport override element stored in the
7700
0
  // prescontext is in the subtree being removed.  Except in fullscreen cases
7701
0
  // (which are handled in Element::UnbindFromTree and do not get stored on the
7702
0
  // prescontext), the override element is always either the root element or a
7703
0
  // <body> child of the root element.  So we can only be removing the stored
7704
0
  // override element if the thing being removed is either the override element
7705
0
  // itself or the root element (which can be a parent of the override element).
7706
0
  if (aChild == presContext->GetViewportScrollStylesOverrideElement() ||
7707
0
      (aChild->IsElement() && !aChild->GetParent())) {
7708
0
    // We might be removing the element that we propagated viewport scrollbar
7709
0
    // styles from.  Recompute those. (This clause covers two of the three
7710
0
    // possible scrollbar-propagation sources: the <body> [as aChild or a
7711
0
    // descendant] and the root node. The other possible scrollbar-propagation
7712
0
    // source is a fullscreen element, and we have code elsewhere to update
7713
0
    // scrollbars after fullscreen elements are removed -- specifically, it's
7714
0
    // part of the fullscreen cleanup code called by Element::UnbindFromTree.
7715
0
    // We don't handle the fullscreen case here, because it doesn't change the
7716
0
    // scrollbar styles override element stored on the prescontext.)
7717
0
    Element* newOverrideElement =
7718
0
      presContext->UpdateViewportScrollStylesOverride();
7719
0
7720
0
    // If aChild is the root, then we don't need to do any reframing of
7721
0
    // newOverrideElement, because we're about to tear down the whole frame tree
7722
0
    // anyway.  And we need to make sure we don't do any such reframing, because
7723
0
    // reframing the <body> can trigger a reframe of the <html> and then reenter
7724
0
    // here.
7725
0
    //
7726
0
    // But if aChild is not the root, and if newOverrideElement is not
7727
0
    // the root and isn't aChild (which it could be if all we're doing
7728
0
    // here is reframing the current override element), it needs
7729
0
    // reframing.  In particular, it used to have a scrollframe
7730
0
    // (because its overflow was not "visible"), but now it will
7731
0
    // propagate its overflow to the viewport, so it should not need a
7732
0
    // scrollframe anymore.
7733
0
    if (aChild->GetParent() && newOverrideElement &&
7734
0
        newOverrideElement->GetParent() && newOverrideElement != aChild) {
7735
0
      LAYOUT_PHASE_TEMP_EXIT();
7736
0
      RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
7737
0
      LAYOUT_PHASE_TEMP_REENTER();
7738
0
    }
7739
0
  }
7740
0
7741
#ifdef DEBUG
7742
  if (gNoisyContentUpdates) {
7743
    printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
7744
           "old-next-sibling=%p\n",
7745
           aChild->GetParent(),
7746
           aChild,
7747
           aOldNextSibling);
7748
    if (gReallyNoisyContentUpdates) {
7749
      aChild->GetParent()->List(stdout, 0);
7750
    }
7751
  }
7752
#endif
7753
7754
0
  nsIFrame* childFrame = aChild->GetPrimaryFrame();
7755
0
  if (!childFrame || childFrame->GetContent() != aChild) {
7756
0
    // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7757
0
    // Remove it once that's fixed.
7758
0
    childFrame = nullptr;
7759
0
  }
7760
0
7761
0
  // If we're removing the root, then make sure to remove things starting at
7762
0
  // the viewport's child instead of the primary frame (which might even be
7763
0
  // null if the root had an XBL binding or display:none, even though the
7764
0
  // frames above it got created).  Detecting removal of a root is a little
7765
0
  // exciting; in particular, having no parent is necessary but NOT sufficient.
7766
0
  // Due to how we process reframes, the content node might not even be in our
7767
0
  // document by now.  So explicitly check whether the viewport's first kid's
7768
0
  // content node is aChild.
7769
0
  //
7770
0
  // FIXME(emilio): I think the "might not be in our document" bit is impossible
7771
0
  // now.
7772
0
  bool isRoot = false;
7773
0
  if (!aChild->GetParent()) {
7774
0
    if (nsIFrame* viewport = GetRootFrame()) {
7775
0
      nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
7776
0
      if (firstChild && firstChild->GetContent() == aChild) {
7777
0
        isRoot = true;
7778
0
        childFrame = firstChild;
7779
0
        NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
7780
0
      }
7781
0
    }
7782
0
  }
7783
0
7784
0
  // We need to be conservative about when to determine whether something has
7785
0
  // display: contents or not because at this point our actual display may be
7786
0
  // different.
7787
0
  //
7788
0
  // Consider the case of:
7789
0
  //
7790
0
  //   <div id="A" style="display: contents"><div id="B"></div></div>
7791
0
  //
7792
0
  // If we reconstruct A because its display changed to "none", we still need to
7793
0
  // cleanup the frame on B, but A's display is now "none", so we can't poke at
7794
0
  // the style of it.
7795
0
  //
7796
0
  // FIXME(emilio, bug 1450366): We can make this faster without adding much
7797
0
  // complexity for the display: none -> other case, which right now
7798
0
  // unnecessarily walks the content tree down.
7799
0
  auto CouldHaveBeenDisplayContents = [aFlags](nsIContent* aContent) -> bool {
7800
0
    return aFlags == REMOVE_FOR_RECONSTRUCTION || IsDisplayContents(aContent);
7801
0
  };
7802
0
7803
0
  if (!childFrame && CouldHaveBeenDisplayContents(aChild)) {
7804
0
    // NOTE(emilio): We may iterate through ::before and ::after here and they
7805
0
    // may be gone after the respective ContentRemoved call. Right now
7806
0
    // StyleChildrenIterator handles that properly, so it's not an issue.
7807
0
    StyleChildrenIterator iter(aChild);
7808
0
    for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
7809
0
      if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(aChild)) {
7810
0
        LAYOUT_PHASE_TEMP_EXIT();
7811
0
        bool didReconstruct =
7812
0
          ContentRemoved(c, nullptr, REMOVE_FOR_RECONSTRUCTION);
7813
0
        LAYOUT_PHASE_TEMP_REENTER();
7814
0
        if (didReconstruct) {
7815
0
          return true;
7816
0
        }
7817
0
      }
7818
0
    }
7819
0
    return false;
7820
0
  }
7821
0
7822
0
7823
0
  if (childFrame) {
7824
0
    InvalidateCanvasIfNeeded(mPresShell, aChild);
7825
0
7826
0
    // See whether we need to remove more than just childFrame
7827
0
    LAYOUT_PHASE_TEMP_EXIT();
7828
0
    if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
7829
0
      LAYOUT_PHASE_TEMP_REENTER();
7830
0
      return true;
7831
0
    }
7832
0
    LAYOUT_PHASE_TEMP_REENTER();
7833
0
7834
0
    // Get the childFrame's parent frame
7835
0
    nsIFrame* parentFrame = childFrame->GetParent();
7836
0
    LayoutFrameType parentType = parentFrame->Type();
7837
0
7838
0
    if (parentType == LayoutFrameType::FrameSet &&
7839
0
        IsSpecialFramesetChild(aChild)) {
7840
0
      // Just reframe the parent, since framesets are weird like that.
7841
0
      LAYOUT_PHASE_TEMP_EXIT();
7842
0
      RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
7843
0
      LAYOUT_PHASE_TEMP_REENTER();
7844
0
      return true;
7845
0
    }
7846
0
7847
0
    // If we're a child of MathML, then we should reframe the MathML content.
7848
0
    // If we're non-MathML, then we would be wrapped in a block so we need to
7849
0
    // check our grandparent in that case.
7850
0
    nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
7851
0
                                         ? parentFrame->GetParent()
7852
0
                                         : parentFrame;
7853
0
    if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
7854
0
      LAYOUT_PHASE_TEMP_EXIT();
7855
0
      RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
7856
0
      LAYOUT_PHASE_TEMP_REENTER();
7857
0
      return true;
7858
0
    }
7859
0
7860
0
    // Undo XUL wrapping if it's no longer needed.
7861
0
    // (If we're in the XUL block-wrapping situation, parentFrame is the
7862
0
    // wrapper frame.)
7863
0
    nsIFrame* grandparentFrame = parentFrame->GetParent();
7864
0
    if (grandparentFrame && grandparentFrame->IsXULBoxFrame() &&
7865
0
        (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
7866
0
        // check if this frame is the only one needing wrapping
7867
0
        aChild == AnyKidsNeedBlockParent(parentFrame->PrincipalChildList().FirstChild()) &&
7868
0
        !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
7869
0
      LAYOUT_PHASE_TEMP_EXIT();
7870
0
      RecreateFramesForContent(grandparentFrame->GetContent(),
7871
0
                               InsertionKind::Async);
7872
0
      LAYOUT_PHASE_TEMP_REENTER();
7873
0
      return true;
7874
0
    }
7875
0
7876
0
#ifdef ACCESSIBILITY
7877
0
    if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
7878
0
      accService->ContentRemoved(mPresShell, aChild);
7879
0
    }
7880
0
#endif
7881
0
7882
0
    // Examine the containing-block for the removed content and see if
7883
0
    // :first-letter style applies.
7884
0
    nsIFrame* inflowChild = childFrame;
7885
0
    if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7886
0
      inflowChild = childFrame->GetPlaceholderFrame();
7887
0
      NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
7888
0
    }
7889
0
    nsContainerFrame* containingBlock =
7890
0
      GetFloatContainingBlock(inflowChild->GetParent());
7891
0
    bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
7892
0
    if (haveFLS) {
7893
0
      // Trap out to special routine that handles adjusting a blocks
7894
0
      // frame tree when first-letter style is present.
7895
#ifdef NOISY_FIRST_LETTER
7896
      printf("ContentRemoved: containingBlock=");
7897
      nsFrame::ListTag(stdout, containingBlock);
7898
      printf(" parentFrame=");
7899
      nsFrame::ListTag(stdout, parentFrame);
7900
      printf(" childFrame=");
7901
      nsFrame::ListTag(stdout, childFrame);
7902
      printf("\n");
7903
#endif
7904
7905
0
      // First update the containing blocks structure by removing the
7906
0
      // existing letter frames. This makes the subsequent logic
7907
0
      // simpler.
7908
0
      RemoveLetterFrames(mPresShell, containingBlock);
7909
0
7910
0
      // Recover childFrame and parentFrame
7911
0
      childFrame = aChild->GetPrimaryFrame();
7912
0
      if (!childFrame || childFrame->GetContent() != aChild) {
7913
0
        // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7914
0
        // Remove it once that's fixed.
7915
0
        return false;
7916
0
      }
7917
0
      parentFrame = childFrame->GetParent();
7918
0
      parentType = parentFrame->Type();
7919
0
7920
#ifdef NOISY_FIRST_LETTER
7921
      printf("  ==> revised parentFrame=");
7922
      nsFrame::ListTag(stdout, parentFrame);
7923
      printf(" childFrame=");
7924
      nsFrame::ListTag(stdout, childFrame);
7925
      printf("\n");
7926
#endif
7927
    }
7928
0
7929
#ifdef DEBUG
7930
    if (gReallyNoisyContentUpdates) {
7931
      printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
7932
      nsFrame::ListTag(stdout, childFrame);
7933
      putchar('\n');
7934
      parentFrame->List(stdout, 0);
7935
    }
7936
#endif
7937
7938
0
    // Notify the parent frame that it should delete the frame
7939
0
    if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7940
0
      childFrame = childFrame->GetPlaceholderFrame();
7941
0
      NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
7942
0
      parentFrame = childFrame->GetParent();
7943
0
    }
7944
0
7945
0
    RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
7946
0
7947
0
    // NOTE(emilio): aChild could be dead here already if it is a ::before or
7948
0
    // ::after pseudo-element (since in that case it was owned by childFrame,
7949
0
    // which we just destroyed).
7950
0
7951
0
    if (isRoot) {
7952
0
      mRootElementFrame = nullptr;
7953
0
      mRootElementStyleFrame = nullptr;
7954
0
      mDocElementContainingBlock = nullptr;
7955
0
      mPageSequenceFrame = nullptr;
7956
0
      mHasRootAbsPosContainingBlock = false;
7957
0
    }
7958
0
7959
0
    if (haveFLS && mRootElementFrame) {
7960
0
      RecoverLetterFrames(containingBlock);
7961
0
    }
7962
0
7963
0
    // If we're just reconstructing frames for the element, then the
7964
0
    // following ContentInserted notification on the element will
7965
0
    // take care of fixing up any adjacent text nodes.  We don't need
7966
0
    // to do this if the table parent type of our parent type is not
7967
0
    // eTypeBlock, though, because in that case the whitespace isn't
7968
0
    // being suppressed due to us anyway.
7969
0
    if (aOldNextSibling && aFlags == REMOVE_CONTENT &&
7970
0
        GetParentType(parentType) == eTypeBlock) {
7971
0
      MOZ_ASSERT(aChild->GetParentNode(),
7972
0
                 "How did we have a sibling without a parent?");
7973
0
      // Adjacent whitespace-only text nodes might have been suppressed if
7974
0
      // this node does not have inline ends. Create frames for them now
7975
0
      // if necessary.
7976
0
      // Reframe any text node just before the node being removed, if there is
7977
0
      // one, and if it's not the last child or the first child. If a whitespace
7978
0
      // textframe was being suppressed and it's now the last child or first
7979
0
      // child then it can stay suppressed since the parent must be a block
7980
0
      // and hence it's adjacent to a block end.
7981
0
      // If aOldNextSibling is null, then the text node before the node being
7982
0
      // removed is the last node, and we don't need to worry about it.
7983
0
      //
7984
0
      // FIXME(emilio): This should probably use the lazy frame construction
7985
0
      // bits if possible instead of reframing it in place.
7986
0
      nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
7987
0
      if (prevSibling && prevSibling->GetPreviousSibling()) {
7988
0
        LAYOUT_PHASE_TEMP_EXIT();
7989
0
        ReframeTextIfNeeded(prevSibling);
7990
0
        LAYOUT_PHASE_TEMP_REENTER();
7991
0
      }
7992
0
      // Reframe any text node just after the node being removed, if there is
7993
0
      // one, and if it's not the last child or the first child.
7994
0
      if (aOldNextSibling->GetNextSibling() &&
7995
0
          aOldNextSibling->GetPreviousSibling()) {
7996
0
        LAYOUT_PHASE_TEMP_EXIT();
7997
0
        ReframeTextIfNeeded(aOldNextSibling);
7998
0
        LAYOUT_PHASE_TEMP_REENTER();
7999
0
      }
8000
0
    }
8001
0
8002
#ifdef DEBUG
8003
    if (gReallyNoisyContentUpdates && parentFrame) {
8004
      printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
8005
      parentFrame->List(stdout, 0);
8006
    }
8007
#endif
8008
  }
8009
0
8010
0
  return false;
8011
0
}
8012
8013
/**
8014
 * This method invalidates the canvas when frames are removed or added for a
8015
 * node that might have its background propagated to the canvas, i.e., a
8016
 * document root node or an HTML BODY which is a child of the root node.
8017
 *
8018
 * @param aFrame a frame for a content node about to be removed or a frame that
8019
 *               was just created for a content node that was inserted.
8020
 */
8021
static void
8022
InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node)
8023
0
{
8024
0
  MOZ_ASSERT(presShell->GetRootFrame(), "What happened here?");
8025
0
  MOZ_ASSERT(presShell->GetPresContext(), "Say what?");
8026
0
8027
0
  //  Note that both in ContentRemoved and ContentInserted the content node
8028
0
  //  will still have the right parent pointer, so looking at that is ok.
8029
0
8030
0
  nsIContent* parent = node->GetParent();
8031
0
  if (parent) {
8032
0
    // Has a parent; might not be what we want
8033
0
    nsIContent* grandParent = parent->GetParent();
8034
0
    if (grandParent) {
8035
0
      // Has a grandparent, so not what we want
8036
0
      return;
8037
0
    }
8038
0
8039
0
    // Check whether it's an HTML body
8040
0
    if (!node->IsHTMLElement(nsGkAtoms::body)) {
8041
0
      return;
8042
0
    }
8043
0
  }
8044
0
8045
0
  // At this point the node has no parent or it's an HTML <body> child of the
8046
0
  // root.  We might not need to invalidate in this case (eg we might be in
8047
0
  // XHTML or something), but chances are we want to.  Play it safe.
8048
0
  // Invalidate the viewport.
8049
0
8050
0
  nsIFrame* rootFrame = presShell->GetRootFrame();
8051
0
  rootFrame->InvalidateFrameSubtree();
8052
0
}
8053
8054
bool
8055
nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
8056
  CharacterData* aContent)
8057
0
{
8058
0
  if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
8059
0
    return false;
8060
0
  }
8061
0
8062
0
  if (mAlwaysCreateFramesForIgnorableWhitespace) {
8063
0
    return false;
8064
0
  }
8065
0
8066
0
  // Text frame may have been suppressed. Disable suppression and signal that a
8067
0
  // flush should be performed. We do this on a document-wide basis so that
8068
0
  // pages that repeatedly query metrics for collapsed-whitespace text nodes
8069
0
  // don't trigger pathological behavior.
8070
0
  mAlwaysCreateFramesForIgnorableWhitespace = true;
8071
0
  Element* root = mDocument->GetRootElement();
8072
0
  if (!root) {
8073
0
    return false;
8074
0
  }
8075
0
8076
0
  RestyleManager()->PostRestyleEvent(
8077
0
    root, nsRestyleHint(0), nsChangeHint_ReconstructFrame);
8078
0
  return true;
8079
0
}
8080
8081
void
8082
nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
8083
                                            const CharacterDataChangeInfo& aInfo)
8084
0
{
8085
0
  AUTO_PROFILER_LABEL("nsCSSFrameConstructor::CharacterDataChanged", LAYOUT);
8086
0
  AUTO_PROFILER_TRACING("Frame Construction", "CharacterDataChanged");
8087
0
  AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
8088
0
8089
0
  if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
8090
0
       !aContent->TextIsOnlyWhitespace()) ||
8091
0
      (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
8092
0
       aContent->TextIsOnlyWhitespace())) {
8093
#ifdef DEBUG
8094
    nsIFrame* frame = aContent->GetPrimaryFrame();
8095
    NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
8096
                 "Bit should never be set on generated content");
8097
#endif
8098
0
    LAYOUT_PHASE_TEMP_EXIT();
8099
0
    RecreateFramesForContent(aContent, InsertionKind::Async);
8100
0
    LAYOUT_PHASE_TEMP_REENTER();
8101
0
    return;
8102
0
  }
8103
0
8104
0
8105
0
  // It's possible the frame whose content changed isn't inserted into the
8106
0
  // frame hierarchy yet, or that there is no frame that maps the content
8107
0
  if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
8108
#if 0
8109
    NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
8110
       ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
8111
        aContent, ContentTag(aContent, 0),
8112
        aSubContent, frame));
8113
#endif
8114
8115
0
    // Special check for text content that is a child of a letter frame.  If
8116
0
    // this happens, we should remove the letter frame, do whatever we're
8117
0
    // planning to do with this notification, then put the letter frame back.
8118
0
    // Note that this is basically what RecreateFramesForContent ends up doing;
8119
0
    // the reason we dont' want to call that here is that our text content
8120
0
    // could be native anonymous, in which case RecreateFramesForContent would
8121
0
    // completely barf on it.  And recreating the non-anonymous ancestor would
8122
0
    // just lead us to come back into this notification (e.g. if quotes or
8123
0
    // counters are involved), leading to a loop.
8124
0
    nsContainerFrame* block = GetFloatContainingBlock(frame);
8125
0
    bool haveFirstLetterStyle = false;
8126
0
    if (block) {
8127
0
      // See if the block has first-letter style applied to it.
8128
0
      haveFirstLetterStyle = HasFirstLetterStyle(block);
8129
0
      if (haveFirstLetterStyle) {
8130
0
        RemoveLetterFrames(mPresShell, block);
8131
0
        // Reget |frame|, since we might have killed it.
8132
0
        // Do we really need to call CharacterDataChanged in this case, though?
8133
0
        frame = aContent->GetPrimaryFrame();
8134
0
        NS_ASSERTION(frame, "Should have frame here!");
8135
0
      }
8136
0
    }
8137
0
8138
0
    // Notify the first frame that maps the content. It will generate a reflow
8139
0
    // command
8140
0
    frame->CharacterDataChanged(aInfo);
8141
0
8142
0
    if (haveFirstLetterStyle) {
8143
0
      RecoverLetterFrames(block);
8144
0
    }
8145
0
  }
8146
0
}
8147
8148
void
8149
nsCSSFrameConstructor::RecalcQuotesAndCounters()
8150
0
{
8151
0
  nsAutoScriptBlocker scriptBlocker;
8152
0
8153
0
  if (mQuotesDirty) {
8154
0
    mQuotesDirty = false;
8155
0
    mQuoteList.RecalcAll();
8156
0
  }
8157
0
8158
0
  if (mCountersDirty) {
8159
0
    mCountersDirty = false;
8160
0
    mCounterManager.RecalcAll();
8161
0
  }
8162
0
8163
0
  NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
8164
0
  NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
8165
0
}
8166
8167
void
8168
nsCSSFrameConstructor::NotifyCounterStylesAreDirty()
8169
0
{
8170
0
  mCounterManager.SetAllDirty();
8171
0
  CountersDirty();
8172
0
}
8173
8174
void
8175
nsCSSFrameConstructor::WillDestroyFrameTree()
8176
0
{
8177
#if defined(DEBUG_dbaron_off)
8178
  mCounterManager.Dump();
8179
#endif
8180
8181
0
  mIsDestroyingFrameTree = true;
8182
0
8183
0
  // Prevent frame tree destruction from being O(N^2)
8184
0
  mQuoteList.Clear();
8185
0
  mCounterManager.Clear();
8186
0
  nsFrameManager::Destroy();
8187
0
}
8188
8189
//STATIC
8190
8191
// XXXbz I'd really like this method to go away. Once we have inline-block and
8192
// I can just use that for sized broken images, that can happen, maybe.
8193
void
8194
nsCSSFrameConstructor::GetAlternateTextFor(Element* aElement,
8195
                                           nsAtom* aTag,
8196
                                           nsAString& aAltText)
8197
0
{
8198
0
  // The "alt" attribute specifies alternate text that is rendered
8199
0
  // when the image can not be displayed.
8200
0
  if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText)) {
8201
0
    return;
8202
0
  }
8203
0
8204
0
  if (nsGkAtoms::input == aTag) {
8205
0
    // If there's no "alt" attribute, and aContent is an input element, then use
8206
0
    // the value of the "value" attribute
8207
0
    if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
8208
0
      return;
8209
0
    }
8210
0
8211
0
    // If there's no "value" attribute either, then use the localized string for
8212
0
    // "Submit" as the alternate text.
8213
0
    nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
8214
0
                                       "Submit", aAltText);
8215
0
  }
8216
0
}
8217
8218
nsIFrame*
8219
nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell*     aPresShell,
8220
                                                       nsPresContext*    aPresContext,
8221
                                                       nsIFrame*         aFrame,
8222
                                                       nsContainerFrame* aParentFrame,
8223
                                                       nsIContent*       aContent,
8224
                                                       ComputedStyle*   aComputedStyle)
8225
0
{
8226
0
  nsTableWrapperFrame* newFrame = NS_NewTableWrapperFrame(aPresShell, aComputedStyle);
8227
0
8228
0
  newFrame->Init(aContent, aParentFrame, aFrame);
8229
0
8230
0
  // Create a continuing inner table frame, and if there's a caption then
8231
0
  // replicate the caption
8232
0
  nsFrameItems  newChildFrames;
8233
0
8234
0
  nsIFrame* childFrame = aFrame->PrincipalChildList().FirstChild();
8235
0
  if (childFrame) {
8236
0
    nsIFrame* continuingTableFrame =
8237
0
      CreateContinuingFrame(aPresContext, childFrame, newFrame);
8238
0
    newChildFrames.AddChild(continuingTableFrame);
8239
0
8240
0
    NS_ASSERTION(!childFrame->GetNextSibling(),"there can be only one inner table frame");
8241
0
  }
8242
0
8243
0
  // Set the table wrapper's initial child list
8244
0
  newFrame->SetInitialChildList(kPrincipalList, newChildFrames);
8245
0
8246
0
  return newFrame;
8247
0
}
8248
8249
nsIFrame*
8250
nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell*     aPresShell,
8251
                                                  nsIFrame*         aFrame,
8252
                                                  nsContainerFrame* aParentFrame,
8253
                                                  nsIContent*       aContent,
8254
                                                  ComputedStyle*   aComputedStyle)
8255
0
{
8256
0
  nsTableFrame* newFrame = NS_NewTableFrame(aPresShell, aComputedStyle);
8257
0
8258
0
  newFrame->Init(aContent, aParentFrame, aFrame);
8259
0
8260
0
  // Replicate any header/footer frames
8261
0
  nsFrameItems  childFrames;
8262
0
  for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
8263
0
    // See if it's a header/footer, possibly wrapped in a scroll frame.
8264
0
    nsTableRowGroupFrame* rowGroupFrame =
8265
0
      static_cast<nsTableRowGroupFrame*>(childFrame);
8266
0
    // If the row group was continued, then don't replicate it.
8267
0
    nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
8268
0
    if (rgNextInFlow) {
8269
0
      rowGroupFrame->SetRepeatable(false);
8270
0
    }
8271
0
    else if (rowGroupFrame->IsRepeatable()) {
8272
0
      // Replicate the header/footer frame.
8273
0
      nsTableRowGroupFrame*   headerFooterFrame;
8274
0
      nsFrameItems            childItems;
8275
0
8276
0
      nsFrameConstructorState state(mPresShell,
8277
0
                                    GetAbsoluteContainingBlock(newFrame, FIXED_POS),
8278
0
                                    GetAbsoluteContainingBlock(newFrame, ABS_POS),
8279
0
                                    nullptr);
8280
0
      state.mCreatingExtraFrames = true;
8281
0
8282
0
      ComputedStyle* const headerFooterComputedStyle = rowGroupFrame->Style();
8283
0
      headerFooterFrame = static_cast<nsTableRowGroupFrame*>
8284
0
                                     (NS_NewTableRowGroupFrame(aPresShell, headerFooterComputedStyle));
8285
0
8286
0
      nsIContent* headerFooter = rowGroupFrame->GetContent();
8287
0
      headerFooterFrame->Init(headerFooter, newFrame, nullptr);
8288
0
8289
0
      nsFrameConstructorSaveState absoluteSaveState;
8290
0
      MakeTablePartAbsoluteContainingBlockIfNeeded(state,
8291
0
                                                   headerFooterComputedStyle->StyleDisplay(),
8292
0
                                                   absoluteSaveState,
8293
0
                                                   headerFooterFrame);
8294
0
8295
0
      ProcessChildren(state, headerFooter, rowGroupFrame->Style(),
8296
0
                      headerFooterFrame, true, childItems, false,
8297
0
                      nullptr);
8298
0
      NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
8299
0
      headerFooterFrame->SetInitialChildList(kPrincipalList, childItems);
8300
0
      headerFooterFrame->SetRepeatable(true);
8301
0
8302
0
      // Table specific initialization
8303
0
      headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
8304
0
8305
0
      // XXX Deal with absolute and fixed frames...
8306
0
      childFrames.AddChild(headerFooterFrame);
8307
0
    }
8308
0
  }
8309
0
8310
0
  // Set the table frame's initial child list
8311
0
  newFrame->SetInitialChildList(kPrincipalList, childFrames);
8312
0
8313
0
  return newFrame;
8314
0
}
8315
8316
nsIFrame*
8317
nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext*    aPresContext,
8318
                                             nsIFrame*         aFrame,
8319
                                             nsContainerFrame* aParentFrame,
8320
                                             bool              aIsFluid)
8321
0
{
8322
0
  nsIPresShell*              shell = aPresContext->PresShell();
8323
0
  ComputedStyle*             computedStyle = aFrame->Style();
8324
0
  nsIFrame*                  newFrame = nullptr;
8325
0
  nsIFrame*                  nextContinuation = aFrame->GetNextContinuation();
8326
0
  nsIFrame*                  nextInFlow = aFrame->GetNextInFlow();
8327
0
8328
0
  // Use the frame type to determine what type of frame to create
8329
0
  LayoutFrameType frameType = aFrame->Type();
8330
0
  nsIContent* content = aFrame->GetContent();
8331
0
8332
0
  NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE,
8333
0
               "why CreateContinuingFrame for a non-splittable frame?");
8334
0
8335
0
  if (LayoutFrameType::Text == frameType) {
8336
0
    newFrame = NS_NewContinuingTextFrame(shell, computedStyle);
8337
0
    newFrame->Init(content, aParentFrame, aFrame);
8338
0
  } else if (LayoutFrameType::Inline == frameType) {
8339
0
    newFrame = NS_NewInlineFrame(shell, computedStyle);
8340
0
    newFrame->Init(content, aParentFrame, aFrame);
8341
0
  } else if (LayoutFrameType::Block == frameType) {
8342
0
    MOZ_ASSERT(!aFrame->IsTableCaption(),
8343
0
               "no support for fragmenting table captions yet");
8344
0
    newFrame = NS_NewBlockFrame(shell, computedStyle);
8345
0
    newFrame->Init(content, aParentFrame, aFrame);
8346
0
#ifdef MOZ_XUL
8347
0
  } else if (LayoutFrameType::XULLabel == frameType) {
8348
0
    newFrame = NS_NewXULLabelFrame(shell, computedStyle);
8349
0
    newFrame->Init(content, aParentFrame, aFrame);
8350
0
#endif
8351
0
  } else if (LayoutFrameType::ColumnSetWrapper == frameType) {
8352
0
    newFrame = NS_NewColumnSetWrapperFrame(shell, computedStyle, nsFrameState(0));
8353
0
    newFrame->Init(content, aParentFrame, aFrame);
8354
0
  } else if (LayoutFrameType::ColumnSet == frameType) {
8355
0
    MOZ_ASSERT(!aFrame->IsTableCaption(),
8356
0
               "no support for fragmenting table captions yet");
8357
0
    newFrame = NS_NewColumnSetFrame(shell, computedStyle, nsFrameState(0));
8358
0
    newFrame->Init(content, aParentFrame, aFrame);
8359
0
  } else if (LayoutFrameType::Page == frameType) {
8360
0
    nsContainerFrame* canvasFrame;
8361
0
    newFrame = ConstructPageFrame(shell, aParentFrame, aFrame, canvasFrame);
8362
0
  } else if (LayoutFrameType::TableWrapper == frameType) {
8363
0
    newFrame =
8364
0
      CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
8365
0
                                      content, computedStyle);
8366
0
8367
0
  } else if (LayoutFrameType::Table == frameType) {
8368
0
    newFrame =
8369
0
      CreateContinuingTableFrame(shell, aFrame, aParentFrame,
8370
0
                                 content, computedStyle);
8371
0
8372
0
  } else if (LayoutFrameType::TableRowGroup == frameType) {
8373
0
    newFrame = NS_NewTableRowGroupFrame(shell, computedStyle);
8374
0
    newFrame->Init(content, aParentFrame, aFrame);
8375
0
    if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8376
0
      nsTableFrame::RegisterPositionedTablePart(newFrame);
8377
0
    }
8378
0
  } else if (LayoutFrameType::TableRow == frameType) {
8379
0
    nsTableRowFrame* rowFrame = NS_NewTableRowFrame(shell, computedStyle);
8380
0
8381
0
    rowFrame->Init(content, aParentFrame, aFrame);
8382
0
    if (rowFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8383
0
      nsTableFrame::RegisterPositionedTablePart(rowFrame);
8384
0
    }
8385
0
8386
0
    // Create a continuing frame for each table cell frame
8387
0
    nsFrameItems  newChildList;
8388
0
    nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
8389
0
    while (cellFrame) {
8390
0
      // See if it's a table cell frame
8391
0
      if (IsTableCell(cellFrame->Type())) {
8392
0
        nsIFrame* continuingCellFrame =
8393
0
          CreateContinuingFrame(aPresContext, cellFrame, rowFrame);
8394
0
        newChildList.AddChild(continuingCellFrame);
8395
0
      }
8396
0
      cellFrame = cellFrame->GetNextSibling();
8397
0
    }
8398
0
8399
0
    rowFrame->SetInitialChildList(kPrincipalList, newChildList);
8400
0
    newFrame = rowFrame;
8401
0
8402
0
  } else if (IsTableCell(frameType)) {
8403
0
    // Warning: If you change this and add a wrapper frame around table cell
8404
0
    // frames, make sure Bug 368554 doesn't regress!
8405
0
    // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
8406
0
    nsTableFrame* tableFrame =
8407
0
      static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
8408
0
    nsTableCellFrame* cellFrame =
8409
0
      NS_NewTableCellFrame(shell, computedStyle, tableFrame);
8410
0
8411
0
    cellFrame->Init(content, aParentFrame, aFrame);
8412
0
    if (cellFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
8413
0
      nsTableFrame::RegisterPositionedTablePart(cellFrame);
8414
0
    }
8415
0
8416
0
    // Create a continuing area frame
8417
0
    nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
8418
0
    nsIFrame* continuingBlockFrame =
8419
0
      CreateContinuingFrame(aPresContext, blockFrame,
8420
0
                            static_cast<nsContainerFrame*>(cellFrame));
8421
0
8422
0
    SetInitialSingleChild(cellFrame, continuingBlockFrame);
8423
0
    newFrame = cellFrame;
8424
0
  } else if (LayoutFrameType::Line == frameType) {
8425
0
    newFrame = NS_NewFirstLineFrame(shell, computedStyle);
8426
0
    newFrame->Init(content, aParentFrame, aFrame);
8427
0
  } else if (LayoutFrameType::Letter == frameType) {
8428
0
    newFrame = NS_NewFirstLetterFrame(shell, computedStyle);
8429
0
    newFrame->Init(content, aParentFrame, aFrame);
8430
0
  } else if (LayoutFrameType::Image == frameType) {
8431
0
    auto* imageFrame = static_cast<nsImageFrame*>(aFrame);
8432
0
    newFrame = imageFrame->CreateContinuingFrame(shell, computedStyle);
8433
0
    newFrame->Init(content, aParentFrame, aFrame);
8434
0
  } else if (LayoutFrameType::ImageControl == frameType) {
8435
0
    newFrame = NS_NewImageControlFrame(shell, computedStyle);
8436
0
    newFrame->Init(content, aParentFrame, aFrame);
8437
0
  } else if (LayoutFrameType::FieldSet == frameType) {
8438
0
    nsContainerFrame* fieldset = NS_NewFieldSetFrame(shell, computedStyle);
8439
0
8440
0
    fieldset->Init(content, aParentFrame, aFrame);
8441
0
8442
0
    // Create a continuing area frame
8443
0
    // XXXbz we really shouldn't have to do this by hand!
8444
0
    nsContainerFrame* blockFrame = GetFieldSetBlockFrame(aFrame);
8445
0
    if (blockFrame) {
8446
0
      nsIFrame* continuingBlockFrame =
8447
0
        CreateContinuingFrame(aPresContext, blockFrame, fieldset);
8448
0
      // Set the fieldset's initial child list
8449
0
      SetInitialSingleChild(fieldset, continuingBlockFrame);
8450
0
    } else {
8451
0
      MOZ_ASSERT(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
8452
0
                 "FieldSet block may only be null for overflow containers");
8453
0
    }
8454
0
    newFrame = fieldset;
8455
0
  } else if (LayoutFrameType::Legend == frameType) {
8456
0
    newFrame = NS_NewLegendFrame(shell, computedStyle);
8457
0
    newFrame->Init(content, aParentFrame, aFrame);
8458
0
  } else if (LayoutFrameType::FlexContainer == frameType) {
8459
0
    newFrame = NS_NewFlexContainerFrame(shell, computedStyle);
8460
0
    newFrame->Init(content, aParentFrame, aFrame);
8461
0
  } else if (LayoutFrameType::GridContainer == frameType) {
8462
0
    newFrame = NS_NewGridContainerFrame(shell, computedStyle);
8463
0
    newFrame->Init(content, aParentFrame, aFrame);
8464
0
  } else if (LayoutFrameType::Ruby == frameType) {
8465
0
    newFrame = NS_NewRubyFrame(shell, computedStyle);
8466
0
    newFrame->Init(content, aParentFrame, aFrame);
8467
0
  } else if (LayoutFrameType::RubyBaseContainer == frameType) {
8468
0
    newFrame = NS_NewRubyBaseContainerFrame(shell, computedStyle);
8469
0
    newFrame->Init(content, aParentFrame, aFrame);
8470
0
  } else if (LayoutFrameType::RubyTextContainer == frameType) {
8471
0
    newFrame = NS_NewRubyTextContainerFrame(shell, computedStyle);
8472
0
    newFrame->Init(content, aParentFrame, aFrame);
8473
0
  } else if (LayoutFrameType::Details == frameType) {
8474
0
    newFrame = NS_NewDetailsFrame(shell, computedStyle);
8475
0
    newFrame->Init(content, aParentFrame, aFrame);
8476
0
  } else {
8477
0
    MOZ_CRASH("unexpected frame type");
8478
0
  }
8479
0
8480
0
  // Init() set newFrame to be a fluid continuation of aFrame.
8481
0
  // If we want a non-fluid continuation, we need to call SetPrevContinuation()
8482
0
  // to reset NS_FRAME_IS_FLUID_CONTINUATION.
8483
0
  if (!aIsFluid) {
8484
0
    newFrame->SetPrevContinuation(aFrame);
8485
0
  }
8486
0
8487
0
  // A continuation of generated content is also generated content
8488
0
  if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
8489
0
    newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
8490
0
  }
8491
0
8492
0
  // A continuation of nsIAnonymousContentCreator content is also
8493
0
  // nsIAnonymousContentCreator created content
8494
0
  if (aFrame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
8495
0
    newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
8496
0
  }
8497
0
8498
0
  // A continuation of an out-of-flow is also an out-of-flow
8499
0
  if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8500
0
    newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
8501
0
  }
8502
0
8503
0
  if (nextInFlow) {
8504
0
    nextInFlow->SetPrevInFlow(newFrame);
8505
0
    newFrame->SetNextInFlow(nextInFlow);
8506
0
  } else if (nextContinuation) {
8507
0
    nextContinuation->SetPrevContinuation(newFrame);
8508
0
    newFrame->SetNextContinuation(nextContinuation);
8509
0
  }
8510
0
8511
0
  MOZ_ASSERT(!newFrame->GetNextSibling(), "unexpected sibling");
8512
0
  return newFrame;
8513
0
}
8514
8515
nsresult
8516
nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
8517
0
{
8518
0
  // Now deal with fixed-pos things....  They should appear on all pages,
8519
0
  // so we want to move over the placeholders when processing the child
8520
0
  // of the pageContentFrame.
8521
0
8522
0
  nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
8523
0
  if (!prevPageContentFrame) {
8524
0
    return NS_OK;
8525
0
  }
8526
0
  nsContainerFrame* canvasFrame =
8527
0
    do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
8528
0
  nsIFrame* prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
8529
0
  if (!canvasFrame || !prevCanvasFrame) {
8530
0
    // document's root element frame missing
8531
0
    return NS_ERROR_UNEXPECTED;
8532
0
  }
8533
0
8534
0
  nsFrameItems fixedPlaceholders;
8535
0
  nsIFrame* firstFixed = prevPageContentFrame->GetChildList(nsIFrame::kFixedList).FirstChild();
8536
0
  if (!firstFixed) {
8537
0
    return NS_OK;
8538
0
  }
8539
0
8540
0
  // Don't allow abs-pos descendants of the fixed content to escape the content.
8541
0
  // This should not normally be possible (because fixed-pos elements should
8542
0
  // be absolute containers) but fixed-pos tables currently aren't abs-pos
8543
0
  // containers.
8544
0
  nsFrameConstructorState state(mPresShell,
8545
0
                                aParentFrame,
8546
0
                                nullptr,
8547
0
                                mRootElementFrame);
8548
0
  state.mCreatingExtraFrames = true;
8549
0
8550
0
  // We can't use an ancestor filter here, because we're not going to
8551
0
  // be usefully recurring down the tree.  This means that other
8552
0
  // places in frame construction can't assume a filter is
8553
0
  // initialized!
8554
0
8555
0
  // Iterate across fixed frames and replicate each whose placeholder is a
8556
0
  // descendant of aFrame. (We don't want to explicitly copy placeholders that
8557
0
  // are within fixed frames, because that would cause duplicates on the new
8558
0
  // page - bug 389619)
8559
0
  for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
8560
0
    nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
8561
0
    if (prevPlaceholder &&
8562
0
        nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
8563
0
      // We want to use the same style as the primary style frame for
8564
0
      // our content
8565
0
      nsIContent* content = fixed->GetContent();
8566
0
      ComputedStyle* computedStyle =
8567
0
        nsLayoutUtils::GetStyleFrame(content)->Style();
8568
0
      AutoFrameConstructionItemList items(this);
8569
0
      AddFrameConstructionItemsInternal(state, content, canvasFrame,
8570
0
                                        true,
8571
0
                                        computedStyle,
8572
0
                                        ITEM_ALLOW_XBL_BASE |
8573
0
                                          ITEM_ALLOW_PAGE_BREAK,
8574
0
                                        items);
8575
0
      ConstructFramesFromItemList(state, items, canvasFrame,
8576
0
                                  /* aParentIsWrapperAnonBox = */ false,
8577
0
                                  fixedPlaceholders);
8578
0
    }
8579
0
  }
8580
0
8581
0
  // Add the placeholders to our primary child list.
8582
0
  // XXXbz this is a little screwed up, since the fixed frames will have
8583
0
  // broken auto-positioning. Oh, well.
8584
0
  NS_ASSERTION(!canvasFrame->PrincipalChildList().FirstChild(),
8585
0
               "leaking frames; doc root continuation must be empty");
8586
0
  canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders);
8587
0
  return NS_OK;
8588
0
}
8589
8590
nsCSSFrameConstructor::InsertionPoint
8591
nsCSSFrameConstructor::GetInsertionPoint(nsIContent* aChild)
8592
0
{
8593
0
  MOZ_ASSERT(aChild);
8594
0
  nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
8595
0
  if (!insertionElement) {
8596
0
    // The element doesn't belong in the flattened tree, and thus we don't want
8597
0
    // to render it.
8598
0
    return { };
8599
0
  }
8600
0
8601
0
  return { GetContentInsertionFrameFor(insertionElement), insertionElement };
8602
0
}
8603
8604
// Capture state for the frame tree rooted at the frame associated with the
8605
// content object, aContent
8606
void
8607
nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
8608
                                               nsILayoutHistoryState* aHistoryState)
8609
0
{
8610
0
  if (!aHistoryState) {
8611
0
    return;
8612
0
  }
8613
0
  nsIFrame* frame = aContent->GetPrimaryFrame();
8614
0
  if (frame == mRootElementFrame) {
8615
0
    frame = mRootElementFrame ?
8616
0
      GetAbsoluteContainingBlock(mRootElementFrame, FIXED_POS) :
8617
0
      GetRootFrame();
8618
0
  }
8619
0
  for ( ; frame;
8620
0
        frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
8621
0
    CaptureFrameState(frame, aHistoryState);
8622
0
  }
8623
0
}
8624
8625
8626
static bool
8627
IsWhitespaceFrame(nsIFrame* aFrame)
8628
0
{
8629
0
  MOZ_ASSERT(aFrame, "invalid argument");
8630
0
  return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
8631
0
}
8632
8633
static nsIFrame*
8634
FindFirstNonWhitespaceChild(nsIFrame* aParentFrame)
8635
0
{
8636
0
  nsIFrame* f = aParentFrame->PrincipalChildList().FirstChild();
8637
0
  while (f && IsWhitespaceFrame(f)) {
8638
0
    f = f->GetNextSibling();
8639
0
  }
8640
0
  return f;
8641
0
}
8642
8643
static nsIFrame*
8644
FindNextNonWhitespaceSibling(nsIFrame* aFrame)
8645
0
{
8646
0
  nsIFrame* f = aFrame;
8647
0
  do {
8648
0
    f = f->GetNextSibling();
8649
0
  } while (f && IsWhitespaceFrame(f));
8650
0
  return f;
8651
0
}
8652
8653
static nsIFrame*
8654
FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
8655
0
{
8656
0
  nsIFrame* f = aFrame;
8657
0
  do {
8658
0
    f = f->GetPrevSibling();
8659
0
  } while (f && IsWhitespaceFrame(f));
8660
0
  return f;
8661
0
}
8662
8663
bool
8664
nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
8665
0
{
8666
0
  MOZ_ASSERT(aFrame, "Must have a frame");
8667
0
  MOZ_ASSERT(aFrame->GetParent(), "Frame shouldn't be root");
8668
0
  MOZ_ASSERT(aFrame == aFrame->FirstContinuation(),
8669
0
             "aFrame not the result of GetPrimaryFrame()?");
8670
0
8671
0
  if (IsFramePartOfIBSplit(aFrame)) {
8672
0
    // The removal functions can't handle removal of an {ib} split directly; we
8673
0
    // need to rebuild the containing block.
8674
#ifdef DEBUG
8675
    if (gNoisyContentUpdates) {
8676
      printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8677
             "frame=");
8678
      nsFrame::ListTag(stdout, aFrame);
8679
      printf(" is ib-split\n");
8680
    }
8681
#endif
8682
8683
0
    ReframeContainingBlock(aFrame);
8684
0
    return true;
8685
0
  }
8686
0
8687
0
  nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
8688
0
  if (insertionFrame && insertionFrame->IsLegendFrame() &&
8689
0
      aFrame->GetParent()->IsFieldSetFrame()) {
8690
0
    RecreateFramesForContent(aFrame->GetParent()->GetContent(),
8691
0
                             InsertionKind::Async);
8692
0
    return true;
8693
0
  }
8694
0
8695
0
  nsIFrame* inFlowFrame =
8696
0
    (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
8697
0
      aFrame->GetPlaceholderFrame() : aFrame;
8698
0
  MOZ_ASSERT(inFlowFrame, "How did that happen?");
8699
0
  MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
8700
0
             "placeholder for primary frame has previous continuations?");
8701
0
  nsIFrame* parent = inFlowFrame->GetParent();
8702
0
8703
0
  if (parent && parent->IsDetailsFrame()) {
8704
0
    HTMLSummaryElement* summary =
8705
0
      HTMLSummaryElement::FromNode(aFrame->GetContent());
8706
0
    DetailsFrame* detailsFrame = static_cast<DetailsFrame*>(parent);
8707
0
8708
0
    // Unlike adding summary element cases, we need to check children of the
8709
0
    // parent details frame since at this moment the summary element has been
8710
0
    // already removed from the parent details element's child list.
8711
0
    if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) {
8712
0
      // When removing a summary, we should reframe the parent details frame to
8713
0
      // ensure that another summary is used or the default summary is
8714
0
      // generated.
8715
0
      RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8716
0
      return true;
8717
0
    }
8718
0
  }
8719
0
8720
0
  // Now check for possibly needing to reconstruct due to a pseudo parent
8721
0
  // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
8722
0
  // need to be checked here, since all other types of parent will be catched
8723
0
  // by "Check ruby containers" section below.
8724
0
  if (IsTableOrRubyPseudo(parent)) {
8725
0
    if (FindFirstNonWhitespaceChild(parent) == inFlowFrame ||
8726
0
        !FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()) ||
8727
0
        // If it is a whitespace, and is the only child of the parent, the
8728
0
        // pseudo parent was created for the space, and should now be removed.
8729
0
        (IsWhitespaceFrame(aFrame) &&
8730
0
         parent->PrincipalChildList().OnlyChild()) ||
8731
0
        // If we're a table-column-group, then the OnlyChild check above is
8732
0
        // not going to catch cases when we're the first child.
8733
0
        (inFlowFrame->IsTableColGroupFrame() &&
8734
0
         parent->GetChildList(nsIFrame::kColGroupList).FirstChild() == inFlowFrame) ||
8735
0
        // Similar if we're a table-caption.
8736
0
        (inFlowFrame->IsTableCaption() &&
8737
0
         parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
8738
0
      RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8739
0
      return true;
8740
0
    }
8741
0
  }
8742
0
8743
0
  // Might need to reconstruct things if this frame's nextSibling is a table
8744
0
  // or ruby pseudo, since removal of this frame might mean that this pseudo
8745
0
  // needs to get merged with the frame's prevSibling if that's also a table
8746
0
  // or ruby pseudo.
8747
0
  nsIFrame* nextSibling =
8748
0
    FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
8749
0
  NS_ASSERTION(!IsTableOrRubyPseudo(inFlowFrame), "Shouldn't happen here");
8750
0
  // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
8751
0
  // need to be checked here, since all other types of such frames will have
8752
0
  // a ruby container parent, and be catched by "Check ruby containers" below.
8753
0
  if (nextSibling && IsTableOrRubyPseudo(nextSibling)) {
8754
0
    nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
8755
0
    if (prevSibling && IsTableOrRubyPseudo(prevSibling)) {
8756
#ifdef DEBUG
8757
      if (gNoisyContentUpdates) {
8758
        printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8759
               "frame=");
8760
        nsFrame::ListTag(stdout, aFrame);
8761
        printf(" has a table pseudo next sibling of different type and a "
8762
               "table pseudo prevsibling\n");
8763
      }
8764
#endif
8765
      // Good enough to recreate frames for aFrame's parent's content; even if
8766
0
      // aFrame's parent is a pseudo, that'll be the right content node.
8767
0
      RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8768
0
      return true;
8769
0
    }
8770
0
  }
8771
0
8772
0
  // Check ruby containers
8773
0
  LayoutFrameType parentType = parent->Type();
8774
0
  if (parentType == LayoutFrameType::Ruby ||
8775
0
      RubyUtils::IsRubyContainerBox(parentType)) {
8776
0
    // In ruby containers, pseudo frames may be created from
8777
0
    // whitespaces or even nothing. There are two cases we actually
8778
0
    // need to handle here, but hard to check exactly:
8779
0
    // 1. Status of spaces beside the frame may vary, and related
8780
0
    //    frames may be constructed or destroyed accordingly.
8781
0
    // 2. The type of the first child of a ruby frame determines
8782
0
    //    whether a pseudo ruby base container should exist.
8783
0
    RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8784
0
    return true;
8785
0
  }
8786
0
8787
0
  // Might need to reconstruct things if the removed frame's nextSibling is an
8788
0
  // anonymous flex item.  The removed frame might've been what divided two
8789
0
  // runs of inline content into two anonymous flex items, which would now
8790
0
  // need to be merged.
8791
0
  // NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
8792
0
  // we're only interested in anonymous flex items here, and those can never
8793
0
  // be adjacent to whitespace, since they absorb contiguous runs of inline
8794
0
  // non-replaced content (including whitespace).
8795
0
  if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
8796
0
    AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
8797
#ifdef DEBUG
8798
    if (gNoisyContentUpdates) {
8799
      printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8800
             "frame=");
8801
      nsFrame::ListTag(stdout, aFrame);
8802
      printf(" has an anonymous flex item as its next sibling\n");
8803
    }
8804
#endif // DEBUG
8805
    // Recreate frames for the flex container (the removed frame's parent)
8806
0
    RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8807
0
    return true;
8808
0
  }
8809
0
8810
0
  // Might need to reconstruct things if the removed frame's nextSibling is
8811
0
  // null and its parent is an anonymous flex item. (This might be the last
8812
0
  // remaining child of that anonymous flex item, which can then go away.)
8813
0
  if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
8814
0
    AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
8815
#ifdef DEBUG
8816
    if (gNoisyContentUpdates) {
8817
      printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8818
             "frame=");
8819
      nsFrame::ListTag(stdout, aFrame);
8820
      printf(" has an anonymous flex item as its parent\n");
8821
    }
8822
#endif // DEBUG
8823
    // Recreate frames for the flex container (the removed frame's grandparent)
8824
0
    RecreateFramesForContent(parent->GetParent()->GetContent(),
8825
0
                             InsertionKind::Async);
8826
0
    return true;
8827
0
  }
8828
0
8829
0
#ifdef MOZ_XUL
8830
0
  if (aFrame->IsPopupSetFrame()) {
8831
0
    nsIPopupContainer* popupContainer =
8832
0
      nsIPopupContainer::GetPopupContainer(mPresShell);
8833
0
    if (popupContainer && popupContainer->GetPopupSetFrame() == aFrame) {
8834
0
      ReconstructDocElementHierarchy(InsertionKind::Async);
8835
0
      return true;
8836
0
    }
8837
0
  }
8838
0
#endif
8839
0
8840
0
  // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
8841
0
  // a non-fluid continuation, i.e. it was split by bidi resolution
8842
0
  if (!inFlowFrame->GetPrevSibling() &&
8843
0
      !inFlowFrame->GetNextSibling() &&
8844
0
      ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
8845
0
       (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
8846
0
    RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
8847
0
    return true;
8848
0
  }
8849
0
8850
0
  // We might still need to reconstruct things if the parent of inFlowFrame is
8851
0
  // ib-split, since in that case the removal of aFrame might affect the
8852
0
  // splitting of its parent.
8853
0
  if (!IsFramePartOfIBSplit(parent)) {
8854
0
    return false;
8855
0
  }
8856
0
8857
0
  // If inFlowFrame is not the only in-flow child of |parent|, then removing
8858
0
  // it will change nothing about the {ib} split.
8859
0
  if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
8860
0
      inFlowFrame->LastContinuation()->GetNextSibling()) {
8861
0
    return false;
8862
0
  }
8863
0
8864
0
  // If the parent is the first or last part of the {ib} split, then
8865
0
  // removing one of its kids will have no effect on the splitting.
8866
0
  // Get the first continuation up front so we don't have to do it twice.
8867
0
  nsIFrame* parentFirstContinuation = parent->FirstContinuation();
8868
0
  if (!GetIBSplitSibling(parentFirstContinuation) ||
8869
0
      !GetIBSplitPrevSibling(parentFirstContinuation)) {
8870
0
    return false;
8871
0
  }
8872
0
8873
#ifdef DEBUG
8874
  if (gNoisyContentUpdates) {
8875
    printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8876
           "frame=");
8877
    nsFrame::ListTag(stdout, parent);
8878
    printf(" is ib-split\n");
8879
  }
8880
#endif
8881
8882
0
  ReframeContainingBlock(parent);
8883
0
  return true;
8884
0
}
8885
8886
void
8887
nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent)
8888
0
{
8889
0
  nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
8890
0
8891
0
  // It's possible that this warning could fire if some other style change
8892
0
  // simultaneously changes the 'display' of the element and makes it no
8893
0
  // longer be a table cell.
8894
0
  NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!");
8895
0
8896
0
  if (cellFrame) {
8897
0
    cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
8898
0
  }
8899
0
}
8900
8901
static nsIContent*
8902
GetTopmostMathMLElement(nsIContent* aMathMLContent)
8903
0
{
8904
0
  MOZ_ASSERT(aMathMLContent->IsMathMLElement());
8905
0
  MOZ_ASSERT(aMathMLContent->GetPrimaryFrame());
8906
0
  MOZ_ASSERT(aMathMLContent->GetPrimaryFrame()->IsFrameOfType(nsIFrame::eMathML));
8907
0
  nsIContent* root = aMathMLContent;
8908
0
8909
0
  for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent();
8910
0
       parent;
8911
0
       parent = parent->GetFlattenedTreeParent()) {
8912
0
    nsIFrame* frame = parent->GetPrimaryFrame();
8913
0
    if (!frame || !frame->IsFrameOfType(nsIFrame::eMathML)) {
8914
0
      break;
8915
0
    }
8916
0
    root = parent;
8917
0
  }
8918
0
8919
0
  return root;
8920
0
}
8921
8922
void
8923
nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
8924
                                                InsertionKind aInsertionKind)
8925
0
{
8926
0
  MOZ_ASSERT(aContent);
8927
0
8928
0
  // If there is no document, we don't want to recreate frames for it.  (You
8929
0
  // shouldn't generally be giving this method content without a document
8930
0
  // anyway).
8931
0
  // Rebuilding the frame tree can have bad effects, especially if it's the
8932
0
  // frame tree for chrome (see bug 157322).
8933
0
  if (NS_WARN_IF(!aContent->GetComposedDoc())) {
8934
0
    return;
8935
0
  }
8936
0
8937
0
  // Is the frame ib-split? If so, we need to reframe the containing
8938
0
  // block *here*, rather than trying to remove and re-insert the
8939
0
  // content (which would otherwise result in *two* nested reframe
8940
0
  // containing block from ContentRemoved() and ContentInserted(),
8941
0
  // below!).  We'd really like to optimize away one of those
8942
0
  // containing block reframes, hence the code here.
8943
0
8944
0
  nsIFrame* frame = aContent->GetPrimaryFrame();
8945
0
  if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
8946
0
    // Reframe the topmost MathML element to prevent exponential blowup
8947
0
    // (see bug 397518).
8948
0
    aContent = GetTopmostMathMLElement(aContent);
8949
0
    frame = aContent->GetPrimaryFrame();
8950
0
  }
8951
0
8952
0
  if (frame) {
8953
0
    nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
8954
0
    if (nonGeneratedAncestor->GetContent() != aContent) {
8955
0
      return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
8956
0
                                      InsertionKind::Async);
8957
0
    }
8958
0
8959
0
    if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
8960
0
      // Recreate the frames for the entire nsIAnonymousContentCreator tree
8961
0
      // since |frame| or one of its descendants may need an ComputedStyle
8962
0
      // that associates it to a CSS pseudo-element, and only the
8963
0
      // nsIAnonymousContentCreator that created this content knows how to make
8964
0
      // that happen.
8965
0
      //
8966
0
      // FIXME(emilio, bug 1465511): This is no longer true, but need to figure
8967
0
      // out what editor is doing.
8968
0
      nsIAnonymousContentCreator* acc = nullptr;
8969
0
      nsIFrame* ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
8970
0
      while (!(acc = do_QueryFrame(ancestor))) {
8971
0
        ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(ancestor);
8972
0
      }
8973
0
      NS_ASSERTION(acc, "Where is the nsIAnonymousContentCreator? We may fail "
8974
0
                        "to recreate its content correctly");
8975
0
      NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
8976
0
                   "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
8977
0
      return RecreateFramesForContent(ancestor->GetContent(),
8978
0
                                      InsertionKind::Async);
8979
0
    }
8980
0
8981
0
    nsIFrame* parent = frame->GetParent();
8982
0
    nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
8983
0
    // If the parent frame is a leaf then the subsequent insert will fail to
8984
0
    // create a frame, so we need to recreate the parent content. This happens
8985
0
    // with native anonymous content from the editor.
8986
0
    if (parent && parent->IsLeaf() && parentContent &&
8987
0
        parentContent != aContent) {
8988
0
      return RecreateFramesForContent(parentContent, InsertionKind::Async);
8989
0
    }
8990
0
  }
8991
0
8992
0
  if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
8993
0
    return;
8994
0
  }
8995
0
8996
0
  MOZ_ASSERT(aContent->GetParentNode());
8997
0
8998
0
  // Before removing the frames associated with the content object,
8999
0
  // ask them to save their state onto a temporary state object.
9000
0
  CaptureStateForFramesOf(aContent, mTempFrameTreeState);
9001
0
9002
0
  // Remove the frames associated with the content object.
9003
0
  nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ?
9004
0
    nullptr : aContent->GetNextSibling();
9005
0
  bool didReconstruct =
9006
0
    ContentRemoved(aContent, nextSibling, REMOVE_FOR_RECONSTRUCTION);
9007
0
9008
0
  if (!didReconstruct) {
9009
0
    if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
9010
0
      // FIXME(emilio, bug 1397239): There's nothing removing the frame state
9011
0
      // for elements that go away before we come back to the frame
9012
0
      // constructor.
9013
0
      //
9014
0
      // Also, it'd be nice to just use the `ContentRangeInserted` path for
9015
0
      // both elements and non-elements, but we need to make lazy frame
9016
0
      // construction to apply to all elements first.
9017
0
      RestyleManager()->PostRestyleEvent(aContent->AsElement(),
9018
0
                                         nsRestyleHint(0),
9019
0
                                         nsChangeHint_ReconstructFrame);
9020
0
    } else {
9021
0
      // Now, recreate the frames associated with this content object. If
9022
0
      // ContentRemoved triggered reconstruction, then we don't need to do this
9023
0
      // because the frames will already have been built.
9024
0
      ContentRangeInserted(aContent,
9025
0
                           aContent->GetNextSibling(),
9026
0
                           mTempFrameTreeState,
9027
0
                           aInsertionKind);
9028
0
    }
9029
0
  }
9030
0
}
9031
9032
bool
9033
nsCSSFrameConstructor::DestroyFramesFor(Element* aElement)
9034
0
{
9035
0
  MOZ_ASSERT(aElement && aElement->GetParentNode());
9036
0
9037
0
  nsIContent* nextSibling =
9038
0
    aElement->IsRootOfAnonymousSubtree() ? nullptr : aElement->GetNextSibling();
9039
0
9040
0
  CaptureStateForFramesOf(aElement, mTempFrameTreeState);
9041
0
  return ContentRemoved(aElement,
9042
0
                        nextSibling,
9043
0
                        REMOVE_FOR_RECONSTRUCTION);
9044
0
}
9045
9046
//////////////////////////////////////////////////////////////////////
9047
9048
// Block frame construction code
9049
9050
already_AddRefed<ComputedStyle>
9051
nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
9052
                                           ComputedStyle* aComputedStyle)
9053
0
{
9054
0
  if (aContent) {
9055
0
    return mPresShell->StyleSet()->
9056
0
      ResolvePseudoElementStyle(aContent->AsElement(),
9057
0
                                CSSPseudoElementType::firstLetter,
9058
0
                                aComputedStyle,
9059
0
                                nullptr);
9060
0
  }
9061
0
  return nullptr;
9062
0
}
9063
9064
already_AddRefed<ComputedStyle>
9065
nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
9066
                                         ComputedStyle* aComputedStyle)
9067
0
{
9068
0
  if (aContent) {
9069
0
    return mPresShell->StyleSet()->
9070
0
      ResolvePseudoElementStyle(aContent->AsElement(),
9071
0
                                CSSPseudoElementType::firstLine,
9072
0
                                aComputedStyle,
9073
0
                                nullptr);
9074
0
  }
9075
0
  return nullptr;
9076
0
}
9077
9078
// Predicate to see if a given content (block element) has
9079
// first-letter style applied to it.
9080
bool
9081
nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
9082
                                                  ComputedStyle* aComputedStyle)
9083
0
{
9084
0
  return nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
9085
0
                                       CSSPseudoElementType::firstLetter,
9086
0
                                       mPresShell->GetPresContext());
9087
0
}
9088
9089
bool
9090
nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame)
9091
0
{
9092
0
  MOZ_ASSERT(aBlockFrame, "Need a frame");
9093
0
  NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
9094
0
               "Not a block frame?");
9095
0
9096
0
  return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0;
9097
0
}
9098
9099
bool
9100
nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
9101
                                                ComputedStyle* aComputedStyle)
9102
0
{
9103
0
  bool hasFirstLine =
9104
0
    nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
9105
0
                                  CSSPseudoElementType::firstLine,
9106
0
                                  mPresShell->GetPresContext());
9107
0
  return hasFirstLine && !aContent->IsHTMLElement(nsGkAtoms::fieldset);
9108
0
}
9109
9110
void
9111
nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent* aContent,
9112
                                                   ComputedStyle* aComputedStyle,
9113
                                                   bool* aHaveFirstLetterStyle,
9114
                                                   bool* aHaveFirstLineStyle)
9115
0
{
9116
0
  *aHaveFirstLetterStyle =
9117
0
    ShouldHaveFirstLetterStyle(aContent, aComputedStyle);
9118
0
  *aHaveFirstLineStyle =
9119
0
    ShouldHaveFirstLineStyle(aContent, aComputedStyle);
9120
0
}
9121
9122
/* static */
9123
const nsCSSFrameConstructor::PseudoParentData
9124
nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
9125
  { // Cell
9126
    FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9127
                     FCDATA_USE_CHILD_ITEMS |
9128
                     FCDATA_IS_WRAPPER_ANON_BOX |
9129
                     FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
9130
                     &nsCSSFrameConstructor::ConstructTableCell),
9131
    &nsCSSAnonBoxes::tableCell()
9132
  },
9133
  { // Row
9134
    FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9135
                     FCDATA_USE_CHILD_ITEMS |
9136
                     FCDATA_IS_WRAPPER_ANON_BOX |
9137
                     FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
9138
                     &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
9139
    &nsCSSAnonBoxes::tableRow()
9140
  },
9141
  { // Row group
9142
    FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9143
                     FCDATA_USE_CHILD_ITEMS |
9144
                     FCDATA_IS_WRAPPER_ANON_BOX |
9145
                     FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9146
                     &nsCSSFrameConstructor::ConstructTableRowOrRowGroup),
9147
    &nsCSSAnonBoxes::tableRowGroup()
9148
  },
9149
  { // Column group
9150
    FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9151
                FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
9152
                FCDATA_SKIP_ABSPOS_PUSH |
9153
                // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
9154
                // restyle these: they have non-inheriting styles.
9155
                FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9156
                NS_NewTableColGroupFrame),
9157
    &nsCSSAnonBoxes::tableColGroup()
9158
  },
9159
  { // Table
9160
    FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
9161
                     FCDATA_IS_WRAPPER_ANON_BOX,
9162
                     &nsCSSFrameConstructor::ConstructTable),
9163
    &nsCSSAnonBoxes::table()
9164
  },
9165
  { // Ruby
9166
    FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
9167
                FCDATA_USE_CHILD_ITEMS |
9168
                FCDATA_IS_WRAPPER_ANON_BOX |
9169
                FCDATA_SKIP_FRAMESET,
9170
                NS_NewRubyFrame),
9171
    &nsCSSAnonBoxes::ruby()
9172
  },
9173
  { // Ruby Base
9174
    FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9175
                FCDATA_IS_LINE_PARTICIPANT |
9176
                FCDATA_IS_WRAPPER_ANON_BOX |
9177
                FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
9178
                FCDATA_SKIP_FRAMESET,
9179
                NS_NewRubyBaseFrame),
9180
    &nsCSSAnonBoxes::rubyBase()
9181
  },
9182
  { // Ruby Base Container
9183
    FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9184
                FCDATA_IS_LINE_PARTICIPANT |
9185
                FCDATA_IS_WRAPPER_ANON_BOX |
9186
                FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
9187
                FCDATA_SKIP_FRAMESET,
9188
                NS_NewRubyBaseContainerFrame),
9189
    &nsCSSAnonBoxes::rubyBaseContainer()
9190
  },
9191
  { // Ruby Text
9192
    FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9193
                FCDATA_IS_LINE_PARTICIPANT |
9194
                FCDATA_IS_WRAPPER_ANON_BOX |
9195
                FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
9196
                FCDATA_SKIP_FRAMESET,
9197
                NS_NewRubyTextFrame),
9198
    &nsCSSAnonBoxes::rubyText()
9199
  },
9200
  { // Ruby Text Container
9201
    FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
9202
                FCDATA_IS_WRAPPER_ANON_BOX |
9203
                FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
9204
                FCDATA_SKIP_FRAMESET,
9205
                NS_NewRubyTextContainerFrame),
9206
    &nsCSSAnonBoxes::rubyTextContainer()
9207
  }
9208
};
9209
9210
void
9211
nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
9212
  nsFrameConstructorState& aState,
9213
  FrameConstructionItemList& aItems,
9214
  nsIFrame* aParentFrame)
9215
0
{
9216
0
  if (aItems.IsEmpty() || !::IsFlexOrGridContainer(aParentFrame)) {
9217
0
    return;
9218
0
  }
9219
0
9220
0
  const bool isLegacyBox = IsFlexContainerForLegacyBox(aParentFrame);
9221
0
  FCItemIterator iter(aItems);
9222
0
  do {
9223
0
    // Advance iter past children that don't want to be wrapped
9224
0
    if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
9225
0
      // Hit the end of the items without finding any remaining children that
9226
0
      // need to be wrapped. We're finished!
9227
0
      return;
9228
0
    }
9229
0
9230
0
    // If our next potentially-wrappable child is whitespace, then see if
9231
0
    // there's anything wrappable immediately after it. If not, we just drop
9232
0
    // the whitespace and move on. (We're not supposed to create any anonymous
9233
0
    // flex/grid items that _only_ contain whitespace).
9234
0
    // (BUT if this is generated content, then we don't give whitespace nodes
9235
0
    // any special treatment, because they're probably not really whitespace --
9236
0
    // they're just temporarily empty, waiting for their generated text.)
9237
0
    // XXXdholbert If this node's generated text will *actually end up being
9238
0
    // entirely whitespace*, then we technically should still skip over it, per
9239
0
    // the CSS grid & flexbox specs. I'm not bothering with that at this point,
9240
0
    // since it's a pretty extreme edge case.
9241
0
    if (!aParentFrame->IsGeneratedContentFrame() &&
9242
0
        iter.item().IsWhitespace(aState)) {
9243
0
      FCItemIterator afterWhitespaceIter(iter);
9244
0
      bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
9245
0
      bool nextChildNeedsAnonItem =
9246
0
        !hitEnd &&
9247
0
        afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox);
9248
0
9249
0
      if (!nextChildNeedsAnonItem) {
9250
0
        // There's nothing after the whitespace that we need to wrap, so we
9251
0
        // just drop this run of whitespace.
9252
0
        iter.DeleteItemsTo(this, afterWhitespaceIter);
9253
0
        if (hitEnd) {
9254
0
          // Nothing left to do -- we're finished!
9255
0
          return;
9256
0
        }
9257
0
        // else, we have a next child and it does not want to be wrapped.  So,
9258
0
        // we jump back to the beginning of the loop to skip over that child
9259
0
        // (and anything else non-wrappable after it)
9260
0
        MOZ_ASSERT(!iter.IsDone() &&
9261
0
                   !iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox),
9262
0
                   "hitEnd and/or nextChildNeedsAnonItem lied");
9263
0
        continue;
9264
0
      }
9265
0
    }
9266
0
9267
0
    // Now |iter| points to the first child that needs to be wrapped in an
9268
0
    // anonymous flex/grid item. Now we see how many children after it also want
9269
0
    // to be wrapped in an anonymous flex/grid item.
9270
0
    FCItemIterator endIter(iter); // iterator to find the end of the group
9271
0
    endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox);
9272
0
9273
0
    NS_ASSERTION(iter != endIter,
9274
0
                 "Should've had at least one wrappable child to seek past");
9275
0
9276
0
    // Now, we create the anonymous flex or grid item to contain the children
9277
0
    // between |iter| and |endIter|.
9278
0
    nsAtom* pseudoType = (aParentFrame->IsFlexContainerFrame())
9279
0
                            ? nsCSSAnonBoxes::anonymousFlexItem()
9280
0
                            : nsCSSAnonBoxes::anonymousGridItem();
9281
0
    ComputedStyle* parentStyle = aParentFrame->Style();
9282
0
    nsIContent* parentContent = aParentFrame->GetContent();
9283
0
    RefPtr<ComputedStyle> wrapperStyle =
9284
0
      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
9285
0
                                                                 parentStyle);
9286
0
9287
0
    static const FrameConstructionData sBlockFormattingContextFCData =
9288
0
      FCDATA_DECL(FCDATA_SKIP_FRAMESET |
9289
0
                  FCDATA_USE_CHILD_ITEMS |
9290
0
                  FCDATA_IS_WRAPPER_ANON_BOX,
9291
0
                  NS_NewBlockFormattingContext);
9292
0
9293
0
    FrameConstructionItem* newItem =
9294
0
      new (this) FrameConstructionItem(&sBlockFormattingContextFCData,
9295
0
                                // Use the content of our parent frame
9296
0
                                parentContent,
9297
0
                                // no pending binding
9298
0
                                nullptr,
9299
0
                                wrapperStyle.forget(),
9300
0
                                true);
9301
0
9302
0
    newItem->mIsAllInline =
9303
0
      newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
9304
0
    newItem->mIsBlock = !newItem->mIsAllInline;
9305
0
9306
0
    MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,
9307
0
               "expecting anonymous flex/grid items to be block-level "
9308
0
               "(this will make a difference when we encounter "
9309
0
               "'align-items: baseline')");
9310
0
9311
0
    // Anonymous flex and grid items induce line boundaries around their
9312
0
    // contents.
9313
0
    newItem->mChildItems.SetLineBoundaryAtStart(true);
9314
0
    newItem->mChildItems.SetLineBoundaryAtEnd(true);
9315
0
    // The parent of the items in aItems is also the parent of the items
9316
0
    // in mChildItems
9317
0
    newItem->mChildItems.SetParentHasNoXBLChildren(
9318
0
      aItems.ParentHasNoXBLChildren());
9319
0
9320
0
    // Eat up all items between |iter| and |endIter| and put them in our
9321
0
    // wrapper. This advances |iter| to point to |endIter|.
9322
0
    iter.AppendItemsToList(this, endIter, newItem->mChildItems);
9323
0
9324
0
    iter.InsertItem(newItem);
9325
0
  } while (!iter.IsDone());
9326
0
}
9327
9328
/* static */ nsCSSFrameConstructor::RubyWhitespaceType
9329
nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
9330
                                                 StyleDisplay aNextDisplay)
9331
0
{
9332
0
  MOZ_ASSERT(nsStyleDisplay::IsRubyDisplayType(aPrevDisplay) &&
9333
0
             nsStyleDisplay::IsRubyDisplayType(aNextDisplay));
9334
0
  if (aPrevDisplay == aNextDisplay &&
9335
0
      (aPrevDisplay == StyleDisplay::RubyBase ||
9336
0
       aPrevDisplay == StyleDisplay::RubyText)) {
9337
0
    return eRubyInterLeafWhitespace;
9338
0
  }
9339
0
  if (aNextDisplay == StyleDisplay::RubyText ||
9340
0
      aNextDisplay == StyleDisplay::RubyTextContainer) {
9341
0
    return eRubyInterLevelWhitespace;
9342
0
  }
9343
0
  return eRubyInterSegmentWhitespace;
9344
0
}
9345
9346
/**
9347
 * This function checks the content from |aStartIter| to |aEndIter|,
9348
 * determines whether it contains only whitespace, and if yes,
9349
 * interprets the type of whitespace. This method does not change
9350
 * any of the iters.
9351
 */
9352
/* static */ nsCSSFrameConstructor::RubyWhitespaceType
9353
nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
9354
                                               const FCItemIterator& aStartIter,
9355
                                               const FCItemIterator& aEndIter)
9356
0
{
9357
0
  if (!aStartIter.item().IsWhitespace(aState)) {
9358
0
    return eRubyNotWhitespace;
9359
0
  }
9360
0
9361
0
  FCItemIterator spaceEndIter(aStartIter);
9362
0
  spaceEndIter.SkipWhitespace(aState);
9363
0
  if (spaceEndIter != aEndIter) {
9364
0
    return eRubyNotWhitespace;
9365
0
  }
9366
0
9367
0
  // Any leading or trailing whitespace in non-pseudo ruby box
9368
0
  // should have been trimmed, hence there should not be any
9369
0
  // whitespace at the start or the end.
9370
0
  MOZ_ASSERT(!aStartIter.AtStart() && !aEndIter.IsDone());
9371
0
  FCItemIterator prevIter(aStartIter);
9372
0
  prevIter.Prev();
9373
0
  return ComputeRubyWhitespaceType(
9374
0
      prevIter.item().mComputedStyle->StyleDisplay()->mDisplay,
9375
0
      aEndIter.item().mComputedStyle->StyleDisplay()->mDisplay);
9376
0
}
9377
9378
9379
/**
9380
 * This function eats up consecutive items which do not want the current
9381
 * parent into either a ruby base box or a ruby text box.  When it
9382
 * returns, |aIter| points to the first item it doesn't wrap.
9383
 */
9384
void
9385
nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
9386
  FCItemIterator& aIter,
9387
  ComputedStyle* aParentStyle, nsIContent* aParentContent)
9388
0
{
9389
0
  StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
9390
0
  ParentType parentType, wrapperType;
9391
0
  if (parentDisplay == StyleDisplay::RubyTextContainer) {
9392
0
    parentType = eTypeRubyTextContainer;
9393
0
    wrapperType = eTypeRubyText;
9394
0
  } else {
9395
0
    MOZ_ASSERT(parentDisplay == StyleDisplay::RubyBaseContainer);
9396
0
    parentType = eTypeRubyBaseContainer;
9397
0
    wrapperType = eTypeRubyBase;
9398
0
  }
9399
0
9400
0
  MOZ_ASSERT(aIter.item().DesiredParentType() != parentType,
9401
0
             "Should point to something needs to be wrapped.");
9402
0
9403
0
  FCItemIterator endIter(aIter);
9404
0
  endIter.SkipItemsNotWantingParentType(parentType);
9405
0
9406
0
  WrapItemsInPseudoParent(aParentContent, aParentStyle,
9407
0
                          wrapperType, aIter, endIter);
9408
0
}
9409
9410
/**
9411
 * This function eats up consecutive items into a ruby level container.
9412
 * It may create zero or one level container. When it returns, |aIter|
9413
 * points to the first item it doesn't wrap.
9414
 */
9415
void
9416
nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
9417
  nsFrameConstructorState& aState, FCItemIterator& aIter,
9418
  ComputedStyle* aParentStyle, nsIContent* aParentContent)
9419
0
{
9420
0
  MOZ_ASSERT(aIter.item().DesiredParentType() != eTypeRuby,
9421
0
             "Pointing to a level container?");
9422
0
9423
0
  FrameConstructionItem& firstItem = aIter.item();
9424
0
  ParentType wrapperType = firstItem.DesiredParentType();
9425
0
  if (wrapperType != eTypeRubyTextContainer) {
9426
0
    // If the first item is not ruby text,
9427
0
    // it should be in a base container.
9428
0
    wrapperType = eTypeRubyBaseContainer;
9429
0
  }
9430
0
9431
0
  FCItemIterator endIter(aIter);
9432
0
  do {
9433
0
    if (endIter.SkipItemsWantingParentType(wrapperType) ||
9434
0
        // If the skipping above stops at some item which wants a
9435
0
        // different ruby parent, then we have finished.
9436
0
        IsRubyParentType(endIter.item().DesiredParentType())) {
9437
0
      // No more items need to be wrapped in this level container.
9438
0
      break;
9439
0
    }
9440
0
9441
0
    FCItemIterator contentEndIter(endIter);
9442
0
    contentEndIter.SkipItemsNotWantingRubyParent();
9443
0
    // endIter must be on something doesn't want a ruby parent.
9444
0
    MOZ_ASSERT(contentEndIter != endIter);
9445
0
9446
0
    // InterpretRubyWhitespace depends on the fact that any leading or
9447
0
    // trailing whitespace described in the spec have been trimmed at
9448
0
    // this point. With this precondition, it is safe not to check
9449
0
    // whether contentEndIter has been done.
9450
0
    RubyWhitespaceType whitespaceType =
9451
0
      InterpretRubyWhitespace(aState, endIter, contentEndIter);
9452
0
    if (whitespaceType == eRubyInterLevelWhitespace) {
9453
0
      // Remove inter-level whitespace.
9454
0
      bool atStart = (aIter == endIter);
9455
0
      endIter.DeleteItemsTo(this, contentEndIter);
9456
0
      if (atStart) {
9457
0
        aIter = endIter;
9458
0
      }
9459
0
    } else if (whitespaceType == eRubyInterSegmentWhitespace) {
9460
0
      // If this level container starts with inter-segment whitespaces,
9461
0
      // wrap them. Break at contentEndIter. Otherwise, leave it here.
9462
0
      // Break at endIter. They will be wrapped when we are here again.
9463
0
      if (aIter == endIter) {
9464
0
        MOZ_ASSERT(wrapperType == eTypeRubyBaseContainer,
9465
0
                   "Inter-segment whitespace should be wrapped in rbc");
9466
0
        endIter = contentEndIter;
9467
0
      }
9468
0
      break;
9469
0
    } else if (wrapperType == eTypeRubyTextContainer &&
9470
0
               whitespaceType != eRubyInterLeafWhitespace) {
9471
0
      // Misparented inline content that's not inter-annotation
9472
0
      // whitespace doesn't belong in a pseudo ruby text container.
9473
0
      // Break at endIter.
9474
0
      break;
9475
0
    } else {
9476
0
      endIter = contentEndIter;
9477
0
    }
9478
0
  } while (!endIter.IsDone());
9479
0
9480
0
  // It is possible that everything our parent wants us to wrap is
9481
0
  // simply an inter-level whitespace, which has been trimmed, or
9482
0
  // an inter-segment whitespace, which will be wrapped later.
9483
0
  // In those cases, don't create anything.
9484
0
  if (aIter != endIter) {
9485
0
    WrapItemsInPseudoParent(aParentContent, aParentStyle,
9486
0
                            wrapperType, aIter, endIter);
9487
0
  }
9488
0
}
9489
9490
/**
9491
 * This function trims leading and trailing whitespaces
9492
 * in the given item list.
9493
 */
9494
void
9495
nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
9496
    nsFrameConstructorState& aState,
9497
    FrameConstructionItemList& aItems)
9498
0
{
9499
0
  FCItemIterator iter(aItems);
9500
0
  if (!iter.IsDone() &&
9501
0
      iter.item().IsWhitespace(aState)) {
9502
0
    FCItemIterator spaceEndIter(iter);
9503
0
    spaceEndIter.SkipWhitespace(aState);
9504
0
    iter.DeleteItemsTo(this, spaceEndIter);
9505
0
  }
9506
0
9507
0
  iter.SetToEnd();
9508
0
  if (!iter.AtStart()) {
9509
0
    FCItemIterator spaceEndIter(iter);
9510
0
    do {
9511
0
      iter.Prev();
9512
0
      if (iter.AtStart()) {
9513
0
        // It's fine to not check the first item, because we
9514
0
        // should have trimmed leading whitespaces above.
9515
0
        break;
9516
0
      }
9517
0
    } while (iter.item().IsWhitespace(aState));
9518
0
    iter.Next();
9519
0
    if (iter != spaceEndIter) {
9520
0
      iter.DeleteItemsTo(this, spaceEndIter);
9521
0
    }
9522
0
  }
9523
0
}
9524
9525
/**
9526
 * This function walks through the child list (aItems) and creates
9527
 * needed pseudo ruby boxes to wrap misparented children.
9528
 */
9529
void
9530
nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
9531
  nsFrameConstructorState& aState,
9532
  FrameConstructionItemList& aItems,
9533
  nsIFrame* aParentFrame)
9534
0
{
9535
0
  const ParentType ourParentType = GetParentType(aParentFrame);
9536
0
  if (!IsRubyParentType(ourParentType) ||
9537
0
      aItems.AllWantParentType(ourParentType)) {
9538
0
    return;
9539
0
  }
9540
0
9541
0
  if (!IsRubyPseudo(aParentFrame)) {
9542
0
    // Normally, ruby pseudo frames start from and end at some elements,
9543
0
    // which means they don't have leading and trailing whitespaces at
9544
0
    // all.  But there are two cases where they do actually have leading
9545
0
    // or trailing whitespaces:
9546
0
    // 1. It is an inter-segment whitespace which in an individual ruby
9547
0
    //    base container.
9548
0
    // 2. The pseudo frame starts from or ends at consecutive inline
9549
0
    //    content, which is not pure whitespace, but includes some.
9550
0
    // In either case, the whitespaces are not the leading or trailing
9551
0
    // whitespaces defined in the spec, and thus should not be trimmed.
9552
0
    TrimLeadingAndTrailingWhitespaces(aState, aItems);
9553
0
  }
9554
0
9555
0
  FCItemIterator iter(aItems);
9556
0
  nsIContent* parentContent = aParentFrame->GetContent();
9557
0
  ComputedStyle* parentStyle = aParentFrame->Style();
9558
0
  while (!iter.IsDone()) {
9559
0
    if (!iter.SkipItemsWantingParentType(ourParentType)) {
9560
0
      if (ourParentType == eTypeRuby) {
9561
0
        WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
9562
0
                                            parentContent);
9563
0
      } else {
9564
0
        WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
9565
0
      }
9566
0
    }
9567
0
  }
9568
0
}
9569
9570
/*
9571
 * This function works as follows: we walk through the child list (aItems) and
9572
 * find items that cannot have aParentFrame as their parent.  We wrap
9573
 * continuous runs of such items into a FrameConstructionItem for a frame that
9574
 * gets them closer to their desired parents.  For example, a run of non-row
9575
 * children of a row-group will get wrapped in a row.  When we later construct
9576
 * the frame for this wrapper (in this case for the row), it'll be the correct
9577
 * parent for the cells in the set of items we wrapped or we'll wrap cells
9578
 * around everything else.  At the end of this method, aItems is guaranteed to
9579
 * contain only items for frames that can be direct kids of aParentFrame.
9580
 */
9581
void
9582
nsCSSFrameConstructor::CreateNeededPseudoContainers(
9583
    nsFrameConstructorState& aState,
9584
    FrameConstructionItemList& aItems,
9585
    nsIFrame* aParentFrame)
9586
0
{
9587
0
  ParentType ourParentType = GetParentType(aParentFrame);
9588
0
  if (IsRubyParentType(ourParentType) ||
9589
0
      aItems.AllWantParentType(ourParentType)) {
9590
0
    // Nothing to do here
9591
0
    return;
9592
0
  }
9593
0
9594
0
  FCItemIterator iter(aItems);
9595
0
  do {
9596
0
    if (iter.SkipItemsWantingParentType(ourParentType)) {
9597
0
      // Nothing else to do here; we're finished
9598
0
      return;
9599
0
    }
9600
0
9601
0
    // Now we're pointing to the first child that wants a different parent
9602
0
    // type.
9603
0
9604
0
    // Now try to figure out what kids we can group together.  We can generally
9605
0
    // group everything that has a different desired parent type from us.  Two
9606
0
    // exceptions to this:
9607
0
    // 1) If our parent type is table, we can't group columns with anything
9608
0
    //    else other than whitespace.
9609
0
    // 2) Whitespace that lies between two things we can group which both want
9610
0
    //    a non-block parent should be dropped, even if we can't group them
9611
0
    //    with each other and even if the whitespace wants a parent of
9612
0
    //    ourParentType.  Ends of the list count as things that don't want a
9613
0
    //    block parent (so that for example we'll drop a whitespace-only list).
9614
0
9615
0
    FCItemIterator endIter(iter); /* iterator to find the end of the group */
9616
0
    ParentType groupingParentType = endIter.item().DesiredParentType();
9617
0
    if (aItems.AllWantParentType(groupingParentType) &&
9618
0
        groupingParentType != eTypeBlock) {
9619
0
      // Just group them all and be done with it.  We need the check for
9620
0
      // eTypeBlock here to catch the "all the items are whitespace" case
9621
0
      // described above.
9622
0
      endIter.SetToEnd();
9623
0
    } else {
9624
0
      // Locate the end of the group.
9625
0
9626
0
      // Keep track of the type the previous item wanted, in case we have to
9627
0
      // deal with whitespace.  Start it off with ourParentType, since that's
9628
0
      // the last thing |iter| would have skipped over.
9629
0
      ParentType prevParentType = ourParentType;
9630
0
      do {
9631
0
        // Walk an iterator past any whitespace that we might be able to drop
9632
0
        // from the list
9633
0
        FCItemIterator spaceEndIter(endIter);
9634
0
        if (prevParentType != eTypeBlock &&
9635
0
            !aParentFrame->IsGeneratedContentFrame() &&
9636
0
            spaceEndIter.item().IsWhitespace(aState)) {
9637
0
          bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
9638
0
9639
0
          // We drop the whitespace in the following cases:
9640
0
          // 1) If these are not trailing spaces and the next item wants a table
9641
0
          //    or table-part parent
9642
0
          // 2) If these are trailing spaces and aParentFrame is a
9643
0
          //    tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
9644
0
          //    (Being a tabular container pretty much means ourParentType is
9645
0
          //    not eTypeBlock besides the eTypeColGroup case, which won't
9646
0
          //    reach here.)
9647
0
          if ((!trailingSpaces &&
9648
0
               IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
9649
0
              (trailingSpaces && ourParentType != eTypeBlock)) {
9650
0
            bool updateStart = (iter == endIter);
9651
0
            endIter.DeleteItemsTo(this, spaceEndIter);
9652
0
            NS_ASSERTION(trailingSpaces == endIter.IsDone(),
9653
0
                         "These should match");
9654
0
9655
0
            if (updateStart) {
9656
0
              iter = endIter;
9657
0
            }
9658
0
9659
0
            if (trailingSpaces) {
9660
0
              break; /* Found group end */
9661
0
            }
9662
0
9663
0
            if (updateStart) {
9664
0
              // Update groupingParentType, since it might have been eTypeBlock
9665
0
              // just because of the whitespace.
9666
0
              groupingParentType = iter.item().DesiredParentType();
9667
0
            }
9668
0
          }
9669
0
        }
9670
0
9671
0
        // Now endIter points to a non-whitespace item or a non-droppable
9672
0
        // whitespace item. In the latter case, if this is the end of the group
9673
0
        // we'll traverse this whitespace again.  But it'll all just be quick
9674
0
        // DesiredParentType() checks which will match ourParentType (that's
9675
0
        // what it means that this is the group end), so it's OK.
9676
0
        // However, when we are grouping a ruby parent, and endIter points to
9677
0
        // a non-droppable whitespace, if the next non-whitespace item also
9678
0
        // wants a ruby parent, the whitespace should also be included into
9679
0
        // the current ruby container.
9680
0
        prevParentType = endIter.item().DesiredParentType();
9681
0
        if (prevParentType == ourParentType &&
9682
0
            (endIter == spaceEndIter ||
9683
0
             spaceEndIter.IsDone() ||
9684
0
             !IsRubyParentType(groupingParentType) ||
9685
0
             !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
9686
0
          // End the group at endIter.
9687
0
          break;
9688
0
        }
9689
0
9690
0
        if (ourParentType == eTypeTable &&
9691
0
            (prevParentType == eTypeColGroup) !=
9692
0
            (groupingParentType == eTypeColGroup)) {
9693
0
          // Either we started with columns and now found something else, or vice
9694
0
          // versa.  In any case, end the grouping.
9695
0
          break;
9696
0
        }
9697
0
9698
0
        // If we have some whitespace that we were not able to drop and there is
9699
0
        // an item after the whitespace that is already properly parented, then
9700
0
        // make sure to include the spaces in our group but stop the group after
9701
0
        // that.
9702
0
        if (spaceEndIter != endIter &&
9703
0
            !spaceEndIter.IsDone() &&
9704
0
            ourParentType == spaceEndIter.item().DesiredParentType()) {
9705
0
            endIter = spaceEndIter;
9706
0
            break;
9707
0
        }
9708
0
9709
0
        // Include the whitespace we didn't drop (if any) in the group.
9710
0
        endIter = spaceEndIter;
9711
0
        prevParentType = endIter.item().DesiredParentType();
9712
0
9713
0
        endIter.Next();
9714
0
      } while (!endIter.IsDone());
9715
0
    }
9716
0
9717
0
    if (iter == endIter) {
9718
0
      // Nothing to wrap here; just skipped some whitespace
9719
0
      continue;
9720
0
    }
9721
0
9722
0
    // Now group together all the items between iter and endIter.  The right
9723
0
    // parent type to use depends on ourParentType.
9724
0
    ParentType wrapperType;
9725
0
    switch (ourParentType) {
9726
0
      case eTypeRow:
9727
0
        // The parent type for a cell is eTypeBlock, since that's what a cell
9728
0
        // looks like to its kids.
9729
0
        wrapperType = eTypeBlock;
9730
0
        break;
9731
0
      case eTypeRowGroup:
9732
0
        wrapperType = eTypeRow;
9733
0
        break;
9734
0
      case eTypeTable:
9735
0
        // Either colgroup or rowgroup, depending on what we're grouping.
9736
0
        wrapperType = groupingParentType == eTypeColGroup ?
9737
0
          eTypeColGroup : eTypeRowGroup;
9738
0
        break;
9739
0
      case eTypeColGroup:
9740
0
        MOZ_CRASH("Colgroups should be suppresing non-col child items");
9741
0
      default:
9742
0
        NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type");
9743
0
        if (IsRubyParentType(groupingParentType)) {
9744
0
          wrapperType = eTypeRuby;
9745
0
        } else {
9746
0
          NS_ASSERTION(IsTableParentType(groupingParentType),
9747
0
                       "groupingParentType should be either Ruby or table");
9748
0
          wrapperType = eTypeTable;
9749
0
        }
9750
0
    }
9751
0
9752
0
    ComputedStyle* parentStyle = aParentFrame->Style();
9753
0
    WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
9754
0
                            wrapperType, iter, endIter);
9755
0
9756
0
    // Now |iter| points to the item that was the first one we didn't wrap;
9757
0
    // loop and see whether we need to skip it or wrap it in something
9758
0
    // different.
9759
0
  } while (!iter.IsDone());
9760
0
}
9761
9762
/**
9763
 * This method wraps frame construction item from |aIter| to
9764
 * |aEndIter|. After it returns, aIter points to the first item
9765
 * after the wrapper.
9766
 */
9767
void
9768
nsCSSFrameConstructor::WrapItemsInPseudoParent(nsIContent* aParentContent,
9769
                                               ComputedStyle* aParentStyle,
9770
                                               ParentType aWrapperType,
9771
                                               FCItemIterator& aIter,
9772
                                               const FCItemIterator& aEndIter)
9773
0
{
9774
0
  const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
9775
0
  nsAtom* pseudoType = *pseudoData.mPseudoType;
9776
0
  StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
9777
0
9778
0
  if (pseudoType == nsCSSAnonBoxes::table() &&
9779
0
      (parentDisplay == StyleDisplay::Inline ||
9780
0
       parentDisplay == StyleDisplay::RubyBase ||
9781
0
       parentDisplay == StyleDisplay::RubyText)) {
9782
0
    pseudoType = nsCSSAnonBoxes::inlineTable();
9783
0
  }
9784
0
9785
0
  RefPtr<ComputedStyle> wrapperStyle;
9786
0
  if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX) {
9787
0
    wrapperStyle =
9788
0
      mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
9789
0
                                                                 aParentStyle);
9790
0
  } else {
9791
0
    wrapperStyle =
9792
0
      mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(pseudoType);
9793
0
  }
9794
0
9795
0
  FrameConstructionItem* newItem =
9796
0
    new (this) FrameConstructionItem(&pseudoData.mFCData,
9797
0
                              // Use the content of our parent frame
9798
0
                              aParentContent,
9799
0
                              // no pending binding
9800
0
                              nullptr,
9801
0
                              wrapperStyle.forget(),
9802
0
                              true);
9803
0
9804
0
  const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
9805
0
  // Here we're cheating a tad... technically, table-internal items should be
9806
0
  // inline if aParentFrame is inline, but they'll get wrapped in an
9807
0
  // inline-table in the end, so it'll all work out.  In any case, arguably
9808
0
  // we don't need to maintain this state at this point... but it's better
9809
0
  // to, I guess.
9810
0
  newItem->mIsAllInline = disp->IsInlineOutsideStyle();
9811
0
9812
0
  bool isRuby = disp->IsRubyDisplayType();
9813
0
  // All types of ruby frames need a block frame to provide line layout,
9814
0
  // hence they are always line participant.
9815
0
  newItem->mIsLineParticipant = isRuby;
9816
0
9817
0
  if (!isRuby) {
9818
0
    // Table pseudo frames always induce line boundaries around their
9819
0
    // contents.
9820
0
    newItem->mChildItems.SetLineBoundaryAtStart(true);
9821
0
    newItem->mChildItems.SetLineBoundaryAtEnd(true);
9822
0
  }
9823
0
  // The parent of the items in aItems is also the parent of the items
9824
0
  // in mChildItems
9825
0
  newItem->mChildItems.SetParentHasNoXBLChildren(
9826
0
      aIter.List()->ParentHasNoXBLChildren());
9827
0
9828
0
  // Eat up all items between |aIter| and |aEndIter| and put them in our
9829
0
  // wrapper Advances |aIter| to point to |aEndIter|.
9830
0
  aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
9831
0
9832
0
  aIter.InsertItem(newItem);
9833
0
}
9834
9835
void
9836
nsCSSFrameConstructor::CreateNeededPseudoSiblings(
9837
    nsFrameConstructorState& aState,
9838
    FrameConstructionItemList& aItems,
9839
    nsIFrame* aParentFrame)
9840
0
{
9841
0
  if (aItems.IsEmpty() ||
9842
0
      GetParentType(aParentFrame) != eTypeRuby) {
9843
0
    return;
9844
0
  }
9845
0
9846
0
  FCItemIterator iter(aItems);
9847
0
  StyleDisplay firstDisplay = iter.item().mComputedStyle->StyleDisplay()->mDisplay;
9848
0
  if (firstDisplay == StyleDisplay::RubyBaseContainer) {
9849
0
    return;
9850
0
  }
9851
0
  NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,
9852
0
               "Child of ruby frame should either a rbc or a rtc");
9853
0
9854
0
  const PseudoParentData& pseudoData =
9855
0
    sPseudoParentData[eTypeRubyBaseContainer];
9856
0
  RefPtr<ComputedStyle> pseudoStyle = mPresShell->StyleSet()->
9857
0
    ResolveInheritingAnonymousBoxStyle(*pseudoData.mPseudoType,
9858
0
                                       aParentFrame->Style());
9859
0
  FrameConstructionItem* newItem =
9860
0
    new (this) FrameConstructionItem(&pseudoData.mFCData,
9861
0
                                     // Use the content of the parent frame
9862
0
                                     aParentFrame->GetContent(),
9863
0
                                     // no pending binding
9864
0
                                     nullptr,
9865
0
                                     pseudoStyle.forget(),
9866
0
                                     true);
9867
0
  newItem->mIsAllInline = true;
9868
0
  newItem->mChildItems.SetParentHasNoXBLChildren(true);
9869
0
  iter.InsertItem(newItem);
9870
0
}
9871
9872
#ifdef DEBUG
9873
/**
9874
 * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
9875
 * rather than being a direct child of aContainerFrame.
9876
 *
9877
 * NOTE: aContainerFrame must be a flex or grid container - this function is
9878
 * purely for sanity-checking the children of these container types.
9879
 * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
9880
 * logic (which operates a bit earlier, on FCData instead of frames).
9881
 */
9882
static bool
9883
FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
9884
                              const nsIFrame* aFrame)
9885
{
9886
  MOZ_ASSERT(::IsFlexOrGridContainer(aContainerFrame));
9887
9888
  // Any line-participant frames (e.g. text) definitely want to be wrapped in
9889
  // an anonymous flex/grid item.
9890
  if (aFrame->IsFrameOfType(nsIFrame::eLineParticipant)) {
9891
    return true;
9892
  }
9893
9894
  // If the container is a -webkit-{inline-}box or -moz-{inline-}box container,
9895
  // then placeholders also need to be wrapped, for compatibility.
9896
  if (IsFlexContainerForLegacyBox(aContainerFrame) &&
9897
      aFrame->IsPlaceholderFrame()) {
9898
    return true;
9899
  }
9900
9901
  return false;
9902
}
9903
#endif
9904
9905
static void
9906
VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
9907
                                const nsFrameList& aChildren)
9908
0
{
9909
#ifdef DEBUG
9910
  if (!::IsFlexOrGridContainer(aParentFrame)) {
9911
    return;
9912
  }
9913
9914
  bool prevChildWasAnonItem = false;
9915
  for (const nsIFrame* child : aChildren) {
9916
    MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(aParentFrame, child),
9917
               "frame wants to be inside an anonymous item, but it isn't");
9918
    if (IsAnonymousFlexOrGridItem(child)) {
9919
      AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
9920
      MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row");
9921
      nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
9922
      MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty");
9923
      prevChildWasAnonItem = true;
9924
    } else {
9925
      prevChildWasAnonItem = false;
9926
    }
9927
  }
9928
#endif
9929
}
9930
9931
inline void
9932
nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState,
9933
                                                   FrameConstructionItemList& aItems,
9934
                                                   nsContainerFrame* aParentFrame,
9935
                                                   bool aParentIsWrapperAnonBox,
9936
                                                   nsFrameItems& aFrameItems)
9937
0
{
9938
0
  // Ensure aParentIsWrapperAnonBox is correct.  We _could_ compute it directly,
9939
0
  // but it would be a bit slow, which is why we pass it from callers, who have
9940
0
  // that information offhand in many cases.
9941
0
  MOZ_ASSERT(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox);
9942
0
9943
0
  CreateNeededPseudoContainers(aState, aItems, aParentFrame);
9944
0
  CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
9945
0
  CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
9946
0
  CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
9947
0
9948
0
  for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
9949
0
    NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
9950
0
                 "Needed pseudos didn't get created; expect bad things");
9951
0
    ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
9952
0
  }
9953
0
9954
0
  VerifyGridFlexContainerChildren(aParentFrame, aFrameItems);
9955
0
  NS_ASSERTION(!aState.mHavePendingPopupgroup,
9956
0
               "Should have proccessed it by now");
9957
0
9958
0
  if (aParentIsWrapperAnonBox) {
9959
0
    for (nsIFrame* f : aFrameItems) {
9960
0
      f->SetParentIsWrapperAnonBox();
9961
0
    }
9962
0
  }
9963
0
}
9964
9965
void
9966
nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
9967
            nsFrameConstructorState& aState,
9968
            nsContainerFrame* aFrame,
9969
            const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
9970
            FrameConstructionItemList& aItemsToConstruct,
9971
            uint32_t aExtraFlags)
9972
0
{
9973
0
  for (const auto& info : aAnonymousItems) {
9974
0
    nsIContent* content = info.mContent;
9975
0
    // Gecko-styled nodes should have no pending restyle flags.
9976
0
    // Assert some things about this content
9977
0
    MOZ_ASSERT(!(content->GetFlags() &
9978
0
                 (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
9979
0
               "Should not be marked as needing frames");
9980
0
    MOZ_ASSERT(!content->GetPrimaryFrame(),
9981
0
               "Should have no existing frame");
9982
0
    MOZ_ASSERT(!content->IsComment() && !content->IsProcessingInstruction(),
9983
0
               "Why is someone creating garbage anonymous content");
9984
0
9985
0
    // Make sure we eagerly performed the servo cascade when the anonymous
9986
0
    // nodes were created.
9987
0
    MOZ_ASSERT(!content->IsElement() || content->AsElement()->HasServoData());
9988
0
9989
0
    RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(content);
9990
0
9991
0
    uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK |
9992
0
                     ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags;
9993
0
9994
0
    AddFrameConstructionItemsInternal(aState, content, aFrame,
9995
0
                                      true, computedStyle, flags,
9996
0
                                      aItemsToConstruct);
9997
0
  }
9998
0
}
9999
10000
void
10001
nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
10002
                                       nsIContent*              aContent,
10003
                                       ComputedStyle*          aComputedStyle,
10004
                                       nsContainerFrame*        aFrame,
10005
                                       const bool               aCanHaveGeneratedContent,
10006
                                       nsFrameItems&            aFrameItems,
10007
                                       const bool               aAllowBlockStyles,
10008
                                       PendingBinding*          aPendingBinding,
10009
                                       nsIFrame*                aPossiblyLeafFrame)
10010
0
{
10011
0
  MOZ_ASSERT(aFrame, "Must have parent frame here");
10012
0
  MOZ_ASSERT(aFrame->GetContentInsertionFrame() == aFrame,
10013
0
             "Parent frame in ProcessChildren should be its own "
10014
0
             "content insertion frame");
10015
0
10016
0
  const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
10017
0
  static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
10018
0
  AutoRestore<uint16_t> savedDepth(mCurrentDepth);
10019
0
  if (mCurrentDepth != UINT16_MAX) {
10020
0
    ++mCurrentDepth;
10021
0
  }
10022
0
10023
0
  if (!aPossiblyLeafFrame) {
10024
0
    aPossiblyLeafFrame = aFrame;
10025
0
  }
10026
0
10027
0
  // XXXbz ideally, this would do all the pushing of various
10028
0
  // containing blocks as needed, so callers don't have to do it...
10029
0
10030
0
  // Check that our parent frame is a block before allowing ::first-letter/line.
10031
0
  // E.g. <button style="display:grid"> should not allow it.
10032
0
  const bool allowFirstPseudos = aAllowBlockStyles &&
10033
0
                                 nsLayoutUtils::GetAsBlock(aFrame);
10034
0
  bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
10035
0
  if (allowFirstPseudos) {
10036
0
    ShouldHaveSpecialBlockStyle(aContent, aComputedStyle, &haveFirstLetterStyle,
10037
0
                                &haveFirstLineStyle);
10038
0
  }
10039
0
10040
0
  const bool isFlexOrGridContainer = ::IsFlexOrGridContainer(aFrame);
10041
0
  // The logic here needs to match the logic in GetFloatContainingBlock()
10042
0
  // (Since we already have isFlexOrGridContainer, we check that eagerly instead
10043
0
  // of letting ShouldSuppressFloatingOfDescendants look it up redundantly.)
10044
0
  nsFrameConstructorSaveState floatSaveState;
10045
0
  if (isFlexOrGridContainer ||
10046
0
      ShouldSuppressFloatingOfDescendants(aFrame)) {
10047
0
    aState.PushFloatContainingBlock(nullptr, floatSaveState);
10048
0
  } else if (aFrame->IsFloatContainingBlock()) {
10049
0
    aState.PushFloatContainingBlock(aFrame, floatSaveState);
10050
0
  }
10051
0
10052
0
  nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
10053
0
                                                           aPendingBinding);
10054
0
10055
0
  AutoFrameConstructionItemList itemsToConstruct(this);
10056
0
10057
0
  // If we have first-letter or first-line style then frames can get
10058
0
  // moved around so don't set these flags.
10059
0
  if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
10060
0
    itemsToConstruct.SetLineBoundaryAtStart(true);
10061
0
    itemsToConstruct.SetLineBoundaryAtEnd(true);
10062
0
  }
10063
0
10064
0
  // Create any anonymous frames we need here.  This must happen before the
10065
0
  // non-anonymous children are processed to ensure that popups are never
10066
0
  // constructed before the popupset.
10067
0
  AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
10068
0
  GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
10069
#ifdef DEBUG
10070
  for (uint32_t i = 0; i < anonymousItems.Length(); ++i) {
10071
    MOZ_ASSERT(anonymousItems[i].mContent->IsRootOfAnonymousSubtree(),
10072
               "Content should know it's an anonymous subtree");
10073
  }
10074
#endif
10075
  AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
10076
0
                                itemsToConstruct);
10077
0
10078
0
  if (!aPossiblyLeafFrame->IsLeaf()) {
10079
0
    // :before/:after content should have the same style parent as normal kids.
10080
0
    //
10081
0
    // Note that we don't use this style for looking up things like special
10082
0
    // block styles because in some cases involving table pseudo-frames it has
10083
0
    // nothing to do with the parent frame's desired behavior.
10084
0
    ComputedStyle* computedStyle;
10085
0
10086
0
    if (aCanHaveGeneratedContent) {
10087
0
      computedStyle =
10088
0
        nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->Style();
10089
0
      // Probe for generated content before
10090
0
      CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
10091
0
                                 *computedStyle, CSSPseudoElementType::before,
10092
0
                                 itemsToConstruct);
10093
0
    }
10094
0
10095
0
    const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
10096
0
    if (!addChildItems) {
10097
0
      NS_WARNING("ProcessChildren max depth exceeded");
10098
0
    }
10099
0
10100
0
    FlattenedChildIterator iter(aContent);
10101
0
    const InsertionPoint insertion(aFrame, aContent);
10102
0
    for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
10103
0
      MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(child).mContainer,
10104
0
                 "GetInsertionPoint should agree with us");
10105
0
      if (addChildItems) {
10106
0
        AddFrameConstructionItems(aState, child, iter.XBLInvolved(), insertion,
10107
0
                                  itemsToConstruct);
10108
0
      } else {
10109
0
        ClearLazyBits(child, child->GetNextSibling());
10110
0
      }
10111
0
    }
10112
0
    itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
10113
0
10114
0
    if (aCanHaveGeneratedContent) {
10115
0
      // Probe for generated content after
10116
0
      CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
10117
0
                                 *computedStyle, CSSPseudoElementType::after,
10118
0
                                 itemsToConstruct);
10119
0
    }
10120
0
  } else {
10121
0
    ClearLazyBits(aContent->GetFirstChild(), nullptr);
10122
0
  }
10123
0
10124
0
  ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
10125
0
                              /* aParentIsWrapperAnonBox = */ false,
10126
0
                              aFrameItems);
10127
0
10128
0
  NS_ASSERTION(!allowFirstPseudos || !aFrame->IsXULBoxFrame(),
10129
0
               "can't be both block and box");
10130
0
10131
0
  if (haveFirstLetterStyle) {
10132
0
    WrapFramesInFirstLetterFrame(aFrame, aFrameItems);
10133
0
  }
10134
0
  if (haveFirstLineStyle) {
10135
0
    WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr,
10136
0
                               aFrameItems);
10137
0
  }
10138
0
10139
0
  // We might end up with first-line frames that change
10140
0
  // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
10141
0
  // should never happen for cases whan aFrame->IsXULBoxFrame().
10142
0
  NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsXULBoxFrame(),
10143
0
               "Shouldn't have first-line style if we're a box");
10144
0
  NS_ASSERTION(!aFrame->IsXULBoxFrame() ||
10145
0
               itemsToConstruct.AnyItemsNeedBlockParent() ==
10146
0
                 (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr),
10147
0
               "Something went awry in our block parent calculations");
10148
0
10149
0
  if (aFrame->IsXULBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
10150
0
    // XXXbz we could do this on the FrameConstructionItemList level,
10151
0
    // no?  And if we cared we could look through the item list
10152
0
    // instead of groveling through the framelist here..
10153
0
    ComputedStyle *frameComputedStyle = aFrame->Style();
10154
0
    // Report a warning for non-GC frames, for chrome:
10155
0
    if (!aFrame->IsGeneratedContentFrame() &&
10156
0
        mPresShell->GetPresContext()->IsChrome()) {
10157
0
      nsIContent *badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild());
10158
0
      nsDependentAtomString parentTag(aContent->NodeInfo()->NameAtom()),
10159
0
                            kidTag(badKid->NodeInfo()->NameAtom());
10160
0
      const char16_t* params[] = { parentTag.get(), kidTag.get() };
10161
0
      const nsStyleDisplay *display = frameComputedStyle->StyleDisplay();
10162
0
      const char *message =
10163
0
        (display->mDisplay == StyleDisplay::MozInlineBox)
10164
0
          ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
10165
0
      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
10166
0
                                      NS_LITERAL_CSTRING("Layout: FrameConstructor"),
10167
0
                                      mDocument,
10168
0
                                      nsContentUtils::eXUL_PROPERTIES,
10169
0
                                      message,
10170
0
                                      params, ArrayLength(params));
10171
0
    }
10172
0
10173
0
    RefPtr<ComputedStyle> blockSC = mPresShell->StyleSet()->
10174
0
      ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock(),
10175
0
                                         frameComputedStyle);
10176
0
    nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10177
0
    // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
10178
0
    // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
10179
0
    // a real block placed here wouldn't get those set on it.
10180
0
10181
0
    InitAndRestoreFrame(aState, aContent, aFrame, blockFrame, false);
10182
0
10183
0
    NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
10184
0
    ReparentFrames(this, blockFrame, aFrameItems, false);
10185
0
10186
0
    blockFrame->SetInitialChildList(kPrincipalList, aFrameItems);
10187
0
    NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?");
10188
0
    aFrameItems.Clear();
10189
0
    aFrameItems.AddChild(blockFrame);
10190
0
10191
0
    aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
10192
0
    MOZ_ASSERT(!aFrame->IsLeaf(),
10193
0
               "Why do we have an nsLeafBoxFrame here?");
10194
0
    aFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
10195
0
  }
10196
0
}
10197
10198
//----------------------------------------------------------------------
10199
10200
// Support for :first-line style
10201
10202
// Special routine to handle placing a list of frames into a block
10203
// frame that has first-line style. The routine ensures that the first
10204
// collection of inline frames end up in a first-line frame.
10205
// NOTE: aState may have containing block information related to a
10206
// different part of the frame tree than where the first line occurs.
10207
// In particular aState may be set up for where ContentInserted or
10208
// ContentAppended is inserting content, which may be some
10209
// non-first-in-flow continuation of the block to which the first-line
10210
// belongs. So this function needs to be careful about how it uses
10211
// aState.
10212
void
10213
nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
10214
  nsFrameConstructorState& aState,
10215
  nsIContent*              aBlockContent,
10216
  nsContainerFrame*        aBlockFrame,
10217
  nsFirstLineFrame*        aLineFrame,
10218
  nsFrameItems&            aFrameItems)
10219
0
{
10220
0
  // Extract any initial inline frames from aFrameItems so we can put them
10221
0
  // in the first-line.
10222
0
  nsFrameList firstLineChildren =
10223
0
    aFrameItems.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
10224
0
10225
0
  if (firstLineChildren.IsEmpty()) {
10226
0
    // Nothing is supposed to go into the first-line; nothing to do
10227
0
    return;
10228
0
  }
10229
0
10230
0
  if (!aLineFrame) {
10231
0
    // Create line frame
10232
0
    ComputedStyle* parentStyle =
10233
0
      nsFrame::CorrectStyleParentFrame(aBlockFrame,
10234
0
                                       nsCSSPseudoElements::firstLine())->
10235
0
        Style();
10236
0
    RefPtr<ComputedStyle> firstLineStyle = GetFirstLineStyle(aBlockContent,
10237
0
                                                                parentStyle);
10238
0
10239
0
    aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
10240
0
10241
0
    // Initialize the line frame
10242
0
    InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
10243
0
10244
0
    // The lineFrame will be the block's first child; the rest of the
10245
0
    // frame list (after lastInlineFrame) will be the second and
10246
0
    // subsequent children; insert lineFrame into aFrameItems.
10247
0
    aFrameItems.InsertFrame(nullptr, nullptr, aLineFrame);
10248
0
10249
0
    NS_ASSERTION(aLineFrame->Style() == firstLineStyle,
10250
0
                 "Bogus style on line frame");
10251
0
  }
10252
0
10253
0
  // Give the inline frames to the lineFrame <b>after</b> reparenting them
10254
0
  ReparentFrames(this, aLineFrame, firstLineChildren, true);
10255
0
  if (aLineFrame->PrincipalChildList().IsEmpty() &&
10256
0
      (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
10257
0
    aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren);
10258
0
  } else {
10259
0
    AppendFrames(aLineFrame, kPrincipalList, firstLineChildren);
10260
0
  }
10261
0
}
10262
10263
// Special routine to handle appending a new frame to a block frame's
10264
// child list. Takes care of placing the new frame into the right
10265
// place when first-line style is present.
10266
void
10267
nsCSSFrameConstructor::AppendFirstLineFrames(
10268
  nsFrameConstructorState& aState,
10269
  nsIContent*              aBlockContent,
10270
  nsContainerFrame*        aBlockFrame,
10271
  nsFrameItems&            aFrameItems)
10272
0
{
10273
0
  // It's possible that aBlockFrame needs to have a first-line frame
10274
0
  // created because it doesn't currently have any children.
10275
0
  const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
10276
0
  if (blockKids.IsEmpty()) {
10277
0
    WrapFramesInFirstLineFrame(aState, aBlockContent,
10278
0
                               aBlockFrame, nullptr, aFrameItems);
10279
0
    return;
10280
0
  }
10281
0
10282
0
  // Examine the last block child - if it's a first-line frame then
10283
0
  // appended frames need special treatment.
10284
0
  nsIFrame* lastBlockKid = blockKids.LastChild();
10285
0
  if (!lastBlockKid->IsLineFrame()) {
10286
0
    // No first-line frame at the end of the list, therefore there is
10287
0
    // an intervening block between any first-line frame the frames
10288
0
    // we are appending. Therefore, we don't need any special
10289
0
    // treatment of the appended frames.
10290
0
    return;
10291
0
  }
10292
0
10293
0
  nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
10294
0
  WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame,
10295
0
                             lineFrame, aFrameItems);
10296
0
}
10297
10298
void
10299
nsCSSFrameConstructor::CheckForFirstLineInsertion(nsIFrame* aParentFrame,
10300
                                                  nsFrameItems& aFrameItems)
10301
0
{
10302
0
  MOZ_ASSERT(aParentFrame->Style()->HasPseudoElementData(),
10303
0
             "Why were we called?");
10304
0
10305
0
  if (aFrameItems.IsEmpty()) {
10306
0
    // Happens often enough, with the caption stuff.  No need to do the ancestor
10307
0
    // walk here.
10308
0
    return;
10309
0
  }
10310
0
10311
0
  class RestyleManager* restyleManager = RestyleManager();
10312
0
10313
0
  // Check whether there's a ::first-line on the path up from aParentFrame.
10314
0
  // Note that we can't stop until we've run out of ancestors with
10315
0
  // pseudo-element data, because the first-letter might be somewhere way up the
10316
0
  // tree; in particular it might be past our containing block.
10317
0
  nsIFrame* ancestor = aParentFrame;
10318
0
  while (ancestor) {
10319
0
    if (!ancestor->Style()->HasPseudoElementData()) {
10320
0
      // We know we won't find a ::first-line now.
10321
0
      return;
10322
0
    }
10323
0
10324
0
    if (!ancestor->IsLineFrame()) {
10325
0
      ancestor = ancestor->GetParent();
10326
0
      continue;
10327
0
    }
10328
0
10329
0
    if (!ancestor->Style()->IsPseudoElement()) {
10330
0
      // This is a continuation lineframe, not the first line; no need to do
10331
0
      // anything to the styles.
10332
0
      return;
10333
0
    }
10334
0
10335
0
    // Fix up the styles of aFrameItems for ::first-line.
10336
0
    for (nsIFrame* f : aFrameItems) {
10337
0
      restyleManager->ReparentComputedStyleForFirstLine(f);
10338
0
    }
10339
0
    return;
10340
0
  }
10341
0
}
10342
10343
//----------------------------------------------------------------------
10344
10345
// First-letter support
10346
10347
// Determine how many characters in the text fragment apply to the
10348
// first letter
10349
static int32_t
10350
FirstLetterCount(const nsTextFragment* aFragment)
10351
0
{
10352
0
  int32_t count = 0;
10353
0
  int32_t firstLetterLength = 0;
10354
0
10355
0
  int32_t i, n = aFragment->GetLength();
10356
0
  for (i = 0; i < n; i++) {
10357
0
    char16_t ch = aFragment->CharAt(i);
10358
0
    // FIXME: take content language into account when deciding whitespace.
10359
0
    if (dom::IsSpaceCharacter(ch)) {
10360
0
      if (firstLetterLength) {
10361
0
        break;
10362
0
      }
10363
0
      count++;
10364
0
      continue;
10365
0
    }
10366
0
    // XXX I18n
10367
0
    if ((ch == '\'') || (ch == '\"')) {
10368
0
      if (firstLetterLength) {
10369
0
        break;
10370
0
      }
10371
0
      // keep looping
10372
0
      firstLetterLength = 1;
10373
0
    }
10374
0
    else {
10375
0
      count++;
10376
0
      break;
10377
0
    }
10378
0
  }
10379
0
10380
0
  return count;
10381
0
}
10382
10383
static bool
10384
NeedFirstLetterContinuation(nsIContent* aContent)
10385
0
{
10386
0
  MOZ_ASSERT(aContent, "null ptr");
10387
0
10388
0
  bool result = false;
10389
0
  if (aContent) {
10390
0
    const nsTextFragment* frag = aContent->GetText();
10391
0
    if (frag) {
10392
0
      int32_t flc = FirstLetterCount(frag);
10393
0
      int32_t tl = frag->GetLength();
10394
0
      if (flc < tl) {
10395
0
        result = true;
10396
0
      }
10397
0
    }
10398
0
  }
10399
0
  return result;
10400
0
}
10401
10402
static bool IsFirstLetterContent(nsIContent* aContent)
10403
0
{
10404
0
  return aContent->TextLength() &&
10405
0
         !aContent->TextIsOnlyWhitespace();
10406
0
}
10407
10408
/**
10409
 * Create a letter frame, only make it a floating frame.
10410
 */
10411
nsFirstLetterFrame*
10412
nsCSSFrameConstructor::CreateFloatingLetterFrame(
10413
  nsFrameConstructorState& aState,
10414
  nsIContent* aTextContent,
10415
  nsIFrame* aTextFrame,
10416
  nsContainerFrame* aParentFrame,
10417
  ComputedStyle* aParentComputedStyle,
10418
  ComputedStyle* aComputedStyle,
10419
  nsFrameItems& aResult)
10420
0
{
10421
0
  MOZ_ASSERT(aParentComputedStyle);
10422
0
10423
0
  nsFirstLetterFrame* letterFrame =
10424
0
    NS_NewFirstLetterFrame(mPresShell, aComputedStyle);
10425
0
  // We don't want to use a text content for a non-text frame (because we want
10426
0
  // its primary frame to be a text frame).
10427
0
  nsIContent* letterContent = aParentFrame->GetContent();
10428
0
  nsContainerFrame* containingBlock = aState.GetGeometricParent(
10429
0
    *aComputedStyle->StyleDisplay(), aParentFrame);
10430
0
  InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
10431
0
10432
0
  // Init the text frame to refer to the letter frame.
10433
0
  //
10434
0
  // Make sure we get a proper style for it (the one passed in is for the letter
10435
0
  // frame and will have the float property set on it; the text frame shouldn't
10436
0
  // have that set).
10437
0
  ServoStyleSet* styleSet = mPresShell->StyleSet();
10438
0
  RefPtr<ComputedStyle> textSC = styleSet->
10439
0
    ResolveStyleForText(aTextContent, aComputedStyle);
10440
0
  aTextFrame->SetComputedStyleWithoutNotification(textSC);
10441
0
  InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
10442
0
10443
0
  // And then give the text frame to the letter frame
10444
0
  SetInitialSingleChild(letterFrame, aTextFrame);
10445
0
10446
0
  // See if we will need to continue the text frame (does it contain
10447
0
  // more than just the first-letter text or not?) If it does, then we
10448
0
  // create (in advance) a continuation frame for it.
10449
0
  nsIFrame* nextTextFrame = nullptr;
10450
0
  if (NeedFirstLetterContinuation(aTextContent)) {
10451
0
    // Create continuation
10452
0
    nextTextFrame =
10453
0
      CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame);
10454
0
    RefPtr<ComputedStyle> newSC = styleSet->
10455
0
      ResolveStyleForText(aTextContent, aParentComputedStyle);
10456
0
    nextTextFrame->SetComputedStyle(newSC);
10457
0
  }
10458
0
10459
0
  NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
10460
0
  // Put the new float before any of the floats in the block we're doing
10461
0
  // first-letter for, that is, before any floats whose parent is
10462
0
  // containingBlock.
10463
0
  nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
10464
0
  while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) {
10465
0
    link.Next();
10466
0
  }
10467
0
10468
0
  aState.AddChild(letterFrame, aResult, letterContent, aParentFrame,
10469
0
                  false, true, false, true, link.PrevFrame());
10470
0
10471
0
  if (nextTextFrame) {
10472
0
    aResult.AddChild(nextTextFrame);
10473
0
  }
10474
0
10475
0
  return letterFrame;
10476
0
}
10477
10478
/**
10479
 * Create a new letter frame for aTextFrame. The letter frame will be
10480
 * a child of aParentFrame.
10481
 */
10482
void
10483
nsCSSFrameConstructor::CreateLetterFrame(nsContainerFrame* aBlockFrame,
10484
                                         nsContainerFrame* aBlockContinuation,
10485
                                         nsIContent* aTextContent,
10486
                                         nsContainerFrame* aParentFrame,
10487
                                         nsFrameItems& aResult)
10488
0
{
10489
0
  MOZ_ASSERT(aTextContent->IsText(), "aTextContent isn't text");
10490
0
  NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
10491
0
                 "Not a block frame?");
10492
0
10493
0
  // Get a ComputedStyle for the first-letter-frame.
10494
0
  //
10495
0
  // Keep this in sync with nsBlockFrame::UpdatePseudoElementStyles.
10496
0
  nsIFrame* parentFrame =
10497
0
    nsFrame::CorrectStyleParentFrame(aParentFrame,
10498
0
                                     nsCSSPseudoElements::firstLetter());
10499
0
10500
0
  ComputedStyle* parentComputedStyle = parentFrame->Style();
10501
0
10502
0
  // Use content from containing block so that we can actually
10503
0
  // find a matching style rule.
10504
0
  nsIContent* blockContent = aBlockFrame->GetContent();
10505
0
10506
0
  // Create first-letter style rule
10507
0
  RefPtr<ComputedStyle> sc =
10508
0
    GetFirstLetterStyle(blockContent, parentComputedStyle);
10509
0
10510
0
  if (sc) {
10511
0
    if (parentFrame->IsLineFrame()) {
10512
0
      nsIFrame* parentIgnoringFirstLine =
10513
0
        nsFrame::CorrectStyleParentFrame(aBlockFrame,
10514
0
                                         nsCSSPseudoElements::firstLetter());
10515
0
10516
0
      sc =
10517
0
        mPresShell->StyleSet()->ReparentComputedStyle(
10518
0
          sc,
10519
0
          parentComputedStyle,
10520
0
          parentIgnoringFirstLine->Style(),
10521
0
          parentComputedStyle,
10522
0
          blockContent->AsElement());
10523
0
    }
10524
0
10525
0
    RefPtr<ComputedStyle> textSC = mPresShell->StyleSet()->
10526
0
      ResolveStyleForText(aTextContent, sc);
10527
0
10528
0
    // Create a new text frame (the original one will be discarded)
10529
0
    // pass a temporary stylecontext, the correct one will be set
10530
0
    // later.  Start off by unsetting the primary frame for
10531
0
    // aTextContent, so it's no longer pointing to the to-be-destroyed
10532
0
    // frame.
10533
0
    // XXXbz it would be really nice to destroy the old frame _first_,
10534
0
    // then create the new one, so we could avoid this hack.
10535
0
    aTextContent->SetPrimaryFrame(nullptr);
10536
0
    nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
10537
0
10538
0
    NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
10539
0
                 "Containing block is confused");
10540
0
    nsFrameConstructorState state(mPresShell,
10541
0
                                  GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
10542
0
                                  GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
10543
0
                                  aBlockContinuation);
10544
0
10545
0
    // Create the right type of first-letter frame
10546
0
    const nsStyleDisplay* display = sc->StyleDisplay();
10547
0
    nsFirstLetterFrame* letterFrame;
10548
0
    if (display->IsFloatingStyle() &&
10549
0
        !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
10550
0
      // Make a floating first-letter frame
10551
0
      letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
10552
0
                                              aParentFrame, parentComputedStyle,
10553
0
                                              sc, aResult);
10554
0
    }
10555
0
    else {
10556
0
      // Make an inflow first-letter frame
10557
0
      letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
10558
0
10559
0
      // Initialize the first-letter-frame.  We don't want to use a text
10560
0
      // content for a non-text frame (because we want its primary frame to
10561
0
      // be a text frame).
10562
0
      nsIContent* letterContent = aParentFrame->GetContent();
10563
0
      letterFrame->Init(letterContent, aParentFrame, nullptr);
10564
0
10565
0
      InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
10566
0
10567
0
      SetInitialSingleChild(letterFrame, textFrame);
10568
0
      aResult.Clear();
10569
0
      aResult.AddChild(letterFrame);
10570
0
      NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
10571
0
                   "should have the first continuation here");
10572
0
      aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
10573
0
    }
10574
0
    MOZ_ASSERT(!aBlockFrame->GetPrevContinuation(),
10575
0
               "Setting up a first-letter frame on a non-first block continuation?");
10576
0
    auto parent = static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
10577
0
    parent->SetHasFirstLetterChild();
10578
0
    aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
10579
0
                             letterFrame);
10580
0
    aTextContent->SetPrimaryFrame(textFrame);
10581
0
  }
10582
0
}
10583
10584
void
10585
nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10586
  nsContainerFrame*        aBlockFrame,
10587
  nsFrameItems&            aBlockFrames)
10588
0
{
10589
0
  aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
10590
0
10591
0
  nsContainerFrame* parentFrame = nullptr;
10592
0
  nsIFrame* textFrame = nullptr;
10593
0
  nsIFrame* prevFrame = nullptr;
10594
0
  nsFrameItems letterFrames;
10595
0
  bool stopLooking = false;
10596
0
  WrapFramesInFirstLetterFrame(aBlockFrame, aBlockFrame, aBlockFrame,
10597
0
                               aBlockFrames.FirstChild(),
10598
0
                               &parentFrame, &textFrame, &prevFrame,
10599
0
                               letterFrames, &stopLooking);
10600
0
  if (parentFrame) {
10601
0
    if (parentFrame == aBlockFrame) {
10602
0
      // Take textFrame out of the block's frame list and substitute the
10603
0
      // letter frame(s) instead.
10604
0
      aBlockFrames.DestroyFrame(textFrame);
10605
0
      aBlockFrames.InsertFrames(nullptr, prevFrame, letterFrames);
10606
0
    }
10607
0
    else {
10608
0
      // Take the old textFrame out of the inline parent's child list
10609
0
      RemoveFrame(kPrincipalList, textFrame);
10610
0
10611
0
      // Insert in the letter frame(s)
10612
0
      parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
10613
0
    }
10614
0
  }
10615
0
}
10616
10617
void
10618
nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10619
  nsContainerFrame*        aBlockFrame,
10620
  nsContainerFrame*        aBlockContinuation,
10621
  nsContainerFrame*        aParentFrame,
10622
  nsIFrame*                aParentFrameList,
10623
  nsContainerFrame**       aModifiedParent,
10624
  nsIFrame**               aTextFrame,
10625
  nsIFrame**               aPrevFrame,
10626
  nsFrameItems&            aLetterFrames,
10627
  bool*                    aStopLooking)
10628
0
{
10629
0
  nsIFrame* prevFrame = nullptr;
10630
0
  nsIFrame* frame = aParentFrameList;
10631
0
10632
0
  while (frame) {
10633
0
    nsIFrame* nextFrame = frame->GetNextSibling();
10634
0
10635
0
    LayoutFrameType frameType = frame->Type();
10636
0
    if (LayoutFrameType::Text == frameType) {
10637
0
      // Wrap up first-letter content in a letter frame
10638
0
      nsIContent* textContent = frame->GetContent();
10639
0
      if (IsFirstLetterContent(textContent)) {
10640
0
        // Create letter frame to wrap up the text
10641
0
        CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
10642
0
                          aParentFrame, aLetterFrames);
10643
0
10644
0
        // Provide adjustment information for parent
10645
0
        *aModifiedParent = aParentFrame;
10646
0
        *aTextFrame = frame;
10647
0
        *aPrevFrame = prevFrame;
10648
0
        *aStopLooking = true;
10649
0
        return;
10650
0
      }
10651
0
    } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
10652
0
      nsIFrame* kids = frame->PrincipalChildList().FirstChild();
10653
0
      WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
10654
0
                                   static_cast<nsContainerFrame*>(frame),
10655
0
                                   kids, aModifiedParent, aTextFrame,
10656
0
                                   aPrevFrame, aLetterFrames, aStopLooking);
10657
0
      if (*aStopLooking) {
10658
0
        return;
10659
0
      }
10660
0
    }
10661
0
    else {
10662
0
      // This will stop us looking to create more letter frames. For
10663
0
      // example, maybe the frame-type is "letterFrame" or
10664
0
      // "placeholderFrame". This keeps us from creating extra letter
10665
0
      // frames, and also prevents us from creating letter frames when
10666
0
      // the first real content child of a block is not text (e.g. an
10667
0
      // image, hr, etc.)
10668
0
      *aStopLooking = true;
10669
0
      break;
10670
0
    }
10671
0
10672
0
    prevFrame = frame;
10673
0
    frame = nextFrame;
10674
0
  }
10675
0
}
10676
10677
static nsIFrame*
10678
FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID)
10679
0
{
10680
0
  nsFrameList list = aFrame->GetChildList(aListID);
10681
0
  for (nsFrameList::Enumerator e(list); !e.AtEnd(); e.Next()) {
10682
0
    if (e.get()->IsLetterFrame()) {
10683
0
      return e.get();
10684
0
    }
10685
0
  }
10686
0
  return nullptr;
10687
0
}
10688
10689
static void ClearHasFirstLetterChildFrom(nsContainerFrame* aParentFrame)
10690
0
{
10691
0
  MOZ_ASSERT(aParentFrame);
10692
0
  auto* parent =
10693
0
    static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
10694
0
  if (MOZ_UNLIKELY(parent->IsLineFrame())) {
10695
0
    parent = parent->GetParent();
10696
0
  }
10697
0
  MOZ_ASSERT(parent->HasFirstLetterChild());
10698
0
  parent->ClearHasFirstLetterChild();
10699
0
}
10700
10701
void
10702
nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
10703
  nsIPresShell* aPresShell,
10704
  nsIFrame* aBlockFrame)
10705
0
{
10706
0
  // Look for the first letter frame on the kFloatList, then kPushedFloatsList.
10707
0
  nsIFrame* floatFrame =
10708
0
    ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kFloatList);
10709
0
  if (!floatFrame) {
10710
0
    floatFrame =
10711
0
      ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList);
10712
0
    if (!floatFrame) {
10713
0
      return;
10714
0
    }
10715
0
  }
10716
0
10717
0
  // Take the text frame away from the letter frame (so it isn't
10718
0
  // destroyed when we destroy the letter frame).
10719
0
  nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
10720
0
  if (!textFrame) {
10721
0
    return;
10722
0
  }
10723
0
10724
0
  // Discover the placeholder frame for the letter frame
10725
0
  nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
10726
0
  if (!placeholderFrame) {
10727
0
    // Somethings really wrong
10728
0
    return;
10729
0
  }
10730
0
  nsContainerFrame* parentFrame = placeholderFrame->GetParent();
10731
0
  if (!parentFrame) {
10732
0
    // Somethings really wrong
10733
0
    return;
10734
0
  }
10735
0
10736
0
  ClearHasFirstLetterChildFrom(parentFrame);
10737
0
10738
0
  // Create a new text frame with the right style that maps all of the content
10739
0
  // that was previously part of the letter frame (and probably continued
10740
0
  // elsewhere).
10741
0
  ComputedStyle* parentSC = parentFrame->Style();
10742
0
  nsIContent* textContent = textFrame->GetContent();
10743
0
  if (!textContent) {
10744
0
    return;
10745
0
  }
10746
0
  RefPtr<ComputedStyle> newSC = aPresShell->StyleSet()->
10747
0
    ResolveStyleForText(textContent, parentSC);
10748
0
  nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
10749
0
  newTextFrame->Init(textContent, parentFrame, nullptr);
10750
0
10751
0
  // Destroy the old text frame's continuations (the old text frame
10752
0
  // will be destroyed when its letter frame is destroyed).
10753
0
  nsIFrame* frameToDelete = textFrame->LastContinuation();
10754
0
  while (frameToDelete != textFrame) {
10755
0
    nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
10756
0
    RemoveFrame(kPrincipalList, frameToDelete);
10757
0
    frameToDelete = nextFrameToDelete;
10758
0
  }
10759
0
10760
0
  nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
10761
0
10762
0
  // Now that everything is set...
10763
#ifdef NOISY_FIRST_LETTER
10764
  printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
10765
         textContent.get(), textFrame, newTextFrame);
10766
#endif
10767
10768
0
  // Remove placeholder frame and the float
10769
0
  RemoveFrame(kPrincipalList, placeholderFrame);
10770
0
10771
0
  // Now that the old frames are gone, we can start pointing to our
10772
0
  // new primary frame.
10773
0
  textContent->SetPrimaryFrame(newTextFrame);
10774
0
10775
0
  // Wallpaper bug 822910.
10776
0
  bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
10777
0
  if (offsetsNeedFixing) {
10778
0
    prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
10779
0
  }
10780
0
10781
0
  // Insert text frame in its place
10782
0
  nsFrameList textList(newTextFrame, newTextFrame);
10783
0
  InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
10784
0
10785
0
  if (offsetsNeedFixing) {
10786
0
    prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
10787
0
  }
10788
0
}
10789
10790
void
10791
nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell,
10792
                                               nsContainerFrame* aFrame,
10793
                                               nsContainerFrame* aBlockFrame,
10794
                                               bool* aStopLooking)
10795
0
{
10796
0
  nsIFrame* prevSibling = nullptr;
10797
0
  nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
10798
0
10799
0
  while (kid) {
10800
0
    if (kid->IsLetterFrame()) {
10801
0
      ClearHasFirstLetterChildFrom(aFrame);
10802
0
      nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
10803
0
      if (!textFrame) {
10804
0
        break;
10805
0
      }
10806
0
10807
0
      // Create a new textframe
10808
0
      ComputedStyle* parentSC = aFrame->Style();
10809
0
      if (!parentSC) {
10810
0
        break;
10811
0
      }
10812
0
      nsIContent* textContent = textFrame->GetContent();
10813
0
      if (!textContent) {
10814
0
        break;
10815
0
      }
10816
0
      RefPtr<ComputedStyle> newSC = aPresShell->StyleSet()->
10817
0
        ResolveStyleForText(textContent, parentSC);
10818
0
      textFrame = NS_NewTextFrame(aPresShell, newSC);
10819
0
      textFrame->Init(textContent, aFrame, nullptr);
10820
0
10821
0
      // Next rip out the kid and replace it with the text frame
10822
0
      RemoveFrame(kPrincipalList, kid);
10823
0
10824
0
      // Now that the old frames are gone, we can start pointing to our
10825
0
      // new primary frame.
10826
0
      textContent->SetPrimaryFrame(textFrame);
10827
0
10828
0
      // Wallpaper bug 822910.
10829
0
      bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
10830
0
      if (offsetsNeedFixing) {
10831
0
        prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
10832
0
      }
10833
0
10834
0
      // Insert text frame in its place
10835
0
      nsFrameList textList(textFrame, textFrame);
10836
0
      InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
10837
0
10838
0
      if (offsetsNeedFixing) {
10839
0
        prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
10840
0
      }
10841
0
10842
0
      *aStopLooking = true;
10843
0
      NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
10844
0
                   "should have the first continuation here");
10845
0
      aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
10846
0
      break;
10847
0
    }
10848
0
    else if (IsInlineFrame(kid)) {
10849
0
      nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
10850
0
      if (kidAsContainerFrame) {
10851
0
        // Look inside child inline frame for the letter frame.
10852
0
        RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame,
10853
0
                                aBlockFrame, aStopLooking);
10854
0
        if (*aStopLooking) {
10855
0
          break;
10856
0
        }
10857
0
      }
10858
0
    }
10859
0
    prevSibling = kid;
10860
0
    kid = kid->GetNextSibling();
10861
0
  }
10862
0
}
10863
10864
void
10865
nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
10866
                                          nsContainerFrame* aBlockFrame)
10867
0
{
10868
0
  aBlockFrame =
10869
0
    static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
10870
0
  aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
10871
0
  nsContainerFrame* continuation = aBlockFrame;
10872
0
10873
0
  bool stopLooking = false;
10874
0
  do {
10875
0
    RemoveFloatingFirstLetterFrames(aPresShell, continuation);
10876
0
    RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
10877
0
                            &stopLooking);
10878
0
    if (stopLooking) {
10879
0
      break;
10880
0
    }
10881
0
    continuation =
10882
0
      static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
10883
0
  }  while (continuation);
10884
0
}
10885
10886
// Fixup the letter frame situation for the given block
10887
void
10888
nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame)
10889
0
{
10890
0
  aBlockFrame =
10891
0
    static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
10892
0
  nsContainerFrame* continuation = aBlockFrame;
10893
0
10894
0
  nsContainerFrame* parentFrame = nullptr;
10895
0
  nsIFrame* textFrame = nullptr;
10896
0
  nsIFrame* prevFrame = nullptr;
10897
0
  nsFrameItems letterFrames;
10898
0
  bool stopLooking = false;
10899
0
  do {
10900
0
    // XXX shouldn't this bit be set already (bug 408493), assert instead?
10901
0
    continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
10902
0
    WrapFramesInFirstLetterFrame(aBlockFrame, continuation, continuation,
10903
0
                                 continuation->PrincipalChildList().FirstChild(),
10904
0
                                 &parentFrame, &textFrame, &prevFrame,
10905
0
                                 letterFrames, &stopLooking);
10906
0
    if (stopLooking) {
10907
0
      break;
10908
0
    }
10909
0
    continuation =
10910
0
      static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
10911
0
  } while (continuation);
10912
0
10913
0
  if (parentFrame) {
10914
0
    // Take the old textFrame out of the parent's child list
10915
0
    RemoveFrame(kPrincipalList, textFrame);
10916
0
10917
0
    // Insert in the letter frame(s)
10918
0
    parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
10919
0
  }
10920
0
}
10921
10922
//----------------------------------------------------------------------
10923
10924
nsContainerFrame*
10925
nsCSSFrameConstructor::InitAndWrapInColumnSetFrameIfNeeded(
10926
  nsFrameConstructorState& aState,
10927
  nsIContent* aContent,
10928
  nsContainerFrame* aParentFrame,
10929
  nsContainerFrame* aBlockFrame,
10930
  ComputedStyle* aComputedStyle)
10931
0
{
10932
0
  MOZ_ASSERT((aBlockFrame->IsBlockFrame() || aBlockFrame->IsDetailsFrame()),
10933
0
             "aBlock should either be a block frame or a details frame.");
10934
0
10935
0
  const nsStyleColumn* styleColumn = aComputedStyle->StyleColumn();
10936
0
10937
0
  if (styleColumn->mColumnCount == nsStyleColumn::kColumnCountAuto &&
10938
0
      styleColumn->mColumnWidth.GetUnit() == eStyleUnit_Auto) {
10939
0
    aBlockFrame->SetComputedStyleWithoutNotification(aComputedStyle);
10940
0
    InitAndRestoreFrame(aState, aContent, aParentFrame, aBlockFrame);
10941
0
    return aBlockFrame;
10942
0
  }
10943
0
10944
0
  // Wrap the block frame in a ColumnSetFrame.
10945
0
  nsContainerFrame* columnSetFrame =
10946
0
    NS_NewColumnSetFrame(mPresShell, aComputedStyle,
10947
0
                         nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10948
0
  InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
10949
0
  SetInitialSingleChild(columnSetFrame, aBlockFrame);
10950
0
10951
0
  RefPtr<ComputedStyle> anonBlockStyle = mPresShell->StyleSet()->
10952
0
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent(),
10953
0
                                       aComputedStyle);
10954
0
  aBlockFrame->SetComputedStyleWithoutNotification(anonBlockStyle);
10955
0
  InitAndRestoreFrame(aState, aContent, columnSetFrame, aBlockFrame);
10956
0
10957
0
  return columnSetFrame;
10958
0
}
10959
10960
void
10961
nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
10962
                                      nsIContent*              aContent,
10963
                                      nsContainerFrame*        aParentFrame,
10964
                                      nsContainerFrame*        aContentParentFrame,
10965
                                      ComputedStyle*          aComputedStyle,
10966
                                      nsContainerFrame**       aNewFrame,
10967
                                      nsFrameItems&            aFrameItems,
10968
                                      nsIFrame*                aPositionedFrameForAbsPosContainer,
10969
                                      PendingBinding*          aPendingBinding)
10970
0
{
10971
0
  // Create column wrapper if necessary
10972
0
  nsContainerFrame* blockFrame = *aNewFrame;
10973
0
  NS_ASSERTION((blockFrame->IsBlockFrame() || blockFrame->IsDetailsFrame()),
10974
0
               "not a block frame nor a details frame?");
10975
0
10976
0
  *aNewFrame =
10977
0
    InitAndWrapInColumnSetFrameIfNeeded(aState, aContent, aParentFrame,
10978
0
                                        blockFrame, aComputedStyle);
10979
0
10980
0
  if (blockFrame != *aNewFrame) {
10981
0
    // blockFrame is wrapped in nsColumnSetFrame.
10982
0
    if (aPositionedFrameForAbsPosContainer == blockFrame) {
10983
0
      aPositionedFrameForAbsPosContainer = *aNewFrame;
10984
0
    }
10985
0
  }
10986
0
10987
0
  aState.AddChild(*aNewFrame, aFrameItems, aContent,
10988
0
                  aContentParentFrame ? aContentParentFrame :
10989
0
                                        aParentFrame);
10990
0
  if (!mRootElementFrame) {
10991
0
    // The frame we're constructing will be the root element frame.
10992
0
    // Set mRootElementFrame before processing children.
10993
0
    mRootElementFrame = *aNewFrame;
10994
0
  }
10995
0
10996
0
  // We should make the outer frame be the absolute containing block,
10997
0
  // if one is required. We have to do this because absolute
10998
0
  // positioning must be computed with respect to the CSS dimensions
10999
0
  // of the element, which are the dimensions of the outer block. But
11000
0
  // we can't really do that because only blocks can have absolute
11001
0
  // children. So use the block and try to compensate with hacks
11002
0
  // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
11003
0
  nsFrameConstructorSaveState absoluteSaveState;
11004
0
  (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11005
0
  if (aPositionedFrameForAbsPosContainer) {
11006
0
    //    NS_ASSERTION(aRelPos, "should have made area frame for this");
11007
0
    aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
11008
0
  }
11009
0
11010
0
  // Process the child content
11011
0
  nsFrameItems childItems;
11012
0
  ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true,
11013
0
                  childItems, true, aPendingBinding);
11014
0
11015
0
  // Set the frame's initial child list
11016
0
  blockFrame->SetInitialChildList(kPrincipalList, childItems);
11017
0
}
11018
11019
nsIFrame*
11020
nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
11021
                                       FrameConstructionItem&   aItem,
11022
                                       nsContainerFrame*        aParentFrame,
11023
                                       const nsStyleDisplay*    aDisplay,
11024
                                       nsFrameItems&            aFrameItems)
11025
0
{
11026
0
  // If an inline frame has non-inline kids, then we chop up the child list
11027
0
  // into runs of blocks and runs of inlines, create anonymous block frames to
11028
0
  // contain the runs of blocks, inline frames with our style for the runs of
11029
0
  // inlines, and put all these frames, in order, into aFrameItems.
11030
0
  //
11031
0
  // We return the the first one.  The whole setup is called an {ib}
11032
0
  // split; in what follows "frames in the split" refers to the anonymous blocks
11033
0
  // and inlines that contain our children.
11034
0
  //
11035
0
  // {ib} splits maintain the following invariants:
11036
0
  // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
11037
0
  //    set.
11038
0
  // 2) Each frame in the split has the nsIFrame::IBSplitSibling
11039
0
  //    property pointing to the next frame in the split, except for the last
11040
0
  //    one, which does not have it set.
11041
0
  // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
11042
0
  //    property pointing to the previous frame in the split, except for the
11043
0
  //    first one, which does not have it set.
11044
0
  // 4) The first and last frame in the split are always inlines.
11045
0
  //
11046
0
  // An invariant that is NOT maintained is that the wrappers are actually
11047
0
  // linked via GetNextSibling linkage.  A simple example is an inline
11048
0
  // containing an inline that contains a block.  The three parts of the inner
11049
0
  // inline end up with three different parents.
11050
0
  //
11051
0
  // For example, this HTML:
11052
0
  // <span>
11053
0
  //   <div>a</div>
11054
0
  //   <span>
11055
0
  //     b
11056
0
  //     <div>c</div>
11057
0
  //   </span>
11058
0
  //   d
11059
0
  //   <div>e</div>
11060
0
  //   f
11061
0
  //  </span>
11062
0
  // Gives the following frame tree:
11063
0
  //
11064
0
  // Inline (outer span)
11065
0
  // Block (anonymous, outer span)
11066
0
  //   Block (div)
11067
0
  //     Text("a")
11068
0
  // Inline (outer span)
11069
0
  //   Inline (inner span)
11070
0
  //     Text("b")
11071
0
  // Block (anonymous, outer span)
11072
0
  //   Block (anonymous, inner span)
11073
0
  //     Block (div)
11074
0
  //       Text("c")
11075
0
  // Inline (outer span)
11076
0
  //   Inline (inner span)
11077
0
  //   Text("d")
11078
0
  // Block (anonymous, outer span)
11079
0
  //   Block (div)
11080
0
  //     Text("e")
11081
0
  // Inline (outer span)
11082
0
  //   Text("f")
11083
0
11084
0
  nsIContent* const content = aItem.mContent;
11085
0
  ComputedStyle* const computedStyle = aItem.mComputedStyle;
11086
0
11087
0
  nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
11088
0
11089
0
  // Initialize the frame
11090
0
  InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
11091
0
11092
0
  nsFrameConstructorSaveState absoluteSaveState;  // definition cannot be inside next block
11093
0
                                                  // because the object's destructor is significant
11094
0
                                                  // this is part of the fix for bug 42372
11095
0
11096
0
  bool isAbsPosCB = newFrame->IsAbsPosContainingBlock();
11097
0
  newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11098
0
  if (isAbsPosCB) {
11099
0
    // Relatively positioned frames becomes a container for child
11100
0
    // frames that are positioned
11101
0
    aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
11102
0
  }
11103
0
11104
0
  // Process the child content
11105
0
  nsFrameItems childItems;
11106
0
  ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
11107
0
                              /* aParentIsWrapperAnonBox = */ false,
11108
0
                              childItems);
11109
0
11110
0
  nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
11111
0
  if (!aItem.mIsAllInline) {
11112
0
    firstBlockEnumerator.Find(
11113
0
      [](nsIFrame* aFrame) { return !aFrame->IsInlineOutside(); });
11114
0
  }
11115
0
11116
0
  if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) {
11117
0
    // This part is easy.  We either already know we have no non-inline kids,
11118
0
    // or haven't found any when constructing actual frames (the latter can
11119
0
    // happen only if out-of-flows that we thought had no containing block
11120
0
    // acquired one when ancestor inline frames and {ib} splits got
11121
0
    // constructed).  Just put all the kids into the single inline frame and
11122
0
    // bail.
11123
0
    newFrame->SetInitialChildList(kPrincipalList, childItems);
11124
0
    aState.AddChild(newFrame, aFrameItems, content, aParentFrame);
11125
0
    return newFrame;
11126
0
  }
11127
0
11128
0
  // This inline frame contains several types of children. Therefore this frame
11129
0
  // has to be chopped into several pieces, as described above.
11130
0
11131
0
  // Grab the first inline's kids
11132
0
  nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
11133
0
  newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
11134
0
11135
0
  aFrameItems.AddChild(newFrame);
11136
0
11137
0
  newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
11138
0
  CreateIBSiblings(aState, newFrame, isAbsPosCB, childItems, aFrameItems);
11139
0
11140
0
  return newFrame;
11141
0
}
11142
11143
void
11144
nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
11145
                                        nsContainerFrame* aInitialInline,
11146
                                        bool aIsAbsPosCB,
11147
                                        nsFrameItems& aChildItems,
11148
                                        nsFrameItems& aSiblings)
11149
0
{
11150
0
  MOZ_ASSERT(aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock());
11151
0
11152
0
  nsIContent* content = aInitialInline->GetContent();
11153
0
  ComputedStyle* computedStyle = aInitialInline->Style();
11154
0
  nsContainerFrame* parentFrame = aInitialInline->GetParent();
11155
0
11156
0
  // Resolve the right style for our anonymous blocks.
11157
0
  //
11158
0
  // The distinction in styles is needed because of CSS 2.1, section
11159
0
  // 9.2.1.1, which says:
11160
0
  //
11161
0
  //   When such an inline box is affected by relative positioning, any
11162
0
  //   resulting translation also affects the block-level box contained
11163
0
  //   in the inline box.
11164
0
  RefPtr<ComputedStyle> blockSC = mPresShell->StyleSet()->
11165
0
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozBlockInsideInlineWrapper(),
11166
0
                                       computedStyle);
11167
0
11168
0
  nsContainerFrame* lastNewInline =
11169
0
    static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
11170
0
  do {
11171
0
    // On entry to this loop aChildItems is not empty and the first frame in it
11172
0
    // is block-level.
11173
0
    MOZ_ASSERT(aChildItems.NotEmpty(), "Should have child items");
11174
0
    MOZ_ASSERT(!aChildItems.FirstChild()->IsInlineOutside(),
11175
0
               "Must have list starting with block");
11176
0
11177
0
    // The initial run of blocks belongs to an anonymous block that we create
11178
0
    // right now. The anonymous block will be the parent of these block
11179
0
    // children of the inline.
11180
0
    nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
11181
0
    InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
11182
0
11183
0
    // Find the first non-block child which defines the end of our block kids
11184
0
    // and the start of our next inline's kids
11185
0
    nsFrameList blockKids =
11186
0
      aChildItems.Split([](nsIFrame* f) { return f->IsInlineOutside(); });
11187
0
    MoveChildrenTo(aInitialInline, blockFrame, blockKids);
11188
0
11189
0
    SetFrameIsIBSplit(lastNewInline, blockFrame);
11190
0
    aSiblings.AddChild(blockFrame);
11191
0
11192
0
    // Now grab the initial inlines in aChildItems and put them into an inline
11193
0
    // frame.
11194
0
    nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
11195
0
    InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
11196
0
    inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
11197
0
    if (aIsAbsPosCB) {
11198
0
      inlineFrame->MarkAsAbsoluteContainingBlock();
11199
0
    }
11200
0
11201
0
    if (aChildItems.NotEmpty()) {
11202
0
      nsFrameList inlineKids =
11203
0
        aChildItems.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
11204
0
      MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
11205
0
    }
11206
0
11207
0
    SetFrameIsIBSplit(blockFrame, inlineFrame);
11208
0
    aSiblings.AddChild(inlineFrame);
11209
0
    lastNewInline = inlineFrame;
11210
0
  } while (aChildItems.NotEmpty());
11211
0
11212
0
  SetFrameIsIBSplit(lastNewInline, nullptr);
11213
0
}
11214
11215
void
11216
nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
11217
                                             FrameConstructionItem& aParentItem,
11218
                                             bool aItemIsWithinSVGText,
11219
                                             bool aItemAllowsTextPathChild)
11220
0
{
11221
0
  // XXXbz should we preallocate aParentItem.mChildItems to some sane
11222
0
  // length?  Maybe even to parentContent->GetChildCount()?
11223
0
  nsFrameConstructorState::PendingBindingAutoPusher
11224
0
    pusher(aState, aParentItem.mPendingBinding);
11225
0
11226
0
  ComputedStyle* const parentComputedStyle = aParentItem.mComputedStyle;
11227
0
  nsIContent* const parentContent = aParentItem.mContent;
11228
0
11229
0
  if (!aItemIsWithinSVGText) {
11230
0
    // Probe for generated content before
11231
0
    CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
11232
0
                               *parentComputedStyle, CSSPseudoElementType::before,
11233
0
                               aParentItem.mChildItems);
11234
0
  }
11235
0
11236
0
  uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
11237
0
  if (aItemIsWithinSVGText) {
11238
0
    flags |= ITEM_IS_WITHIN_SVG_TEXT;
11239
0
  }
11240
0
  if (aItemAllowsTextPathChild &&
11241
0
      aParentItem.mContent->IsSVGElement(nsGkAtoms::a)) {
11242
0
    flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
11243
0
  }
11244
0
11245
0
  FlattenedChildIterator iter(parentContent);
11246
0
  for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
11247
0
    // Manually check for comments/PIs, since we don't have a frame to pass to
11248
0
    // AddFrameConstructionItems.  We know our parent is a non-replaced inline,
11249
0
    // so there is no need to do the NeedFrameFor check.
11250
0
    content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
11251
0
    if (content->IsComment() || content->IsProcessingInstruction()) {
11252
0
      continue;
11253
0
    }
11254
0
11255
0
    RefPtr<ComputedStyle> childContext = ResolveComputedStyle(content);
11256
0
    AddFrameConstructionItemsInternal(aState, content, nullptr,
11257
0
                                      iter.XBLInvolved(), childContext,
11258
0
                                      flags,
11259
0
                                      aParentItem.mChildItems);
11260
0
  }
11261
0
11262
0
  if (!aItemIsWithinSVGText) {
11263
0
    // Probe for generated content after
11264
0
    CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
11265
0
                               *parentComputedStyle,
11266
0
                               CSSPseudoElementType::after,
11267
0
                               aParentItem.mChildItems);
11268
0
  }
11269
0
11270
0
  aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
11271
0
}
11272
11273
// return whether it's ok to append (in the AppendFrames sense) to
11274
// aParentFrame if our nextSibling is aNextSibling.  aParentFrame must
11275
// be an ib-split inline.
11276
static bool
11277
IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
11278
0
{
11279
0
  MOZ_ASSERT(IsInlineFrame(aParentFrame), "Must have an inline parent here");
11280
0
11281
0
  do {
11282
0
    NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),
11283
0
                 "How is this not part of an ib-split?");
11284
0
    if (aNextSibling || aParentFrame->GetNextContinuation() ||
11285
0
        GetIBSplitSibling(aParentFrame)) {
11286
0
      return false;
11287
0
    }
11288
0
11289
0
    aNextSibling = aParentFrame->GetNextSibling();
11290
0
    aParentFrame = aParentFrame->GetParent();
11291
0
  } while (IsInlineFrame(aParentFrame));
11292
0
11293
0
  return true;
11294
0
}
11295
11296
bool
11297
nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
11298
                                           nsIFrame* aContainingBlock,
11299
                                           nsIFrame* aFrame,
11300
                                           FrameConstructionItemList& aItems,
11301
                                           bool aIsAppend,
11302
                                           nsIFrame* aPrevSibling)
11303
0
{
11304
0
  if (aItems.IsEmpty()) {
11305
0
    return false;
11306
0
  }
11307
0
11308
0
  // Before we go and append the frames, we must check for several
11309
0
  // special situations.
11310
0
11311
0
  // Situation #1 is a XUL frame that contains frames that are required
11312
0
  // to be wrapped in blocks.
11313
0
  if (aFrame->IsXULBoxFrame() &&
11314
0
      !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
11315
0
      aItems.AnyItemsNeedBlockParent()) {
11316
0
    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11317
0
    return true;
11318
0
  }
11319
0
11320
0
  nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
11321
0
11322
0
  // Situation #2 is a flex or grid container frame into which we're inserting
11323
0
  // new inline non-replaced children, adjacent to an existing anonymous
11324
0
  // flex or grid item.
11325
0
  LayoutFrameType frameType = aFrame->Type();
11326
0
  if (frameType == LayoutFrameType::FlexContainer ||
11327
0
      frameType == LayoutFrameType::GridContainer) {
11328
0
    FCItemIterator iter(aItems);
11329
0
11330
0
    // Check if we're adding to-be-wrapped content right *after* an existing
11331
0
    // anonymous flex or grid item (which would need to absorb this content).
11332
0
    const bool isLegacyBox = IsFlexContainerForLegacyBox(aFrame);
11333
0
    if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
11334
0
        iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
11335
0
      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11336
0
      return true;
11337
0
    }
11338
0
11339
0
    // Check if we're adding to-be-wrapped content right *before* an existing
11340
0
    // anonymous flex or grid item (which would need to absorb this content).
11341
0
    if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
11342
0
      // Jump to the last entry in the list
11343
0
      iter.SetToEnd();
11344
0
      iter.Prev();
11345
0
      if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
11346
0
        RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11347
0
        return true;
11348
0
      }
11349
0
    }
11350
0
  }
11351
0
11352
0
  // Situation #3 is an anonymous flex or grid item that's getting new children
11353
0
  // who don't want to be wrapped.
11354
0
  if (IsAnonymousFlexOrGridItem(aFrame)) {
11355
0
    AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
11356
0
11357
0
    // We need to push a null float containing block to be sure that
11358
0
    // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
11359
0
    // inserted content. (In particular, this is necessary in order for
11360
0
    // its "GetGeometricParent" call to return the correct result.)
11361
0
    // We're not honoring floats on this content because it has the
11362
0
    // _flex/grid container_ as its parent in the content tree.
11363
0
    nsFrameConstructorSaveState floatSaveState;
11364
0
    aState.PushFloatContainingBlock(nullptr, floatSaveState);
11365
0
11366
0
    FCItemIterator iter(aItems);
11367
0
    // Skip over things that _do_ need an anonymous flex item, because
11368
0
    // they're perfectly happy to go here -- they won't cause a reframe.
11369
0
    nsIFrame* containerFrame = aFrame->GetParent();
11370
0
    const bool isLegacyBox = IsFlexContainerForLegacyBox(containerFrame);
11371
0
    if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
11372
0
      // We hit something that _doesn't_ need an anonymous flex item!
11373
0
      // Rebuild the flex container to bust it out.
11374
0
      RecreateFramesForContent(containerFrame->GetContent(), InsertionKind::Async);
11375
0
      return true;
11376
0
    }
11377
0
11378
0
    // If we get here, then everything in |aItems| needs to be wrapped in
11379
0
    // an anonymous flex or grid item.  That's where it's already going - good!
11380
0
  }
11381
0
11382
0
  // Situation #4 is a ruby-related frame that's getting new children.
11383
0
  // The situation for ruby is complex, especially when interacting with
11384
0
  // spaces. It containes these two special cases apart from tables:
11385
0
  // 1) There are effectively three types of white spaces in ruby frames
11386
0
  //    we handle differently: leading/tailing/inter-level space,
11387
0
  //    inter-base/inter-annotation space, and inter-segment space.
11388
0
  //    These three types of spaces can be converted to each other when
11389
0
  //    their sibling changes.
11390
0
  // 2) The first effective child of a ruby frame must always be a ruby
11391
0
  //    base container. It should be created or destroyed accordingly.
11392
0
  if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
11393
0
      RubyUtils::IsRubyContainerBox(frameType)) {
11394
0
    // We want to optimize it better, and avoid reframing as much as
11395
0
    // possible. But given the cases above, and the fact that a ruby
11396
0
    // usually won't be very large, it should be fine to reframe it.
11397
0
    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11398
0
    return true;
11399
0
  }
11400
0
11401
0
  // Situation #5 is a case when table pseudo-frames don't work out right
11402
0
  ParentType parentType = GetParentType(aFrame);
11403
0
  // If all the kids want a parent of the type that aFrame is, then we're all
11404
0
  // set to go.  Indeed, there won't be any table pseudo-frames created between
11405
0
  // aFrame and the kids, so those won't need to be merged with any table
11406
0
  // pseudo-frames that might already be kids of aFrame.  If aFrame itself is a
11407
0
  // table pseudo-frame, then all the kids in this list would have wanted a
11408
0
  // frame of that type wrapping them anyway, so putting them inside it is ok.
11409
0
  if (!aItems.AllWantParentType(parentType)) {
11410
0
    // Don't give up yet.  If parentType is not eTypeBlock and the parent is
11411
0
    // not a generated content frame, then try filtering whitespace out of the
11412
0
    // list.
11413
0
    if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
11414
0
      // For leading whitespace followed by a kid that wants our parent type,
11415
0
      // there are four cases:
11416
0
      // 1) We have a previous sibling which is not a table pseudo.  That means
11417
0
      //    that previous sibling wanted a (non-block) parent of the type we're
11418
0
      //    looking at.  Then the whitespace comes between two table-internal
11419
0
      //    elements, so should be collapsed out.
11420
0
      // 2) We have a previous sibling which is a table pseudo.  It might have
11421
0
      //    kids who want this whitespace, so we need to reframe.
11422
0
      // 3) We have no previous sibling and our parent frame is not a table
11423
0
      //    pseudo.  That means that we'll be at the beginning of our actual
11424
0
      //    non-block-type parent, and the whitespace is OK to collapse out.
11425
0
      //    If something is ever inserted before us, it'll find our own parent
11426
0
      //    as its parent and if it's something that would care about the
11427
0
      //    whitespace it'll want a block parent, so it'll trigger a reframe at
11428
0
      //    that point.
11429
0
      // 4) We have no previous sibling and our parent frame is a table pseudo.
11430
0
      //    Need to reframe.
11431
0
      // All that is predicated on finding the correct previous sibling.  We
11432
0
      // might have to walk backwards along continuations from aFrame to do so.
11433
0
      //
11434
0
      // It's always OK to drop whitespace between any two items that want a
11435
0
      // parent of type parentType.
11436
0
      //
11437
0
      // For trailing whitespace preceded by a kid that wants our parent type,
11438
0
      // there are four cases:
11439
0
      // 1) We have a next sibling which is not a table pseudo.  That means
11440
0
      //    that next sibling wanted a (non-block) parent of the type we're
11441
0
      //    looking at.  Then the whitespace comes between two table-internal
11442
0
      //    elements, so should be collapsed out.
11443
0
      // 2) We have a next sibling which is a table pseudo.  It might have
11444
0
      //    kids who want this whitespace, so we need to reframe.
11445
0
      // 3) We have no next sibling and our parent frame is not a table
11446
0
      //    pseudo.  That means that we'll be at the end of our actual
11447
0
      //    non-block-type parent, and the whitespace is OK to collapse out.
11448
0
      //    If something is ever inserted after us, it'll find our own parent
11449
0
      //    as its parent and if it's something that would care about the
11450
0
      //    whitespace it'll want a block parent, so it'll trigger a reframe at
11451
0
      //    that point.
11452
0
      // 4) We have no next sibling and our parent frame is a table pseudo.
11453
0
      //    Need to reframe.
11454
0
      // All that is predicated on finding the correct next sibling.  We might
11455
0
      // have to walk forward along continuations from aFrame to do so.  That
11456
0
      // said, in the case when nextSibling is null at this point and aIsAppend
11457
0
      // is true, we know we're in case 3.  Furthermore, in that case we don't
11458
0
      // even have to worry about the table pseudo situation; we know our
11459
0
      // parent is not a table pseudo there.
11460
0
      FCItemIterator iter(aItems);
11461
0
      FCItemIterator start(iter);
11462
0
      do {
11463
0
        if (iter.SkipItemsWantingParentType(parentType)) {
11464
0
          break;
11465
0
        }
11466
0
11467
0
        // iter points to an item that wants a different parent.  If it's not
11468
0
        // whitespace, we're done; no more point scanning the list.
11469
0
        if (!iter.item().IsWhitespace(aState)) {
11470
0
          break;
11471
0
        }
11472
0
11473
0
        if (iter == start) {
11474
0
          // Leading whitespace.  How to handle this depends on our
11475
0
          // previous sibling and aFrame.  See the long comment above.
11476
0
          nsIFrame* prevSibling = aPrevSibling;
11477
0
          if (!prevSibling) {
11478
0
            // Try to find one after all
11479
0
            nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
11480
0
            while (parentPrevCont) {
11481
0
              prevSibling = parentPrevCont->GetChildList(kPrincipalList).LastChild();
11482
0
              if (prevSibling) {
11483
0
                break;
11484
0
              }
11485
0
              parentPrevCont = parentPrevCont->GetPrevContinuation();
11486
0
            }
11487
0
          };
11488
0
          if (prevSibling) {
11489
0
            if (IsTablePseudo(prevSibling)) {
11490
0
              // need to reframe
11491
0
              break;
11492
0
            }
11493
0
          } else if (IsTablePseudo(aFrame)) {
11494
0
            // need to reframe
11495
0
            break;
11496
0
          }
11497
0
        }
11498
0
11499
0
        FCItemIterator spaceEndIter(iter);
11500
0
        // Advance spaceEndIter past any whitespace
11501
0
        bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
11502
0
11503
0
        bool okToDrop;
11504
0
        if (trailingSpaces) {
11505
0
          // Trailing whitespace.  How to handle this depeds on aIsAppend, our
11506
0
          // next sibling and aFrame.  See the long comment above.
11507
0
          okToDrop = aIsAppend && !nextSibling;
11508
0
          if (!okToDrop) {
11509
0
            if (!nextSibling) {
11510
0
              // Try to find one after all
11511
0
              nsIFrame* parentNextCont = aFrame->GetNextContinuation();
11512
0
              while (parentNextCont) {
11513
0
                nextSibling = parentNextCont->PrincipalChildList().FirstChild();
11514
0
                if (nextSibling) {
11515
0
                  break;
11516
0
                }
11517
0
                parentNextCont = parentNextCont->GetNextContinuation();
11518
0
              }
11519
0
            }
11520
0
11521
0
            okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
11522
0
                       (!nextSibling && !IsTablePseudo(aFrame));
11523
0
          }
11524
#ifdef DEBUG
11525
          else {
11526
            NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
11527
          }
11528
#endif
11529
0
        } else {
11530
0
          okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
11531
0
        }
11532
0
11533
0
        if (okToDrop) {
11534
0
          iter.DeleteItemsTo(this, spaceEndIter);
11535
0
        } else {
11536
0
          // We're done: we don't want to drop the whitespace, and it has the
11537
0
          // wrong parent type.
11538
0
          break;
11539
0
        }
11540
0
11541
0
        // Now loop, since |iter| points to item right after the whitespace we
11542
0
        // removed.
11543
0
      } while (!iter.IsDone());
11544
0
    }
11545
0
11546
0
    // We might be able to figure out some sort of optimizations here, but they
11547
0
    // would have to depend on having a correct aPrevSibling and a correct next
11548
0
    // sibling.  For example, we can probably avoid reframing if none of
11549
0
    // aFrame, aPrevSibling, and next sibling are table pseudo-frames.  But it
11550
0
    // doesn't seem worth it to worry about that for now, especially since we
11551
0
    // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11552
0
    // this method.
11553
0
11554
0
    // aItems might have changed, so recheck the parent type thing.  In fact,
11555
0
    // it might be empty, so recheck that too.
11556
0
    if (aItems.IsEmpty()) {
11557
0
      return false;
11558
0
    }
11559
0
11560
0
    if (!aItems.AllWantParentType(parentType)) {
11561
0
      // Reframing aFrame->GetContent() is good enough, since the content of
11562
0
      // table pseudo-frames is the ancestor content.
11563
0
      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11564
0
      return true;
11565
0
    }
11566
0
  }
11567
0
11568
0
  // Now we have several cases involving {ib} splits.  Put them all in a
11569
0
  // do/while with breaks to take us to the "go and reconstruct" code.
11570
0
  do {
11571
0
    if (IsInlineFrame(aFrame)) {
11572
0
      if (aItems.AreAllItemsInline()) {
11573
0
        // We can just put the kids in.
11574
0
        return false;
11575
0
      }
11576
0
11577
0
      if (!IsFramePartOfIBSplit(aFrame)) {
11578
0
        // Need to go ahead and reconstruct.
11579
0
        break;
11580
0
      }
11581
0
11582
0
      // Now we're adding kids including some blocks to an inline part of an
11583
0
      // {ib} split.  If we plan to call AppendFrames, and don't have a next
11584
0
      // sibling for the new frames, and our parent is the last continuation of
11585
0
      // the last part of the {ib} split, and the same is true of all our
11586
0
      // ancestor inlines (they have no following continuations and they're the
11587
0
      // last part of their {ib} splits and we'd be adding to the end for all
11588
0
      // of them), then AppendFrames will handle things for us.  Bail out in
11589
0
      // that case.
11590
0
      if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
11591
0
        return false;
11592
0
      }
11593
0
11594
0
      // Need to reconstruct.
11595
0
      break;
11596
0
    }
11597
0
11598
0
    // Now we know we have a block parent.  If it's not part of an
11599
0
    // ib-split, we're all set.
11600
0
    if (!IsFramePartOfIBSplit(aFrame)) {
11601
0
      return false;
11602
0
    }
11603
0
11604
0
    // We're adding some kids to a block part of an {ib} split.  If all the
11605
0
    // kids are blocks, we don't need to reconstruct.
11606
0
    if (aItems.AreAllItemsBlock()) {
11607
0
      return false;
11608
0
    }
11609
0
11610
0
    // We might have some inline kids for this block.  Just fall out of the
11611
0
    // loop and reconstruct.
11612
0
  } while (0);
11613
0
11614
0
  // If we don't have a containing block, start with aFrame and look for one.
11615
0
  if (!aContainingBlock) {
11616
0
    aContainingBlock = aFrame;
11617
0
  }
11618
0
11619
0
  // To find the right block to reframe, just walk up the tree until we find a
11620
0
  // frame that is:
11621
0
  // 1)  Not part of an IB split
11622
0
  // 2)  Not a pseudo-frame
11623
0
  // 3)  Not an inline frame
11624
0
  // We're guaranteed to find one, since ComputedStyle::ApplyStyleFixups
11625
0
  // enforces that the root is display:none, display:table, or display:block.
11626
0
  // Note that walking up "too far" is OK in terms of correctness, even if it
11627
0
  // might be a little inefficient.  This is why we walk out of all
11628
0
  // pseudo-frames -- telling which ones are or are not OK to walk out of is
11629
0
  // too hard (and I suspect that we do in fact need to walk out of all of
11630
0
  // them).
11631
0
  while (IsFramePartOfIBSplit(aContainingBlock) ||
11632
0
         aContainingBlock->IsInlineOutside() ||
11633
0
         aContainingBlock->Style()->GetPseudo()) {
11634
0
    aContainingBlock = aContainingBlock->GetParent();
11635
0
    NS_ASSERTION(aContainingBlock,
11636
0
                 "Must have non-inline, non-ib-split, non-pseudo frame as "
11637
0
                 "root (or child of root, for a table root)!");
11638
0
  }
11639
0
11640
0
  // Tell parent of the containing block to reformulate the
11641
0
  // entire block. This is painful and definitely not optimal
11642
0
  // but it will *always* get the right answer.
11643
0
11644
0
  nsIContent* blockContent = aContainingBlock->GetContent();
11645
#ifdef DEBUG
11646
  if (gNoisyContentUpdates) {
11647
    printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
11648
           blockContent);
11649
  }
11650
#endif
11651
  RecreateFramesForContent(blockContent, InsertionKind::Async);
11652
0
  return true;
11653
0
}
11654
11655
void
11656
nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
11657
0
{
11658
0
11659
#ifdef DEBUG
11660
  // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
11661
  // so I want to see when it is happening!  Unfortunately, it is happening way to often because
11662
  // so much content on the web causes block-in-inline frame situations and we handle them
11663
  // very poorly
11664
  if (gNoisyContentUpdates) {
11665
    printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
11666
           aFrame);
11667
  }
11668
#endif
11669
11670
0
  // XXXbz how exactly would we get here while isReflowing anyway?  Should this
11671
0
  // whole test be ifdef DEBUG?
11672
0
  if (mPresShell->IsReflowLocked()) {
11673
0
    // don't ReframeContainingBlock, this will result in a crash
11674
0
    // if we remove a tree that's in reflow - see bug 121368 for testcase
11675
0
    NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
11676
0
    return;
11677
0
  }
11678
0
11679
0
  // Get the first "normal" ancestor of the target frame.
11680
0
  nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
11681
0
  if (containingBlock) {
11682
0
    // From here we look for the containing block in case the target
11683
0
    // frame is already a block (which can happen when an inline frame
11684
0
    // wraps some of its content in an anonymous block; see
11685
0
    // ConstructInline)
11686
0
11687
0
    // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
11688
0
    // GetIBContainingBlock works much better and provides the correct container in all cases
11689
0
    // so GetFloatContainingBlock(aFrame) has been removed
11690
0
11691
0
    // And get the containingBlock's content
11692
0
    if (nsIContent* blockContent = containingBlock->GetContent()) {
11693
#ifdef DEBUG
11694
      if (gNoisyContentUpdates) {
11695
        printf("  ==> blockContent=%p\n", blockContent);
11696
      }
11697
#endif
11698
      RecreateFramesForContent(blockContent->AsElement(), InsertionKind::Async);
11699
0
      return;
11700
0
    }
11701
0
  }
11702
0
11703
0
  // If we get here, we're screwed!
11704
0
  RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11705
0
                           InsertionKind::Async);
11706
0
}
11707
11708
void
11709
nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
11710
0
{
11711
0
  {
11712
0
    nsAutoScriptBlocker scriptBlocker;
11713
0
    nsFrameItems childItems;
11714
0
    nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
11715
0
    // We don't have a parent frame with a pending binding constructor here,
11716
0
    // so no need to worry about ordering of the kids' constructors with it.
11717
0
    // Pass null for the PendingBinding.
11718
0
    ProcessChildren(state, aFrame->GetContent(), aFrame->Style(),
11719
0
                    aFrame, false, childItems, false,
11720
0
                    nullptr);
11721
0
11722
0
    aFrame->SetInitialChildList(kPrincipalList, childItems);
11723
0
  }
11724
0
11725
0
#ifdef ACCESSIBILITY
11726
0
  if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
11727
0
    if (nsIContent* child = aFrame->GetContent()->GetFirstChild()) {
11728
0
      accService->ContentRangeInserted(mPresShell, child, nullptr);
11729
0
    }
11730
0
  }
11731
0
#endif
11732
0
11733
0
  // call XBL constructors after the frames are created
11734
0
  mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
11735
0
}
11736
11737
//////////////////////////////////////////////////////////
11738
// nsCSSFrameConstructor::FrameConstructionItem methods //
11739
//////////////////////////////////////////////////////////
11740
bool
11741
nsCSSFrameConstructor::
11742
FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const
11743
0
{
11744
0
  MOZ_ASSERT(aState.mCreatingExtraFrames ||
11745
0
             !mContent->GetPrimaryFrame(), "How did that happen?");
11746
0
  if (!mIsText) {
11747
0
    return false;
11748
0
  }
11749
0
  mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11750
0
                     NS_REFRAME_IF_WHITESPACE);
11751
0
  return mContent->TextIsOnlyWhitespace();
11752
0
}
11753
11754
//////////////////////////////////////////////////////////////
11755
// nsCSSFrameConstructor::FrameConstructionItemList methods //
11756
//////////////////////////////////////////////////////////////
11757
void
11758
nsCSSFrameConstructor::FrameConstructionItemList::
11759
AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta)
11760
0
{
11761
0
  MOZ_ASSERT(aDelta == 1 || aDelta == -1, "Unexpected delta");
11762
0
  mItemCount += aDelta;
11763
0
  if (aItem->mIsAllInline) {
11764
0
    mInlineCount += aDelta;
11765
0
  }
11766
0
  if (aItem->mIsBlock) {
11767
0
    mBlockCount += aDelta;
11768
0
  }
11769
0
  if (aItem->mIsLineParticipant) {
11770
0
    mLineParticipantCount += aDelta;
11771
0
  }
11772
0
  mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
11773
0
}
11774
11775
////////////////////////////////////////////////////////////////////////
11776
// nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11777
////////////////////////////////////////////////////////////////////////
11778
inline bool
11779
nsCSSFrameConstructor::FrameConstructionItemList::
11780
Iterator::SkipItemsWantingParentType(ParentType aParentType)
11781
0
{
11782
0
  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
11783
0
  while (item().DesiredParentType() == aParentType) {
11784
0
    Next();
11785
0
    if (IsDone()) {
11786
0
      return true;
11787
0
    }
11788
0
  }
11789
0
  return false;
11790
0
}
11791
11792
inline bool
11793
nsCSSFrameConstructor::FrameConstructionItemList::
11794
Iterator::SkipItemsNotWantingParentType(ParentType aParentType)
11795
0
{
11796
0
  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
11797
0
  while (item().DesiredParentType() != aParentType) {
11798
0
    Next();
11799
0
    if (IsDone()) {
11800
0
      return true;
11801
0
    }
11802
0
  }
11803
0
  return false;
11804
0
}
11805
11806
// Note: we implement -webkit-{inline-}box (and optionally -moz-{inline-}box)
11807
// using nsFlexContainerFrame, but we use different rules for what gets wrapped
11808
// in an anonymous flex item.
11809
bool
11810
nsCSSFrameConstructor::FrameConstructionItem::
11811
  NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
11812
                          bool aIsLegacyBox)
11813
0
{
11814
0
  if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
11815
0
    // This will be an inline non-replaced box.
11816
0
    return true;
11817
0
  }
11818
0
11819
0
  if (aIsLegacyBox) {
11820
0
    if (mComputedStyle->StyleDisplay()->IsInlineOutsideStyle()) {
11821
0
      // In an emulated legacy box, all inline-level content gets wrapped in an
11822
0
      // anonymous flex item.
11823
0
      return true;
11824
0
    }
11825
0
    if (mIsPopup ||
11826
0
        (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
11827
0
         aState.GetGeometricParent(*mComputedStyle->StyleDisplay(), nullptr))) {
11828
0
      // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
11829
0
      // placeholder which (because our container is an emulated legacy box)
11830
0
      // we'll need to wrap in an anonymous flex item.  So, we just treat
11831
0
      // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
11832
0
      // and then when we spawn the placeholder, it'll end up in the right
11833
0
      // spot.
11834
0
      return true;
11835
0
    }
11836
0
  }
11837
0
11838
0
  return false;
11839
0
}
11840
11841
inline bool
11842
nsCSSFrameConstructor::FrameConstructionItemList::
11843
Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
11844
  const nsFrameConstructorState& aState,
11845
  bool aIsLegacyBox)
11846
0
{
11847
0
  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
11848
0
  while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyBox)) {
11849
0
    Next();
11850
0
    if (IsDone()) {
11851
0
      return true;
11852
0
    }
11853
0
  }
11854
0
  return false;
11855
0
}
11856
11857
inline bool
11858
nsCSSFrameConstructor::FrameConstructionItemList::
11859
Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
11860
  const nsFrameConstructorState& aState,
11861
  bool aIsLegacyBox)
11862
0
{
11863
0
  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
11864
0
  while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyBox))) {
11865
0
    Next();
11866
0
    if (IsDone()) {
11867
0
      return true;
11868
0
    }
11869
0
  }
11870
0
  return false;
11871
0
}
11872
11873
inline bool
11874
nsCSSFrameConstructor::FrameConstructionItemList::
11875
Iterator::SkipItemsNotWantingRubyParent()
11876
0
{
11877
0
  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
11878
0
  while (!IsRubyParentType(item().DesiredParentType())) {
11879
0
    Next();
11880
0
    if (IsDone()) {
11881
0
      return true;
11882
0
    }
11883
0
  }
11884
0
  return false;
11885
0
}
11886
11887
inline bool
11888
nsCSSFrameConstructor::FrameConstructionItemList::
11889
Iterator::SkipWhitespace(nsFrameConstructorState& aState)
11890
0
{
11891
0
  MOZ_ASSERT(!IsDone(), "Shouldn't be done yet");
11892
0
  MOZ_ASSERT(item().IsWhitespace(aState), "Not pointing to whitespace?");
11893
0
  do {
11894
0
    Next();
11895
0
    if (IsDone()) {
11896
0
      return true;
11897
0
    }
11898
0
  } while (item().IsWhitespace(aState));
11899
0
11900
0
  return false;
11901
0
}
11902
11903
void
11904
nsCSSFrameConstructor::FrameConstructionItemList::
11905
Iterator::AppendItemToList(FrameConstructionItemList& aTargetList)
11906
0
{
11907
0
  NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
11908
0
  MOZ_ASSERT(!IsDone(), "should not be done");
11909
0
11910
0
  FrameConstructionItem* item = mCurrent;
11911
0
  Next();
11912
0
  item->remove();
11913
0
  aTargetList.mItems.insertBack(item);
11914
0
11915
0
  mList.AdjustCountsForItem(item, -1);
11916
0
  aTargetList.AdjustCountsForItem(item, 1);
11917
0
}
11918
11919
void
11920
nsCSSFrameConstructor::FrameConstructionItemList::
11921
Iterator::AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
11922
                            FrameConstructionItemList& aTargetList)
11923
0
{
11924
0
  NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
11925
0
  MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?");
11926
0
11927
0
  // We can't just move our guts to the other list if it already has
11928
0
  // some information or if we're not moving our entire list.
11929
0
  if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
11930
0
    do {
11931
0
      AppendItemToList(aTargetList);
11932
0
    } while (*this != aEnd);
11933
0
    return;
11934
0
  }
11935
0
11936
0
  // Move our entire list of items into the empty target list.
11937
0
  aTargetList.mItems = std::move(mList.mItems);
11938
0
11939
0
  // Copy over the various counters
11940
0
  aTargetList.mInlineCount = mList.mInlineCount;
11941
0
  aTargetList.mBlockCount = mList.mBlockCount;
11942
0
  aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
11943
0
  aTargetList.mItemCount = mList.mItemCount;
11944
0
  memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
11945
0
         sizeof(aTargetList.mDesiredParentCounts));
11946
0
11947
0
  // reset mList
11948
0
  mList.Reset(aFCtor);
11949
0
11950
0
  // Point ourselves to aEnd, as advertised
11951
0
  SetToEnd();
11952
0
  MOZ_ASSERT(*this == aEnd, "How did that happen?");
11953
0
}
11954
11955
void
11956
nsCSSFrameConstructor::FrameConstructionItemList::
11957
Iterator::InsertItem(FrameConstructionItem* aItem)
11958
0
{
11959
0
  if (IsDone()) {
11960
0
    mList.mItems.insertBack(aItem);
11961
0
  } else {
11962
0
    // Just insert the item before us.  There's no magic here.
11963
0
    mCurrent->setPrevious(aItem);
11964
0
  }
11965
0
  mList.AdjustCountsForItem(aItem, 1);
11966
0
11967
0
  MOZ_ASSERT(aItem->getNext() == mCurrent, "How did that happen?");
11968
0
}
11969
11970
void
11971
nsCSSFrameConstructor::FrameConstructionItemList::
11972
Iterator::DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd)
11973
0
{
11974
0
  MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?");
11975
0
  MOZ_ASSERT(*this != aEnd, "Shouldn't be at aEnd yet");
11976
0
11977
0
  do {
11978
0
    NS_ASSERTION(!IsDone(), "Ran off end of list?");
11979
0
    FrameConstructionItem* item = mCurrent;
11980
0
    Next();
11981
0
    item->remove();
11982
0
    mList.AdjustCountsForItem(item, -1);
11983
0
    item->Delete(aFCtor);
11984
0
  } while (*this != aEnd);
11985
0
}
11986
11987
void
11988
nsCSSFrameConstructor::QuotesDirty()
11989
0
{
11990
0
  mQuotesDirty = true;
11991
0
  mPresShell->SetNeedLayoutFlush();
11992
0
}
11993
11994
void
11995
nsCSSFrameConstructor::CountersDirty()
11996
0
{
11997
0
  mCountersDirty = true;
11998
0
  mPresShell->SetNeedLayoutFlush();
11999
0
}
12000
12001
void*
12002
nsCSSFrameConstructor::AllocateFCItem()
12003
0
{
12004
0
  void* item;
12005
0
  if (mFirstFreeFCItem) {
12006
0
    item = mFirstFreeFCItem;
12007
0
    mFirstFreeFCItem = mFirstFreeFCItem->mNext;
12008
0
  } else {
12009
0
    item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
12010
0
  }
12011
0
  ++mFCItemsInUse;
12012
0
  return item;
12013
0
}
12014
12015
void
12016
nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem)
12017
0
{
12018
0
  MOZ_ASSERT(mFCItemsInUse != 0);
12019
0
  if (--mFCItemsInUse == 0) {
12020
0
    // The arena is now unused - clear it but retain one chunk.
12021
0
    mFirstFreeFCItem = nullptr;
12022
0
    mFCItemPool.Clear();
12023
0
  } else {
12024
0
    // Prepend it to the list of free items.
12025
0
    FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
12026
0
    item->mNext = mFirstFreeFCItem;
12027
0
    mFirstFreeFCItem = item;
12028
0
  }
12029
0
}
12030
12031
void
12032
nsCSSFrameConstructor::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
12033
0
{
12034
0
  if (nsIFrame* rootFrame = GetRootFrame()) {
12035
0
    rootFrame->AddSizeOfExcludingThisForTree(aSizes);
12036
0
  }
12037
0
12038
0
  // This must be done after measuring from the frame tree, since frame
12039
0
  // manager will measure sizes of staled computed values and style
12040
0
  // structs, which only make sense after we know what are being used.
12041
0
  nsFrameManager::AddSizeOfIncludingThis(aSizes);
12042
0
12043
0
  // Measurement of the following members may be added later if DMD finds it
12044
0
  // is worthwhile:
12045
0
  // - mFCItemPool
12046
0
  // - mQuoteList
12047
0
  // - mCounterManager
12048
0
}