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

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

Powered by Google App Engine
This is Rietveld 408576698