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