OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/paint/InlinePainter.h" | 6 #include "core/paint/InlinePainter.h" |
7 | 7 |
8 #include "core/layout/LayoutBlock.h" | 8 #include "core/layout/LayoutBlock.h" |
9 #include "core/layout/LayoutInline.h" | 9 #include "core/layout/LayoutInline.h" |
10 #include "core/layout/LayoutTheme.h" | 10 #include "core/layout/LayoutTheme.h" |
11 #include "core/layout/line/RootInlineBox.h" | 11 #include "core/layout/line/RootInlineBox.h" |
12 #include "core/paint/BoxPainter.h" | 12 #include "core/paint/BoxPainter.h" |
13 #include "core/paint/LayoutObjectDrawingRecorder.h" | 13 #include "core/paint/LayoutObjectDrawingRecorder.h" |
14 #include "core/paint/LineBoxListPainter.h" | 14 #include "core/paint/LineBoxListPainter.h" |
15 #include "core/paint/ObjectPainter.h" | 15 #include "core/paint/ObjectPainter.h" |
16 #include "core/paint/PaintInfo.h" | 16 #include "core/paint/PaintInfo.h" |
17 #include "platform/geometry/LayoutPoint.h" | 17 #include "platform/geometry/LayoutPoint.h" |
18 #include <limits> | 18 #include <limits> |
19 | 19 |
20 namespace blink { | 20 namespace blink { |
21 | 21 |
22 void InlinePainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOf
fset) | 22 void InlinePainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOf
fset) |
23 { | 23 { |
24 // FIXME: When Skia supports annotation rect covering (https://code.google.c
om/p/skia/issues/detail?id=3872), | 24 // FIXME: When Skia supports annotation rect covering (https://code.google.c
om/p/skia/issues/detail?id=3872), |
25 // this rect may be covered by foreground and descendant drawings. Then we m
ay need a dedicated paint phase. | 25 // this rect may be covered by foreground and descendant drawings. Then we m
ay need a dedicated paint phase. |
26 if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) | 26 if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) |
27 ObjectPainter(m_layoutInline).addPDFURLRectIfNeeded(paintInfo, paintOffs
et); | 27 ObjectPainter(m_layoutInline).addPDFURLRectIfNeeded(paintInfo, paintOffs
et); |
28 | 28 |
| 29 if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSel
fOutline || paintInfo.phase == PaintPhaseChildOutlines) { |
| 30 ObjectPainter painter(m_layoutInline); |
| 31 if (paintInfo.phase != PaintPhaseSelfOutline) |
| 32 painter.paintInlineChildrenOutlines(paintInfo, paintOffset); |
| 33 if (paintInfo.phase != PaintPhaseChildOutlines && !m_layoutInline.isElem
entContinuation()) |
| 34 painter.paintOutline(paintInfo, paintOffset); |
| 35 return; |
| 36 } |
| 37 |
29 LineBoxListPainter(*m_layoutInline.lineBoxes()).paint(&m_layoutInline, paint
Info, paintOffset); | 38 LineBoxListPainter(*m_layoutInline.lineBoxes()).paint(&m_layoutInline, paint
Info, paintOffset); |
30 } | 39 } |
31 | 40 |
32 LayoutRect InlinePainter::outlinePaintRect(const Vector<LayoutRect>& outlineRect
s, const LayoutPoint& paintOffset) const | |
33 { | |
34 int outlineOutset = m_layoutInline.styleRef().outlineOutsetExtent(); | |
35 LayoutRect outlineRect; | |
36 for (const LayoutRect& rect : outlineRects) { | |
37 LayoutRect inflatedRect(rect); | |
38 // Inflate the individual rects instead of the union, to avoid losing | |
39 // rects which have degenerate width/height (== isEmpty() true.) | |
40 inflatedRect.inflate(outlineOutset); | |
41 outlineRect.unite(inflatedRect); | |
42 } | |
43 outlineRect.moveBy(paintOffset); | |
44 return outlineRect; | |
45 } | |
46 | |
47 void InlinePainter::paintOutline(const PaintInfo& paintInfo, const LayoutPoint&
paintOffset) | |
48 { | |
49 const ComputedStyle& styleToUse = m_layoutInline.styleRef(); | |
50 if (!styleToUse.hasOutline()) | |
51 return; | |
52 | |
53 if (styleToUse.outlineStyleIsAuto()) { | |
54 if (!LayoutTheme::theme().shouldDrawDefaultFocusRing(&m_layoutInline)) | |
55 return; | |
56 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.c
ontext, m_layoutInline, paintInfo.phase)) | |
57 return; | |
58 | |
59 Vector<LayoutRect> focusRingRects; | |
60 m_layoutInline.addOutlineRects(focusRingRects, paintOffset); | |
61 | |
62 LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutInline,
paintInfo.phase, outlinePaintRect(focusRingRects, LayoutPoint())); | |
63 // Only paint the focus ring by hand if the theme isn't able to draw the
focus ring. | |
64 ObjectPainter(m_layoutInline).paintFocusRing(paintInfo, styleToUse, focu
sRingRects); | |
65 return; | |
66 } | |
67 | |
68 if (styleToUse.outlineStyle() == BNONE) | |
69 return; | |
70 | |
71 GraphicsContext* graphicsContext = paintInfo.context; | |
72 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*graphicsContext
, m_layoutInline, paintInfo.phase)) | |
73 return; | |
74 | |
75 Vector<LayoutRect> rects; | |
76 | |
77 rects.append(LayoutRect()); | |
78 for (InlineFlowBox* curr = m_layoutInline.firstLineBox(); curr; curr = curr-
>nextLineBox()) { | |
79 RootInlineBox& root = curr->root(); | |
80 LayoutUnit top = std::max<LayoutUnit>(root.lineTop(), curr->logicalTop()
); | |
81 LayoutUnit bottom = std::min<LayoutUnit>(root.lineBottom(), curr->logica
lBottom()); | |
82 rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - t
op)); | |
83 } | |
84 rects.append(LayoutRect()); | |
85 | |
86 Color outlineColor = m_layoutInline.resolveColor(styleToUse, CSSPropertyOutl
ineColor); | |
87 bool useTransparencyLayer = outlineColor.hasAlpha(); | |
88 | |
89 LayoutObjectDrawingRecorder recorder(*graphicsContext, m_layoutInline, paint
Info.phase, outlinePaintRect(rects, paintOffset)); | |
90 if (useTransparencyLayer) { | |
91 graphicsContext->beginLayer(static_cast<float>(outlineColor.alpha()) / 2
55); | |
92 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineCo
lor.blue()); | |
93 } | |
94 | |
95 for (unsigned i = 1; i < rects.size() - 1; i++) | |
96 paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects
.at(i), rects.at(i + 1), outlineColor); | |
97 | |
98 if (useTransparencyLayer) | |
99 graphicsContext->endLayer(); | |
100 } | |
101 | |
102 static IntRect pixelSnappedOutsetPaintRect(const LayoutRect& baseRect, const Lay
outPoint& paintOffset, int outset) | |
103 { | |
104 LayoutRect box(baseRect); | |
105 box.moveBy(paintOffset); | |
106 box.inflate(outset); | |
107 return pixelSnappedIntRect(box); | |
108 } | |
109 | |
110 void InlinePainter::paintOutlineForLine(GraphicsContext* graphicsContext, const
LayoutPoint& paintOffset, | |
111 const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& ne
xtline, const Color outlineColor) | |
112 { | |
113 const ComputedStyle& styleToUse = m_layoutInline.styleRef(); | |
114 int outlineWidth = styleToUse.outlineWidth(); | |
115 EBorderStyle outlineStyle = styleToUse.outlineStyle(); | |
116 | |
117 int offset = m_layoutInline.style()->outlineOffset(); | |
118 | |
119 IntRect pixelSnappedBox = pixelSnappedOutsetPaintRect(thisline, paintOffset,
offset); | |
120 if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0) | |
121 return; | |
122 // Note that we use IntRect below for working with solely x/width values, si
mplifying logic at cost of a bit of memory. | |
123 IntRect pixelSnappedLastLine = pixelSnappedOutsetPaintRect(lastline, paintOf
fset, offset); | |
124 IntRect pixelSnappedNextLine = pixelSnappedOutsetPaintRect(nextline, paintOf
fset, offset); | |
125 | |
126 const int fallbackMaxOutlineX = std::numeric_limits<int>::max(); | |
127 const int fallbackMinOutlineX = std::numeric_limits<int>::min(); | |
128 | |
129 // left edge | |
130 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
131 pixelSnappedBox.x() - outlineWidth, | |
132 pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x()
|| (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), | |
133 pixelSnappedBox.x(), | |
134 pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline
.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), | |
135 BSLeft, | |
136 outlineColor, outlineStyle, | |
137 (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() -
1) <= thisline.x() ? outlineWidth : -outlineWidth), | |
138 (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX()
- 1) <= thisline.x() ? outlineWidth : -outlineWidth), | |
139 false); | |
140 | |
141 // right edge | |
142 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
143 pixelSnappedBox.maxX(), | |
144 pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.
maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0), | |
145 pixelSnappedBox.maxX() + outlineWidth, | |
146 pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisl
ine.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0), | |
147 BSRight, | |
148 outlineColor, outlineStyle, | |
149 (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.ma
xX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth), | |
150 (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.m
axX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth), | |
151 false); | |
152 // upper edge | |
153 if (thisline.x() < lastline.x()) { | |
154 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
155 pixelSnappedBox.x() - outlineWidth, | |
156 pixelSnappedBox.y() - outlineWidth, | |
157 std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty()
? fallbackMaxOutlineX : pixelSnappedLastLine.x())), | |
158 pixelSnappedBox.y(), | |
159 BSTop, outlineColor, outlineStyle, | |
160 outlineWidth, | |
161 (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSn
appedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, | |
162 false); | |
163 } | |
164 | |
165 if (lastline.maxX() < thisline.maxX()) { | |
166 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
167 std::max(lastline.isEmpty() ? fallbackMinOutlineX : pixelSnappedLast
Line.maxX(), pixelSnappedBox.x() - outlineWidth), | |
168 pixelSnappedBox.y() - outlineWidth, | |
169 pixelSnappedBox.maxX() + outlineWidth, | |
170 pixelSnappedBox.y(), | |
171 BSTop, outlineColor, outlineStyle, | |
172 (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOf
fset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth, | |
173 outlineWidth, false); | |
174 } | |
175 | |
176 if (thisline.x() == thisline.maxX()) { | |
177 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
178 pixelSnappedBox.x() - outlineWidth, | |
179 pixelSnappedBox.y() - outlineWidth, | |
180 pixelSnappedBox.maxX() + outlineWidth, | |
181 pixelSnappedBox.y(), | |
182 BSTop, outlineColor, outlineStyle, | |
183 outlineWidth, | |
184 outlineWidth, | |
185 false); | |
186 } | |
187 | |
188 // lower edge | |
189 if (thisline.x() < nextline.x()) { | |
190 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
191 pixelSnappedBox.x() - outlineWidth, | |
192 pixelSnappedBox.maxY(), | |
193 std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty()
? pixelSnappedNextLine.x() + 1 : fallbackMaxOutlineX), | |
194 pixelSnappedBox.maxY() + outlineWidth, | |
195 BSBottom, outlineColor, outlineStyle, | |
196 outlineWidth, | |
197 (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSn
appedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, | |
198 false); | |
199 } | |
200 | |
201 if (nextline.maxX() < thisline.maxX()) { | |
202 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
203 std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : fallbac
kMinOutlineX, pixelSnappedBox.x() - outlineWidth), | |
204 pixelSnappedBox.maxY(), | |
205 pixelSnappedBox.maxX() + outlineWidth, | |
206 pixelSnappedBox.maxY() + outlineWidth, | |
207 BSBottom, outlineColor, outlineStyle, | |
208 (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOf
fset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth, | |
209 outlineWidth, false); | |
210 } | |
211 | |
212 if (thisline.x() == thisline.maxX()) { | |
213 ObjectPainter::drawLineForBoxSide(graphicsContext, | |
214 pixelSnappedBox.x() - outlineWidth, | |
215 pixelSnappedBox.maxY(), | |
216 pixelSnappedBox.maxX() + outlineWidth, | |
217 pixelSnappedBox.maxY() + outlineWidth, | |
218 BSBottom, outlineColor, outlineStyle, | |
219 outlineWidth, | |
220 outlineWidth, | |
221 false); | |
222 } | |
223 } | |
224 | |
225 } // namespace blink | 41 } // namespace blink |
OLD | NEW |