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

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

Issue 2737063002: Improve dashed line drawing (Closed)
Patch Set: More expectations. Flaky? 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 1016 matching lines...) Expand 10 before | Expand all | Expand 10 after
1027 1027
1028 graphicsContext.setStrokeColor(color); 1028 graphicsContext.setStrokeColor(color);
1029 1029
1030 if (!StrokeData::strokeIsDashed(thickness, borderStyle == BorderStyleDashed 1030 if (!StrokeData::strokeIsDashed(thickness, borderStyle == BorderStyleDashed
1031 ? DashedStroke 1031 ? DashedStroke
1032 : DottedStroke)) { 1032 : DottedStroke)) {
1033 drawWideDottedBoxSideFromPath(graphicsContext, centerlinePath, thickness); 1033 drawWideDottedBoxSideFromPath(graphicsContext, centerlinePath, thickness);
1034 return; 1034 return;
1035 } 1035 }
1036 1036
1037 // The stroke is doubled here because the provided path is the
1038 // outside edge of the border so half the stroke is clipped off.
1039 // The extra multiplier is so that the clipping mask can antialias 1037 // The extra multiplier is so that the clipping mask can antialias
1040 // the edges to prevent jaggies. 1038 // the edges to prevent jaggies.
1041 graphicsContext.setStrokeThickness(drawThickness * 1.1f); 1039 graphicsContext.setStrokeThickness(drawThickness * 1.1f);
1042 graphicsContext.setStrokeStyle( 1040 graphicsContext.setStrokeStyle(
1043 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke); 1041 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke);
1044 1042
1045 // If the number of dashes that fit in the path is odd and non-integral
1046 // then we will have an awkwardly-sized dash at the end of the path. To
1047 // try to avoid that here, we simply make the whitespace dashes ever so
1048 // slightly bigger.
1049 // TODO(schenney): This code for setting up the dash effect is trying to 1043 // TODO(schenney): This code for setting up the dash effect is trying to
1050 // do the same thing as StrokeData::setupPaintDashPathEffect and should be 1044 // do the same thing as StrokeData::setupPaintDashPathEffect and should be
1051 // refactored to re-use that code. It would require 1045 // refactored to re-use that code. It would require
1052 // GraphicsContext::strokePath to take a length parameter. 1046 // GraphicsContext::strokePath to take a length parameter.
1053 float dashLength = 1047 float dashLength = drawThickness;
1054 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f);
1055 float gapLength = dashLength; 1048 float gapLength = dashLength;
1056 float numberOfDashes = centerlinePath.length() / dashLength; 1049 if (borderStyle == BorderStyleDashed) {
1050 dashLength *= StrokeData::dashLengthRatio(drawThickness);
1051 gapLength *= StrokeData::dashGapRatio(drawThickness);
1052 }
1053 float pathLength = centerlinePath.length();
1057 // Don't try to show dashes if we have less than 2 dashes + 2 gaps. 1054 // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
1058 // FIXME: should do this test per side. 1055 // TODO(schenney): should do this test per side.
1059 if (numberOfDashes >= 4) { 1056 if (pathLength >= 2 * dashLength + gapLength) {
1060 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); 1057 float gap = gapLength;
1061 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); 1058 if (borderStyle == BorderStyleDashed)
1062 if (!evenNumberOfFullDashes && !integralNumberOfDashes) { 1059 gap = StrokeData::selectBestDashGap(pathLength, dashLength, gapLength);
1063 float numberOfGaps = numberOfDashes / 2;
1064 gapLength += (dashLength / numberOfGaps);
1065 }
1066
1067 DashArray lineDash; 1060 DashArray lineDash;
1068 lineDash.push_back(dashLength); 1061 lineDash.push_back(dashLength);
1069 lineDash.push_back(gapLength); 1062 lineDash.push_back(gap);
1070 graphicsContext.setLineDash(lineDash, dashLength); 1063 graphicsContext.setLineDash(lineDash, dashLength);
1071 } 1064 } else if (pathLength > dashLength) {
1065 // Exactly 2 dashes proportionally sized
1066 float multiplier = pathLength / (2 * dashLength + gapLength);
1067 DashArray lineDash;
1068 lineDash.push_back(dashLength * multiplier);
1069 lineDash.push_back(gapLength * multiplier);
1070 graphicsContext.setLineDash(lineDash, 0);
1071 } // else don't dash at all
1072 1072
1073 // FIXME: stroking the border path causes issues with tight corners: 1073 // TODO(schenney): stroking the border path causes issues with tight corners:
1074 // https://bugs.webkit.org/show_bug.cgi?id=58711 1074 // https://bugs.chromium.org/p/chromium/issues/detail?id=344234
1075 graphicsContext.strokePath(centerlinePath); 1075 graphicsContext.strokePath(centerlinePath);
1076 } 1076 }
1077 1077
1078 void BoxBorderPainter::drawWideDottedBoxSideFromPath( 1078 void BoxBorderPainter::drawWideDottedBoxSideFromPath(
1079 GraphicsContext& graphicsContext, 1079 GraphicsContext& graphicsContext,
1080 const Path& borderPath, 1080 const Path& borderPath,
1081 float thickness) const { 1081 float thickness) const {
1082 graphicsContext.setStrokeThickness(thickness); 1082 graphicsContext.setStrokeThickness(thickness);
1083 graphicsContext.setStrokeStyle(DottedStroke); 1083 graphicsContext.setStrokeStyle(DottedStroke);
1084 1084
1085 // TODO(schenney): This code for setting up the dash effect is largely 1085 // TODO(schenney): This code for setting up the dash effect is largely
1086 // duplicated from StrokeData::setupPaintDashPathEffect and both this code 1086 // duplicated from StrokeData::setupPaintDashPathEffect and both this code
1087 // and the method above should be refactored to re-use that code. It would 1087 // and the method above should be refactored to re-use that code. It would
1088 // require GraphicsContext::strokePath to take a length parameter. 1088 // require GraphicsContext::strokePath to take a length parameter.
1089 graphicsContext.setLineCap(RoundCap); 1089 graphicsContext.setLineCap(RoundCap);
1090 1090
1091 // Adjust the width to get equal dot spacing as much as possible. 1091 // Adjust the width to get equal dot spacing as much as possible.
1092 float perDotLength = thickness * 2; 1092 float perDotLength = thickness * 2;
1093 static float epsilon = 1.0e-2f;
1094 float pathLength = borderPath.length(); 1093 float pathLength = borderPath.length();
1095 1094
1096 if (pathLength < perDotLength + thickness) { 1095 if (pathLength < perDotLength) {
1097 // Exactly 2 dots with whatever space we can get 1096 // Not enoguh space for 2 dots. Just draw 1 by giving a gap that is
1097 // bigger than the length.
1098 DashArray lineDash; 1098 DashArray lineDash;
1099 lineDash.push_back(0); 1099 lineDash.push_back(0);
1100 lineDash.push_back(pathLength - thickness - epsilon); 1100 lineDash.push_back(perDotLength);
1101 graphicsContext.setLineDash(lineDash, 0); 1101 graphicsContext.setLineDash(lineDash, 0);
1102 } else { 1102 } else {
1103 // Determine what number of dots gives the minimum deviation from 1103 float gap = StrokeData::selectBestDashGap(pathLength, thickness, thickness);
1104 // idealGap between dots. Set the gap to that width. 1104 static const float epsilon = 1.0e-2f;
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; 1105 DashArray lineDash;
1112 lineDash.push_back(0); 1106 lineDash.push_back(0);
1113 lineDash.push_back(gap + thickness - epsilon); 1107 lineDash.push_back(gap + thickness - epsilon);
1114 graphicsContext.setLineDash(lineDash, 0); 1108 graphicsContext.setLineDash(lineDash, 0);
1115 } 1109 }
1116 1110
1117 // TODO(schenney): stroking the border path causes issues with tight corners: 1111 // TODO(schenney): stroking the border path causes issues with tight corners:
1118 // https://bugs.webkit.org/show_bug.cgi?id=58711 1112 // https://bugs.webkit.org/show_bug.cgi?id=58711
1119 graphicsContext.strokePath(borderPath); 1113 graphicsContext.strokePath(borderPath);
1120 } 1114 }
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
1465 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2, 1459 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2,
1466 clippingQuad[2]); 1460 clippingQuad[2]);
1467 clippingQuad[2] -= extensionOffset; 1461 clippingQuad[2] -= extensionOffset;
1468 clippingQuad[3] = edgeQuad[3] - extensionOffset; 1462 clippingQuad[3] = edgeQuad[3] - extensionOffset;
1469 1463
1470 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter); 1464 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter);
1471 } 1465 }
1472 } 1466 }
1473 1467
1474 } // namespace blink 1468 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698