Chromium Code Reviews| 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 |