Apply canonicalizations to path GrShapes.
The following canonicalizations of path-backed GrShapes are added: *convex shapes are stored with even/odd (or inv even/odd) fill. *filled paths are closed. *dashed paths ignore inverseness of the fill This will improve the results of queries about the geometry that will be added in a future change. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2067283003 Review-Url: https://codereview.chromium.org/2067283003
This commit is contained in:
parent
9b972c4a12
commit
93f66bc3af
@ -32,6 +32,7 @@ GrShape& GrShape::operator=(const GrShape& that) {
|
||||
} else {
|
||||
fPath.set(*that.fPath.get());
|
||||
}
|
||||
fPathGenID = that.fPathGenID;
|
||||
break;
|
||||
}
|
||||
fInheritedKey.reset(that.fInheritedKey.count());
|
||||
@ -75,7 +76,7 @@ int GrShape::unstyledKeySize() const {
|
||||
// + 1 for the direction, start index, and inverseness.
|
||||
return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
|
||||
case Type::kPath:
|
||||
if (fPath.get()->isVolatile()) {
|
||||
if (0 == fPathGenID) {
|
||||
return -1;
|
||||
} else {
|
||||
// The key is the path ID and fill type.
|
||||
@ -106,8 +107,8 @@ void GrShape::writeUnstyledKey(uint32_t* key) const {
|
||||
SkASSERT(fRRectStart < 8);
|
||||
break;
|
||||
case Type::kPath:
|
||||
SkASSERT(!fPath.get()->isVolatile());
|
||||
*key++ = fPath.get()->getGenerationID();
|
||||
SkASSERT(fPathGenID);
|
||||
*key++ = fPathGenID;
|
||||
// We could canonicalize the fill rule for paths that don't differentiate between
|
||||
// even/odd or winding fill (e.g. convex).
|
||||
*key++ = fPath.get()->getFillType();
|
||||
@ -133,7 +134,7 @@ void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca
|
||||
parentCnt = parent.unstyledKeySize();
|
||||
if (parentCnt < 0) {
|
||||
// The parent's geometry has no key so we will have no key.
|
||||
fPath.get()->setIsVolatile(true);
|
||||
fPathGenID = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -143,9 +144,9 @@ void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca
|
||||
}
|
||||
int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags);
|
||||
if (styleCnt < 0) {
|
||||
// The style doesn't allow a key, set the path to volatile so that we fail when
|
||||
// The style doesn't allow a key, set the path gen ID to 0 so that we fail when
|
||||
// we try to get a key for the shape.
|
||||
fPath.get()->setIsVolatile(true);
|
||||
fPathGenID = 0;
|
||||
return;
|
||||
}
|
||||
fInheritedKey.reset(parentCnt + styleCnt);
|
||||
@ -166,20 +167,21 @@ void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca
|
||||
GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) {
|
||||
switch (fType) {
|
||||
case Type::kEmpty:
|
||||
return;
|
||||
break;
|
||||
case Type::kRRect:
|
||||
fRRect = that.fRRect;
|
||||
fRRectDir = that.fRRectDir;
|
||||
fRRectStart = that.fRRectStart;
|
||||
fRRectIsInverted = that.fRRectIsInverted;
|
||||
return;
|
||||
break;
|
||||
case Type::kPath:
|
||||
fPath.set(*that.fPath.get());
|
||||
return;
|
||||
fPathGenID = that.fPathGenID;
|
||||
break;
|
||||
}
|
||||
fInheritedKey.reset(that.fInheritedKey.count());
|
||||
memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
|
||||
sizeof(uint32_t) * fInheritedKey.count());
|
||||
sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
|
||||
sizeof(uint32_t) * fInheritedKey.count());
|
||||
}
|
||||
|
||||
GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) {
|
||||
@ -315,6 +317,44 @@ void GrShape::attemptToSimplifyPath() {
|
||||
if (Type::kRRect == fType) {
|
||||
this->attemptToSimplifyRRect();
|
||||
}
|
||||
} else {
|
||||
if (fInheritedKey.count() || fPath.get()->isVolatile()) {
|
||||
fPathGenID = 0;
|
||||
} else {
|
||||
fPathGenID = fPath.get()->getGenerationID();
|
||||
}
|
||||
if (this->style().isSimpleFill()) {
|
||||
// Filled paths are treated as though all their contours were closed.
|
||||
// Since SkPath doesn't track individual contours, this will only close the last. :(
|
||||
// There is no point in closing lines, though, since they loose their line-ness.
|
||||
if (!fPath.get()->isLine(nullptr)) {
|
||||
fPath.get()->close();
|
||||
fPath.get()->setIsVolatile(true);
|
||||
}
|
||||
}
|
||||
if (fPath.get()->isConvex()) {
|
||||
// There is no distinction between even/odd and non-zero winding count for convex
|
||||
// paths.
|
||||
if (fPath.get()->isInverseFillType()) {
|
||||
fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
|
||||
} else {
|
||||
fPath.get()->setFillType(SkPath::kEvenOdd_FillType);
|
||||
}
|
||||
}
|
||||
if (this->style().isDashed()) {
|
||||
// Dashing ignores inverseness (skbug.com/5421)
|
||||
switch (fPath.get()->getFillType()) {
|
||||
case SkPath::kWinding_FillType:
|
||||
case SkPath::kEvenOdd_FillType:
|
||||
break;
|
||||
case SkPath::kInverseWinding_FillType:
|
||||
fPath.get()->setFillType(SkPath::kWinding_FillType);
|
||||
break;
|
||||
case SkPath::kInverseEvenOdd_FillType:
|
||||
fPath.get()->setFillType(SkPath::kEvenOdd_FillType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,8 +188,11 @@ public:
|
||||
case Type::kRRect:
|
||||
out->reset();
|
||||
out->addRRect(fRRect, fRRectDir, fRRectStart);
|
||||
// Below matches the fill type that attemptToSimplifyPath uses.
|
||||
if (fRRectIsInverted) {
|
||||
out->setFillType(SkPath::kInverseWinding_FillType);
|
||||
out->setFillType(SkPath::kInverseEvenOdd_FillType);
|
||||
} else {
|
||||
out->setFillType(SkPath::kEvenOdd_FillType);
|
||||
}
|
||||
break;
|
||||
case Type::kPath:
|
||||
@ -279,7 +282,6 @@ private:
|
||||
void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
|
||||
|
||||
void attemptToSimplifyPath();
|
||||
|
||||
void attemptToSimplifyRRect();
|
||||
|
||||
static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction;
|
||||
@ -333,6 +335,8 @@ private:
|
||||
unsigned fRRectStart;
|
||||
bool fRRectIsInverted;
|
||||
SkTLazy<SkPath> fPath;
|
||||
// Gen ID of the original path (fPath may be modified)
|
||||
int32_t fPathGenID = 0;
|
||||
GrStyle fStyle;
|
||||
SkAutoSTArray<8, uint32_t> fInheritedKey;
|
||||
};
|
||||
|
@ -314,6 +314,12 @@ void check_equivalence(skiatest::Reporter* r, const GrShape& a, const GrShape& b
|
||||
} else {
|
||||
REPORTER_ASSERT(r, keyA == keyB);
|
||||
}
|
||||
if (a.style().isSimpleFill() != b.style().isSimpleFill()) {
|
||||
// GrShape will close paths with simple fill style. Make the non-filled path closed
|
||||
// so that the comparision will succeed. Make sure both are closed before comparing.
|
||||
pA.close();
|
||||
pB.close();
|
||||
}
|
||||
REPORTER_ASSERT(r, pA == pB);
|
||||
REPORTER_ASSERT(r, aIsRRect == bIsRRect);
|
||||
if (aIsRRect) {
|
||||
@ -1347,7 +1353,8 @@ DEF_TEST(GrShape, reporter) {
|
||||
}
|
||||
|
||||
struct TestPath {
|
||||
TestPath(const SkPath& path, bool isRRectFill, bool isRRectStroke, bool isLine, const SkRRect& rrect)
|
||||
TestPath(const SkPath& path, bool isRRectFill, bool isRRectStroke, bool isLine,
|
||||
const SkRRect& rrect)
|
||||
: fPath(path)
|
||||
, fIsRRectForFill(isRRectFill)
|
||||
, fIsRRectForStroke(isRRectStroke)
|
||||
|
Loading…
Reference in New Issue
Block a user