Unreviewed, rolling out r180599.
[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
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 TextFragmentIterator::TextFragment& fragment) { m_overflowedFragment = fragment; }
235
236     float availableWidth() const { return m_availableWidth; }
237     float logicalLeftOffset() const { return m_logicalLeftOffset; }
238     const TextFragmentIterator::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 TextFragmentIterator::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() == TextFragmentIterator::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     TextFragmentIterator::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 class FragmentForwardIterator : public std::iterator<std::forward_iterator_tag, unsigned> {
301 public:
302     FragmentForwardIterator(unsigned fragmentIndex)
303         : m_fragmentIndex(fragmentIndex)
304     {
305     }
306
307     FragmentForwardIterator& operator++()
308     {
309         ++m_fragmentIndex;
310         return *this;
311     }
312
313     bool operator!=(const FragmentForwardIterator& other) const { return m_fragmentIndex != other.m_fragmentIndex; }
314     unsigned operator*() const { return m_fragmentIndex; }
315
316 private:
317     unsigned m_fragmentIndex { 0 };
318 };
319
320 static FragmentForwardIterator begin(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.start()); }
321 static FragmentForwardIterator end(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.end()); }
322
323 static bool preWrap(const TextFragmentIterator::Style& style)
324 {
325     return style.wrapLines && !style.collapseWhitespace;
326 }
327     
328 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& runs, const TextFragmentIterator& textFragmentIterator)
329 {
330     if (!lineState.hasTrailingWhitespace())
331         return;
332     
333     // 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.
334     const auto& style = textFragmentIterator.style();
335     bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
336     if (!collapseWhitespace)
337         return;
338
339     if (preWrap(style) && lineState.isWhitespaceOnly())
340         return;
341
342     lineState.removeTrailingWhitespace(runs);
343 }
344
345 static void updateLineConstrains(const RenderBlockFlow& flow, LineState& line)
346 {
347     LayoutUnit height = flow.logicalHeight();
348     LayoutUnit logicalHeight = flow.minLineHeightForReplacedRenderer(false, 0);
349     float logicalRightOffset = flow.logicalRightOffsetForLine(height, false, logicalHeight);
350     line.setLogicalLeftOffset(flow.logicalLeftOffsetForLine(height, false, logicalHeight));
351     line.setAvailableWidth(std::max<float>(0, logicalRightOffset - line.logicalLeftOffset()));
352 }
353
354 static TextFragmentIterator::TextFragment splitFragmentToFitLine(TextFragmentIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const TextFragmentIterator& textFragmentIterator)
355 {
356     // FIXME: add surrogate pair support.
357     unsigned start = fragmentToSplit.start();
358     auto it = std::upper_bound(begin(fragmentToSplit), end(fragmentToSplit), availableWidth, [&textFragmentIterator, start](float availableWidth, unsigned index) {
359         // FIXME: use the actual left position of the line (instead of 0) to calculated width. It might give false width for tab characters.
360         return availableWidth < textFragmentIterator.textWidth(start, index + 1, 0);
361     });
362     unsigned splitPosition = (*it);
363     if (keepAtLeastOneCharacter && splitPosition == fragmentToSplit.start())
364         ++splitPosition;
365     return fragmentToSplit.split(splitPosition, textFragmentIterator);
366 }
367
368 static TextFragmentIterator::TextFragment firstFragment(TextFragmentIterator& textFragmentIterator, const LineState& previousLine)
369 {
370     // Handle overflowed fragment from previous line.
371     TextFragmentIterator::TextFragment firstFragment(previousLine.overflowedFragment());
372     const auto& style = textFragmentIterator.style();
373
374     if (firstFragment.isEmpty())
375         firstFragment = textFragmentIterator.nextTextFragment();
376     else {
377         // Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
378         // 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.
379         if (firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace && preWrap(style) && previousLine.firstCharacterFits()) {
380             firstFragment = textFragmentIterator.nextTextFragment();
381             // If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
382             if (firstFragment.type() == TextFragmentIterator::TextFragment::LineBreak)
383                 firstFragment = textFragmentIterator.nextTextFragment();
384         }
385     }
386
387     // Check if we need to skip the leading whitespace.
388     if (style.collapseWhitespace && firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace)
389         firstFragment = textFragmentIterator.nextTextFragment();
390     return firstFragment;
391 }
392
393 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, TextFragmentIterator& textFragmentIterator)
394 {
395     const auto& style = textFragmentIterator.style();
396     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
397     auto fragment = firstFragment(textFragmentIterator, previousLine);
398     while (fragment.type() != TextFragmentIterator::TextFragment::ContentEnd) {
399         // Hard linebreak.
400         if (fragment.type() == TextFragmentIterator::TextFragment::LineBreak) {
401             // 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.)
402             if (!line.width())
403                 line.appendFragment(fragment, runs);
404             break;
405         }
406         if (lineCanBeWrapped && !line.fits(fragment.width())) {
407             // Overflow wrapping behaviour:
408             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
409             // 2. Whitespace collapse off: whitespace is wrapped.
410             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
411             // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
412             bool emptyLine = !line.width();
413             // Whitespace fragment.
414             if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
415                 if (!style.collapseWhitespace) {
416                     // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
417                     line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
418                     line.appendFragment(fragment, runs);
419                 }
420                 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
421                 break;
422             }
423             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
424             if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
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, textFragmentIterator));
427                 line.appendFragment(fragment, runs);
428                 break;
429             }
430             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
431             if (emptyLine) {
432                 line.appendFragment(fragment, runs);
433                 break;
434             }
435             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
436             line.setOverflowedFragment(fragment);
437             break;
438         }
439         line.appendFragment(fragment, runs);
440         // Find the next text fragment.
441         fragment = textFragmentIterator.nextTextFragment(line.width());
442     }
443     return fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty();
444 }
445
446 static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const TextFragmentIterator& textFragmentIterator)
447 {
448     if (previousRunCount == runs.size())
449         return;
450     ASSERT(runs.size());
451     removeTrailingWhitespace(line, runs, textFragmentIterator);
452     if (!runs.size())
453         return;
454     // Adjust runs' position by taking line's alignment into account.
455     if (float lineLogicalLeft = computeLineLeft(textFragmentIterator.style().textAlign, line.availableWidth(), line.width(), line.logicalLeftOffset())) {
456         for (unsigned i = previousRunCount; i < runs.size(); ++i) {
457             runs[i].logicalLeft += lineLogicalLeft;
458             runs[i].logicalRight += lineLogicalLeft;
459         }
460     }
461     runs.last().isEndOfLine = true;
462     ++lineCount;
463 }
464
465 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const TextFragmentIterator& textFragmentIterator)
466 {
467     // FIXME: We should probably split during run construction instead of as a separate pass.
468     if (lineRuns.isEmpty())
469         return;
470     unsigned runIndex = 0;
471     do {
472         const Run& run = lineRuns.at(runIndex);
473         ASSERT(run.start != run.end);
474         auto& startSegment = textFragmentIterator.segmentForPosition(run.start);
475         if (run.end <= startSegment.end)
476             continue;
477         // This run overlaps multiple renderers. Split it up.
478         // 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.
479         float logicalRightOfLeftRun = run.logicalLeft + textFragmentIterator.textWidth(run.start, startSegment.end, run.logicalLeft);
480         lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
481         Run& rightSideRun = lineRuns.at(runIndex + 1);
482         rightSideRun.start = startSegment.end;
483         rightSideRun.logicalLeft = logicalRightOfLeftRun;
484     } while (++runIndex < lineRuns.size());
485 }
486
487 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
488 {
489     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
490     LayoutUnit lineHeight = lineHeightFromFlow(flow);
491     LineState line;
492     bool isEndOfContent = false;
493     TextFragmentIterator textFragmentIterator = TextFragmentIterator(flow);
494
495     do {
496         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
497         LineState previousLine = line;
498         unsigned previousRunCount = runs.size();
499         line = LineState();
500         updateLineConstrains(flow, line);
501         isEndOfContent = createLineRuns(line, previousLine, runs, textFragmentIterator);
502         closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, textFragmentIterator);
503     } while (!isEndOfContent);
504
505     if (flow.firstChild() != flow.lastChild())
506         splitRunsAtRendererBoundary(runs, textFragmentIterator);
507 }
508
509 std::unique_ptr<Layout> create(RenderBlockFlow& flow)
510 {
511     unsigned lineCount = 0;
512     Layout::RunVector runs;
513
514     createTextRuns(runs, flow, lineCount);
515     for (auto& renderer : childrenOfType<RenderObject>(flow)) {
516         ASSERT(is<RenderText>(renderer));
517         renderer.clearNeedsLayout();
518     }
519     return Layout::create(runs, lineCount);
520 }
521
522 std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
523 {
524     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
525     return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
526 }
527
528 Layout::Layout(const RunVector& runVector, unsigned lineCount)
529     : m_lineCount(lineCount)
530     , m_runCount(runVector.size())
531 {
532     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
533 }
534
535 }
536 }