ASSERTION FAILED: !simpleLineLayout() in WebCore::RenderText::collectSelectionRectsFo...
[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 "Logging.h"
39 #include "PaintInfo.h"
40 #include "RenderBlockFlow.h"
41 #include "RenderChildIterator.h"
42 #include "RenderLineBreak.h"
43 #include "RenderStyle.h"
44 #include "RenderText.h"
45 #include "RenderTextControl.h"
46 #include "RenderView.h"
47 #include "Settings.h"
48 #include "SimpleLineLayoutFlowContents.h"
49 #include "SimpleLineLayoutFunctions.h"
50 #include "SimpleLineLayoutTextFragmentIterator.h"
51 #include "Text.h"
52 #include "TextPaintStyle.h"
53 #include "TextStream.h"
54
55 namespace WebCore {
56 namespace SimpleLineLayout {
57
58 #ifndef NDEBUG
59 void printSimpleLineLayoutCoverage();
60 void printSimpleLineLayoutBlockList();
61 #endif
62
63 enum AvoidanceReason_ : uint64_t {
64     FlowIsInsideRegion                  = 1LLU  << 0,
65     FlowHasHorizonalWritingMode         = 1LLU  << 1,
66     FlowHasOutline                      = 1LLU  << 2,
67     FlowIsRuby                          = 1LLU  << 3,
68     FlowIsPaginated                     = 1LLU  << 4,
69     FlowHasTextOverflow                 = 1LLU  << 5,
70     FlowIsDepricatedFlexBox             = 1LLU  << 6,
71     FlowParentIsPlaceholderElement      = 1LLU  << 7,
72     FlowParentIsTextAreaWithWrapping    = 1LLU  << 8,
73     FlowHasNonSupportedChild            = 1LLU  << 9,
74     FlowHasUnsupportedFloat             = 1LLU  << 10,
75     FlowHasTextDecoration               = 1LLU  << 11,
76     FlowIsJustifyAligned                = 1LLU  << 12,
77     FlowHasOverflowVisible              = 1LLU  << 13,
78     FlowIsNotLTR                        = 1LLU  << 14,
79     FlowHasLineBoxContainProperty       = 1LLU  << 15,
80     FlowIsNotTopToBottom                = 1LLU  << 16,
81     FlowHasLineBreak                    = 1LLU  << 17,
82     FlowHasWordBreak                    = 1LLU  << 18,
83     FlowHasNonNormalUnicodeBiDi         = 1LLU  << 19,
84     FlowHasRTLOrdering                  = 1LLU  << 20,
85     FlowHasLineAlignEdges               = 1LLU  << 21,
86     FlowHasLineSnap                     = 1LLU  << 22,
87     FlowHasHypensAuto                   = 1LLU  << 23,
88     FlowHasTextEmphasisFillOrMark       = 1LLU  << 24,
89     FlowHasTextShadow                   = 1LLU  << 25,
90     FlowHasPseudoFirstLine              = 1LLU  << 26,
91     FlowHasPseudoFirstLetter            = 1LLU  << 27,
92     FlowHasTextCombine                  = 1LLU  << 28,
93     FlowHasTextFillBox                  = 1LLU  << 29,
94     FlowHasBorderFitLines               = 1LLU  << 30,
95     FlowHasNonAutoLineBreak             = 1LLU  << 31,
96     FlowHasNonAutoTrailingWord          = 1LLU  << 32,
97     FlowHasSVGFont                      = 1LLU  << 33,
98     FlowTextIsEmpty                     = 1LLU  << 34,
99     FlowTextHasNoBreakSpace             = 1LLU  << 35,
100     FlowTextHasSoftHyphen               = 1LLU  << 36,
101     FlowTextHasDirectionCharacter       = 1LLU  << 37,
102     FlowIsMissingPrimaryFont            = 1LLU  << 38,
103     FlowFontIsMissingGlyph              = 1LLU  << 39,
104     FlowTextIsCombineText               = 1LLU  << 40,
105     FlowTextIsRenderCounter             = 1LLU  << 41,
106     FlowTextIsRenderQuote               = 1LLU  << 42,
107     FlowTextIsTextFragment              = 1LLU  << 43,
108     FlowTextIsSVGInlineText             = 1LLU  << 44,
109     FlowFontIsNotSimple                 = 1LLU  << 45,
110     FeatureIsDisabled                   = 1LLU  << 46,
111     FlowHasNoParent                     = 1LLU  << 47,
112     FlowHasNoChild                      = 1LLU  << 48,
113     FlowChildIsSelected                 = 1LLU  << 49,
114     EndOfReasons                        = 1LLU  << 50
115 };
116 const unsigned NoReason = 0;
117
118 typedef uint64_t AvoidanceReason;
119 typedef uint64_t AvoidanceReasonFlags;
120
121 enum class IncludeReasons { First , All };
122
123 #ifndef NDEBUG
124 #define SET_REASON_AND_RETURN_IF_NEEDED(reason, reasons, includeReasons) { \
125         reasons |= reason; \
126         if (includeReasons == IncludeReasons::First) \
127             return reasons; \
128     }
129 #else
130 #define SET_REASON_AND_RETURN_IF_NEEDED(reason, reasons, includeReasons) { \
131         ASSERT_UNUSED(includeReasons, includeReasons == IncludeReasons::First); \
132         reasons |= reason; \
133         return reasons; \
134     }
135 #endif
136
137 template <typename CharacterType>
138 static AvoidanceReasonFlags canUseForText(const CharacterType* text, unsigned length, const Font& font, IncludeReasons includeReasons)
139 {
140     AvoidanceReasonFlags reasons = { };
141     // FIXME: <textarea maxlength=0> generates empty text node.
142     if (!length)
143         SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsEmpty, reasons, includeReasons);
144
145     for (unsigned i = 0; i < length; ++i) {
146         UChar character = text[i];
147         if (character == ' ')
148             continue;
149
150         // These would be easy to support.
151         if (character == noBreakSpace)
152             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasNoBreakSpace, reasons, includeReasons);
153         if (character == softHyphen)
154             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasSoftHyphen, reasons, includeReasons);
155
156         UCharDirection direction = u_charDirection(character);
157         if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC
158             || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE
159             || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE
160             || direction == U_POP_DIRECTIONAL_FORMAT || direction == U_BOUNDARY_NEUTRAL)
161             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasDirectionCharacter, reasons, includeReasons);
162
163         if (!font.glyphForCharacter(character))
164             SET_REASON_AND_RETURN_IF_NEEDED(FlowFontIsMissingGlyph, reasons, includeReasons);
165     }
166     return reasons;
167 }
168
169 static AvoidanceReasonFlags canUseForText(const RenderText& textRenderer, const Font& font, IncludeReasons includeReasons)
170 {
171     if (textRenderer.is8Bit())
172         return canUseForText(textRenderer.characters8(), textRenderer.textLength(), font, includeReasons);
173     return canUseForText(textRenderer.characters16(), textRenderer.textLength(), font, includeReasons);
174 }
175
176 static AvoidanceReasonFlags canUseForFontAndText(const RenderBlockFlow& flow, IncludeReasons includeReasons)
177 {
178     AvoidanceReasonFlags reasons = { };
179     // We assume that all lines have metrics based purely on the primary font.
180     const auto& style = flow.style();
181     auto& primaryFont = style.fontCascade().primaryFont();
182     if (primaryFont.isLoading())
183         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsMissingPrimaryFont, reasons, includeReasons);
184     if (primaryFont.isSVGFont())
185         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasSVGFont, reasons, includeReasons);
186
187     for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
188         if (textRenderer.isCombineText())
189             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsCombineText, reasons, includeReasons);
190         if (textRenderer.isCounter())
191             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsRenderCounter, reasons, includeReasons);
192         if (textRenderer.isQuote())
193             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsRenderQuote, reasons, includeReasons);
194         if (textRenderer.isTextFragment())
195             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsTextFragment, reasons, includeReasons);
196         if (textRenderer.isSVGInlineText())
197             SET_REASON_AND_RETURN_IF_NEEDED(FlowTextIsSVGInlineText, reasons, includeReasons);
198         if (style.fontCascade().codePath(TextRun(textRenderer.text())) != FontCascade::Simple)
199             SET_REASON_AND_RETURN_IF_NEEDED(FlowFontIsNotSimple, reasons, includeReasons);
200
201         auto textReasons = canUseForText(textRenderer, primaryFont, includeReasons);
202         if (textReasons != NoReason)
203             SET_REASON_AND_RETURN_IF_NEEDED(textReasons, reasons, includeReasons);
204     }
205     return reasons;
206 }
207
208 static AvoidanceReasonFlags canUseForStyle(const RenderStyle& style, IncludeReasons includeReasons)
209 {
210     AvoidanceReasonFlags reasons = { };
211     if (style.textOverflow())
212         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextOverflow, reasons, includeReasons);
213     if (style.textDecorationsInEffect() != TextDecorationNone)
214         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextDecoration, reasons, includeReasons);
215     if (style.textAlign() == JUSTIFY)
216         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsJustifyAligned, reasons, includeReasons);
217     // Non-visible overflow should be pretty easy to support.
218     if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE)
219         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasOverflowVisible, reasons, includeReasons);
220     if (!style.isLeftToRightDirection())
221         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsNotLTR, reasons, includeReasons);
222     if (style.lineBoxContain() != RenderStyle::initialLineBoxContain())
223         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineBoxContainProperty, reasons, includeReasons);
224     if (style.writingMode() != TopToBottomWritingMode)
225         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsNotTopToBottom, reasons, includeReasons);
226     if (style.lineBreak() != LineBreakAuto)
227         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineBreak, reasons, includeReasons);
228     if (style.wordBreak() != NormalWordBreak)
229         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasWordBreak, reasons, includeReasons);
230     if (style.unicodeBidi() != UBNormal)
231         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonNormalUnicodeBiDi, reasons, includeReasons);
232     if (style.rtlOrdering() != LogicalOrder)
233         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasRTLOrdering, reasons, includeReasons);
234     if (style.lineAlign() != LineAlignNone)
235         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineAlignEdges, reasons, includeReasons);
236     if (style.lineSnap() != LineSnapNone)
237         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineSnap, reasons, includeReasons);
238     if (style.hyphens() == HyphensAuto)
239         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHypensAuto, reasons, includeReasons);
240     if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone)
241         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextEmphasisFillOrMark, reasons, includeReasons);
242     if (style.textShadow())
243         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextShadow, reasons, includeReasons);
244     if (style.hasPseudoStyle(FIRST_LINE))
245         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasPseudoFirstLine, reasons, includeReasons);
246     if (style.hasPseudoStyle(FIRST_LETTER))
247         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasPseudoFirstLetter, reasons, includeReasons);
248     if (style.hasTextCombine())
249         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextCombine, reasons, includeReasons);
250     if (style.backgroundClip() == TextFillBox)
251         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextFillBox, reasons, includeReasons);
252     if (style.borderFit() == BorderFitLines)
253         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasBorderFitLines, reasons, includeReasons);
254     if (style.lineBreak() != LineBreakAuto)
255         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonAutoLineBreak, reasons, includeReasons);
256 #if ENABLE(CSS_TRAILING_WORD)
257     if (style.trailingWord() != TrailingWord::Auto)
258         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonAutoTrailingWord, reasons, includeReasons);
259 #endif
260     return reasons;
261 }
262
263 static AvoidanceReasonFlags canUseForWithReason(const RenderBlockFlow& flow, IncludeReasons includeReasons)
264 {
265 #ifndef NDEBUG
266     static std::once_flag onceFlag;
267     std::call_once(onceFlag, [] {
268         registerNotifyCallback("com.apple.WebKit.showSimpleLineLayoutCoverage", printSimpleLineLayoutCoverage);
269         registerNotifyCallback("com.apple.WebKit.showSimpleLineLayoutReasons", printSimpleLineLayoutBlockList);
270     });
271 #endif
272     AvoidanceReasonFlags reasons = { };
273     if (!flow.frame().settings().simpleLineLayoutEnabled())
274         SET_REASON_AND_RETURN_IF_NEEDED(FeatureIsDisabled, reasons, includeReasons);
275     if (!flow.parent())
276         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNoParent, reasons, includeReasons);
277     if (!flow.firstChild())
278         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNoChild, reasons, includeReasons);
279     if (flow.flowThreadState() != RenderObject::NotInsideFlowThread)
280         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsInsideRegion, reasons, includeReasons);
281     if (!flow.isHorizontalWritingMode())
282         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHorizonalWritingMode, reasons, includeReasons);
283     if (flow.hasOutline())
284         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasOutline, reasons, includeReasons);
285     if (flow.isRubyText() || flow.isRubyBase())
286         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsRuby, reasons, includeReasons);
287     // Printing does pagination without a flow thread.
288     if (flow.document().paginated())
289         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsPaginated, reasons, includeReasons);
290     if (flow.isAnonymous() && flow.firstLineBlock())
291         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasPseudoFirstLine, reasons, includeReasons);
292     if (flow.isAnonymousBlock() && flow.parent()->style().textOverflow())
293         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextOverflow, reasons, includeReasons);
294     if (flow.parent()->isDeprecatedFlexibleBox())
295         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsDepricatedFlexBox, reasons, includeReasons);
296     // FIXME: Placeholders do something strange.
297     if (is<RenderTextControl>(*flow.parent()) && downcast<RenderTextControl>(*flow.parent()).textFormControlElement().placeholderElement())
298         SET_REASON_AND_RETURN_IF_NEEDED(FlowParentIsPlaceholderElement, reasons, includeReasons);
299     // FIXME: Implementation of wrap=hard looks into lineboxes.
300     if (flow.parent()->isTextArea() && flow.parent()->element()->fastHasAttribute(HTMLNames::wrapAttr))
301         SET_REASON_AND_RETURN_IF_NEEDED(FlowParentIsTextAreaWithWrapping, reasons, includeReasons);
302     // This currently covers <blockflow>#text</blockflow>, <blockflow>#text<br></blockflow> and mutiple (sibling) RenderText cases.
303     // The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover.
304     for (const auto* child = flow.firstChild(); child;) {
305         if (child->selectionState() != RenderObject::SelectionNone)
306             SET_REASON_AND_RETURN_IF_NEEDED(FlowChildIsSelected, reasons, includeReasons);
307         if (is<RenderText>(*child)) {
308             child = child->nextSibling();
309             continue;
310         }
311         if (is<RenderLineBreak>(child) && !downcast<RenderLineBreak>(*child).isWBR() && child->style().clear() == CNONE) {
312             child = child->nextSibling();
313             continue;
314         }
315         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonSupportedChild, reasons, includeReasons);
316         break;
317     }
318     auto styleReasons = canUseForStyle(flow.style(), includeReasons);
319     if (styleReasons != NoReason)
320         SET_REASON_AND_RETURN_IF_NEEDED(styleReasons, reasons, includeReasons);
321     // 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.
322     if (flow.containsFloats()) {
323         float minimumWidthNeeded = std::numeric_limits<float>::max();
324         for (const auto& textRenderer : childrenOfType<RenderText>(flow)) {
325             minimumWidthNeeded = std::min(minimumWidthNeeded, textRenderer.minLogicalWidth());
326
327             for (auto& floatingObject : *flow.floatingObjectSet()) {
328                 ASSERT(floatingObject);
329 #if ENABLE(CSS_SHAPES)
330                 // if a float has a shape, we cannot tell if content will need to be shifted until after we lay it out,
331                 // since the amount of space is not uniform for the height of the float.
332                 if (floatingObject->renderer().shapeOutsideInfo())
333                     SET_REASON_AND_RETURN_IF_NEEDED(FlowHasUnsupportedFloat, reasons, includeReasons);
334 #endif
335                 float availableWidth = flow.availableLogicalWidthForLine(floatingObject->y(), false);
336                 if (availableWidth < minimumWidthNeeded)
337                     SET_REASON_AND_RETURN_IF_NEEDED(FlowHasUnsupportedFloat, reasons, includeReasons);
338             }
339         }
340     }
341     auto fontAndTextReasons = canUseForFontAndText(flow, includeReasons);
342     if (fontAndTextReasons != NoReason)
343         SET_REASON_AND_RETURN_IF_NEEDED(fontAndTextReasons, reasons, includeReasons);
344     return reasons;
345 }
346
347 bool canUseFor(const RenderBlockFlow& flow)
348 {
349     return canUseForWithReason(flow, IncludeReasons::First) == NoReason;
350 }
351
352 static float computeLineLeft(ETextAlign textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)
353 {
354     float remainingWidth = availableWidth - committedWidth;
355     float left = logicalLeftOffset;
356     switch (textAlign) {
357     case LEFT:
358     case WEBKIT_LEFT:
359     case TASTART:
360         return left;
361     case RIGHT:
362     case WEBKIT_RIGHT:
363     case TAEND:
364         return left + std::max<float>(remainingWidth, 0);
365     case CENTER:
366     case WEBKIT_CENTER:
367         return left + std::max<float>(remainingWidth / 2, 0);
368     case JUSTIFY:
369         ASSERT_NOT_REACHED();
370         break;
371     }
372     ASSERT_NOT_REACHED();
373     return 0;
374 }
375
376 static void revertRuns(Layout::RunVector& runs, unsigned length, float width)
377 {
378     while (length) {
379         ASSERT(runs.size());
380         Run& lastRun = runs.last();
381         unsigned lastRunLength = lastRun.end - lastRun.start;
382         if (lastRunLength > length) {
383             lastRun.logicalRight -= width;
384             lastRun.end -= length;
385             break;
386         }
387         length -= lastRunLength;
388         width -= (lastRun.logicalRight - lastRun.logicalLeft);
389         runs.removeLast();
390     }
391 }
392
393 class LineState {
394 public:
395     void setAvailableWidth(float width) { m_availableWidth = width; }
396     void setCollapedWhitespaceWidth(float width) { m_collapsedWhitespaceWidth = width; }
397     void setLogicalLeftOffset(float offset) { m_logicalLeftOffset = offset; }
398     void setOverflowedFragment(const TextFragmentIterator::TextFragment& fragment) { m_overflowedFragment = fragment; }
399
400     float availableWidth() const { return m_availableWidth; }
401     float logicalLeftOffset() const { return m_logicalLeftOffset; }
402     const TextFragmentIterator::TextFragment& overflowedFragment() const { return m_overflowedFragment; }
403     bool hasTrailingWhitespace() const { return m_trailingWhitespaceLength; }
404     TextFragmentIterator::TextFragment lastFragment() const { return m_fragments.last(); }
405     bool isWhitespaceOnly() const { return m_trailingWhitespaceWidth && m_runsWidth == m_trailingWhitespaceWidth; }
406     bool fits(float extra) const { return m_availableWidth >= m_runsWidth + extra; }
407     bool firstCharacterFits() const { return m_firstCharacterFits; }
408     float width() const { return m_runsWidth; }
409     bool isEmpty() const
410     {
411         if (!m_fragments.size())
412             return true;
413         if (!m_lastCompleteFragment.isEmpty())
414             return false;
415         return m_fragments.last().overlapsToNextRenderer();
416     }
417
418     void appendFragmentAndCreateRunIfNeeded(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs)
419     {
420         // Adjust end position while collapsing.
421         unsigned endPosition = fragment.isCollapsed() ? fragment.start() + 1 : fragment.end();
422         // New line needs new run.
423         if (!m_runsWidth)
424             runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
425         else {
426             const auto& lastFragment = m_fragments.last();
427             // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers)
428             if ((lastFragment.type() != fragment.type()) || !lastFragment.overlapsToNextRenderer())
429                 m_lastCompleteFragment = lastFragment;
430             // Collapse neighbouring whitespace, if they are across multiple renderers and are not collapsed yet.
431             if (lastFragment.isCollapsible() && fragment.isCollapsible()) {
432                 ASSERT(lastFragment.isLastInRenderer());
433                 if (!lastFragment.isCollapsed()) {
434                     // Line width needs to be reset so that now it takes collapsing into consideration.
435                     m_runsWidth -= (lastFragment.width() - m_collapsedWhitespaceWidth);
436                 }
437                 // This fragment is collapsed completely. No run is needed.
438                 return;
439             }
440             if (lastFragment.isLastInRenderer() || lastFragment.isCollapsed())
441                 runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
442             else {
443                 Run& lastRun = runs.last();
444                 lastRun.end = endPosition;
445                 lastRun.logicalRight += fragment.width();
446             }
447         }
448         m_fragments.append(fragment);
449         m_runsWidth += fragment.width();
450
451         if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
452             m_trailingWhitespaceLength += endPosition - fragment.start();
453             m_trailingWhitespaceWidth += fragment.width();
454         } else {
455             m_trailingWhitespaceLength = 0;
456             m_trailingWhitespaceWidth = 0;
457         }
458
459         if (!m_firstCharacterFits)
460             m_firstCharacterFits = fragment.start() + 1 > endPosition || m_runsWidth <= m_availableWidth;
461     }
462
463     TextFragmentIterator::TextFragment revertToLastCompleteFragment(Layout::RunVector& runs)
464     {
465         ASSERT(m_fragments.size());
466         unsigned revertLength = 0;
467         float revertWidth = 0;
468         while (m_fragments.size()) {
469             const auto& current = m_fragments.last();
470             if (current == m_lastCompleteFragment)
471                 break;
472             revertLength += current.end() - current.start();
473             revertWidth += current.width();
474             m_fragments.removeLast();
475         }
476         m_runsWidth -= revertWidth;
477         if (revertLength)
478             revertRuns(runs, revertLength, revertWidth);
479         return m_lastCompleteFragment;
480     }
481
482     void removeTrailingWhitespace(Layout::RunVector& runs)
483     {
484         if (!m_trailingWhitespaceLength)
485             return;
486         revertRuns(runs, m_trailingWhitespaceLength, m_trailingWhitespaceWidth);
487         m_runsWidth -= m_trailingWhitespaceWidth;
488         ASSERT(m_fragments.last().type() == TextFragmentIterator::TextFragment::Whitespace);
489         while (m_fragments.size()) {
490             const auto& current = m_fragments.last();
491             if (current.type() != TextFragmentIterator::TextFragment::Whitespace)
492                 break;
493 #if !ASSERT_DISABLED
494             m_trailingWhitespaceLength -= (current.isCollapsed() ? 1 : current.end() - current.start());
495             m_trailingWhitespaceWidth -= current.width();
496 #endif
497             m_fragments.removeLast();
498         }
499 #if !ASSERT_DISABLED
500         ASSERT(!m_trailingWhitespaceLength);
501         ASSERT(!m_trailingWhitespaceWidth);
502 #endif
503         m_trailingWhitespaceLength = 0;
504         m_trailingWhitespaceWidth = 0;
505     }
506
507 private:
508     float m_availableWidth { 0 };
509     float m_logicalLeftOffset { 0 };
510     TextFragmentIterator::TextFragment m_overflowedFragment;
511     float m_runsWidth { 0 };
512     TextFragmentIterator::TextFragment m_lastCompleteFragment;
513     float m_trailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
514     unsigned m_trailingWhitespaceLength { 0 };
515     float m_collapsedWhitespaceWidth { 0 };
516     // Having one character on the line does not necessarily mean it actually fits.
517     // First character of the first fragment might be forced on to the current line even if it does not fit.
518     bool m_firstCharacterFits { false };
519     Vector<TextFragmentIterator::TextFragment> m_fragments;
520 };
521
522 class FragmentForwardIterator : public std::iterator<std::forward_iterator_tag, unsigned> {
523 public:
524     FragmentForwardIterator(unsigned fragmentIndex)
525         : m_fragmentIndex(fragmentIndex)
526     {
527     }
528
529     FragmentForwardIterator& operator++()
530     {
531         ++m_fragmentIndex;
532         return *this;
533     }
534
535     bool operator!=(const FragmentForwardIterator& other) const { return m_fragmentIndex != other.m_fragmentIndex; }
536     unsigned operator*() const { return m_fragmentIndex; }
537
538 private:
539     unsigned m_fragmentIndex { 0 };
540 };
541
542 static FragmentForwardIterator begin(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.start()); }
543 static FragmentForwardIterator end(const TextFragmentIterator::TextFragment& fragment)  { return FragmentForwardIterator(fragment.end()); }
544
545 static bool preWrap(const TextFragmentIterator::Style& style)
546 {
547     return style.wrapLines && !style.collapseWhitespace;
548 }
549     
550 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& runs, const TextFragmentIterator& textFragmentIterator)
551 {
552     if (!lineState.hasTrailingWhitespace())
553         return;
554
555     // 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.
556     const auto& style = textFragmentIterator.style();
557     bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
558     if (!collapseWhitespace)
559         return;
560
561     if (preWrap(style) && lineState.isWhitespaceOnly())
562         return;
563
564     lineState.removeTrailingWhitespace(runs);
565 }
566
567 static void updateLineConstrains(const RenderBlockFlow& flow, LineState& line, bool isFirstLine)
568 {
569     bool shouldApplyTextIndent = !flow.isAnonymous() || flow.parent()->firstChild() == &flow;
570     LayoutUnit height = flow.logicalHeight();
571     LayoutUnit logicalHeight = flow.minLineHeightForReplacedRenderer(false, 0);
572     float logicalRightOffset = flow.logicalRightOffsetForLine(height, false, logicalHeight);
573     line.setLogicalLeftOffset(flow.logicalLeftOffsetForLine(height, false, logicalHeight) + (shouldApplyTextIndent && isFirstLine ? flow.textIndentOffset() : LayoutUnit(0)));
574     line.setAvailableWidth(std::max<float>(0, logicalRightOffset - line.logicalLeftOffset()));
575 }
576
577 static TextFragmentIterator::TextFragment splitFragmentToFitLine(TextFragmentIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const TextFragmentIterator& textFragmentIterator)
578 {
579     // FIXME: add surrogate pair support.
580     unsigned start = fragmentToSplit.start();
581     auto it = std::upper_bound(begin(fragmentToSplit), end(fragmentToSplit), availableWidth, [&textFragmentIterator, start](float availableWidth, unsigned index) {
582         // FIXME: use the actual left position of the line (instead of 0) to calculated width. It might give false width for tab characters.
583         return availableWidth < textFragmentIterator.textWidth(start, index + 1, 0);
584     });
585     unsigned splitPosition = (*it);
586     if (keepAtLeastOneCharacter && splitPosition == fragmentToSplit.start())
587         ++splitPosition;
588     return fragmentToSplit.split(splitPosition, textFragmentIterator);
589 }
590
591 enum PreWrapLineBreakRule { Preserve, Ignore };
592
593 static TextFragmentIterator::TextFragment consumeLineBreakIfNeeded(const TextFragmentIterator::TextFragment& fragment, TextFragmentIterator& textFragmentIterator, LineState& line, Layout::RunVector& runs,
594     PreWrapLineBreakRule preWrapLineBreakRule = PreWrapLineBreakRule::Preserve)
595 {
596     if (!fragment.isLineBreak())
597         return fragment;
598
599     if (preWrap(textFragmentIterator.style()) && preWrapLineBreakRule != PreWrapLineBreakRule::Ignore)
600         return fragment;
601
602     // <br> always produces a run. (required by testing output)
603     if (fragment.type() == TextFragmentIterator::TextFragment::HardLineBreak)
604         line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
605     return textFragmentIterator.nextTextFragment();
606 }
607
608 static TextFragmentIterator::TextFragment skipWhitespaceIfNeeded(const TextFragmentIterator::TextFragment& fragment, TextFragmentIterator& textFragmentIterator)
609 {
610     if (!textFragmentIterator.style().collapseWhitespace)
611         return fragment;
612
613     TextFragmentIterator::TextFragment firstNonWhitespaceFragment = fragment;
614     while (firstNonWhitespaceFragment.type() == TextFragmentIterator::TextFragment::Whitespace)
615         firstNonWhitespaceFragment = textFragmentIterator.nextTextFragment();
616     return firstNonWhitespaceFragment;
617 }
618
619 static TextFragmentIterator::TextFragment firstFragment(TextFragmentIterator& textFragmentIterator, LineState& currentLine, const LineState& previousLine, Layout::RunVector& runs)
620 {
621     // Handle overflowed fragment from previous line.
622     TextFragmentIterator::TextFragment firstFragment(previousLine.overflowedFragment());
623
624     if (firstFragment.isEmpty())
625         firstFragment = textFragmentIterator.nextTextFragment();
626     else if (firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace && preWrap(textFragmentIterator.style()) && previousLine.firstCharacterFits()) {
627         // Special overflow pre-wrap whitespace handling: skip the overflowed whitespace (even when style says not-collapsible) if we managed to fit at least one character on the previous line.
628         firstFragment = textFragmentIterator.nextTextFragment();
629         // If skipping the whitespace puts us on a newline, skip the newline too as we already wrapped the line.
630         firstFragment = consumeLineBreakIfNeeded(firstFragment, textFragmentIterator, currentLine, runs, PreWrapLineBreakRule::Ignore);
631     }
632     return skipWhitespaceIfNeeded(firstFragment, textFragmentIterator);
633 }
634
635 static void forceFragmentToLine(LineState& line, TextFragmentIterator& textFragmentIterator, Layout::RunVector& runs, const TextFragmentIterator::TextFragment& fragment)
636 {
637     line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
638     // Check if there are more fragments to add to the current line.
639     auto nextFragment = textFragmentIterator.nextTextFragment();
640     if (fragment.overlapsToNextRenderer()) {
641         while (true) {
642             if (nextFragment.type() != fragment.type())
643                 break;
644             line.appendFragmentAndCreateRunIfNeeded(nextFragment, runs);
645             // Does it overlap to the next segment?
646             if (!nextFragment.overlapsToNextRenderer())
647                 return;
648             nextFragment = textFragmentIterator.nextTextFragment();
649         }
650     }
651     // When the forced fragment is followed by either whitespace and/or line break, consume them too, otherwise we end up with an extra whitespace and/or line break.
652     nextFragment = skipWhitespaceIfNeeded(nextFragment, textFragmentIterator);
653     nextFragment = consumeLineBreakIfNeeded(nextFragment, textFragmentIterator, line, runs);
654     line.setOverflowedFragment(nextFragment);
655 }
656
657 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, TextFragmentIterator& textFragmentIterator)
658 {
659     const auto& style = textFragmentIterator.style();
660     line.setCollapedWhitespaceWidth(style.spaceWidth + style.wordSpacing);
661     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
662     auto fragment = firstFragment(textFragmentIterator, line, previousLine, runs);
663     while (fragment.type() != TextFragmentIterator::TextFragment::ContentEnd) {
664         // Hard linebreak.
665         if (fragment.isLineBreak()) {
666             // 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.)
667             if (line.isEmpty() || fragment.type() == TextFragmentIterator::TextFragment::HardLineBreak) {
668                 if (style.textAlign == RIGHT || style.textAlign == WEBKIT_RIGHT)
669                     line.removeTrailingWhitespace(runs);
670                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
671             }
672             break;
673         }
674         if (lineCanBeWrapped && !line.fits(fragment.width())) {
675             // Overflow wrapping behaviour:
676             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
677             // 2. Whitespace collapse off: whitespace is wrapped.
678             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
679             // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
680             bool emptyLine = line.isEmpty();
681             // Whitespace fragment.
682             if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
683                 if (!style.collapseWhitespace) {
684                     // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
685                     line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
686                     line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
687                 }
688                 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
689                 break;
690             }
691             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
692             if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
693                 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
694                 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
695                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
696                 break;
697             }
698             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
699             ASSERT(fragment.type() == TextFragmentIterator::TextFragment::NonWhitespace);
700             if (emptyLine) {
701                 forceFragmentToLine(line, textFragmentIterator, runs, fragment);
702                 break;
703             }
704             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
705             if (line.lastFragment().overlapsToNextRenderer()) {
706                 // Check if this fragment is a continuation of a previous segment. In such cases, we need to remove them all.
707                 const auto& lastCompleteFragment = line.revertToLastCompleteFragment(runs);
708                 textFragmentIterator.revertToEndOfFragment(lastCompleteFragment);
709                 break;
710             }
711             line.setOverflowedFragment(fragment);
712             break;
713         }
714         line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
715         // Find the next text fragment.
716         fragment = textFragmentIterator.nextTextFragment(line.width());
717     }
718     return (fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty()) || line.overflowedFragment().type() == TextFragmentIterator::TextFragment::ContentEnd;
719 }
720
721 static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const TextFragmentIterator& textFragmentIterator)
722 {
723     if (previousRunCount == runs.size())
724         return;
725     ASSERT(runs.size());
726     removeTrailingWhitespace(line, runs, textFragmentIterator);
727     if (!runs.size())
728         return;
729     // Adjust runs' position by taking line's alignment into account.
730     if (float lineLogicalLeft = computeLineLeft(textFragmentIterator.style().textAlign, line.availableWidth(), line.width(), line.logicalLeftOffset())) {
731         for (unsigned i = previousRunCount; i < runs.size(); ++i) {
732             runs[i].logicalLeft += lineLogicalLeft;
733             runs[i].logicalRight += lineLogicalLeft;
734         }
735     }
736     runs.last().isEndOfLine = true;
737     ++lineCount;
738 }
739
740 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
741 {
742     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
743     LayoutUnit lineHeight = lineHeightFromFlow(flow);
744     LineState line;
745     bool isEndOfContent = false;
746     TextFragmentIterator textFragmentIterator = TextFragmentIterator(flow);
747     do {
748         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
749         LineState previousLine = line;
750         unsigned previousRunCount = runs.size();
751         line = LineState();
752         updateLineConstrains(flow, line, !lineCount);
753         isEndOfContent = createLineRuns(line, previousLine, runs, textFragmentIterator);
754         closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, textFragmentIterator);
755     } while (!isEndOfContent);
756 }
757
758 std::unique_ptr<Layout> create(RenderBlockFlow& flow)
759 {
760     unsigned lineCount = 0;
761     Layout::RunVector runs;
762
763     createTextRuns(runs, flow, lineCount);
764     for (auto& renderer : childrenOfType<RenderObject>(flow)) {
765         ASSERT(is<RenderText>(renderer) || is<RenderLineBreak>(renderer));
766         renderer.clearNeedsLayout();
767     }
768     return Layout::create(runs, lineCount);
769 }
770
771 std::unique_ptr<Layout> Layout::create(const RunVector& runVector, unsigned lineCount)
772 {
773     void* slot = WTF::fastMalloc(sizeof(Layout) + sizeof(Run) * runVector.size());
774     return std::unique_ptr<Layout>(new (NotNull, slot) Layout(runVector, lineCount));
775 }
776
777 Layout::Layout(const RunVector& runVector, unsigned lineCount)
778     : m_lineCount(lineCount)
779     , m_runCount(runVector.size())
780 {
781     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
782 }
783
784 #ifndef NDEBUG
785 static void printReason(AvoidanceReason reason, TextStream& stream)
786 {
787     switch (reason) {
788     case FlowIsInsideRegion:
789         stream << "flow is inside region";
790         break;
791     case FlowHasHorizonalWritingMode:
792         stream << "horizontal writing mode";
793         break;
794     case FlowHasOutline:
795         stream << "outline";
796         break;
797     case FlowIsRuby:
798         stream << "ruby";
799         break;
800     case FlowIsPaginated:
801         stream << "paginated";
802         break;
803     case FlowHasTextOverflow:
804         stream << "text-overflow";
805         break;
806     case FlowIsDepricatedFlexBox:
807         stream << "depricatedFlexBox";
808         break;
809     case FlowParentIsPlaceholderElement:
810         stream << "placeholder element";
811         break;
812     case FlowParentIsTextAreaWithWrapping:
813         stream << "wrapping textarea";
814         break;
815     case FlowHasNonSupportedChild:
816         stream << "nested renderers";
817         break;
818     case FlowHasUnsupportedFloat:
819         stream << "complicated float";
820         break;
821     case FlowHasTextDecoration:
822         stream << "text-decoration";
823         break;
824     case FlowIsJustifyAligned:
825         stream << "text-align: justify";
826         break;
827     case FlowHasOverflowVisible:
828         stream << "overflow: visible";
829         break;
830     case FlowIsNotLTR:
831         stream << "dir is not LTR";
832         break;
833     case FlowHasLineBoxContainProperty:
834         stream << "line-box-contain property";
835         break;
836     case FlowIsNotTopToBottom:
837         stream << "non top-to-bottom flow";
838         break;
839     case FlowHasLineBreak:
840         stream << "line-break property";
841         break;
842     case FlowHasWordBreak:
843         stream << "word-break property";
844         break;
845     case FlowHasNonNormalUnicodeBiDi:
846         stream << "non-normal Unicode bidi";
847         break;
848     case FlowHasRTLOrdering:
849         stream << "-webkit-rtl-ordering";
850         break;
851     case FlowHasLineAlignEdges:
852         stream << "-webkit-line-align edges";
853         break;
854     case FlowHasLineSnap:
855         stream << "-webkit-line-snap property";
856         break;
857     case FlowHasHypensAuto:
858         stream << "hyphen: auto";
859         break;
860     case FlowHasTextEmphasisFillOrMark:
861         stream << "text-emphasis (fill/mark)";
862         break;
863     case FlowHasPseudoFirstLine:
864         stream << "first-line";
865         break;
866     case FlowHasPseudoFirstLetter:
867         stream << "first-letter";
868         break;
869     case FlowHasTextCombine:
870         stream << "text combine";
871         break;
872     case FlowHasTextFillBox:
873         stream << "background-color (text-fill)";
874         break;
875     case FlowHasBorderFitLines:
876         stream << "-webkit-border-fit";
877         break;
878     case FlowHasNonAutoLineBreak:
879         stream << "line-break is not auto";
880         break;
881     case FlowHasNonAutoTrailingWord:
882         stream << "-apple-trailing-word is not auto";
883         break;
884     case FlowHasSVGFont:
885         stream << "SVG font";
886         break;
887     case FlowTextHasNoBreakSpace:
888         stream << "No-break-space character";
889         break;
890     case FlowTextHasSoftHyphen:
891         stream << "soft hyphen character";
892         break;
893     case FlowTextHasDirectionCharacter:
894         stream << "direction character";
895         break;
896     case FlowIsMissingPrimaryFont:
897         stream << "missing primary font";
898         break;
899     case FlowFontIsMissingGlyph:
900         stream << "missing glyph";
901         break;
902     case FlowTextIsCombineText:
903         stream << "text is combine";
904         break;
905     case FlowTextIsRenderCounter:
906         stream << "unsupported RenderCounter";
907         break;
908     case FlowTextIsRenderQuote:
909         stream << "unsupported RenderQuote";
910         break;
911     case FlowTextIsTextFragment:
912         stream << "unsupported TextFragment";
913         break;
914     case FlowTextIsSVGInlineText:
915         stream << "unsupported SVGInlineText";
916         break;
917     case FlowFontIsNotSimple:
918         stream << "complext font";
919         break;
920     case FlowHasTextShadow:
921         stream << "text-shadow";
922         break;
923     case FlowChildIsSelected:
924         stream << "selected content";
925         break;
926     case FlowTextIsEmpty:
927     case FlowHasNoChild:
928     case FlowHasNoParent:
929     case FeatureIsDisabled:
930     default:
931         break;
932     }
933 }
934
935 static void printReasons(AvoidanceReasonFlags reasons, TextStream& stream)
936 {
937     bool first = true;
938     for (auto reasonItem = EndOfReasons >> 1; reasonItem != NoReason; reasonItem >>= 1) {
939         if (!(reasons & reasonItem))
940             continue;
941         stream << (first ? " " : ", ");
942         first = false;
943         printReason(reasonItem, stream);
944     }
945 }
946
947 static void printTextForSubtree(const RenderObject& renderer, unsigned& charactersLeft, TextStream& stream)
948 {
949     if (!charactersLeft)
950         return;
951     if (is<RenderText>(renderer)) {
952         String text = downcast<RenderText>(renderer).text();
953         text = text.stripWhiteSpace();
954         unsigned len = std::min(charactersLeft, text.length());
955         stream << text.left(len);
956         charactersLeft -= len;
957         return;
958     }
959     if (!is<RenderElement>(renderer))
960         return;
961     for (const auto* child = downcast<RenderElement>(renderer).firstChild(); child; child = child->nextSibling())
962         printTextForSubtree(*child, charactersLeft, stream);
963 }
964
965 static unsigned textLengthForSubtree(const RenderObject& renderer)
966 {
967     if (is<RenderText>(renderer))
968         return downcast<RenderText>(renderer).textLength();
969     if (!is<RenderElement>(renderer))
970         return 0;
971     unsigned textLength = 0;
972     for (const auto* child = downcast<RenderElement>(renderer).firstChild(); child; child = child->nextSibling())
973         textLength += textLengthForSubtree(*child);
974     return textLength;
975 }
976
977 static void collectNonEmptyLeafRenderBlockFlows(const RenderObject& renderer, HashSet<const RenderBlockFlow*>& leafRenderers)
978 {
979     if (is<RenderText>(renderer)) {
980         if (!downcast<RenderText>(renderer).textLength())
981             return;
982         // Find RenderBlockFlow ancestor.
983         for (const auto* current = renderer.parent(); current; current = current->parent()) {
984             if (!is<RenderBlockFlow>(current))
985                 continue;
986             leafRenderers.add(downcast<RenderBlockFlow>(current));
987             break;
988         }
989         return;
990     }
991     if (!is<RenderElement>(renderer))
992         return;
993     for (const auto* child = downcast<RenderElement>(renderer).firstChild(); child; child = child->nextSibling())
994         collectNonEmptyLeafRenderBlockFlows(*child, leafRenderers);
995 }
996
997 static void collectNonEmptyLeafRenderBlockFlowsForCurrentPage(HashSet<const RenderBlockFlow*>& leafRenderers)
998 {
999     for (const auto* document : Document::allDocuments()) {
1000         if (!document->renderView() || document->inPageCache())
1001             continue;
1002         if (!document->isHTMLDocument() && !document->isXHTMLDocument())
1003             continue;
1004         collectNonEmptyLeafRenderBlockFlows(*document->renderView(), leafRenderers);
1005     }
1006 }
1007
1008 void printSimpleLineLayoutBlockList()
1009 {
1010     HashSet<const RenderBlockFlow*> leafRenderers;
1011     collectNonEmptyLeafRenderBlockFlowsForCurrentPage(leafRenderers);
1012     if (!leafRenderers.size()) {
1013         WTFLogAlways("No text found in this document\n");
1014         return;
1015     }
1016     TextStream stream;
1017     stream << "---------------------------------------------------\n";
1018     for (const auto* flow : leafRenderers) {
1019         auto reason = canUseForWithReason(*flow, IncludeReasons::All);
1020         if (reason == NoReason)
1021             continue;
1022         unsigned printedLength = 30;
1023         stream << "\"";
1024         printTextForSubtree(*flow, printedLength, stream);
1025         for (;printedLength > 0; --printedLength)
1026             stream << " ";
1027         stream << "\"(" << textLengthForSubtree(*flow) << "):";
1028         printReasons(reason, stream);
1029         stream << "\n";
1030     }
1031     stream << "---------------------------------------------------\n";
1032     WTFLogAlways("%s", stream.release().utf8().data());
1033 }
1034
1035 void printSimpleLineLayoutCoverage()
1036 {
1037     HashSet<const RenderBlockFlow*> leafRenderers;
1038     collectNonEmptyLeafRenderBlockFlowsForCurrentPage(leafRenderers);
1039     if (!leafRenderers.size()) {
1040         WTFLogAlways("No text found in this document\n");
1041         return;
1042     }
1043     TextStream stream;
1044     HashMap<AvoidanceReason, unsigned> flowStatistics;
1045     unsigned textLength = 0;
1046     unsigned unsupportedTextLength = 0;
1047     unsigned numberOfUnsupportedLeafBlocks = 0;
1048     for (const auto* flow : leafRenderers) {
1049         auto flowLength = textLengthForSubtree(*flow);
1050         textLength += flowLength;
1051         auto reasons = canUseForWithReason(*flow, IncludeReasons::All);
1052         if (reasons == NoReason)
1053             continue;
1054         ++numberOfUnsupportedLeafBlocks;
1055         unsupportedTextLength += flowLength;
1056         for (auto reasonItem = EndOfReasons >> 1; reasonItem != NoReason; reasonItem >>= 1) {
1057             if (!(reasons & reasonItem))
1058                 continue;
1059             auto result = flowStatistics.add(reasonItem, flowLength);
1060             if (!result.isNewEntry)
1061                 result.iterator->value += flowLength;
1062         }
1063     }
1064     stream << "---------------------------------------------------\n";
1065     stream << "Number of text blocks: total(" <<  leafRenderers.size() << ") non-simple(" << numberOfUnsupportedLeafBlocks << ")\nText length: total(" <<
1066         textLength << ") non-simple(" << unsupportedTextLength << ")\n";
1067     for (const auto reasonEntry : flowStatistics) {
1068         printReason(reasonEntry.key, stream);
1069         stream << ": " << (float)reasonEntry.value / (float)textLength * 100 << "%\n";
1070     }
1071     stream << "simple line layout coverage: " << (float)(textLength - unsupportedTextLength) / (float)textLength * 100 << "%\n";
1072     stream << "---------------------------------------------------\n";
1073     WTFLogAlways("%s", stream.release().utf8().data());
1074 }
1075 #endif
1076 }
1077 }