OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/paint/ObjectPainter.h" |
| 7 |
| 8 #include "core/rendering/PaintInfo.h" |
| 9 #include "core/rendering/RenderObject.h" |
| 10 #include "core/rendering/RenderTheme.h" |
| 11 #include "core/rendering/style/RenderStyle.h" |
| 12 #include "platform/geometry/LayoutPoint.h" |
| 13 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 14 |
| 15 namespace blink { |
| 16 |
| 17 void ObjectPainter::paintFocusRing(PaintInfo& paintInfo, const LayoutPoint& pain
tOffset, RenderStyle* style) |
| 18 { |
| 19 Vector<LayoutRect> focusRingRects; |
| 20 m_renderObject.addFocusRingRects(focusRingRects, paintOffset, paintInfo.pain
tContainer()); |
| 21 ASSERT(style->outlineStyleIsAuto()); |
| 22 Vector<IntRect> focusRingIntRects; |
| 23 for (size_t i = 0; i < focusRingRects.size(); ++i) |
| 24 focusRingIntRects.append(pixelSnappedIntRect(focusRingRects[i])); |
| 25 paintInfo.context->drawFocusRing(focusRingIntRects, style->outlineWidth(), s
tyle->outlineOffset(), m_renderObject.resolveColor(style, CSSPropertyOutlineColo
r)); |
| 26 } |
| 27 |
| 28 void ObjectPainter::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRe
ct) |
| 29 { |
| 30 RenderStyle* styleToUse = m_renderObject.style(); |
| 31 if (!styleToUse->hasOutline()) |
| 32 return; |
| 33 |
| 34 LayoutUnit outlineWidth = styleToUse->outlineWidth(); |
| 35 |
| 36 int outlineOffset = styleToUse->outlineOffset(); |
| 37 |
| 38 if (styleToUse->outlineStyleIsAuto()) { |
| 39 if (RenderTheme::theme().shouldDrawDefaultFocusRing(&m_renderObject)) { |
| 40 // Only paint the focus ring by hand if the theme isn't able to draw
the focus ring. |
| 41 paintFocusRing(paintInfo, paintRect.location(), styleToUse); |
| 42 } |
| 43 return; |
| 44 } |
| 45 |
| 46 if (styleToUse->outlineStyle() == BNONE) |
| 47 return; |
| 48 |
| 49 IntRect inner = pixelSnappedIntRect(paintRect); |
| 50 inner.inflate(outlineOffset); |
| 51 |
| 52 IntRect outer = pixelSnappedIntRect(inner); |
| 53 outer.inflate(outlineWidth); |
| 54 |
| 55 // FIXME: This prevents outlines from painting inside the object. See bug 12
042 |
| 56 if (outer.isEmpty()) |
| 57 return; |
| 58 |
| 59 EBorderStyle outlineStyle = styleToUse->outlineStyle(); |
| 60 Color outlineColor = m_renderObject.resolveColor(styleToUse, CSSPropertyOutl
ineColor); |
| 61 |
| 62 GraphicsContext* graphicsContext = paintInfo.context; |
| 63 bool useTransparencyLayer = outlineColor.hasAlpha(); |
| 64 if (useTransparencyLayer) { |
| 65 if (outlineStyle == SOLID) { |
| 66 Path path; |
| 67 path.addRect(outer); |
| 68 path.addRect(inner); |
| 69 graphicsContext->setFillRule(RULE_EVENODD); |
| 70 graphicsContext->setFillColor(outlineColor); |
| 71 graphicsContext->fillPath(path); |
| 72 return; |
| 73 } |
| 74 graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.
alpha()) / 255); |
| 75 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineCo
lor.blue()); |
| 76 } |
| 77 |
| 78 int leftOuter = outer.x(); |
| 79 int leftInner = inner.x(); |
| 80 int rightOuter = outer.maxX(); |
| 81 int rightInner = inner.maxX(); |
| 82 int topOuter = outer.y(); |
| 83 int topInner = inner.y(); |
| 84 int bottomOuter = outer.maxY(); |
| 85 int bottomInner = inner.maxY(); |
| 86 |
| 87 drawLineForBoxSide(graphicsContext, leftOuter, topOuter, leftInner, bottomOu
ter, BSLeft, outlineColor, outlineStyle, outlineWidth, outlineWidth); |
| 88 drawLineForBoxSide(graphicsContext, leftOuter, topOuter, rightOuter, topInne
r, BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth); |
| 89 drawLineForBoxSide(graphicsContext, rightInner, topOuter, rightOuter, bottom
Outer, BSRight, outlineColor, outlineStyle, outlineWidth, outlineWidth); |
| 90 drawLineForBoxSide(graphicsContext, leftOuter, bottomInner, rightOuter, bott
omOuter, BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth); |
| 91 |
| 92 if (useTransparencyLayer) |
| 93 graphicsContext->endLayer(); |
| 94 } |
| 95 |
| 96 void ObjectPainter::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
int y1, int x2, int y2, |
| 97 BoxSide side, Color color, EBorderStyle style, |
| 98 int adjacentWidth1, int adjacentWidth2, bool antialias) |
| 99 { |
| 100 int thickness; |
| 101 int length; |
| 102 if (side == BSTop || side == BSBottom) { |
| 103 thickness = y2 - y1; |
| 104 length = x2 - x1; |
| 105 } else { |
| 106 thickness = x2 - x1; |
| 107 length = y2 - y1; |
| 108 } |
| 109 |
| 110 // FIXME: We really would like this check to be an ASSERT as we don't want t
o draw empty borders. However |
| 111 // nothing guarantees that the following recursive calls to drawLineForBoxSi
de will have non-null dimensions. |
| 112 if (!thickness || !length) |
| 113 return; |
| 114 |
| 115 if (style == DOUBLE && thickness < 3) |
| 116 style = SOLID; |
| 117 |
| 118 switch (style) { |
| 119 case BNONE: |
| 120 case BHIDDEN: |
| 121 return; |
| 122 case DOTTED: |
| 123 case DASHED: |
| 124 drawDashedOrDottedBoxSide(graphicsContext, x1, y1, x2, y2, side, |
| 125 color, thickness, style, antialias); |
| 126 break; |
| 127 case DOUBLE: |
| 128 drawDoubleBoxSide(graphicsContext, x1, y1, x2, y2, length, side, color, |
| 129 thickness, adjacentWidth1, adjacentWidth2, antialias); |
| 130 break; |
| 131 case RIDGE: |
| 132 case GROOVE: |
| 133 drawRidgeOrGrooveBoxSide(graphicsContext, x1, y1, x2, y2, side, color, |
| 134 style, adjacentWidth1, adjacentWidth2, antialias); |
| 135 break; |
| 136 case INSET: |
| 137 // FIXME: Maybe we should lighten the colors on one side like Firefox. |
| 138 // https://bugs.webkit.org/show_bug.cgi?id=58608 |
| 139 if (side == BSTop || side == BSLeft) |
| 140 color = color.dark(); |
| 141 // fall through |
| 142 case OUTSET: |
| 143 if (style == OUTSET && (side == BSBottom || side == BSRight)) |
| 144 color = color.dark(); |
| 145 // fall through |
| 146 case SOLID: |
| 147 drawSolidBoxSide(graphicsContext, x1, y1, x2, y2, side, color, adjacentW
idth1, adjacentWidth2, antialias); |
| 148 break; |
| 149 } |
| 150 } |
| 151 |
| 152 void ObjectPainter::drawDashedOrDottedBoxSide(GraphicsContext* graphicsContext,
int x1, int y1, int x2, int y2, |
| 153 BoxSide side, Color color, int thickness, EBorderStyle style, bool antialias
) |
| 154 { |
| 155 if (thickness <= 0) |
| 156 return; |
| 157 |
| 158 bool wasAntialiased = graphicsContext->shouldAntialias(); |
| 159 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); |
| 160 graphicsContext->setShouldAntialias(antialias); |
| 161 graphicsContext->setStrokeColor(color); |
| 162 graphicsContext->setStrokeThickness(thickness); |
| 163 graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStrok
e); |
| 164 |
| 165 switch (side) { |
| 166 case BSBottom: |
| 167 case BSTop: |
| 168 graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1
+ y2) / 2)); |
| 169 break; |
| 170 case BSRight: |
| 171 case BSLeft: |
| 172 graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2
) / 2, y2)); |
| 173 break; |
| 174 } |
| 175 graphicsContext->setShouldAntialias(wasAntialiased); |
| 176 graphicsContext->setStrokeStyle(oldStrokeStyle); |
| 177 } |
| 178 |
| 179 void ObjectPainter::drawDoubleBoxSide(GraphicsContext* graphicsContext, int x1,
int y1, int x2, int y2, |
| 180 int length, BoxSide side, Color color, int thickness, int adjacentWidth1, in
t adjacentWidth2, bool antialias) |
| 181 { |
| 182 int thirdOfThickness = (thickness + 1) / 3; |
| 183 ASSERT(thirdOfThickness); |
| 184 |
| 185 if (!adjacentWidth1 && !adjacentWidth2) { |
| 186 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); |
| 187 graphicsContext->setStrokeStyle(NoStroke); |
| 188 graphicsContext->setFillColor(color); |
| 189 |
| 190 bool wasAntialiased = graphicsContext->shouldAntialias(); |
| 191 graphicsContext->setShouldAntialias(antialias); |
| 192 |
| 193 switch (side) { |
| 194 case BSTop: |
| 195 case BSBottom: |
| 196 graphicsContext->drawRect(IntRect(x1, y1, length, thirdOfThickness))
; |
| 197 graphicsContext->drawRect(IntRect(x1, y2 - thirdOfThickness, length,
thirdOfThickness)); |
| 198 break; |
| 199 case BSLeft: |
| 200 case BSRight: |
| 201 // FIXME: Why do we offset the border by 1 in this case but not the
other one? |
| 202 if (length > 1) { |
| 203 graphicsContext->drawRect(IntRect(x1, y1 + 1, thirdOfThickness,
length - 1)); |
| 204 graphicsContext->drawRect(IntRect(x2 - thirdOfThickness, y1 + 1,
thirdOfThickness, length - 1)); |
| 205 } |
| 206 break; |
| 207 } |
| 208 |
| 209 graphicsContext->setShouldAntialias(wasAntialiased); |
| 210 graphicsContext->setStrokeStyle(oldStrokeStyle); |
| 211 return; |
| 212 } |
| 213 |
| 214 int adjacent1BigThird = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacen
tWidth1 - 1) / 3; |
| 215 int adjacent2BigThird = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacen
tWidth2 - 1) / 3; |
| 216 |
| 217 switch (side) { |
| 218 case BSTop: |
| 219 drawLineForBoxSide(graphicsContext, x1 + std::max((-adjacentWidth1 * 2 +
1) / 3, 0), |
| 220 y1, x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThi
ckness, |
| 221 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 222 drawLineForBoxSide(graphicsContext, x1 + std::max((adjacentWidth1 * 2 +
1) / 3, 0), |
| 223 y2 - thirdOfThickness, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0
), y2, |
| 224 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 225 break; |
| 226 case BSLeft: |
| 227 drawLineForBoxSide(graphicsContext, x1, y1 + std::max((-adjacentWidth1 *
2 + 1) / 3, 0), |
| 228 x1 + thirdOfThickness, y2 - std::max((-adjacentWidth2 * 2 + 1) / 3,
0), |
| 229 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 230 drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + std::max
((adjacentWidth1 * 2 + 1) / 3, 0), |
| 231 x2, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), |
| 232 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 233 break; |
| 234 case BSBottom: |
| 235 drawLineForBoxSide(graphicsContext, x1 + std::max((adjacentWidth1 * 2 +
1) / 3, 0), |
| 236 y1, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThic
kness, |
| 237 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 238 drawLineForBoxSide(graphicsContext, x1 + std::max((-adjacentWidth1 * 2 +
1) / 3, 0), |
| 239 y2 - thirdOfThickness, x2 - std::max((-adjacentWidth2 * 2 + 1) / 3,
0), y2, |
| 240 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 241 break; |
| 242 case BSRight: |
| 243 drawLineForBoxSide(graphicsContext, x1, y1 + std::max((adjacentWidth1 *
2 + 1) / 3, 0), |
| 244 x1 + thirdOfThickness, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0
), |
| 245 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 246 drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + std::max
((-adjacentWidth1 * 2 + 1) / 3, 0), |
| 247 x2, y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), |
| 248 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias)
; |
| 249 break; |
| 250 default: |
| 251 break; |
| 252 } |
| 253 } |
| 254 |
| 255 void ObjectPainter::drawRidgeOrGrooveBoxSide(GraphicsContext* graphicsContext, i
nt x1, int y1, int x2, int y2, |
| 256 BoxSide side, Color color, EBorderStyle style, int adjacentWidth1, int adjac
entWidth2, bool antialias) |
| 257 { |
| 258 EBorderStyle s1; |
| 259 EBorderStyle s2; |
| 260 if (style == GROOVE) { |
| 261 s1 = INSET; |
| 262 s2 = OUTSET; |
| 263 } else { |
| 264 s1 = OUTSET; |
| 265 s2 = INSET; |
| 266 } |
| 267 |
| 268 int adjacent1BigHalf = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacent
Width1 - 1) / 2; |
| 269 int adjacent2BigHalf = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacent
Width2 - 1) / 2; |
| 270 |
| 271 switch (side) { |
| 272 case BSTop: |
| 273 drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1, 0) /
2, y1, x2 - std::max(-adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2, |
| 274 side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias); |
| 275 drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1 + 1, 0)
/ 2, (y1 + y2 + 1) / 2, x2 - std::max(adjacentWidth2 + 1, 0) / 2, y2, |
| 276 side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); |
| 277 break; |
| 278 case BSLeft: |
| 279 drawLineForBoxSide(graphicsContext, x1, y1 + std::max(-adjacentWidth1, 0
) / 2, (x1 + x2 + 1) / 2, y2 - std::max(-adjacentWidth2, 0) / 2, |
| 280 side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias); |
| 281 drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + std::max(adj
acentWidth1 + 1, 0) / 2, x2, y2 - std::max(adjacentWidth2 + 1, 0) / 2, |
| 282 side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); |
| 283 break; |
| 284 case BSBottom: |
| 285 drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1, 0) / 2
, y1, x2 - std::max(adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2, |
| 286 side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias); |
| 287 drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1 + 1, 0
) / 2, (y1 + y2 + 1) / 2, x2 - std::max(-adjacentWidth2 + 1, 0) / 2, y2, |
| 288 side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); |
| 289 break; |
| 290 case BSRight: |
| 291 drawLineForBoxSide(graphicsContext, x1, y1 + std::max(adjacentWidth1, 0)
/ 2, (x1 + x2 + 1) / 2, y2 - std::max(adjacentWidth2, 0) / 2, |
| 292 side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias); |
| 293 drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + std::max(-ad
jacentWidth1 + 1, 0) / 2, x2, y2 - std::max(-adjacentWidth2 + 1, 0) / 2, |
| 294 side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); |
| 295 break; |
| 296 } |
| 297 } |
| 298 |
| 299 void ObjectPainter::drawSolidBoxSide(GraphicsContext* graphicsContext, int x1, i
nt y1, int x2, int y2, |
| 300 BoxSide side, Color color, int adjacentWidth1, int adjacentWidth2, bool anti
alias) |
| 301 { |
| 302 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); |
| 303 graphicsContext->setStrokeStyle(NoStroke); |
| 304 graphicsContext->setFillColor(color); |
| 305 ASSERT(x2 >= x1); |
| 306 ASSERT(y2 >= y1); |
| 307 if (!adjacentWidth1 && !adjacentWidth2) { |
| 308 // Turn off antialiasing to match the behavior of drawConvexPolygon(); |
| 309 // this matters for rects in transformed contexts. |
| 310 bool wasAntialiased = graphicsContext->shouldAntialias(); |
| 311 graphicsContext->setShouldAntialias(antialias); |
| 312 graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1)); |
| 313 graphicsContext->setShouldAntialias(wasAntialiased); |
| 314 graphicsContext->setStrokeStyle(oldStrokeStyle); |
| 315 return; |
| 316 } |
| 317 FloatPoint quad[4]; |
| 318 switch (side) { |
| 319 case BSTop: |
| 320 quad[0] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y1); |
| 321 quad[1] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y2); |
| 322 quad[2] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y2); |
| 323 quad[3] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y1); |
| 324 break; |
| 325 case BSBottom: |
| 326 quad[0] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y1); |
| 327 quad[1] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y2); |
| 328 quad[2] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y2); |
| 329 quad[3] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y1); |
| 330 break; |
| 331 case BSLeft: |
| 332 quad[0] = FloatPoint(x1, y1 + std::max(-adjacentWidth1, 0)); |
| 333 quad[1] = FloatPoint(x1, y2 - std::max(-adjacentWidth2, 0)); |
| 334 quad[2] = FloatPoint(x2, y2 - std::max(adjacentWidth2, 0)); |
| 335 quad[3] = FloatPoint(x2, y1 + std::max(adjacentWidth1, 0)); |
| 336 break; |
| 337 case BSRight: |
| 338 quad[0] = FloatPoint(x1, y1 + std::max(adjacentWidth1, 0)); |
| 339 quad[1] = FloatPoint(x1, y2 - std::max(adjacentWidth2, 0)); |
| 340 quad[2] = FloatPoint(x2, y2 - std::max(-adjacentWidth2, 0)); |
| 341 quad[3] = FloatPoint(x2, y1 + std::max(-adjacentWidth1, 0)); |
| 342 break; |
| 343 } |
| 344 |
| 345 graphicsContext->drawConvexPolygon(4, quad, antialias); |
| 346 graphicsContext->setStrokeStyle(oldStrokeStyle); |
| 347 } |
| 348 |
| 349 } // namespace blink |
OLD | NEW |