[iOS] Add WebKitSystemInterface for iOS 8.2
[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
46 namespace WebCore {
47 namespace SimpleLineLayout {
48
49 static void paintDebugBorders(GraphicsContext& context, LayoutRect borderRect, const LayoutPoint& paintOffset)
50 {
51     borderRect.moveBy(paintOffset);
52     IntRect snappedRect = snappedIntRect(borderRect);
53     if (snappedRect.isEmpty())
54         return;
55     GraphicsContextStateSaver stateSaver(context);
56     context.setStrokeColor(Color(0, 255, 0), ColorSpaceDeviceRGB);
57     context.setFillColor(Color::transparent, ColorSpaceDeviceRGB);
58     context.drawRect(snappedRect);
59 }
60
61 void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
62 {
63     if (paintInfo.phase != PaintPhaseForeground)
64         return;
65
66     RenderStyle& style = flow.style();
67     if (style.visibility() != VISIBLE)
68         return;
69
70     bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled();
71
72     GraphicsContext& context = *paintInfo.context;
73     const FontCascade& font = style.fontCascade();
74     TextPaintStyle textPaintStyle = computeTextPaintStyle(flow.frame(), style, paintInfo);
75     GraphicsContextStateSaver stateSaver(context, textPaintStyle.strokeWidth > 0);
76
77     updateGraphicsContext(context, textPaintStyle);
78     LayoutRect paintRect = paintInfo.rect;
79     paintRect.moveBy(-paintOffset);
80
81     auto resolver = runResolver(flow, layout);
82     for (const auto& run : resolver.rangeForRect(paintRect)) {
83         if (!run.rect().intersects(paintRect))
84             continue;
85         TextRun textRun(run.text());
86         textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
87         FloatPoint textOrigin = run.baseline() + paintOffset;
88         textOrigin.setY(roundToDevicePixel(LayoutUnit(textOrigin.y()), flow.document().deviceScaleFactor()));
89         context.drawText(font, textRun, textOrigin);
90         if (debugBordersEnabled)
91             paintDebugBorders(context, run.rect(), paintOffset);
92     }
93 }
94
95 bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
96 {
97     if (hitTestAction != HitTestForeground)
98         return false;
99
100     if (!layout.runCount())
101         return false;
102
103     RenderStyle& style = flow.style();
104     if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE)
105         return false;
106
107     RenderText& textRenderer = downcast<RenderText>(*flow.firstChild());
108
109     LayoutRect rangeRect = locationInContainer.boundingBox();
110     rangeRect.moveBy(-accumulatedOffset);
111
112     auto resolver = lineResolver(flow, layout);
113     auto range = resolver.rangeForRect(rangeRect);
114     for (auto it = range.begin(), end = range.end(); it != end; ++it) {
115         auto lineRect = *it;
116         lineRect.moveBy(accumulatedOffset);
117         if (!locationInContainer.intersects(lineRect))
118             continue;
119         textRenderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
120         if (!result.addNodeToRectBasedTestResult(textRenderer.textNode(), request, locationInContainer, lineRect))
121             return true;
122     }
123
124     return false;
125 }
126
127 void collectFlowOverflow(RenderBlockFlow& flow, const Layout& layout)
128 {
129     auto resolver = lineResolver(flow, layout);
130     for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
131         auto rect = *it;
132         flow.addLayoutOverflow(rect);
133         flow.addVisualOverflow(rect);
134     }
135 }
136
137 IntRect computeTextBoundingBox(const RenderText& textRenderer, const Layout& layout)
138 {
139     auto resolver = runResolver(downcast<RenderBlockFlow>(*textRenderer.parent()), layout);
140     FloatRect boundingBoxRect;
141     for (const auto& run : resolver.rangeForRenderer(textRenderer)) {
142         FloatRect rect = run.rect();
143         if (boundingBoxRect == FloatRect())
144             boundingBoxRect = rect;
145         else
146             boundingBoxRect.uniteEvenIfEmpty(rect);
147     }
148     return enclosingIntRect(boundingBoxRect);
149 }
150
151 IntPoint computeTextFirstRunLocation(const RenderText& textRenderer, const Layout& layout)
152 {
153     auto resolver = runResolver(downcast<RenderBlockFlow>(*textRenderer.parent()), layout);
154     const auto& it = resolver.rangeForRenderer(textRenderer);
155     auto begin = it.begin();
156     if (begin == it.end())
157         return IntPoint(0, 0);
158
159     return flooredIntPoint((*begin).rect().location());
160 }
161
162 Vector<IntRect> collectTextAbsoluteRects(const RenderText& textRenderer, const Layout& layout, const LayoutPoint& accumulatedOffset)
163 {
164     Vector<IntRect> rects;
165     auto resolver = runResolver(downcast<RenderBlockFlow>(*textRenderer.parent()), layout);
166     for (const auto& run : resolver.rangeForRenderer(textRenderer)) {
167         LayoutRect rect = run.rect();
168         rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size())));
169     }
170     return rects;
171 }
172
173 Vector<FloatQuad> collectTextAbsoluteQuads(const RenderText& textRenderer, const Layout& layout, bool* wasFixed)
174 {
175     Vector<FloatQuad> quads;
176     auto resolver = runResolver(downcast<RenderBlockFlow>(*textRenderer.parent()), layout);
177     for (const auto& run : resolver.rangeForRenderer(textRenderer))
178         quads.append(textRenderer.localToAbsoluteQuad(FloatQuad(run.rect()), 0, wasFixed));
179     return quads;
180 }
181
182 #if ENABLE(TREE_DEBUGGING)
183 static void printPrefix(int& printedCharacters, int depth)
184 {
185     fprintf(stderr, "------- --");
186     printedCharacters = 0;
187     while (++printedCharacters <= depth * 2)
188         fputc(' ', stderr);
189 }
190
191 void showLineLayoutForFlow(const RenderBlockFlow& flow, const Layout& layout, int depth)
192 {
193     int printedCharacters = 0;
194     printPrefix(printedCharacters, depth);
195
196     fprintf(stderr, "SimpleLineLayout (%u lines, %u runs) (%p)\n", layout.lineCount(), layout.runCount(), &layout);
197     ++depth;
198
199     auto resolver = runResolver(flow, layout);
200     for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
201         const auto& run = *it;
202         LayoutRect r = run.rect();
203         printPrefix(printedCharacters, depth);
204         fprintf(stderr, "line %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f) \"%s\"\n", run.lineIndex(), run.start(), run.end(),
205             r.x().toFloat(), r.y().toFloat(), r.width().toFloat(), r.height().toFloat(), run.text().toStringWithoutCopying().utf8().data());
206     }
207 }
208 #endif
209
210 }
211 }