Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/nsInlineFrame.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
/* rendering object for CSS display:inline objects */
8
9
#include "nsInlineFrame.h"
10
11
#include "gfxContext.h"
12
#include "nsLineLayout.h"
13
#include "nsBlockFrame.h"
14
#include "nsPlaceholderFrame.h"
15
#include "nsGkAtoms.h"
16
#include "nsPresContext.h"
17
#include "nsCSSAnonBoxes.h"
18
#include "mozilla/RestyleManager.h"
19
#include "nsDisplayList.h"
20
#include "mozilla/Likely.h"
21
#include "SVGTextFrame.h"
22
#include "nsStyleChangeList.h"
23
#include "mozilla/ComputedStyle.h"
24
#include "mozilla/ServoStyleSet.h"
25
26
#ifdef DEBUG
27
#undef NOISY_PUSHING
28
#endif
29
30
using namespace mozilla;
31
using namespace mozilla::layout;
32
33
34
//////////////////////////////////////////////////////////////////////
35
36
// Basic nsInlineFrame methods
37
38
nsInlineFrame*
39
NS_NewInlineFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
40
0
{
41
0
  return new (aPresShell) nsInlineFrame(aStyle);
42
0
}
43
44
NS_IMPL_FRAMEARENA_HELPERS(nsInlineFrame)
45
46
0
NS_QUERYFRAME_HEAD(nsInlineFrame)
47
0
  NS_QUERYFRAME_ENTRY(nsInlineFrame)
48
0
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
49
50
#ifdef DEBUG_FRAME_DUMP
51
nsresult
52
nsInlineFrame::GetFrameName(nsAString& aResult) const
53
{
54
  return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult);
55
}
56
#endif
57
58
void
59
nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey, bool aRebuildDisplayItems)
60
0
{
61
0
  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
62
0
    nsIFrame* svgTextFrame = nsLayoutUtils::GetClosestFrameOfType(
63
0
      GetParent(), LayoutFrameType::SVGText);
64
0
    svgTextFrame->InvalidateFrame();
65
0
    return;
66
0
  }
67
0
  nsContainerFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
68
0
}
69
70
void
71
nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey, bool aRebuildDisplayItems)
72
0
{
73
0
  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
74
0
    nsIFrame* svgTextFrame = nsLayoutUtils::GetClosestFrameOfType(
75
0
      GetParent(), LayoutFrameType::SVGText);
76
0
    svgTextFrame->InvalidateFrame();
77
0
    return;
78
0
  }
79
0
  nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey, aRebuildDisplayItems);
80
0
}
81
82
static inline bool
83
IsMarginZero(const nsStyleCoord &aCoord)
84
0
{
85
0
  return aCoord.GetUnit() == eStyleUnit_Auto ||
86
0
         nsLayoutUtils::IsMarginZero(aCoord);
87
0
}
88
89
/* virtual */ bool
90
nsInlineFrame::IsSelfEmpty()
91
0
{
92
#if 0
93
  // I used to think inline frames worked this way, but it seems they
94
  // don't.  At least not in our codebase.
95
  if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
96
    return false;
97
  }
98
#endif
99
  const nsStyleMargin* margin = StyleMargin();
100
0
  const nsStyleBorder* border = StyleBorder();
101
0
  const nsStylePadding* padding = StylePadding();
102
0
  // Block-start and -end ignored, since they shouldn't affect things, but this
103
0
  // doesn't really match with nsLineLayout.cpp's setting of
104
0
  // ZeroEffectiveSpanBox, anymore, so what should this really be?
105
0
  WritingMode wm = GetWritingMode();
106
0
  bool haveStart, haveEnd;
107
0
  // Initially set up haveStart and haveEnd in terms of visual (LTR/TTB)
108
0
  // coordinates; we'll exchange them later if bidi-RTL is in effect to
109
0
  // get logical start and end flags.
110
0
  if (wm.IsVertical()) {
111
0
    haveStart =
112
0
      border->GetComputedBorderWidth(eSideTop) != 0 ||
113
0
      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetTop()) ||
114
0
      !IsMarginZero(margin->mMargin.GetTop());
115
0
    haveEnd =
116
0
      border->GetComputedBorderWidth(eSideBottom) != 0 ||
117
0
      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBottom()) ||
118
0
      !IsMarginZero(margin->mMargin.GetBottom());
119
0
  } else {
120
0
    haveStart =
121
0
      border->GetComputedBorderWidth(eSideLeft) != 0 ||
122
0
      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
123
0
      !IsMarginZero(margin->mMargin.GetLeft());
124
0
    haveEnd =
125
0
      border->GetComputedBorderWidth(eSideRight) != 0 ||
126
0
      !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
127
0
      !IsMarginZero(margin->mMargin.GetRight());
128
0
  }
129
0
  if (haveStart || haveEnd) {
130
0
    // We skip this block and return false for box-decoration-break:clone since
131
0
    // in that case all the continuations will have the border/padding/margin.
132
0
    if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
133
0
        StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Slice) {
134
0
      // When direction=rtl, we need to consider logical rather than visual
135
0
      // start and end, so swap the flags.
136
0
      if (!wm.IsBidiLTR()) {
137
0
        Swap(haveStart, haveEnd);
138
0
      }
139
0
      // For ib-split frames, ignore things we know we'll skip in GetSkipSides.
140
0
      // XXXbz should we be doing this for non-ib-split frames too, in a more
141
0
      // general way?
142
0
143
0
      // Get the first continuation eagerly, as a performance optimization, to
144
0
      // avoid having to get it twice..
145
0
      nsIFrame* firstCont = FirstContinuation();
146
0
      return
147
0
        (!haveStart || firstCont->FrameIsNonFirstInIBSplit()) &&
148
0
        (!haveEnd || firstCont->FrameIsNonLastInIBSplit());
149
0
    }
150
0
    return false;
151
0
  }
152
0
  return true;
153
0
}
154
155
bool
156
nsInlineFrame::IsEmpty()
157
0
{
158
0
  if (!IsSelfEmpty()) {
159
0
    return false;
160
0
  }
161
0
162
0
  for (nsIFrame* kid : mFrames) {
163
0
    if (!kid->IsEmpty())
164
0
      return false;
165
0
  }
166
0
167
0
  return true;
168
0
}
169
170
nsIFrame::FrameSearchResult
171
nsInlineFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
172
                                   PeekOffsetCharacterOptions aOptions)
173
0
{
174
0
  // Override the implementation in nsFrame, to skip empty inline frames
175
0
  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
176
0
  int32_t startOffset = *aOffset;
177
0
  if (startOffset < 0)
178
0
    startOffset = 1;
179
0
  if (aForward == (startOffset == 0)) {
180
0
    // We're before the frame and moving forward, or after it and moving backwards:
181
0
    // skip to the other side, but keep going.
182
0
    *aOffset = 1 - startOffset;
183
0
  }
184
0
  return CONTINUE;
185
0
}
186
187
void
188
nsInlineFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
189
0
{
190
0
  nsFrameList* overflowFrames = GetOverflowFrames();
191
0
  if (overflowFrames) {
192
0
    // Fixup the parent pointers for any child frames on the OverflowList.
193
0
    // nsIFrame::DestroyFrom depends on that to find the sticky scroll
194
0
    // container (an ancestor).
195
0
    overflowFrames->ApplySetParent(this);
196
0
  }
197
0
  nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
198
0
}
199
200
nsresult
201
nsInlineFrame::StealFrame(nsIFrame* aChild)
202
0
{
203
0
  if (MaybeStealOverflowContainerFrame(aChild)) {
204
0
    return NS_OK;
205
0
  }
206
0
207
0
  nsInlineFrame* parent = this;
208
0
  bool removed = false;
209
0
  do {
210
0
    removed = parent->mFrames.StartRemoveFrame(aChild);
211
0
    if (removed) {
212
0
      break;
213
0
    }
214
0
215
0
    // We didn't find the child in our principal child list.
216
0
    // Maybe it's on the overflow list?
217
0
    nsFrameList* frameList = parent->GetOverflowFrames();
218
0
    if (frameList) {
219
0
      removed = frameList->ContinueRemoveFrame(aChild);
220
0
      if (frameList->IsEmpty()) {
221
0
        parent->DestroyOverflowList();
222
0
      }
223
0
      if (removed) {
224
0
        break;
225
0
      }
226
0
    }
227
0
228
0
    // Due to our "lazy reparenting" optimization 'aChild' might not actually
229
0
    // be on any of our child lists, but instead in one of our next-in-flows.
230
0
    parent = static_cast<nsInlineFrame*>(parent->GetNextInFlow());
231
0
  } while (parent);
232
0
233
0
  MOZ_ASSERT(removed, "nsInlineFrame::StealFrame: can't find aChild");
234
0
  return removed ? NS_OK : NS_ERROR_UNEXPECTED;
235
0
}
236
237
void
238
nsInlineFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
239
                                const nsDisplayListSet& aLists)
240
0
{
241
0
  BuildDisplayListForInline(aBuilder, aLists);
242
0
243
0
  // The sole purpose of this is to trigger display of the selection
244
0
  // window for Named Anchors, which don't have any children and
245
0
  // normally don't have any size, but in Editor we use CSS to display
246
0
  // an image to represent this "hidden" element.
247
0
  if (!mFrames.FirstChild()) {
248
0
    DisplaySelectionOverlay(aBuilder, aLists.Content());
249
0
  }
250
0
}
251
252
//////////////////////////////////////////////////////////////////////
253
// Reflow methods
254
255
/* virtual */ void
256
nsInlineFrame::AddInlineMinISize(gfxContext *aRenderingContext,
257
                                 nsIFrame::InlineMinISizeData *aData)
258
0
{
259
0
  DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::MIN_ISIZE);
260
0
}
261
262
/* virtual */ void
263
nsInlineFrame::AddInlinePrefISize(gfxContext *aRenderingContext,
264
                                  nsIFrame::InlinePrefISizeData *aData)
265
0
{
266
0
  DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::PREF_ISIZE);
267
0
  aData->mLineIsEmpty = false;
268
0
}
269
270
/* virtual */
271
LogicalSize
272
nsInlineFrame::ComputeSize(gfxContext *aRenderingContext,
273
                           WritingMode aWM,
274
                           const LogicalSize& aCBSize,
275
                           nscoord aAvailableISize,
276
                           const LogicalSize& aMargin,
277
                           const LogicalSize& aBorder,
278
                           const LogicalSize& aPadding,
279
                           ComputeSizeFlags aFlags)
280
0
{
281
0
  // Inlines and text don't compute size before reflow.
282
0
  return LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
283
0
}
284
285
nsRect
286
nsInlineFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
287
0
{
288
0
  // be conservative
289
0
  if (Style()->HasTextDecorationLines()) {
290
0
    return GetVisualOverflowRect();
291
0
  }
292
0
  return ComputeSimpleTightBounds(aDrawTarget);
293
0
}
294
295
static void
296
ReparentChildListStyle(nsPresContext* aPresContext,
297
                       const nsFrameList::Slice& aFrames,
298
                       nsIFrame* aParentFrame)
299
0
{
300
0
  RestyleManager* restyleManager = aPresContext->RestyleManager();
301
0
302
0
  for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
303
0
    NS_ASSERTION(e.get()->GetParent() == aParentFrame, "Bogus parentage");
304
0
    restyleManager->ReparentComputedStyleForFirstLine(e.get());
305
0
    nsLayoutUtils::MarkDescendantsDirty(e.get());
306
0
  }
307
0
}
308
309
void
310
nsInlineFrame::Reflow(nsPresContext*          aPresContext,
311
                      ReflowOutput&     aMetrics,
312
                      const ReflowInput& aReflowInput,
313
                      nsReflowStatus&          aStatus)
314
0
{
315
0
  MarkInReflow();
316
0
  DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
317
0
  DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
318
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
319
0
320
0
  if (nullptr == aReflowInput.mLineLayout) {
321
0
    NS_ERROR("must have non-null aReflowInput.mLineLayout");
322
0
    return;
323
0
  }
324
0
  if (IsFrameTreeTooDeep(aReflowInput, aMetrics, aStatus)) {
325
0
    return;
326
0
  }
327
0
328
0
  bool lazilySetParentPointer = false;
329
0
330
0
   // Check for an overflow list with our prev-in-flow
331
0
  nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow();
332
0
  if (prevInFlow) {
333
0
    AutoFrameListPtr prevOverflowFrames(aPresContext,
334
0
                                        prevInFlow->StealOverflowFrames());
335
0
    if (prevOverflowFrames) {
336
0
      // When pushing and pulling frames we need to check for whether any
337
0
      // views need to be reparented.
338
0
      nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow,
339
0
                                              this);
340
0
341
0
      // Check if we should do the lazilySetParentPointer optimization.
342
0
      // Only do it in simple cases where we're being reflowed for the
343
0
      // first time, nothing (e.g. bidi resolution) has already given
344
0
      // us children, and there's no next-in-flow, so all our frames
345
0
      // will be taken from prevOverflowFrames.
346
0
      if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() &&
347
0
          !GetNextInFlow()) {
348
0
        // If our child list is empty, just put the new frames into it.
349
0
        // Note that we don't set the parent pointer for the new frames. Instead wait
350
0
        // to do this until we actually reflow the frame. If the overflow list contains
351
0
        // thousands of frames this is a big performance issue (see bug #5588)
352
0
        mFrames.SetFrames(*prevOverflowFrames);
353
0
        lazilySetParentPointer = true;
354
0
      } else {
355
0
        // Insert the new frames at the beginning of the child list
356
0
        // and set their parent pointer
357
0
        const nsFrameList::Slice& newFrames =
358
0
          mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
359
0
        // If our prev in flow was under the first continuation of a first-line
360
0
        // frame then we need to reparent the ComputedStyles to remove the
361
0
        // the special first-line styling. In the lazilySetParentPointer case
362
0
        // we reparent the ComputedStyles when we set their parents in
363
0
        // nsInlineFrame::ReflowFrames and nsInlineFrame::ReflowInlineFrame.
364
0
        if (aReflowInput.mLineLayout->GetInFirstLine()) {
365
0
          ReparentChildListStyle(aPresContext, newFrames, this);
366
0
        }
367
0
      }
368
0
    }
369
0
  }
370
0
371
0
  // It's also possible that we have an overflow list for ourselves
372
#ifdef DEBUG
373
  if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
374
    // If it's our initial reflow, then we should not have an overflow list.
375
    // However, add an assertion in case we get reflowed more than once with
376
    // the initial reflow reason
377
    nsFrameList* overflowFrames = GetOverflowFrames();
378
    NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(),
379
                 "overflow list is not empty for initial reflow");
380
  }
381
#endif
382
0
  if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
383
0
    DrainSelfOverflowListInternal(aReflowInput.mLineLayout->GetInFirstLine());
384
0
  }
385
0
386
0
  // Set our own reflow state (additional state above and beyond aReflowInput).
387
0
  InlineReflowInput irs;
388
0
  irs.mPrevFrame = nullptr;
389
0
  irs.mLineContainer = aReflowInput.mLineLayout->LineContainerFrame();
390
0
  irs.mLineLayout = aReflowInput.mLineLayout;
391
0
  irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
392
0
  irs.mSetParentPointer = lazilySetParentPointer;
393
0
394
0
  if (mFrames.IsEmpty()) {
395
0
    // Try to pull over one frame before starting so that we know
396
0
    // whether we have an anonymous block or not.
397
0
    Unused << PullOneFrame(aPresContext, irs);
398
0
  }
399
0
400
0
  ReflowFrames(aPresContext, aReflowInput, irs, aMetrics, aStatus);
401
0
402
0
  ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowInput, aStatus);
403
0
404
0
  // Note: the line layout code will properly compute our
405
0
  // overflow-rect state for us.
406
0
407
0
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
408
0
}
409
410
nsresult
411
nsInlineFrame::AttributeChanged(int32_t aNameSpaceID,
412
                                nsAtom* aAttribute,
413
                                int32_t aModType)
414
0
{
415
0
  nsresult rv =
416
0
    nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
417
0
418
0
  if (NS_FAILED(rv)) {
419
0
    return rv;
420
0
  }
421
0
422
0
  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
423
0
    SVGTextFrame* f = static_cast<SVGTextFrame*>(
424
0
      nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText));
425
0
    f->HandleAttributeChangeInDescendant(mContent->AsElement(),
426
0
                                         aNameSpaceID, aAttribute);
427
0
  }
428
0
429
0
  return NS_OK;
430
0
}
431
432
bool
433
nsInlineFrame::DrainSelfOverflowListInternal(bool aInFirstLine)
434
0
{
435
0
  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
436
0
  if (!overflowFrames || overflowFrames->IsEmpty()) {
437
0
    return false;
438
0
  }
439
0
440
0
  // The frames on our own overflowlist may have been pushed by a
441
0
  // previous lazilySetParentPointer Reflow so we need to ensure the
442
0
  // correct parent pointer.  This is sometimes skipped by Reflow.
443
0
  nsIFrame* firstChild = overflowFrames->FirstChild();
444
0
  RestyleManager* restyleManager = PresContext()->RestyleManager();
445
0
  for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
446
0
    f->SetParent(this);
447
0
    if (MOZ_UNLIKELY(aInFirstLine)) {
448
0
      restyleManager->ReparentComputedStyleForFirstLine(f);
449
0
      nsLayoutUtils::MarkDescendantsDirty(f);
450
0
    }
451
0
  }
452
0
  mFrames.AppendFrames(nullptr, *overflowFrames);
453
0
  return true;
454
0
}
455
456
/* virtual */ bool
457
nsInlineFrame::DrainSelfOverflowList()
458
0
{
459
0
  nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this);
460
0
  // Add the eInFirstLine flag if we have a ::first-line ancestor frame.
461
0
  // No need to look further than the nearest line container though.
462
0
  bool inFirstLine = false;
463
0
  for (nsIFrame* p = GetParent(); p != lineContainer; p = p->GetParent()) {
464
0
    if (p->IsLineFrame()) {
465
0
      inFirstLine = true;
466
0
      break;
467
0
    }
468
0
  }
469
0
  return DrainSelfOverflowListInternal(inFirstLine);
470
0
}
471
472
/* virtual */ bool
473
nsInlineFrame::CanContinueTextRun() const
474
0
{
475
0
  // We can continue a text run through an inline frame
476
0
  return true;
477
0
}
478
479
/* virtual */ void
480
nsInlineFrame::PullOverflowsFromPrevInFlow()
481
0
{
482
0
  nsInlineFrame* prevInFlow = static_cast<nsInlineFrame*>(GetPrevInFlow());
483
0
  if (prevInFlow) {
484
0
    nsPresContext* presContext = PresContext();
485
0
    AutoFrameListPtr prevOverflowFrames(presContext,
486
0
                                        prevInFlow->StealOverflowFrames());
487
0
    if (prevOverflowFrames) {
488
0
      // Assume that our prev-in-flow has the same line container that we do.
489
0
      nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow,
490
0
                                              this);
491
0
      mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
492
0
    }
493
0
  }
494
0
}
495
496
void
497
nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
498
                            const ReflowInput& aReflowInput,
499
                            InlineReflowInput& irs,
500
                            ReflowOutput& aMetrics,
501
                            nsReflowStatus& aStatus)
502
0
{
503
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
504
0
505
0
  nsLineLayout* lineLayout = aReflowInput.mLineLayout;
506
0
  bool inFirstLine = aReflowInput.mLineLayout->GetInFirstLine();
507
0
  RestyleManager* restyleManager = aPresContext->RestyleManager();
508
0
  WritingMode frameWM = aReflowInput.GetWritingMode();
509
0
  WritingMode lineWM = aReflowInput.mLineLayout->mRootSpan->mWritingMode;
510
0
  LogicalMargin framePadding = aReflowInput.ComputedLogicalBorderPadding();
511
0
  nscoord startEdge = 0;
512
0
  const bool boxDecorationBreakClone =
513
0
    MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
514
0
                   StyleBoxDecorationBreak::Clone);
515
0
  // Don't offset by our start borderpadding if we have a prev continuation or
516
0
  // if we're in a part of an {ib} split other than the first one. For
517
0
  // box-decoration-break:clone we always offset our start since all
518
0
  // continuations have border/padding.
519
0
  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
520
0
      boxDecorationBreakClone) {
521
0
    startEdge = framePadding.IStart(frameWM);
522
0
  }
523
0
  nscoord availableISize = aReflowInput.AvailableISize();
524
0
  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
525
0
               "should no longer use available widths");
526
0
  // Subtract off inline axis border+padding from availableISize
527
0
  availableISize -= startEdge;
528
0
  availableISize -= framePadding.IEnd(frameWM);
529
0
  lineLayout->BeginSpan(this, &aReflowInput, startEdge,
530
0
                        startEdge + availableISize, &mBaseline);
531
0
532
0
  // First reflow our principal children.
533
0
  nsIFrame* frame = mFrames.FirstChild();
534
0
  bool done = false;
535
0
  while (frame) {
536
0
    // Check if we should lazily set the child frame's parent pointer.
537
0
    if (irs.mSetParentPointer) {
538
0
      nsIFrame* child = frame;
539
0
      do {
540
0
        child->SetParent(this);
541
0
        if (inFirstLine) {
542
0
          restyleManager->ReparentComputedStyleForFirstLine(child);
543
0
          nsLayoutUtils::MarkDescendantsDirty(child);
544
0
        }
545
0
        // We also need to do the same for |frame|'s next-in-flows that are in
546
0
        // the sibling list. Otherwise, if we reflow |frame| and it's complete
547
0
        // we'll crash when trying to delete its next-in-flow.
548
0
        // This scenario doesn't happen often, but it can happen.
549
0
        nsIFrame* nextSibling = child->GetNextSibling();
550
0
        child = child->GetNextInFlow();
551
0
        if (MOZ_UNLIKELY(child)) {
552
0
          while (child != nextSibling && nextSibling) {
553
0
            nextSibling = nextSibling->GetNextSibling();
554
0
          }
555
0
          if (!nextSibling) {
556
0
            child = nullptr;
557
0
          }
558
0
        }
559
0
        MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
560
0
      } while (child);
561
0
562
0
      // Fix the parent pointer for ::first-letter child frame next-in-flows,
563
0
      // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
564
0
      nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
565
0
      if (realFrame->IsLetterFrame()) {
566
0
        nsIFrame* child = realFrame->PrincipalChildList().FirstChild();
567
0
        if (child) {
568
0
          NS_ASSERTION(child->IsTextFrame(), "unexpected frame type");
569
0
          nsIFrame* nextInFlow = child->GetNextInFlow();
570
0
          for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
571
0
            NS_ASSERTION(nextInFlow->IsTextFrame(), "unexpected frame type");
572
0
            if (mFrames.ContainsFrame(nextInFlow)) {
573
0
              nextInFlow->SetParent(this);
574
0
              if (inFirstLine) {
575
0
                restyleManager->ReparentComputedStyleForFirstLine(nextInFlow);
576
0
                nsLayoutUtils::MarkDescendantsDirty(nextInFlow);
577
0
              }
578
0
            }
579
0
            else {
580
#ifdef DEBUG
581
              // Once we find a next-in-flow that isn't ours none of the
582
              // remaining next-in-flows should be either.
583
              for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
584
                NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
585
                             "unexpected letter frame flow");
586
              }
587
#endif
588
              break;
589
0
            }
590
0
          }
591
0
        }
592
0
      }
593
0
    }
594
0
    MOZ_ASSERT(frame->GetParent() == this);
595
0
596
0
    if (!done) {
597
0
      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
598
0
      ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus);
599
0
      done = aStatus.IsInlineBreak() ||
600
0
             (!reflowingFirstLetter && aStatus.IsIncomplete());
601
0
      if (done) {
602
0
        if (!irs.mSetParentPointer) {
603
0
          break;
604
0
        }
605
0
        // Keep reparenting the remaining siblings, but don't reflow them.
606
0
        nsFrameList* pushedFrames = GetOverflowFrames();
607
0
        if (pushedFrames && pushedFrames->FirstChild() == frame) {
608
0
          // Don't bother if |frame| was pushed to our overflow list.
609
0
          break;
610
0
        }
611
0
      } else {
612
0
        irs.mPrevFrame = frame;
613
0
      }
614
0
    }
615
0
    frame = frame->GetNextSibling();
616
0
  }
617
0
618
0
  // Attempt to pull frames from our next-in-flow until we can't
619
0
  if (!done && GetNextInFlow()) {
620
0
    while (true) {
621
0
      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
622
0
      if (!frame) { // Could be non-null if we pulled a first-letter frame and
623
0
                    // it created a continuation, since we don't push those.
624
0
        frame = PullOneFrame(aPresContext, irs);
625
0
      }
626
#ifdef NOISY_PUSHING
627
      printf("%p pulled up %p\n", this, frame);
628
#endif
629
0
      if (!frame) {
630
0
        break;
631
0
      }
632
0
      ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus);
633
0
      if (aStatus.IsInlineBreak() ||
634
0
          (!reflowingFirstLetter && aStatus.IsIncomplete())) {
635
0
        break;
636
0
      }
637
0
      irs.mPrevFrame = frame;
638
0
      frame = frame->GetNextSibling();
639
0
    }
640
0
  }
641
0
642
0
  NS_ASSERTION(!aStatus.IsComplete() || !GetOverflowFrames(),
643
0
               "We can't be complete AND have overflow frames!");
644
0
645
0
  // If after reflowing our children they take up no area then make
646
0
  // sure that we don't either.
647
0
  //
648
0
  // Note: CSS demands that empty inline elements still affect the
649
0
  // line-height calculations. However, continuations of an inline
650
0
  // that are empty we force to empty so that things like collapsed
651
0
  // whitespace in an inline element don't affect the line-height.
652
0
  aMetrics.ISize(lineWM) = lineLayout->EndSpan(this);
653
0
654
0
  // Compute final width.
655
0
656
0
  // XXX Note that that the padding start and end are in the frame's
657
0
  //     writing mode, but the metrics' inline-size is in the line's
658
0
  //     writing mode. This makes sense if the line and frame are both
659
0
  //     vertical or both horizontal, but what should happen with
660
0
  //     orthogonal inlines?
661
0
662
0
  // Make sure to not include our start border and padding if we have a prev
663
0
  // continuation or if we're in a part of an {ib} split other than the first
664
0
  // one.  For box-decoration-break:clone we always include our start border
665
0
  // and padding since all continuations have them.
666
0
  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
667
0
      boxDecorationBreakClone) {
668
0
    aMetrics.ISize(lineWM) += framePadding.IStart(frameWM);
669
0
  }
670
0
671
0
  /*
672
0
   * We want to only apply the end border and padding if we're the last
673
0
   * continuation and either not in an {ib} split or the last part of it.  To
674
0
   * be the last continuation we have to be complete (so that we won't get a
675
0
   * next-in-flow) and have no non-fluid continuations on our continuation
676
0
   * chain.  For box-decoration-break:clone we always apply the end border and
677
0
   * padding since all continuations have them.
678
0
   */
679
0
  if ((aStatus.IsComplete() &&
680
0
       !LastInFlow()->GetNextContinuation() &&
681
0
       !FrameIsNonLastInIBSplit()) ||
682
0
      boxDecorationBreakClone) {
683
0
    aMetrics.ISize(lineWM) += framePadding.IEnd(frameWM);
684
0
  }
685
0
686
0
  nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics,
687
0
                                         framePadding, lineWM, frameWM);
688
0
689
0
  // For now our overflow area is zero. The real value will be
690
0
  // computed in |nsLineLayout::RelativePositionFrames|.
691
0
  aMetrics.mOverflowAreas.Clear();
692
0
693
#ifdef NOISY_FINAL_SIZE
694
  ListTag(stdout);
695
  printf(": metrics=%d,%d ascent=%d\n",
696
         aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent());
697
#endif
698
}
699
700
// Returns whether there's any remaining frame to pull.
701
/* static */ bool
702
nsInlineFrame::HasFramesToPull(nsInlineFrame* aNextInFlow)
703
0
{
704
0
  while (aNextInFlow) {
705
0
    if (!aNextInFlow->mFrames.IsEmpty()) {
706
0
      return true;
707
0
    }
708
0
    if (const nsFrameList* overflow = aNextInFlow->GetOverflowFrames()) {
709
0
      if (!overflow->IsEmpty()) {
710
0
        return true;
711
0
      }
712
0
    }
713
0
    aNextInFlow = static_cast<nsInlineFrame*>(aNextInFlow->GetNextInFlow());
714
0
  }
715
0
  return false;
716
0
}
717
718
void
719
nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
720
                                 const ReflowInput& aReflowInput,
721
                                 InlineReflowInput& irs,
722
                                 nsIFrame* aFrame,
723
                                 nsReflowStatus& aStatus)
724
0
{
725
0
  nsLineLayout* lineLayout = aReflowInput.mLineLayout;
726
0
  bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
727
0
  bool pushedFrame;
728
0
  aStatus.Reset();
729
0
  lineLayout->ReflowFrame(aFrame, aStatus, nullptr, pushedFrame);
730
0
731
0
  if (aStatus.IsInlineBreakBefore()) {
732
0
    if (aFrame != mFrames.FirstChild()) {
733
0
      // Change break-before status into break-after since we have
734
0
      // already placed at least one child frame. This preserves the
735
0
      // break-type so that it can be propagated upward.
736
0
      StyleClear oldBreakType = aStatus.BreakType();
737
0
      aStatus.Reset();
738
0
      aStatus.SetIncomplete();
739
0
      aStatus.SetInlineLineBreakAfter(oldBreakType);
740
0
      PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
741
0
    }
742
0
    else {
743
0
      // Preserve reflow status when breaking-before our first child
744
0
      // and propagate it upward without modification.
745
0
    }
746
0
    return;
747
0
  }
748
0
749
0
  // Create a next-in-flow if needed.
750
0
  if (!aStatus.IsFullyComplete()) {
751
0
    CreateNextInFlow(aFrame);
752
0
  }
753
0
754
0
  if (aStatus.IsInlineBreakAfter()) {
755
0
    nsIFrame* nextFrame = aFrame->GetNextSibling();
756
0
    if (nextFrame) {
757
0
      aStatus.SetIncomplete();
758
0
      PushFrames(aPresContext, nextFrame, aFrame, irs);
759
0
    } else {
760
0
      // We must return an incomplete status if there are more child
761
0
      // frames remaining in a next-in-flow that follows this frame.
762
0
      if (HasFramesToPull(static_cast<nsInlineFrame*>(GetNextInFlow()))) {
763
0
        aStatus.SetIncomplete();
764
0
      }
765
0
    }
766
0
    return;
767
0
  }
768
0
769
0
  if (!aStatus.IsFullyComplete() && !reflowingFirstLetter) {
770
0
    nsIFrame* nextFrame = aFrame->GetNextSibling();
771
0
    if (nextFrame) {
772
0
      PushFrames(aPresContext, nextFrame, aFrame, irs);
773
0
    }
774
0
  }
775
0
}
776
777
nsIFrame*
778
nsInlineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowInput& irs)
779
0
{
780
0
  nsIFrame* frame = nullptr;
781
0
  nsInlineFrame* nextInFlow = irs.mNextInFlow;
782
0
783
#ifdef DEBUG
784
  bool willPull = HasFramesToPull(nextInFlow);
785
#endif
786
787
0
  while (nextInFlow) {
788
0
    frame = nextInFlow->mFrames.FirstChild();
789
0
    if (!frame) {
790
0
      // The nextInFlow's principal list has no frames, try its overflow list.
791
0
      nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
792
0
      if (overflowFrames) {
793
0
        frame = overflowFrames->RemoveFirstChild();
794
0
        if (overflowFrames->IsEmpty()) {
795
0
          // We're stealing the only frame - delete the overflow list.
796
0
          nextInFlow->DestroyOverflowList();
797
0
        } else {
798
0
          // We leave the remaining frames on the overflow list (rather than
799
0
          // putting them on nextInFlow's principal list) so we don't have to
800
0
          // set up the parent for them.
801
0
        }
802
0
        // ReparentFloatsForInlineChild needs it to be on a child list -
803
0
        // we remove it again below.
804
0
        nextInFlow->mFrames.SetFrames(frame);
805
0
      }
806
0
    }
807
0
808
0
    if (frame) {
809
0
      // If our block has no next continuation, then any floats belonging to
810
0
      // the pulled frame must belong to our block already. This check ensures
811
0
      // we do no extra work in the common non-vertical-breaking case.
812
0
      if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
813
0
        // The blockChildren.ContainsFrame check performed by
814
0
        // ReparentFloatsForInlineChild will be fast because frame's ancestor
815
0
        // will be the first child of its containing block.
816
0
        ReparentFloatsForInlineChild(irs.mLineContainer, frame, false,
817
0
                                     ReparentingDirection::Backwards);
818
0
      }
819
0
      nextInFlow->mFrames.RemoveFirstChild();
820
0
      // nsFirstLineFrame::PullOneFrame calls ReparentComputedStyle.
821
0
822
0
      mFrames.InsertFrame(this, irs.mPrevFrame, frame);
823
0
      if (irs.mLineLayout) {
824
0
        irs.mLineLayout->SetDirtyNextLine();
825
0
      }
826
0
      nsContainerFrame::ReparentFrameView(frame, nextInFlow, this);
827
0
      break;
828
0
    }
829
0
    nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
830
0
    irs.mNextInFlow = nextInFlow;
831
0
  }
832
0
833
0
  MOZ_ASSERT(!!frame == willPull);
834
0
  return frame;
835
0
}
836
837
void
838
nsInlineFrame::PushFrames(nsPresContext* aPresContext,
839
                          nsIFrame* aFromChild,
840
                          nsIFrame* aPrevSibling,
841
                          InlineReflowInput& aState)
842
0
{
843
#ifdef NOISY_PUSHING
844
  printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n",
845
         this, aFromChild, aPrevSibling);
846
#endif
847
848
0
  PushChildrenToOverflow(aFromChild, aPrevSibling);
849
0
  if (aState.mLineLayout) {
850
0
    aState.mLineLayout->SetDirtyNextLine();
851
0
  }
852
0
}
853
854
855
//////////////////////////////////////////////////////////////////////
856
857
nsIFrame::LogicalSides
858
nsInlineFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
859
0
{
860
0
  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
861
0
                     StyleBoxDecorationBreak::Clone)) {
862
0
    return LogicalSides();
863
0
  }
864
0
865
0
  LogicalSides skip;
866
0
  if (!IsFirst()) {
867
0
    nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();
868
0
    if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
869
0
        (prev && (prev->mRect.height || prev->mRect.width))) {
870
0
      // Prev continuation is not empty therefore we don't render our start
871
0
      // border edge.
872
0
      skip |= eLogicalSideBitsIStart;
873
0
    }
874
0
    else {
875
0
      // If the prev continuation is empty, then go ahead and let our start
876
0
      // edge border render.
877
0
    }
878
0
  }
879
0
  if (!IsLast()) {
880
0
    nsInlineFrame* next = (nsInlineFrame*) GetNextContinuation();
881
0
    if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
882
0
        (next && (next->mRect.height || next->mRect.width))) {
883
0
      // Next continuation is not empty therefore we don't render our end
884
0
      // border edge.
885
0
      skip |= eLogicalSideBitsIEnd;
886
0
    }
887
0
    else {
888
0
      // If the next continuation is empty, then go ahead and let our end
889
0
      // edge border render.
890
0
    }
891
0
  }
892
0
893
0
  if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
894
0
    // All but the last part of an {ib} split should skip the "end" side (as
895
0
    // determined by this frame's direction) and all but the first part of such
896
0
    // a split should skip the "start" side.  But figuring out which part of
897
0
    // the split we are involves getting our first continuation, which might be
898
0
    // expensive.  So don't bother if we already have the relevant bits set.
899
0
    if (skip != LogicalSides(eLogicalSideBitsIBoth)) {
900
0
      // We're missing one of the skip bits, so check whether we need to set it.
901
0
      // Only get the first continuation once, as an optimization.
902
0
      nsIFrame* firstContinuation = FirstContinuation();
903
0
      if (firstContinuation->FrameIsNonLastInIBSplit()) {
904
0
        skip |= eLogicalSideBitsIEnd;
905
0
      }
906
0
      if (firstContinuation->FrameIsNonFirstInIBSplit()) {
907
0
        skip |= eLogicalSideBitsIStart;
908
0
      }
909
0
    }
910
0
  }
911
0
912
0
  return skip;
913
0
}
914
915
nscoord
916
nsInlineFrame::GetLogicalBaseline(mozilla::WritingMode aWritingMode) const
917
0
{
918
0
  return mBaseline;
919
0
}
920
921
#ifdef ACCESSIBILITY
922
a11y::AccType
923
nsInlineFrame::AccessibleType()
924
0
{
925
0
  // Broken image accessibles are created here, because layout
926
0
  // replaces the image or image control frame with an inline frame
927
0
  if (mContent->IsHTMLElement(nsGkAtoms::input))  // Broken <input type=image ... />
928
0
    return a11y::eHTMLButtonType;
929
0
  if (mContent->IsHTMLElement(nsGkAtoms::img))  // Create accessible for broken <img>
930
0
    return a11y::eHyperTextType;
931
0
932
0
  return a11y::eNoType;
933
0
}
934
#endif
935
936
void
937
nsInlineFrame::UpdateStyleOfOwnedAnonBoxesForIBSplit(
938
  ServoRestyleState& aRestyleState)
939
0
{
940
0
  MOZ_ASSERT(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES,
941
0
             "Why did we get called?");
942
0
  MOZ_ASSERT(GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
943
0
             "Why did we have the NS_FRAME_OWNS_ANON_BOXES bit set?");
944
0
  // Note: this assert _looks_ expensive, but it's cheap in all the cases when
945
0
  // it passes!
946
0
  MOZ_ASSERT(nsLayoutUtils::FirstContinuationOrIBSplitSibling(this) == this,
947
0
             "Only the primary frame of the inline in a block-inside-inline "
948
0
             "split should have NS_FRAME_OWNS_ANON_BOXES");
949
0
  MOZ_ASSERT(mContent->GetPrimaryFrame() == this,
950
0
             "We should be the primary frame for our element");
951
0
952
0
  nsIFrame* blockFrame = GetProperty(nsIFrame::IBSplitSibling());
953
0
  MOZ_ASSERT(blockFrame, "Why did we have an IB split?");
954
0
955
0
  // The later inlines need to get our style.
956
0
  ComputedStyle* ourStyle = Style();
957
0
958
0
  // The anonymous block's style inherits from ours, and we already have our new
959
0
  // ComputedStyle.
960
0
  RefPtr<ComputedStyle> newContext =
961
0
    aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
962
0
      nsCSSAnonBoxes::mozBlockInsideInlineWrapper(), ourStyle);
963
0
964
0
  // We're guaranteed that newContext only differs from the old ComputedStyle on
965
0
  // the block in things they might inherit from us.  And changehint processing
966
0
  // guarantees walking the continuation and ib-sibling chains, so our existing
967
0
  // changehint being in aChangeList is good enough.  So we don't need to touch
968
0
  // aChangeList at all here.
969
0
970
0
  while (blockFrame) {
971
0
    MOZ_ASSERT(!blockFrame->GetPrevContinuation(),
972
0
               "Must be first continuation");
973
0
974
0
    MOZ_ASSERT(blockFrame->Style()->GetPseudo() ==
975
0
               nsCSSAnonBoxes::mozBlockInsideInlineWrapper(),
976
0
               "Unexpected kind of ComputedStyle");
977
0
978
0
    // We don't want to just walk through using GetNextContinuationWithSameStyle
979
0
    // here, because we want to set updated ComputedStyles on both our
980
0
    // ib-sibling blocks and inlines.
981
0
    for (nsIFrame* cont = blockFrame; cont; cont = cont->GetNextContinuation()) {
982
0
      cont->SetComputedStyle(newContext);
983
0
    }
984
0
985
0
    nsIFrame* nextInline = blockFrame->GetProperty(nsIFrame::IBSplitSibling());
986
0
987
0
    // This check is here due to bug 1431232.  Please remove it once
988
0
    // that bug is fixed.
989
0
    if (MOZ_UNLIKELY(!nextInline)) {
990
0
      break;
991
0
    }
992
0
993
0
    MOZ_ASSERT(nextInline, "There is always a trailing inline in an IB split");
994
0
995
0
    for (nsIFrame* cont = nextInline; cont; cont = cont->GetNextContinuation()) {
996
0
      cont->SetComputedStyle(ourStyle);
997
0
    }
998
0
    blockFrame = nextInline->GetProperty(nsIFrame::IBSplitSibling());
999
0
  }
1000
0
}
1001
1002
//////////////////////////////////////////////////////////////////////
1003
1004
// nsLineFrame implementation
1005
1006
nsFirstLineFrame*
1007
NS_NewFirstLineFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
1008
0
{
1009
0
  return new (aPresShell) nsFirstLineFrame(aStyle);
1010
0
}
1011
1012
NS_IMPL_FRAMEARENA_HELPERS(nsFirstLineFrame)
1013
1014
void
1015
nsFirstLineFrame::Init(nsIContent*       aContent,
1016
                       nsContainerFrame* aParent,
1017
                       nsIFrame*         aPrevInFlow)
1018
0
{
1019
0
  nsInlineFrame::Init(aContent, aParent, aPrevInFlow);
1020
0
  if (!aPrevInFlow) {
1021
0
    MOZ_ASSERT(Style()->GetPseudo() == nsCSSPseudoElements::firstLine());
1022
0
    return;
1023
0
  }
1024
0
1025
0
  // This frame is a continuation - fixup the computed style if aPrevInFlow
1026
0
  // is the first-in-flow (the only one with a ::first-line pseudo).
1027
0
  if (aPrevInFlow->Style()->GetPseudo() == nsCSSPseudoElements::firstLine()) {
1028
0
    MOZ_ASSERT(FirstInFlow() == aPrevInFlow);
1029
0
    // Create a new ComputedStyle that is a child of the parent
1030
0
    // ComputedStyle thus removing the ::first-line style. This way
1031
0
    // we behave as if an anonymous (unstyled) span was the child
1032
0
    // of the parent frame.
1033
0
    ComputedStyle* parentContext = aParent->Style();
1034
0
    RefPtr<ComputedStyle> newSC = PresContext()->StyleSet()->
1035
0
      ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozLineFrame(),
1036
0
                                         parentContext);
1037
0
    SetComputedStyle(newSC);
1038
0
  } else {
1039
0
    MOZ_ASSERT(FirstInFlow() != aPrevInFlow);
1040
0
    MOZ_ASSERT(aPrevInFlow->Style()->GetPseudo() ==
1041
0
                 nsCSSAnonBoxes::mozLineFrame());
1042
0
  }
1043
0
}
1044
1045
#ifdef DEBUG_FRAME_DUMP
1046
nsresult
1047
nsFirstLineFrame::GetFrameName(nsAString& aResult) const
1048
{
1049
  return MakeFrameName(NS_LITERAL_STRING("Line"), aResult);
1050
}
1051
#endif
1052
1053
nsIFrame*
1054
nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext,
1055
                               InlineReflowInput& irs)
1056
0
{
1057
0
  nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs);
1058
0
  if (frame && !GetPrevInFlow()) {
1059
0
    // We are a first-line frame. Fixup the child frames
1060
0
    // style-context that we just pulled.
1061
0
    NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?");
1062
0
    aPresContext->RestyleManager()->ReparentComputedStyleForFirstLine(frame);
1063
0
    nsLayoutUtils::MarkDescendantsDirty(frame);
1064
0
  }
1065
0
  return frame;
1066
0
}
1067
1068
void
1069
nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
1070
                         ReflowOutput& aMetrics,
1071
                         const ReflowInput& aReflowInput,
1072
                         nsReflowStatus& aStatus)
1073
0
{
1074
0
  MarkInReflow();
1075
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
1076
0
1077
0
  if (nullptr == aReflowInput.mLineLayout) {
1078
0
    return;  // XXX does this happen? why?
1079
0
  }
1080
0
1081
0
  // Check for an overflow list with our prev-in-flow
1082
0
  nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow();
1083
0
  if (prevInFlow) {
1084
0
    AutoFrameListPtr prevOverflowFrames(aPresContext,
1085
0
                                        prevInFlow->StealOverflowFrames());
1086
0
    if (prevOverflowFrames) {
1087
0
      // Reparent the new frames and their ComputedStyles.
1088
0
      const nsFrameList::Slice& newFrames =
1089
0
        mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
1090
0
      ReparentChildListStyle(aPresContext, newFrames, this);
1091
0
    }
1092
0
  }
1093
0
1094
0
  // It's also possible that we have an overflow list for ourselves.
1095
0
  DrainSelfOverflowList();
1096
0
1097
0
  // Set our own reflow state (additional state above and beyond aReflowInput).
1098
0
  InlineReflowInput irs;
1099
0
  irs.mPrevFrame = nullptr;
1100
0
  irs.mLineContainer = aReflowInput.mLineLayout->LineContainerFrame();
1101
0
  irs.mLineLayout = aReflowInput.mLineLayout;
1102
0
  irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
1103
0
1104
0
  bool wasEmpty = mFrames.IsEmpty();
1105
0
  if (wasEmpty) {
1106
0
    // Try to pull over one frame before starting so that we know
1107
0
    // whether we have an anonymous block or not.
1108
0
    PullOneFrame(aPresContext, irs);
1109
0
  }
1110
0
1111
0
  if (nullptr == GetPrevInFlow()) {
1112
0
    // XXX This is pretty sick, but what we do here is to pull-up, in
1113
0
    // advance, all of the next-in-flows children. We re-resolve their
1114
0
    // style while we are at at it so that when we reflow they have
1115
0
    // the right style.
1116
0
    //
1117
0
    // All of this is so that text-runs reflow properly.
1118
0
    irs.mPrevFrame = mFrames.LastChild();
1119
0
    for (;;) {
1120
0
      nsIFrame* frame = PullOneFrame(aPresContext, irs);
1121
0
      if (!frame) {
1122
0
        break;
1123
0
      }
1124
0
      irs.mPrevFrame = frame;
1125
0
    }
1126
0
    irs.mPrevFrame = nullptr;
1127
0
  }
1128
0
1129
0
  NS_ASSERTION(!aReflowInput.mLineLayout->GetInFirstLine(),
1130
0
               "Nested first-line frames? BOGUS");
1131
0
  aReflowInput.mLineLayout->SetInFirstLine(true);
1132
0
  ReflowFrames(aPresContext, aReflowInput, irs, aMetrics, aStatus);
1133
0
  aReflowInput.mLineLayout->SetInFirstLine(false);
1134
0
1135
0
  ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowInput, aStatus);
1136
0
1137
0
  // Note: the line layout code will properly compute our overflow state for us
1138
0
}
1139
1140
/* virtual */ void
1141
nsFirstLineFrame::PullOverflowsFromPrevInFlow()
1142
0
{
1143
0
  nsFirstLineFrame* prevInFlow = static_cast<nsFirstLineFrame*>(GetPrevInFlow());
1144
0
  if (prevInFlow) {
1145
0
    nsPresContext* presContext = PresContext();
1146
0
    AutoFrameListPtr prevOverflowFrames(presContext,
1147
0
                                        prevInFlow->StealOverflowFrames());
1148
0
    if (prevOverflowFrames) {
1149
0
      // Assume that our prev-in-flow has the same line container that we do.
1150
0
      const nsFrameList::Slice& newFrames =
1151
0
        mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
1152
0
      ReparentChildListStyle(presContext, newFrames, this);
1153
0
    }
1154
0
  }
1155
0
}
1156
1157
/* virtual */ bool
1158
nsFirstLineFrame::DrainSelfOverflowList()
1159
0
{
1160
0
  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
1161
0
  if (overflowFrames) {
1162
0
    bool result = !overflowFrames->IsEmpty();
1163
0
    const nsFrameList::Slice& newFrames =
1164
0
      mFrames.AppendFrames(nullptr, *overflowFrames);
1165
0
    ReparentChildListStyle(PresContext(), newFrames, this);
1166
0
    return result;
1167
0
  }
1168
0
  return false;
1169
0
}