Expand GrStyle's interface.
Adds some basic getters on GrStyle as well as static const instances for fill and hairline. Adds the ability to apply a GrStyle to a SkPath to produce an output SkPath. Moves style key functions from GrShape to GrStyle. Also fixes some issues with SkPath creation when applying style to GrShapes. Adds tests that GrShape produces the correct SkPath when its GrStyle is applied. GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1951613002 Review-Url: https://codereview.chromium.org/1951613002
This commit is contained in:
parent
419ca64f0f
commit
fb08327e59
@ -83,80 +83,7 @@ void GrShape::writeUnstyledKey(uint32_t* key) const {
|
||||
SkASSERT(key - origKey == this->unstyledKeySize());
|
||||
}
|
||||
|
||||
int GrShape::StyleKeySize(const GrStyle& style, bool stopAfterPE) {
|
||||
GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
|
||||
int size = 0;
|
||||
if (style.isDashed()) {
|
||||
// One scalar for dash phase and one for each dash value.
|
||||
size += 1 + style.dashIntervalCnt();
|
||||
} else if (style.pathEffect()) {
|
||||
// No key for a generic path effect.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stopAfterPE) {
|
||||
return size;
|
||||
}
|
||||
|
||||
if (style.strokeRec().needToApply()) {
|
||||
// One for style/cap/join, 2 for miter and width.
|
||||
size += 3;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void GrShape::StyleKey(uint32_t* key, const GrStyle& style, bool stopAfterPE) {
|
||||
SkASSERT(key);
|
||||
SkASSERT(StyleKeySize(style, stopAfterPE) >= 0);
|
||||
GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
|
||||
|
||||
int i = 0;
|
||||
if (style.isDashed()) {
|
||||
GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t));
|
||||
SkScalar phase = style.dashPhase();
|
||||
memcpy(&key[i++], &phase, sizeof(SkScalar));
|
||||
|
||||
int32_t count = style.dashIntervalCnt();
|
||||
// Dash count should always be even.
|
||||
SkASSERT(0 == (count & 0x1));
|
||||
const SkScalar* intervals = style.dashIntervals();
|
||||
int intervalByteCnt = count * sizeof(SkScalar);
|
||||
memcpy(&key[i], intervals, intervalByteCnt);
|
||||
i += count;
|
||||
} else {
|
||||
SkASSERT(!style.pathEffect());
|
||||
}
|
||||
|
||||
if (!stopAfterPE && style.strokeRec().needToApply()) {
|
||||
enum {
|
||||
kStyleBits = 2,
|
||||
kJoinBits = 2,
|
||||
kCapBits = 32 - kStyleBits - kJoinBits,
|
||||
|
||||
kJoinShift = kStyleBits,
|
||||
kCapShift = kJoinShift + kJoinBits,
|
||||
};
|
||||
GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
|
||||
GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits));
|
||||
GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits));
|
||||
key[i++] = style.strokeRec().getStyle() |
|
||||
style.strokeRec().getJoin() << kJoinShift |
|
||||
style.strokeRec().getCap() << kCapShift;
|
||||
|
||||
SkScalar scalar;
|
||||
// Miter limit only affects miter joins
|
||||
scalar = SkPaint::kMiter_Join == style.strokeRec().getJoin()
|
||||
? style.strokeRec().getMiter()
|
||||
: -1.f;
|
||||
memcpy(&key[i++], &scalar, sizeof(scalar));
|
||||
|
||||
scalar = style.strokeRec().getWidth();
|
||||
memcpy(&key[i++], &scalar, sizeof(scalar));
|
||||
}
|
||||
SkASSERT(StyleKeySize(style, stopAfterPE) == i);
|
||||
}
|
||||
|
||||
void GrShape::setInheritedKey(const GrShape &parent, bool stopAfterPE) {
|
||||
void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply) {
|
||||
SkASSERT(!fInheritedKey.count());
|
||||
// If the output shape turns out to be simple, then we will just use its geometric key
|
||||
if (Type::kPath == fType) {
|
||||
@ -176,7 +103,7 @@ void GrShape::setInheritedKey(const GrShape &parent, bool stopAfterPE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
int styleCnt = StyleKeySize(parent.fStyle, stopAfterPE);
|
||||
int styleCnt = GrStyle::KeySize(parent.fStyle, apply);
|
||||
if (styleCnt < 0) {
|
||||
// The style doesn't allow a key, set the path to volatile so that we fail when
|
||||
// we try to get a key for the shape.
|
||||
@ -193,7 +120,7 @@ void GrShape::setInheritedKey(const GrShape &parent, bool stopAfterPE) {
|
||||
parentCnt * sizeof(uint32_t));
|
||||
}
|
||||
// Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke)
|
||||
StyleKey(fInheritedKey.get() + parentCnt, parent.fStyle, stopAfterPE);
|
||||
GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,69 +140,80 @@ GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) {
|
||||
sizeof(uint32_t) * fInheritedKey.count());
|
||||
}
|
||||
|
||||
GrShape::GrShape(const GrShape& parent, bool stopAfterPE) {
|
||||
fType = Type::kEmpty;
|
||||
GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply) {
|
||||
if (!parent.style().applies() ||
|
||||
(GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) {
|
||||
fType = Type::kEmpty;
|
||||
*this = parent;
|
||||
return;
|
||||
}
|
||||
|
||||
SkPathEffect* pe = parent.fStyle.pathEffect();
|
||||
const SkPath* inPath;
|
||||
SkStrokeRec strokeRec = parent.fStyle.strokeRec();
|
||||
bool appliedPE = false;
|
||||
SkTLazy<SkPath> tmpPath;
|
||||
const GrShape* parentForKey = &parent;
|
||||
SkTLazy<GrShape> tmpParent;
|
||||
fType = Type::kPath;
|
||||
fPath.init();
|
||||
if (pe) {
|
||||
fType = Type::kPath;
|
||||
fPath.init();
|
||||
SkPath* srcForPathEffect;
|
||||
if (parent.fType == Type::kPath) {
|
||||
inPath = parent.fPath.get();
|
||||
srcForPathEffect = parent.fPath.get();
|
||||
} else {
|
||||
inPath = fPath.get();
|
||||
parent.asPath(fPath.get());
|
||||
srcForPathEffect = tmpPath.init();
|
||||
parent.asPath(tmpPath.get());
|
||||
}
|
||||
// Should we consider bounds? Would have to include in key, but it'd be nice to know
|
||||
// if the bounds actually modified anything before including in key.
|
||||
if (!pe->filterPath(fPath.get(), *inPath, &strokeRec, nullptr)) {
|
||||
SkStrokeRec strokeRec = parent.fStyle.strokeRec();
|
||||
if (!pe->filterPath(fPath.get(), *srcForPathEffect, &strokeRec, nullptr)) {
|
||||
// Make an empty unstyled shape if filtering fails.
|
||||
fType = Type::kEmpty;
|
||||
fStyle = GrStyle();
|
||||
fPath.reset();
|
||||
return;
|
||||
}
|
||||
appliedPE = true;
|
||||
inPath = fPath.get();
|
||||
} else if (stopAfterPE || !strokeRec.needToApply()) {
|
||||
*this = parent;
|
||||
return;
|
||||
} else {
|
||||
fType = Type::kPath;
|
||||
fPath.init();
|
||||
if (parent.fType == Type::kPath) {
|
||||
inPath = parent.fPath.get();
|
||||
} else {
|
||||
inPath = fPath.get();
|
||||
parent.asPath(fPath.get());
|
||||
}
|
||||
}
|
||||
const GrShape* effectiveParent = &parent;
|
||||
SkTLazy<GrShape> tmpParent;
|
||||
if (!stopAfterPE) {
|
||||
if (appliedPE) {
|
||||
// If the intermediate shape from just the PE is not a path then we capture that here
|
||||
// so that we can pass the non-path parent to setInheritedKey.
|
||||
SkRRect rrect;
|
||||
Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rrect, nullptr, strokeRec);
|
||||
switch (parentType) {
|
||||
case Type::kEmpty:
|
||||
tmpParent.init();
|
||||
effectiveParent = tmpParent.get();
|
||||
break;
|
||||
case Type::kRRect:
|
||||
tmpParent.init(rrect, GrStyle(strokeRec, nullptr));
|
||||
effectiveParent = tmpParent.get();
|
||||
case Type::kPath:
|
||||
break;
|
||||
if (GrStyle::Apply::kPathEffectAndStrokeRec == apply) {
|
||||
if (strokeRec.needToApply()) {
|
||||
// The intermediate shape may not be a general path. If we we're just applying
|
||||
// the path effect then attemptToReduceFromPath would catch it. This means that
|
||||
// when we subsequently applied the remaining strokeRec we would have a non-path
|
||||
// parent shape that would be used to determine the the stroked path's key.
|
||||
// We detect that case here and change parentForKey to a temporary that represents
|
||||
// the simpler shape so that applying both path effect and the strokerec all at
|
||||
// once produces the same key.
|
||||
SkRRect rrect;
|
||||
Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rrect, nullptr,
|
||||
strokeRec);
|
||||
switch (parentType) {
|
||||
case Type::kEmpty:
|
||||
tmpParent.init();
|
||||
parentForKey = tmpParent.get();
|
||||
break;
|
||||
case Type::kRRect:
|
||||
tmpParent.init(rrect, GrStyle(strokeRec, nullptr));
|
||||
parentForKey = tmpParent.get();
|
||||
case Type::kPath:
|
||||
break;
|
||||
}
|
||||
SkAssertResult(strokeRec.applyToPath(fPath.get(), *fPath.get()));
|
||||
} else {
|
||||
fStyle = GrStyle(strokeRec, nullptr);
|
||||
}
|
||||
} else {
|
||||
fStyle = GrStyle(strokeRec, nullptr);
|
||||
}
|
||||
strokeRec.applyToPath(fPath.get(), *inPath);
|
||||
} else {
|
||||
fStyle = GrStyle(strokeRec, nullptr);
|
||||
const SkPath* srcForStrokeRec;
|
||||
if (parent.fType == Type::kPath) {
|
||||
srcForStrokeRec = parent.fPath.get();
|
||||
} else {
|
||||
srcForStrokeRec = tmpPath.init();
|
||||
parent.asPath(tmpPath.get());
|
||||
}
|
||||
SkASSERT(parent.fStyle.strokeRec().needToApply());
|
||||
SkAssertResult(parent.fStyle.strokeRec().applyToPath(fPath.get(), *srcForStrokeRec));
|
||||
fStyle.resetToInitStyle(SkStrokeRec::kFill_InitStyle);
|
||||
}
|
||||
this->attemptToReduceFromPath();
|
||||
this->setInheritedKey(*effectiveParent, stopAfterPE);
|
||||
this->setInheritedKey(*parentForKey, apply);
|
||||
}
|
||||
|
@ -106,19 +106,7 @@ public:
|
||||
|
||||
const GrStyle& style() const { return fStyle; }
|
||||
|
||||
/**
|
||||
* Returns a GrShape where the shape's geometry fully reflects the original shape's GrStyle.
|
||||
* The GrStyle of the returned shape will either be fill or hairline.
|
||||
*/
|
||||
GrShape applyFullStyle() { return GrShape(*this, false); }
|
||||
|
||||
/**
|
||||
* Similar to above but applies only the path effect. Path effects take the original geometry
|
||||
* and fill/stroking information and compute a new geometry and residual fill/stroking
|
||||
* information to be applied. The path effect's output geometry and stroking will be captured
|
||||
* in the returned GrShape.
|
||||
*/
|
||||
GrShape applyPathEffect() { return GrShape(*this, true); }
|
||||
GrShape applyStyle(GrStyle::Apply apply) { return GrShape(*this, apply); }
|
||||
|
||||
bool asRRect(SkRRect* rrect) const {
|
||||
if (Type::kRRect != fType) {
|
||||
@ -165,29 +153,15 @@ private:
|
||||
kPath,
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the key length for a GrStyle. The return will be negative if it cannot be turned
|
||||
* into a key.
|
||||
*/
|
||||
static int StyleKeySize(const GrStyle& , bool stopAfterPE);
|
||||
|
||||
/**
|
||||
* Writes a unique key for the style into the provided buffer. This function assumes the buffer
|
||||
* has room for at least StyleKeySize() values. It assumes that StyleKeySize() returns a
|
||||
* positive value for the style and stopAfterPE param. This is written so that the key for just
|
||||
* dash application followed by the key for the remaining SkStrokeRec is the same as the
|
||||
* key for applying dashing and SkStrokeRec all at once.
|
||||
*/
|
||||
static void StyleKey(uint32_t*, const GrStyle&, bool stopAfterPE);
|
||||
|
||||
/** Constructor used by Apply* functions */
|
||||
GrShape(const GrShape& parentShape, bool stopAfterPE);
|
||||
GrShape(const GrShape& parentShape, GrStyle::Apply);
|
||||
|
||||
/**
|
||||
* Determines the key we should inherit from the input shape's geometry and style when
|
||||
* we are applying the style to create a new shape.
|
||||
*/
|
||||
void setInheritedKey(const GrShape& parentShape, bool stopAfterPE);
|
||||
void setInheritedKey(const GrShape& parentShape, GrStyle::Apply);
|
||||
|
||||
void attemptToReduceFromPath() {
|
||||
SkASSERT(Type::kPath == fType);
|
||||
|
@ -7,27 +7,142 @@
|
||||
|
||||
#include "GrStyle.h"
|
||||
|
||||
int GrStyle::KeySize(const GrStyle &style, Apply apply) {
|
||||
GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
|
||||
int size = 0;
|
||||
if (style.isDashed()) {
|
||||
// One scalar for dash phase and one for each dash value.
|
||||
size += 1 + style.dashIntervalCnt();
|
||||
} else if (style.pathEffect()) {
|
||||
// No key for a generic path effect.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Apply::kPathEffectOnly == apply) {
|
||||
return size;
|
||||
}
|
||||
|
||||
if (style.strokeRec().needToApply()) {
|
||||
// One for style/cap/join, 2 for miter and width.
|
||||
size += 3;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply) {
|
||||
SkASSERT(key);
|
||||
SkASSERT(KeySize(style, apply) >= 0);
|
||||
GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
|
||||
|
||||
int i = 0;
|
||||
if (style.isDashed()) {
|
||||
GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t));
|
||||
SkScalar phase = style.dashPhase();
|
||||
memcpy(&key[i++], &phase, sizeof(SkScalar));
|
||||
|
||||
int32_t count = style.dashIntervalCnt();
|
||||
// Dash count should always be even.
|
||||
SkASSERT(0 == (count & 0x1));
|
||||
const SkScalar *intervals = style.dashIntervals();
|
||||
int intervalByteCnt = count * sizeof(SkScalar);
|
||||
memcpy(&key[i], intervals, intervalByteCnt);
|
||||
i += count;
|
||||
} else {
|
||||
SkASSERT(!style.pathEffect());
|
||||
}
|
||||
|
||||
if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) {
|
||||
enum {
|
||||
kStyleBits = 2,
|
||||
kJoinBits = 2,
|
||||
kCapBits = 32 - kStyleBits - kJoinBits,
|
||||
|
||||
kJoinShift = kStyleBits,
|
||||
kCapShift = kJoinShift + kJoinBits,
|
||||
};
|
||||
GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
|
||||
GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits));
|
||||
GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits));
|
||||
key[i++] = style.strokeRec().getStyle() |
|
||||
style.strokeRec().getJoin() << kJoinShift |
|
||||
style.strokeRec().getCap() << kCapShift;
|
||||
|
||||
SkScalar scalar;
|
||||
// Miter limit only affects miter joins
|
||||
scalar = SkPaint::kMiter_Join == style.strokeRec().getJoin()
|
||||
? style.strokeRec().getMiter()
|
||||
: -1.f;
|
||||
memcpy(&key[i++], &scalar, sizeof(scalar));
|
||||
|
||||
scalar = style.strokeRec().getWidth();
|
||||
memcpy(&key[i++], &scalar, sizeof(scalar));
|
||||
}
|
||||
SkASSERT(KeySize(style, apply) == i);
|
||||
}
|
||||
|
||||
void GrStyle::initPathEffect(SkPathEffect* pe) {
|
||||
SkASSERT(!fPathEffect)
|
||||
SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType);
|
||||
SkASSERT(0 == fDashInfo.fIntervals.count());
|
||||
if (!pe) {
|
||||
fDashInfo.fType = SkPathEffect::kNone_DashType;
|
||||
return;
|
||||
}
|
||||
SkPathEffect::DashInfo info;
|
||||
if (SkPathEffect::kDash_DashType == pe->asADash(&info)) {
|
||||
if (fStrokeRec.getStyle() == SkStrokeRec::kFill_Style) {
|
||||
fPathEffect.reset(nullptr);
|
||||
} else {
|
||||
fPathEffect.reset(SkSafeRef(pe));
|
||||
if (fStrokeRec.getStyle() != SkStrokeRec::kFill_Style) {
|
||||
fDashInfo.fType = SkPathEffect::kDash_DashType;
|
||||
fDashInfo.fIntervals.reset(info.fCount);
|
||||
fDashInfo.fPhase = info.fPhase;
|
||||
info.fIntervals = fDashInfo.fIntervals.get();
|
||||
pe->asADash(&info);
|
||||
return;
|
||||
fPathEffect.reset(SkSafeRef(pe));
|
||||
}
|
||||
} else {
|
||||
fPathEffect.reset(SkSafeRef(pe));
|
||||
}
|
||||
fDashInfo.fType = SkPathEffect::kNone_DashType;
|
||||
fDashInfo.fIntervals.reset(0);
|
||||
}
|
||||
|
||||
static inline bool apply_path_effect(SkPath* dst, SkStrokeRec* strokeRec,
|
||||
const sk_sp<SkPathEffect>& pe, const SkPath& src) {
|
||||
if (!pe) {
|
||||
return false;
|
||||
}
|
||||
if (!pe->filterPath(dst, src, strokeRec, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
dst->setIsVolatile(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke,
|
||||
const SkPath &src) const {
|
||||
SkASSERT(dst);
|
||||
SkStrokeRec strokeRec = fStrokeRec;
|
||||
if (!apply_path_effect(dst, &strokeRec, fPathEffect, src)) {
|
||||
return false;
|
||||
}
|
||||
*remainingStroke = strokeRec;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src) const {
|
||||
SkASSERT(style);
|
||||
SkASSERT(dst);
|
||||
SkStrokeRec strokeRec = fStrokeRec;
|
||||
if (!apply_path_effect(dst, &strokeRec, fPathEffect, src)) {
|
||||
return false;
|
||||
}
|
||||
if (strokeRec.needToApply()) {
|
||||
if (!strokeRec.applyToPath(dst, *dst)) {
|
||||
return false;
|
||||
}
|
||||
*style = SkStrokeRec::kFill_InitStyle;
|
||||
} else {
|
||||
SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() ||
|
||||
SkStrokeRec::kHairline_Style == strokeRec.getStyle());
|
||||
*style = strokeRec.getStyle() == SkStrokeRec::kFill_Style
|
||||
? SkStrokeRec::kFill_InitStyle
|
||||
: SkStrokeRec::kHairline_InitStyle;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -25,18 +25,56 @@
|
||||
*/
|
||||
class GrStyle {
|
||||
public:
|
||||
GrStyle() : fStrokeRec(SkStrokeRec::kFill_InitStyle) {
|
||||
fDashInfo.fType = SkPathEffect::kNone_DashType;
|
||||
/**
|
||||
* A style object that represents a fill with no path effect.
|
||||
* TODO: constexpr with C++14
|
||||
*/
|
||||
static const GrStyle& SimpleFill() {
|
||||
static const GrStyle kFill(SkStrokeRec::kFill_InitStyle);
|
||||
return kFill;
|
||||
}
|
||||
|
||||
/**
|
||||
* A style object that represents a hairline stroke with no path effect.
|
||||
* TODO: constexpr with C++14
|
||||
*/
|
||||
static const GrStyle& SimpleHairline() {
|
||||
static const GrStyle kHairline(SkStrokeRec::kHairline_InitStyle);
|
||||
return kHairline;
|
||||
}
|
||||
|
||||
enum class Apply {
|
||||
kPathEffectOnly,
|
||||
kPathEffectAndStrokeRec
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the key length for a GrStyle. The return will be negative if it cannot be turned
|
||||
* into a key. This occurs when there is a path effect that is not a dash. The key can
|
||||
* either reflect just the path effect (if one) or the path effect and the strokerec. Note
|
||||
* that a simple fill has a zero sized key.
|
||||
*/
|
||||
static int KeySize(const GrStyle& , Apply);
|
||||
|
||||
/**
|
||||
* Writes a unique key for the style into the provided buffer. This function assumes the buffer
|
||||
* has room for at least KeySize() values. It assumes that KeySize() returns a non-negative
|
||||
* value for the style and Apply param. This is written so that the key for just dash
|
||||
* application followed by the key for the remaining SkStrokeRec is the same as the key for
|
||||
* applying dashing and SkStrokeRec all at once.
|
||||
*/
|
||||
static void WriteKey(uint32_t*, const GrStyle&, Apply);
|
||||
|
||||
GrStyle() : GrStyle(SkStrokeRec::kFill_InitStyle) {}
|
||||
|
||||
explicit GrStyle(SkStrokeRec::InitStyle initStyle) : fStrokeRec(initStyle) {}
|
||||
|
||||
GrStyle(const SkStrokeRec& strokeRec, SkPathEffect* pe) : fStrokeRec(strokeRec) {
|
||||
SkASSERT(SkStrokeRec::kStrokeAndFill_Style != strokeRec.getStyle());
|
||||
this->initPathEffect(pe);
|
||||
}
|
||||
|
||||
GrStyle(const GrStyle& that) : fStrokeRec(SkStrokeRec::kFill_InitStyle) {
|
||||
*this = that;
|
||||
}
|
||||
GrStyle(const GrStyle& that) : fStrokeRec(SkStrokeRec::kFill_InitStyle) { *this = that; }
|
||||
|
||||
explicit GrStyle(const SkPaint& paint) : fStrokeRec(paint) {
|
||||
SkASSERT(SkStrokeRec::kStrokeAndFill_Style != fStrokeRec.getStyle());
|
||||
@ -49,8 +87,27 @@ public:
|
||||
fStrokeRec = that.fStrokeRec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void resetToInitStyle(SkStrokeRec::InitStyle fillOrHairline) {
|
||||
fDashInfo.reset();
|
||||
fPathEffect.reset(nullptr);
|
||||
if (SkStrokeRec::kFill_InitStyle == fillOrHairline) {
|
||||
fStrokeRec.setFillStyle();
|
||||
} else {
|
||||
fStrokeRec.setHairlineStyle();
|
||||
}
|
||||
}
|
||||
|
||||
/** Is this style a fill with no path effect? */
|
||||
bool isSimpleFill() const { return fStrokeRec.isFillStyle() && !fPathEffect; }
|
||||
|
||||
/** Is this style a hairline with no path effect? */
|
||||
bool isSimpleHairline() const { return fStrokeRec.isHairlineStyle() && !fPathEffect; }
|
||||
|
||||
SkPathEffect* pathEffect() const { return fPathEffect.get(); }
|
||||
|
||||
bool hasNonDashPathEffect() const { return fPathEffect.get() && !this->isDashed(); }
|
||||
|
||||
bool isDashed() const { return SkPathEffect::kDash_DashType == fDashInfo.fType; }
|
||||
SkScalar dashPhase() const {
|
||||
SkASSERT(this->isDashed());
|
||||
@ -67,10 +124,37 @@ public:
|
||||
|
||||
const SkStrokeRec& strokeRec() const { return fStrokeRec; }
|
||||
|
||||
/** Hairline or fill styles without path effects make no alterations to a geometry. */
|
||||
bool applies() const {
|
||||
return this->pathEffect() || (!fStrokeRec.isFillStyle() && !fStrokeRec.isHairlineStyle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies just the path effect and returns remaining stroke information. This will fail if
|
||||
* there is no path effect.
|
||||
*/
|
||||
bool applyPathEffectToPath(SkPath* dst, SkStrokeRec* remainingStoke, const SkPath& src) const;
|
||||
|
||||
/** If this succeeds then the result path should be filled or hairlined as indicated by the
|
||||
returned SkStrokeRec::InitStyle value. Will fail if there is no path effect and the
|
||||
strokerec doesn't change the geometry. */
|
||||
bool applyToPath(SkPath* dst, SkStrokeRec::InitStyle* fillOrHairline, const SkPath& src) const;
|
||||
|
||||
/** Given bounds of a path compute the bounds of path with the style applied. */
|
||||
void adjustBounds(SkRect* dst, const SkRect& src) const {
|
||||
if (this->pathEffect()) {
|
||||
this->pathEffect()->computeFastBounds(dst, src);
|
||||
} else {
|
||||
SkScalar radius = fStrokeRec.getInflationRadius();
|
||||
*dst = src.makeOutset(radius, radius);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void initPathEffect(SkPathEffect* pe);
|
||||
|
||||
struct DashInfo {
|
||||
DashInfo() : fType(SkPathEffect::kNone_DashType) {}
|
||||
DashInfo& operator=(const DashInfo& that) {
|
||||
fType = that.fType;
|
||||
fPhase = that.fPhase;
|
||||
@ -79,6 +163,10 @@ private:
|
||||
sizeof(SkScalar) * that.fIntervals.count());
|
||||
return *this;
|
||||
}
|
||||
void reset() {
|
||||
fType = SkPathEffect::kNone_DashType;
|
||||
fIntervals.reset(0);
|
||||
}
|
||||
SkPathEffect::DashType fType;
|
||||
SkScalar fPhase;
|
||||
SkAutoSTArray<4, SkScalar> fIntervals;
|
||||
|
@ -32,8 +32,8 @@ namespace {
|
||||
class TestCase {
|
||||
public:
|
||||
template <typename GEO>
|
||||
TestCase(const GEO& geo, const SkPaint& paint) : fBase(geo, paint) {
|
||||
this->init();
|
||||
TestCase(const GEO& geo, const SkPaint& paint, skiatest::Reporter* r) : fBase(geo, paint) {
|
||||
this->init(r);
|
||||
}
|
||||
|
||||
struct SelfExpectations {
|
||||
@ -64,15 +64,50 @@ public:
|
||||
const Key& appliedPathEffectThenStrokeKey() const { return fAppliedPEThenStrokeKey; }
|
||||
|
||||
private:
|
||||
void init() {
|
||||
fAppliedPE = fBase.applyPathEffect();
|
||||
fAppliedPEThenStroke = fAppliedPE.applyFullStyle();
|
||||
fAppliedFull = fBase.applyFullStyle();
|
||||
void init(skiatest::Reporter* r) {
|
||||
fAppliedPE = fBase.applyStyle(GrStyle::Apply::kPathEffectOnly);
|
||||
fAppliedPEThenStroke = fAppliedPE.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||
fAppliedFull = fBase.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||
|
||||
make_key(&fBaseKey, fBase);
|
||||
make_key(&fAppliedPEKey, fAppliedPE);
|
||||
make_key(&fAppliedPEThenStrokeKey, fAppliedPEThenStroke);
|
||||
make_key(&fAppliedFullKey, fAppliedFull);
|
||||
|
||||
// Applying the path effect and then the stroke should always be the same as applying
|
||||
// both in one go.
|
||||
REPORTER_ASSERT(r, fAppliedPEThenStrokeKey == fAppliedFullKey);
|
||||
SkPath a, b;
|
||||
fAppliedPEThenStroke.asPath(&a);
|
||||
fAppliedFull.asPath(&b);
|
||||
REPORTER_ASSERT(r, a == b);
|
||||
|
||||
// Check that the same path is produced when style is applied by GrShape and GrStyle.
|
||||
SkPath preStyle;
|
||||
SkPath postPathEffect;
|
||||
SkPath postAllStyle;
|
||||
|
||||
fBase.asPath(&preStyle);
|
||||
SkStrokeRec postPathEffectStrokeRec(SkStrokeRec::kFill_InitStyle);
|
||||
if (fBase.style().applyPathEffectToPath(&postPathEffect, &postPathEffectStrokeRec,
|
||||
preStyle)) {
|
||||
SkPath testPath;
|
||||
fAppliedPE.asPath(&testPath);
|
||||
REPORTER_ASSERT(r, testPath == postPathEffect);
|
||||
REPORTER_ASSERT(r,
|
||||
postPathEffectStrokeRec.hasEqualEffect(fAppliedPE.style().strokeRec()));
|
||||
}
|
||||
SkStrokeRec::InitStyle fillOrHairline;
|
||||
if (fBase.style().applyToPath(&postAllStyle, &fillOrHairline, preStyle)) {
|
||||
SkPath testPath;
|
||||
fAppliedFull.asPath(&testPath);
|
||||
REPORTER_ASSERT(r, testPath == postAllStyle);
|
||||
if (fillOrHairline == SkStrokeRec::kFill_InitStyle) {
|
||||
REPORTER_ASSERT(r, fAppliedFull.style().isSimpleFill());
|
||||
} else {
|
||||
REPORTER_ASSERT(r, fAppliedFull.style().isSimpleHairline());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrShape fBase;
|
||||
@ -88,13 +123,6 @@ private:
|
||||
};
|
||||
|
||||
void TestCase::testExpectations(skiatest::Reporter* reporter, SelfExpectations expectations) const {
|
||||
// Applying the path effect and then the stroke should always be the same as applying
|
||||
// both in one go.
|
||||
REPORTER_ASSERT(reporter, fAppliedPEThenStrokeKey == fAppliedFullKey);
|
||||
SkPath a, b;
|
||||
fAppliedPEThenStroke.asPath(&a);
|
||||
fAppliedFull.asPath(&b);
|
||||
REPORTER_ASSERT(reporter, a == b);
|
||||
// The base's key should always be valid (unless the path is volatile)
|
||||
REPORTER_ASSERT(reporter, fBaseKey.count());
|
||||
if (expectations.fPEHasEffect) {
|
||||
@ -108,6 +136,7 @@ void TestCase::testExpectations(skiatest::Reporter* reporter, SelfExpectations e
|
||||
}
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, fBaseKey == fAppliedPEKey);
|
||||
SkPath a, b;
|
||||
fBase.asPath(&a);
|
||||
fAppliedPE.asPath(&b);
|
||||
REPORTER_ASSERT(reporter, a == b);
|
||||
@ -183,36 +212,37 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase::SelfExpectations expectations;
|
||||
SkPaint fill;
|
||||
|
||||
TestCase fillCase(geo, fill);
|
||||
TestCase fillCase(geo, fill, reporter);
|
||||
expectations.fPEHasEffect = false;
|
||||
expectations.fPEHasValidKey = false;
|
||||
expectations.fStrokeApplies = false;
|
||||
fillCase.testExpectations(reporter, expectations);
|
||||
// Test that another GrShape instance built from the same primitive is the same.
|
||||
TestCase(geo, fill).compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(geo, fill, reporter).compare(reporter, fillCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
SkPaint stroke2RoundBevel;
|
||||
stroke2RoundBevel.setStyle(SkPaint::kStroke_Style);
|
||||
stroke2RoundBevel.setStrokeCap(SkPaint::kRound_Cap);
|
||||
stroke2RoundBevel.setStrokeJoin(SkPaint::kBevel_Join);
|
||||
stroke2RoundBevel.setStrokeWidth(2.f);
|
||||
TestCase stroke2RoundBevelCase(geo, stroke2RoundBevel);
|
||||
TestCase stroke2RoundBevelCase(geo, stroke2RoundBevel, reporter);
|
||||
expectations.fPEHasValidKey = true;
|
||||
expectations.fPEHasEffect = false;
|
||||
expectations.fStrokeApplies = true;
|
||||
stroke2RoundBevelCase.testExpectations(reporter, expectations);
|
||||
TestCase(geo, stroke2RoundBevel).compare(reporter, stroke2RoundBevelCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(geo, stroke2RoundBevel, reporter).compare(reporter, stroke2RoundBevelCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
SkPaint stroke2RoundBevelDash = stroke2RoundBevel;
|
||||
stroke2RoundBevelDash.setPathEffect(make_dash());
|
||||
TestCase stroke2RoundBevelDashCase(geo, stroke2RoundBevelDash);
|
||||
TestCase stroke2RoundBevelDashCase(geo, stroke2RoundBevelDash, reporter);
|
||||
expectations.fPEHasValidKey = true;
|
||||
expectations.fPEHasEffect = true;
|
||||
expectations.fStrokeApplies = true;
|
||||
stroke2RoundBevelDashCase.testExpectations(reporter, expectations);
|
||||
TestCase(geo, stroke2RoundBevelDash).compare(reporter, stroke2RoundBevelDashCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(geo, stroke2RoundBevelDash, reporter).compare(reporter, stroke2RoundBevelDashCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
fillCase.compare(reporter, stroke2RoundBevelCase,
|
||||
TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
@ -224,7 +254,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
SkPaint hairline;
|
||||
hairline.setStyle(SkPaint::kStroke_Style);
|
||||
hairline.setStrokeWidth(0.f);
|
||||
TestCase hairlineCase(geo, hairline);
|
||||
TestCase hairlineCase(geo, hairline, reporter);
|
||||
// Since hairline style doesn't change the SkPath data, it is keyed identically to fill.
|
||||
hairlineCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
@ -243,16 +273,16 @@ static void test_stroke_param(skiatest::Reporter* reporter, const GEO& geo,
|
||||
strokeB.setStrokeWidth(2.f);
|
||||
setter(&strokeB, b);
|
||||
|
||||
TestCase strokeACase(geo, strokeA);
|
||||
TestCase strokeBCase(geo, strokeB);
|
||||
TestCase strokeACase(geo, strokeA, reporter);
|
||||
TestCase strokeBCase(geo, strokeB, reporter);
|
||||
strokeACase.compare(reporter, strokeBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
|
||||
// Make sure stroking params don't affect fill style.
|
||||
SkPaint fillA = strokeA, fillB = strokeB;
|
||||
fillA.setStyle(SkPaint::kFill_Style);
|
||||
fillB.setStyle(SkPaint::kFill_Style);
|
||||
TestCase fillACase(geo, fillA);
|
||||
TestCase fillBCase(geo, fillB);
|
||||
TestCase fillACase(geo, fillA, reporter);
|
||||
TestCase fillBCase(geo, fillB, reporter);
|
||||
fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// Make sure just applying the dash but not stroke gives the same key for both stroking
|
||||
@ -260,8 +290,8 @@ static void test_stroke_param(skiatest::Reporter* reporter, const GEO& geo,
|
||||
SkPaint dashA = strokeA, dashB = strokeB;
|
||||
dashA.setPathEffect(make_dash());
|
||||
dashB.setPathEffect(make_dash());
|
||||
TestCase dashACase(geo, dashA);
|
||||
TestCase dashBCase(geo, dashB);
|
||||
TestCase dashACase(geo, dashA, reporter);
|
||||
TestCase dashBCase(geo, dashB, reporter);
|
||||
dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
}
|
||||
|
||||
@ -277,22 +307,22 @@ static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
SkPaint miterB = miterA;
|
||||
miterA.setStrokeMiter(0.6f);
|
||||
|
||||
TestCase miterACase(geo, miterA);
|
||||
TestCase miterBCase(geo, miterB);
|
||||
TestCase miterACase(geo, miterA, reporter);
|
||||
TestCase miterBCase(geo, miterB, reporter);
|
||||
miterACase.compare(reporter, miterBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
|
||||
SkPaint noMiterA = miterA, noMiterB = miterB;
|
||||
noMiterA.setStrokeJoin(SkPaint::kRound_Join);
|
||||
noMiterB.setStrokeJoin(SkPaint::kRound_Join);
|
||||
TestCase noMiterACase(geo, noMiterA);
|
||||
TestCase noMiterBCase(geo, noMiterB);
|
||||
TestCase noMiterACase(geo, noMiterA, reporter);
|
||||
TestCase noMiterBCase(geo, noMiterB, reporter);
|
||||
noMiterACase.compare(reporter, noMiterBCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
SkPaint fillA = miterA, fillB = miterB;
|
||||
fillA.setStyle(SkPaint::kFill_Style);
|
||||
fillB.setStyle(SkPaint::kFill_Style);
|
||||
TestCase fillACase(geo, fillA);
|
||||
TestCase fillBCase(geo, fillB);
|
||||
TestCase fillACase(geo, fillA, reporter);
|
||||
TestCase fillBCase(geo, fillB, reporter);
|
||||
fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
|
||||
@ -303,9 +333,9 @@ static void test_dash_fill(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
for (DashFactoryFn md : {&make_dash, &make_null_dash}) {
|
||||
SkPaint dashFill;
|
||||
dashFill.setPathEffect((*md)());
|
||||
TestCase dashFillCase(geo, dashFill);
|
||||
TestCase dashFillCase(geo, dashFill, reporter);
|
||||
|
||||
TestCase fillCase(geo, SkPaint());
|
||||
TestCase fillCase(geo, SkPaint(), reporter);
|
||||
dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
}
|
||||
@ -325,10 +355,10 @@ void test_null_dash(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
nullDash.setStrokeWidth(1.f);
|
||||
nullDash.setPathEffect(make_null_dash());
|
||||
|
||||
TestCase fillCase(geo, fill);
|
||||
TestCase strokeCase(geo, stroke);
|
||||
TestCase dashCase(geo, dash);
|
||||
TestCase nullDashCase(geo, nullDash);
|
||||
TestCase fillCase(geo, fill, reporter);
|
||||
TestCase strokeCase(geo, stroke, reporter);
|
||||
TestCase dashCase(geo, dash, reporter);
|
||||
TestCase nullDashCase(geo, nullDash, reporter);
|
||||
|
||||
nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
@ -365,27 +395,27 @@ void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const GEO& geo)
|
||||
};
|
||||
|
||||
SkPaint fill;
|
||||
TestCase fillGeoCase(geo, fill);
|
||||
TestCase fillGeoCase(geo, fill, reporter);
|
||||
|
||||
SkPaint pe;
|
||||
pe.setPathEffect(RRectPathEffect::Make());
|
||||
TestCase geoPECase(geo, pe);
|
||||
TestCase geoPECase(geo, pe, reporter);
|
||||
|
||||
SkPaint peStroke;
|
||||
peStroke.setPathEffect(RRectPathEffect::Make());
|
||||
peStroke.setStrokeWidth(2.f);
|
||||
peStroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase geoPEStrokeCase(geo, peStroke);
|
||||
TestCase geoPEStrokeCase(geo, peStroke, reporter);
|
||||
|
||||
fillGeoCase.compare(reporter, geoPECase, TestCase::kSameUpToPE_ComparisonExpecation);
|
||||
fillGeoCase.compare(reporter, geoPEStrokeCase, TestCase::kSameUpToPE_ComparisonExpecation);
|
||||
geoPECase.compare(reporter, geoPEStrokeCase,
|
||||
TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
|
||||
TestCase rrectFillCase(RRectPathEffect::RRect(), fill);
|
||||
TestCase rrectFillCase(RRectPathEffect::RRect(), fill, reporter);
|
||||
SkPaint stroke = peStroke;
|
||||
stroke.setPathEffect(nullptr);
|
||||
TestCase rrectStrokeCase(RRectPathEffect::RRect(), stroke);
|
||||
TestCase rrectStrokeCase(RRectPathEffect::RRect(), stroke, reporter);
|
||||
|
||||
SkRRect rrect;
|
||||
// Applying the path effect should make a SkRRect shape. There is no further stroking in the
|
||||
@ -441,7 +471,7 @@ void test_unknown_path_effect(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
peStroke.setPathEffect(AddLineTosPathEffect::Make());
|
||||
peStroke.setStrokeWidth(2.f);
|
||||
peStroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase geoPEStrokeCase(geo, peStroke);
|
||||
TestCase geoPEStrokeCase(geo, peStroke, reporter);
|
||||
TestCase::SelfExpectations expectations;
|
||||
expectations.fPEHasEffect = true;
|
||||
expectations.fPEHasValidKey = false;
|
||||
@ -462,13 +492,13 @@ void test_volatile_path(skiatest::Reporter* reporter, const SkPath& path,
|
||||
dashAndStroke.setPathEffect(make_dash());
|
||||
dashAndStroke.setStrokeWidth(2.f);
|
||||
dashAndStroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase volatileCase(vPath, dashAndStroke);
|
||||
TestCase volatileCase(vPath, dashAndStroke, reporter);
|
||||
// We expect a shape made from a volatile path to have a key iff the shape is recognized
|
||||
// as a specialized geometry.
|
||||
if (isNonPath) {
|
||||
REPORTER_ASSERT(reporter, SkToBool(volatileCase.baseKey().count()));
|
||||
// In this case all the keys should be identical to the non-volatile case.
|
||||
TestCase nonVolatileCase(path, dashAndStroke);
|
||||
TestCase nonVolatileCase(path, dashAndStroke, reporter);
|
||||
volatileCase.compare(reporter, nonVolatileCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
} else {
|
||||
// None of the keys should be valid.
|
||||
@ -508,7 +538,7 @@ void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const GEO&
|
||||
|
||||
SkPaint pe;
|
||||
pe.setPathEffect(EmptyPathEffect::Make());
|
||||
TestCase geoCase(geo, pe);
|
||||
TestCase geoCase(geo, pe, reporter);
|
||||
REPORTER_ASSERT(reporter, geoCase.appliedFullStyleKey() == emptyKey);
|
||||
REPORTER_ASSERT(reporter, geoCase.appliedPathEffectKey() == emptyKey);
|
||||
REPORTER_ASSERT(reporter, geoCase.appliedPathEffectThenStrokeKey() == emptyKey);
|
||||
@ -517,7 +547,7 @@ void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const GEO&
|
||||
peStroke.setPathEffect(EmptyPathEffect::Make());
|
||||
peStroke.setStrokeWidth(2.f);
|
||||
peStroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase geoPEStrokeCase(geo, peStroke);
|
||||
TestCase geoPEStrokeCase(geo, peStroke, reporter);
|
||||
REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleKey() == emptyKey);
|
||||
REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectKey() == emptyKey);
|
||||
REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectThenStrokeKey() == emptyKey);
|
||||
@ -526,7 +556,7 @@ void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const GEO&
|
||||
void test_empty_shape(skiatest::Reporter* reporter) {
|
||||
SkPath emptyPath;
|
||||
SkPaint fill;
|
||||
TestCase fillEmptyCase(emptyPath, fill);
|
||||
TestCase fillEmptyCase(emptyPath, fill, reporter);
|
||||
|
||||
Key emptyKey(fillEmptyCase.baseKey());
|
||||
REPORTER_ASSERT(reporter, emptyKey.count());
|
||||
@ -541,7 +571,7 @@ void test_empty_shape(skiatest::Reporter* reporter) {
|
||||
SkPaint stroke;
|
||||
stroke.setStrokeWidth(2.f);
|
||||
stroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase strokeEmptyCase(emptyPath2, stroke);
|
||||
TestCase strokeEmptyCase(emptyPath2, stroke, reporter);
|
||||
strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// Dashing and stroking an empty path should have no effect
|
||||
@ -550,20 +580,20 @@ void test_empty_shape(skiatest::Reporter* reporter) {
|
||||
dashAndStroke.setPathEffect(make_dash());
|
||||
dashAndStroke.setStrokeWidth(2.f);
|
||||
dashAndStroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase dashAndStrokeEmptyCase(emptyPath3, dashAndStroke);
|
||||
TestCase dashAndStrokeEmptyCase(emptyPath3, dashAndStroke, reporter);
|
||||
dashAndStrokeEmptyCase.compare(reporter, fillEmptyCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// A shape made from an empty rrect should behave the same as an empty path.
|
||||
SkRRect emptyRRect = SkRRect::MakeRect(SkRect::MakeEmpty());
|
||||
REPORTER_ASSERT(reporter, emptyRRect.getType() == SkRRect::kEmpty_Type);
|
||||
TestCase dashAndStrokeEmptyRRectCase(emptyRRect, dashAndStroke);
|
||||
TestCase dashAndStrokeEmptyRRectCase(emptyRRect, dashAndStroke, reporter);
|
||||
dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// Same for a rect.
|
||||
SkRect emptyRect = SkRect::MakeEmpty();
|
||||
TestCase dashAndStrokeEmptyRectCase(emptyRect, dashAndStroke);
|
||||
TestCase dashAndStrokeEmptyRectCase(emptyRect, dashAndStroke, reporter);
|
||||
dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
@ -658,25 +688,25 @@ DEF_TEST(GrShape, reporter) {
|
||||
test_path_effect_makes_empty_shape(reporter, path);
|
||||
|
||||
SkPaint fillPaint;
|
||||
TestCase fillPathCase(path, fillPaint);
|
||||
TestCase fillPathCase(path, fillPaint, reporter);
|
||||
SkRRect rrect;
|
||||
REPORTER_ASSERT(reporter, testPath.fIsRRectForFill ==
|
||||
fillPathCase.baseShape().asRRect(&rrect));
|
||||
if (testPath.fIsRRectForFill) {
|
||||
REPORTER_ASSERT(reporter, rrect == testPath.fRRect);
|
||||
TestCase fillRRectCase(rrect, fillPaint);
|
||||
TestCase fillRRectCase(rrect, fillPaint, reporter);
|
||||
fillPathCase.compare(reporter, fillRRectCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
|
||||
SkPaint strokePaint;
|
||||
strokePaint.setStrokeWidth(3.f);
|
||||
strokePaint.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase strokePathCase(path, strokePaint);
|
||||
TestCase strokePathCase(path, strokePaint, reporter);
|
||||
REPORTER_ASSERT(reporter, testPath.fIsRRectForStroke ==
|
||||
strokePathCase.baseShape().asRRect(&rrect));
|
||||
if (testPath.fIsRRectForStroke) {
|
||||
REPORTER_ASSERT(reporter, rrect == testPath.fRRect);
|
||||
TestCase strokeRRectCase(rrect, strokePaint);
|
||||
TestCase strokeRRectCase(rrect, strokePaint, reporter);
|
||||
strokePathCase.compare(reporter, strokeRRectCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user