Update GrShape test to allow more flexible shape creation.
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2277483002 Review-Url: https://codereview.chromium.org/2277483002
This commit is contained in:
parent
9b8583dd1f
commit
a395f7c7a5
@ -74,14 +74,186 @@ static bool test_bounds_by_rasterizing(const SkPath& path, const SkRect& bounds)
|
||||
}
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Geo is a factory for creating a GrShape from another representation. It also answers some
|
||||
* questions about expected behavior for GrShape given the inputs.
|
||||
*/
|
||||
class Geo {
|
||||
public:
|
||||
virtual ~Geo() {};
|
||||
virtual GrShape makeShape(const SkPaint&) const = 0;
|
||||
virtual SkPath path() const = 0;
|
||||
// These functions allow tests to check for special cases where style gets
|
||||
// applied by GrShape in its constructor (without calling GrShape::applyStyle).
|
||||
// These unfortunately rely on knowing details of GrShape's implementation.
|
||||
// These predicates are factored out here to avoid littering the rest of the
|
||||
// test code with GrShape implementation details.
|
||||
virtual bool fillChangesGeom() const { return false; }
|
||||
virtual bool strokeIsConvertedToFill() const { return false; }
|
||||
virtual bool strokeAndFillIsConvertedToFill(const SkPaint&) const { return false; }
|
||||
// Is this something we expect GrShape to recognize as something simpler than a path.
|
||||
virtual bool isNonPath(const SkPaint& paint) const { return true; }
|
||||
};
|
||||
|
||||
class RectGeo : public Geo {
|
||||
public:
|
||||
RectGeo(const SkRect& rect) : fRect(rect) {}
|
||||
|
||||
SkPath path() const override {
|
||||
SkPath path;
|
||||
path.addRect(fRect);
|
||||
return path;
|
||||
}
|
||||
|
||||
GrShape makeShape(const SkPaint& paint) const override {
|
||||
return GrShape(fRect, paint);
|
||||
}
|
||||
|
||||
bool strokeAndFillIsConvertedToFill(const SkPaint& paint) const override {
|
||||
SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
|
||||
// Converted to an outset rectangle.
|
||||
return paint.getStrokeJoin() == SkPaint::kMiter_Join &&
|
||||
paint.getStrokeMiter() >= SK_ScalarSqrt2;
|
||||
}
|
||||
|
||||
private:
|
||||
SkRect fRect;
|
||||
};
|
||||
|
||||
class RRectGeo : public Geo {
|
||||
public:
|
||||
RRectGeo(const SkRRect& rrect) : fRRect(rrect) {}
|
||||
|
||||
GrShape makeShape(const SkPaint& paint) const override {
|
||||
return GrShape(fRRect, paint);
|
||||
}
|
||||
|
||||
SkPath path() const override {
|
||||
SkPath path;
|
||||
path.addRRect(fRRect);
|
||||
return path;
|
||||
}
|
||||
|
||||
bool strokeAndFillIsConvertedToFill(const SkPaint& paint) const override {
|
||||
SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
|
||||
if (fRRect.isRect()) {
|
||||
return RectGeo(fRRect.rect()).strokeAndFillIsConvertedToFill(paint);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
SkRRect fRRect;
|
||||
};
|
||||
|
||||
class PathGeo : public Geo {
|
||||
public:
|
||||
enum class Invert { kNo, kYes };
|
||||
|
||||
PathGeo(const SkPath& path, Invert invert) : fPath(path) {
|
||||
SkASSERT(!path.isInverseFillType());
|
||||
if (Invert::kYes == invert) {
|
||||
if (fPath.getFillType() == SkPath::kEvenOdd_FillType) {
|
||||
fPath.setFillType(SkPath::kInverseEvenOdd_FillType);
|
||||
} else {
|
||||
SkASSERT(fPath.getFillType() == SkPath::kWinding_FillType);
|
||||
fPath.setFillType(SkPath::kInverseWinding_FillType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrShape makeShape(const SkPaint& paint) const override {
|
||||
return GrShape(fPath, paint);
|
||||
}
|
||||
|
||||
SkPath path() const override { return fPath; }
|
||||
|
||||
bool fillChangesGeom() const override {
|
||||
// unclosed rects get closed. Lines get turned into empty geometry
|
||||
return this->isUnclosedRect() || (fPath.isLine(nullptr) && !fPath.isInverseFillType());
|
||||
}
|
||||
|
||||
bool strokeIsConvertedToFill() const override {
|
||||
return this->isAxisAlignedLine();
|
||||
}
|
||||
|
||||
bool strokeAndFillIsConvertedToFill(const SkPaint& paint) const override {
|
||||
SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
|
||||
if (this->isAxisAlignedLine()) {
|
||||
// The fill is ignored (zero area) and the stroke is converted to a rrect.
|
||||
return true;
|
||||
}
|
||||
SkRect rect;
|
||||
unsigned start;
|
||||
SkPath::Direction dir;
|
||||
if (SkPathPriv::IsSimpleClosedRect(fPath, &rect, &dir, &start)) {
|
||||
return RectGeo(rect).strokeAndFillIsConvertedToFill(paint);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNonPath(const SkPaint& paint) const override {
|
||||
return fPath.isLine(nullptr) || fPath.isEmpty();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isAxisAlignedLine() const {
|
||||
SkPoint pts[2];
|
||||
if (!fPath.isLine(pts)) {
|
||||
return false;
|
||||
}
|
||||
return pts[0].fX == pts[1].fX || pts[0].fY == pts[1].fY;
|
||||
}
|
||||
|
||||
bool isUnclosedRect() const {
|
||||
bool closed;
|
||||
return fPath.isRect(nullptr, &closed, nullptr) && !closed;
|
||||
}
|
||||
|
||||
SkPath fPath;
|
||||
};
|
||||
|
||||
class RRectPathGeo : public PathGeo {
|
||||
public:
|
||||
enum class RRectForStroke { kNo, kYes };
|
||||
|
||||
RRectPathGeo(const SkPath& path, const SkRRect& equivalentRRect, RRectForStroke rrectForStroke,
|
||||
Invert invert)
|
||||
: PathGeo(path, invert)
|
||||
, fRRect(equivalentRRect)
|
||||
, fRRectForStroke(rrectForStroke) {}
|
||||
|
||||
RRectPathGeo(const SkPath& path, const SkRect& equivalentRect, RRectForStroke rrectForStroke,
|
||||
Invert invert)
|
||||
: RRectPathGeo(path, SkRRect::MakeRect(equivalentRect), rrectForStroke, invert) {}
|
||||
|
||||
bool isNonPath(const SkPaint& paint) const override {
|
||||
if (SkPaint::kFill_Style == paint.getStyle() || RRectForStroke::kYes == fRRectForStroke) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkRRect& rrect() const { return fRRect; }
|
||||
|
||||
private:
|
||||
SkRRect fRRect;
|
||||
RRectForStroke fRRectForStroke;
|
||||
};
|
||||
|
||||
class TestCase {
|
||||
public:
|
||||
template <typename GEO>
|
||||
TestCase(const GEO& geo, const SkPaint& paint, skiatest::Reporter* r,
|
||||
SkScalar scale = SK_Scalar1) : fBase(geo, paint) {
|
||||
TestCase(const Geo& geo, const SkPaint& paint, skiatest::Reporter* r,
|
||||
SkScalar scale = SK_Scalar1) : fBase(geo.makeShape(paint)) {
|
||||
this->init(r, scale);
|
||||
}
|
||||
|
||||
template<typename... ShapeArgs>
|
||||
TestCase(skiatest::Reporter* r, ShapeArgs... shapeArgs)
|
||||
: fBase(shapeArgs...) {
|
||||
this->init(r, SK_Scalar1);
|
||||
}
|
||||
|
||||
TestCase(const GrShape& shape, skiatest::Reporter* r, SkScalar scale = SK_Scalar1)
|
||||
: fBase(shape) {
|
||||
this->init(r, scale);
|
||||
@ -433,78 +605,7 @@ static sk_sp<SkPathEffect> make_null_dash() {
|
||||
return SkDashPathEffect::Make(kNullIntervals, SK_ARRAY_COUNT(kNullIntervals), 0.f);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// These functions allow tests to check for special cases where style gets
|
||||
// applied by GrShape in its constructor (without calling GrShape::applyStyle).
|
||||
// These unfortunately rely on knowing details of GrShape's implementation.
|
||||
// These predicates are factored out here to avoid littering the rest of the
|
||||
// test code with GrShape implementation details.
|
||||
|
||||
static bool path_is_axis_aligned_line(const SkPath& path) {
|
||||
SkPoint pts[2];
|
||||
if (!path.isLine(pts)) {
|
||||
return false;
|
||||
}
|
||||
return pts[0].fX == pts[1].fX || pts[0].fY == pts[1].fY;
|
||||
}
|
||||
|
||||
static bool path_is_unclosed_rect(const SkPath& path) {
|
||||
bool closed;
|
||||
return path.isRect(nullptr, &closed, nullptr) && !closed;
|
||||
}
|
||||
|
||||
// Will a GrShape constructed from a geometry perform a geometric transformation if the style is
|
||||
// simple fill that would not otherwise be applied.
|
||||
template <typename GEO> static bool fill_changes_geom(const GEO& geo) { return false; }
|
||||
template <> bool fill_changes_geom<SkPath>(const SkPath& path) {
|
||||
// unclosed rects get closed. Lines get turned into empty geometry
|
||||
return path_is_unclosed_rect(path) || (path.isLine(nullptr) && !path.isInverseFillType());
|
||||
}
|
||||
|
||||
// Will a GrShape constructed from the geometry with a stroke style (without path effect) perform a
|
||||
// geometric transformation that applies the the stroke immediately without storing a stroke style.
|
||||
template <typename GEO> static bool stroke_is_converted_to_fill(const GEO& geo) { return false; }
|
||||
template <> bool stroke_is_converted_to_fill(const SkPath& path) {
|
||||
// converted to a rrect.
|
||||
return path_is_axis_aligned_line(path);
|
||||
}
|
||||
|
||||
// Will a GrShape constructed from the geometry with a stroke-and-fill style (without path effect)
|
||||
// perform a geometric transformation that applies the the stroke immediately without storing a
|
||||
// stroke-and-fill style.
|
||||
template <typename GEO> static bool stroke_and_fill_is_converted_to_fill(const GEO& geo, const SkPaint& paint);
|
||||
template <> bool stroke_and_fill_is_converted_to_fill(const SkRect& rect, const SkPaint& paint) {
|
||||
SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
|
||||
// Converted to an outset rectangle.
|
||||
return paint.getStrokeJoin() == SkPaint::kMiter_Join &&
|
||||
paint.getStrokeMiter() >= SK_ScalarSqrt2;
|
||||
}
|
||||
template <> bool stroke_and_fill_is_converted_to_fill(const SkPath& path, const SkPaint& paint) {
|
||||
SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
|
||||
if (path_is_axis_aligned_line(path)) {
|
||||
// The fill is ignored (zero area) and the stroke is converted to a rrect.
|
||||
return true;
|
||||
}
|
||||
SkRect rect;
|
||||
unsigned start;
|
||||
SkPath::Direction dir;
|
||||
if (SkPathPriv::IsSimpleClosedRect(path, &rect, &dir, &start)) {
|
||||
return stroke_and_fill_is_converted_to_fill<SkRect>(rect, paint);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <> bool stroke_and_fill_is_converted_to_fill(const SkRRect& rr, const SkPaint& paint) {
|
||||
SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
|
||||
if (rr.isRect()) {
|
||||
return stroke_and_fill_is_converted_to_fill<SkRect>(rr.rect(), paint);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename GEO>
|
||||
static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
static void test_basic(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
sk_sp<SkPathEffect> dashPE = make_dash();
|
||||
|
||||
TestCase::SelfExpectations expectations;
|
||||
@ -527,7 +628,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase stroke2RoundBevelCase(geo, stroke2RoundBevel, reporter);
|
||||
expectations.fPEHasValidKey = true;
|
||||
expectations.fPEHasEffect = false;
|
||||
expectations.fStrokeApplies = !stroke_is_converted_to_fill(geo);
|
||||
expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
|
||||
stroke2RoundBevelCase.testExpectations(reporter, expectations);
|
||||
TestCase(geo, stroke2RoundBevel, reporter).compare(reporter, stroke2RoundBevelCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
@ -542,7 +643,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase(geo, stroke2RoundBevelDash, reporter).compare(reporter, stroke2RoundBevelDashCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
if (fill_changes_geom(geo) || stroke_is_converted_to_fill(geo)) {
|
||||
if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
|
||||
fillCase.compare(reporter, stroke2RoundBevelCase,
|
||||
TestCase::kAllDifferent_ComparisonExpecation);
|
||||
fillCase.compare(reporter, stroke2RoundBevelDashCase,
|
||||
@ -553,7 +654,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
fillCase.compare(reporter, stroke2RoundBevelDashCase,
|
||||
TestCase::kSameUpToPE_ComparisonExpecation);
|
||||
}
|
||||
if (stroke_is_converted_to_fill(geo)) {
|
||||
if (geo.strokeIsConvertedToFill()) {
|
||||
stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase,
|
||||
TestCase::kAllDifferent_ComparisonExpecation);
|
||||
} else {
|
||||
@ -567,7 +668,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase stroke2RoundBevelAndFillCase(geo, stroke2RoundBevelAndFill, reporter);
|
||||
expectations.fPEHasValidKey = true;
|
||||
expectations.fPEHasEffect = false;
|
||||
expectations.fStrokeApplies = !stroke_is_converted_to_fill(geo);
|
||||
expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
|
||||
stroke2RoundBevelAndFillCase.testExpectations(reporter, expectations);
|
||||
TestCase(geo, stroke2RoundBevelAndFill, reporter).compare(reporter,
|
||||
stroke2RoundBevelAndFillCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
@ -577,7 +678,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase stroke2RoundBevelAndFillDashCase(geo, stroke2RoundBevelAndFillDash, reporter);
|
||||
expectations.fPEHasValidKey = true;
|
||||
expectations.fPEHasEffect = false;
|
||||
expectations.fStrokeApplies = !stroke_is_converted_to_fill(geo);
|
||||
expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
|
||||
stroke2RoundBevelAndFillDashCase.testExpectations(reporter, expectations);
|
||||
TestCase(geo, stroke2RoundBevelAndFillDash, reporter).compare(
|
||||
reporter, stroke2RoundBevelAndFillDashCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
@ -590,7 +691,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase hairlineCase(geo, hairline, reporter);
|
||||
// Since hairline style doesn't change the SkPath data, it is keyed identically to fill (except
|
||||
// in the line and unclosed rect cases).
|
||||
if (fill_changes_geom(geo)) {
|
||||
if (geo.fillChangesGeom()) {
|
||||
hairlineCase.compare(reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
} else {
|
||||
hairlineCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
@ -601,8 +702,7 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
|
||||
}
|
||||
|
||||
template<typename GEO>
|
||||
static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
static void test_scale(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
sk_sp<SkPathEffect> dashPE = make_dash();
|
||||
|
||||
static const SkScalar kS1 = 1.f;
|
||||
@ -628,7 +728,7 @@ static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase strokeCase1(geo, stroke, reporter, kS1);
|
||||
TestCase strokeCase2(geo, stroke, reporter, kS2);
|
||||
// Scale affects the stroke
|
||||
if (stroke_is_converted_to_fill(geo)) {
|
||||
if (geo.strokeIsConvertedToFill()) {
|
||||
REPORTER_ASSERT(reporter, !strokeCase1.baseShape().style().applies());
|
||||
strokeCase1.compare(reporter, strokeCase2, TestCase::kAllSame_ComparisonExpecation);
|
||||
} else {
|
||||
@ -656,7 +756,7 @@ static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
// Scale affects the stroke, but check to make sure this didn't become a simpler shape (e.g.
|
||||
// stroke-and-filled rect can become a rect), in which case the scale shouldn't matter and the
|
||||
// geometries should agree.
|
||||
if (stroke_and_fill_is_converted_to_fill(geo, strokeAndFillDash)) {
|
||||
if (geo.strokeAndFillIsConvertedToFill(strokeAndFillDash)) {
|
||||
REPORTER_ASSERT(reporter, !strokeAndFillCase1.baseShape().style().applies());
|
||||
strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
@ -672,8 +772,8 @@ static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
|
||||
template <typename GEO, typename T>
|
||||
static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
||||
template <typename T>
|
||||
static void test_stroke_param_impl(skiatest::Reporter* reporter, const Geo& geo,
|
||||
std::function<void(SkPaint*, T)> setter, T a, T b,
|
||||
bool paramAffectsStroke,
|
||||
bool paramAffectsDashAndStroke) {
|
||||
@ -693,7 +793,7 @@ static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
||||
if (paramAffectsStroke) {
|
||||
// If stroking is immediately incorporated into a geometric transformation then the base
|
||||
// shapes will differ.
|
||||
if (stroke_is_converted_to_fill(geo)) {
|
||||
if (geo.strokeIsConvertedToFill()) {
|
||||
strokeACase.compare(reporter, strokeBCase,
|
||||
TestCase::kAllDifferent_ComparisonExpecation);
|
||||
} else {
|
||||
@ -713,8 +813,8 @@ static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
||||
if (paramAffectsStroke) {
|
||||
// If stroking is immediately incorporated into a geometric transformation then the base
|
||||
// shapes will differ.
|
||||
if (stroke_and_fill_is_converted_to_fill(geo, strokeAndFillA) ||
|
||||
stroke_and_fill_is_converted_to_fill(geo, strokeAndFillB)) {
|
||||
if (geo.strokeAndFillIsConvertedToFill(strokeAndFillA) ||
|
||||
geo.strokeAndFillIsConvertedToFill(strokeAndFillB)) {
|
||||
strokeAndFillACase.compare(reporter, strokeAndFillBCase,
|
||||
TestCase::kAllDifferent_ComparisonExpecation);
|
||||
} else {
|
||||
@ -748,20 +848,22 @@ static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename GEO, typename T>
|
||||
static void test_stroke_param(skiatest::Reporter* reporter, const GEO& geo,
|
||||
template <typename T>
|
||||
static void test_stroke_param(skiatest::Reporter* reporter, const Geo& geo,
|
||||
std::function<void(SkPaint*, T)> setter, T a, T b) {
|
||||
test_stroke_param_impl(reporter, geo, setter, a, b, true, true);
|
||||
};
|
||||
|
||||
template <typename GEO>
|
||||
static void test_stroke_cap(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
GrShape shape(geo, GrStyle(SkStrokeRec::kHairline_InitStyle));
|
||||
static void test_stroke_cap(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
SkPaint hairline;
|
||||
hairline.setStrokeWidth(0);
|
||||
hairline.setStyle(SkPaint::kStroke_Style);
|
||||
GrShape shape = geo.makeShape(hairline);
|
||||
// The cap should only affect shapes that may be open.
|
||||
bool affectsStroke = !shape.knownToBeClosed();
|
||||
// Dashing adds ends that need caps.
|
||||
bool affectsDashAndStroke = true;
|
||||
test_stroke_param_impl<GEO, SkPaint::Cap>(
|
||||
test_stroke_param_impl<SkPaint::Cap>(
|
||||
reporter,
|
||||
geo,
|
||||
[](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);},
|
||||
@ -774,15 +876,17 @@ static bool shape_known_not_to_have_joins(const GrShape& shape) {
|
||||
return shape.asLine(nullptr, nullptr) || shape.isEmpty();
|
||||
}
|
||||
|
||||
template <typename GEO>
|
||||
static void test_stroke_join(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
GrShape shape(geo, GrStyle(SkStrokeRec::kHairline_InitStyle));
|
||||
static void test_stroke_join(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
SkPaint hairline;
|
||||
hairline.setStrokeWidth(0);
|
||||
hairline.setStyle(SkPaint::kStroke_Style);
|
||||
GrShape shape = geo.makeShape(hairline);
|
||||
// GrShape recognizes certain types don't have joins and will prevent the join type from
|
||||
// affecting the style key.
|
||||
// Dashing doesn't add additional joins. However, GrShape currently loses track of this
|
||||
// after applying the dash.
|
||||
bool affectsStroke = !shape_known_not_to_have_joins(shape);
|
||||
test_stroke_param_impl<GEO, SkPaint::Join>(
|
||||
test_stroke_param_impl<SkPaint::Join>(
|
||||
reporter,
|
||||
geo,
|
||||
[](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
|
||||
@ -790,8 +894,7 @@ static void test_stroke_join(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
affectsStroke, true);
|
||||
};
|
||||
|
||||
template <typename GEO>
|
||||
static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
static void test_miter_limit(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
auto setMiterJoinAndLimit = [](SkPaint* p, SkScalar miter) {
|
||||
p->setStrokeJoin(SkPaint::kMiter_Join);
|
||||
p->setStrokeMiter(miter);
|
||||
@ -802,12 +905,15 @@ static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
p->setStrokeMiter(miter);
|
||||
};
|
||||
|
||||
GrShape shape(geo, GrStyle(SkStrokeRec::kHairline_InitStyle));
|
||||
SkPaint hairline;
|
||||
hairline.setStrokeWidth(0);
|
||||
hairline.setStyle(SkPaint::kStroke_Style);
|
||||
GrShape shape = geo.makeShape(hairline);
|
||||
bool mayHaveJoins = !shape_known_not_to_have_joins(shape);
|
||||
|
||||
// The miter limit should affect stroked and dashed-stroked cases when the join type is
|
||||
// miter.
|
||||
test_stroke_param_impl<GEO, SkScalar>(
|
||||
test_stroke_param_impl<SkScalar>(
|
||||
reporter,
|
||||
geo,
|
||||
setMiterJoinAndLimit,
|
||||
@ -817,7 +923,7 @@ static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
|
||||
// The miter limit should not affect stroked and dashed-stroked cases when the join type is
|
||||
// not miter.
|
||||
test_stroke_param_impl<GEO, SkScalar>(
|
||||
test_stroke_param_impl<SkScalar>(
|
||||
reporter,
|
||||
geo,
|
||||
setOtherJoinAndLimit,
|
||||
@ -826,8 +932,7 @@ static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
false);
|
||||
}
|
||||
|
||||
template<typename GEO>
|
||||
static void test_dash_fill(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
static void test_dash_fill(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
// A dash with no stroke should have no effect
|
||||
using DashFactoryFn = sk_sp<SkPathEffect>(*)();
|
||||
for (DashFactoryFn md : {&make_dash, &make_null_dash}) {
|
||||
@ -840,8 +945,7 @@ static void test_dash_fill(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename GEO>
|
||||
void test_null_dash(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
void test_null_dash(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
SkPaint fill;
|
||||
SkPaint stroke;
|
||||
stroke.setStyle(SkPaint::kStroke_Style);
|
||||
@ -864,21 +968,20 @@ void test_null_dash(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
// Check whether the fillCase or strokeCase/nullDashCase would undergo a geometric tranformation
|
||||
// on construction in order to determine how to compare the fill and stroke.
|
||||
if (fill_changes_geom(geo) || stroke_is_converted_to_fill(geo)) {
|
||||
if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
|
||||
nullDashCase.compare(reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
} else {
|
||||
nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
}
|
||||
// In the null dash case we may immediately convert to a fill, but not for the normal dash case.
|
||||
if (stroke_is_converted_to_fill(geo)) {
|
||||
if (geo.strokeIsConvertedToFill()) {
|
||||
nullDashCase.compare(reporter, dashCase, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
} else {
|
||||
nullDashCase.compare(reporter, dashCase, TestCase::kSameUpToPE_ComparisonExpecation);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename GEO>
|
||||
void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
/**
|
||||
* This path effect takes any input path and turns it into a rrect. It passes through stroke
|
||||
* info.
|
||||
@ -921,7 +1024,7 @@ void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const GEO& geo)
|
||||
|
||||
// Check whether constructing the filled case would cause the base shape to have a different
|
||||
// geometry (because of a geometric transformation upon initial GrShape construction).
|
||||
if (fill_changes_geom(geo)) {
|
||||
if (geo.fillChangesGeom()) {
|
||||
fillGeoCase.compare(reporter, geoPECase, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
fillGeoCase.compare(reporter, geoPEStrokeCase,
|
||||
TestCase::kAllDifferent_ComparisonExpecation);
|
||||
@ -932,10 +1035,10 @@ void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const GEO& geo)
|
||||
geoPECase.compare(reporter, geoPEStrokeCase,
|
||||
TestCase::kSameUpToStroke_ComparisonExpecation);
|
||||
|
||||
TestCase rrectFillCase(RRectPathEffect::RRect(), fill, reporter);
|
||||
TestCase rrectFillCase(reporter, RRectPathEffect::RRect(), fill);
|
||||
SkPaint stroke = peStroke;
|
||||
stroke.setPathEffect(nullptr);
|
||||
TestCase rrectStrokeCase(RRectPathEffect::RRect(), stroke, reporter);
|
||||
TestCase rrectStrokeCase(reporter, RRectPathEffect::RRect(), stroke);
|
||||
|
||||
SkRRect rrect;
|
||||
// Applying the path effect should make a SkRRect shape. There is no further stroking in the
|
||||
@ -962,8 +1065,7 @@ void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const GEO& geo)
|
||||
rrectStrokeCase.appliedFullStyleKey());
|
||||
}
|
||||
|
||||
template <typename GEO>
|
||||
void test_unknown_path_effect(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
void test_unknown_path_effect(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
/**
|
||||
* This path effect just adds two lineTos to the input path.
|
||||
*/
|
||||
@ -1003,8 +1105,7 @@ void test_unknown_path_effect(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
geoPEStrokeCase.testExpectations(reporter, expectations);
|
||||
}
|
||||
|
||||
template <typename GEO>
|
||||
void test_make_hairline_path_effect(skiatest::Reporter* reporter, const GEO& geo, bool isNonPath) {
|
||||
void test_make_hairline_path_effect(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
/**
|
||||
* This path effect just changes the stroke rec to hairline.
|
||||
*/
|
||||
@ -1036,7 +1137,7 @@ void test_make_hairline_path_effect(skiatest::Reporter* reporter, const GEO& geo
|
||||
peCase.baseShape().asPath(&a);
|
||||
peCase.appliedPathEffectShape().asPath(&b);
|
||||
peCase.appliedFullStyleShape().asPath(&c);
|
||||
if (isNonPath) {
|
||||
if (geo.isNonPath(pe)) {
|
||||
// RRect types can have a change in start index or direction after the PE is applied. This
|
||||
// is because once the PE is applied, GrShape may canonicalize the dir and index since it
|
||||
// is not germane to the styling any longer.
|
||||
@ -1058,26 +1159,21 @@ void test_make_hairline_path_effect(skiatest::Reporter* reporter, const GEO& geo
|
||||
REPORTER_ASSERT(reporter, peCase.appliedFullStyleShape().style().isSimpleHairline());
|
||||
}
|
||||
|
||||
/**
|
||||
* isNonPath indicates whether the initial shape made from the path is expected to be recognized
|
||||
* as a simpler shape type (e.g. rrect)
|
||||
*/
|
||||
void test_volatile_path(skiatest::Reporter* reporter, const SkPath& path,
|
||||
bool isNonPath) {
|
||||
SkPath vPath(path);
|
||||
void test_volatile_path(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
SkPath vPath = geo.path();
|
||||
vPath.setIsVolatile(true);
|
||||
|
||||
SkPaint dashAndStroke;
|
||||
dashAndStroke.setPathEffect(make_dash());
|
||||
dashAndStroke.setStrokeWidth(2.f);
|
||||
dashAndStroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase volatileCase(vPath, dashAndStroke, reporter);
|
||||
TestCase volatileCase(reporter, vPath, dashAndStroke);
|
||||
// We expect a shape made from a volatile path to have a key iff the shape is recognized
|
||||
// as a specialized geometry.
|
||||
if (isNonPath) {
|
||||
if (geo.isNonPath(dashAndStroke)) {
|
||||
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, reporter);
|
||||
TestCase nonVolatileCase(reporter, geo.path(), dashAndStroke);
|
||||
volatileCase.compare(reporter, nonVolatileCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
} else {
|
||||
// None of the keys should be valid.
|
||||
@ -1088,8 +1184,7 @@ void test_volatile_path(skiatest::Reporter* reporter, const SkPath& path,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename GEO>
|
||||
void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
/**
|
||||
* This path effect returns an empty path.
|
||||
*/
|
||||
@ -1137,8 +1232,7 @@ void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const GEO&
|
||||
REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleShape().isEmpty());
|
||||
}
|
||||
|
||||
template <typename GEO>
|
||||
void test_path_effect_fails(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
void test_path_effect_fails(skiatest::Reporter* reporter, const Geo& geo) {
|
||||
/**
|
||||
* This path effect always fails to apply.
|
||||
*/
|
||||
@ -1203,7 +1297,7 @@ void test_path_effect_fails(skiatest::Reporter* reporter, const GEO& geo) {
|
||||
void test_empty_shape(skiatest::Reporter* reporter) {
|
||||
SkPath emptyPath;
|
||||
SkPaint fill;
|
||||
TestCase fillEmptyCase(emptyPath, fill, reporter);
|
||||
TestCase fillEmptyCase(reporter, emptyPath, fill);
|
||||
REPORTER_ASSERT(reporter, fillEmptyCase.baseShape().isEmpty());
|
||||
REPORTER_ASSERT(reporter, fillEmptyCase.appliedPathEffectShape().isEmpty());
|
||||
REPORTER_ASSERT(reporter, fillEmptyCase.appliedFullStyleShape().isEmpty());
|
||||
@ -1221,7 +1315,7 @@ void test_empty_shape(skiatest::Reporter* reporter) {
|
||||
SkPaint stroke;
|
||||
stroke.setStrokeWidth(2.f);
|
||||
stroke.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase strokeEmptyCase(emptyPath2, stroke, reporter);
|
||||
TestCase strokeEmptyCase(reporter, emptyPath2, stroke);
|
||||
strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// Dashing and stroking an empty path should have no effect
|
||||
@ -1230,20 +1324,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, reporter);
|
||||
TestCase dashAndStrokeEmptyCase(reporter, emptyPath3, dashAndStroke);
|
||||
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, reporter);
|
||||
TestCase dashAndStrokeEmptyRRectCase(reporter, emptyRRect, dashAndStroke);
|
||||
dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// Same for a rect.
|
||||
SkRect emptyRect = SkRect::MakeEmpty();
|
||||
TestCase dashAndStrokeEmptyRectCase(emptyRect, dashAndStroke, reporter);
|
||||
TestCase dashAndStrokeEmptyRectCase(reporter, emptyRect, dashAndStroke);
|
||||
dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
@ -1535,22 +1629,22 @@ void test_lines(skiatest::Reporter* r) {
|
||||
SkPaint dash = stroke;
|
||||
dash.setPathEffect(make_dash());
|
||||
|
||||
TestCase fillAB(lineAB, fill, r);
|
||||
TestCase fillEmpty(SkPath(), fill, r);
|
||||
TestCase fillAB(r, lineAB, fill);
|
||||
TestCase fillEmpty(r, SkPath(), fill);
|
||||
fillAB.compare(r, fillEmpty, TestCase::kAllSame_ComparisonExpecation);
|
||||
REPORTER_ASSERT(r, !fillAB.baseShape().asLine(nullptr, nullptr));
|
||||
|
||||
TestCase strokeAB(lineAB, stroke, r);
|
||||
TestCase strokeBA(lineBA, stroke, r);
|
||||
TestCase strokeAC(lineAC, stroke, r);
|
||||
TestCase strokeAB(r, lineAB, stroke);
|
||||
TestCase strokeBA(r, lineBA, stroke);
|
||||
TestCase strokeAC(r, lineAC, stroke);
|
||||
|
||||
TestCase hairlineAB(lineAB, hairline, r);
|
||||
TestCase hairlineBA(lineBA, hairline, r);
|
||||
TestCase hairlineAC(lineAC, hairline, r);
|
||||
TestCase hairlineAB(r, lineAB, hairline);
|
||||
TestCase hairlineBA(r, lineBA, hairline);
|
||||
TestCase hairlineAC(r, lineAC, hairline);
|
||||
|
||||
TestCase dashAB(lineAB, dash, r);
|
||||
TestCase dashBA(lineBA, dash, r);
|
||||
TestCase dashAC(lineAC, dash, r);
|
||||
TestCase dashAB(r, lineAB, dash);
|
||||
TestCase dashBA(r, lineBA, dash);
|
||||
TestCase dashAC(r, lineAC, dash);
|
||||
|
||||
strokeAB.compare(r, fillAB, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
|
||||
@ -1595,9 +1689,9 @@ void test_lines(skiatest::Reporter* r) {
|
||||
pts[0] == kB && pts[1] == kA);
|
||||
|
||||
|
||||
TestCase strokeInvAB(invLineAB, stroke, r);
|
||||
TestCase hairlineInvAB(invLineAB, hairline, r);
|
||||
TestCase dashInvAB(invLineAB, dash, r);
|
||||
TestCase strokeInvAB(r, invLineAB, stroke);
|
||||
TestCase hairlineInvAB(r, invLineAB, hairline);
|
||||
TestCase dashInvAB(r, invLineAB, dash);
|
||||
strokeInvAB.compare(r, strokeAB, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
hairlineInvAB.compare(r, hairlineAB, TestCase::kAllDifferent_ComparisonExpecation);
|
||||
// Dashing ignores inverse.
|
||||
@ -1633,14 +1727,14 @@ static void test_stroked_lines(skiatest::Reporter* r) {
|
||||
|
||||
SkPaint fill;
|
||||
|
||||
TestCase(linePath, buttCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 4, 6, 5), fill, r),
|
||||
TestCase(r, linePath, buttCap).compare(r, TestCase(r, SkRect::MakeLTRB(2, 4, 6, 5), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
TestCase(linePath, squareCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 2, 6, 7), fill, r),
|
||||
TestCase(r, linePath, squareCap).compare(r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 7), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
TestCase(linePath, roundCap, r).compare(r,
|
||||
TestCase(SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 7), 2, 2), fill, r),
|
||||
TestCase(r, linePath, roundCap).compare(r,
|
||||
TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 7), 2, 2), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// horizontal
|
||||
@ -1648,12 +1742,12 @@ static void test_stroked_lines(skiatest::Reporter* r) {
|
||||
linePath.moveTo(4, 4);
|
||||
linePath.lineTo(5, 4);
|
||||
|
||||
TestCase(linePath, buttCap, r).compare(r, TestCase(SkRect::MakeLTRB(4, 2, 5, 6), fill, r),
|
||||
TestCase(r, linePath, buttCap).compare(r, TestCase(r, SkRect::MakeLTRB(4, 2, 5, 6), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(linePath, squareCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 2, 7, 6), fill, r),
|
||||
TestCase(r, linePath, squareCap).compare(r, TestCase(r, SkRect::MakeLTRB(2, 2, 7, 6), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(linePath, roundCap, r).compare(r,
|
||||
TestCase(SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 7, 6), 2, 2), fill, r),
|
||||
TestCase(r, linePath, roundCap).compare(r,
|
||||
TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 7, 6), 2, 2), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
|
||||
// point
|
||||
@ -1661,183 +1755,135 @@ static void test_stroked_lines(skiatest::Reporter* r) {
|
||||
linePath.moveTo(4, 4);
|
||||
linePath.lineTo(4, 4);
|
||||
|
||||
TestCase(linePath, buttCap, r).compare(r, TestCase(SkRect::MakeEmpty(), fill, r),
|
||||
TestCase(r, linePath, buttCap).compare(r, TestCase(r, SkRect::MakeEmpty(), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(linePath, squareCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 2, 6, 6), fill, r),
|
||||
TestCase(r, linePath, squareCap).compare(r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 6), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
TestCase(linePath, roundCap, r).compare(r,
|
||||
TestCase(SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 6), 2, 2), fill, r),
|
||||
TestCase(r, linePath, roundCap).compare(r,
|
||||
TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 6), 2, 2), fill),
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
|
||||
DEF_TEST(GrShape, reporter) {
|
||||
SkTArray<std::unique_ptr<Geo>> geos;
|
||||
SkTArray<std::unique_ptr<RRectPathGeo>> rrectPathGeos;
|
||||
|
||||
for (auto r : { SkRect::MakeWH(10, 20),
|
||||
SkRect::MakeWH(-10, -20),
|
||||
SkRect::MakeWH(-10, 20),
|
||||
SkRect::MakeWH(10, -20)}) {
|
||||
test_basic(reporter, r);
|
||||
test_scale(reporter, r);
|
||||
test_dash_fill(reporter, r);
|
||||
test_null_dash(reporter, r);
|
||||
// Test modifying various stroke params.
|
||||
test_stroke_param<SkRect, SkScalar>(
|
||||
reporter, r,
|
||||
[](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
|
||||
SkIntToScalar(2), SkIntToScalar(4));
|
||||
test_stroke_join(reporter, r);
|
||||
test_stroke_cap(reporter, r);
|
||||
test_miter_limit(reporter, r);
|
||||
test_path_effect_makes_rrect(reporter, r);
|
||||
test_unknown_path_effect(reporter, r);
|
||||
test_path_effect_makes_empty_shape(reporter, r);
|
||||
test_path_effect_fails(reporter, r);
|
||||
test_make_hairline_path_effect(reporter, r, true);
|
||||
GrShape shape(r);
|
||||
REPORTER_ASSERT(reporter, !shape.asLine(nullptr, nullptr));
|
||||
geos.emplace_back(new RectGeo(r));
|
||||
SkPath rectPath;
|
||||
rectPath.addRect(r);
|
||||
geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
|
||||
PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
|
||||
PathGeo::Invert::kYes));
|
||||
rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
|
||||
PathGeo::Invert::kNo));
|
||||
}
|
||||
|
||||
for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)),
|
||||
SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4),
|
||||
SkRRect::MakeOval(SkRect::MakeWH(20, 20))}) {
|
||||
test_basic(reporter, rr);
|
||||
geos.emplace_back(new RRectGeo(rr));
|
||||
test_rrect(reporter, rr);
|
||||
test_scale(reporter, rr);
|
||||
test_dash_fill(reporter, rr);
|
||||
test_null_dash(reporter, rr);
|
||||
// Test modifying various stroke params.
|
||||
test_stroke_param<SkRRect, SkScalar>(
|
||||
reporter, rr,
|
||||
[](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
|
||||
SkIntToScalar(2), SkIntToScalar(4));
|
||||
test_stroke_join(reporter, rr);
|
||||
test_stroke_cap(reporter, rr);
|
||||
test_miter_limit(reporter, rr);
|
||||
test_path_effect_makes_rrect(reporter, rr);
|
||||
test_unknown_path_effect(reporter, rr);
|
||||
test_path_effect_makes_empty_shape(reporter, rr);
|
||||
test_path_effect_fails(reporter, rr);
|
||||
test_make_hairline_path_effect(reporter, rr, true);
|
||||
GrShape shape(rr);
|
||||
REPORTER_ASSERT(reporter, !shape.asLine(nullptr, nullptr));
|
||||
SkPath rectPath;
|
||||
rectPath.addRRect(rr);
|
||||
geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
|
||||
PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
|
||||
PathGeo::Invert::kYes));
|
||||
rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, rr,
|
||||
RRectPathGeo::RRectForStroke::kYes,
|
||||
PathGeo::Invert::kNo));
|
||||
}
|
||||
|
||||
struct TestPath {
|
||||
TestPath(const SkPath& path, bool isRRectFill, bool isRRectStroke, bool isLine,
|
||||
const SkRRect& rrect)
|
||||
: fPath(path)
|
||||
, fIsRRectForFill(isRRectFill)
|
||||
, fIsRRectForStroke(isRRectStroke)
|
||||
, fIsLine(isLine)
|
||||
, fRRect(rrect) {}
|
||||
SkPath fPath;
|
||||
bool fIsRRectForFill;
|
||||
bool fIsRRectForStroke;
|
||||
bool fIsLine;
|
||||
SkRRect fRRect;
|
||||
};
|
||||
SkTArray<TestPath> paths;
|
||||
|
||||
SkPath circlePath;
|
||||
circlePath.addCircle(10, 10, 10);
|
||||
paths.emplace_back(circlePath, true, true, false, SkRRect::MakeOval(SkRect::MakeWH(20,20)));
|
||||
|
||||
SkPath rectPath;
|
||||
rectPath.addRect(SkRect::MakeWH(10, 10));
|
||||
paths.emplace_back(rectPath, true, true, false, SkRRect::MakeRect(SkRect::MakeWH(10, 10)));
|
||||
|
||||
SkPath openRectPath;
|
||||
openRectPath.moveTo(0, 0);
|
||||
openRectPath.lineTo(10, 0);
|
||||
openRectPath.lineTo(10, 10);
|
||||
openRectPath.lineTo(0, 10);
|
||||
paths.emplace_back(openRectPath, true, false, false, SkRRect::MakeRect(SkRect::MakeWH(10, 10)));
|
||||
geos.emplace_back(new RRectPathGeo(openRectPath, SkRect::MakeWH(10, 10),
|
||||
RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new RRectPathGeo(openRectPath, SkRect::MakeWH(10, 10),
|
||||
RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kYes));
|
||||
rrectPathGeos.emplace_back(new RRectPathGeo(openRectPath, SkRect::MakeWH(10, 10),
|
||||
RRectPathGeo::RRectForStroke::kNo,
|
||||
PathGeo::Invert::kNo));
|
||||
|
||||
SkPath quadPath;
|
||||
quadPath.quadTo(10, 10, 5, 8);
|
||||
paths.emplace_back(quadPath, false, false, false, SkRRect());
|
||||
geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kYes));
|
||||
|
||||
SkPath linePath;
|
||||
linePath.lineTo(10, 10);
|
||||
paths.emplace_back(linePath, false, false, true, SkRRect());
|
||||
geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kYes));
|
||||
|
||||
// Horizontal and vertical paths become rrects when stroked.
|
||||
SkPath vLinePath;
|
||||
vLinePath.lineTo(0, 10);
|
||||
paths.emplace_back(vLinePath, false, false, true, SkRRect());
|
||||
geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kYes));
|
||||
|
||||
SkPath hLinePath;
|
||||
hLinePath.lineTo(10, 0);
|
||||
paths.emplace_back(hLinePath, false, false, true, SkRRect());
|
||||
geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kNo));
|
||||
geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kYes));
|
||||
|
||||
for (auto testPath : paths) {
|
||||
for (bool inverseFill : {false, true}) {
|
||||
if (inverseFill) {
|
||||
if (testPath.fPath.getFillType() == SkPath::kEvenOdd_FillType) {
|
||||
testPath.fPath.setFillType(SkPath::kInverseEvenOdd_FillType);
|
||||
} else {
|
||||
SkASSERT(testPath.fPath.getFillType() == SkPath::kWinding_FillType);
|
||||
testPath.fPath.setFillType(SkPath::kInverseWinding_FillType);
|
||||
}
|
||||
}
|
||||
const SkPath& path = testPath.fPath;
|
||||
test_basic(reporter, path);
|
||||
test_null_dash(reporter, path);
|
||||
test_path_effect_makes_rrect(reporter, path);
|
||||
test_scale(reporter, path);
|
||||
// This test uses a stroking paint, hence use of fIsRRectForStroke
|
||||
test_volatile_path(reporter, path, testPath.fIsRRectForStroke || testPath.fIsLine);
|
||||
test_dash_fill(reporter, path);
|
||||
// Test modifying various stroke params.
|
||||
test_stroke_param<SkPath, SkScalar>(
|
||||
reporter, path,
|
||||
for (int i = 0; i < geos.count(); ++i) {
|
||||
test_basic(reporter, *geos[i]);
|
||||
test_scale(reporter, *geos[i]);
|
||||
test_dash_fill(reporter, *geos[i]);
|
||||
test_null_dash(reporter, *geos[i]);
|
||||
// Test modifying various stroke params.
|
||||
test_stroke_param<SkScalar>(
|
||||
reporter, *geos[i],
|
||||
[](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
|
||||
SkIntToScalar(2), SkIntToScalar(4));
|
||||
test_stroke_join(reporter, path);
|
||||
test_stroke_cap(reporter, path);
|
||||
test_miter_limit(reporter, path);
|
||||
test_unknown_path_effect(reporter, path);
|
||||
test_path_effect_makes_empty_shape(reporter, path);
|
||||
test_path_effect_fails(reporter, path);
|
||||
test_make_hairline_path_effect(reporter, path, testPath.fIsRRectForStroke ||
|
||||
testPath.fIsLine);
|
||||
}
|
||||
test_stroke_join(reporter, *geos[i]);
|
||||
test_stroke_cap(reporter, *geos[i]);
|
||||
test_miter_limit(reporter, *geos[i]);
|
||||
test_path_effect_makes_rrect(reporter, *geos[i]);
|
||||
test_unknown_path_effect(reporter, *geos[i]);
|
||||
test_path_effect_makes_empty_shape(reporter, *geos[i]);
|
||||
test_path_effect_fails(reporter, *geos[i]);
|
||||
test_make_hairline_path_effect(reporter, *geos[i]);
|
||||
test_volatile_path(reporter, *geos[i]);
|
||||
}
|
||||
|
||||
for (auto testPath : paths) {
|
||||
const SkPath& path = testPath.fPath;
|
||||
|
||||
for (int i = 0; i < rrectPathGeos.count(); ++i) {
|
||||
const RRectPathGeo& rrgeo = *rrectPathGeos[i];
|
||||
SkPaint fillPaint;
|
||||
TestCase fillPathCase(path, fillPaint, reporter);
|
||||
TestCase fillPathCase(reporter, rrgeo.path(), fillPaint);
|
||||
SkRRect rrect;
|
||||
REPORTER_ASSERT(reporter, testPath.fIsRRectForFill ==
|
||||
REPORTER_ASSERT(reporter, rrgeo.isNonPath(fillPaint) ==
|
||||
fillPathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
|
||||
nullptr));
|
||||
if (testPath.fIsRRectForFill) {
|
||||
TestCase fillPathCase2(testPath.fPath, fillPaint, reporter);
|
||||
REPORTER_ASSERT(reporter, rrect == testPath.fRRect);
|
||||
TestCase fillRRectCase(rrect, fillPaint, reporter);
|
||||
if (rrgeo.isNonPath(fillPaint)) {
|
||||
TestCase fillPathCase2(reporter, rrgeo.path(), fillPaint);
|
||||
REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
|
||||
TestCase fillRRectCase(reporter, rrect, fillPaint);
|
||||
fillPathCase2.compare(reporter, fillRRectCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
SkPaint strokePaint;
|
||||
strokePaint.setStrokeWidth(3.f);
|
||||
strokePaint.setStyle(SkPaint::kStroke_Style);
|
||||
TestCase strokePathCase(path, strokePaint, reporter);
|
||||
if (testPath.fIsRRectForStroke) {
|
||||
TestCase strokePathCase(reporter, rrgeo.path(), strokePaint);
|
||||
if (rrgeo.isNonPath(strokePaint)) {
|
||||
REPORTER_ASSERT(reporter, strokePathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
if (testPath.fIsRRectForStroke) {
|
||||
REPORTER_ASSERT(reporter, rrect == testPath.fRRect);
|
||||
TestCase strokeRRectCase(rrect, strokePaint, reporter);
|
||||
REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
|
||||
TestCase strokeRRectCase(reporter, rrect, strokePaint);
|
||||
strokePathCase.compare(reporter, strokeRRectCase,
|
||||
TestCase::kAllSame_ComparisonExpecation);
|
||||
}
|
||||
}
|
||||
|
||||
// Test a volatile empty path.
|
||||
test_volatile_path(reporter, SkPath(), true);
|
||||
test_volatile_path(reporter, PathGeo(SkPath(), PathGeo::Invert::kNo));
|
||||
|
||||
test_empty_shape(reporter);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user