Source/WebCore: fast/frames/seamless/seamless-nested-crash.html asserts on wk2 only
[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 "GraphicsContext.h"
31 #include "HitTestLocation.h"
32 #include "HitTestRequest.h"
33 #include "HitTestResult.h"
34 #include "InlineTextBox.h"
35 #include "LineWidth.h"
36 #include "PaintInfo.h"
37 #include "RenderBlockFlow.h"
38 #include "RenderStyle.h"
39 #include "RenderText.h"
40 #include "RenderView.h"
41 #include "SimpleLineLayoutResolver.h"
42 #include "Text.h"
43 #include "TextPaintStyle.h"
44 #include "break_lines.h"
45 #include <wtf/unicode/Unicode.h>
46
47 namespace WebCore {
48 namespace SimpleLineLayout {
49
50 static inline bool isWhitespace(UChar character)
51 {
52     return character == ' ' || character == '\t' || character == '\n';
53 }
54
55 bool canUseFor(const RenderBlockFlow& flow)
56 {
57 #if !PLATFORM(MAC)
58     // FIXME: Non-mac platforms are hitting ASSERT(run.charactersLength() >= run.length())
59     // https://bugs.webkit.org/show_bug.cgi?id=123338
60     return false;
61 #endif
62     if (!flow.firstChild())
63         return false;
64     // This currently covers <blockflow>#text</blockflow> case.
65     // The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover.
66     if (flow.firstChild() != flow.lastChild())
67         return false;
68     if (!flow.firstChild()->isText())
69         return false;
70     // Supporting floats would be very beneficial.
71     if (flow.containsFloats())
72         return false;
73     if (!flow.isHorizontalWritingMode())
74         return false;
75     if (flow.flowThreadState() != RenderObject::NotInsideFlowThread)
76         return false;
77     if (flow.hasOutline())
78         return false;
79     if (flow.isRubyText() || flow.isRubyBase())
80         return false;
81     // These tests only works during layout. Outside layout this function may give false positives.
82     if (flow.view().layoutState()) {
83 #if ENABLE(CSS_SHAPES)
84         if (flow.view().layoutState()->shapeInsideInfo())
85             return false;
86 #endif
87         if (flow.view().layoutState()->m_columnInfo)
88             return false;
89     }
90     const RenderStyle& style = *flow.style();
91     // It shoudn't be hard to support other alignments.
92     if (style.textAlign() != LEFT && style.textAlign() != WEBKIT_LEFT && style.textAlign() != TASTART)
93         return false;
94     // Non-visible overflow should be pretty easy to support.
95     if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE)
96         return false;
97     // Pre/no-wrap would be very helpful to support.
98     if (style.whiteSpace() != NORMAL)
99         return false;
100     if (!style.textIndent().isZero())
101         return false;
102     if (style.wordSpacing() || style.letterSpacing())
103         return false;
104     if (style.textTransform() != TTNONE)
105         return false;
106     if (!style.isLeftToRightDirection())
107         return false;
108     if (style.lineBoxContain() != RenderStyle::initialLineBoxContain())
109         return false;
110     if (style.writingMode() != TopToBottomWritingMode)
111         return false;
112     if (style.lineBreak() != LineBreakAuto)
113         return false;
114     if (style.wordBreak() != NormalWordBreak)
115         return false;
116     if (style.unicodeBidi() != UBNormal || style.rtlOrdering() != LogicalOrder)
117         return false;
118     if (style.lineAlign() != LineAlignNone || style.lineSnap() != LineSnapNone)
119         return false;
120     if (style.hyphens() == HyphensAuto)
121         return false;
122     if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone)
123         return false;
124     if (style.textShadow())
125         return false;
126 #if ENABLE(CSS_SHAPES)
127     if (style.resolvedShapeInside())
128         return true;
129 #endif
130     if (style.textOverflow() || (flow.isAnonymousBlock() && flow.parent()->style()->textOverflow()))
131         return false;
132     if (style.hasPseudoStyle(FIRST_LINE) || style.hasPseudoStyle(FIRST_LETTER))
133         return false;
134     if (style.hasTextCombine())
135         return false;
136     if (style.overflowWrap() != NormalOverflowWrap)
137         return false;
138     if (style.backgroundClip() == TextFillBox)
139         return false;
140     if (style.borderFit() == BorderFitLines)
141         return false;
142     const RenderText& textRenderer = toRenderText(*flow.firstChild());
143     if (textRenderer.isCombineText() || textRenderer.isCounter() || textRenderer.isQuote() || textRenderer.isTextFragment()
144 #if ENABLE(SVG)
145         || textRenderer.isSVGInlineText()
146 #endif
147         )
148         return false;
149     if (style.font().codePath(TextRun(textRenderer.text())) != Font::Simple)
150         return false;
151
152     // We assume that all lines have metrics based purely on the primary font.
153     auto& primaryFontData = *style.font().primaryFont();
154     if (primaryFontData.isLoading())
155         return false;
156
157     unsigned length = textRenderer.textLength();
158     unsigned consecutiveSpaceCount = 0;
159     for (unsigned i = 0; i < length; ++i) {
160         // This rejects anything with more than one consecutive whitespace, except at the beginning or end.
161         // This is because we don't currently do subruns within lines. Fixing this would improve coverage significantly.
162         UChar character = textRenderer.characterAt(i);
163         if (isWhitespace(character)) {
164             ++consecutiveSpaceCount;
165             continue;
166         }
167         if (consecutiveSpaceCount != i && consecutiveSpaceCount > 1)
168             return false;
169         consecutiveSpaceCount = 0;
170
171         // These would be easy to support.
172         if (character == noBreakSpace)
173             return false;
174         if (character == softHyphen)
175             return false;
176
177         static const UChar lowestRTLCharacter = 0x590;
178         if (character >= lowestRTLCharacter) {
179             UCharDirection direction = u_charDirection(character);
180             if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC
181                 || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE
182                 || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE)
183                 return false;
184         }
185
186         if (!primaryFontData.glyphForCharacter(character))
187             return false;
188     }
189     return true;
190 }
191
192 static inline unsigned skipWhitespaces(const RenderText& textRenderer, unsigned offset, unsigned length)
193 {
194     for (; offset < length; ++offset) {
195         if (!isWhitespace(textRenderer.characterAt(offset)))
196             break;
197     }
198     return offset;
199 }
200
201 static float textWidth(const RenderText& text, unsigned from, unsigned length, float xPosition, const RenderStyle& style)
202 {
203     if (style.font().isFixedPitch() || (!from && length == text.textLength()))
204         return text.width(from, length, style.font(), xPosition, nullptr, nullptr);
205     // FIXME: Add templated UChar/LChar paths.
206     TextRun run = text.is8Bit() ? TextRun(text.characters8() + from, length) : TextRun(text.characters16() + from, length);
207     run.setCharactersLength(text.textLength() - from);
208     ASSERT(run.charactersLength() >= run.length());
209
210     run.setXPos(xPosition);
211     return style.font().width(run);
212 }
213
214 std::unique_ptr<Lines> createLines(RenderBlockFlow& flow)
215 {
216     auto lines = std::make_unique<Lines>();
217
218     RenderText& textRenderer = toRenderText(*flow.firstChild());
219     ASSERT(!textRenderer.firstTextBox());
220
221     const RenderStyle& style = *flow.style();
222     const unsigned textLength = textRenderer.textLength();
223
224     float wordTrailingSpaceWidth = style.font().width(TextRun(&space, 1));
225
226     LazyLineBreakIterator lineBreakIterator(textRenderer.text(), style.locale());
227     int nextBreakable = -1;
228
229     unsigned lineEndOffset = 0;
230     while (lineEndOffset < textLength) {
231         lineEndOffset = skipWhitespaces(textRenderer, lineEndOffset, textLength);
232         unsigned lineStartOffset = lineEndOffset;
233         unsigned runEndOffset = lineEndOffset;
234         LineWidth lineWidth(flow, false, DoNotIndentText);
235         while (runEndOffset < textLength) {
236             ASSERT(!isWhitespace(textRenderer.characterAt(runEndOffset)));
237
238             bool previousWasSpaceBetweenRuns = runEndOffset > lineStartOffset && isWhitespace(textRenderer.characterAt(runEndOffset - 1));
239             unsigned runStartOffset = previousWasSpaceBetweenRuns ? runEndOffset - 1 : runEndOffset;
240
241             ++runEndOffset;
242             while (runEndOffset < textLength) {
243                 if (runEndOffset > lineStartOffset && isBreakable(lineBreakIterator, runEndOffset, nextBreakable, false))
244                     break;
245                 ++runEndOffset;
246             }
247
248             unsigned runLength = runEndOffset - runStartOffset;
249             bool includeEndSpace = runEndOffset < textLength && textRenderer.characterAt(runEndOffset) == ' ';
250             float wordWidth;
251             if (includeEndSpace)
252                 wordWidth = textWidth(textRenderer, runStartOffset, runLength + 1, lineWidth.committedWidth(), style) - wordTrailingSpaceWidth;
253             else
254                 wordWidth = textWidth(textRenderer, runStartOffset, runLength, lineWidth.committedWidth(), style);
255
256             lineWidth.addUncommittedWidth(wordWidth);
257             if (!lineWidth.fitsOnLine()) {
258                 if (!lineWidth.committedWidth()) {
259                     lineWidth.commit();
260                     lineEndOffset = runEndOffset;
261                 }
262                 break;
263             }
264             lineWidth.commit();
265             lineEndOffset = runEndOffset;
266             runEndOffset = skipWhitespaces(textRenderer, runEndOffset, textLength);
267         }
268         if (lineStartOffset == lineEndOffset)
269             continue;
270
271         Line line;
272         line.textOffset = lineStartOffset;
273         line.textLength = lineEndOffset - lineStartOffset;
274         line.width = lineWidth.committedWidth();
275
276         lines->append(line);
277     }
278
279     textRenderer.clearNeedsLayout();
280
281     lines->shrinkToFit();
282     return lines;
283 }
284
285 }
286 }