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

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

Issue 1162863006: Relocate box border painting code into BoxBorderPainter (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: minor cleanup Created 5 years, 6 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/BoxPainter.h" 6 #include "core/paint/BoxPainter.h"
7 7
8 #include "core/HTMLNames.h" 8 #include "core/HTMLNames.h"
9 #include "core/frame/Settings.h" 9 #include "core/frame/Settings.h"
10 #include "core/html/HTMLFrameOwnerElement.h" 10 #include "core/html/HTMLFrameOwnerElement.h"
11 #include "core/layout/ImageQualityController.h" 11 #include "core/layout/ImageQualityController.h"
12 #include "core/layout/LayoutBox.h" 12 #include "core/layout/LayoutBox.h"
13 #include "core/layout/LayoutBoxModelObject.h" 13 #include "core/layout/LayoutBoxModelObject.h"
14 #include "core/layout/LayoutObject.h" 14 #include "core/layout/LayoutObject.h"
15 #include "core/layout/LayoutTable.h" 15 #include "core/layout/LayoutTable.h"
16 #include "core/layout/LayoutTheme.h" 16 #include "core/layout/LayoutTheme.h"
17 #include "core/layout/LayoutView.h" 17 #include "core/layout/LayoutView.h"
18 #include "core/layout/compositing/CompositedDeprecatedPaintLayerMapping.h" 18 #include "core/layout/compositing/CompositedDeprecatedPaintLayerMapping.h"
19 #include "core/style/BorderEdge.h" 19 #include "core/style/BorderEdge.h"
20 #include "core/style/ShadowList.h" 20 #include "core/style/ShadowList.h"
21 #include "core/paint/BackgroundImageGeometry.h" 21 #include "core/paint/BackgroundImageGeometry.h"
22 #include "core/paint/BoxBorderPainter.h"
22 #include "core/paint/BoxDecorationData.h" 23 #include "core/paint/BoxDecorationData.h"
23 #include "core/paint/DeprecatedPaintLayer.h" 24 #include "core/paint/DeprecatedPaintLayer.h"
24 #include "core/paint/LayoutObjectDrawingRecorder.h" 25 #include "core/paint/LayoutObjectDrawingRecorder.h"
25 #include "core/paint/PaintInfo.h" 26 #include "core/paint/PaintInfo.h"
26 #include "core/paint/RoundedInnerRectClipper.h" 27 #include "core/paint/RoundedInnerRectClipper.h"
27 #include "core/paint/ThemePainter.h" 28 #include "core/paint/ThemePainter.h"
28 #include "platform/LengthFunctions.h" 29 #include "platform/LengthFunctions.h"
29 #include "platform/geometry/LayoutPoint.h" 30 #include "platform/geometry/LayoutPoint.h"
30 #include "platform/geometry/LayoutRectOutsets.h" 31 #include "platform/geometry/LayoutRectOutsets.h"
31 #include "platform/graphics/GraphicsContextStateSaver.h" 32 #include "platform/graphics/GraphicsContextStateSaver.h"
(...skipping 1090 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 1123
1123 graphicsContext->drawTiledImage(image.get(), 1124 graphicsContext->drawTiledImage(image.get(),
1124 IntRect(borderImageRect.x() + leftWidth, borderImageRect.y() + topWi dth, destinationWidth, destinationHeight), 1125 IntRect(borderImageRect.x() + leftWidth, borderImageRect.y() + topWi dth, destinationWidth, destinationHeight),
1125 IntRect(leftSlice, topSlice, sourceWidth, sourceHeight), 1126 IntRect(leftSlice, topSlice, sourceWidth, sourceHeight),
1126 middleScaleFactor, (Image::TileRule)hRule, (Image::TileRule)vRule, o p); 1127 middleScaleFactor, (Image::TileRule)hRule, (Image::TileRule)vRule, o p);
1127 } 1128 }
1128 graphicsContext->setImageInterpolationQuality(previousInterpolationQuality); 1129 graphicsContext->setImageInterpolationQuality(previousInterpolationQuality);
1129 return true; 1130 return true;
1130 } 1131 }
1131 1132
1132 static FloatRect calculateSideRect(const FloatRoundedRect& outerBorder, const Bo rderEdge& edge, int side)
1133 {
1134 FloatRect sideRect = outerBorder.rect();
1135 int width = edge.width;
1136
1137 if (side == BSTop)
1138 sideRect.setHeight(width);
1139 else if (side == BSBottom)
1140 sideRect.shiftYEdgeTo(sideRect.maxY() - width);
1141 else if (side == BSLeft)
1142 sideRect.setWidth(width);
1143 else
1144 sideRect.shiftXEdgeTo(sideRect.maxX() - width);
1145
1146 return sideRect;
1147 }
1148
1149 enum BorderEdgeFlag {
1150 TopBorderEdge = 1 << BSTop,
1151 RightBorderEdge = 1 << BSRight,
1152 BottomBorderEdge = 1 << BSBottom,
1153 LeftBorderEdge = 1 << BSLeft,
1154 AllBorderEdges = TopBorderEdge | BottomBorderEdge | LeftBorderEdge | RightBo rderEdge
1155 };
1156
1157 static inline BorderEdgeFlag edgeFlagForSide(BoxSide side)
1158 {
1159 return static_cast<BorderEdgeFlag>(1 << side);
1160 }
1161
1162 static inline bool includesEdge(BorderEdgeFlags flags, BoxSide side)
1163 {
1164 return flags & edgeFlagForSide(side);
1165 }
1166
1167 inline bool styleRequiresClipPolygon(EBorderStyle style)
1168 {
1169 return style == DOTTED || style == DASHED; // These are drawn with a stroke, so we have to clip to get corner miters.
1170 }
1171
1172 static bool borderStyleFillsBorderArea(EBorderStyle style)
1173 {
1174 return !(style == DOTTED || style == DASHED || style == DOUBLE);
1175 }
1176
1177 static bool borderStyleHasInnerDetail(EBorderStyle style)
1178 {
1179 return style == GROOVE || style == RIDGE || style == DOUBLE;
1180 }
1181
1182 static bool borderStyleIsDottedOrDashed(EBorderStyle style)
1183 {
1184 return style == DOTTED || style == DASHED;
1185 }
1186
1187 // OUTSET darkens the bottom and right (and maybe lightens the top and left)
1188 // INSET darkens the top and left (and maybe lightens the bottom and right)
1189 static inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style, Box Side side, BoxSide adjacentSide)
1190 {
1191 // These styles match at the top/left and bottom/right.
1192 if (style == INSET || style == GROOVE || style == RIDGE || style == OUTSET) {
1193 const BorderEdgeFlags topRightFlags = edgeFlagForSide(BSTop) | edgeFlagF orSide(BSRight);
1194 const BorderEdgeFlags bottomLeftFlags = edgeFlagForSide(BSBottom) | edge FlagForSide(BSLeft);
1195
1196 BorderEdgeFlags flags = edgeFlagForSide(side) | edgeFlagForSide(adjacent Side);
1197 return flags == topRightFlags || flags == bottomLeftFlags;
1198 }
1199 return false;
1200 }
1201
1202 static inline bool colorsMatchAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1203 {
1204 if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
1205 return false;
1206
1207 if (!edges[side].sharesColorWith(edges[adjacentSide]))
1208 return false;
1209
1210 return !borderStyleHasUnmatchedColorsAtCorner(edges[side].borderStyle(), sid e, adjacentSide);
1211 }
1212
1213 static inline bool colorNeedsAntiAliasAtCorner(BoxSide side, BoxSide adjacentSid e, const BorderEdge edges[])
1214 {
1215 if (!edges[side].color.hasAlpha())
1216 return false;
1217
1218 if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
1219 return false;
1220
1221 if (!edges[side].sharesColorWith(edges[adjacentSide]))
1222 return true;
1223
1224 return borderStyleHasUnmatchedColorsAtCorner(edges[side].borderStyle(), side , adjacentSide);
1225 }
1226
1227 bool BoxPainter::shouldAntialiasLines(GraphicsContext* context) 1133 bool BoxPainter::shouldAntialiasLines(GraphicsContext* context)
1228 { 1134 {
1229 // FIXME: We may want to not antialias when scaled by an integral value, 1135 // FIXME: We may want to not antialias when scaled by an integral value,
1230 // and we may want to antialias when translated by a non-integral value. 1136 // and we may want to antialias when translated by a non-integral value.
1231 // FIXME: See crbug.com/382491. getCTM does not include scale factors applie d at raster time, such 1137 // FIXME: See crbug.com/382491. getCTM does not include scale factors applie d at raster time, such
1232 // as device zoom. 1138 // as device zoom.
1233 return !context->getCTM().isIdentityOrTranslationOrFlipped(); 1139 return !context->getCTM().isIdentityOrTranslationOrFlipped();
1234 } 1140 }
1235 1141
1236 static bool borderWillArcInnerEdge(const FloatSize& firstRadius, const FloatSize & secondRadius) 1142 bool BoxPainter::allCornersClippedOut(const FloatRoundedRect& border, const IntR ect& intClipRect)
1237 {
1238 return !firstRadius.isZero() || !secondRadius.isZero();
1239 }
1240
1241 // This assumes that we draw in order: top, bottom, left, right.
1242 static inline bool willBeOverdrawn(BoxSide side, BoxSide adjacentSide, const Bor derEdge edges[])
1243 {
1244 switch (side) {
1245 case BSTop:
1246 case BSBottom:
1247 if (edges[adjacentSide].presentButInvisible())
1248 return false;
1249
1250 if (!edges[side].sharesColorWith(edges[adjacentSide]) && edges[adjacentS ide].color.hasAlpha())
1251 return false;
1252
1253 if (!borderStyleFillsBorderArea(edges[adjacentSide].borderStyle()))
1254 return false;
1255
1256 return true;
1257
1258 case BSLeft:
1259 case BSRight:
1260 // These draw last, so are never overdrawn.
1261 return false;
1262 }
1263 return false;
1264 }
1265
1266 static inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorderStyle style, EBorderStyle adjacentStyle)
1267 {
1268 if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE || adjacentStyle == RIDGE)
1269 return true;
1270
1271 if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjace ntStyle))
1272 return true;
1273
1274 if (style != adjacentStyle)
1275 return true;
1276
1277 return borderStyleHasUnmatchedColorsAtCorner(style, side, adjacentSide);
1278 }
1279
1280 static bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEd ge edges[], bool allowOverdraw)
1281 {
1282 if ((edges[side].isTransparent && edges[adjacentSide].isTransparent) || !edg es[adjacentSide].isPresent)
1283 return false;
1284
1285 if (allowOverdraw && willBeOverdrawn(side, adjacentSide, edges))
1286 return false;
1287
1288 if (!edges[side].sharesColorWith(edges[adjacentSide]))
1289 return true;
1290
1291 if (borderStylesRequireMitre(side, adjacentSide, edges[side].borderStyle(), edges[adjacentSide].borderStyle()))
1292 return true;
1293
1294 return false;
1295 }
1296
1297 static FloatRect calculateSideRectIncludingInner(const FloatRoundedRect& outerBo rder, const BorderEdge edges[], BoxSide side)
1298 {
1299 FloatRect sideRect = outerBorder.rect();
1300 int width;
1301
1302 switch (side) {
1303 case BSTop:
1304 width = sideRect.height() - edges[BSBottom].width;
1305 sideRect.setHeight(width);
1306 break;
1307 case BSBottom:
1308 width = sideRect.height() - edges[BSTop].width;
1309 sideRect.shiftYEdgeTo(sideRect.maxY() - width);
1310 break;
1311 case BSLeft:
1312 width = sideRect.width() - edges[BSRight].width;
1313 sideRect.setWidth(width);
1314 break;
1315 case BSRight:
1316 width = sideRect.width() - edges[BSLeft].width;
1317 sideRect.shiftXEdgeTo(sideRect.maxX() - width);
1318 break;
1319 }
1320
1321 return sideRect;
1322 }
1323
1324 static FloatRoundedRect calculateAdjustedInnerBorder(const FloatRoundedRect& inn erBorder, BoxSide side)
1325 {
1326 // Expand the inner border as necessary to make it a rounded rect (i.e. radi i contained within each edge).
1327 // This function relies on the fact we only get radii not contained within e ach edge if one of the radii
1328 // for an edge is zero, so we can shift the arc towards the zero radius corn er.
1329 FloatRoundedRect::Radii newRadii = innerBorder.radii();
1330 FloatRect newRect = innerBorder.rect();
1331
1332 float overshoot;
1333 float maxRadii;
1334
1335 switch (side) {
1336 case BSTop:
1337 overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - n ewRect.width();
1338 // FIXME: once we start pixel-snapping rounded rects after this point, t he overshoot concept
1339 // should disappear.
1340 if (overshoot > 0.1) {
1341 newRect.setWidth(newRect.width() + overshoot);
1342 if (!newRadii.topLeft().width())
1343 newRect.move(-overshoot, 0);
1344 }
1345 newRadii.setBottomLeft(IntSize(0, 0));
1346 newRadii.setBottomRight(IntSize(0, 0));
1347 maxRadii = std::max(newRadii.topLeft().height(), newRadii.topRight().hei ght());
1348 if (maxRadii > newRect.height())
1349 newRect.setHeight(maxRadii);
1350 break;
1351
1352 case BSBottom:
1353 overshoot = newRadii.bottomLeft().width() + newRadii.bottomRight().width () - newRect.width();
1354 if (overshoot > 0.1) {
1355 newRect.setWidth(newRect.width() + overshoot);
1356 if (!newRadii.bottomLeft().width())
1357 newRect.move(-overshoot, 0);
1358 }
1359 newRadii.setTopLeft(IntSize(0, 0));
1360 newRadii.setTopRight(IntSize(0, 0));
1361 maxRadii = std::max(newRadii.bottomLeft().height(), newRadii.bottomRight ().height());
1362 if (maxRadii > newRect.height()) {
1363 newRect.move(0, newRect.height() - maxRadii);
1364 newRect.setHeight(maxRadii);
1365 }
1366 break;
1367
1368 case BSLeft:
1369 overshoot = newRadii.topLeft().height() + newRadii.bottomLeft().height() - newRect.height();
1370 if (overshoot > 0.1) {
1371 newRect.setHeight(newRect.height() + overshoot);
1372 if (!newRadii.topLeft().height())
1373 newRect.move(0, -overshoot);
1374 }
1375 newRadii.setTopRight(IntSize(0, 0));
1376 newRadii.setBottomRight(IntSize(0, 0));
1377 maxRadii = std::max(newRadii.topLeft().width(), newRadii.bottomLeft().wi dth());
1378 if (maxRadii > newRect.width())
1379 newRect.setWidth(maxRadii);
1380 break;
1381
1382 case BSRight:
1383 overshoot = newRadii.topRight().height() + newRadii.bottomRight().height () - newRect.height();
1384 if (overshoot > 0.1) {
1385 newRect.setHeight(newRect.height() + overshoot);
1386 if (!newRadii.topRight().height())
1387 newRect.move(0, -overshoot);
1388 }
1389 newRadii.setTopLeft(IntSize(0, 0));
1390 newRadii.setBottomLeft(IntSize(0, 0));
1391 maxRadii = std::max(newRadii.topRight().width(), newRadii.bottomRight(). width());
1392 if (maxRadii > newRect.width()) {
1393 newRect.move(newRect.width() - maxRadii, 0);
1394 newRect.setWidth(maxRadii);
1395 }
1396 break;
1397 }
1398
1399 return FloatRoundedRect(newRect, newRadii);
1400 }
1401
1402 void BoxPainter::clipBorderSideForComplexInnerPath(GraphicsContext* graphicsCont ext, const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder,
1403 BoxSide side, const BorderEdge edges[])
1404 {
1405 graphicsContext->clip(calculateSideRectIncludingInner(outerBorder, edges, si de));
1406 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(innerBorde r, side);
1407 if (!adjustedInnerRect.isEmpty())
1408 graphicsContext->clipOutRoundedRect(adjustedInnerRect);
1409 }
1410
1411 namespace {
1412
1413 bool allCornersClippedOut(const FloatRoundedRect& border, const IntRect& intClip Rect)
1414 { 1143 {
1415 LayoutRect boundingRect(border.rect()); 1144 LayoutRect boundingRect(border.rect());
1416 LayoutRect clipRect(intClipRect); 1145 LayoutRect clipRect(intClipRect);
1417 if (clipRect.contains(boundingRect)) 1146 if (clipRect.contains(boundingRect))
1418 return false; 1147 return false;
1419 1148
1420 FloatRoundedRect::Radii radii = border.radii(); 1149 FloatRoundedRect::Radii radii = border.radii();
1421 1150
1422 LayoutRect topLeftRect(boundingRect.location(), LayoutSize(radii.topLeft())) ; 1151 LayoutRect topLeftRect(boundingRect.location(), LayoutSize(radii.topLeft())) ;
1423 if (clipRect.intersects(topLeftRect)) 1152 if (clipRect.intersects(topLeftRect))
(...skipping 11 matching lines...) Expand all
1435 1164
1436 LayoutRect bottomRightRect(boundingRect.location(), LayoutSize(radii.bottomR ight())); 1165 LayoutRect bottomRightRect(boundingRect.location(), LayoutSize(radii.bottomR ight()));
1437 bottomRightRect.setX(boundingRect.maxX() - bottomRightRect.width()); 1166 bottomRightRect.setX(boundingRect.maxX() - bottomRightRect.width());
1438 bottomRightRect.setY(boundingRect.maxY() - bottomRightRect.height()); 1167 bottomRightRect.setY(boundingRect.maxY() - bottomRightRect.height());
1439 if (clipRect.intersects(bottomRightRect)) 1168 if (clipRect.intersects(bottomRightRect))
1440 return false; 1169 return false;
1441 1170
1442 return true; 1171 return true;
1443 } 1172 }
1444 1173
1445 // TODO(fmalita): Border painting is complex enough to warrant a standalone clas s. Move all related
1446 // logic out into BoxBorderPainter or such.
1447 // TODO(fmalita): Move static BoxPainter border methods to anonymous ns and upda te to use a
1448 // BoxBorderInfo argument.
1449 struct BoxBorderInfo {
1450 STACK_ALLOCATED();
1451 public:
1452 BoxBorderInfo(const ComputedStyle& style, BackgroundBleedAvoidance bleedAvoi dance,
1453 bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1454 : style(style)
1455 , bleedAvoidance(bleedAvoidance)
1456 , includeLogicalLeftEdge(includeLogicalLeftEdge)
1457 , includeLogicalRightEdge(includeLogicalRightEdge)
1458 , visibleEdgeCount(0)
1459 , firstVisibleEdge(0)
1460 , visibleEdgeSet(0)
1461 , isUniformStyle(true)
1462 , isUniformWidth(true)
1463 , isUniformColor(true)
1464 , hasAlpha(false)
1465 {
1466
1467 style.getBorderEdgeInfo(edges, includeLogicalLeftEdge, includeLogicalRig htEdge);
1468
1469 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(edges); ++i) {
1470 const BorderEdge& edge = edges[i];
1471
1472 if (!edge.shouldRender()) {
1473 if (edge.presentButInvisible()) {
1474 isUniformWidth = false;
1475 isUniformColor = false;
1476 }
1477
1478 continue;
1479 }
1480
1481 visibleEdgeCount++;
1482 visibleEdgeSet |= edgeFlagForSide(static_cast<BoxSide>(i));
1483
1484 hasAlpha = hasAlpha || edge.color.hasAlpha();
1485
1486 if (visibleEdgeCount == 1) {
1487 firstVisibleEdge = i;
1488 continue;
1489 }
1490
1491 isUniformStyle = isUniformStyle && (edge.borderStyle() == edges[firs tVisibleEdge].borderStyle());
1492 isUniformWidth = isUniformWidth && (edge.width == edges[firstVisible Edge].width);
1493 isUniformColor = isUniformColor && (edge.color == edges[firstVisible Edge].color);
1494 }
1495 }
1496
1497 const ComputedStyle& style;
1498 const BackgroundBleedAvoidance bleedAvoidance;
1499 const bool includeLogicalLeftEdge;
1500 const bool includeLogicalRightEdge;
1501
1502 BorderEdge edges[4];
1503
1504 unsigned visibleEdgeCount;
1505 unsigned firstVisibleEdge;
1506 BorderEdgeFlags visibleEdgeSet;
1507
1508 bool isUniformStyle;
1509 bool isUniformWidth;
1510 bool isUniformColor;
1511 bool hasAlpha;
1512 };
1513
1514 LayoutRectOutsets doubleStripeInsets(const BorderEdge edges[], BorderEdge::Doubl eBorderStripe stripe)
1515 {
1516 // Insets are representes as negative outsets.
1517 return LayoutRectOutsets(
1518 -edges[BSTop].getDoubleBorderStripeWidth(stripe),
1519 -edges[BSRight].getDoubleBorderStripeWidth(stripe),
1520 -edges[BSBottom].getDoubleBorderStripeWidth(stripe),
1521 -edges[BSLeft].getDoubleBorderStripeWidth(stripe));
1522 }
1523
1524 void drawSolidBorderRect(GraphicsContext* context, const FloatRect& borderRect,
1525 float borderWidth, const Color& color)
1526 {
1527 FloatRect strokeRect(borderRect);
1528 strokeRect.inflate(-borderWidth / 2);
1529
1530 bool antialias = BoxPainter::shouldAntialiasLines(context);
1531 bool wasAntialias = context->shouldAntialias();
1532 if (antialias != wasAntialias)
1533 context->setShouldAntialias(antialias);
1534
1535 context->setStrokeStyle(SolidStroke);
1536 context->setStrokeColor(color);
1537 context->strokeRect(strokeRect, borderWidth);
1538
1539 if (antialias != wasAntialias)
1540 context->setShouldAntialias(wasAntialias);
1541 }
1542
1543 void drawBleedAdjustedDRRect(GraphicsContext* context, BackgroundBleedAvoidance bleedAvoidance,
1544 const FloatRoundedRect& outer, const FloatRoundedRect& inner, Color color)
1545 {
1546 switch (bleedAvoidance) {
1547 case BackgroundBleedBackgroundOverBorder:
1548 // BackgroundBleedBackgroundOverBorder draws an opaque background over t he inner rrect,
1549 // so we can simply fill the outer rect here to avoid backdrop bleeding.
1550 context->fillRoundedRect(outer, color);
1551 break;
1552 case BackgroundBleedClipLayer: {
1553 // BackgroundBleedClipLayer clips the outer rrect for the whole layer. B ased on this,
1554 // we can avoid background bleeding by filling the *outside* of inner rr ect, all the
1555 // way to the layer bounds (enclosing int rect for the clip, in device s pace).
1556 ASSERT(outer.isRounded());
1557
1558 SkPath path;
1559 path.addRRect(inner);
1560 path.setFillType(SkPath::kInverseWinding_FillType);
1561
1562 SkPaint paint;
1563 paint.setColor(color.rgb());
1564 paint.setStyle(SkPaint::kFill_Style);
1565 paint.setAntiAlias(true);
1566 context->drawPath(path, paint);
1567
1568 break;
1569 }
1570 case BackgroundBleedClipOnly:
1571 if (outer.isRounded()) {
1572 // BackgroundBleedClipOnly clips the outer rrect corners for us.
1573 FloatRoundedRect adjustedOuter = outer;
1574 adjustedOuter.setRadii(FloatRoundedRect::Radii());
1575 context->fillDRRect(adjustedOuter, inner, color);
1576 break;
1577 }
1578 // fall through
1579 default:
1580 context->fillDRRect(outer, inner, color);
1581 break;
1582 }
1583 }
1584
1585 void drawDoubleBorder(GraphicsContext* context, const BoxBorderInfo& borderInfo, const LayoutRect& borderRect,
1586 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder)
1587 {
1588 ASSERT(borderInfo.isUniformColor);
1589 ASSERT(borderInfo.isUniformStyle);
1590 ASSERT(borderInfo.edges[borderInfo.firstVisibleEdge].borderStyle() == DOUBLE );
1591 ASSERT(borderInfo.visibleEdgeSet == AllBorderEdges);
1592
1593 const Color color = borderInfo.edges[borderInfo.firstVisibleEdge].color;
1594
1595 // outer stripe
1596 const LayoutRectOutsets outerThirdInsets =
1597 doubleStripeInsets(borderInfo.edges, BorderEdge::DoubleBorderStripeOuter );
1598 const FloatRoundedRect outerThirdRect = borderInfo.style.getRoundedInnerBord erFor(borderRect,
1599 outerThirdInsets, borderInfo.includeLogicalLeftEdge, borderInfo.includeL ogicalRightEdge);
1600 drawBleedAdjustedDRRect(context, borderInfo.bleedAvoidance, outerBorder, out erThirdRect, color);
1601
1602 // inner stripe
1603 const LayoutRectOutsets innerThirdInsets =
1604 doubleStripeInsets(borderInfo.edges, BorderEdge::DoubleBorderStripeInner );
1605 const FloatRoundedRect innerThirdRect = borderInfo.style.getRoundedInnerBord erFor(borderRect,
1606 innerThirdInsets, borderInfo.includeLogicalLeftEdge, borderInfo.includeL ogicalRightEdge);
1607 context->fillDRRect(innerThirdRect, innerBorder, color);
1608 }
1609
1610 bool paintBorderFastPath(GraphicsContext* context, const BoxBorderInfo& info,
1611 const LayoutRect& borderRect, const FloatRoundedRect& outer, const FloatRoun dedRect& inner)
1612 {
1613 if (!info.isUniformColor || !info.isUniformStyle || !inner.isRenderable())
1614 return false;
1615
1616 const BorderEdge& firstEdge = info.edges[info.firstVisibleEdge];
1617 if (firstEdge.borderStyle() != SOLID && firstEdge.borderStyle() != DOUBLE)
1618 return false;
1619
1620 if (info.visibleEdgeSet == AllBorderEdges) {
1621 if (firstEdge.borderStyle() == SOLID) {
1622 if (info.isUniformWidth && !outer.isRounded()) {
1623 // 4-side, solid, uniform-width, rectangular border => one drawR ect()
1624 drawSolidBorderRect(context, outer.rect(), firstEdge.width, firs tEdge.color);
1625 } else {
1626 // 4-side, solid border => one drawDRRect()
1627 drawBleedAdjustedDRRect(context, info.bleedAvoidance, outer, inn er, firstEdge.color);
1628 }
1629 } else {
1630 // 4-side, double border => 2x drawDRRect()
1631 ASSERT(firstEdge.borderStyle() == DOUBLE);
1632 drawDoubleBorder(context, info, borderRect, outer, inner);
1633 }
1634
1635 return true;
1636 }
1637
1638 // This is faster than the normal complex border path only if it avoids crea ting transparency
1639 // layers (when the border is translucent).
1640 if (firstEdge.borderStyle() == SOLID && !outer.isRounded() && info.hasAlpha) {
1641 ASSERT(info.visibleEdgeSet != AllBorderEdges);
1642 // solid, rectangular border => one drawPath()
1643 Path path;
1644
1645 for (int i = BSTop; i <= BSLeft; ++i) {
1646 const BorderEdge& currEdge = info.edges[i];
1647 if (currEdge.shouldRender())
1648 path.addRect(calculateSideRect(outer, currEdge, i));
1649 }
1650
1651 context->setFillRule(RULE_NONZERO);
1652 context->setFillColor(firstEdge.color);
1653 context->fillPath(path);
1654
1655 return true;
1656 }
1657
1658 return false;
1659 }
1660
1661 } // anonymous namespace
1662
1663 void BoxPainter::paintBorder(LayoutBoxModelObject& obj, const PaintInfo& info, c onst LayoutRect& rect, const ComputedStyle& style, BackgroundBleedAvoidance blee dAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) 1174 void BoxPainter::paintBorder(LayoutBoxModelObject& obj, const PaintInfo& info, c onst LayoutRect& rect, const ComputedStyle& style, BackgroundBleedAvoidance blee dAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1664 { 1175 {
1665 GraphicsContext* graphicsContext = info.context; 1176 BoxBorderPainter().paintBorder(obj, info, rect, style, bleedAvoidance, inclu deLogicalLeftEdge, includeLogicalRightEdge);
1666 // border-image is not affected by border-radius.
1667 if (paintNinePieceImage(obj, graphicsContext, rect, style, style.borderImage ()))
1668 return;
1669
1670 const BoxBorderInfo borderInfo(style, bleedAvoidance, includeLogicalLeftEdge , includeLogicalRightEdge);
1671 FloatRoundedRect outerBorder = style.getRoundedBorderFor(rect, includeLogica lLeftEdge, includeLogicalRightEdge);
1672 FloatRoundedRect innerBorder = style.getRoundedInnerBorderFor(rect, includeL ogicalLeftEdge, includeLogicalRightEdge);
1673
1674 if (outerBorder.rect().isEmpty() || !borderInfo.visibleEdgeCount)
1675 return;
1676
1677 const BorderEdge& firstEdge = borderInfo.edges[borderInfo.firstVisibleEdge];
1678 bool haveAllSolidEdges = borderInfo.isUniformStyle && firstEdge.borderStyle( ) == SOLID;
1679
1680 // If no corner intersects the clip region, we can pretend outerBorder is
1681 // rectangular to improve performance.
1682 if (haveAllSolidEdges && outerBorder.isRounded() && allCornersClippedOut(out erBorder, info.rect))
1683 outerBorder.setRadii(FloatRoundedRect::Radii());
1684
1685 if (paintBorderFastPath(graphicsContext, borderInfo, rect, outerBorder, inne rBorder))
1686 return;
1687
1688 bool clipToOuterBorder = outerBorder.isRounded();
1689 GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder);
1690 if (clipToOuterBorder) {
1691 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already applied.
1692 if (!bleedAvoidanceIsClipping(bleedAvoidance))
1693 graphicsContext->clipRoundedRect(outerBorder);
1694
1695 // For BackgroundBleedBackgroundOverBorder, we're going to draw an opaqu e background over
1696 // the inner rrect - so clipping is not needed (nor desirable due to bac kdrop bleeding).
1697 if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && innerBorder .isRenderable() && !innerBorder.isEmpty())
1698 graphicsContext->clipOutRoundedRect(innerBorder);
1699 }
1700
1701 // If only one edge visible antialiasing doesn't create seams
1702 bool antialias = shouldAntialiasLines(graphicsContext) || borderInfo.visible EdgeCount == 1;
1703 if (borderInfo.hasAlpha) {
1704 paintTranslucentBorderSides(graphicsContext, style, outerBorder, innerBo rder, borderInfo.edges,
1705 borderInfo.visibleEdgeSet, bleedAvoidance, includeLogicalLeftEdge, inclu deLogicalRightEdge, antialias);
1706 } else {
1707 paintBorderSides(graphicsContext, style, outerBorder, innerBorder, borde rInfo.edges,
1708 borderInfo.visibleEdgeSet, bleedAvoidance, includeLogicalLeftEdge, inclu deLogicalRightEdge, antialias);
1709 }
1710 }
1711
1712 static inline bool includesAdjacentEdges(BorderEdgeFlags flags)
1713 {
1714 // The set includes adjacent edges iff it contains at least one horizontal a nd one vertical edge.
1715 return (flags & (TopBorderEdge | BottomBorderEdge))
1716 && (flags & (LeftBorderEdge | RightBorderEdge));
1717 }
1718
1719 void BoxPainter::paintTranslucentBorderSides(GraphicsContext* graphicsContext, c onst ComputedStyle& style,
1720 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder, co nst BorderEdge edges[],
1721 BorderEdgeFlags edgesToDraw, BackgroundBleedAvoidance bleedAvoidance, bool i ncludeLogicalLeftEdge,
1722 bool includeLogicalRightEdge, bool antialias)
1723 {
1724 // willBeOverdrawn assumes that we draw in order: top, bottom, left, right.
1725 // This is different from BoxSide enum order.
1726 static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight };
1727
1728 while (edgesToDraw) {
1729 // Find undrawn edges sharing a color.
1730 Color commonColor;
1731
1732 BorderEdgeFlags commonColorEdgeSet = 0;
1733 for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i) {
1734 BoxSide currSide = paintOrder[i];
1735 if (!includesEdge(edgesToDraw, currSide))
1736 continue;
1737
1738 bool includeEdge;
1739 if (!commonColorEdgeSet) {
1740 commonColor = edges[currSide].color;
1741 includeEdge = true;
1742 } else {
1743 includeEdge = edges[currSide].color == commonColor;
1744 }
1745
1746 if (includeEdge)
1747 commonColorEdgeSet |= edgeFlagForSide(currSide);
1748 }
1749
1750 bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) && commonColor.hasAlpha();
1751 if (useTransparencyLayer) {
1752 graphicsContext->beginLayer(static_cast<float>(commonColor.alpha()) / 255);
1753 commonColor = Color(commonColor.red(), commonColor.green(), commonCo lor.blue());
1754 }
1755
1756 paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges , commonColorEdgeSet,
1757 bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, ant ialias, &commonColor);
1758
1759 if (useTransparencyLayer)
1760 graphicsContext->endLayer();
1761
1762 edgesToDraw &= ~commonColorEdgeSet;
1763 }
1764 }
1765
1766 void BoxPainter::paintOneBorderSide(GraphicsContext* graphicsContext, const Comp utedStyle& style, const FloatRoundedRect& outerBorder, const FloatRoundedRect& i nnerBorder,
1767 const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adja centSide2, const BorderEdge edges[], const Path* path,
1768 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool i ncludeLogicalRightEdge, bool antialias, const Color* overrideColor)
1769 {
1770 const BorderEdge& edgeToRender = edges[side];
1771 ASSERT(edgeToRender.width);
1772 const BorderEdge& adjacentEdge1 = edges[adjacentSide1];
1773 const BorderEdge& adjacentEdge2 = edges[adjacentSide2];
1774
1775 bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, edges, !ant ialias);
1776 bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, edges, !ant ialias);
1777
1778 bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, edg es);
1779 bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, edg es);
1780
1781 const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.co lor;
1782
1783 if (path) {
1784 GraphicsContextStateSaver stateSaver(*graphicsContext);
1785 if (innerBorder.isRenderable())
1786 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, sid e, adjacentSide1StylesMatch, adjacentSide2StylesMatch);
1787 else
1788 clipBorderSideForComplexInnerPath(graphicsContext, outerBorder, inne rBorder, side, edges);
1789 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi dth), adjacentEdge2.width);
1790 drawBoxSideFromPath(graphicsContext, LayoutRect(outerBorder.rect()), *pa th, edges, edgeToRender.width, thickness, side, style,
1791 colorToPaint, edgeToRender.borderStyle(), bleedAvoidance, includeLog icalLeftEdge, includeLogicalRightEdge);
1792 } else {
1793 bool clipForStyle = styleRequiresClipPolygon(edgeToRender.borderStyle()) && (mitreAdjacentSide1 || mitreAdjacentSide2);
1794 bool clipAdjacentSide1 = colorNeedsAntiAliasAtCorner(side, adjacentSide1 , edges) && mitreAdjacentSide1;
1795 bool clipAdjacentSide2 = colorNeedsAntiAliasAtCorner(side, adjacentSide2 , edges) && mitreAdjacentSide2;
1796 bool shouldClip = clipForStyle || clipAdjacentSide1 || clipAdjacentSide2 ;
1797
1798 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip);
1799 if (shouldClip) {
1800 bool aliasAdjacentSide1 = clipAdjacentSide1 || (clipForStyle && mitr eAdjacentSide1);
1801 bool aliasAdjacentSide2 = clipAdjacentSide2 || (clipForStyle && mitr eAdjacentSide2);
1802 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, sid e, !aliasAdjacentSide1, !aliasAdjacentSide2);
1803 // Since we clipped, no need to draw with a mitre.
1804 mitreAdjacentSide1 = false;
1805 mitreAdjacentSide2 = false;
1806 }
1807
1808 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec t.y(), sideRect.maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.border Style(),
1809 mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? a djacentEdge2.width : 0, antialias);
1810 }
1811 }
1812
1813 void BoxPainter::paintBorderSides(GraphicsContext* graphicsContext, const Comput edStyle& style, const FloatRoundedRect& outerBorder, const FloatRoundedRect& inn erBorder,
1814 const BorderEdge edges[], BorderEdgeFlags edgeSet, BackgroundBleedAvoidance bleedAvoidance,
1815 bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, c onst Color* overrideColor)
1816 {
1817 bool renderRadii = outerBorder.isRounded();
1818
1819 Path roundedPath;
1820 if (renderRadii)
1821 roundedPath.addRoundedRect(outerBorder);
1822
1823 // The inner border adjustment for bleed avoidance mode BackgroundBleedBackg roundOverBorder
1824 // is only applied to sideRect, which is okay since BackgroundBleedBackgroun dOverBorder
1825 // is only to be used for solid borders and the shape of the border painted by drawBoxSideFromPath
1826 // only depends on sideRect when painting solid borders.
1827
1828 if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) {
1829 FloatRect sideRect = outerBorder.rect();
1830 sideRect.setHeight(edges[BSTop].width);
1831
1832 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].bo rderStyle()) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorde r.radii().topRight()));
1833 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance , includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1834 }
1835
1836 if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) {
1837 FloatRect sideRect = outerBorder.rect();
1838 sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width);
1839
1840 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom] .borderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), inne rBorder.radii().bottomRight()));
1841 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoida nce, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1842 }
1843
1844 if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) {
1845 FloatRect sideRect = outerBorder.rect();
1846 sideRect.setWidth(edges[BSLeft].width);
1847
1848 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].b orderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerB order.radii().topLeft()));
1849 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidanc e, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1850 }
1851
1852 if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) {
1853 FloatRect sideRect = outerBorder.rect();
1854 sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width);
1855
1856 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight]. borderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), inne rBorder.radii().topRight()));
1857 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidan ce, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1858 }
1859 }
1860
1861 void BoxPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext, const Lay outRect& borderRect, const Path& borderPath, const BorderEdge edges[],
1862 float thickness, float drawThickness, BoxSide side, const ComputedStyle& sty le, Color color, EBorderStyle borderStyle, BackgroundBleedAvoidance bleedAvoidan ce,
1863 bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1864 {
1865 if (thickness <= 0)
1866 return;
1867
1868 if (borderStyle == DOUBLE && thickness < 3)
1869 borderStyle = SOLID;
1870
1871 switch (borderStyle) {
1872 case BNONE:
1873 case BHIDDEN:
1874 return;
1875 case DOTTED:
1876 case DASHED: {
1877 graphicsContext->setStrokeColor(color);
1878
1879 // The stroke is doubled here because the provided path is the
1880 // outside edge of the border so half the stroke is clipped off.
1881 // The extra multiplier is so that the clipping mask can antialias
1882 // the edges to prevent jaggies.
1883 graphicsContext->setStrokeThickness(drawThickness * 2 * 1.1f);
1884 graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : D ottedStroke);
1885
1886 // If the number of dashes that fit in the path is odd and non-integral then we
1887 // will have an awkwardly-sized dash at the end of the path. To try to a void that
1888 // here, we simply make the whitespace dashes ever so slightly bigger.
1889 // FIXME: This could be even better if we tried to manipulate the dash o ffset
1890 // and possibly the gapLength to get the corners dash-symmetrical.
1891 float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f);
1892 float gapLength = dashLength;
1893 float numberOfDashes = borderPath.length() / dashLength;
1894 // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
1895 // FIXME: should do this test per side.
1896 if (numberOfDashes >= 4) {
1897 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
1898 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes );
1899 if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
1900 float numberOfGaps = numberOfDashes / 2;
1901 gapLength += (dashLength / numberOfGaps);
1902 }
1903
1904 DashArray lineDash;
1905 lineDash.append(dashLength);
1906 lineDash.append(gapLength);
1907 graphicsContext->setLineDash(lineDash, dashLength);
1908 }
1909
1910 // FIXME: stroking the border path causes issues with tight corners:
1911 // https://bugs.webkit.org/show_bug.cgi?id=58711
1912 // Also, to get the best appearance we should stroke a path between the two borders.
1913 graphicsContext->strokePath(borderPath);
1914 return;
1915 }
1916 case DOUBLE: {
1917 // Draw inner border line
1918 {
1919 GraphicsContextStateSaver stateSaver(*graphicsContext);
1920 const LayoutRectOutsets innerInsets = doubleStripeInsets(edges, Bord erEdge::DoubleBorderStripeInner);
1921 FloatRoundedRect innerClip = style.getRoundedInnerBorderFor(borderRe ct,
1922 innerInsets, includeLogicalLeftEdge, includeLogicalRightEdge);
1923
1924 graphicsContext->clipRoundedRect(innerClip);
1925 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogi calLeftEdge, includeLogicalRightEdge);
1926 }
1927
1928 // Draw outer border line
1929 {
1930 GraphicsContextStateSaver stateSaver(*graphicsContext);
1931 LayoutRect outerRect = borderRect;
1932 LayoutRectOutsets outerInsets = doubleStripeInsets(edges, BorderEdge ::DoubleBorderStripeOuter);
1933
1934 if (bleedAvoidanceIsClipping(bleedAvoidance)) {
1935 outerRect.inflate(1);
1936 outerInsets.setTop(outerInsets.top() - 1);
1937 outerInsets.setRight(outerInsets.right() - 1);
1938 outerInsets.setBottom(outerInsets.bottom() - 1);
1939 outerInsets.setLeft(outerInsets.left() - 1);
1940 }
1941
1942 FloatRoundedRect outerClip = style.getRoundedInnerBorderFor(outerRec t, outerInsets,
1943 includeLogicalLeftEdge, includeLogicalRightEdge);
1944 graphicsContext->clipOutRoundedRect(outerClip);
1945 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogi calLeftEdge, includeLogicalRightEdge);
1946 }
1947 return;
1948 }
1949 case RIDGE:
1950 case GROOVE:
1951 {
1952 EBorderStyle s1;
1953 EBorderStyle s2;
1954 if (borderStyle == GROOVE) {
1955 s1 = INSET;
1956 s2 = OUTSET;
1957 } else {
1958 s1 = OUTSET;
1959 s2 = INSET;
1960 }
1961
1962 // Paint full border
1963 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thic kness, drawThickness, side, style, color, s1, bleedAvoidance, includeLogicalLeft Edge, includeLogicalRightEdge);
1964
1965 // Paint inner only
1966 GraphicsContextStateSaver stateSaver(*graphicsContext);
1967 LayoutUnit topWidth = edges[BSTop].usedWidth() / 2;
1968 LayoutUnit bottomWidth = edges[BSBottom].usedWidth() / 2;
1969 LayoutUnit leftWidth = edges[BSLeft].usedWidth() / 2;
1970 LayoutUnit rightWidth = edges[BSRight].usedWidth() / 2;
1971
1972 FloatRoundedRect clipRect = style.getRoundedInnerBorderFor(borderRect,
1973 LayoutRectOutsets(-topWidth, -rightWidth, -bottomWidth, -leftWidth),
1974 includeLogicalLeftEdge, includeLogicalRightEdge);
1975
1976 graphicsContext->clipRoundedRect(clipRect);
1977 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thic kness, drawThickness, side, style, color, s2, bleedAvoidance, includeLogicalLeft Edge, includeLogicalRightEdge);
1978 return;
1979 }
1980 case INSET:
1981 if (side == BSTop || side == BSLeft)
1982 color = color.dark();
1983 break;
1984 case OUTSET:
1985 if (side == BSBottom || side == BSRight)
1986 color = color.dark();
1987 break;
1988 default:
1989 break;
1990 }
1991
1992 graphicsContext->setStrokeStyle(NoStroke);
1993 graphicsContext->setFillColor(color);
1994 graphicsContext->drawRect(pixelSnappedIntRect(borderRect));
1995 } 1177 }
1996 1178
1997 void BoxPainter::paintBoxShadow(const PaintInfo& info, const LayoutRect& paintRe ct, const ComputedStyle& style, ShadowStyle shadowStyle, bool includeLogicalLeft Edge, bool includeLogicalRightEdge) 1179 void BoxPainter::paintBoxShadow(const PaintInfo& info, const LayoutRect& paintRe ct, const ComputedStyle& style, ShadowStyle shadowStyle, bool includeLogicalLeft Edge, bool includeLogicalRightEdge)
1998 { 1180 {
1999 // FIXME: Deal with border-image. Would be great to use border-image as a ma sk. 1181 // FIXME: Deal with border-image. Would be great to use border-image as a ma sk.
2000 GraphicsContext* context = info.context; 1182 GraphicsContext* context = info.context;
2001 if (!style.boxShadow()) 1183 if (!style.boxShadow())
2002 return; 1184 return;
2003 FloatRoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBord erFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge) 1185 FloatRoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBord erFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
2004 : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLo gicalRightEdge); 1186 : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLo gicalRightEdge);
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
2110 clippedEdges |= GraphicsContext::RightEdge; 1292 clippedEdges |= GraphicsContext::RightEdge;
2111 else 1293 else
2112 clippedEdges |= GraphicsContext::BottomEdge; 1294 clippedEdges |= GraphicsContext::BottomEdge;
2113 } 1295 }
2114 // TODO: support non-integer shadows - crbug.com/334828 1296 // TODO: support non-integer shadows - crbug.com/334828
2115 context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowO ffset), shadowBlur, shadowSpread, clippedEdges); 1297 context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowO ffset), shadowBlur, shadowSpread, clippedEdges);
2116 } 1298 }
2117 } 1299 }
2118 } 1300 }
2119 1301
2120 void BoxPainter::clipBorderSidePolygon(GraphicsContext* graphicsContext, const F loatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder, BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches)
2121 {
2122 FloatPoint quad[4];
2123
2124 const LayoutRect outerRect(outerBorder.rect());
2125 const LayoutRect innerRect(innerBorder.rect());
2126
2127 FloatPoint centerPoint(innerRect.location().x().toFloat() + innerRect.width( ).toFloat() / 2, innerRect.location().y().toFloat() + innerRect.height().toFloat () / 2);
2128
2129 // For each side, create a quad that encompasses all parts of that side that may draw,
2130 // including areas inside the innerBorder.
2131 //
2132 // 0----------------3
2133 // 0 \ / 0
2134 // |\ 1----------- 2 /|
2135 // | 1 1 |
2136 // | | | |
2137 // | | | |
2138 // | 2 2 |
2139 // |/ 1------------2 \|
2140 // 3 / \ 3
2141 // 0----------------3
2142 //
2143 switch (side) {
2144 case BSTop:
2145 quad[0] = FloatPoint(outerRect.minXMinYCorner());
2146 quad[1] = FloatPoint(innerRect.minXMinYCorner());
2147 quad[2] = FloatPoint(innerRect.maxXMinYCorner());
2148 quad[3] = FloatPoint(outerRect.maxXMinYCorner());
2149
2150 if (!innerBorder.radii().topLeft().isZero()) {
2151 findIntersection(quad[0], quad[1],
2152 FloatPoint(
2153 quad[1].x() + innerBorder.radii().topLeft().width(),
2154 quad[1].y()),
2155 FloatPoint(
2156 quad[1].x(),
2157 quad[1].y() + innerBorder.radii().topLeft().height()),
2158 quad[1]);
2159 }
2160
2161 if (!innerBorder.radii().topRight().isZero()) {
2162 findIntersection(quad[3], quad[2],
2163 FloatPoint(
2164 quad[2].x() - innerBorder.radii().topRight().width(),
2165 quad[2].y()),
2166 FloatPoint(
2167 quad[2].x(),
2168 quad[2].y() + innerBorder.radii().topRight().height()),
2169 quad[2]);
2170 }
2171 break;
2172
2173 case BSLeft:
2174 quad[0] = FloatPoint(outerRect.minXMinYCorner());
2175 quad[1] = FloatPoint(innerRect.minXMinYCorner());
2176 quad[2] = FloatPoint(innerRect.minXMaxYCorner());
2177 quad[3] = FloatPoint(outerRect.minXMaxYCorner());
2178
2179 if (!innerBorder.radii().topLeft().isZero()) {
2180 findIntersection(quad[0], quad[1],
2181 FloatPoint(
2182 quad[1].x() + innerBorder.radii().topLeft().width(),
2183 quad[1].y()),
2184 FloatPoint(
2185 quad[1].x(),
2186 quad[1].y() + innerBorder.radii().topLeft().height()),
2187 quad[1]);
2188 }
2189
2190 if (!innerBorder.radii().bottomLeft().isZero()) {
2191 findIntersection(quad[3], quad[2],
2192 FloatPoint(
2193 quad[2].x() + innerBorder.radii().bottomLeft().width(),
2194 quad[2].y()),
2195 FloatPoint(
2196 quad[2].x(),
2197 quad[2].y() - innerBorder.radii().bottomLeft().height()),
2198 quad[2]);
2199 }
2200 break;
2201
2202 case BSBottom:
2203 quad[0] = FloatPoint(outerRect.minXMaxYCorner());
2204 quad[1] = FloatPoint(innerRect.minXMaxYCorner());
2205 quad[2] = FloatPoint(innerRect.maxXMaxYCorner());
2206 quad[3] = FloatPoint(outerRect.maxXMaxYCorner());
2207
2208 if (!innerBorder.radii().bottomLeft().isZero()) {
2209 findIntersection(quad[0], quad[1],
2210 FloatPoint(
2211 quad[1].x() + innerBorder.radii().bottomLeft().width(),
2212 quad[1].y()),
2213 FloatPoint(
2214 quad[1].x(),
2215 quad[1].y() - innerBorder.radii().bottomLeft().height()),
2216 quad[1]);
2217 }
2218
2219 if (!innerBorder.radii().bottomRight().isZero()) {
2220 findIntersection(quad[3], quad[2],
2221 FloatPoint(
2222 quad[2].x() - innerBorder.radii().bottomRight().width(),
2223 quad[2].y()),
2224 FloatPoint(
2225 quad[2].x(),
2226 quad[2].y() - innerBorder.radii().bottomRight().height()),
2227 quad[2]);
2228 }
2229 break;
2230
2231 case BSRight:
2232 quad[0] = FloatPoint(outerRect.maxXMinYCorner());
2233 quad[1] = FloatPoint(innerRect.maxXMinYCorner());
2234 quad[2] = FloatPoint(innerRect.maxXMaxYCorner());
2235 quad[3] = FloatPoint(outerRect.maxXMaxYCorner());
2236
2237 if (!innerBorder.radii().topRight().isZero()) {
2238 findIntersection(quad[0], quad[1],
2239 FloatPoint(
2240 quad[1].x() - innerBorder.radii().topRight().width(),
2241 quad[1].y()),
2242 FloatPoint(
2243 quad[1].x(),
2244 quad[1].y() + innerBorder.radii().topRight().height()),
2245 quad[1]);
2246 }
2247
2248 if (!innerBorder.radii().bottomRight().isZero()) {
2249 findIntersection(quad[3], quad[2],
2250 FloatPoint(
2251 quad[2].x() - innerBorder.radii().bottomRight().width(),
2252 quad[2].y()),
2253 FloatPoint(
2254 quad[2].x(),
2255 quad[2].y() - innerBorder.radii().bottomRight().height()),
2256 quad[2]);
2257 }
2258 break;
2259 }
2260
2261 // If the border matches both of its adjacent sides, don't anti-alias the cl ip, and
2262 // if neither side matches, anti-alias the clip.
2263 if (firstEdgeMatches == secondEdgeMatches) {
2264 graphicsContext->clipPolygon(4, quad, !firstEdgeMatches);
2265 return;
2266 }
2267
2268 // If antialiasing settings for the first edge and second edge is different,
2269 // they have to be addressed separately. We do this by breaking the quad int o
2270 // two parallelograms, made by moving quad[1] and quad[2].
2271 float ax = quad[1].x() - quad[0].x();
2272 float ay = quad[1].y() - quad[0].y();
2273 float bx = quad[2].x() - quad[1].x();
2274 float by = quad[2].y() - quad[1].y();
2275 float cx = quad[3].x() - quad[2].x();
2276 float cy = quad[3].y() - quad[2].y();
2277
2278 const static float kEpsilon = 1e-2f;
2279 float r1, r2;
2280 if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) {
2281 // The quad was actually a triangle.
2282 r1 = r2 = 1.0f;
2283 } else {
2284 // Extend parallelogram a bit to hide calculation error
2285 const static float kExtendFill = 1e-2f;
2286
2287 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill;
2288 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill;
2289 }
2290
2291 FloatPoint firstQuad[4];
2292 firstQuad[0] = quad[0];
2293 firstQuad[1] = quad[1];
2294 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay);
2295 firstQuad[3] = quad[3];
2296 graphicsContext->clipPolygon(4, firstQuad, !firstEdgeMatches);
2297
2298 FloatPoint secondQuad[4];
2299 secondQuad[0] = quad[0];
2300 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy);
2301 secondQuad[2] = quad[2];
2302 secondQuad[3] = quad[3];
2303 graphicsContext->clipPolygon(4, secondQuad, !secondEdgeMatches);
2304 }
2305
2306 } // namespace blink 1302 } // namespace blink
OLDNEW
« Source/core/paint/BoxBorderPainter.h ('K') | « Source/core/paint/BoxPainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698