Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: Source/core/paint/ObjectPainter.cpp

Issue 1224933002: Combine outline and focus ring code paths (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebase Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698