Use a smaller tolerance when chopping conics to quads

In most places we were using 0.25 (maximum distance between the actual
and approximated curves). In these few places, we were using 0.5, which
is enough to produce visible errors.

Added a GM that demonstrated the problem as reported - many of the arcs
with radius ~8 were previously closer to round-rects than circles.

Bug: chromium:888453
Change-Id: I7d22e27773f56174861526dd0223f52a93bf48eb
Reviewed-on: https://skia-review.googlesource.com/c/172060
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Brian Osman 2018-11-20 11:10:15 -05:00 committed by Skia Commit-Bot
parent 343063f338
commit e3deee1319
5 changed files with 24 additions and 4 deletions

View File

@ -233,3 +233,23 @@ DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) {
SkRect kRect = { 60, 0, 100, 40};
canvas->drawArc(kRect, 45, 90, true, p0);
}
DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) {
// Two GPU path renderers were using a too-large tolerance when chopping connics to quads.
// This manifested as not-very-round circular arcs at certain radii. All the arcs being drawn
// here should look like circles.
SkPaint fill;
fill.setAntiAlias(true);
SkPaint hairline = fill;
hairline.setStyle(SkPaint::kStroke_Style);
SkPaint stroke = hairline;
stroke.setStrokeWidth(2.0f);
int x = 4;
int y0 = 25, y1 = 75, y2 = 125;
for (int r = 2; r <= 20; ++r) {
canvas->drawArc(SkRect::MakeXYWH(x - r, y0 - r, 2 * r, 2 * r), 0, 360, false, fill);
canvas->drawArc(SkRect::MakeXYWH(x - r, y1 - r, 2 * r, 2 * r), 0, 360, false, hairline);
canvas->drawArc(SkRect::MakeXYWH(x - r, y2 - r, 2 * r, 2 * r), 0, 360, false, stroke);
x += 2 * r + 4;
}
}

View File

@ -316,7 +316,7 @@ static bool get_segments(const SkPath& path,
m.mapPoints(pts, 3);
SkScalar weight = iter.conicWeight();
SkAutoConicToQuads converter;
const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.5f);
const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
for (int i = 0; i < converter.countQuads(); ++i) {
update_degenerate_test(&degenerateData, quadPts[2*i + 1]);
update_degenerate_test(&degenerateData, quadPts[2*i + 2]);

View File

@ -24,7 +24,7 @@ static const SkScalar kCloseSqd = kClose * kClose;
// tesselation tolerance values, in device space pixels
static const SkScalar kQuadTolerance = 0.2f;
static const SkScalar kCubicTolerance = 0.2f;
static const SkScalar kConicTolerance = 0.5f;
static const SkScalar kConicTolerance = 0.25f;
// dot product below which we use a round cap between curve segments
static const SkScalar kRoundCapThreshold = 0.8f;

View File

@ -318,7 +318,7 @@ static int gather_lines_and_quads(const SkPath& path,
if (convertConicsToQuads) {
SkScalar weight = iter.conicWeight();
SkAutoConicToQuads converter;
const SkPoint* quadPts = converter.computeQuads(pathPts, weight, 0.5f);
const SkPoint* quadPts = converter.computeQuads(pathPts, weight, 0.25f);
for (int i = 0; i < converter.countQuads(); ++i) {
addSrcChoppedQuad(quadPts + 2 * i, !verbsInContour && 0 == i);
}

View File

@ -725,7 +725,7 @@ void SkBaseShadowTessellator::stitchConcaveRings(const SkTDArray<SkPoint>& umbra
static const SkScalar kQuadTolerance = 0.2f;
static const SkScalar kCubicTolerance = 0.2f;
#endif
static const SkScalar kConicTolerance = 0.5f;
static const SkScalar kConicTolerance = 0.25f;
// clamps the point to the nearest 16th of a pixel
static void sanitize_point(const SkPoint& in, SkPoint* out) {