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

Side by Side Diff: third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp

Issue 2711983002: Paint dotted borders using circular dots (Closed)
Patch Set: More baselines Created 3 years, 9 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
OLDNEW
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
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, borderPath,
980 drawThickness, color, borderStyle); 980 thickness, drawThickness, color,
981 borderStyle);
981 return; 982 return;
982 } 983 }
983 case BorderStyleDouble: { 984 case BorderStyleDouble: {
984 drawDoubleBoxSideFromPath(graphicsContext, borderRect, borderPath, 985 drawDoubleBoxSideFromPath(graphicsContext, borderRect, borderPath,
985 thickness, drawThickness, side, color); 986 thickness, drawThickness, side, color);
986 return; 987 return;
987 } 988 }
988 case BorderStyleRidge: 989 case BorderStyleRidge:
989 case BorderStyleGroove: { 990 case BorderStyleGroove: {
990 drawRidgeGrooveBoxSideFromPath(graphicsContext, borderRect, borderPath, 991 drawRidgeGrooveBoxSideFromPath(graphicsContext, borderRect, borderPath,
(...skipping 13 matching lines...) Expand all
1004 break; 1005 break;
1005 } 1006 }
1006 1007
1007 graphicsContext.setStrokeStyle(NoStroke); 1008 graphicsContext.setStrokeStyle(NoStroke);
1008 graphicsContext.setFillColor(color); 1009 graphicsContext.setFillColor(color);
1009 graphicsContext.drawRect(pixelSnappedIntRect(borderRect)); 1010 graphicsContext.drawRect(pixelSnappedIntRect(borderRect));
1010 } 1011 }
1011 1012
1012 void BoxBorderPainter::drawDashedDottedBoxSideFromPath( 1013 void BoxBorderPainter::drawDashedDottedBoxSideFromPath(
1013 GraphicsContext& graphicsContext, 1014 GraphicsContext& graphicsContext,
1015 const LayoutRect& borderRect,
1014 const Path& borderPath, 1016 const Path& borderPath,
1015 float thickness, 1017 float thickness,
1016 float drawThickness, 1018 float drawThickness,
1017 Color color, 1019 Color color,
1018 EBorderStyle borderStyle) const { 1020 EBorderStyle borderStyle) const {
1019 graphicsContext.setStrokeColor(color); 1021 graphicsContext.setStrokeColor(color);
1020 1022
1023 if (borderStyle == BorderStyleDotted && thickness > 3) {
f(malita) 2017/03/03 15:34:08 Why is dotted predicated on thickness > 3? These
Stephen Chennney 2017/03/03 22:19:22 Done.
1024 drawWideDottedBoxSideFromPath(graphicsContext, borderRect, borderPath,
1025 thickness);
1026 return;
1027 }
1028
1021 // The stroke is doubled here because the provided path is the 1029 // The stroke is doubled here because the provided path is the
1022 // outside edge of the border so half the stroke is clipped off. 1030 // outside edge of the border so half the stroke is clipped off.
1023 // The extra multiplier is so that the clipping mask can antialias 1031 // The extra multiplier is so that the clipping mask can antialias
1024 // the edges to prevent jaggies. 1032 // the edges to prevent jaggies.
1025 graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f); 1033 graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f);
1026 graphicsContext.setStrokeStyle( 1034 graphicsContext.setStrokeStyle(
1027 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke); 1035 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke);
1028 1036
1029 // If the number of dashes that fit in the path is odd and non-integral 1037 // 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 1038 // 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 1039 // try to avoid that here, we simply make the whitespace dashes ever so
1032 // slightly bigger. 1040 // slightly bigger.
1033 // TODO(schenney): This code for setting up the dash effect is trying to 1041 // TODO(schenney): This code for setting up the dash effect is trying to
1034 // do the same thing as StrokeData::setupPaintDashPathEffect and should be 1042 // do the same thing as StrokeData::setupPaintDashPathEffect and should be
1035 // refactored to re-use that code. It would require 1043 // refactored to re-use that code. It would require
1036 // GraphicsContext::strokePath to take a length parameter. 1044 // GraphicsContext::strokePath to take a length parameter.
1037
1038 float dashLength = 1045 float dashLength =
1039 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f); 1046 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f);
1040 float gapLength = dashLength; 1047 float gapLength = dashLength;
1041 float numberOfDashes = borderPath.length() / dashLength; 1048 float numberOfDashes = borderPath.length() / dashLength;
1042 // Don't try to show dashes if we have less than 2 dashes + 2 gaps. 1049 // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
1043 // FIXME: should do this test per side. 1050 // FIXME: should do this test per side.
1044 if (numberOfDashes >= 4) { 1051 if (numberOfDashes >= 4) {
1045 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); 1052 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
1046 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); 1053 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes);
1047 if (!evenNumberOfFullDashes && !integralNumberOfDashes) { 1054 if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
1048 float numberOfGaps = numberOfDashes / 2; 1055 float numberOfGaps = numberOfDashes / 2;
1049 gapLength += (dashLength / numberOfGaps); 1056 gapLength += (dashLength / numberOfGaps);
1050 } 1057 }
1051 1058
1052 DashArray lineDash; 1059 DashArray lineDash;
1053 lineDash.push_back(dashLength); 1060 lineDash.push_back(dashLength);
1054 lineDash.push_back(gapLength); 1061 lineDash.push_back(gapLength);
1055 graphicsContext.setLineDash(lineDash, dashLength); 1062 graphicsContext.setLineDash(lineDash, dashLength);
1056 } 1063 }
1057 1064
1058 // FIXME: stroking the border path causes issues with tight corners: 1065 // FIXME: stroking the border path causes issues with tight corners:
1059 // https://bugs.webkit.org/show_bug.cgi?id=58711 1066 // https://bugs.webkit.org/show_bug.cgi?id=58711
1060 // Also, to get the best appearance we should stroke a path between the 1067 // Also, to get the best appearance we should stroke a path between the
1061 // two borders. 1068 // two borders.
1062 graphicsContext.strokePath(borderPath); 1069 graphicsContext.strokePath(borderPath);
1063 } 1070 }
1064 1071
1072 void BoxBorderPainter::drawWideDottedBoxSideFromPath(
1073 GraphicsContext& graphicsContext,
1074 const LayoutRect& borderRect,
1075 const Path& borderPath,
f(malita) 2017/03/03 15:34:08 It's kind of annoying that we don't use the provid
Stephen Chennney 2017/03/03 22:19:22 Done.
1076 float thickness) const {
1077 // Convert the path to be down the middle of the dots.
1078 const LayoutRectOutsets centerOffsets(
1079 -roundf(m_edges[BSTop].usedWidth() * 0.5),
f(malita) 2017/03/03 15:34:08 Is rounding needed here? I'm always wary of snapp
Stephen Chennney 2017/03/03 22:19:22 Not needed, probably. Have changed it and we'll se
1080 -roundf(m_edges[BSRight].usedWidth() * 0.5),
1081 -roundf(m_edges[BSBottom].usedWidth() * 0.5),
1082 -roundf(m_edges[BSLeft].usedWidth() * 0.5));
1083 FloatRoundedRect innerClip = m_style.getRoundedInnerBorderFor(
f(malita) 2017/03/03 15:34:08 Naming nit: not an inner clip. Maybe centeredBord
Stephen Chennney 2017/03/03 22:19:22 Inlined.
1084 borderRect, centerOffsets, m_includeLogicalLeftEdge,
1085 m_includeLogicalRightEdge);
1086 Path centerlinePath;
1087 centerlinePath.addRoundedRect(innerClip);
1088
1089 graphicsContext.setStrokeThickness(thickness);
1090 graphicsContext.setStrokeStyle(DottedStroke);
1091
1092 // TODO(schenney): This code for setting up the dash effect is largely
1093 // duplicated from StrokeData::setupPaintDashPathEffect and both this code
1094 // and the method above should be refactored to re-use that code. It would
1095 // require GraphicsContext::strokePath to take a length parameter.
1096 graphicsContext.setLineCap(RoundCap);
1097
1098 // Adjust the width to get equal dot spacing as much as possible.
1099 float perDotLength = thickness * 2;
1100 static float epsilon = 1.0e-2f;
1101 float pathLength = centerlinePath.length();
1102
1103 if (pathLength < perDotLength + thickness) {
1104 // Exactly 2 dots with whatever space we can get
1105 DashArray lineDash;
1106 lineDash.push_back(0);
1107 lineDash.push_back(pathLength - thickness - epsilon);
1108 graphicsContext.setLineDash(lineDash, 0);
1109 } else {
1110 // Determine what number of dots gives the minimum deviation from
1111 // idealGap between dots. Set the gap to that width.
1112 float minNumDots = floorf((pathLength + thickness) / perDotLength);
1113 float maxNumDots = minNumDots + 1;
1114 float minGap = (pathLength - minNumDots * thickness) / (minNumDots - 1);
1115 float maxGap = (pathLength - maxNumDots * thickness) / (maxNumDots - 1);
1116 if (fabs(minGap - thickness) < fabs(maxGap - thickness)) {
1117 DashArray lineDash;
1118 lineDash.push_back(0);
1119 lineDash.push_back(minGap + thickness - epsilon);
1120 graphicsContext.setLineDash(lineDash, 0);
1121 } else {
1122 DashArray lineDash;
1123 lineDash.push_back(0);
1124 lineDash.push_back(maxGap + thickness - epsilon);
1125 graphicsContext.setLineDash(lineDash, 0);
1126 }
f(malita) 2017/03/03 15:34:08 nit: these two branches are mostly the same; maybe
Stephen Chennney 2017/03/03 22:19:22 Done.
1127 }
1128
1129 // TODO(schenney): stroking the border path causes issues with tight corners:
1130 // https://bugs.webkit.org/show_bug.cgi?id=58711
1131 graphicsContext.strokePath(centerlinePath);
1132 }
1133
1065 void BoxBorderPainter::drawDoubleBoxSideFromPath( 1134 void BoxBorderPainter::drawDoubleBoxSideFromPath(
1066 GraphicsContext& graphicsContext, 1135 GraphicsContext& graphicsContext,
1067 const LayoutRect& borderRect, 1136 const LayoutRect& borderRect,
1068 const Path& borderPath, 1137 const Path& borderPath,
1069 float thickness, 1138 float thickness,
1070 float drawThickness, 1139 float drawThickness,
1071 BoxSide side, 1140 BoxSide side,
1072 Color color) const { 1141 Color color) const {
1073 // Draw inner border line 1142 // Draw inner border line
1074 { 1143 {
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
1408 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2, 1477 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2,
1409 clippingQuad[2]); 1478 clippingQuad[2]);
1410 clippingQuad[2] -= extensionOffset; 1479 clippingQuad[2] -= extensionOffset;
1411 clippingQuad[3] = edgeQuad[3] - extensionOffset; 1480 clippingQuad[3] = edgeQuad[3] - extensionOffset;
1412 1481
1413 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter); 1482 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter);
1414 } 1483 }
1415 } 1484 }
1416 1485
1417 } // namespace blink 1486 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698