Unreviewed, rolling out r181667, r181682, and r181683.
[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 "SimpleLineLayoutFunctions.h"
48 #include "SimpleLineLayoutTextFragmentIterator.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 #if ENABLE(CSS_TRAILING_WORD)
168     if (style.trailingWord() != TrailingWord::Auto)
169         return false;
170 #endif
171
172     // 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.
173     if (flow.containsFloats()) {
174         float minimumWidthNeeded = std::numeric_limits<float>::max();
175         for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
176             minimumWidthNeeded = std::min(minimumWidthNeeded, textRenderer.minLogicalWidth());
177
178             for (auto& floatingObject : *flow.floatingObjectSet()) {
179                 ASSERT(floatingObject);
180 #if ENABLE(CSS_SHAPES)
181                 // if a float has a shape, we cannot tell if content will need to be shifted until after we lay it out,
182                 // since the amount of space is not uniform for the height of the float.
183                 if (floatingObject->renderer().shapeOutsideInfo())
184                     return false;
185 #endif
186                 float availableWidth = flow.availableLogicalWidthForLine(floatingObject->y(), false);
187                 if (availableWidth < minimumWidthNeeded)
188                     return false;
189             }
190         }
191     }
192     if (style.fontCascade().primaryFont().isSVGFont())
193         return false;
194     // We assume that all lines have metrics based purely on the primary font.
195     auto& primaryFont = style.fontCascade().primaryFont();
196     if (primaryFont.isLoading())
197         return false;
198     for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
199         if (textRenderer.isCombineText() || textRenderer.isCounter() || textRenderer.isQuote() || textRenderer.isTextFragment()
200             || textRenderer.isSVGInlineText())
201             return false;
202         if (style.fontCascade().codePath(TextRun(textRenderer.text())) != FontCascade::Simple)
203             return false;
204         if (!canUseForText(textRenderer, primaryFont))
205             return false;
206     }
207     return true;
208 }
209
210 static float computeLineLeft(ETextAlign textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)
211 {
212     float remainingWidth = availableWidth - committedWidth;
213     float left = logicalLeftOffset;
214     switch (textAlign) {
215     case LEFT:
216     case WEBKIT_LEFT:
217     case TASTART:
218         return left;
219     case RIGHT:
220     case WEBKIT_RIGHT:
221     case TAEND:
222         return left + std::max<float>(remainingWidth, 0);
223     case CENTER:
224     case WEBKIT_CENTER:
225         return left + std::max<float>(remainingWidth / 2, 0);
226     case JUSTIFY:
227         ASSERT_NOT_REACHED();
228         break;
229     }
230     ASSERT_NOT_REACHED();
231     return 0;
232 }
233
234 class LineState {
235 public:
236     void setAvailableWidth(float width) { m_availableWidth = width; }
237     void setLogicalLeftOffset(float offset) { m_logicalLeftOffset = offset; }
238     void setOverflowedFragment(const TextFragmentIterator::TextFragment& fragment) { m_overflowedFragment = fragment; }
239
240     float availableWidth() const { return m_availableWidth; }
241     float logicalLeftOffset() const { return m_logicalLeftOffset; }
242     const TextFragmentIterator::TextFragment& overflowedFragment() const { return m_overflowedFragment; }
243     bool hasTrailingWhitespace() const { return m_trailingWhitespaceLength; }
244     bool isWhitespaceOnly() const { return m_trailingWhitespaceWidth && m_runsWidth == m_trailingWhitespaceWidth; }
245     bool fits(float extra) const { return m_availableWidth >= m_runsWidth + extra; }
246     bool firstCharacterFits() const { return m_firstCharacterFits; }
247     float width() const { return m_runsWidth; }
248
249     void appendFragment(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs)
250     {
251         // Adjust end position while collapsing.
252         unsigned endPosition = fragment.isCollapsed() ? fragment.start() + 1 : fragment.end();
253
254         if (m_createNewRun)
255             runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
256         else {
257             ASSERT(runs.size());
258             Run& lastRun = runs.last();
259             lastRun.end = endPosition;
260             lastRun.logicalRight = m_runsWidth + fragment.width();
261         }
262         m_createNewRun = fragment.isCollapsed();
263         m_runsWidth += fragment.width();
264
265         if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
266             m_trailingWhitespaceLength += endPosition - fragment.start();
267             m_trailingWhitespaceWidth += fragment.width();
268         } else {
269             m_trailingWhitespaceLength = 0;
270             m_trailingWhitespaceWidth = 0;
271         }
272
273         if (!m_firstCharacterFits)
274             m_firstCharacterFits = fragment.start() + 1 > endPosition || m_runsWidth <= m_availableWidth;
275     }
276
277     void removeTrailingWhitespace(Layout::RunVector& runs)
278     {
279         ASSERT(runs.size());
280         Run& lastRun = runs.last();
281         lastRun.logicalRight -= m_trailingWhitespaceWidth;
282         lastRun.end -= m_trailingWhitespaceLength;
283         if (lastRun.start == lastRun.end)
284             runs.removeLast();
285
286         m_runsWidth -= m_trailingWhitespaceWidth;
287         m_trailingWhitespaceWidth = 0;
288         m_trailingWhitespaceLength = 0;
289     }
290
291 private:
292     float m_availableWidth { 0 };
293     float m_logicalLeftOffset { 0 };
294     TextFragmentIterator::TextFragment m_overflowedFragment;
295     float m_runsWidth { 0 };
296     bool m_createNewRun { true };
297     float m_trailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
298     unsigned m_trailingWhitespaceLength { 0 };
299     // Having one character on the line does not necessarily mean it actually fits.
300     // First character of the first fragment might be forced on to the current line even if it does not fit.
301     bool m_firstCharacterFits { false };
302 };
303
304 class FragmentForwardIterator : public std::iterator<std::forward_iterator_tag, unsigned> {
305 public:
306     FragmentForwardIterator(unsigned fragmentIndex)
307         : m_fragmentIndex(fragmentIndex)
308     {
309     }
310
311     FragmentForwardIterator& operator++()
312     {
313         ++m_fragmentIndex;
314         return *this;
315     }
316
317     bool operator!=(const FragmentForwardIterator& other) const { return m_fragmentIndex != other.m_fragmentIndex; }
318     unsigned operator*() const { return m_fragmentIndex; }
319
320 private:
321     unsigned m_fragmentIndex { 0 };
322 };
323
324 static FragmentForwardIterator begin(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.start()); }
325 static FragmentForwardIterator end(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.end()); }
326
327 static bool preWrap(const TextFragmentIterator::Style& style)
328 {
329     return style.wrapLines && !style.collapseWhitespace;
330 }
331     
332 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& runs, const TextFragmentIterator& textFragmentIterator)
333 {
334     if (!lineState.hasTrailingWhitespace())
335         return;
336     
337     // 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.
338     const auto& style = textFragmentIterator.style();
339     bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
340     if (!collapseWhitespace)
341         return;
342
343     if (preWrap(style) && lineState.isWhitespaceOnly())
344         return;
345
346     lineState.removeTrailingWhitespace(runs);
347 }
348
349 static void updateLineConstrains(const RenderBlockFlow& flow, LineState& line)
350 {
351     LayoutUnit height = flow.logicalHeight();
352     LayoutUnit logicalHeight = flow.minLineHeightForReplacedRenderer(false, 0);
353     float logicalRightOffset = flow.logicalRightOffsetForLine(height, false, logicalHeight);
354     line.setLogicalLeftOffset(flow.logicalLeftOffsetForLine(height, false, logicalHeight));
355     line.setAvailableWidth(std::max<float>(0, logicalRightOffset - line.logicalLeftOffset()));
356 }
357
358 static TextFragmentIterator::TextFragment splitFragmentToFitLine(TextFragmentIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const TextFragmentIterator& textFragmentIterator)
359 {
360     // FIXME: add surrogate pair support.
361     unsigned start = fragmentToSplit.start();
362     auto it = std::upper_bound(begin(fragmentToSplit), end(fragmentToSplit), availableWidth, [&textFragmentIterator, start](float availableWidth, unsigned index) {
363         // FIXME: use the actual left position of the line (instead of 0) to calculated width. It might give false width for tab characters.
364         return availableWidth < textFragmentIterator.textWidth(start, index + 1, 0);
365     });
366     unsigned splitPosition = (*it);
367     if (keepAtLeastOneCharacter && splitPosition == fragmentToSplit.start())
368         ++splitPosition;
369     return fragmentToSplit.split(splitPosition, textFragmentIterator);
370 }
371
372 static TextFragmentIterator::TextFragment firstFragment(TextFragmentIterator& textFragmentIterator, const LineState& previousLine)
373 {
374     // Handle overflowed fragment from previous line.
375     TextFragmentIterator::TextFragment firstFragment(previousLine.overflowedFragment());
376     const auto& style = textFragmentIterator.style();
377
378     if (firstFragment.isEmpty())
379         firstFragment = textFragmentIterator.nextTextFragment();
380     else {
381         // Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
382         // 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.
383         if (firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace && preWrap(style) && previousLine.firstCharacterFits()) {
384             firstFragment = textFragmentIterator.nextTextFragment();
385             // If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
386             if (firstFragment.type() == TextFragmentIterator::TextFragment::LineBreak)
387                 firstFragment = textFragmentIterator.nextTextFragment();
388         }
389     }
390
391     // Check if we need to skip the leading whitespace.
392     if (style.collapseWhitespace && firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace)
393         firstFragment = textFragmentIterator.nextTextFragment();
394     return firstFragment;
395 }
396
397 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, TextFragmentIterator& textFragmentIterator)
398 {
399     const auto& style = textFragmentIterator.style();
400     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
401     auto fragment = firstFragment(textFragmentIterator, previousLine);
402     while (fragment.type() != TextFragmentIterator::TextFragment::ContentEnd) {
403         // Hard linebreak.
404         if (fragment.type() == TextFragmentIterator::TextFragment::LineBreak) {
405             // 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.)
406             if (!line.width())
407                 line.appendFragment(fragment, runs);
408             break;
409         }
410         if (lineCanBeWrapped && !line.fits(fragment.width())) {
411             // Overflow wrapping behaviour:
412             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
413             // 2. Whitespace collapse off: whitespace is wrapped.
414             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
415             // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
416             bool emptyLine = !line.width();
417             // Whitespace fragment.
418             if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
419                 if (!style.collapseWhitespace) {
420                     // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
421                     line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
422                     line.appendFragment(fragment, runs);
423                 }
424                 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
425                 break;
426             }
427             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
428             if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
429                 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
430                 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
431                 line.appendFragment(fragment, runs);
432                 break;
433             }
434             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
435             if (emptyLine) {
436                 line.appendFragment(fragment, runs);
437                 break;
438             }
439             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
440             line.setOverflowedFragment(fragment);
441             break;
442         }
443         line.appendFragment(fragment, runs);
444         // Find the next text fragment.
445         fragment = textFragmentIterator.nextTextFragment(line.width());
446     }
447     return fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty();
448 }
449
450 static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const TextFragmentIterator& textFragmentIterator)
451 {
452     if (previousRunCount == runs.size())
453         return;
454     ASSERT(runs.size());
455     removeTrailingWhitespace(line, runs, textFragmentIterator);
456     if (!runs.size())
457         return;
458     // Adjust runs' position by taking line's alignment into account.
459     if (float lineLogicalLeft = computeLineLeft(textFragmentIterator.style().textAlign, line.availableWidth(), line.width(), line.logicalLeftOffset())) {
460         for (unsigned i = previousRunCount; i < runs.size(); ++i) {
461             runs[i].logicalLeft += lineLogicalLeft;
462             runs[i].logicalRight += lineLogicalLeft;
463         }
464     }
465     runs.last().isEndOfLine = true;
466     ++lineCount;
467 }
468
469 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const TextFragmentIterator& textFragmentIterator)
470 {
471     // FIXME: We should probably split during run construction instead of as a separate pass.
472     if (lineRuns.isEmpty())
473         return;
474     unsigned runIndex = 0;
475     do {
476         const Run& run = lineRuns.at(runIndex);
477         ASSERT(run.start != run.end);
478         auto& startSegment = textFragmentIterator.segmentForPosition(run.start);
479         if (run.end <= startSegment.end)
480             continue;
481         // This run overlaps multiple renderers. Split it up.
482         // 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.
483         float logicalRightOfLeftRun = run.logicalLeft + textFragmentIterator.textWidth(run.start, startSegment.end, run.logicalLeft);
484         lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
485         Run& rightSideRun = lineRuns.at(runIndex + 1);
486         rightSideRun.start = startSegment.end;
487         rightSideRun.logicalLeft = logicalRightOfLeftRun;
488     } while (++runIndex < lineRuns.size());
489 }
490
491 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
492 {
493     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
494     LayoutUnit lineHeight = lineHeightFromFlow(flow);
495     LineState line;
496     bool isEndOfContent = false;
497     TextFragmentIterator textFragmentIterator = TextFragmentIterator(flow);
498
499     do {
500         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
501         LineState previousLine = line;
502         unsigned previousRunCount = runs.size();
503         line = LineState();
504         updateLineConstrains(flow, line);
505         isEndOfContent = createLineRuns(line, previousLine, runs, textFragmentIterator);
506         closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, textFragmentIterator);
507     } while (!isEndOfContent);
508
509     if (flow.firstChild() != flow.lastChild())
510         splitRunsAtRendererBoundary(runs, textFragmentIterator);
511 }
512
513 std::unique_ptr<Layout> create(RenderBlockFlow& flow)
514 {
515     unsigned lineCount = 0;
516     Layout::RunVector runs;
517
518     createTextRuns(runs, flow, lineCount);
519     for (auto& renderer : childrenOfType<RenderObject>(flow)) {
520         ASSERT(is<RenderText>(renderer));
521         renderer.clearNeedsLayout();
522     }
523     return Layout::create(runs, lineCount);
524 }
525
526 std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
527 {
528     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
529     return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
530 }
531
532 Layout::Layout(const RunVector& runVector, unsigned lineCount)
533     : m_lineCount(lineCount)
534     , m_runCount(runVector.size())
535 {
536     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
537 }
538
539 }
540 }