Regression(r179438) Simple line layout: ASSERTION at SimpleLineLayout::FlowContentsIt...
[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 "InlineTextBox.h"
37 #include "LineWidth.h"
38 #include "PaintInfo.h"
39 #include "RenderBlockFlow.h"
40 #include "RenderChildIterator.h"
41 #include "RenderStyle.h"
42 #include "RenderText.h"
43 #include "RenderTextControl.h"
44 #include "RenderView.h"
45 #include "Settings.h"
46 #include "SimpleLineLayoutFlowContents.h"
47 #include "SimpleLineLayoutFlowContentsIterator.h"
48 #include "SimpleLineLayoutFunctions.h"
49 #include "Text.h"
50 #include "TextPaintStyle.h"
51
52 namespace WebCore {
53 namespace SimpleLineLayout {
54
55 template <typename CharacterType>
56 static bool canUseForText(const CharacterType* text, unsigned length, const Font& font)
57 {
58     // FIXME: <textarea maxlength=0> generates empty text node.
59     if (!length)
60         return false;
61     for (unsigned i = 0; i < length; ++i) {
62         UChar character = text[i];
63         if (character == ' ')
64             continue;
65
66         // These would be easy to support.
67         if (character == noBreakSpace)
68             return false;
69         if (character == softHyphen)
70             return false;
71
72         UCharDirection direction = u_charDirection(character);
73         if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC
74             || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE
75             || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE
76             || direction == U_POP_DIRECTIONAL_FORMAT || direction == U_BOUNDARY_NEUTRAL)
77             return false;
78
79         if (!font.glyphForCharacter(character))
80             return false;
81     }
82     return true;
83 }
84
85 static bool canUseForText(const RenderText& textRenderer, const Font& font)
86 {
87     if (textRenderer.is8Bit())
88         return canUseForText(textRenderer.characters8(), textRenderer.textLength(), font);
89     return canUseForText(textRenderer.characters16(), textRenderer.textLength(), font);
90 }
91
92 bool canUseFor(const RenderBlockFlow& flow)
93 {
94     if (!flow.frame().settings().simpleLineLayoutEnabled())
95         return false;
96     if (!flow.firstChild())
97         return false;
98     // This currently covers <blockflow>#text</blockflow> and mutiple (sibling) RenderText cases.
99     // The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover.
100     for (const auto& renderer : childrenOfType<RenderObject>(flow)) {
101         if (!is<RenderText>(renderer))
102             return false;
103     }
104     if (!flow.isHorizontalWritingMode())
105         return false;
106     if (flow.flowThreadState() != RenderObject::NotInsideFlowThread)
107         return false;
108     // Printing does pagination without a flow thread.
109     if (flow.document().paginated())
110         return false;
111     if (flow.hasOutline())
112         return false;
113     if (flow.isRubyText() || flow.isRubyBase())
114         return false;
115     if (flow.parent()->isDeprecatedFlexibleBox())
116         return false;
117     // FIXME: Implementation of wrap=hard looks into lineboxes.
118     if (flow.parent()->isTextArea() && flow.parent()->element()->fastHasAttribute(HTMLNames::wrapAttr))
119         return false;
120     // FIXME: Placeholders do something strange.
121     if (is<RenderTextControl>(*flow.parent()) && downcast<RenderTextControl>(*flow.parent()).textFormControlElement().placeholderElement())
122         return false;
123     const RenderStyle& style = flow.style();
124     if (style.textDecorationsInEffect() != TextDecorationNone)
125         return false;
126     if (style.textAlign() == JUSTIFY)
127         return false;
128     // Non-visible overflow should be pretty easy to support.
129     if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE)
130         return false;
131     if (!style.textIndent().isZero())
132         return false;
133     if (!style.wordSpacing().isZero() || style.letterSpacing())
134         return false;
135     if (!style.isLeftToRightDirection())
136         return false;
137     if (style.lineBoxContain() != RenderStyle::initialLineBoxContain())
138         return false;
139     if (style.writingMode() != TopToBottomWritingMode)
140         return false;
141     if (style.lineBreak() != LineBreakAuto)
142         return false;
143     if (style.wordBreak() != NormalWordBreak)
144         return false;
145     if (style.unicodeBidi() != UBNormal || style.rtlOrdering() != LogicalOrder)
146         return false;
147     if (style.lineAlign() != LineAlignNone || style.lineSnap() != LineSnapNone)
148         return false;
149     if (style.hyphens() == HyphensAuto)
150         return false;
151     if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone)
152         return false;
153     if (style.textShadow())
154         return false;
155     if (style.textOverflow() || (flow.isAnonymousBlock() && flow.parent()->style().textOverflow()))
156         return false;
157     if (style.hasPseudoStyle(FIRST_LINE) || style.hasPseudoStyle(FIRST_LETTER))
158         return false;
159     if (style.hasTextCombine())
160         return false;
161     if (style.backgroundClip() == TextFillBox)
162         return false;
163     if (style.borderFit() == BorderFitLines)
164         return false;
165     if (style.lineBreak() != LineBreakAuto)
166         return false;
167
168     // 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.
169     if (flow.containsFloats()) {
170         float minimumWidthNeeded = std::numeric_limits<float>::max();
171         for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
172             minimumWidthNeeded = std::min(minimumWidthNeeded, textRenderer.minLogicalWidth());
173
174             for (auto& floatingObject : *flow.floatingObjectSet()) {
175                 ASSERT(floatingObject);
176 #if ENABLE(CSS_SHAPES)
177                 // if a float has a shape, we cannot tell if content will need to be shifted until after we lay it out,
178                 // since the amount of space is not uniform for the height of the float.
179                 if (floatingObject->renderer().shapeOutsideInfo())
180                     return false;
181 #endif
182                 float availableWidth = flow.availableLogicalWidthForLine(floatingObject->y(), false);
183                 if (availableWidth < minimumWidthNeeded)
184                     return false;
185             }
186         }
187     }
188     if (style.fontCascade().primaryFont().isSVGFont())
189         return false;
190     // We assume that all lines have metrics based purely on the primary font.
191     auto& primaryFont = style.fontCascade().primaryFont();
192     if (primaryFont.isLoading())
193         return false;
194     for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
195         if (textRenderer.isCombineText() || textRenderer.isCounter() || textRenderer.isQuote() || textRenderer.isTextFragment()
196             || textRenderer.isSVGInlineText())
197             return false;
198         if (style.fontCascade().codePath(TextRun(textRenderer.text())) != FontCascade::Simple)
199             return false;
200         if (!canUseForText(textRenderer, primaryFont))
201             return false;
202     }
203     return true;
204 }
205
206 static float computeLineLeft(ETextAlign textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)
207 {
208     float remainingWidth = availableWidth - committedWidth;
209     float left = logicalLeftOffset;
210     switch (textAlign) {
211     case LEFT:
212     case WEBKIT_LEFT:
213     case TASTART:
214         return left;
215     case RIGHT:
216     case WEBKIT_RIGHT:
217     case TAEND:
218         return left + std::max<float>(remainingWidth, 0);
219     case CENTER:
220     case WEBKIT_CENTER:
221         return left + std::max<float>(remainingWidth / 2, 0);
222     case JUSTIFY:
223         ASSERT_NOT_REACHED();
224         break;
225     }
226     ASSERT_NOT_REACHED();
227     return 0;
228 }
229
230 class LineState {
231 public:
232     void setAvailableWidth(float width) { m_availableWidth = width; }
233     void setLogicalLeftOffset(float offset) { m_logicalLeftOffset = offset; }
234     void setOverflowedFragment(const FlowContentsIterator::TextFragment& fragment) { m_overflowedFragment = fragment; }
235
236     float availableWidth() const { return m_availableWidth; }
237     float logicalLeftOffset() const { return m_logicalLeftOffset; }
238     const FlowContentsIterator::TextFragment& overflowedFragment() const { return m_overflowedFragment; }
239     bool hasTrailingWhitespace() const { return m_trailingWhitespaceLength; }
240     bool isWhitespaceOnly() const { return m_trailingWhitespaceWidth && m_runsWidth == m_trailingWhitespaceWidth; }
241     bool fits(float extra) const { return m_availableWidth >= m_runsWidth + extra; }
242     bool firstCharacterFits() const { return m_firstCharacterFits; }
243     float width() const { return m_runsWidth; }
244
245     void appendFragment(const FlowContentsIterator::TextFragment& fragment, Layout::RunVector& runs)
246     {
247         // Adjust end position while collapsing.
248         unsigned endPosition = fragment.isCollapsed() ? fragment.start() + 1 : fragment.end();
249
250         if (m_createNewRun)
251             runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
252         else {
253             ASSERT(runs.size());
254             Run& lastRun = runs.last();
255             lastRun.end = endPosition;
256             lastRun.logicalRight = m_runsWidth + fragment.width();
257         }
258         m_createNewRun = fragment.isCollapsed();
259         m_runsWidth += fragment.width();
260
261         if (fragment.type() == FlowContentsIterator::TextFragment::Whitespace) {
262             m_trailingWhitespaceLength += endPosition - fragment.start();
263             m_trailingWhitespaceWidth += fragment.width();
264         } else {
265             m_trailingWhitespaceLength = 0;
266             m_trailingWhitespaceWidth = 0;
267         }
268
269         if (!m_firstCharacterFits)
270             m_firstCharacterFits = fragment.start() + 1 > endPosition || m_runsWidth <= m_availableWidth;
271     }
272
273     void removeTrailingWhitespace(Layout::RunVector& runs)
274     {
275         ASSERT(runs.size());
276         Run& lastRun = runs.last();
277         lastRun.logicalRight -= m_trailingWhitespaceWidth;
278         lastRun.end -= m_trailingWhitespaceLength;
279         if (lastRun.start == lastRun.end)
280             runs.removeLast();
281
282         m_runsWidth -= m_trailingWhitespaceWidth;
283         m_trailingWhitespaceWidth = 0;
284         m_trailingWhitespaceLength = 0;
285     }
286
287 private:
288     float m_availableWidth { 0 };
289     float m_logicalLeftOffset { 0 };
290     FlowContentsIterator::TextFragment m_overflowedFragment;
291     float m_runsWidth { 0 };
292     bool m_createNewRun { true };
293     float m_trailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
294     unsigned m_trailingWhitespaceLength { 0 };
295     // Having one character on the line does not necessarily mean it actually fits.
296     // First character of the first fragment might be forced on to the current line even if it does not fit.
297     bool m_firstCharacterFits { false };
298 };
299
300 static bool preWrap(const FlowContentsIterator::Style& style)
301 {
302     return style.wrapLines && !style.collapseWhitespace;
303 }
304     
305 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& runs, const FlowContentsIterator& flowContentsIterator)
306 {
307     if (!lineState.hasTrailingWhitespace())
308         return;
309     
310     // Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce would produce an empty line.
311     const auto& style = flowContentsIterator.style();
312     bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
313     if (!collapseWhitespace)
314         return;
315
316     if (preWrap(style) && lineState.isWhitespaceOnly())
317         return;
318
319     lineState.removeTrailingWhitespace(runs);
320 }
321
322 static void updateLineConstrains(const RenderBlockFlow& flow, LineState& line)
323 {
324     LayoutUnit height = flow.logicalHeight();
325     LayoutUnit logicalHeight = flow.minLineHeightForReplacedRenderer(false, 0);
326     float logicalRightOffset = flow.logicalRightOffsetForLine(height, false, logicalHeight);
327     line.setLogicalLeftOffset(flow.logicalLeftOffsetForLine(height, false, logicalHeight));
328     line.setAvailableWidth(std::max<float>(0, logicalRightOffset - line.logicalLeftOffset()));
329 }
330
331 static FlowContentsIterator::TextFragment splitFragmentToFitLine(FlowContentsIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const FlowContentsIterator& flowContentsIterator)
332 {
333     // Fast path for single char fragments.
334     if (fragmentToSplit.start() + 1 == fragmentToSplit.end()) {
335         if (keepAtLeastOneCharacter)
336             return FlowContentsIterator::TextFragment();
337
338         FlowContentsIterator::TextFragment fragmentForNextLine(fragmentToSplit);
339         // Make it empty fragment.
340         fragmentToSplit = FlowContentsIterator::TextFragment(fragmentToSplit.start(), fragmentToSplit.start(), 0, fragmentToSplit.type());
341         return fragmentForNextLine;
342     }
343     // Simple binary search to find out what fits the current line.
344     // FIXME: add surrogate pair support.
345     unsigned left = fragmentToSplit.start();
346     unsigned right = fragmentToSplit.end() - 1; // We can ignore the last character. It surely does not fit.
347     float width = 0;
348     while (left < right) {
349         unsigned middle = (left + right) / 2;
350         width = flowContentsIterator.textWidth(fragmentToSplit.start(), middle + 1, 0);
351         if (availableWidth > width)
352             left = middle + 1;
353         else if (availableWidth < width)
354             right = middle;
355         else {
356             right = middle + 1;
357             break;
358         }
359     }
360
361     if (keepAtLeastOneCharacter && right == fragmentToSplit.start())
362         ++right;
363
364     // Fragment for next line.
365     unsigned nextLineStart = right;
366     unsigned nextLineEnd = fragmentToSplit.end();
367     float nextLineWidth = flowContentsIterator.textWidth(nextLineStart, nextLineEnd, 0);
368
369     unsigned thisLineStart = fragmentToSplit.start();
370     unsigned thisLineEnd = right;
371     ASSERT(thisLineStart <= thisLineEnd);
372     float thisLineWidth = thisLineStart < thisLineEnd ? flowContentsIterator.textWidth(thisLineStart, thisLineEnd, 0) : 0;
373     fragmentToSplit = FlowContentsIterator::TextFragment(thisLineStart, thisLineEnd, thisLineWidth, fragmentToSplit.type(), fragmentToSplit.isCollapsed(), fragmentToSplit.isBreakable());
374     return FlowContentsIterator::TextFragment(nextLineStart, nextLineEnd, nextLineWidth, fragmentToSplit.type(), fragmentToSplit.isCollapsed(), fragmentToSplit.isBreakable());
375 }
376
377 static FlowContentsIterator::TextFragment firstFragment(FlowContentsIterator& flowContentsIterator, const LineState& previousLine)
378 {
379     // Handle overflowed fragment from previous line.
380     FlowContentsIterator::TextFragment firstFragment(previousLine.overflowedFragment());
381     const auto& style = flowContentsIterator.style();
382
383     if (firstFragment.isEmpty())
384         firstFragment = flowContentsIterator.nextTextFragment();
385     else {
386         // Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
387         // When the line is too short to fit one character (thought it still stays on the line) we continue with the overflow whitespace content on this line.
388         if (firstFragment.type() == FlowContentsIterator::TextFragment::Whitespace && preWrap(style) && previousLine.firstCharacterFits()) {
389             firstFragment = flowContentsIterator.nextTextFragment();
390             // If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
391             if (firstFragment.type() == FlowContentsIterator::TextFragment::LineBreak)
392                 firstFragment = flowContentsIterator.nextTextFragment();
393         }
394     }
395
396     // Check if we need to skip the leading whitespace.
397     if (style.collapseWhitespace && firstFragment.type() == FlowContentsIterator::TextFragment::Whitespace)
398         firstFragment = flowContentsIterator.nextTextFragment();
399     return firstFragment;
400 }
401
402 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, FlowContentsIterator& flowContentsIterator)
403 {
404     const auto& style = flowContentsIterator.style();
405     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
406     auto fragment = firstFragment(flowContentsIterator, previousLine);
407     while (fragment.type() != FlowContentsIterator::TextFragment::ContentEnd) {
408         // Hard linebreak.
409         if (fragment.type() == FlowContentsIterator::TextFragment::LineBreak) {
410             // 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.)
411             if (!line.width())
412                 line.appendFragment(fragment, runs);
413             break;
414         }
415         if (lineCanBeWrapped && !line.fits(fragment.width())) {
416             // Overflow wrapping behaviour:
417             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
418             // 2. Whitespace collapse off: whitespace is wrapped.
419             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
420             // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
421             bool emptyLine = !line.width();
422             // Whitespace fragment.
423             if (fragment.type() == FlowContentsIterator::TextFragment::Whitespace) {
424                 if (!style.collapseWhitespace) {
425                     // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
426                     line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, flowContentsIterator));
427                     line.appendFragment(fragment, runs);
428                 }
429                 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
430                 break;
431             }
432             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
433             if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
434                 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
435                 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, flowContentsIterator));
436                 line.appendFragment(fragment, runs);
437                 break;
438             }
439             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
440             if (emptyLine) {
441                 line.appendFragment(fragment, runs);
442                 break;
443             }
444             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
445             line.setOverflowedFragment(fragment);
446             break;
447         }
448         line.appendFragment(fragment, runs);
449         // Find the next text fragment.
450         fragment = flowContentsIterator.nextTextFragment(line.width());
451     }
452     return fragment.type() == FlowContentsIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty();
453 }
454
455 static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const FlowContentsIterator& flowContentsIterator)
456 {
457     if (previousRunCount == runs.size())
458         return;
459     ASSERT(runs.size());
460     removeTrailingWhitespace(line, runs, flowContentsIterator);
461     if (!runs.size())
462         return;
463     // Adjust runs' position by taking line's alignment into account.
464     if (float lineLogicalLeft = computeLineLeft(flowContentsIterator.style().textAlign, line.availableWidth(), line.width(), line.logicalLeftOffset())) {
465         for (unsigned i = previousRunCount; i < runs.size(); ++i) {
466             runs[i].logicalLeft += lineLogicalLeft;
467             runs[i].logicalRight += lineLogicalLeft;
468         }
469     }
470     runs.last().isEndOfLine = true;
471     ++lineCount;
472 }
473
474 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContentsIterator& flowContentsIterator)
475 {
476     // FIXME: We should probably split during run construction instead of as a separate pass.
477     if (lineRuns.isEmpty())
478         return;
479     unsigned runIndex = 0;
480     do {
481         const Run& run = lineRuns.at(runIndex);
482         ASSERT(run.start != run.end);
483         auto& startSegment = flowContentsIterator.segmentForPosition(run.start);
484         if (run.end <= startSegment.end)
485             continue;
486         // This run overlaps multiple renderers. Split it up.
487         // Split run at the renderer's boundary and create a new run for the left side, while use the current run as the right side.
488         float logicalRightOfLeftRun = run.logicalLeft + flowContentsIterator.textWidth(run.start, startSegment.end, run.logicalLeft);
489         lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
490         Run& rightSideRun = lineRuns.at(runIndex + 1);
491         rightSideRun.start = startSegment.end;
492         rightSideRun.logicalLeft = logicalRightOfLeftRun;
493     } while (++runIndex < lineRuns.size());
494 }
495
496 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
497 {
498     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
499     LayoutUnit lineHeight = lineHeightFromFlow(flow);
500     LineState line;
501     bool isEndOfContent = false;
502     FlowContentsIterator flowContentsIterator = FlowContentsIterator(flow);
503
504     do {
505         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
506         LineState previousLine = line;
507         unsigned previousRunCount = runs.size();
508         line = LineState();
509         updateLineConstrains(flow, line);
510         isEndOfContent = createLineRuns(line, previousLine, runs, flowContentsIterator);
511         closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, flowContentsIterator);
512     } while (!isEndOfContent);
513
514     if (flow.firstChild() != flow.lastChild())
515         splitRunsAtRendererBoundary(runs, flowContentsIterator);
516 }
517
518 std::unique_ptr<Layout> create(RenderBlockFlow& flow)
519 {
520     unsigned lineCount = 0;
521     Layout::RunVector runs;
522
523     createTextRuns(runs, flow, lineCount);
524     for (auto& renderer : childrenOfType<RenderObject>(flow)) {
525         ASSERT(is<RenderText>(renderer));
526         renderer.clearNeedsLayout();
527     }
528     return Layout::create(runs, lineCount);
529 }
530
531 std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
532 {
533     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
534     return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
535 }
536
537 Layout::Layout(const RunVector& runVector, unsigned lineCount)
538     : m_lineCount(lineCount)
539     , m_runCount(runVector.size())
540 {
541     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
542 }
543
544 }
545 }