OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "core/paint/BoxBorderPainter.h" | 5 #include "core/paint/BoxBorderPainter.h" |
6 | 6 |
7 #include "core/paint/BoxPainter.h" | 7 #include "core/paint/BoxPainter.h" |
8 #include "core/paint/ObjectPainter.h" | 8 #include "core/paint/ObjectPainter.h" |
9 #include "core/paint/PaintInfo.h" | 9 #include "core/paint/PaintInfo.h" |
10 #include "core/style/BorderEdge.h" | 10 #include "core/style/BorderEdge.h" |
(...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 | 969 |
970 if (borderStyle == BorderStyleDouble && thickness < 3) | 970 if (borderStyle == BorderStyleDouble && thickness < 3) |
971 borderStyle = BorderStyleSolid; | 971 borderStyle = BorderStyleSolid; |
972 | 972 |
973 switch (borderStyle) { | 973 switch (borderStyle) { |
974 case BorderStyleNone: | 974 case BorderStyleNone: |
975 case BorderStyleHidden: | 975 case BorderStyleHidden: |
976 return; | 976 return; |
977 case BorderStyleDotted: | 977 case BorderStyleDotted: |
978 case BorderStyleDashed: { | 978 case BorderStyleDashed: { |
979 drawDashedDottedBoxSideFromPath(graphicsContext, borderPath, thickness, | 979 drawDashedDottedBoxSideFromPath(graphicsContext, borderRect, thickness, |
980 drawThickness, color, borderStyle); | 980 drawThickness, color, borderStyle); |
981 return; | 981 return; |
982 } | 982 } |
983 case BorderStyleDouble: { | 983 case BorderStyleDouble: { |
984 drawDoubleBoxSideFromPath(graphicsContext, borderRect, borderPath, | 984 drawDoubleBoxSideFromPath(graphicsContext, borderRect, borderPath, |
985 thickness, drawThickness, side, color); | 985 thickness, drawThickness, side, color); |
986 return; | 986 return; |
987 } | 987 } |
988 case BorderStyleRidge: | 988 case BorderStyleRidge: |
989 case BorderStyleGroove: { | 989 case BorderStyleGroove: { |
(...skipping 14 matching lines...) Expand all Loading... |
1004 break; | 1004 break; |
1005 } | 1005 } |
1006 | 1006 |
1007 graphicsContext.setStrokeStyle(NoStroke); | 1007 graphicsContext.setStrokeStyle(NoStroke); |
1008 graphicsContext.setFillColor(color); | 1008 graphicsContext.setFillColor(color); |
1009 graphicsContext.drawRect(pixelSnappedIntRect(borderRect)); | 1009 graphicsContext.drawRect(pixelSnappedIntRect(borderRect)); |
1010 } | 1010 } |
1011 | 1011 |
1012 void BoxBorderPainter::drawDashedDottedBoxSideFromPath( | 1012 void BoxBorderPainter::drawDashedDottedBoxSideFromPath( |
1013 GraphicsContext& graphicsContext, | 1013 GraphicsContext& graphicsContext, |
1014 const Path& borderPath, | 1014 const LayoutRect& borderRect, |
1015 float thickness, | 1015 float thickness, |
1016 float drawThickness, | 1016 float drawThickness, |
1017 Color color, | 1017 Color color, |
1018 EBorderStyle borderStyle) const { | 1018 EBorderStyle borderStyle) const { |
| 1019 // Convert the path to be down the middle of the dots or dashes. |
| 1020 const LayoutRectOutsets centerOffsets( |
| 1021 -m_edges[BSTop].usedWidth() * 0.5, -m_edges[BSRight].usedWidth() * 0.5, |
| 1022 -m_edges[BSBottom].usedWidth() * 0.5, -m_edges[BSLeft].usedWidth() * 0.5); |
| 1023 Path centerlinePath; |
| 1024 centerlinePath.addRoundedRect(m_style.getRoundedInnerBorderFor( |
| 1025 borderRect, centerOffsets, m_includeLogicalLeftEdge, |
| 1026 m_includeLogicalRightEdge)); |
| 1027 |
1019 graphicsContext.setStrokeColor(color); | 1028 graphicsContext.setStrokeColor(color); |
1020 | 1029 |
| 1030 if (!StrokeData::strokeIsDashed(thickness, borderStyle == BorderStyleDashed |
| 1031 ? DashedStroke |
| 1032 : DottedStroke)) { |
| 1033 drawWideDottedBoxSideFromPath(graphicsContext, centerlinePath, thickness); |
| 1034 return; |
| 1035 } |
| 1036 |
1021 // The stroke is doubled here because the provided path is the | 1037 // The stroke is doubled here because the provided path is the |
1022 // outside edge of the border so half the stroke is clipped off. | 1038 // outside edge of the border so half the stroke is clipped off. |
1023 // The extra multiplier is so that the clipping mask can antialias | 1039 // The extra multiplier is so that the clipping mask can antialias |
1024 // the edges to prevent jaggies. | 1040 // the edges to prevent jaggies. |
1025 graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f); | 1041 graphicsContext.setStrokeThickness(drawThickness * 1.1f); |
1026 graphicsContext.setStrokeStyle( | 1042 graphicsContext.setStrokeStyle( |
1027 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke); | 1043 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke); |
1028 | 1044 |
1029 // If the number of dashes that fit in the path is odd and non-integral | 1045 // If the number of dashes that fit in the path is odd and non-integral |
1030 // then we will have an awkwardly-sized dash at the end of the path. To | 1046 // then we will have an awkwardly-sized dash at the end of the path. To |
1031 // try to avoid that here, we simply make the whitespace dashes ever so | 1047 // try to avoid that here, we simply make the whitespace dashes ever so |
1032 // slightly bigger. | 1048 // slightly bigger. |
1033 // TODO(schenney): This code for setting up the dash effect is trying to | 1049 // TODO(schenney): This code for setting up the dash effect is trying to |
1034 // do the same thing as StrokeData::setupPaintDashPathEffect and should be | 1050 // do the same thing as StrokeData::setupPaintDashPathEffect and should be |
1035 // refactored to re-use that code. It would require | 1051 // refactored to re-use that code. It would require |
1036 // GraphicsContext::strokePath to take a length parameter. | 1052 // GraphicsContext::strokePath to take a length parameter. |
1037 | |
1038 float dashLength = | 1053 float dashLength = |
1039 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f); | 1054 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f); |
1040 float gapLength = dashLength; | 1055 float gapLength = dashLength; |
1041 float numberOfDashes = borderPath.length() / dashLength; | 1056 float numberOfDashes = centerlinePath.length() / dashLength; |
1042 // Don't try to show dashes if we have less than 2 dashes + 2 gaps. | 1057 // Don't try to show dashes if we have less than 2 dashes + 2 gaps. |
1043 // FIXME: should do this test per side. | 1058 // FIXME: should do this test per side. |
1044 if (numberOfDashes >= 4) { | 1059 if (numberOfDashes >= 4) { |
1045 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); | 1060 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); |
1046 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); | 1061 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); |
1047 if (!evenNumberOfFullDashes && !integralNumberOfDashes) { | 1062 if (!evenNumberOfFullDashes && !integralNumberOfDashes) { |
1048 float numberOfGaps = numberOfDashes / 2; | 1063 float numberOfGaps = numberOfDashes / 2; |
1049 gapLength += (dashLength / numberOfGaps); | 1064 gapLength += (dashLength / numberOfGaps); |
1050 } | 1065 } |
1051 | 1066 |
1052 DashArray lineDash; | 1067 DashArray lineDash; |
1053 lineDash.push_back(dashLength); | 1068 lineDash.push_back(dashLength); |
1054 lineDash.push_back(gapLength); | 1069 lineDash.push_back(gapLength); |
1055 graphicsContext.setLineDash(lineDash, dashLength); | 1070 graphicsContext.setLineDash(lineDash, dashLength); |
1056 } | 1071 } |
1057 | 1072 |
1058 // FIXME: stroking the border path causes issues with tight corners: | 1073 // FIXME: stroking the border path causes issues with tight corners: |
1059 // https://bugs.webkit.org/show_bug.cgi?id=58711 | 1074 // https://bugs.webkit.org/show_bug.cgi?id=58711 |
1060 // Also, to get the best appearance we should stroke a path between the | 1075 graphicsContext.strokePath(centerlinePath); |
1061 // two borders. | 1076 } |
| 1077 |
| 1078 void BoxBorderPainter::drawWideDottedBoxSideFromPath( |
| 1079 GraphicsContext& graphicsContext, |
| 1080 const Path& borderPath, |
| 1081 float thickness) const { |
| 1082 graphicsContext.setStrokeThickness(thickness); |
| 1083 graphicsContext.setStrokeStyle(DottedStroke); |
| 1084 |
| 1085 // TODO(schenney): This code for setting up the dash effect is largely |
| 1086 // duplicated from StrokeData::setupPaintDashPathEffect and both this code |
| 1087 // and the method above should be refactored to re-use that code. It would |
| 1088 // require GraphicsContext::strokePath to take a length parameter. |
| 1089 graphicsContext.setLineCap(RoundCap); |
| 1090 |
| 1091 // Adjust the width to get equal dot spacing as much as possible. |
| 1092 float perDotLength = thickness * 2; |
| 1093 static float epsilon = 1.0e-2f; |
| 1094 float pathLength = borderPath.length(); |
| 1095 |
| 1096 if (pathLength < perDotLength + thickness) { |
| 1097 // Exactly 2 dots with whatever space we can get |
| 1098 DashArray lineDash; |
| 1099 lineDash.push_back(0); |
| 1100 lineDash.push_back(pathLength - thickness - epsilon); |
| 1101 graphicsContext.setLineDash(lineDash, 0); |
| 1102 } else { |
| 1103 // Determine what number of dots gives the minimum deviation from |
| 1104 // idealGap between dots. Set the gap to that width. |
| 1105 float minNumDots = floorf((pathLength + thickness) / perDotLength); |
| 1106 float maxNumDots = minNumDots + 1; |
| 1107 float minGap = (pathLength - minNumDots * thickness) / (minNumDots - 1); |
| 1108 float maxGap = (pathLength - maxNumDots * thickness) / (maxNumDots - 1); |
| 1109 auto gap = |
| 1110 fabs(minGap - thickness) < fabs(maxGap - thickness) ? minGap : maxGap; |
| 1111 DashArray lineDash; |
| 1112 lineDash.push_back(0); |
| 1113 lineDash.push_back(gap + thickness - epsilon); |
| 1114 graphicsContext.setLineDash(lineDash, 0); |
| 1115 } |
| 1116 |
| 1117 // TODO(schenney): stroking the border path causes issues with tight corners: |
| 1118 // https://bugs.webkit.org/show_bug.cgi?id=58711 |
1062 graphicsContext.strokePath(borderPath); | 1119 graphicsContext.strokePath(borderPath); |
1063 } | 1120 } |
1064 | 1121 |
1065 void BoxBorderPainter::drawDoubleBoxSideFromPath( | 1122 void BoxBorderPainter::drawDoubleBoxSideFromPath( |
1066 GraphicsContext& graphicsContext, | 1123 GraphicsContext& graphicsContext, |
1067 const LayoutRect& borderRect, | 1124 const LayoutRect& borderRect, |
1068 const Path& borderPath, | 1125 const Path& borderPath, |
1069 float thickness, | 1126 float thickness, |
1070 float drawThickness, | 1127 float drawThickness, |
1071 BoxSide side, | 1128 BoxSide side, |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1408 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2, | 1465 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2, |
1409 clippingQuad[2]); | 1466 clippingQuad[2]); |
1410 clippingQuad[2] -= extensionOffset; | 1467 clippingQuad[2] -= extensionOffset; |
1411 clippingQuad[3] = edgeQuad[3] - extensionOffset; | 1468 clippingQuad[3] = edgeQuad[3] - extensionOffset; |
1412 | 1469 |
1413 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter); | 1470 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter); |
1414 } | 1471 } |
1415 } | 1472 } |
1416 | 1473 |
1417 } // namespace blink | 1474 } // namespace blink |
OLD | NEW |