43c50f3e81f144a8f5ecf3405a975727b8b6acef
[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 struct LineState {
231     void createRun(Layout::RunVector& lineRuns)
232     {
233         if (segmentStart == segmentEnd)
234             return;
235
236         lineRuns.append(Run(segmentStart, segmentEnd, runsWidth, runsWidth + segmentWidth, false));
237         // Move uncommitted to committed.
238         runsWidth += segmentWidth;
239         lastRunTrailingWhitespaceWidth = segmentTrailingWhitespaceWidth;
240         lastRunTrailingWhitespaceLength = segmentTrailingWhitespaceLength;
241         if (!m_firstCharacterFits)
242             m_firstCharacterFits = segmentStart + 1 > segmentEnd || runsWidth <= availableWidth;
243
244         segmentStart = segmentEnd;
245         segmentWidth = 0;
246         segmentTrailingWhitespaceWidth = 0;
247         segmentTrailingWhitespaceLength = 0;
248         m_newSegment = true;
249     }
250
251     void addFragment(const FlowContentsIterator::TextFragment& fragment)
252     {
253         // Start a new uncommitted segment.
254         if (m_newSegment) {
255             segmentStart = fragment.start;
256             m_newSegment = false;
257         }
258         segmentWidth += fragment.width;
259         segmentEnd = fragment.end;
260         segmentTrailingWhitespaceWidth = fragment.type == FlowContentsIterator::TextFragment::Whitespace ? fragment.width : 0;
261         segmentTrailingWhitespaceLength = fragment.type == FlowContentsIterator::TextFragment::Whitespace ? fragment.end - fragment.start  : 0;
262     }
263
264     void addWhitespace(float whitespaceWidth)
265     {
266         addFragment(FlowContentsIterator::TextFragment(segmentEnd, segmentEnd + 1, whitespaceWidth, true));
267     }
268
269     bool hasWhitespaceOnly() const
270     {
271         return lastRunTrailingWhitespaceWidth && runsWidth == lastRunTrailingWhitespaceWidth;
272     }
273
274     float width() const
275     {
276         return runsWidth + segmentWidth;
277     }
278
279     bool fits(float extra) const
280     {
281         return availableWidth >= width() + extra;
282     }
283
284     bool firstCharacterFits() const { return m_firstCharacterFits; }
285
286     void removeTrailingWhitespace()
287     {
288         runsWidth -= lastRunTrailingWhitespaceWidth;
289         lastRunTrailingWhitespaceWidth = 0;
290         lastRunTrailingWhitespaceLength = 0;
291     }
292
293     float availableWidth { 0 };
294     float logicalLeftOffset { 0 };
295     float runsWidth { 0 };
296     float lastRunTrailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
297     unsigned lastRunTrailingWhitespaceLength { 0 };
298     FlowContentsIterator::TextFragment overflowedFragment;
299
300 private:
301     unsigned segmentStart { 0 };
302     unsigned segmentEnd { 0 };
303     float segmentWidth { 0 };
304     float segmentTrailingWhitespaceWidth { 0 };
305     unsigned segmentTrailingWhitespaceLength { 0 };
306     // Having one character on the line does not necessarily mean it actually fits.
307     // First character of the first fragment might be forced on to the current line even if it does not fit.
308     bool m_firstCharacterFits { false };
309     bool m_newSegment { true };
310 };
311
312 static bool preWrap(const FlowContentsIterator::Style& style)
313 {
314     return style.wrapLines && !style.collapseWhitespace;
315 }
316     
317 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& lineRuns, const FlowContentsIterator& flowContentsIterator)
318 {
319     if (!lineState.lastRunTrailingWhitespaceLength)
320         return;
321     
322     // 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.
323     const auto& style = flowContentsIterator.style();
324     bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
325     if (!collapseWhitespace)
326         return;
327
328     if (preWrap(style) && lineState.hasWhitespaceOnly())
329         return;
330
331     ASSERT(lineRuns.size());
332     Run& lastRun = lineRuns.last();
333     lastRun.logicalRight -= lineState.lastRunTrailingWhitespaceWidth;
334     lastRun.end -= lineState.lastRunTrailingWhitespaceLength;
335     if (lastRun.start == lastRun.end)
336         lineRuns.removeLast();
337     lineState.removeTrailingWhitespace();
338 }
339
340 static void updateLineConstrains(const RenderBlockFlow& flow, float& availableWidth, float& logicalLeftOffset)
341 {
342     LayoutUnit height = flow.logicalHeight();
343     LayoutUnit logicalHeight = flow.minLineHeightForReplacedRenderer(false, 0);
344     float logicalRightOffset = flow.logicalRightOffsetForLine(height, false, logicalHeight);
345     logicalLeftOffset = flow.logicalLeftOffsetForLine(height, false, logicalHeight);
346     availableWidth = std::max<float>(0, logicalRightOffset - logicalLeftOffset);
347 }
348
349 static FlowContentsIterator::TextFragment splitFragmentToFitLine(FlowContentsIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const FlowContentsIterator& flowContentsIterator)
350 {
351     // Fast path for single char fragments.
352     if (fragmentToSplit.start + 1 == fragmentToSplit.end) {
353         if (keepAtLeastOneCharacter)
354             return FlowContentsIterator::TextFragment();
355
356         FlowContentsIterator::TextFragment fragmentForNextLine(fragmentToSplit);
357         fragmentToSplit.end = fragmentToSplit.start;
358         fragmentToSplit.width = 0;
359         return fragmentForNextLine;
360     }
361     // Simple binary search to find out what fits the current line.
362     // FIXME: add surrogate pair support.
363     unsigned left = fragmentToSplit.start;
364     unsigned right = fragmentToSplit.end - 1; // We can ignore the last character. It surely does not fit.
365     float width = 0;
366     while (left < right) {
367         unsigned middle = (left + right) / 2;
368         width = flowContentsIterator.textWidth(fragmentToSplit.start, middle + 1, 0);
369         if (availableWidth > width)
370             left = middle + 1;
371         else if (availableWidth < width)
372             right = middle;
373         else {
374             right = middle + 1;
375             break;
376         }
377     }
378
379     if (keepAtLeastOneCharacter && right == fragmentToSplit.start)
380         ++right;
381     FlowContentsIterator::TextFragment fragmentForNextLine(fragmentToSplit);
382     fragmentToSplit.end = right;
383     fragmentToSplit.width = fragmentToSplit.isEmpty() ? 0 : flowContentsIterator.textWidth(fragmentToSplit.start, fragmentToSplit.end, 0);
384
385     fragmentForNextLine.start = fragmentToSplit.end;
386     fragmentForNextLine.width -= fragmentToSplit.width;
387     return fragmentForNextLine;
388 }
389
390 static FlowContentsIterator::TextFragment firstFragment(FlowContentsIterator& flowContentsIterator, const LineState& previousLine)
391 {
392     // Handle overflowed fragment from previous line.
393     FlowContentsIterator::TextFragment firstFragment = previousLine.overflowedFragment;
394     const auto& style = flowContentsIterator.style();
395
396     if (firstFragment.isEmpty())
397         firstFragment = flowContentsIterator.nextTextFragment();
398     else {
399         // Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
400         // 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.
401         if (firstFragment.type == FlowContentsIterator::TextFragment::Whitespace && preWrap(style) && previousLine.firstCharacterFits()) {
402             firstFragment = flowContentsIterator.nextTextFragment();
403             // If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
404             if (firstFragment.type == FlowContentsIterator::TextFragment::LineBreak)
405                 firstFragment = flowContentsIterator.nextTextFragment();
406         }
407     }
408
409     // Check if we need to skip the leading whitespace.
410     if (style.collapseWhitespace && firstFragment.type == FlowContentsIterator::TextFragment::Whitespace)
411         firstFragment = flowContentsIterator.nextTextFragment();
412     return firstFragment;
413 }
414
415 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& lineRuns, FlowContentsIterator& flowContentsIterator)
416 {
417     const auto& style = flowContentsIterator.style();
418     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
419     auto fragment = firstFragment(flowContentsIterator, previousLine);
420     while (!fragment.isEmpty()) {
421         // Hard linebreak.
422         if (fragment.type == FlowContentsIterator::TextFragment::LineBreak) {
423             // 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.)
424             if (!line.width())
425                 line.addFragment(fragment);
426             break;
427         }
428         if (lineCanBeWrapped && !line.fits(fragment.width)) {
429             // Overflow wrapping behaviour:
430             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
431             // 2. Whitespace collapse off: whitespace is wrapped.
432             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
433             // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
434             bool emptyLine = !line.width();
435             // Whitespace fragment.
436             if (fragment.type == FlowContentsIterator::TextFragment::Whitespace) {
437                 if (!style.collapseWhitespace) {
438                     // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
439                     line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContentsIterator);
440                     line.addFragment(fragment);
441                 }
442                 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
443                 break;
444             }
445             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
446             if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
447                 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
448                 line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContentsIterator);
449                 line.addFragment(fragment);
450                 break;
451             }
452             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
453             if (emptyLine) {
454                 line.addFragment(fragment);
455                 break;
456             }
457             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
458             line.overflowedFragment = fragment;
459             break;
460         }
461         // When the current fragment is collapsed whitespace, we need to create a run for what we've processed so far.
462         if (fragment.isCollapsed) {
463             // One trailing whitespace to preserve.
464             line.addWhitespace(style.spaceWidth);
465             line.createRun(lineRuns);
466         } else
467             line.addFragment(fragment);
468         // Find the next text fragment.
469         fragment = flowContentsIterator.nextTextFragment(line.width());
470     }
471     line.createRun(lineRuns);
472     return fragment.isEmpty() && line.overflowedFragment.isEmpty();
473 }
474
475 static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const FlowContentsIterator& flowContentsIterator)
476 {
477     if (previousRunCount == runs.size())
478         return;
479     ASSERT(runs.size());
480     removeTrailingWhitespace(line, runs, flowContentsIterator);
481     if (!runs.size())
482         return;
483     // Adjust runs' position by taking line's alignment into account.
484     if (float lineLogicalLeft = computeLineLeft(flowContentsIterator.style().textAlign, line.availableWidth, line.runsWidth, line.logicalLeftOffset)) {
485         for (unsigned i = previousRunCount; i < runs.size(); ++i) {
486             runs[i].logicalLeft += lineLogicalLeft;
487             runs[i].logicalRight += lineLogicalLeft;
488         }
489     }
490     runs.last().isEndOfLine = true;
491     ++lineCount;
492 }
493
494 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContentsIterator& flowContentsIterator)
495 {
496     // FIXME: We should probably split during run construction instead of as a separate pass.
497     if (lineRuns.isEmpty())
498         return;
499     unsigned runIndex = 0;
500     do {
501         const Run& run = lineRuns.at(runIndex);
502         ASSERT(run.start != run.end);
503         auto& startSegment = flowContentsIterator.segmentForPosition(run.start);
504         if (run.end <= startSegment.end)
505             continue;
506         // This run overlaps multiple renderers. Split it up.
507         // 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.
508         float logicalRightOfLeftRun = run.logicalLeft + flowContentsIterator.textWidth(run.start, startSegment.end, run.logicalLeft);
509         lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
510         Run& rightSideRun = lineRuns.at(runIndex + 1);
511         rightSideRun.start = startSegment.end;
512         rightSideRun.logicalLeft = logicalRightOfLeftRun;
513     } while (++runIndex < lineRuns.size());
514 }
515
516 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
517 {
518     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
519     LayoutUnit lineHeight = lineHeightFromFlow(flow);
520     LineState line;
521     bool isEndOfContent = false;
522     FlowContentsIterator flowContentsIterator = FlowContentsIterator(flow);
523
524     do {
525         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
526         LineState previousLine = line;
527         unsigned previousRunCount = runs.size();
528         line = LineState();
529         updateLineConstrains(flow, line.availableWidth, line.logicalLeftOffset);
530         isEndOfContent = createLineRuns(line, previousLine, runs, flowContentsIterator);
531         closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, flowContentsIterator);
532     } while (!isEndOfContent);
533
534     if (flow.firstChild() != flow.lastChild())
535         splitRunsAtRendererBoundary(runs, flowContentsIterator);
536 }
537
538 std::unique_ptr<Layout> create(RenderBlockFlow& flow)
539 {
540     unsigned lineCount = 0;
541     Layout::RunVector runs;
542
543     createTextRuns(runs, flow, lineCount);
544     for (auto& renderer : childrenOfType<RenderObject>(flow)) {
545         ASSERT(is<RenderText>(renderer));
546         renderer.clearNeedsLayout();
547     }
548     return Layout::create(runs, lineCount);
549 }
550
551 std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
552 {
553     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
554     return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
555 }
556
557 Layout::Layout(const RunVector& runVector, unsigned lineCount)
558     : m_lineCount(lineCount)
559     , m_runCount(runVector.size())
560 {
561     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
562 }
563
564 }
565 }