Revert "Revert "Fix rendering of drrects with small circular inner rrects.""

This reverts commit ec727c981d.

Change-Id: Id3164619016d58b2bcc0b8af606215653f553fce
Reviewed-on: https://skia-review.googlesource.com/79422
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2017-12-01 16:01:47 -05:00 committed by Skia Commit-Bot
parent 80654c16bd
commit 6574921253
6 changed files with 90 additions and 3 deletions

42
gm/drrect_small_inner.cpp Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkRRect.h"
#include "gm.h"
DEF_SIMPLE_GM(drrect_small_inner, canvas, 170, 610) {
SkPaint paint;
paint.setAntiAlias(true);
static constexpr SkScalar kOuterRadius = 35.f;
auto outer = SkRRect::MakeOval(SkRect::MakeXYWH(0, 0, 2 * kOuterRadius, 2 * kOuterRadius));
canvas->translate(10.f, 10.f);
canvas->save();
for (bool offcenter : {false, true}) {
for (bool oval : {false, true}) {
for (SkScalar innerRadiusX : {1.f, 0.5f, 0.1f, .01f}) {
SkScalar innerRadiusY = innerRadiusX;
if (oval) {
innerRadiusY *= 0.95f;
}
SkScalar tx = kOuterRadius - innerRadiusX;
SkScalar ty = kOuterRadius - innerRadiusY;
if (offcenter) {
tx += 1.f;
}
auto inner = SkRRect::MakeOval(
SkRect::MakeXYWH(tx, ty, 2 * innerRadiusX, 2 * innerRadiusY));
canvas->drawDRRect(outer, inner, paint);
canvas->translate(0, 2 * kOuterRadius + 5);
}
}
canvas->restore();
canvas->translate(2 * kOuterRadius + 2, 0);
}
canvas->restore();
}

View File

@ -118,6 +118,7 @@ gm_sources = [
"$_gm/drawregionmodes.cpp",
"$_gm/dropshadowimagefilter.cpp",
"$_gm/drrect.cpp",
"$_gm/drrect_small_inner.cpp",
"$_gm/dstreadshuffle.cpp",
"$_gm/emboss.cpp",
"$_gm/emptypath.cpp",

View File

@ -1224,6 +1224,28 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
}
}
SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
if (aa == GrAA::kYes && inner->isCircle() && outer->isCircle()) {
auto outerR = outer->width() / 2.f;
auto innerR = inner->width() / 2.f;
auto cx = outer->getBounds().fLeft + outerR;
auto cy = outer->getBounds().fTop + outerR;
if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
auto avgR = (innerR + outerR) / 2.f;
auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
stroke.setStrokeStyle(outerR - innerR);
auto op = GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, circleBounds,
stroke, this->caps()->shaderCaps());
if (op) {
this->addDrawOp(clip, std::move(op));
return true;
}
}
}
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
GrClipEdgeType innerEdgeType, outerEdgeType;
@ -1235,7 +1257,6 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
outerEdgeType = GrClipEdgeType::kFillBW;
}
SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
SkMatrix inverseVM;
if (!viewMatrix.isIdentity()) {
if (!origInner.transform(viewMatrix, inner.writable())) {

View File

@ -66,6 +66,9 @@ private:
SkScalar effectiveRadius = radius;
if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType)edgeType)) {
effectiveRadius -= 0.5f;
// When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the
// shader.
effectiveRadius = SkTMax(0.001f, effectiveRadius);
} else {
effectiveRadius += 0.5f;
}
@ -108,7 +111,7 @@ std::unique_ptr<GrFragmentProcessor> GrCircleEffect::TestCreate(GrProcessorTestD
SkPoint center;
center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
SkScalar radius = testData->fRandom->nextRangeF(0.f, 1000.f);
SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f);
GrClipEdgeType et;
do {
et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);

View File

@ -15,6 +15,18 @@ half prevRadius = -1;
// fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
uniform half4 circle;
@make {
static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center,
float radius) {
// A radius below half causes the implicit insetting done by this processor to become
// inverted. We could handle this case by making the processor code more complicated.
if (radius < .5f) {
return nullptr;
}
return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius));
}
}
@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag }
@setData(pdman) {
@ -22,6 +34,8 @@ uniform half4 circle;
SkScalar effectiveRadius = radius;
if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType) edgeType)) {
effectiveRadius -= 0.5f;
// When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
effectiveRadius = SkTMax(0.001f, effectiveRadius);
} else {
effectiveRadius += 0.5f;
}
@ -58,7 +72,7 @@ void main() {
SkPoint center;
center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
SkScalar radius = testData->fRandom->nextRangeF(0.f, 1000.f);
SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f);
GrClipEdgeType et;
do {
et = (GrClipEdgeType) testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);

View File

@ -19,8 +19,14 @@ public:
GrClipEdgeType edgeType() const { return fEdgeType; }
SkPoint center() const { return fCenter; }
float radius() const { return fRadius; }
static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center,
float radius) {
// A radius below half causes the implicit insetting done by this processor to become
// inverted. We could handle this case by making the processor code more complicated.
if (radius < .5f) {
return nullptr;
}
return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius));
}
GrCircleEffect(const GrCircleEffect& src);