Simple line layout: Do not use invalid m_lastNonWhitespaceFragment while removing...
[WebKit-https.git] / Source / WebCore / rendering / SimpleLineLayout.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SimpleLineLayout.h"
28
29 #include "FontCache.h"
30 #include "Frame.h"
31 #include "GraphicsContext.h"
32 #include "HTMLTextFormControlElement.h"
33 #include "HitTestLocation.h"
34 #include "HitTestRequest.h"
35 #include "HitTestResult.h"
36 #include "Hyphenation.h"
37 #include "InlineTextBox.h"
38 #include "LineWidth.h"
39 #include "Logging.h"
40 #include "PaintInfo.h"
41 #include "RenderBlockFlow.h"
42 #include "RenderChildIterator.h"
43 #include "RenderLineBreak.h"
44 #include "RenderStyle.h"
45 #include "RenderText.h"
46 #include "RenderTextControl.h"
47 #include "Settings.h"
48 #include "SimpleLineLayoutFlowContents.h"
49 #include "SimpleLineLayoutFunctions.h"
50 #include "SimpleLineLayoutTextFragmentIterator.h"
51 #include "Text.h"
52 #include "TextPaintStyle.h"
53
54 namespace WebCore {
55 namespace SimpleLineLayout {
56
57 #ifndef NDEBUG
58 #define SET_REASON_AND_RETURN_IF_NEEDED(reason, reasons, includeReasons) { \
59         reasons |= reason; \
60         if (includeReasons == IncludeReasons::First) \
61             return reasons; \
62     }
63 #else
64 #define SET_REASON_AND_RETURN_IF_NEEDED(reason, reasons, includeReasons) { \
65         ASSERT_UNUSED(includeReasons, includeReasons == IncludeReasons::First); \
66         reasons |= reason; \
67         return reasons; \
68     }
69 #endif
70
71
72 template <typename CharacterType> AvoidanceReasonFlags canUseForCharacter(CharacterType, bool textIsJustified, IncludeReasons);
73
74 template<> AvoidanceReasonFlags canUseForCharacter(UChar character, bool textIsJustified, IncludeReasons includeReasons)
75 {
76     AvoidanceReasonFlags reasons = { };
77     if (textIsJustified) {
78         // Include characters up to Latin Extended-B and some punctuation range when text is justified.
79         bool isLatinIncludingExtendedB = character <= 0x01FF;
80         bool isPunctuationRange = character >= 0x2010 && character <= 0x2027;
81         if (!(isLatinIncludingExtendedB || isPunctuationRange))
82             SET_REASON_AND_RETURN_IF_NEEDED(FlowHasJustifiedNonLatinText, reasons, includeReasons);
83     }
84
85     if (U16_IS_SURROGATE(character))
86         SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasSurrogatePair, reasons, includeReasons);
87     
88     UCharDirection direction = u_charDirection(character);
89     if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC
90         || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE
91         || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE
92         || direction == U_POP_DIRECTIONAL_FORMAT || direction == U_BOUNDARY_NEUTRAL)
93         SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasDirectionCharacter, reasons, includeReasons);
94
95     return reasons;
96 }
97
98 template<> AvoidanceReasonFlags canUseForCharacter(LChar, bool, IncludeReasons)
99 {
100     return { };
101 }
102
103 template <typename CharacterType>
104 static AvoidanceReasonFlags canUseForText(const CharacterType* text, unsigned length, const FontCascade& fontCascade, std::optional<float> lineHeightConstraint,
105     bool textIsJustified, IncludeReasons includeReasons)
106 {
107     AvoidanceReasonFlags reasons = { };
108     auto& primaryFont = fontCascade.primaryFont();
109     for (unsigned i = 0; i < length; ++i) {
110         auto character = text[i];
111         if (FontCascade::treatAsSpace(character))
112             continue;
113
114         if (character == softHyphen)
115             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasSoftHyphen, reasons, includeReasons);
116
117         auto characterReasons = canUseForCharacter(character, textIsJustified, includeReasons);
118         if (characterReasons != NoReason)
119             SET_REASON_AND_RETURN_IF_NEEDED(characterReasons, reasons, includeReasons);
120
121         auto glyphData = fontCascade.glyphDataForCharacter(character, false);
122         if (!glyphData.isValid() || glyphData.font != &primaryFont)
123             SET_REASON_AND_RETURN_IF_NEEDED(FlowPrimaryFontIsInsufficient, reasons, includeReasons);
124
125         if (lineHeightConstraint && primaryFont.boundsForGlyph(glyphData.glyph).height() > *lineHeightConstraint)
126             SET_REASON_AND_RETURN_IF_NEEDED(FlowFontHasOverflowGlyph, reasons, includeReasons);
127     }
128     return reasons;
129 }
130
131 static AvoidanceReasonFlags canUseForText(StringView text, const FontCascade& fontCascade, std::optional<float> lineHeightConstraint, bool textIsJustified, IncludeReasons includeReasons)
132 {
133     if (text.is8Bit())
134         return canUseForText(text.characters8(), text.length(), fontCascade, lineHeightConstraint, textIsJustified, includeReasons);
135     return canUseForText(text.characters16(), text.length(), fontCascade, lineHeightConstraint, textIsJustified, includeReasons);
136 }
137
138 static AvoidanceReasonFlags canUseForFontAndText(const RenderBlockFlow& flow, IncludeReasons includeReasons)
139 {
140     AvoidanceReasonFlags reasons = { };
141     // We assume that all lines have metrics based purely on the primary font.
142     const auto& style = flow.style();
143     auto& fontCascade = style.fontCascade();
144     if (fontCascade.primaryFont().isLoading())
145         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsMissingPrimaryFont, reasons, includeReasons);
146     std::optional<float> lineHeightConstraint;
147     if (style.lineBoxContain() & LineBoxContainGlyphs)
148         lineHeightConstraint = lineHeightFromFlow(flow).toFloat();
149     bool flowIsJustified = style.textAlign() == JUSTIFY;
150     for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
151         // FIXME: Do not return until after checking all children.
152         if (!textRenderer.textLength())
153             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsEmpty, reasons, includeReasons);
154         if (textRenderer.isCombineText())
155             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsCombineText, reasons, includeReasons);
156         if (textRenderer.isCounter())
157             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsRenderCounter, reasons, includeReasons);
158         if (textRenderer.isQuote())
159             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsRenderQuote, reasons, includeReasons);
160         if (textRenderer.isTextFragment())
161             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsTextFragment, reasons, includeReasons);
162         if (textRenderer.isSVGInlineText())
163             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsSVGInlineText, reasons, includeReasons);
164         if (!textRenderer.canUseSimpleFontCodePath()) {
165             // No need to check the code path at this point. We already know it can't be simple.
166             SET_REASON_AND_RETURN_IF_NEEDED(FlowHasComplexFontCodePath, reasons, includeReasons);
167         } else {
168             TextRun run(textRenderer.text());
169             run.setCharacterScanForCodePath(false);
170             if (style.fontCascade().codePath(run) != FontCascade::Simple)
171                 SET_REASON_AND_RETURN_IF_NEEDED(FlowHasComplexFontCodePath, reasons, includeReasons);
172         }
173
174         auto textReasons = canUseForText(textRenderer.stringView(), fontCascade, lineHeightConstraint, flowIsJustified, includeReasons);
175         if (textReasons != NoReason)
176             SET_REASON_AND_RETURN_IF_NEEDED(textReasons, reasons, includeReasons);
177     }
178     return reasons;
179 }
180
181 static AvoidanceReasonFlags canUseForStyle(const RenderStyle& style, IncludeReasons includeReasons)
182 {
183     AvoidanceReasonFlags reasons = { };
184     if (style.textOverflow())
185         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextOverflow, reasons, includeReasons);
186     if ((style.textDecorationsInEffect() & TextDecorationUnderline) && style.textUnderlinePosition() == TextUnderlinePositionUnder)
187         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasUnsupportedUnderlineDecoration, reasons, includeReasons);
188     // Non-visible overflow should be pretty easy to support.
189     if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE)
190         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasOverflowNotVisible, reasons, includeReasons);
191     if (!style.isLeftToRightDirection())
192         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsNotLTR, reasons, includeReasons);
193     if (!(style.lineBoxContain() & LineBoxContainBlock))
194         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineBoxContainProperty, reasons, includeReasons);
195     if (style.writingMode() != TopToBottomWritingMode)
196         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsNotTopToBottom, reasons, includeReasons);
197     if (style.lineBreak() != LineBreakAuto)
198         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineBreak, reasons, includeReasons);
199     if (style.unicodeBidi() != UBNormal)
200         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonNormalUnicodeBiDi, reasons, includeReasons);
201     if (style.rtlOrdering() != LogicalOrder)
202         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasRTLOrdering, reasons, includeReasons);
203     if (style.lineAlign() != LineAlignNone)
204         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineAlignEdges, reasons, includeReasons);
205     if (style.lineSnap() != LineSnapNone)
206         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineSnap, reasons, includeReasons);
207     if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone)
208         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextEmphasisFillOrMark, reasons, includeReasons);
209     if (style.textShadow())
210         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextShadow, reasons, includeReasons);
211     if (style.hasPseudoStyle(FIRST_LINE))
212         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasPseudoFirstLine, reasons, includeReasons);
213     if (style.hasPseudoStyle(FIRST_LETTER))
214         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasPseudoFirstLetter, reasons, includeReasons);
215     if (style.hasTextCombine())
216         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextCombine, reasons, includeReasons);
217     if (style.backgroundClip() == TextFillBox)
218         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextFillBox, reasons, includeReasons);
219     if (style.borderFit() == BorderFitLines)
220         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasBorderFitLines, reasons, includeReasons);
221     if (style.lineBreak() != LineBreakAuto)
222         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonAutoLineBreak, reasons, includeReasons);
223     if (style.nbspMode() != NBNORMAL)
224         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasWebKitNBSPMode, reasons, includeReasons);
225 #if ENABLE(CSS_TRAILING_WORD)
226     if (style.trailingWord() != TrailingWord::Auto)
227         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonAutoTrailingWord, reasons, includeReasons);
228 #endif
229     return reasons;
230 }
231
232 AvoidanceReasonFlags canUseForWithReason(const RenderBlockFlow& flow, IncludeReasons includeReasons)
233 {
234 #ifndef NDEBUG
235     static std::once_flag onceFlag;
236     std::call_once(onceFlag, [] {
237         registerNotifyCallback("com.apple.WebKit.showSimpleLineLayoutCoverage", printSimpleLineLayoutCoverage);
238         registerNotifyCallback("com.apple.WebKit.showSimpleLineLayoutReasons", printSimpleLineLayoutBlockList);
239         registerNotifyCallback("com.apple.WebKit.toggleSimpleLineLayout", toggleSimpleLineLayout);
240     });
241 #endif
242     AvoidanceReasonFlags reasons = { };
243     if (!flow.settings().simpleLineLayoutEnabled())
244         SET_REASON_AND_RETURN_IF_NEEDED(FeatureIsDisabled, reasons, includeReasons);
245     if (!flow.parent())
246         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNoParent, reasons, includeReasons);
247     if (!flow.firstChild())
248         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNoChild, reasons, includeReasons);
249     if (flow.flowThreadState() != RenderObject::NotInsideFlowThread)
250         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsInsideRegion, reasons, includeReasons);
251     if (!flow.isHorizontalWritingMode())
252         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHorizonalWritingMode, reasons, includeReasons);
253     if (flow.hasOutline())
254         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasOutline, reasons, includeReasons);
255     if (flow.isRubyText() || flow.isRubyBase())
256         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsRuby, reasons, includeReasons);
257     if (flow.style().hangingPunctuation() != NoHangingPunctuation)
258         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHangingPunctuation, reasons, includeReasons);
259     
260     // Printing does pagination without a flow thread.
261     if (flow.document().paginated())
262         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsPaginated, reasons, includeReasons);
263     if (flow.firstLineBlock())
264         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasPseudoFirstLine, reasons, includeReasons);
265     if (flow.isAnonymousBlock() && flow.parent()->style().textOverflow())
266         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextOverflow, reasons, includeReasons);
267     if (flow.parent()->isDeprecatedFlexibleBox())
268         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsDepricatedFlexBox, reasons, includeReasons);
269     // FIXME: Placeholders do something strange.
270     if (is<RenderTextControl>(*flow.parent()) && downcast<RenderTextControl>(*flow.parent()).textFormControlElement().placeholderElement())
271         SET_REASON_AND_RETURN_IF_NEEDED(FlowParentIsPlaceholderElement, reasons, includeReasons);
272     // FIXME: Implementation of wrap=hard looks into lineboxes.
273     if (flow.parent()->isTextArea() && flow.parent()->element()->hasAttributeWithoutSynchronization(HTMLNames::wrapAttr))
274         SET_REASON_AND_RETURN_IF_NEEDED(FlowParentIsTextAreaWithWrapping, reasons, includeReasons);
275     // This currently covers <blockflow>#text</blockflow>, <blockflow>#text<br></blockflow> and mutiple (sibling) RenderText cases.
276     // The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover.
277     for (const auto* child = flow.firstChild(); child;) {
278         if (child->selectionState() != RenderObject::SelectionNone)
279             SET_REASON_AND_RETURN_IF_NEEDED(FlowChildIsSelected, reasons, includeReasons);
280         if (is<RenderText>(*child)) {
281             child = child->nextSibling();
282             continue;
283         }
284         if (is<RenderLineBreak>(child) && !downcast<RenderLineBreak>(*child).isWBR() && child->style().clear() == CNONE) {
285             child = child->nextSibling();
286             continue;
287         }
288         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonSupportedChild, reasons, includeReasons);
289         break;
290     }
291     auto styleReasons = canUseForStyle(flow.style(), includeReasons);
292     if (styleReasons != NoReason)
293         SET_REASON_AND_RETURN_IF_NEEDED(styleReasons, reasons, includeReasons);
294     // We can't use the code path if any lines would need to be shifted below floats. This is because we don't keep per-line y coordinates.
295     if (flow.containsFloats()) {
296         float minimumWidthNeeded = std::numeric_limits<float>::max();
297         for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
298             minimumWidthNeeded = std::min(minimumWidthNeeded, textRenderer.minLogicalWidth());
299
300             for (auto& floatingObject : *flow.floatingObjectSet()) {
301                 ASSERT(floatingObject);
302                 // if a float has a shape, we cannot tell if content will need to be shifted until after we lay it out,
303                 // since the amount of space is not uniform for the height of the float.
304                 if (floatingObject->renderer().shapeOutsideInfo())
305                     SET_REASON_AND_RETURN_IF_NEEDED(FlowHasUnsupportedFloat, reasons, includeReasons);
306                 float availableWidth = flow.availableLogicalWidthForLine(floatingObject->y(), DoNotIndentText);
307                 if (availableWidth < minimumWidthNeeded)
308                     SET_REASON_AND_RETURN_IF_NEEDED(FlowHasUnsupportedFloat, reasons, includeReasons);
309             }
310         }
311     }
312     auto fontAndTextReasons = canUseForFontAndText(flow, includeReasons);
313     if (fontAndTextReasons != NoReason)
314         SET_REASON_AND_RETURN_IF_NEEDED(fontAndTextReasons, reasons, includeReasons);
315     return reasons;
316 }
317
318 bool canUseFor(const RenderBlockFlow& flow)
319 {
320     return canUseForWithReason(flow, IncludeReasons::First) == NoReason;
321 }
322
323 static float computeLineLeft(ETextAlign textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)
324 {
325     float remainingWidth = availableWidth - committedWidth;
326     float left = logicalLeftOffset;
327     switch (textAlign) {
328     case LEFT:
329     case WEBKIT_LEFT:
330     case TASTART:
331         return left;
332     case RIGHT:
333     case WEBKIT_RIGHT:
334     case TAEND:
335         return left + std::max<float>(remainingWidth, 0);
336     case CENTER:
337     case WEBKIT_CENTER:
338         return left + std::max<float>(remainingWidth / 2, 0);
339     case JUSTIFY:
340         ASSERT_NOT_REACHED();
341         break;
342     }
343     ASSERT_NOT_REACHED();
344     return 0;
345 }
346
347 static void revertAllRunsOnCurrentLine(Layout::RunVector& runs)
348 {
349     while (!runs.isEmpty() && !runs.last().isEndOfLine)
350         runs.removeLast();
351 }
352
353 static void revertRuns(Layout::RunVector& runs, unsigned positionToRevertTo, float width)
354 {
355     while (runs.size()) {
356         auto& lastRun = runs.last();
357         if (lastRun.end <= positionToRevertTo)
358             break;
359         if (lastRun.start >= positionToRevertTo) {
360             // Revert this run completely.
361             width -= (lastRun.logicalRight - lastRun.logicalLeft);
362             runs.removeLast();
363         } else {
364             lastRun.logicalRight -= width;
365             width = 0;
366             lastRun.end = positionToRevertTo;
367             // Partial removal.
368             break;
369         }
370     }
371 }
372
373 class LineState {
374 public:
375     void setAvailableWidth(float width) { m_availableWidth = width; }
376     void setCollapedWhitespaceWidth(float width) { m_collapsedWhitespaceWidth = width; }
377     void setLogicalLeftOffset(float offset) { m_logicalLeftOffset = offset; }
378     void setOverflowedFragment(const TextFragmentIterator::TextFragment& fragment) { m_overflowedFragment = fragment; }
379     void setNeedsAllFragments()
380     {
381         ASSERT(!m_fragments);
382         m_fragments.emplace();
383     }
384
385     float availableWidth() const { return m_availableWidth; }
386     float logicalLeftOffset() const { return m_logicalLeftOffset; }
387     const TextFragmentIterator::TextFragment& overflowedFragment() const { return m_overflowedFragment; }
388     bool hasTrailingWhitespace() const { return m_lastFragment.type() == TextFragmentIterator::TextFragment::Whitespace; }
389     TextFragmentIterator::TextFragment lastFragment() const { return m_lastFragment; }
390     bool isWhitespaceOnly() const { return m_trailingWhitespaceWidth && m_runsWidth == m_trailingWhitespaceWidth; }
391     bool fits(float extra) const { return m_availableWidth >= m_runsWidth + extra; }
392     bool firstCharacterFits() const { return m_firstCharacterFits; }
393     float width() const { return m_runsWidth; }
394     std::pair<unsigned, bool> expansionOpportunityCount(unsigned from, unsigned to) const
395     {
396         ASSERT(m_fragments);
397         // linebreak runs are special.
398         if (from == to)
399             return std::make_pair(0, false);
400         unsigned expansionOpportunityCount = 0;
401         auto previousFragmentType = TextFragmentIterator::TextFragment::ContentEnd;
402         for (const auto& fragment : *m_fragments) {
403             if (fragment.end() <= from)
404                 continue;
405             auto currentFragmentType = fragment.type();
406             auto expansionOpportunity = this->expansionOpportunity(currentFragmentType, previousFragmentType);
407             if (expansionOpportunity)
408                 ++expansionOpportunityCount;
409             previousFragmentType = currentFragmentType;
410             if (fragment.end() >= to)
411                 return std::make_pair(expansionOpportunityCount, expansionOpportunity);
412         }
413         ASSERT_NOT_REACHED();
414         return std::make_pair(expansionOpportunityCount, false);
415     }
416
417     bool isEmpty() const
418     {
419         if (!m_lastFragment.isValid())
420             return true;
421         if (!m_lastCompleteFragment.isEmpty())
422             return false;
423         return m_lastFragment.overlapsToNextRenderer();
424     }
425
426     static inline unsigned endPositionForCollapsedFragment(const TextFragmentIterator::TextFragment& fragment)
427     {
428         return fragment.isCollapsed() ? fragment.start() + 1 : fragment.end();
429     }
430
431     void appendFragmentAndCreateRunIfNeeded(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs)
432     {
433         // Adjust end position while collapsing.
434         unsigned endPosition = endPositionForCollapsedFragment(fragment);
435         // New line needs new run.
436         if (!m_runsWidth) {
437             ASSERT(!m_uncompletedWidth);
438             runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false, fragment.hasHyphen()));
439         } else {
440             // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers)
441             if ((m_lastFragment.type() != fragment.type()) || !m_lastFragment.overlapsToNextRenderer()) {
442                 m_lastCompleteFragment = m_lastFragment;
443                 m_uncompletedWidth = fragment.width();
444             } else
445                 m_uncompletedWidth += fragment.width();
446             // Collapse neighbouring whitespace, if they are across multiple renderers and are not collapsed yet.
447             if (m_lastFragment.isCollapsible() && fragment.isCollapsible()) {
448                 ASSERT(m_lastFragment.isLastInRenderer());
449                 if (!m_lastFragment.isCollapsed()) {
450                     // Line width needs to be adjusted so that now it takes collapsing into consideration.
451                     m_runsWidth -= (m_lastFragment.width() - m_collapsedWhitespaceWidth);
452                 }
453                 // This fragment is collapsed completely. No run is needed.
454                 return;
455             }
456             if (m_lastFragment.isLastInRenderer() || m_lastFragment.isCollapsed())
457                 runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false, fragment.hasHyphen()));
458             else {
459                 Run& lastRun = runs.last();
460                 lastRun.end = endPosition;
461                 lastRun.logicalRight += fragment.width();
462                 ASSERT(!lastRun.hasHyphen);
463                 lastRun.hasHyphen = fragment.hasHyphen();
464             }
465         }
466         m_runsWidth += fragment.width();
467         m_lastFragment = fragment;
468         if (m_fragments)
469             (*m_fragments).append(fragment);
470
471         if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace)
472             m_trailingWhitespaceWidth += fragment.width();
473         else {
474             m_trailingWhitespaceWidth = 0;
475             m_lastNonWhitespaceFragment = fragment;
476         }
477
478         if (!m_firstCharacterFits)
479             m_firstCharacterFits = fragment.start() + 1 > endPosition || m_runsWidth <= m_availableWidth;
480     }
481
482     TextFragmentIterator::TextFragment revertToLastCompleteFragment(Layout::RunVector& runs)
483     {
484         if (!m_uncompletedWidth) {
485             ASSERT(m_lastFragment == m_lastCompleteFragment);
486             return m_lastFragment;
487         }
488         ASSERT(m_lastFragment.isValid());
489         m_runsWidth -= m_uncompletedWidth;
490         revertRuns(runs, endPositionForCollapsedFragment(m_lastCompleteFragment), m_uncompletedWidth);
491         m_uncompletedWidth = 0;
492         ASSERT(m_lastCompleteFragment.isValid());
493         return m_lastCompleteFragment;
494     }
495
496     void removeTrailingWhitespace(Layout::RunVector& runs)
497     {
498         if (m_lastFragment.type() != TextFragmentIterator::TextFragment::Whitespace)
499             return;
500         if (m_lastNonWhitespaceFragment) {
501             auto needsReverting = m_lastNonWhitespaceFragment->end() != m_lastFragment.end();
502             // Trailing whitespace fragment might actually have zero length.
503             ASSERT(needsReverting || !m_trailingWhitespaceWidth);
504             if (needsReverting) {
505                 revertRuns(runs, m_lastNonWhitespaceFragment->end(), m_trailingWhitespaceWidth);
506                 m_runsWidth -= m_trailingWhitespaceWidth;
507             }
508             m_trailingWhitespaceWidth = 0;
509             m_lastFragment = *m_lastNonWhitespaceFragment;
510             return;
511         }
512         // This line is all whitespace.
513         revertAllRunsOnCurrentLine(runs);
514         m_runsWidth = 0;
515         m_trailingWhitespaceWidth = 0;
516         // FIXME: Make m_lastFragment optional.
517         m_lastFragment = TextFragmentIterator::TextFragment();
518     }
519
520 private:
521     bool expansionOpportunity(TextFragmentIterator::TextFragment::Type currentFragmentType, TextFragmentIterator::TextFragment::Type previousFragmentType) const
522     {
523         return (currentFragmentType == TextFragmentIterator::TextFragment::Whitespace
524             || (currentFragmentType == TextFragmentIterator::TextFragment::NonWhitespace && previousFragmentType == TextFragmentIterator::TextFragment::NonWhitespace));
525     }
526
527     float m_availableWidth { 0 };
528     float m_logicalLeftOffset { 0 };
529     float m_runsWidth { 0 };
530     TextFragmentIterator::TextFragment m_overflowedFragment;
531     TextFragmentIterator::TextFragment m_lastFragment;
532     std::optional<TextFragmentIterator::TextFragment> m_lastNonWhitespaceFragment;
533     TextFragmentIterator::TextFragment m_lastCompleteFragment;
534     float m_uncompletedWidth { 0 };
535     float m_trailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
536     float m_collapsedWhitespaceWidth { 0 };
537     // Having one character on the line does not necessarily mean it actually fits.
538     // First character of the first fragment might be forced on to the current line even if it does not fit.
539     bool m_firstCharacterFits { false };
540     std::optional<Vector<TextFragmentIterator::TextFragment, 30>> m_fragments;
541 };
542
543 class FragmentForwardIterator : public std::iterator<std::forward_iterator_tag, unsigned> {
544 public:
545     FragmentForwardIterator(unsigned fragmentIndex)
546         : m_fragmentIndex(fragmentIndex)
547     {
548     }
549
550     FragmentForwardIterator& operator++()
551     {
552         ++m_fragmentIndex;
553         return *this;
554     }
555
556     bool operator!=(const FragmentForwardIterator& other) const { return m_fragmentIndex != other.m_fragmentIndex; }
557     bool operator==(const FragmentForwardIterator& other) const { return m_fragmentIndex == other.m_fragmentIndex; }
558     unsigned operator*() const { return m_fragmentIndex; }
559
560 private:
561     unsigned m_fragmentIndex { 0 };
562 };
563
564 static FragmentForwardIterator begin(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.start()); }
565 static FragmentForwardIterator end(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.end()); }
566
567 static bool preWrap(const TextFragmentIterator::Style& style)
568 {
569     return style.wrapLines && !style.collapseWhitespace;
570 }
571     
572 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& runs, const TextFragmentIterator& textFragmentIterator)
573 {
574     if (!lineState.hasTrailingWhitespace())
575         return;
576     // Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce
577     // would produce an empty line.
578     const auto& style = textFragmentIterator.style();
579     bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
580     if (!collapseWhitespace)
581         return;
582     if (preWrap(style) && lineState.isWhitespaceOnly())
583         return;
584     lineState.removeTrailingWhitespace(runs);
585 }
586
587 static void updateLineConstrains(const RenderBlockFlow& flow, LineState& line, const TextFragmentIterator::Style& style, bool isFirstLine)
588 {
589     bool shouldApplyTextIndent = !flow.isAnonymous() || flow.parent()->firstChild() == &flow;
590     LayoutUnit height = flow.logicalHeight();
591     line.setLogicalLeftOffset(flow.logicalLeftOffsetForLine(height, DoNotIndentText) + (shouldApplyTextIndent && isFirstLine ? flow.textIndentOffset() : LayoutUnit(0)));
592     float logicalRightOffset = flow.logicalRightOffsetForLine(height, DoNotIndentText);
593     line.setAvailableWidth(std::max<float>(0, logicalRightOffset - line.logicalLeftOffset()));
594     if (style.textAlign == JUSTIFY)
595         line.setNeedsAllFragments();
596 }
597
598 static std::optional<unsigned> hyphenPositionForFragment(unsigned splitPosition, TextFragmentIterator::TextFragment& fragmentToSplit,
599     const TextFragmentIterator& textFragmentIterator, float availableWidth)
600 {
601     auto& style = textFragmentIterator.style();
602     bool shouldHyphenate = style.shouldHyphenate && (!style.hyphenLimitLines || fragmentToSplit.wrappingWithHyphenCounter() < *style.hyphenLimitLines);
603     if (!shouldHyphenate)
604         return std::nullopt;
605
606     if (!enoughWidthForHyphenation(availableWidth, style.font.pixelSize()))
607         return std::nullopt;
608
609     // We might be able to fit the hyphen at the split position.
610     auto splitPositionWithHyphen = splitPosition;
611     // Find a splitting position where hyphen surely fits.
612     unsigned start = fragmentToSplit.start();
613     auto leftSideWidth = textFragmentIterator.textWidth(start, splitPosition, 0);
614     while (leftSideWidth + style.hyphenStringWidth > availableWidth) {
615         if (--splitPositionWithHyphen <= start)
616             return std::nullopt; // No space for hyphen.
617         leftSideWidth -= textFragmentIterator.textWidth(splitPositionWithHyphen, splitPositionWithHyphen + 1, 0);
618     }
619     ASSERT(splitPositionWithHyphen > start);
620     return textFragmentIterator.lastHyphenPosition(fragmentToSplit, splitPositionWithHyphen + 1);
621 }
622
623 static TextFragmentIterator::TextFragment splitFragmentToFitLine(TextFragmentIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const TextFragmentIterator& textFragmentIterator)
624 {
625     // FIXME: add surrogate pair support.
626     unsigned start = fragmentToSplit.start();
627     auto it = std::upper_bound(begin(fragmentToSplit), end(fragmentToSplit), availableWidth, [&textFragmentIterator, start](float availableWidth, unsigned index) {
628         // FIXME: use the actual left position of the line (instead of 0) to calculated width. It might give false width for tab characters.
629         return availableWidth < textFragmentIterator.textWidth(start, index + 1, 0);
630     });
631     unsigned splitPosition = (*it);
632     // Does first character fit this line?
633     if (splitPosition == start) {
634         if (keepAtLeastOneCharacter)
635             ++splitPosition;
636     } else if (auto hyphenPosition = hyphenPositionForFragment(splitPosition, fragmentToSplit, textFragmentIterator, availableWidth))
637         return fragmentToSplit.splitWithHyphen(*hyphenPosition, textFragmentIterator);
638     return fragmentToSplit.split(splitPosition, textFragmentIterator);
639 }
640
641 enum PreWrapLineBreakRule { Preserve, Ignore };
642
643 static TextFragmentIterator::TextFragment consumeLineBreakIfNeeded(const TextFragmentIterator::TextFragment& fragment, TextFragmentIterator& textFragmentIterator, LineState& line, Layout::RunVector& runs,
644     PreWrapLineBreakRule preWrapLineBreakRule = PreWrapLineBreakRule::Preserve)
645 {
646     if (!fragment.isLineBreak())
647         return fragment;
648
649     if (preWrap(textFragmentIterator.style()) && preWrapLineBreakRule != PreWrapLineBreakRule::Ignore)
650         return fragment;
651
652     // <br> always produces a run. (required by testing output)
653     if (fragment.type() == TextFragmentIterator::TextFragment::HardLineBreak)
654         line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
655     return textFragmentIterator.nextTextFragment();
656 }
657
658 static TextFragmentIterator::TextFragment skipWhitespaceIfNeeded(const TextFragmentIterator::TextFragment& fragment, TextFragmentIterator& textFragmentIterator)
659 {
660     if (!textFragmentIterator.style().collapseWhitespace)
661         return fragment;
662
663     TextFragmentIterator::TextFragment firstNonWhitespaceFragment = fragment;
664     while (firstNonWhitespaceFragment.type() == TextFragmentIterator::TextFragment::Whitespace)
665         firstNonWhitespaceFragment = textFragmentIterator.nextTextFragment();
666     return firstNonWhitespaceFragment;
667 }
668
669 static TextFragmentIterator::TextFragment firstFragment(TextFragmentIterator& textFragmentIterator, LineState& currentLine, const LineState& previousLine, Layout::RunVector& runs)
670 {
671     // Handle overflowed fragment from previous line.
672     TextFragmentIterator::TextFragment firstFragment(previousLine.overflowedFragment());
673
674     if (firstFragment.isEmpty())
675         firstFragment = textFragmentIterator.nextTextFragment();
676     else if (firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace && preWrap(textFragmentIterator.style()) && previousLine.firstCharacterFits()) {
677         // Special overflow pre-wrap whitespace handling: skip the overflowed whitespace (even when style says not-collapsible) if we managed to fit at least one character on the previous line.
678         firstFragment = textFragmentIterator.nextTextFragment();
679         // If skipping the whitespace puts us on a newline, skip the newline too as we already wrapped the line.
680         firstFragment = consumeLineBreakIfNeeded(firstFragment, textFragmentIterator, currentLine, runs, PreWrapLineBreakRule::Ignore);
681     }
682     return skipWhitespaceIfNeeded(firstFragment, textFragmentIterator);
683 }
684
685 static void forceFragmentToLine(LineState& line, TextFragmentIterator& textFragmentIterator, Layout::RunVector& runs, const TextFragmentIterator::TextFragment& fragment)
686 {
687     line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
688     // Check if there are more fragments to add to the current line.
689     auto nextFragment = textFragmentIterator.nextTextFragment();
690     if (fragment.overlapsToNextRenderer()) {
691         while (true) {
692             if (nextFragment.type() != fragment.type())
693                 break;
694             line.appendFragmentAndCreateRunIfNeeded(nextFragment, runs);
695             // Does it overlap to the next segment?
696             if (!nextFragment.overlapsToNextRenderer())
697                 return;
698             nextFragment = textFragmentIterator.nextTextFragment();
699         }
700     }
701     // When the forced fragment is followed by either whitespace and/or line break, consume them too, otherwise we end up with an extra whitespace and/or line break.
702     nextFragment = skipWhitespaceIfNeeded(nextFragment, textFragmentIterator);
703     nextFragment = consumeLineBreakIfNeeded(nextFragment, textFragmentIterator, line, runs);
704     line.setOverflowedFragment(nextFragment);
705 }
706
707 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, TextFragmentIterator& textFragmentIterator)
708 {
709     const auto& style = textFragmentIterator.style();
710     line.setCollapedWhitespaceWidth(style.spaceWidth + style.wordSpacing);
711     bool lineCanBeWrapped = style.wrapLines || style.breakFirstWordOnOverflow || style.breakAnyWordOnOverflow;
712     auto fragment = firstFragment(textFragmentIterator, line, previousLine, runs);
713     while (fragment.type() != TextFragmentIterator::TextFragment::ContentEnd) {
714         // Hard linebreak.
715         if (fragment.isLineBreak()) {
716             // Add the new line fragment only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.)
717             if (line.isEmpty() || fragment.type() == TextFragmentIterator::TextFragment::HardLineBreak) {
718                 if (style.textAlign == RIGHT || style.textAlign == WEBKIT_RIGHT)
719                     line.removeTrailingWhitespace(runs);
720                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
721             }
722             break;
723         }
724         if (lineCanBeWrapped && !line.fits(fragment.width())) {
725             // Overflow wrapping behaviour:
726             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
727             // 2. Whitespace collapse off: whitespace is wrapped.
728             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
729             // 5. Non-whitespace fragment when there's already another fragment on the line either gets wrapped (word-break: break-all)
730             // or gets pushed to the next line.
731             bool emptyLine = line.isEmpty();
732             // Whitespace fragment.
733             if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
734                 if (!style.collapseWhitespace) {
735                     // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
736                     line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
737                     line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
738                 }
739                 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
740                 break;
741             }
742             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
743             if (((emptyLine && style.breakFirstWordOnOverflow) || style.breakAnyWordOnOverflow) || !style.wrapLines) {
744                 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
745                 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
746                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
747                 break;
748             }
749             ASSERT(fragment.type() == TextFragmentIterator::TextFragment::NonWhitespace);
750             // Find out if this non-whitespace fragment has a hyphen where we can break.
751             if (style.shouldHyphenate) {
752                 auto fragmentToSplit = fragment;
753                 // Split and check if we actually ended up with a hyphen.
754                 auto overflowFragment = splitFragmentToFitLine(fragmentToSplit, line.availableWidth() - line.width(), emptyLine, textFragmentIterator);
755                 if (fragmentToSplit.hasHyphen()) {
756                     line.setOverflowedFragment(overflowFragment);
757                     line.appendFragmentAndCreateRunIfNeeded(fragmentToSplit, runs);
758                     break;
759                 }
760                 // No hyphen, no split.
761             }
762             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
763             if (emptyLine) {
764                 forceFragmentToLine(line, textFragmentIterator, runs, fragment);
765                 break;
766             }
767             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
768             ASSERT(line.lastFragment().isValid());
769             if (line.lastFragment().overlapsToNextRenderer()) {
770                 // Check if this fragment is a continuation of a previous segment. In such cases, we need to remove them all.
771                 textFragmentIterator.revertToEndOfFragment(line.revertToLastCompleteFragment(runs));
772                 break;
773             }
774             line.setOverflowedFragment(fragment);
775             break;
776         }
777         line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
778         // Find the next text fragment.
779         fragment = textFragmentIterator.nextTextFragment(line.width());
780     }
781     return (fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty()) || line.overflowedFragment().type() == TextFragmentIterator::TextFragment::ContentEnd;
782 }
783
784 static ExpansionBehavior expansionBehavior(bool isAfterExpansion, bool lastRunOnLine)
785 {
786     ExpansionBehavior expansionBehavior;
787     expansionBehavior = isAfterExpansion ? ForbidLeadingExpansion : AllowLeadingExpansion;
788     expansionBehavior |= lastRunOnLine ? ForbidTrailingExpansion : AllowTrailingExpansion;
789     return expansionBehavior;
790 }
791
792 static void justifyRuns(const LineState& line, Layout::RunVector& runs, unsigned firstRunIndex)
793 {
794     ASSERT(runs.size());
795     auto widthToDistribute = line.availableWidth() - line.width();
796     if (widthToDistribute <= 0)
797         return;
798
799     auto lastRunIndex = runs.size() - 1;
800     ASSERT(firstRunIndex <= lastRunIndex);
801     Vector<std::pair<unsigned, ExpansionBehavior>> expansionOpportunityList;
802     unsigned expansionOpportunityCountOnThisLine = 0;
803     auto isAfterExpansion = true;
804     for (auto i = firstRunIndex; i <= lastRunIndex; ++i) {
805         const auto& run = runs.at(i);
806         unsigned opportunityCountInRun = 0;
807         std::tie(opportunityCountInRun, isAfterExpansion) = line.expansionOpportunityCount(run.start, run.end);
808         expansionOpportunityList.append(std::make_pair(opportunityCountInRun, expansionBehavior(isAfterExpansion, i == lastRunIndex)));
809         expansionOpportunityCountOnThisLine += opportunityCountInRun;
810     }
811     if (!expansionOpportunityCountOnThisLine)
812         return;
813
814     ASSERT(expansionOpportunityList.size() == lastRunIndex - firstRunIndex + 1);
815     auto expansion = widthToDistribute / expansionOpportunityCountOnThisLine;
816     float accumulatedExpansion = 0;
817     for (auto i = firstRunIndex; i <= lastRunIndex; ++i) {
818         auto& run = runs.at(i);
819         unsigned opportunityCountInRun;
820         std::tie(opportunityCountInRun, run.expansionBehavior) = expansionOpportunityList.at(i - firstRunIndex);
821         run.expansion = opportunityCountInRun * expansion;
822         run.logicalLeft += accumulatedExpansion;
823         run.logicalRight += (accumulatedExpansion + run.expansion);
824         accumulatedExpansion += run.expansion;
825     }
826 }
827
828 static ETextAlign textAlignForLine(const TextFragmentIterator::Style& style, bool lastLine)
829 {
830     // Fallback to LEFT (START) alignment for non-collapsable content and for the last line before a forced break or the end of the block.
831     auto textAlign = style.textAlign;
832     if (textAlign == JUSTIFY && (!style.collapseWhitespace || lastLine))
833         textAlign = LEFT;
834     return textAlign;
835 }
836
837 static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, std::optional<unsigned> lastRunIndexOfPreviousLine, unsigned& lineCount,
838     const TextFragmentIterator& textFragmentIterator, bool lastLineInFlow)
839 {
840     if (!runs.size() || (lastRunIndexOfPreviousLine && runs.size() - 1 == lastRunIndexOfPreviousLine.value()))
841         return;
842     removeTrailingWhitespace(line, runs, textFragmentIterator);
843     if (!runs.size())
844         return;
845     // Adjust runs' position by taking line's alignment into account.
846     const auto& style = textFragmentIterator.style();
847     auto firstRunIndex = lastRunIndexOfPreviousLine ? lastRunIndexOfPreviousLine.value() + 1 : 0;
848     auto lineLogicalLeft = line.logicalLeftOffset();
849     auto textAlign = textAlignForLine(style, lastLineInFlow || (line.lastFragment().isValid() && line.lastFragment().type() == TextFragmentIterator::TextFragment::HardLineBreak));
850     if (textAlign == JUSTIFY)
851         justifyRuns(line, runs, firstRunIndex);
852     else
853         lineLogicalLeft = computeLineLeft(textAlign, line.availableWidth(), line.width(), line.logicalLeftOffset());
854     for (auto i = firstRunIndex; i < runs.size(); ++i) {
855         runs[i].logicalLeft += lineLogicalLeft;
856         runs[i].logicalRight += lineLogicalLeft;
857     }
858     runs.last().isEndOfLine = true;
859     ++lineCount;
860 }
861
862 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
863 {
864     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
865     LayoutUnit lineHeight = lineHeightFromFlow(flow);
866     LineState line;
867     bool isEndOfContent = false;
868     TextFragmentIterator textFragmentIterator = TextFragmentIterator(flow);
869     std::optional<unsigned> lastRunIndexOfPreviousLine;
870     do {
871         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
872         LineState previousLine = line;
873         line = LineState();
874         updateLineConstrains(flow, line, textFragmentIterator.style(), !lineCount);
875         isEndOfContent = createLineRuns(line, previousLine, runs, textFragmentIterator);
876         closeLineEndingAndAdjustRuns(line, runs, lastRunIndexOfPreviousLine, lineCount, textFragmentIterator, isEndOfContent);
877         if (runs.size())
878             lastRunIndexOfPreviousLine = runs.size() - 1;
879     } while (!isEndOfContent);
880 }
881
882 std::unique_ptr<Layout> create(RenderBlockFlow& flow)
883 {
884     unsigned lineCount = 0;
885     Layout::RunVector runs;
886     createTextRuns(runs, flow, lineCount);
887     return Layout::create(runs, lineCount);
888 }
889
890 std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
891 {
892     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
893     return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
894 }
895
896 Layout::Layout(const RunVector& runVector, unsigned lineCount)
897     : m_lineCount(lineCount)
898     , m_runCount(runVector.size())
899 {
900     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
901 }
902
903 }
904 }