Unreviewed, rolling out r218373.
[WebKit-https.git] / Source / WebCore / rendering / SimpleLineLayoutFunctions.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 "SimpleLineLayoutFunctions.h"
28
29 #include "FontCache.h"
30 #include "Frame.h"
31 #include "GraphicsContext.h"
32 #include "HitTestLocation.h"
33 #include "HitTestRequest.h"
34 #include "HitTestResult.h"
35 #include "InlineTextBox.h"
36 #include "PaintInfo.h"
37 #include "RenderBlockFlow.h"
38 #include "RenderIterator.h"
39 #include "RenderStyle.h"
40 #include "RenderText.h"
41 #include "RenderView.h"
42 #include "Settings.h"
43 #include "SimpleLineLayoutFlowContents.h"
44 #include "SimpleLineLayoutResolver.h"
45 #include "Text.h"
46 #include "TextDecorationPainter.h"
47 #include "TextPaintStyle.h"
48 #include "TextPainter.h"
49
50 #if ENABLE(TREE_DEBUGGING)
51 #include <stdio.h>
52 #endif
53
54 namespace WebCore {
55 namespace SimpleLineLayout {
56
57 FloatRect computeOverflow(const RenderBlockFlow& flow, const FloatRect& layoutRect)
58 {
59     auto overflowRect = layoutRect;
60     auto viewportSize = flow.frame().view() ? flow.frame().view()->size() : IntSize();
61     auto strokeOverflow = std::ceil(flow.style().computedStrokeWidth(viewportSize));
62     overflowRect.inflate(strokeOverflow);
63
64     auto letterSpacing = flow.style().fontCascade().letterSpacing();
65     if (letterSpacing >= 0)
66         return overflowRect;
67     // Last letter's negative spacing shrinks layout rect. Push it to visual overflow.
68     overflowRect.expand(-letterSpacing, 0);
69     return overflowRect;
70 }
71
72 void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
73 {
74     if (paintInfo.phase != PaintPhaseForeground)
75         return;
76
77     auto& style = flow.style();
78     if (style.visibility() != VISIBLE)
79         return;
80
81     TextPainter textPainter(paintInfo.context());
82     textPainter.setFont(style.fontCascade());
83     textPainter.setTextPaintStyle(computeTextPaintStyle(flow.frame(), style, paintInfo));
84
85     std::unique_ptr<ShadowData> debugShadow = nullptr;
86     if (flow.settings().simpleLineLayoutDebugBordersEnabled()) {
87         debugShadow = std::make_unique<ShadowData>(IntPoint(0, 0), 10, 20, ShadowStyle::Normal, true, Color(0, 255, 0, 200));
88         textPainter.addTextShadow(debugShadow.get(), nullptr);
89     }
90
91     std::optional<TextDecorationPainter> textDecorationPainter;
92     if (style.textDecorationsInEffect() != TextDecorationNone) {
93         const RenderText* textRenderer = childrenOfType<RenderText>(flow).first();
94         if (textRenderer) {
95             textDecorationPainter.emplace(paintInfo.context(), style.textDecorationsInEffect(), *textRenderer, false);
96             textDecorationPainter->setFont(style.fontCascade());
97             textDecorationPainter->setBaseline(style.fontMetrics().ascent());
98         }
99     }
100
101     LayoutRect paintRect = paintInfo.rect;
102     paintRect.moveBy(-paintOffset);
103
104     auto resolver = runResolver(flow, layout);
105     float deviceScaleFactor = flow.document().deviceScaleFactor();
106     for (auto run : resolver.rangeForRect(paintRect)) {
107         if (run.start() == run.end())
108             continue;
109
110         FloatRect rect = run.rect();
111         FloatRect visualOverflowRect = computeOverflow(flow, rect);
112         if (paintRect.y() > visualOverflowRect.maxY() || paintRect.maxY() < visualOverflowRect.y())
113             continue;
114
115         String textWithHyphen;
116         if (run.hasHyphen())
117             textWithHyphen = run.textWithHyphen();
118         // x position indicates the line offset from the rootbox. It's always 0 in case of simple line layout.
119         TextRun textRun(run.hasHyphen() ? textWithHyphen : run.text(), 0, run.expansion(), run.expansionBehavior());
120         textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
121         FloatPoint textOrigin = FloatPoint(rect.x() + paintOffset.x(), roundToDevicePixel(run.baselinePosition() + paintOffset.y(), deviceScaleFactor));
122         textPainter.paintText(textRun, textRun.length(), rect, textOrigin);
123         if (textDecorationPainter) {
124             textDecorationPainter->setWidth(rect.width());
125             textDecorationPainter->paintTextDecoration(textRun, textOrigin, rect.location() + paintOffset);
126         }
127     }
128 }
129
130 bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
131 {
132     if (hitTestAction != HitTestForeground)
133         return false;
134
135     if (!layout.runCount())
136         return false;
137
138     auto& style = flow.style();
139     if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE)
140         return false;
141
142     LayoutRect rangeRect = locationInContainer.boundingBox();
143     rangeRect.moveBy(-accumulatedOffset);
144     auto resolver = lineResolver(flow, layout);
145     auto range = resolver.rangeForRect(rangeRect);
146     for (auto it = range.begin(), end = range.end(); it != end; ++it) {
147         auto lineRect = *it;
148         lineRect.moveBy(accumulatedOffset);
149         auto& renderer = const_cast<RenderObject&>(it.renderer());
150         if (!locationInContainer.intersects(lineRect))
151             continue;
152         renderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
153         if (!result.addNodeToRectBasedTestResult(renderer.node(), request, locationInContainer, lineRect))
154             return true;
155     }
156     return false;
157 }
158
159 void collectFlowOverflow(RenderBlockFlow& flow, const Layout& layout)
160 {
161     for (auto lineRect : lineResolver(flow, layout)) {
162         LayoutRect visualOverflowRect = LayoutRect(computeOverflow(flow, lineRect));
163         flow.addLayoutOverflow(LayoutRect(lineRect));
164         flow.addVisualOverflow(visualOverflowRect);
165     }
166 }
167
168 IntRect computeBoundingBox(const RenderObject& renderer, const Layout& layout)
169 {
170     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
171     FloatRect boundingBoxRect;
172     for (auto run : resolver.rangeForRenderer(renderer)) {
173         FloatRect rect = run.rect();
174         if (boundingBoxRect == FloatRect())
175             boundingBoxRect = rect;
176         else
177             boundingBoxRect.uniteEvenIfEmpty(rect);
178     }
179     return enclosingIntRect(boundingBoxRect);
180 }
181
182 IntPoint computeFirstRunLocation(const RenderObject& renderer, const Layout& layout)
183 {
184     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
185     auto range = resolver.rangeForRenderer(renderer);
186     auto begin = range.begin();
187     if (begin == range.end())
188         return IntPoint(0, 0);
189     return flooredIntPoint((*begin).rect().location());
190 }
191
192 Vector<IntRect> collectAbsoluteRects(const RenderObject& renderer, const Layout& layout, const LayoutPoint& accumulatedOffset)
193 {
194     Vector<IntRect> rects;
195     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
196     for (auto run : resolver.rangeForRenderer(renderer)) {
197         FloatRect rect = run.rect();
198         rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size())));
199     }
200     return rects;
201 }
202
203 Vector<FloatQuad> collectAbsoluteQuads(const RenderObject& renderer, const Layout& layout, bool* wasFixed)
204 {
205     Vector<FloatQuad> quads;
206     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
207     for (auto run : resolver.rangeForRenderer(renderer))
208         quads.append(renderer.localToAbsoluteQuad(FloatQuad(run.rect()), UseTransforms, wasFixed));
209     return quads;
210 }
211
212 unsigned textOffsetForPoint(const LayoutPoint& point, const RenderText& renderer, const Layout& layout)
213 {
214     auto& flow = downcast<RenderBlockFlow>(*renderer.parent());
215     ASSERT(flow.firstChild() == flow.lastChild());
216     auto resolver = runResolver(flow, layout);
217     auto it = resolver.runForPoint(point);
218     if (it == resolver.end())
219         return renderer.textLength();
220     auto run = *it;
221     auto& style = flow.style();
222     TextRun textRun(run.text(), run.logicalLeft(), run.expansion(), run.expansionBehavior());
223     textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
224     return run.start() + style.fontCascade().offsetForPosition(textRun, point.x() - run.logicalLeft(), true);
225 }
226
227 Vector<FloatQuad> collectAbsoluteQuadsForRange(const RenderObject& renderer, unsigned start, unsigned end, const Layout& layout, bool* wasFixed)
228 {
229     auto& style = downcast<RenderBlockFlow>(*renderer.parent()).style();
230     Vector<FloatQuad> quads;
231     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
232     for (auto run : resolver.rangeForRendererWithOffsets(renderer, start, end)) {
233         // This run is fully contained.
234         if (start <= run.start() && end >= run.end()) {
235             quads.append(renderer.localToAbsoluteQuad(FloatQuad(run.rect()), UseTransforms, wasFixed));
236             continue;
237         }
238         // Partially contained run.
239         TextRun textRun(run.text(), run.logicalLeft(), run.expansion(), run.expansionBehavior());
240         textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
241         LayoutRect runRect(run.rect());
242         // Special case empty ranges.
243         if (start == end) {
244             runRect.setWidth(0);
245             quads.append(renderer.localToAbsoluteQuad(FloatQuad(runRect), UseTransforms, wasFixed));
246             continue;
247         }
248         ASSERT(start < run.end());
249         ASSERT(end > run.start());
250         auto localStart = std::max(run.start(), start) - run.start();
251         auto localEnd = std::min(run.end(), end) - run.start();
252         style.fontCascade().adjustSelectionRectForText(textRun, runRect, localStart, localEnd);
253         quads.append(renderer.localToAbsoluteQuad(FloatQuad(runRect), UseTransforms, wasFixed));
254     }
255     return quads;
256 }
257
258 const RenderObject& rendererForPosition(const FlowContents& flowContents, unsigned position)
259 {
260     return flowContents.segmentForPosition(position).renderer;
261 }
262
263 #if ENABLE(TREE_DEBUGGING)
264 static void printPrefix(int& printedCharacters, int depth)
265 {
266     fprintf(stderr, "-------- --");
267     printedCharacters = 0;
268     while (++printedCharacters <= depth * 2)
269         fputc(' ', stderr);
270 }
271
272 void showLineLayoutForFlow(const RenderBlockFlow& flow, const Layout& layout, int depth)
273 {
274     int printedCharacters = 0;
275     printPrefix(printedCharacters, depth);
276
277     fprintf(stderr, "SimpleLineLayout (%u lines, %u runs) (%p)\n", layout.lineCount(), layout.runCount(), &layout);
278     ++depth;
279
280     for (auto run : runResolver(flow, layout)) {
281         FloatRect rect = run.rect();
282         printPrefix(printedCharacters, depth);
283         if (run.start() < run.end()) {
284             fprintf(stderr, "line %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f) \"%s\"\n", run.lineIndex(), run.start(), run.end(),
285                 rect.x(), rect.y(), rect.width(), rect.height(), run.text().toStringWithoutCopying().utf8().data());
286         } else {
287             ASSERT(run.start() == run.end());
288             fprintf(stderr, "line break %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f)\n", run.lineIndex(), run.start(), run.end(), rect.x(), rect.y(), rect.width(), rect.height());
289         }
290     }
291 }
292 #endif
293
294 }
295 }