Move class into impl

I think this finishes all public subclasses, so we can proceed next with
moving the virtuals themselves to a private subclass.

Change-Id: I490f3cf6497a6bdcafc1ce756cfdeb32eab18585
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/411239
Reviewed-by: Tyler Denniston <tdenniston@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2021-05-21 11:00:36 -04:00 committed by Skia Commit-Bot
parent b1e9cb08c1
commit 8f4e924181
5 changed files with 245 additions and 243 deletions

View File

@ -8,7 +8,6 @@
#ifndef SkCornerPathEffect_DEFINED
#define SkCornerPathEffect_DEFINED
#include "include/core/SkFlattenable.h"
#include "include/core/SkPathEffect.h"
/** \class SkCornerPathEffect
@ -16,34 +15,14 @@
SkCornerPathEffect is a subclass of SkPathEffect that can turn sharp corners
into various treatments (e.g. rounded corners)
*/
class SK_API SkCornerPathEffect : public SkPathEffect {
class SK_API SkCornerPathEffect {
public:
/** radius must be > 0 to have an effect. It specifies the distance from each corner
that should be "rounded".
*/
static sk_sp<SkPathEffect> Make(SkScalar radius) {
return radius > 0 ? sk_sp<SkPathEffect>(new SkCornerPathEffect(radius)) : nullptr;
}
static sk_sp<SkPathEffect> Make(SkScalar radius);
protected:
~SkCornerPathEffect() override;
explicit SkCornerPathEffect(SkScalar radius);
void flatten(SkWriteBuffer&) const override;
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
private:
SK_FLATTENABLE_HOOKS(SkCornerPathEffect)
bool computeFastBounds(SkRect*) const override {
// Rounding sharp corners within a path produces a new path that is still contained within
// the original's bounds, so leave 'bounds' unmodified.
return true;
}
SkScalar fRadius;
using INHERITED = SkPathEffect;
static void RegisterFlattenables();
};
#endif

View File

@ -8,7 +8,6 @@
#ifndef SkDiscretePathEffect_DEFINED
#define SkDiscretePathEffect_DEFINED
#include "include/core/SkFlattenable.h"
#include "include/core/SkPathEffect.h"
/** \class SkDiscretePathEffect
@ -32,24 +31,7 @@ public:
*/
static sk_sp<SkPathEffect> Make(SkScalar segLength, SkScalar dev, uint32_t seedAssist = 0);
protected:
SkDiscretePathEffect(SkScalar segLength,
SkScalar deviation,
uint32_t seedAssist);
void flatten(SkWriteBuffer&) const override;
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
private:
SK_FLATTENABLE_HOOKS(SkDiscretePathEffect)
bool computeFastBounds(SkRect* bounds) const override;
SkScalar fSegLength, fPerterb;
/* Caller-supplied 32 bit seed assist */
uint32_t fSeedAssist;
using INHERITED = SkPathEffect;
static void RegisterFlattenables();
};
#endif

View File

@ -12,15 +12,6 @@
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) {
// check with ! to catch NaNs
if (!(radius > 0)) {
radius = 0;
}
fRadius = radius;
}
SkCornerPathEffect::~SkCornerPathEffect() {}
static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
SkPoint* step) {
SkScalar dist = SkPoint::Distance(a, b);
@ -35,122 +26,152 @@ static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
}
}
bool SkCornerPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
SkStrokeRec*, const SkRect*) const {
if (fRadius <= 0) {
return false;
class SkCornerPathEffectImpl : public SkPathEffect {
public:
explicit SkCornerPathEffectImpl(SkScalar radius) : fRadius(radius) {
SkASSERT(radius > 0);
}
SkPath::Iter iter(src, false);
SkPath::Verb verb, prevVerb = SkPath::kDone_Verb;
SkPoint pts[4];
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override {
if (fRadius <= 0) {
return false;
}
bool closed;
SkPoint moveTo, lastCorner;
SkVector firstStep, step;
bool prevIsValid = true;
SkPath::Iter iter(src, false);
SkPath::Verb verb, prevVerb = SkPath::kDone_Verb;
SkPoint pts[4];
// to avoid warnings
step.set(0, 0);
moveTo.set(0, 0);
firstStep.set(0, 0);
lastCorner.set(0, 0);
bool closed;
SkPoint moveTo, lastCorner;
SkVector firstStep, step;
bool prevIsValid = true;
for (;;) {
switch (verb = iter.next(pts)) {
case SkPath::kMove_Verb:
// close out the previous (open) contour
if (SkPath::kLine_Verb == prevVerb) {
dst->lineTo(lastCorner);
// to avoid warnings
step.set(0, 0);
moveTo.set(0, 0);
firstStep.set(0, 0);
lastCorner.set(0, 0);
for (;;) {
switch (verb = iter.next(pts)) {
case SkPath::kMove_Verb:
// close out the previous (open) contour
if (SkPath::kLine_Verb == prevVerb) {
dst->lineTo(lastCorner);
}
closed = iter.isClosedContour();
if (closed) {
moveTo = pts[0];
prevIsValid = false;
} else {
dst->moveTo(pts[0]);
prevIsValid = true;
}
break;
case SkPath::kLine_Verb: {
bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
// prev corner
if (!prevIsValid) {
dst->moveTo(moveTo + step);
prevIsValid = true;
} else {
dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
pts[0].fY + step.fY);
}
if (drawSegment) {
dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
}
lastCorner = pts[1];
prevIsValid = true;
break;
}
closed = iter.isClosedContour();
if (closed) {
moveTo = pts[0];
case SkPath::kQuad_Verb:
// TBD - just replicate the curve for now
if (!prevIsValid) {
dst->moveTo(pts[0]);
prevIsValid = true;
}
dst->quadTo(pts[1], pts[2]);
lastCorner = pts[2];
firstStep.set(0, 0);
break;
case SkPath::kConic_Verb:
// TBD - just replicate the curve for now
if (!prevIsValid) {
dst->moveTo(pts[0]);
prevIsValid = true;
}
dst->conicTo(pts[1], pts[2], iter.conicWeight());
lastCorner = pts[2];
firstStep.set(0, 0);
break;
case SkPath::kCubic_Verb:
if (!prevIsValid) {
dst->moveTo(pts[0]);
prevIsValid = true;
}
// TBD - just replicate the curve for now
dst->cubicTo(pts[1], pts[2], pts[3]);
lastCorner = pts[3];
firstStep.set(0, 0);
break;
case SkPath::kClose_Verb:
if (firstStep.fX || firstStep.fY) {
dst->quadTo(lastCorner.fX, lastCorner.fY,
lastCorner.fX + firstStep.fX,
lastCorner.fY + firstStep.fY);
}
dst->close();
prevIsValid = false;
} else {
dst->moveTo(pts[0]);
prevIsValid = true;
}
break;
case SkPath::kLine_Verb: {
bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
// prev corner
if (!prevIsValid) {
dst->moveTo(moveTo + step);
prevIsValid = true;
} else {
dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
pts[0].fY + step.fY);
}
if (drawSegment) {
dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
}
lastCorner = pts[1];
prevIsValid = true;
break;
break;
case SkPath::kDone_Verb:
if (prevIsValid) {
dst->lineTo(lastCorner);
}
return true;
default:
SkDEBUGFAIL("default should not be reached");
return false;
}
case SkPath::kQuad_Verb:
// TBD - just replicate the curve for now
if (!prevIsValid) {
dst->moveTo(pts[0]);
prevIsValid = true;
}
dst->quadTo(pts[1], pts[2]);
lastCorner = pts[2];
firstStep.set(0, 0);
break;
case SkPath::kConic_Verb:
// TBD - just replicate the curve for now
if (!prevIsValid) {
dst->moveTo(pts[0]);
prevIsValid = true;
}
dst->conicTo(pts[1], pts[2], iter.conicWeight());
lastCorner = pts[2];
firstStep.set(0, 0);
break;
case SkPath::kCubic_Verb:
if (!prevIsValid) {
dst->moveTo(pts[0]);
prevIsValid = true;
}
// TBD - just replicate the curve for now
dst->cubicTo(pts[1], pts[2], pts[3]);
lastCorner = pts[3];
firstStep.set(0, 0);
break;
case SkPath::kClose_Verb:
if (firstStep.fX || firstStep.fY) {
dst->quadTo(lastCorner.fX, lastCorner.fY,
lastCorner.fX + firstStep.fX,
lastCorner.fY + firstStep.fY);
}
dst->close();
prevIsValid = false;
break;
case SkPath::kDone_Verb:
if (prevIsValid) {
dst->lineTo(lastCorner);
}
return true;
default:
SkDEBUGFAIL("default should not be reached");
return false;
}
if (SkPath::kMove_Verb == prevVerb) {
firstStep = step;
if (SkPath::kMove_Verb == prevVerb) {
firstStep = step;
}
prevVerb = verb;
}
prevVerb = verb;
return true;
}
return true;
bool computeFastBounds(SkRect*) const override {
// Rounding sharp corners within a path produces a new path that is still contained within
// the original's bounds, so leave 'bounds' unmodified.
return true;
}
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
return SkCornerPathEffect::Make(buffer.readScalar());
}
void flatten(SkWriteBuffer& buffer) const override {
buffer.writeScalar(fRadius);
}
Factory getFactory() const override { return CreateProc; }
const char* getTypeName() const override { return "SkCornerPathEffect"; }
private:
const SkScalar fRadius;
using INHERITED = SkPathEffect;
};
//////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkPathEffect> SkCornerPathEffect::Make(SkScalar radius) {
return SkScalarIsFinite(radius) && (radius > 0) ?
sk_sp<SkPathEffect>(new SkCornerPathEffectImpl(radius)) : nullptr;
}
sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
return SkCornerPathEffect::Make(buffer.readScalar());
}
void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
buffer.writeScalar(fRadius);
void SkCornerPathEffect::RegisterFlattenables() {
SkFlattenable::Register("SkCornerPathEffect", SkCornerPathEffectImpl::CreateProc);
}

View File

@ -14,31 +14,6 @@
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
sk_sp<SkPathEffect> SkDiscretePathEffect::Make(SkScalar segLength, SkScalar deviation,
uint32_t seedAssist) {
if (!SkScalarIsFinite(segLength) || !SkScalarIsFinite(deviation)) {
return nullptr;
}
if (segLength <= SK_ScalarNearlyZero) {
return nullptr;
}
return sk_sp<SkPathEffect>(new SkDiscretePathEffect(segLength, deviation, seedAssist));
}
static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
SkVector normal = tangent;
SkPointPriv::RotateCCW(&normal);
normal.setLength(scale);
*p += normal;
}
SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength,
SkScalar deviation,
uint32_t seedAssist)
: fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
{
}
/** \class LCGRandom
Utility class that implements pseudo random 32bit numbers using a fast
@ -49,7 +24,6 @@ SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength,
methods used by SkDiscretePathEffect::filterPath, with methods that were
not called directly moved to private.
*/
class LCGRandom {
public:
LCGRandom(uint32_t seed) : fSeed(seed) {}
@ -81,78 +55,124 @@ private:
uint32_t fSeed;
};
bool SkDiscretePathEffect::onFilterPath(SkPath* dst, const SkPath& src,
SkStrokeRec* rec, const SkRect*) const {
bool doFill = rec->isFillStyle();
static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
SkVector normal = tangent;
SkPointPriv::RotateCCW(&normal);
normal.setLength(scale);
*p += normal;
}
SkPathMeasure meas(src, doFill);
class SK_API SkDiscretePathEffectImpl : public SkPathEffect {
public:
SkDiscretePathEffectImpl(SkScalar segLength, SkScalar deviation, uint32_t seedAssist)
: fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
{
SkASSERT(SkScalarIsFinite(segLength));
SkASSERT(SkScalarIsFinite(deviation));
SkASSERT(segLength > SK_ScalarNearlyZero);
}
/* Caller may supply their own seed assist, which by default is 0 */
uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength());
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
const SkRect*) const override {
bool doFill = rec->isFillStyle();
LCGRandom rand(seed ^ ((seed << 16) | (seed >> 16)));
SkScalar scale = fPerterb;
SkPoint p;
SkVector v;
SkPathMeasure meas(src, doFill);
do {
SkScalar length = meas.getLength();
#if defined(SK_BUILD_FOR_FUZZER)
if (length > 1000) {
return false;
}
#endif
/* Caller may supply their own seed assist, which by default is 0 */
uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength());
if (fSegLength * (2 + doFill) > length) {
meas.getSegment(0, length, dst, true); // to short for us to mangle
} else {
int n = SkScalarRoundToInt(length / fSegLength);
constexpr int kMaxReasonableIterations = 100000;
n = std::min(n, kMaxReasonableIterations);
SkScalar delta = length / n;
SkScalar distance = 0;
LCGRandom rand(seed ^ ((seed << 16) | (seed >> 16)));
SkScalar scale = fPerterb;
SkPoint p;
SkVector v;
if (meas.isClosed()) {
n -= 1;
distance += delta/2;
do {
SkScalar length = meas.getLength();
#if defined(SK_BUILD_FOR_FUZZER)
if (length > 1000) {
return false;
}
#endif
if (fSegLength * (2 + doFill) > length) {
meas.getSegment(0, length, dst, true); // to short for us to mangle
} else {
int n = SkScalarRoundToInt(length / fSegLength);
constexpr int kMaxReasonableIterations = 100000;
n = std::min(n, kMaxReasonableIterations);
SkScalar delta = length / n;
SkScalar distance = 0;
if (meas.isClosed()) {
n -= 1;
distance += delta/2;
}
if (meas.getPosTan(distance, &p, &v)) {
Perterb(&p, v, rand.nextSScalar1() * scale);
dst->moveTo(p);
}
while (--n >= 0) {
distance += delta;
if (meas.getPosTan(distance, &p, &v)) {
Perterb(&p, v, rand.nextSScalar1() * scale);
dst->lineTo(p);
dst->moveTo(p);
}
while (--n >= 0) {
distance += delta;
if (meas.getPosTan(distance, &p, &v)) {
Perterb(&p, v, rand.nextSScalar1() * scale);
dst->lineTo(p);
}
}
if (meas.isClosed()) {
dst->close();
}
}
if (meas.isClosed()) {
dst->close();
}
}
} while (meas.nextContour());
return true;
}
bool SkDiscretePathEffect::computeFastBounds(SkRect* bounds) const {
if (bounds) {
SkScalar maxOutset = SkScalarAbs(fPerterb);
bounds->outset(maxOutset, maxOutset);
} while (meas.nextContour());
return true;
}
return true;
bool computeFastBounds(SkRect* bounds) const override {
if (bounds) {
SkScalar maxOutset = SkScalarAbs(fPerterb);
bounds->outset(maxOutset, maxOutset);
}
return true;
}
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
SkScalar segLength = buffer.readScalar();
SkScalar perterb = buffer.readScalar();
uint32_t seed = buffer.readUInt();
return SkDiscretePathEffect::Make(segLength, perterb, seed);
}
void flatten(SkWriteBuffer& buffer) const override {
buffer.writeScalar(fSegLength);
buffer.writeScalar(fPerterb);
buffer.writeUInt(fSeedAssist);
}
Factory getFactory() const override { return CreateProc; }
const char* getTypeName() const override { return "SkDiscretePathEffect"; }
private:
const SkScalar fSegLength,
fPerterb;
/* Caller-supplied 32 bit seed assist */
const uint32_t fSeedAssist;
using INHERITED = SkPathEffect;
};
//////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkPathEffect> SkDiscretePathEffect::Make(SkScalar segLength, SkScalar deviation,
uint32_t seedAssist) {
if (!SkScalarIsFinite(segLength) || !SkScalarIsFinite(deviation)) {
return nullptr;
}
if (segLength <= SK_ScalarNearlyZero) {
return nullptr;
}
return sk_sp<SkPathEffect>(new SkDiscretePathEffectImpl(segLength, deviation, seedAssist));
}
sk_sp<SkFlattenable> SkDiscretePathEffect::CreateProc(SkReadBuffer& buffer) {
SkScalar segLength = buffer.readScalar();
SkScalar perterb = buffer.readScalar();
uint32_t seed = buffer.readUInt();
return Make(segLength, perterb, seed);
}
void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const {
buffer.writeScalar(fSegLength);
buffer.writeScalar(fPerterb);
buffer.writeUInt(fSeedAssist);
void SkDiscretePathEffect::RegisterFlattenables() {
SkFlattenable::Register("SkDiscretePathEffect", SkDiscretePathEffectImpl::CreateProc);
}

View File

@ -86,9 +86,9 @@
SkShaderMaskFilter::RegisterFlattenables();
// Path effects.
SK_REGISTER_FLATTENABLE(SkCornerPathEffect);
SkCornerPathEffect::RegisterFlattenables();
SK_REGISTER_FLATTENABLE(SkDashImpl);
SK_REGISTER_FLATTENABLE(SkDiscretePathEffect);
SkDiscretePathEffect::RegisterFlattenables();
SkLine2DPathEffect::RegisterFlattenables();
SkPath2DPathEffect::RegisterFlattenables();
SK_REGISTER_FLATTENABLE(SkMatrixPE);