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/ObjectPainter.h" | 6 #include "core/paint/ObjectPainter.h" |
7 | 7 |
8 #include "core/layout/LayoutInline.h" | |
8 #include "core/layout/LayoutObject.h" | 9 #include "core/layout/LayoutObject.h" |
9 #include "core/layout/LayoutTheme.h" | 10 #include "core/layout/LayoutTheme.h" |
10 #include "core/paint/BoxBorderPainter.h" | 11 #include "core/paint/BoxBorderPainter.h" |
11 #include "core/paint/LayoutObjectDrawingRecorder.h" | 12 #include "core/paint/LayoutObjectDrawingRecorder.h" |
12 #include "core/paint/PaintInfo.h" | 13 #include "core/paint/PaintInfo.h" |
13 #include "core/style/BorderEdge.h" | 14 #include "core/style/BorderEdge.h" |
14 #include "core/style/ComputedStyle.h" | 15 #include "core/style/ComputedStyle.h" |
15 #include "platform/geometry/LayoutPoint.h" | 16 #include "platform/geometry/LayoutPoint.h" |
16 | 17 |
17 namespace blink { | 18 namespace blink { |
18 | 19 |
19 void ObjectPainter::paintFocusRing(const PaintInfo& paintInfo, const ComputedSty le& style, const Vector<LayoutRect>& focusRingRects) | 20 namespace { |
21 | |
22 void paintNonAutoOutlineFastPath(const PaintInfo& paintInfo, const IntRect& rect , const ComputedStyle& style, const Color& color) | |
pdr.
2015/08/27 22:59:33
How "outline:auto" affects this was confusing to m
Xianzhu
2015/08/28 00:26:04
Renamed it to paintSingleRectangleOutline, and pai
| |
20 { | 23 { |
21 ASSERT(style.outlineStyleIsAuto()); | 24 LayoutRect inner(rect); |
pdr.
2015/08/27 22:59:33
Can you assert that the style is not auto here?
Xianzhu
2015/08/28 00:26:04
Done.
This seems less confusing to include "NonAu
| |
22 Vector<IntRect> focusRingIntRects; | 25 inner.inflate(style.outlineOffset()); |
23 for (size_t i = 0; i < focusRingRects.size(); ++i) | 26 LayoutRect outer(inner); |
24 focusRingIntRects.append(pixelSnappedIntRect(focusRingRects[i])); | 27 outer.inflate(style.outlineWidth()); |
25 paintInfo.context->drawFocusRing(focusRingIntRects, style.outlineWidth(), st yle.outlineOffset(), m_layoutObject.resolveColor(style, CSSPropertyOutlineColor) ); | 28 const BorderEdge commonEdgeInfo(style.outlineWidth(), color, style.outlineSt yle()); |
29 BoxBorderPainter(style, outer, inner, commonEdgeInfo).paintBorder(paintInfo, outer); | |
26 } | 30 } |
27 | 31 |
28 void ObjectPainter::paintOutline(const PaintInfo& paintInfo, const LayoutRect& v isualOverflowRect, const LayoutSize& objectSize, const LayoutPoint& paintOffset) | 32 struct OutlineEdgeInfo { |
33 int x1; | |
34 int y1; | |
35 int x2; | |
36 int y2; | |
37 BoxSide side; | |
38 }; | |
39 | |
40 // Adjust length of edges if needed. Returns the width of the joint. | |
41 int adjustJoint(int outlineWidth, OutlineEdgeInfo& edge1, OutlineEdgeInfo& edge2 ) | |
42 { | |
43 // A clockwise joint: | |
44 // - needs no adjustment of edge length because our edges are along the cloc kwise outer edge of the outline; | |
45 // - needs a positive adjacent joint width (required by drawLineForBoxSide). | |
46 // A counterclockwise joint: | |
47 // - needs to increase the edge length to include the joint; | |
48 // - needs a negative adjacent joint width (required by drawLineForBoxSide). | |
49 switch (edge1.side) { | |
50 case BSTop: | |
51 switch (edge2.side) { | |
52 case BSRight: // Clockwise | |
53 return outlineWidth; | |
54 case BSLeft: // Counterclockwise | |
55 edge1.x2 += outlineWidth; | |
56 edge2.y2 += outlineWidth; | |
57 return -outlineWidth; | |
58 default: // Same side or no joint. | |
59 return 0; | |
60 } | |
61 case BSRight: | |
62 switch (edge2.side) { | |
63 case BSBottom: // Clockwise | |
64 return outlineWidth; | |
65 case BSTop: // Counterclockwise | |
66 edge1.y2 += outlineWidth; | |
67 edge2.x1 -= outlineWidth; | |
68 return -outlineWidth; | |
69 default: // Same side or no joint. | |
70 return 0; | |
71 } | |
72 case BSBottom: | |
73 switch (edge2.side) { | |
74 case BSLeft: // Clockwise | |
75 return outlineWidth; | |
76 case BSRight: // Counterclockwise | |
77 edge1.x1 -= outlineWidth; | |
78 edge2.y1 -= outlineWidth; | |
79 return -outlineWidth; | |
80 default: // Same side or no joint. | |
81 return 0; | |
82 } | |
83 case BSLeft: | |
84 switch (edge2.side) { | |
85 case BSTop: // Clockwise | |
86 return outlineWidth; | |
87 case BSBottom: // Counterclockwise | |
88 edge1.y1 -= outlineWidth; | |
89 edge2.x2 += outlineWidth; | |
90 return -outlineWidth; | |
91 default: // Same side or no joint. | |
92 return 0; | |
93 } | |
94 default: | |
95 ASSERT_NOT_REACHED(); | |
96 return 0; | |
97 } | |
98 } | |
99 | |
100 void paintNonAutoOutlineSlowPath(GraphicsContext& graphicsContext, const Vector< IntRect> rects, const ComputedStyle& style, const Color& color) | |
pdr.
2015/08/27 22:59:33
Same comments here as above.
Xianzhu
2015/08/28 00:26:04
Done.
| |
101 { | |
102 // Construct a clockwise path along the outer edge of the outline. | |
103 SkRegion region; | |
104 int width = style.outlineWidth(); | |
105 int outset = style.outlineOffset() + style.outlineWidth(); | |
106 for (auto& r : rects) { | |
107 IntRect rect = r; | |
108 rect.inflate(outset); | |
109 region.op(rect, SkRegion::kUnion_Op); | |
110 } | |
111 SkPath path; | |
112 if (!region.getBoundaryPath(&path)) | |
113 return; | |
114 | |
115 Vector<OutlineEdgeInfo, 4> edges; | |
116 | |
117 SkPath::Iter iter(path, false); | |
118 SkPoint points[4]; | |
119 size_t count = 0; | |
120 for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Ver b; verb = iter.next(points, false)) { | |
121 if (verb != SkPath::kLine_Verb) | |
122 continue; | |
123 | |
124 edges.grow(++count); | |
125 OutlineEdgeInfo& edge = edges.last(); | |
126 edge.x1 = SkScalarTruncToInt(points[0].x()); | |
127 edge.y1 = SkScalarTruncToInt(points[0].y()); | |
128 edge.x2 = SkScalarTruncToInt(points[1].x()); | |
129 edge.y2 = SkScalarTruncToInt(points[1].y()); | |
130 if (edge.x1 == edge.x2) { | |
131 if (edge.y1 < edge.y2) { | |
132 edge.x1 -= width; | |
133 edge.side = BSRight; | |
134 } else { | |
135 std::swap(edge.y1, edge.y2); | |
136 edge.x2 += width; | |
137 edge.side = BSLeft; | |
138 } | |
139 } else { | |
140 ASSERT(edge.y1 == edge.y2); | |
141 if (edge.x1 < edge.x2) { | |
142 edge.y2 += width; | |
143 edge.side = BSTop; | |
144 } else { | |
145 std::swap(edge.x1, edge.x2); | |
146 edge.y1 -= width; | |
147 edge.side = BSBottom; | |
148 } | |
149 } | |
150 } | |
151 | |
152 if (!count) | |
153 return; | |
154 | |
155 Color outlineColor = color; | |
156 bool useTransparencyLayer = color.hasAlpha(); | |
157 if (useTransparencyLayer) { | |
158 graphicsContext.beginLayer(static_cast<float>(color.alpha()) / 255); | |
159 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineCo lor.blue()); | |
160 } | |
161 | |
162 ASSERT(count >= 4 && edges.size() == count); | |
163 int firstAdjacentWidth = adjustJoint(width, edges.last(), edges.first()); | |
164 | |
165 // The width of the angled part of starting and ending joint of the current edge. | |
166 int adjacentWidthStart = firstAdjacentWidth; | |
167 int adjacentWidthEnd; | |
168 for (size_t i = 0; i < count; ++i) { | |
169 OutlineEdgeInfo& edge = edges[i]; | |
170 adjacentWidthEnd = i == count - 1 ? firstAdjacentWidth : adjustJoint(wid th, edge, edges[i + 1]); | |
171 int adjacentWidth1 = adjacentWidthStart; | |
172 int adjacentWidth2 = adjacentWidthEnd; | |
173 if (edge.side == BSLeft || edge.side == BSBottom) | |
174 std::swap(adjacentWidth1, adjacentWidth2); | |
175 ObjectPainter::drawLineForBoxSide(&graphicsContext, edge.x1, edge.y1, ed ge.x2, edge.y2, edge.side, outlineColor, style.outlineStyle(), adjacentWidth1, a djacentWidth2, false); | |
176 adjacentWidthStart = adjacentWidthEnd; | |
177 } | |
178 | |
179 if (useTransparencyLayer) | |
180 graphicsContext.endLayer(); | |
181 } | |
182 | |
183 } // namespace | |
184 | |
185 void ObjectPainter::paintOutline(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) | |
29 { | 186 { |
30 const ComputedStyle& styleToUse = m_layoutObject.styleRef(); | 187 const ComputedStyle& styleToUse = m_layoutObject.styleRef(); |
31 if (!styleToUse.hasOutline()) | 188 if (!styleToUse.hasOutline()) |
32 return; | 189 return; |
33 | 190 |
34 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte xt, m_layoutObject, paintInfo.phase)) | 191 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte xt, m_layoutObject, paintInfo.phase)) |
35 return; | 192 return; |
36 | 193 |
37 LayoutRect visualOverflowBounds(visualOverflowRect); | 194 // Only paint the focus ring by hand if the theme isn't able to draw the foc us ring. |
38 visualOverflowBounds.moveBy(paintOffset); | 195 bool paintFocusRing = styleToUse.outlineStyleIsAuto(); |
39 LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutObject, pai ntInfo.phase, visualOverflowBounds); | 196 if (paintFocusRing && !LayoutTheme::theme().shouldDrawDefaultFocusRing(&m_la youtObject)) |
197 return; | |
40 | 198 |
199 Vector<LayoutRect> outlineRects; | |
200 m_layoutObject.addOutlineRects(outlineRects, paintOffset); | |
201 | |
202 Vector<IntRect> pixelSnappedOutlineRects; | |
203 for (auto& r : outlineRects) | |
204 pixelSnappedOutlineRects.append(pixelSnappedIntRect(r)); | |
205 | |
206 IntRect unitedOutlineRect = unionRect(pixelSnappedOutlineRects); | |
207 if (unitedOutlineRect.isEmpty()) { | |
208 // We need to draw an outline around an empty point. | |
209 IntRect emptyPointRect = pixelSnappedIntRect(LayoutRect(paintOffset, Lay outSize())); | |
210 pixelSnappedOutlineRects.append(emptyPointRect); | |
211 unitedOutlineRect = emptyPointRect; | |
212 } | |
213 | |
214 IntRect bounds = unitedOutlineRect; | |
215 bounds.inflate(m_layoutObject.styleRef().outlineOutsetExtent()); | |
216 LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutObject, pai ntInfo.phase, bounds); | |
217 | |
218 Color color = m_layoutObject.resolveColor(styleToUse, CSSPropertyOutlineColo r); | |
41 if (styleToUse.outlineStyleIsAuto()) { | 219 if (styleToUse.outlineStyleIsAuto()) { |
42 if (LayoutTheme::theme().shouldDrawDefaultFocusRing(&m_layoutObject)) { | 220 paintInfo.context->drawFocusRing(pixelSnappedOutlineRects, styleToUse.ou tlineWidth(), styleToUse.outlineOffset(), color); |
43 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. | |
44 Vector<LayoutRect> focusRingRects; | |
45 m_layoutObject.addOutlineRects(focusRingRects, paintOffset); | |
46 paintFocusRing(paintInfo, styleToUse, focusRingRects); | |
47 } | |
48 return; | 221 return; |
49 } | 222 } |
50 | 223 |
51 if (styleToUse.outlineStyle() == BNONE) | 224 if (unitedOutlineRect == pixelSnappedOutlineRects[0]) { |
225 paintNonAutoOutlineFastPath(paintInfo, unitedOutlineRect, styleToUse, co lor); | |
52 return; | 226 return; |
227 } | |
228 paintNonAutoOutlineSlowPath(*paintInfo.context, pixelSnappedOutlineRects, st yleToUse, color); | |
229 } | |
53 | 230 |
54 LayoutRect inner(paintOffset, objectSize); | 231 void ObjectPainter::paintInlineChildrenOutlines(const PaintInfo& paintInfo, cons t LayoutPoint& paintOffset) |
55 inner = LayoutRect(pixelSnappedIntRect(inner)); | 232 { |
56 inner.inflate(styleToUse.outlineOffset()); | 233 ASSERT(paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhase ChildOutlines); |
57 | 234 |
58 LayoutRect outer(inner); | 235 PaintInfo childPaintInfo(paintInfo); |
59 int outlineWidth = styleToUse.outlineWidth(); | 236 childPaintInfo.phase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPha seOutline : paintInfo.phase; |
60 outer.inflate(outlineWidth); | |
61 | 237 |
62 const BorderEdge commonEdgeInfo(outlineWidth, | 238 for (LayoutObject* child = m_layoutObject.slowFirstChild(); child; child = c hild->nextSibling()) { |
63 m_layoutObject.resolveColor(styleToUse, CSSPropertyOutlineColor), styleT oUse.outlineStyle()); | 239 if (child->isLayoutInline() && !toLayoutInline(child)->hasSelfPaintingLa yer()) |
64 BoxBorderPainter(styleToUse, outer, inner, commonEdgeInfo).paintBorder(paint Info, outer); | 240 child->paint(childPaintInfo, paintOffset); |
241 } | |
65 } | 242 } |
66 | 243 |
67 void ObjectPainter::addPDFURLRectIfNeeded(const PaintInfo& paintInfo, const Layo utPoint& paintOffset) | 244 void ObjectPainter::addPDFURLRectIfNeeded(const PaintInfo& paintInfo, const Layo utPoint& paintOffset) |
68 { | 245 { |
69 ASSERT(paintInfo.isPrinting()); | 246 ASSERT(paintInfo.isPrinting()); |
70 if (m_layoutObject.isElementContinuation() || !m_layoutObject.node() || !m_l ayoutObject.node()->isLink() || m_layoutObject.styleRef().visibility() != VISIBL E) | 247 if (m_layoutObject.isElementContinuation() || !m_layoutObject.node() || !m_l ayoutObject.node()->isLink() || m_layoutObject.styleRef().visibility() != VISIBL E) |
71 return; | 248 return; |
72 | 249 |
73 KURL url = toElement(m_layoutObject.node())->hrefURL(); | 250 KURL url = toElement(m_layoutObject.node())->hrefURL(); |
74 if (!url.isValid()) | 251 if (!url.isValid()) |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 quad[1] = FloatPoint(x1, y2 - std::max(adjacentWidth2, 0)); | 513 quad[1] = FloatPoint(x1, y2 - std::max(adjacentWidth2, 0)); |
337 quad[2] = FloatPoint(x2, y2 - std::max(-adjacentWidth2, 0)); | 514 quad[2] = FloatPoint(x2, y2 - std::max(-adjacentWidth2, 0)); |
338 quad[3] = FloatPoint(x2, y1 + std::max(-adjacentWidth1, 0)); | 515 quad[3] = FloatPoint(x2, y1 + std::max(-adjacentWidth1, 0)); |
339 break; | 516 break; |
340 } | 517 } |
341 | 518 |
342 graphicsContext->fillPolygon(4, quad, color, antialias); | 519 graphicsContext->fillPolygon(4, quad, color, antialias); |
343 } | 520 } |
344 | 521 |
345 } // namespace blink | 522 } // namespace blink |
OLD | NEW |