21f75b76341530b260837db83b3fc9707a161718
[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 "RenderStyle.h"
39 #include "RenderText.h"
40 #include "RenderView.h"
41 #include "Settings.h"
42 #include "SimpleLineLayoutResolver.h"
43 #include "Text.h"
44 #include "TextPaintStyle.h"
45 #include "TextPainter.h"
46
47 #if ENABLE(TREE_DEBUGGING)
48 #include <stdio.h>
49 #endif
50
51 namespace WebCore {
52 namespace SimpleLineLayout {
53
54 static void paintDebugBorders(GraphicsContext& context, LayoutRect borderRect, const LayoutPoint& paintOffset)
55 {
56     borderRect.moveBy(paintOffset);
57     IntRect snappedRect = snappedIntRect(borderRect);
58     if (snappedRect.isEmpty())
59         return;
60     GraphicsContextStateSaver stateSaver(context);
61     context.setStrokeColor(Color(0, 255, 0));
62     context.setFillColor(Color::transparent);
63     context.drawRect(snappedRect);
64 }
65
66 void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
67 {
68     if (paintInfo.phase != PaintPhaseForeground)
69         return;
70
71     RenderStyle& style = flow.style();
72     if (style.visibility() != VISIBLE)
73         return;
74
75     bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled();
76
77     TextPainter textPainter(paintInfo.context());
78     textPainter.setFont(style.fontCascade());
79     textPainter.setTextPaintStyle(computeTextPaintStyle(flow.frame(), style, paintInfo));
80
81     LayoutRect paintRect = paintInfo.rect;
82     paintRect.moveBy(-paintOffset);
83
84     auto resolver = runResolver(flow, layout);
85     float strokeOverflow = ceilf(flow.style().textStrokeWidth());
86     float deviceScaleFactor = flow.document().deviceScaleFactor();
87     for (const auto& run : resolver.rangeForRect(paintRect)) {
88         if (run.start() == run.end())
89             continue;
90
91         FloatRect rect = run.rect();
92         FloatRect visualOverflowRect = rect;
93         visualOverflowRect.inflate(strokeOverflow);
94         if (paintRect.y() > visualOverflowRect.maxY() || paintRect.maxY() < visualOverflowRect.y())
95             continue;
96
97         TextRun textRun(run.text());
98         textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
99         // x position indicates the line offset from the rootbox. It's always 0 in case of simple line layout.
100         textRun.setXPos(0);
101         FloatPoint textOrigin = FloatPoint(rect.x() + paintOffset.x(), roundToDevicePixel(run.baselinePosition() + paintOffset.y(), deviceScaleFactor));
102         textPainter.paintText(textRun, textRun.length(), rect, textOrigin);
103         if (debugBordersEnabled)
104             paintDebugBorders(paintInfo.context(), LayoutRect(run.rect()), paintOffset);
105     }
106 }
107
108 bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
109 {
110     if (hitTestAction != HitTestForeground)
111         return false;
112
113     if (!layout.runCount())
114         return false;
115
116     RenderStyle& style = flow.style();
117     if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE)
118         return false;
119
120     RenderObject& renderer = *flow.firstChild();
121     LayoutRect rangeRect = locationInContainer.boundingBox();
122     rangeRect.moveBy(-accumulatedOffset);
123
124     auto resolver = lineResolver(flow, layout);
125     auto range = resolver.rangeForRect(rangeRect);
126     for (auto it = range.begin(), end = range.end(); it != end; ++it) {
127         auto lineRect = *it;
128         lineRect.moveBy(accumulatedOffset);
129         if (!locationInContainer.intersects(lineRect))
130             continue;
131         renderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
132         if (!result.addNodeToRectBasedTestResult(renderer.node(), request, locationInContainer, lineRect))
133             return true;
134     }
135
136     return false;
137 }
138
139 void collectFlowOverflow(RenderBlockFlow& flow, const Layout& layout)
140 {
141     auto resolver = lineResolver(flow, layout);
142     float strokeOverflow = ceilf(flow.style().textStrokeWidth());
143     for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
144         auto rect = LayoutRect(*it);
145         rect.inflate(strokeOverflow);
146         flow.addLayoutOverflow(rect);
147         flow.addVisualOverflow(rect);
148     }
149 }
150
151 IntRect computeBoundingBox(const RenderObject& renderer, const Layout& layout)
152 {
153     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
154     FloatRect boundingBoxRect;
155     for (const auto& run : resolver.rangeForRenderer(renderer)) {
156         FloatRect rect = run.rect();
157         if (boundingBoxRect == FloatRect())
158             boundingBoxRect = rect;
159         else
160             boundingBoxRect.uniteEvenIfEmpty(rect);
161     }
162     return enclosingIntRect(boundingBoxRect);
163 }
164
165 IntPoint computeFirstRunLocation(const RenderObject& renderer, const Layout& layout)
166 {
167     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
168     const auto& it = resolver.rangeForRenderer(renderer);
169     auto begin = it.begin();
170     if (begin == it.end())
171         return IntPoint(0, 0);
172
173     return flooredIntPoint((*begin).rect().location());
174 }
175
176 Vector<IntRect> collectAbsoluteRects(const RenderObject& renderer, const Layout& layout, const LayoutPoint& accumulatedOffset)
177 {
178     Vector<IntRect> rects;
179     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
180     for (const auto& run : resolver.rangeForRenderer(renderer)) {
181         FloatRect rect = run.rect();
182         rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size())));
183     }
184     return rects;
185 }
186
187 Vector<FloatQuad> collectAbsoluteQuads(const RenderObject& renderer, const Layout& layout, bool* wasFixed)
188 {
189     Vector<FloatQuad> quads;
190     auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout);
191     for (const auto& run : resolver.rangeForRenderer(renderer))
192         quads.append(renderer.localToAbsoluteQuad(FloatQuad(run.rect()), UseTransforms, wasFixed));
193     return quads;
194 }
195
196 #if ENABLE(TREE_DEBUGGING)
197 static void printPrefix(int& printedCharacters, int depth)
198 {
199     fprintf(stderr, "------- --");
200     printedCharacters = 0;
201     while (++printedCharacters <= depth * 2)
202         fputc(' ', stderr);
203 }
204
205 void showLineLayoutForFlow(const RenderBlockFlow& flow, const Layout& layout, int depth)
206 {
207     int printedCharacters = 0;
208     printPrefix(printedCharacters, depth);
209
210     fprintf(stderr, "SimpleLineLayout (%u lines, %u runs) (%p)\n", layout.lineCount(), layout.runCount(), &layout);
211     ++depth;
212
213     auto resolver = runResolver(flow, layout);
214     for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
215         const auto& run = *it;
216         FloatRect rect = run.rect();
217         printPrefix(printedCharacters, depth);
218         if (run.start() < run.end()) {
219             fprintf(stderr, "line %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f) \"%s\"\n", run.lineIndex(), run.start(), run.end(),
220                 rect.x(), rect.y(), rect.width(), rect.height(), run.text().toStringWithoutCopying().utf8().data());
221         } else {
222             ASSERT(run.start() == run.end());
223             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());
224         }
225     }
226 }
227 #endif
228
229 }
230 }