1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
9cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
10cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
11cb93a386Sopenharmony_ci#include "include/effects/SkDashPathEffect.h"
12cb93a386Sopenharmony_ci#include "include/pathops/SkPathOps.h"
13cb93a386Sopenharmony_ci#include "src/core/SkPathEffectBase.h"
14cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h"
15cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h"
16cb93a386Sopenharmony_ci#include "tests/Test.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci#include <initializer_list>
19cb93a386Sopenharmony_ci#include <functional>
20cb93a386Sopenharmony_ci#include <memory>
21cb93a386Sopenharmony_ci#include <utility>
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciuint32_t GrStyledShape::testingOnly_getOriginalGenerationID() const {
24cb93a386Sopenharmony_ci    if (const auto* lp = this->originalPathForListeners()) {
25cb93a386Sopenharmony_ci        return lp->getGenerationID();
26cb93a386Sopenharmony_ci    }
27cb93a386Sopenharmony_ci    return SkPath().getGenerationID();
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_cibool GrStyledShape::testingOnly_isPath() const {
31cb93a386Sopenharmony_ci    return fShape.isPath();
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cibool GrStyledShape::testingOnly_isNonVolatilePath() const {
35cb93a386Sopenharmony_ci    return fShape.isPath() && !fShape.path().isVolatile();
36cb93a386Sopenharmony_ci}
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ciusing Key = SkTArray<uint32_t>;
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_cistatic bool make_key(Key* key, const GrStyledShape& shape) {
41cb93a386Sopenharmony_ci    int size = shape.unstyledKeySize();
42cb93a386Sopenharmony_ci    if (size <= 0) {
43cb93a386Sopenharmony_ci        key->reset(0);
44cb93a386Sopenharmony_ci        return false;
45cb93a386Sopenharmony_ci    }
46cb93a386Sopenharmony_ci    SkASSERT(size);
47cb93a386Sopenharmony_ci    key->reset(size);
48cb93a386Sopenharmony_ci    shape.writeUnstyledKey(key->begin());
49cb93a386Sopenharmony_ci    return true;
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cistatic bool paths_fill_same(const SkPath& a, const SkPath& b) {
53cb93a386Sopenharmony_ci    SkPath pathXor;
54cb93a386Sopenharmony_ci    Op(a, b, SkPathOp::kXOR_SkPathOp, &pathXor);
55cb93a386Sopenharmony_ci    return pathXor.isEmpty();
56cb93a386Sopenharmony_ci}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_cistatic bool test_bounds_by_rasterizing(const SkPath& path, const SkRect& bounds) {
59cb93a386Sopenharmony_ci    // We test the bounds by rasterizing the path into a kRes by kRes grid. The bounds is
60cb93a386Sopenharmony_ci    // mapped to the range kRes/4 to 3*kRes/4 in x and y. A difference clip is used to avoid
61cb93a386Sopenharmony_ci    // rendering within the bounds (with a tolerance). Then we render the path and check that
62cb93a386Sopenharmony_ci    // everything got clipped out.
63cb93a386Sopenharmony_ci    static constexpr int kRes = 2000;
64cb93a386Sopenharmony_ci    // This tolerance is in units of 1/kRes fractions of the bounds width/height.
65cb93a386Sopenharmony_ci    static constexpr int kTol = 2;
66cb93a386Sopenharmony_ci    static_assert(kRes % 4 == 0);
67cb93a386Sopenharmony_ci    SkImageInfo info = SkImageInfo::MakeA8(kRes, kRes);
68cb93a386Sopenharmony_ci    sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
69cb93a386Sopenharmony_ci    surface->getCanvas()->clear(0x0);
70cb93a386Sopenharmony_ci    SkRect clip = SkRect::MakeXYWH(kRes/4, kRes/4, kRes/2, kRes/2);
71cb93a386Sopenharmony_ci    SkMatrix matrix = SkMatrix::RectToRect(bounds, clip);
72cb93a386Sopenharmony_ci    clip.outset(SkIntToScalar(kTol), SkIntToScalar(kTol));
73cb93a386Sopenharmony_ci    surface->getCanvas()->clipRect(clip, SkClipOp::kDifference);
74cb93a386Sopenharmony_ci    surface->getCanvas()->concat(matrix);
75cb93a386Sopenharmony_ci    SkPaint whitePaint;
76cb93a386Sopenharmony_ci    whitePaint.setColor(SK_ColorWHITE);
77cb93a386Sopenharmony_ci    surface->getCanvas()->drawPath(path, whitePaint);
78cb93a386Sopenharmony_ci    SkPixmap pixmap;
79cb93a386Sopenharmony_ci    surface->getCanvas()->peekPixels(&pixmap);
80cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_WIN)
81cb93a386Sopenharmony_ci    // The static constexpr version in #else causes cl.exe to crash.
82cb93a386Sopenharmony_ci    const uint8_t* kZeros = reinterpret_cast<uint8_t*>(calloc(kRes, 1));
83cb93a386Sopenharmony_ci#else
84cb93a386Sopenharmony_ci    static constexpr uint8_t kZeros[kRes] = {0};
85cb93a386Sopenharmony_ci#endif
86cb93a386Sopenharmony_ci    for (int y = 0; y < kRes; ++y) {
87cb93a386Sopenharmony_ci        const uint8_t* row = pixmap.addr8(0, y);
88cb93a386Sopenharmony_ci        if (0 != memcmp(kZeros, row, kRes)) {
89cb93a386Sopenharmony_ci            return false;
90cb93a386Sopenharmony_ci        }
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_WIN
93cb93a386Sopenharmony_ci    free(const_cast<uint8_t*>(kZeros));
94cb93a386Sopenharmony_ci#endif
95cb93a386Sopenharmony_ci    return true;
96cb93a386Sopenharmony_ci}
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_cistatic bool can_interchange_winding_and_even_odd_fill(const GrStyledShape& shape) {
99cb93a386Sopenharmony_ci    SkPath path;
100cb93a386Sopenharmony_ci    shape.asPath(&path);
101cb93a386Sopenharmony_ci    if (shape.style().hasNonDashPathEffect()) {
102cb93a386Sopenharmony_ci        return false;
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci    const SkStrokeRec::Style strokeRecStyle = shape.style().strokeRec().getStyle();
105cb93a386Sopenharmony_ci    return strokeRecStyle == SkStrokeRec::kStroke_Style ||
106cb93a386Sopenharmony_ci           strokeRecStyle == SkStrokeRec::kHairline_Style ||
107cb93a386Sopenharmony_ci           (shape.style().isSimpleFill() && path.isConvex());
108cb93a386Sopenharmony_ci}
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_cistatic void check_equivalence(skiatest::Reporter* r, const GrStyledShape& a, const GrStyledShape& b,
111cb93a386Sopenharmony_ci                              const Key& keyA, const Key& keyB) {
112cb93a386Sopenharmony_ci    // GrStyledShape only respects the input winding direction and start point for rrect shapes
113cb93a386Sopenharmony_ci    // when there is a path effect. Thus, if there are two GrStyledShapes representing the same
114cb93a386Sopenharmony_ci    // rrect but one has a path effect in its style and the other doesn't then asPath() and the
115cb93a386Sopenharmony_ci    // unstyled key will differ. GrStyledShape will have canonicalized the direction and start point
116cb93a386Sopenharmony_ci    // for the shape without the path effect. If *both* have path effects then they should have both
117cb93a386Sopenharmony_ci    // preserved the direction and starting point.
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    // The asRRect() output params are all initialized just to silence compiler warnings about
120cb93a386Sopenharmony_ci    // uninitialized variables.
121cb93a386Sopenharmony_ci    SkRRect rrectA = SkRRect::MakeEmpty(), rrectB = SkRRect::MakeEmpty();
122cb93a386Sopenharmony_ci    SkPathDirection dirA = SkPathDirection::kCW, dirB = SkPathDirection::kCW;
123cb93a386Sopenharmony_ci    unsigned startA = ~0U, startB = ~0U;
124cb93a386Sopenharmony_ci    bool invertedA = true, invertedB = true;
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    bool aIsRRect = a.asRRect(&rrectA, &dirA, &startA, &invertedA);
127cb93a386Sopenharmony_ci    bool bIsRRect = b.asRRect(&rrectB, &dirB, &startB, &invertedB);
128cb93a386Sopenharmony_ci    bool aHasPE = a.style().hasPathEffect();
129cb93a386Sopenharmony_ci    bool bHasPE = b.style().hasPathEffect();
130cb93a386Sopenharmony_ci    bool allowSameRRectButDiffStartAndDir = (aIsRRect && bIsRRect) && (aHasPE != bHasPE);
131cb93a386Sopenharmony_ci    // GrStyledShape will close paths with simple fill style.
132cb93a386Sopenharmony_ci    bool allowedClosednessDiff = (a.style().isSimpleFill() != b.style().isSimpleFill());
133cb93a386Sopenharmony_ci    SkPath pathA, pathB;
134cb93a386Sopenharmony_ci    a.asPath(&pathA);
135cb93a386Sopenharmony_ci    b.asPath(&pathB);
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    // Having a dash path effect can allow 'a' but not 'b' to turn a inverse fill type into a
138cb93a386Sopenharmony_ci    // non-inverse fill type  (or vice versa).
139cb93a386Sopenharmony_ci    bool ignoreInversenessDifference = false;
140cb93a386Sopenharmony_ci    if (pathA.isInverseFillType() != pathB.isInverseFillType()) {
141cb93a386Sopenharmony_ci        const GrStyledShape* s1 = pathA.isInverseFillType() ? &a : &b;
142cb93a386Sopenharmony_ci        const GrStyledShape* s2 = pathA.isInverseFillType() ? &b : &a;
143cb93a386Sopenharmony_ci        bool canDropInverse1 = s1->style().isDashed();
144cb93a386Sopenharmony_ci        bool canDropInverse2 = s2->style().isDashed();
145cb93a386Sopenharmony_ci        ignoreInversenessDifference = (canDropInverse1 != canDropInverse2);
146cb93a386Sopenharmony_ci    }
147cb93a386Sopenharmony_ci    bool ignoreWindingVsEvenOdd = false;
148cb93a386Sopenharmony_ci    if (SkPathFillType_ConvertToNonInverse(pathA.getFillType()) !=
149cb93a386Sopenharmony_ci        SkPathFillType_ConvertToNonInverse(pathB.getFillType())) {
150cb93a386Sopenharmony_ci        bool aCanChange = can_interchange_winding_and_even_odd_fill(a);
151cb93a386Sopenharmony_ci        bool bCanChange = can_interchange_winding_and_even_odd_fill(b);
152cb93a386Sopenharmony_ci        if (aCanChange != bCanChange) {
153cb93a386Sopenharmony_ci            ignoreWindingVsEvenOdd = true;
154cb93a386Sopenharmony_ci        }
155cb93a386Sopenharmony_ci    }
156cb93a386Sopenharmony_ci    if (allowSameRRectButDiffStartAndDir) {
157cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, rrectA == rrectB);
158cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, paths_fill_same(pathA, pathB));
159cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, ignoreInversenessDifference || invertedA == invertedB);
160cb93a386Sopenharmony_ci    } else {
161cb93a386Sopenharmony_ci        SkPath pA = pathA;
162cb93a386Sopenharmony_ci        SkPath pB = pathB;
163cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, a.inverseFilled() == pA.isInverseFillType());
164cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, b.inverseFilled() == pB.isInverseFillType());
165cb93a386Sopenharmony_ci        if (ignoreInversenessDifference) {
166cb93a386Sopenharmony_ci            pA.setFillType(SkPathFillType_ConvertToNonInverse(pathA.getFillType()));
167cb93a386Sopenharmony_ci            pB.setFillType(SkPathFillType_ConvertToNonInverse(pathB.getFillType()));
168cb93a386Sopenharmony_ci        }
169cb93a386Sopenharmony_ci        if (ignoreWindingVsEvenOdd) {
170cb93a386Sopenharmony_ci            pA.setFillType(pA.isInverseFillType() ? SkPathFillType::kInverseEvenOdd
171cb93a386Sopenharmony_ci                                                  : SkPathFillType::kEvenOdd);
172cb93a386Sopenharmony_ci            pB.setFillType(pB.isInverseFillType() ? SkPathFillType::kInverseEvenOdd
173cb93a386Sopenharmony_ci                                                  : SkPathFillType::kEvenOdd);
174cb93a386Sopenharmony_ci        }
175cb93a386Sopenharmony_ci        if (!ignoreInversenessDifference && !ignoreWindingVsEvenOdd) {
176cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, keyA == keyB);
177cb93a386Sopenharmony_ci        } else {
178cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, keyA != keyB);
179cb93a386Sopenharmony_ci        }
180cb93a386Sopenharmony_ci        if (allowedClosednessDiff) {
181cb93a386Sopenharmony_ci            // GrStyledShape will close paths with simple fill style. Make the non-filled path
182cb93a386Sopenharmony_ci            // closed so that the comparision will succeed. Make sure both are closed before
183cb93a386Sopenharmony_ci            // comparing.
184cb93a386Sopenharmony_ci            pA.close();
185cb93a386Sopenharmony_ci            pB.close();
186cb93a386Sopenharmony_ci        }
187cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, pA == pB);
188cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, aIsRRect == bIsRRect);
189cb93a386Sopenharmony_ci        if (aIsRRect) {
190cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, rrectA == rrectB);
191cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, dirA == dirB);
192cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, startA == startB);
193cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, ignoreInversenessDifference || invertedA == invertedB);
194cb93a386Sopenharmony_ci        }
195cb93a386Sopenharmony_ci    }
196cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, a.isEmpty() == b.isEmpty());
197cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, allowedClosednessDiff || a.knownToBeClosed() == b.knownToBeClosed());
198cb93a386Sopenharmony_ci    // closedness can affect convexity.
199cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, allowedClosednessDiff || a.knownToBeConvex() == b.knownToBeConvex());
200cb93a386Sopenharmony_ci    if (a.knownToBeConvex()) {
201cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, pathA.isConvex());
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci    if (b.knownToBeConvex()) {
204cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, pathB.isConvex());
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, a.bounds() == b.bounds());
207cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, a.segmentMask() == b.segmentMask());
208cb93a386Sopenharmony_ci    // Init these to suppress warnings.
209cb93a386Sopenharmony_ci    SkPoint pts[4] {{0, 0,}, {0, 0}, {0, 0}, {0, 0}} ;
210cb93a386Sopenharmony_ci    bool invertedLine[2] {true, true};
211cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, a.asLine(pts, &invertedLine[0]) == b.asLine(pts + 2, &invertedLine[1]));
212cb93a386Sopenharmony_ci    // mayBeInverseFilledAfterStyling() is allowed to differ if one has a arbitrary PE and the other
213cb93a386Sopenharmony_ci    // doesn't (since the PE can set any fill type on its output path).
214cb93a386Sopenharmony_ci    // Moreover, dash style explicitly ignores inverseness. So if one is dashed but not the other
215cb93a386Sopenharmony_ci    // then they may disagree about inverseness.
216cb93a386Sopenharmony_ci    if (a.style().hasNonDashPathEffect() == b.style().hasNonDashPathEffect() &&
217cb93a386Sopenharmony_ci        a.style().isDashed() == b.style().isDashed()) {
218cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, a.mayBeInverseFilledAfterStyling() ==
219cb93a386Sopenharmony_ci                           b.mayBeInverseFilledAfterStyling());
220cb93a386Sopenharmony_ci    }
221cb93a386Sopenharmony_ci    if (a.asLine(nullptr, nullptr)) {
222cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, pts[2] == pts[0] && pts[3] == pts[1]);
223cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, ignoreInversenessDifference || invertedLine[0] == invertedLine[1]);
224cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, invertedLine[0] == a.inverseFilled());
225cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, invertedLine[1] == b.inverseFilled());
226cb93a386Sopenharmony_ci    }
227cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, ignoreInversenessDifference || a.inverseFilled() == b.inverseFilled());
228cb93a386Sopenharmony_ci}
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_cistatic void check_original_path_ids(skiatest::Reporter* r, const GrStyledShape& base,
231cb93a386Sopenharmony_ci                                    const GrStyledShape& pe, const GrStyledShape& peStroke,
232cb93a386Sopenharmony_ci                                    const GrStyledShape& full) {
233cb93a386Sopenharmony_ci    bool baseIsNonVolatilePath = base.testingOnly_isNonVolatilePath();
234cb93a386Sopenharmony_ci    bool peIsPath = pe.testingOnly_isPath();
235cb93a386Sopenharmony_ci    bool peStrokeIsPath = peStroke.testingOnly_isPath();
236cb93a386Sopenharmony_ci    bool fullIsPath = full.testingOnly_isPath();
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, peStrokeIsPath == fullIsPath);
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ci    uint32_t baseID = base.testingOnly_getOriginalGenerationID();
241cb93a386Sopenharmony_ci    uint32_t peID = pe.testingOnly_getOriginalGenerationID();
242cb93a386Sopenharmony_ci    uint32_t peStrokeID = peStroke.testingOnly_getOriginalGenerationID();
243cb93a386Sopenharmony_ci    uint32_t fullID = full.testingOnly_getOriginalGenerationID();
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    // All empty paths have the same gen ID
246cb93a386Sopenharmony_ci    uint32_t emptyID = SkPath().getGenerationID();
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_ci    // If we started with a real path, then our genID should match that path's gen ID (and not be
249cb93a386Sopenharmony_ci    // empty). If we started with a simple shape or a volatile path, our original path should have
250cb93a386Sopenharmony_ci    // been reset.
251cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, baseIsNonVolatilePath == (baseID != emptyID));
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci    // For the derived shapes, if they're simple types, their original paths should have been reset
254cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, peIsPath || (peID == emptyID));
255cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, peStrokeIsPath || (peStrokeID == emptyID));
256cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, fullIsPath || (fullID == emptyID));
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ci    if (!peIsPath) {
259cb93a386Sopenharmony_ci        // If the path effect produces a simple shape, then there are no unbroken chains to test
260cb93a386Sopenharmony_ci        return;
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_ci    // From here on, we know that the path effect produced a shape that was a "real" path
264cb93a386Sopenharmony_ci
265cb93a386Sopenharmony_ci    if (baseIsNonVolatilePath) {
266cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, baseID == peID);
267cb93a386Sopenharmony_ci    }
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci    if (peStrokeIsPath) {
270cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, peID == peStrokeID);
271cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, peStrokeID == fullID);
272cb93a386Sopenharmony_ci    }
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci    if (baseIsNonVolatilePath && peStrokeIsPath) {
275cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, baseID == peStrokeID);
276cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, baseID == fullID);
277cb93a386Sopenharmony_ci    }
278cb93a386Sopenharmony_ci}
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_civoid test_inversions(skiatest::Reporter* r, const GrStyledShape& shape, const Key& shapeKey) {
281cb93a386Sopenharmony_ci    GrStyledShape preserve = GrStyledShape::MakeFilled(
282cb93a386Sopenharmony_ci            shape, GrStyledShape::FillInversion::kPreserve);
283cb93a386Sopenharmony_ci    Key preserveKey;
284cb93a386Sopenharmony_ci    make_key(&preserveKey, preserve);
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ci    GrStyledShape flip = GrStyledShape::MakeFilled(shape, GrStyledShape::FillInversion::kFlip);
287cb93a386Sopenharmony_ci    Key flipKey;
288cb93a386Sopenharmony_ci    make_key(&flipKey, flip);
289cb93a386Sopenharmony_ci
290cb93a386Sopenharmony_ci    GrStyledShape inverted = GrStyledShape::MakeFilled(
291cb93a386Sopenharmony_ci            shape, GrStyledShape::FillInversion::kForceInverted);
292cb93a386Sopenharmony_ci    Key invertedKey;
293cb93a386Sopenharmony_ci    make_key(&invertedKey, inverted);
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci    GrStyledShape noninverted = GrStyledShape::MakeFilled(
296cb93a386Sopenharmony_ci            shape, GrStyledShape::FillInversion::kForceNoninverted);
297cb93a386Sopenharmony_ci    Key noninvertedKey;
298cb93a386Sopenharmony_ci    make_key(&noninvertedKey, noninverted);
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_ci    if (invertedKey.count() || noninvertedKey.count()) {
301cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, invertedKey != noninvertedKey);
302cb93a386Sopenharmony_ci    }
303cb93a386Sopenharmony_ci    if (shape.style().isSimpleFill()) {
304cb93a386Sopenharmony_ci        check_equivalence(r, shape, preserve, shapeKey, preserveKey);
305cb93a386Sopenharmony_ci    }
306cb93a386Sopenharmony_ci    if (shape.inverseFilled()) {
307cb93a386Sopenharmony_ci        check_equivalence(r, preserve, inverted, preserveKey, invertedKey);
308cb93a386Sopenharmony_ci        check_equivalence(r, flip, noninverted, flipKey, noninvertedKey);
309cb93a386Sopenharmony_ci    } else {
310cb93a386Sopenharmony_ci        check_equivalence(r, preserve, noninverted, preserveKey, noninvertedKey);
311cb93a386Sopenharmony_ci        check_equivalence(r, flip, inverted, flipKey, invertedKey);
312cb93a386Sopenharmony_ci    }
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_ci    GrStyledShape doubleFlip = GrStyledShape::MakeFilled(flip, GrStyledShape::FillInversion::kFlip);
315cb93a386Sopenharmony_ci    Key doubleFlipKey;
316cb93a386Sopenharmony_ci    make_key(&doubleFlipKey, doubleFlip);
317cb93a386Sopenharmony_ci    // It can be the case that the double flip has no key but preserve does. This happens when the
318cb93a386Sopenharmony_ci    // original shape has an inherited style key. That gets dropped on the first inversion flip.
319cb93a386Sopenharmony_ci    if (preserveKey.count() && !doubleFlipKey.count()) {
320cb93a386Sopenharmony_ci        preserveKey.reset();
321cb93a386Sopenharmony_ci    }
322cb93a386Sopenharmony_ci    check_equivalence(r, preserve, doubleFlip, preserveKey, doubleFlipKey);
323cb93a386Sopenharmony_ci}
324cb93a386Sopenharmony_ci
325cb93a386Sopenharmony_cinamespace {
326cb93a386Sopenharmony_ci/**
327cb93a386Sopenharmony_ci * Geo is a factory for creating a GrStyledShape from another representation. It also answers some
328cb93a386Sopenharmony_ci * questions about expected behavior for GrStyledShape given the inputs.
329cb93a386Sopenharmony_ci */
330cb93a386Sopenharmony_ciclass Geo {
331cb93a386Sopenharmony_cipublic:
332cb93a386Sopenharmony_ci    virtual ~Geo() {}
333cb93a386Sopenharmony_ci    virtual GrStyledShape makeShape(const SkPaint&) const = 0;
334cb93a386Sopenharmony_ci    virtual SkPath path() const = 0;
335cb93a386Sopenharmony_ci    // These functions allow tests to check for special cases where style gets
336cb93a386Sopenharmony_ci    // applied by GrStyledShape in its constructor (without calling GrStyledShape::applyStyle).
337cb93a386Sopenharmony_ci    // These unfortunately rely on knowing details of GrStyledShape's implementation.
338cb93a386Sopenharmony_ci    // These predicates are factored out here to avoid littering the rest of the
339cb93a386Sopenharmony_ci    // test code with GrStyledShape implementation details.
340cb93a386Sopenharmony_ci    virtual bool fillChangesGeom() const { return false; }
341cb93a386Sopenharmony_ci    virtual bool strokeIsConvertedToFill() const { return false; }
342cb93a386Sopenharmony_ci    virtual bool strokeAndFillIsConvertedToFill(const SkPaint&) const { return false; }
343cb93a386Sopenharmony_ci    // Is this something we expect GrStyledShape to recognize as something simpler than a path.
344cb93a386Sopenharmony_ci    virtual bool isNonPath(const SkPaint& paint) const { return true; }
345cb93a386Sopenharmony_ci};
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ciclass RectGeo : public Geo {
348cb93a386Sopenharmony_cipublic:
349cb93a386Sopenharmony_ci    RectGeo(const SkRect& rect) : fRect(rect) {}
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ci    SkPath path() const override {
352cb93a386Sopenharmony_ci        SkPath path;
353cb93a386Sopenharmony_ci        path.addRect(fRect);
354cb93a386Sopenharmony_ci        return path;
355cb93a386Sopenharmony_ci    }
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci    GrStyledShape makeShape(const SkPaint& paint) const override {
358cb93a386Sopenharmony_ci        return GrStyledShape(fRect, paint);
359cb93a386Sopenharmony_ci    }
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_ci    bool strokeAndFillIsConvertedToFill(const SkPaint& paint) const override {
362cb93a386Sopenharmony_ci        SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
363cb93a386Sopenharmony_ci        // Converted to an outset rectangle or round rect
364cb93a386Sopenharmony_ci        return (paint.getStrokeJoin() == SkPaint::kMiter_Join &&
365cb93a386Sopenharmony_ci                paint.getStrokeMiter() >= SK_ScalarSqrt2) ||
366cb93a386Sopenharmony_ci               paint.getStrokeJoin() == SkPaint::kRound_Join;
367cb93a386Sopenharmony_ci    }
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ciprivate:
370cb93a386Sopenharmony_ci    SkRect fRect;
371cb93a386Sopenharmony_ci};
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ciclass RRectGeo : public Geo {
374cb93a386Sopenharmony_cipublic:
375cb93a386Sopenharmony_ci    RRectGeo(const SkRRect& rrect) : fRRect(rrect) {}
376cb93a386Sopenharmony_ci
377cb93a386Sopenharmony_ci    GrStyledShape makeShape(const SkPaint& paint) const override {
378cb93a386Sopenharmony_ci        return GrStyledShape(fRRect, paint);
379cb93a386Sopenharmony_ci    }
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci    SkPath path() const override {
382cb93a386Sopenharmony_ci        SkPath path;
383cb93a386Sopenharmony_ci        path.addRRect(fRRect);
384cb93a386Sopenharmony_ci        return path;
385cb93a386Sopenharmony_ci    }
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ci    bool strokeAndFillIsConvertedToFill(const SkPaint& paint) const override {
388cb93a386Sopenharmony_ci        SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
389cb93a386Sopenharmony_ci        if (fRRect.isRect()) {
390cb93a386Sopenharmony_ci            return RectGeo(fRRect.rect()).strokeAndFillIsConvertedToFill(paint);
391cb93a386Sopenharmony_ci        }
392cb93a386Sopenharmony_ci        return false;
393cb93a386Sopenharmony_ci    }
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ciprivate:
396cb93a386Sopenharmony_ci    SkRRect fRRect;
397cb93a386Sopenharmony_ci};
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ciclass ArcGeo : public Geo {
400cb93a386Sopenharmony_cipublic:
401cb93a386Sopenharmony_ci    ArcGeo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter)
402cb93a386Sopenharmony_ci            : fOval(oval)
403cb93a386Sopenharmony_ci            , fStartAngle(startAngle)
404cb93a386Sopenharmony_ci            , fSweepAngle(sweepAngle)
405cb93a386Sopenharmony_ci            , fUseCenter(useCenter) {}
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_ci    SkPath path() const override {
408cb93a386Sopenharmony_ci        SkPath path;
409cb93a386Sopenharmony_ci        SkPathPriv::CreateDrawArcPath(&path, fOval, fStartAngle, fSweepAngle, fUseCenter, false);
410cb93a386Sopenharmony_ci        return path;
411cb93a386Sopenharmony_ci    }
412cb93a386Sopenharmony_ci
413cb93a386Sopenharmony_ci    GrStyledShape makeShape(const SkPaint& paint) const override {
414cb93a386Sopenharmony_ci        return GrStyledShape::MakeArc(fOval, fStartAngle, fSweepAngle, fUseCenter, GrStyle(paint));
415cb93a386Sopenharmony_ci    }
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci    // GrStyledShape specializes when created from arc params but it doesn't recognize arcs from
418cb93a386Sopenharmony_ci    // SkPath.
419cb93a386Sopenharmony_ci    bool isNonPath(const SkPaint& paint) const override { return false; }
420cb93a386Sopenharmony_ci
421cb93a386Sopenharmony_ciprivate:
422cb93a386Sopenharmony_ci    SkRect fOval;
423cb93a386Sopenharmony_ci    SkScalar fStartAngle;
424cb93a386Sopenharmony_ci    SkScalar fSweepAngle;
425cb93a386Sopenharmony_ci    bool fUseCenter;
426cb93a386Sopenharmony_ci};
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ciclass PathGeo : public Geo {
429cb93a386Sopenharmony_cipublic:
430cb93a386Sopenharmony_ci    enum class Invert { kNo, kYes };
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ci    PathGeo(const SkPath& path, Invert invert) : fPath(path)  {
433cb93a386Sopenharmony_ci        SkASSERT(!path.isInverseFillType());
434cb93a386Sopenharmony_ci        if (Invert::kYes == invert) {
435cb93a386Sopenharmony_ci            if (fPath.getFillType() == SkPathFillType::kEvenOdd) {
436cb93a386Sopenharmony_ci                fPath.setFillType(SkPathFillType::kInverseEvenOdd);
437cb93a386Sopenharmony_ci            } else {
438cb93a386Sopenharmony_ci                SkASSERT(fPath.getFillType() == SkPathFillType::kWinding);
439cb93a386Sopenharmony_ci                fPath.setFillType(SkPathFillType::kInverseWinding);
440cb93a386Sopenharmony_ci            }
441cb93a386Sopenharmony_ci        }
442cb93a386Sopenharmony_ci    }
443cb93a386Sopenharmony_ci
444cb93a386Sopenharmony_ci    GrStyledShape makeShape(const SkPaint& paint) const override {
445cb93a386Sopenharmony_ci        return GrStyledShape(fPath, paint);
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci
448cb93a386Sopenharmony_ci    SkPath path() const override { return fPath; }
449cb93a386Sopenharmony_ci
450cb93a386Sopenharmony_ci    bool fillChangesGeom() const override {
451cb93a386Sopenharmony_ci        // unclosed rects get closed. Lines get turned into empty geometry
452cb93a386Sopenharmony_ci        return this->isUnclosedRect() || fPath.isLine(nullptr);
453cb93a386Sopenharmony_ci    }
454cb93a386Sopenharmony_ci
455cb93a386Sopenharmony_ci    bool strokeIsConvertedToFill() const override {
456cb93a386Sopenharmony_ci        return this->isAxisAlignedLine();
457cb93a386Sopenharmony_ci    }
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ci    bool strokeAndFillIsConvertedToFill(const SkPaint& paint) const override {
460cb93a386Sopenharmony_ci        SkASSERT(paint.getStyle() == SkPaint::kStrokeAndFill_Style);
461cb93a386Sopenharmony_ci        if (this->isAxisAlignedLine()) {
462cb93a386Sopenharmony_ci            // The fill is ignored (zero area) and the stroke is converted to a rrect.
463cb93a386Sopenharmony_ci            return true;
464cb93a386Sopenharmony_ci        }
465cb93a386Sopenharmony_ci        SkRect rect;
466cb93a386Sopenharmony_ci        unsigned start;
467cb93a386Sopenharmony_ci        SkPathDirection dir;
468cb93a386Sopenharmony_ci        if (SkPathPriv::IsSimpleRect(fPath, false, &rect, &dir, &start)) {
469cb93a386Sopenharmony_ci            return RectGeo(rect).strokeAndFillIsConvertedToFill(paint);
470cb93a386Sopenharmony_ci        }
471cb93a386Sopenharmony_ci        return false;
472cb93a386Sopenharmony_ci    }
473cb93a386Sopenharmony_ci
474cb93a386Sopenharmony_ci    bool isNonPath(const SkPaint& paint) const override {
475cb93a386Sopenharmony_ci        return fPath.isLine(nullptr) || fPath.isEmpty();
476cb93a386Sopenharmony_ci    }
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_ciprivate:
479cb93a386Sopenharmony_ci    bool isAxisAlignedLine() const {
480cb93a386Sopenharmony_ci        SkPoint pts[2];
481cb93a386Sopenharmony_ci        if (!fPath.isLine(pts)) {
482cb93a386Sopenharmony_ci            return false;
483cb93a386Sopenharmony_ci        }
484cb93a386Sopenharmony_ci        return pts[0].fX == pts[1].fX || pts[0].fY == pts[1].fY;
485cb93a386Sopenharmony_ci    }
486cb93a386Sopenharmony_ci
487cb93a386Sopenharmony_ci    bool isUnclosedRect() const {
488cb93a386Sopenharmony_ci        bool closed;
489cb93a386Sopenharmony_ci        return fPath.isRect(nullptr, &closed, nullptr) && !closed;
490cb93a386Sopenharmony_ci    }
491cb93a386Sopenharmony_ci
492cb93a386Sopenharmony_ci    SkPath fPath;
493cb93a386Sopenharmony_ci};
494cb93a386Sopenharmony_ci
495cb93a386Sopenharmony_ciclass RRectPathGeo : public PathGeo {
496cb93a386Sopenharmony_cipublic:
497cb93a386Sopenharmony_ci    enum class RRectForStroke { kNo, kYes };
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_ci    RRectPathGeo(const SkPath& path, const SkRRect& equivalentRRect, RRectForStroke rrectForStroke,
500cb93a386Sopenharmony_ci                 Invert invert)
501cb93a386Sopenharmony_ci            : PathGeo(path, invert)
502cb93a386Sopenharmony_ci            , fRRect(equivalentRRect)
503cb93a386Sopenharmony_ci            , fRRectForStroke(rrectForStroke) {}
504cb93a386Sopenharmony_ci
505cb93a386Sopenharmony_ci    RRectPathGeo(const SkPath& path, const SkRect& equivalentRect, RRectForStroke rrectForStroke,
506cb93a386Sopenharmony_ci                 Invert invert)
507cb93a386Sopenharmony_ci            : RRectPathGeo(path, SkRRect::MakeRect(equivalentRect), rrectForStroke, invert) {}
508cb93a386Sopenharmony_ci
509cb93a386Sopenharmony_ci    bool isNonPath(const SkPaint& paint) const override {
510cb93a386Sopenharmony_ci        if (SkPaint::kFill_Style == paint.getStyle() || RRectForStroke::kYes == fRRectForStroke) {
511cb93a386Sopenharmony_ci            return true;
512cb93a386Sopenharmony_ci        }
513cb93a386Sopenharmony_ci        return false;
514cb93a386Sopenharmony_ci    }
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_ci    const SkRRect& rrect() const { return fRRect; }
517cb93a386Sopenharmony_ci
518cb93a386Sopenharmony_ciprivate:
519cb93a386Sopenharmony_ci    SkRRect         fRRect;
520cb93a386Sopenharmony_ci    RRectForStroke  fRRectForStroke;
521cb93a386Sopenharmony_ci};
522cb93a386Sopenharmony_ci
523cb93a386Sopenharmony_ciclass TestCase {
524cb93a386Sopenharmony_cipublic:
525cb93a386Sopenharmony_ci    TestCase(const Geo& geo, const SkPaint& paint, skiatest::Reporter* r,
526cb93a386Sopenharmony_ci             SkScalar scale = SK_Scalar1)
527cb93a386Sopenharmony_ci            : fBase(new GrStyledShape(geo.makeShape(paint))) {
528cb93a386Sopenharmony_ci        this->init(r, scale);
529cb93a386Sopenharmony_ci    }
530cb93a386Sopenharmony_ci
531cb93a386Sopenharmony_ci    template <typename... ShapeArgs>
532cb93a386Sopenharmony_ci    TestCase(skiatest::Reporter* r, ShapeArgs... shapeArgs)
533cb93a386Sopenharmony_ci            : fBase(new GrStyledShape(shapeArgs...)) {
534cb93a386Sopenharmony_ci        this->init(r, SK_Scalar1);
535cb93a386Sopenharmony_ci    }
536cb93a386Sopenharmony_ci
537cb93a386Sopenharmony_ci    TestCase(const GrStyledShape& shape, skiatest::Reporter* r, SkScalar scale = SK_Scalar1)
538cb93a386Sopenharmony_ci            : fBase(new GrStyledShape(shape)) {
539cb93a386Sopenharmony_ci        this->init(r, scale);
540cb93a386Sopenharmony_ci    }
541cb93a386Sopenharmony_ci
542cb93a386Sopenharmony_ci    struct SelfExpectations {
543cb93a386Sopenharmony_ci        bool fPEHasEffect;
544cb93a386Sopenharmony_ci        bool fPEHasValidKey;
545cb93a386Sopenharmony_ci        bool fStrokeApplies;
546cb93a386Sopenharmony_ci    };
547cb93a386Sopenharmony_ci
548cb93a386Sopenharmony_ci    void testExpectations(skiatest::Reporter* reporter, SelfExpectations expectations) const;
549cb93a386Sopenharmony_ci
550cb93a386Sopenharmony_ci    enum ComparisonExpecation {
551cb93a386Sopenharmony_ci        kAllDifferent_ComparisonExpecation,
552cb93a386Sopenharmony_ci        kSameUpToPE_ComparisonExpecation,
553cb93a386Sopenharmony_ci        kSameUpToStroke_ComparisonExpecation,
554cb93a386Sopenharmony_ci        kAllSame_ComparisonExpecation,
555cb93a386Sopenharmony_ci    };
556cb93a386Sopenharmony_ci
557cb93a386Sopenharmony_ci    void compare(skiatest::Reporter*, const TestCase& that, ComparisonExpecation) const;
558cb93a386Sopenharmony_ci
559cb93a386Sopenharmony_ci    const GrStyledShape& baseShape() const { return *fBase; }
560cb93a386Sopenharmony_ci    const GrStyledShape& appliedPathEffectShape() const { return *fAppliedPE; }
561cb93a386Sopenharmony_ci    const GrStyledShape& appliedFullStyleShape() const { return *fAppliedFull; }
562cb93a386Sopenharmony_ci
563cb93a386Sopenharmony_ci    // The returned array's count will be 0 if the key shape has no key.
564cb93a386Sopenharmony_ci    const Key& baseKey() const { return fBaseKey; }
565cb93a386Sopenharmony_ci    const Key& appliedPathEffectKey() const { return fAppliedPEKey; }
566cb93a386Sopenharmony_ci    const Key& appliedFullStyleKey() const { return fAppliedFullKey; }
567cb93a386Sopenharmony_ci    const Key& appliedPathEffectThenStrokeKey() const { return fAppliedPEThenStrokeKey; }
568cb93a386Sopenharmony_ci
569cb93a386Sopenharmony_ciprivate:
570cb93a386Sopenharmony_ci    static void CheckBounds(skiatest::Reporter* r, const GrStyledShape& shape,
571cb93a386Sopenharmony_ci                            const SkRect& bounds) {
572cb93a386Sopenharmony_ci        SkPath path;
573cb93a386Sopenharmony_ci        shape.asPath(&path);
574cb93a386Sopenharmony_ci        // If the bounds are empty, the path ought to be as well.
575cb93a386Sopenharmony_ci        if (bounds.fLeft > bounds.fRight || bounds.fTop > bounds.fBottom) {
576cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, path.isEmpty());
577cb93a386Sopenharmony_ci            return;
578cb93a386Sopenharmony_ci        }
579cb93a386Sopenharmony_ci        if (path.isEmpty()) {
580cb93a386Sopenharmony_ci            return;
581cb93a386Sopenharmony_ci        }
582cb93a386Sopenharmony_ci        // The bounds API explicitly calls out that it does not consider inverseness.
583cb93a386Sopenharmony_ci        SkPath p = path;
584cb93a386Sopenharmony_ci        p.setFillType(SkPathFillType_ConvertToNonInverse(path.getFillType()));
585cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, test_bounds_by_rasterizing(p, bounds));
586cb93a386Sopenharmony_ci    }
587cb93a386Sopenharmony_ci
588cb93a386Sopenharmony_ci    void init(skiatest::Reporter* r, SkScalar scale) {
589cb93a386Sopenharmony_ci        fAppliedPE = std::make_unique<GrStyledShape>();
590cb93a386Sopenharmony_ci        fAppliedPEThenStroke = std::make_unique<GrStyledShape>();
591cb93a386Sopenharmony_ci        fAppliedFull = std::make_unique<GrStyledShape>();
592cb93a386Sopenharmony_ci
593cb93a386Sopenharmony_ci        *fAppliedPE = fBase->applyStyle(GrStyle::Apply::kPathEffectOnly, scale);
594cb93a386Sopenharmony_ci        *fAppliedPEThenStroke =
595cb93a386Sopenharmony_ci                fAppliedPE->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, scale);
596cb93a386Sopenharmony_ci        *fAppliedFull = fBase->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, scale);
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci        make_key(&fBaseKey, *fBase);
599cb93a386Sopenharmony_ci        make_key(&fAppliedPEKey, *fAppliedPE);
600cb93a386Sopenharmony_ci        make_key(&fAppliedPEThenStrokeKey, *fAppliedPEThenStroke);
601cb93a386Sopenharmony_ci        make_key(&fAppliedFullKey, *fAppliedFull);
602cb93a386Sopenharmony_ci
603cb93a386Sopenharmony_ci        // All shapes should report the same "original" path, so that path renderers can get to it
604cb93a386Sopenharmony_ci        // if necessary.
605cb93a386Sopenharmony_ci        check_original_path_ids(r, *fBase, *fAppliedPE, *fAppliedPEThenStroke, *fAppliedFull);
606cb93a386Sopenharmony_ci
607cb93a386Sopenharmony_ci        // Applying the path effect and then the stroke should always be the same as applying
608cb93a386Sopenharmony_ci        // both in one go.
609cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, fAppliedPEThenStrokeKey == fAppliedFullKey);
610cb93a386Sopenharmony_ci        SkPath a, b;
611cb93a386Sopenharmony_ci        fAppliedPEThenStroke->asPath(&a);
612cb93a386Sopenharmony_ci        fAppliedFull->asPath(&b);
613cb93a386Sopenharmony_ci        // If the output of the path effect is a rrect then it is possible for a and b to be
614cb93a386Sopenharmony_ci        // different paths that fill identically. The reason is that fAppliedFull will do this:
615cb93a386Sopenharmony_ci        // base -> apply path effect -> rrect_as_path -> stroke -> stroked_rrect_as_path
616cb93a386Sopenharmony_ci        // fAppliedPEThenStroke will have converted the rrect_as_path back to a rrect. However,
617cb93a386Sopenharmony_ci        // now that there is no longer a path effect, the direction and starting index get
618cb93a386Sopenharmony_ci        // canonicalized before the stroke.
619cb93a386Sopenharmony_ci        if (fAppliedPE->asRRect(nullptr, nullptr, nullptr, nullptr)) {
620cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, paths_fill_same(a, b));
621cb93a386Sopenharmony_ci        } else {
622cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, a == b);
623cb93a386Sopenharmony_ci        }
624cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, fAppliedFull->isEmpty() == fAppliedPEThenStroke->isEmpty());
625cb93a386Sopenharmony_ci
626cb93a386Sopenharmony_ci        SkPath path;
627cb93a386Sopenharmony_ci        fBase->asPath(&path);
628cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, path.isEmpty() == fBase->isEmpty());
629cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, path.getSegmentMasks() == fBase->segmentMask());
630cb93a386Sopenharmony_ci        fAppliedPE->asPath(&path);
631cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, path.isEmpty() == fAppliedPE->isEmpty());
632cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, path.getSegmentMasks() == fAppliedPE->segmentMask());
633cb93a386Sopenharmony_ci        fAppliedFull->asPath(&path);
634cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, path.isEmpty() == fAppliedFull->isEmpty());
635cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, path.getSegmentMasks() == fAppliedFull->segmentMask());
636cb93a386Sopenharmony_ci
637cb93a386Sopenharmony_ci        CheckBounds(r, *fBase, fBase->bounds());
638cb93a386Sopenharmony_ci        CheckBounds(r, *fAppliedPE, fAppliedPE->bounds());
639cb93a386Sopenharmony_ci        CheckBounds(r, *fAppliedPEThenStroke, fAppliedPEThenStroke->bounds());
640cb93a386Sopenharmony_ci        CheckBounds(r, *fAppliedFull, fAppliedFull->bounds());
641cb93a386Sopenharmony_ci        SkRect styledBounds = fBase->styledBounds();
642cb93a386Sopenharmony_ci        CheckBounds(r, *fAppliedFull, styledBounds);
643cb93a386Sopenharmony_ci        styledBounds = fAppliedPE->styledBounds();
644cb93a386Sopenharmony_ci        CheckBounds(r, *fAppliedFull, styledBounds);
645cb93a386Sopenharmony_ci
646cb93a386Sopenharmony_ci        // Check that the same path is produced when style is applied by GrStyledShape and GrStyle.
647cb93a386Sopenharmony_ci        SkPath preStyle;
648cb93a386Sopenharmony_ci        SkPath postPathEffect;
649cb93a386Sopenharmony_ci        SkPath postAllStyle;
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ci        fBase->asPath(&preStyle);
652cb93a386Sopenharmony_ci        SkStrokeRec postPEStrokeRec(SkStrokeRec::kFill_InitStyle);
653cb93a386Sopenharmony_ci        if (fBase->style().applyPathEffectToPath(&postPathEffect, &postPEStrokeRec, preStyle,
654cb93a386Sopenharmony_ci                                                 scale)) {
655cb93a386Sopenharmony_ci            // run postPathEffect through GrStyledShape to get any geometry reductions that would
656cb93a386Sopenharmony_ci            // have occurred to fAppliedPE.
657cb93a386Sopenharmony_ci            GrStyledShape(postPathEffect, GrStyle(postPEStrokeRec, nullptr))
658cb93a386Sopenharmony_ci                    .asPath(&postPathEffect);
659cb93a386Sopenharmony_ci
660cb93a386Sopenharmony_ci            SkPath testPath;
661cb93a386Sopenharmony_ci            fAppliedPE->asPath(&testPath);
662cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, testPath == postPathEffect);
663cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, postPEStrokeRec.hasEqualEffect(fAppliedPE->style().strokeRec()));
664cb93a386Sopenharmony_ci        }
665cb93a386Sopenharmony_ci        SkStrokeRec::InitStyle fillOrHairline;
666cb93a386Sopenharmony_ci        if (fBase->style().applyToPath(&postAllStyle, &fillOrHairline, preStyle, scale)) {
667cb93a386Sopenharmony_ci            SkPath testPath;
668cb93a386Sopenharmony_ci            fAppliedFull->asPath(&testPath);
669cb93a386Sopenharmony_ci            if (fBase->style().hasPathEffect()) {
670cb93a386Sopenharmony_ci                // Because GrStyledShape always does two-stage application when there is a path
671cb93a386Sopenharmony_ci                // effect there may be a reduction/canonicalization step between the path effect and
672cb93a386Sopenharmony_ci                // strokerec not reflected in postAllStyle since it applied both the path effect
673cb93a386Sopenharmony_ci                // and strokerec without analyzing the intermediate path.
674cb93a386Sopenharmony_ci                REPORTER_ASSERT(r, paths_fill_same(postAllStyle, testPath));
675cb93a386Sopenharmony_ci            } else {
676cb93a386Sopenharmony_ci                // Make sure that postAllStyle sees any reductions/canonicalizations that
677cb93a386Sopenharmony_ci                // GrStyledShape would apply.
678cb93a386Sopenharmony_ci                GrStyledShape(postAllStyle, GrStyle(fillOrHairline)).asPath(&postAllStyle);
679cb93a386Sopenharmony_ci                REPORTER_ASSERT(r, testPath == postAllStyle);
680cb93a386Sopenharmony_ci            }
681cb93a386Sopenharmony_ci
682cb93a386Sopenharmony_ci            if (fillOrHairline == SkStrokeRec::kFill_InitStyle) {
683cb93a386Sopenharmony_ci                REPORTER_ASSERT(r, fAppliedFull->style().isSimpleFill());
684cb93a386Sopenharmony_ci            } else {
685cb93a386Sopenharmony_ci                REPORTER_ASSERT(r, fAppliedFull->style().isSimpleHairline());
686cb93a386Sopenharmony_ci            }
687cb93a386Sopenharmony_ci        }
688cb93a386Sopenharmony_ci        test_inversions(r, *fBase, fBaseKey);
689cb93a386Sopenharmony_ci        test_inversions(r, *fAppliedPE, fAppliedPEKey);
690cb93a386Sopenharmony_ci        test_inversions(r, *fAppliedFull, fAppliedFullKey);
691cb93a386Sopenharmony_ci    }
692cb93a386Sopenharmony_ci
693cb93a386Sopenharmony_ci    std::unique_ptr<GrStyledShape> fBase;
694cb93a386Sopenharmony_ci    std::unique_ptr<GrStyledShape> fAppliedPE;
695cb93a386Sopenharmony_ci    std::unique_ptr<GrStyledShape> fAppliedPEThenStroke;
696cb93a386Sopenharmony_ci    std::unique_ptr<GrStyledShape> fAppliedFull;
697cb93a386Sopenharmony_ci
698cb93a386Sopenharmony_ci    Key fBaseKey;
699cb93a386Sopenharmony_ci    Key fAppliedPEKey;
700cb93a386Sopenharmony_ci    Key fAppliedPEThenStrokeKey;
701cb93a386Sopenharmony_ci    Key fAppliedFullKey;
702cb93a386Sopenharmony_ci};
703cb93a386Sopenharmony_ci
704cb93a386Sopenharmony_civoid TestCase::testExpectations(skiatest::Reporter* reporter, SelfExpectations expectations) const {
705cb93a386Sopenharmony_ci    // The base's key should always be valid (unless the path is volatile)
706cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fBaseKey.count());
707cb93a386Sopenharmony_ci    if (expectations.fPEHasEffect) {
708cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, fBaseKey != fAppliedPEKey);
709cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, expectations.fPEHasValidKey == SkToBool(fAppliedPEKey.count()));
710cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey);
711cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, expectations.fPEHasValidKey == SkToBool(fAppliedFullKey.count()));
712cb93a386Sopenharmony_ci        if (expectations.fStrokeApplies && expectations.fPEHasValidKey) {
713cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, fAppliedPEKey != fAppliedFullKey);
714cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, SkToBool(fAppliedFullKey.count()));
715cb93a386Sopenharmony_ci        }
716cb93a386Sopenharmony_ci    } else {
717cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, fBaseKey == fAppliedPEKey);
718cb93a386Sopenharmony_ci        SkPath a, b;
719cb93a386Sopenharmony_ci        fBase->asPath(&a);
720cb93a386Sopenharmony_ci        fAppliedPE->asPath(&b);
721cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, a == b);
722cb93a386Sopenharmony_ci        if (expectations.fStrokeApplies) {
723cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey);
724cb93a386Sopenharmony_ci        } else {
725cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, fBaseKey == fAppliedFullKey);
726cb93a386Sopenharmony_ci        }
727cb93a386Sopenharmony_ci    }
728cb93a386Sopenharmony_ci}
729cb93a386Sopenharmony_ci
730cb93a386Sopenharmony_civoid TestCase::compare(skiatest::Reporter* r, const TestCase& that,
731cb93a386Sopenharmony_ci                       ComparisonExpecation expectation) const {
732cb93a386Sopenharmony_ci    SkPath a, b;
733cb93a386Sopenharmony_ci    switch (expectation) {
734cb93a386Sopenharmony_ci        case kAllDifferent_ComparisonExpecation:
735cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fBaseKey != that.fBaseKey);
736cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fAppliedPEKey != that.fAppliedPEKey);
737cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fAppliedFullKey != that.fAppliedFullKey);
738cb93a386Sopenharmony_ci            break;
739cb93a386Sopenharmony_ci        case kSameUpToPE_ComparisonExpecation:
740cb93a386Sopenharmony_ci            check_equivalence(r, *fBase, *that.fBase, fBaseKey, that.fBaseKey);
741cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fAppliedPEKey != that.fAppliedPEKey);
742cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fAppliedFullKey != that.fAppliedFullKey);
743cb93a386Sopenharmony_ci            break;
744cb93a386Sopenharmony_ci        case kSameUpToStroke_ComparisonExpecation:
745cb93a386Sopenharmony_ci            check_equivalence(r, *fBase, *that.fBase, fBaseKey, that.fBaseKey);
746cb93a386Sopenharmony_ci            check_equivalence(r, *fAppliedPE, *that.fAppliedPE, fAppliedPEKey, that.fAppliedPEKey);
747cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, fAppliedFullKey != that.fAppliedFullKey);
748cb93a386Sopenharmony_ci            break;
749cb93a386Sopenharmony_ci        case kAllSame_ComparisonExpecation:
750cb93a386Sopenharmony_ci            check_equivalence(r, *fBase, *that.fBase, fBaseKey, that.fBaseKey);
751cb93a386Sopenharmony_ci            check_equivalence(r, *fAppliedPE, *that.fAppliedPE, fAppliedPEKey, that.fAppliedPEKey);
752cb93a386Sopenharmony_ci            check_equivalence(r, *fAppliedFull, *that.fAppliedFull, fAppliedFullKey,
753cb93a386Sopenharmony_ci                              that.fAppliedFullKey);
754cb93a386Sopenharmony_ci            break;
755cb93a386Sopenharmony_ci    }
756cb93a386Sopenharmony_ci}
757cb93a386Sopenharmony_ci}  // namespace
758cb93a386Sopenharmony_ci
759cb93a386Sopenharmony_cistatic sk_sp<SkPathEffect> make_dash() {
760cb93a386Sopenharmony_ci    static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f };
761cb93a386Sopenharmony_ci    static const SkScalar kPhase = 0.75;
762cb93a386Sopenharmony_ci    return SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), kPhase);
763cb93a386Sopenharmony_ci}
764cb93a386Sopenharmony_ci
765cb93a386Sopenharmony_cistatic sk_sp<SkPathEffect> make_null_dash() {
766cb93a386Sopenharmony_ci    static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0};
767cb93a386Sopenharmony_ci    return SkDashPathEffect::Make(kNullIntervals, SK_ARRAY_COUNT(kNullIntervals), 0.f);
768cb93a386Sopenharmony_ci}
769cb93a386Sopenharmony_ci
770cb93a386Sopenharmony_ci// We make enough TestCases, and they're large enough, that on Google3 builds we exceed
771cb93a386Sopenharmony_ci// the maximum stack frame limit.  make_TestCase() moves those temporaries over to the heap.
772cb93a386Sopenharmony_citemplate <typename... Args>
773cb93a386Sopenharmony_cistatic std::unique_ptr<TestCase> make_TestCase(Args&&... args) {
774cb93a386Sopenharmony_ci    return std::make_unique<TestCase>( std::forward<Args>(args)... );
775cb93a386Sopenharmony_ci}
776cb93a386Sopenharmony_ci
777cb93a386Sopenharmony_cistatic void test_basic(skiatest::Reporter* reporter, const Geo& geo) {
778cb93a386Sopenharmony_ci    sk_sp<SkPathEffect> dashPE = make_dash();
779cb93a386Sopenharmony_ci
780cb93a386Sopenharmony_ci    TestCase::SelfExpectations expectations;
781cb93a386Sopenharmony_ci    SkPaint fill;
782cb93a386Sopenharmony_ci
783cb93a386Sopenharmony_ci    TestCase fillCase(geo, fill, reporter);
784cb93a386Sopenharmony_ci    expectations.fPEHasEffect = false;
785cb93a386Sopenharmony_ci    expectations.fPEHasValidKey = false;
786cb93a386Sopenharmony_ci    expectations.fStrokeApplies = false;
787cb93a386Sopenharmony_ci    fillCase.testExpectations(reporter, expectations);
788cb93a386Sopenharmony_ci    // Test that another GrStyledShape instance built from the same primitive is the same.
789cb93a386Sopenharmony_ci    make_TestCase(geo, fill, reporter)
790cb93a386Sopenharmony_ci        ->compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
791cb93a386Sopenharmony_ci
792cb93a386Sopenharmony_ci    SkPaint stroke2RoundBevel;
793cb93a386Sopenharmony_ci    stroke2RoundBevel.setStyle(SkPaint::kStroke_Style);
794cb93a386Sopenharmony_ci    stroke2RoundBevel.setStrokeCap(SkPaint::kRound_Cap);
795cb93a386Sopenharmony_ci    stroke2RoundBevel.setStrokeJoin(SkPaint::kBevel_Join);
796cb93a386Sopenharmony_ci    stroke2RoundBevel.setStrokeWidth(2.f);
797cb93a386Sopenharmony_ci    TestCase stroke2RoundBevelCase(geo, stroke2RoundBevel, reporter);
798cb93a386Sopenharmony_ci    expectations.fPEHasValidKey = true;
799cb93a386Sopenharmony_ci    expectations.fPEHasEffect = false;
800cb93a386Sopenharmony_ci    expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
801cb93a386Sopenharmony_ci    stroke2RoundBevelCase.testExpectations(reporter, expectations);
802cb93a386Sopenharmony_ci    make_TestCase(geo, stroke2RoundBevel, reporter)
803cb93a386Sopenharmony_ci        ->compare(reporter, stroke2RoundBevelCase, TestCase::kAllSame_ComparisonExpecation);
804cb93a386Sopenharmony_ci
805cb93a386Sopenharmony_ci    SkPaint stroke2RoundBevelDash = stroke2RoundBevel;
806cb93a386Sopenharmony_ci    stroke2RoundBevelDash.setPathEffect(make_dash());
807cb93a386Sopenharmony_ci    TestCase stroke2RoundBevelDashCase(geo, stroke2RoundBevelDash, reporter);
808cb93a386Sopenharmony_ci    expectations.fPEHasValidKey = true;
809cb93a386Sopenharmony_ci    expectations.fPEHasEffect = true;
810cb93a386Sopenharmony_ci    expectations.fStrokeApplies = true;
811cb93a386Sopenharmony_ci    stroke2RoundBevelDashCase.testExpectations(reporter, expectations);
812cb93a386Sopenharmony_ci    make_TestCase(geo, stroke2RoundBevelDash, reporter)
813cb93a386Sopenharmony_ci        ->compare(reporter, stroke2RoundBevelDashCase, TestCase::kAllSame_ComparisonExpecation);
814cb93a386Sopenharmony_ci
815cb93a386Sopenharmony_ci    if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
816cb93a386Sopenharmony_ci        fillCase.compare(reporter, stroke2RoundBevelCase,
817cb93a386Sopenharmony_ci                         TestCase::kAllDifferent_ComparisonExpecation);
818cb93a386Sopenharmony_ci        fillCase.compare(reporter, stroke2RoundBevelDashCase,
819cb93a386Sopenharmony_ci                         TestCase::kAllDifferent_ComparisonExpecation);
820cb93a386Sopenharmony_ci    } else {
821cb93a386Sopenharmony_ci        fillCase.compare(reporter, stroke2RoundBevelCase,
822cb93a386Sopenharmony_ci                         TestCase::kSameUpToStroke_ComparisonExpecation);
823cb93a386Sopenharmony_ci        fillCase.compare(reporter, stroke2RoundBevelDashCase,
824cb93a386Sopenharmony_ci                         TestCase::kSameUpToPE_ComparisonExpecation);
825cb93a386Sopenharmony_ci    }
826cb93a386Sopenharmony_ci    if (geo.strokeIsConvertedToFill()) {
827cb93a386Sopenharmony_ci        stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase,
828cb93a386Sopenharmony_ci                                      TestCase::kAllDifferent_ComparisonExpecation);
829cb93a386Sopenharmony_ci    } else {
830cb93a386Sopenharmony_ci        stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase,
831cb93a386Sopenharmony_ci                                      TestCase::kSameUpToPE_ComparisonExpecation);
832cb93a386Sopenharmony_ci    }
833cb93a386Sopenharmony_ci
834cb93a386Sopenharmony_ci    // Stroke and fill cases
835cb93a386Sopenharmony_ci    SkPaint stroke2RoundBevelAndFill = stroke2RoundBevel;
836cb93a386Sopenharmony_ci    stroke2RoundBevelAndFill.setStyle(SkPaint::kStrokeAndFill_Style);
837cb93a386Sopenharmony_ci    TestCase stroke2RoundBevelAndFillCase(geo, stroke2RoundBevelAndFill, reporter);
838cb93a386Sopenharmony_ci    expectations.fPEHasValidKey = true;
839cb93a386Sopenharmony_ci    expectations.fPEHasEffect = false;
840cb93a386Sopenharmony_ci    expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
841cb93a386Sopenharmony_ci    stroke2RoundBevelAndFillCase.testExpectations(reporter, expectations);
842cb93a386Sopenharmony_ci    make_TestCase(geo, stroke2RoundBevelAndFill, reporter)->compare(
843cb93a386Sopenharmony_ci            reporter, stroke2RoundBevelAndFillCase, TestCase::kAllSame_ComparisonExpecation);
844cb93a386Sopenharmony_ci
845cb93a386Sopenharmony_ci    SkPaint stroke2RoundBevelAndFillDash = stroke2RoundBevelDash;
846cb93a386Sopenharmony_ci    stroke2RoundBevelAndFillDash.setStyle(SkPaint::kStrokeAndFill_Style);
847cb93a386Sopenharmony_ci    TestCase stroke2RoundBevelAndFillDashCase(geo, stroke2RoundBevelAndFillDash, reporter);
848cb93a386Sopenharmony_ci    expectations.fPEHasValidKey = true;
849cb93a386Sopenharmony_ci    expectations.fPEHasEffect = false;
850cb93a386Sopenharmony_ci    expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
851cb93a386Sopenharmony_ci    stroke2RoundBevelAndFillDashCase.testExpectations(reporter, expectations);
852cb93a386Sopenharmony_ci    make_TestCase(geo, stroke2RoundBevelAndFillDash, reporter)->compare(
853cb93a386Sopenharmony_ci        reporter, stroke2RoundBevelAndFillDashCase, TestCase::kAllSame_ComparisonExpecation);
854cb93a386Sopenharmony_ci    stroke2RoundBevelAndFillDashCase.compare(reporter, stroke2RoundBevelAndFillCase,
855cb93a386Sopenharmony_ci                                             TestCase::kAllSame_ComparisonExpecation);
856cb93a386Sopenharmony_ci
857cb93a386Sopenharmony_ci    SkPaint hairline;
858cb93a386Sopenharmony_ci    hairline.setStyle(SkPaint::kStroke_Style);
859cb93a386Sopenharmony_ci    hairline.setStrokeWidth(0.f);
860cb93a386Sopenharmony_ci    TestCase hairlineCase(geo, hairline, reporter);
861cb93a386Sopenharmony_ci    // Since hairline style doesn't change the SkPath data, it is keyed identically to fill (except
862cb93a386Sopenharmony_ci    // in the line and unclosed rect cases).
863cb93a386Sopenharmony_ci    if (geo.fillChangesGeom()) {
864cb93a386Sopenharmony_ci        hairlineCase.compare(reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
865cb93a386Sopenharmony_ci    } else {
866cb93a386Sopenharmony_ci        hairlineCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
867cb93a386Sopenharmony_ci    }
868cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, hairlineCase.baseShape().style().isSimpleHairline());
869cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, hairlineCase.appliedFullStyleShape().style().isSimpleHairline());
870cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, hairlineCase.appliedPathEffectShape().style().isSimpleHairline());
871cb93a386Sopenharmony_ci
872cb93a386Sopenharmony_ci}
873cb93a386Sopenharmony_ci
874cb93a386Sopenharmony_cistatic void test_scale(skiatest::Reporter* reporter, const Geo& geo) {
875cb93a386Sopenharmony_ci    sk_sp<SkPathEffect> dashPE = make_dash();
876cb93a386Sopenharmony_ci
877cb93a386Sopenharmony_ci    static const SkScalar kS1 = 1.f;
878cb93a386Sopenharmony_ci    static const SkScalar kS2 = 2.f;
879cb93a386Sopenharmony_ci
880cb93a386Sopenharmony_ci    SkPaint fill;
881cb93a386Sopenharmony_ci    TestCase fillCase1(geo, fill, reporter, kS1);
882cb93a386Sopenharmony_ci    TestCase fillCase2(geo, fill, reporter, kS2);
883cb93a386Sopenharmony_ci    // Scale doesn't affect fills.
884cb93a386Sopenharmony_ci    fillCase1.compare(reporter, fillCase2, TestCase::kAllSame_ComparisonExpecation);
885cb93a386Sopenharmony_ci
886cb93a386Sopenharmony_ci    SkPaint hairline;
887cb93a386Sopenharmony_ci    hairline.setStyle(SkPaint::kStroke_Style);
888cb93a386Sopenharmony_ci    hairline.setStrokeWidth(0.f);
889cb93a386Sopenharmony_ci    TestCase hairlineCase1(geo, hairline, reporter, kS1);
890cb93a386Sopenharmony_ci    TestCase hairlineCase2(geo, hairline, reporter, kS2);
891cb93a386Sopenharmony_ci    // Scale doesn't affect hairlines.
892cb93a386Sopenharmony_ci    hairlineCase1.compare(reporter, hairlineCase2, TestCase::kAllSame_ComparisonExpecation);
893cb93a386Sopenharmony_ci
894cb93a386Sopenharmony_ci    SkPaint stroke;
895cb93a386Sopenharmony_ci    stroke.setStyle(SkPaint::kStroke_Style);
896cb93a386Sopenharmony_ci    stroke.setStrokeWidth(2.f);
897cb93a386Sopenharmony_ci    TestCase strokeCase1(geo, stroke, reporter, kS1);
898cb93a386Sopenharmony_ci    TestCase strokeCase2(geo, stroke, reporter, kS2);
899cb93a386Sopenharmony_ci    // Scale affects the stroke
900cb93a386Sopenharmony_ci    if (geo.strokeIsConvertedToFill()) {
901cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !strokeCase1.baseShape().style().applies());
902cb93a386Sopenharmony_ci        strokeCase1.compare(reporter, strokeCase2, TestCase::kAllSame_ComparisonExpecation);
903cb93a386Sopenharmony_ci    } else {
904cb93a386Sopenharmony_ci        strokeCase1.compare(reporter, strokeCase2, TestCase::kSameUpToStroke_ComparisonExpecation);
905cb93a386Sopenharmony_ci    }
906cb93a386Sopenharmony_ci
907cb93a386Sopenharmony_ci    SkPaint strokeDash = stroke;
908cb93a386Sopenharmony_ci    strokeDash.setPathEffect(make_dash());
909cb93a386Sopenharmony_ci    TestCase strokeDashCase1(geo, strokeDash, reporter, kS1);
910cb93a386Sopenharmony_ci    TestCase strokeDashCase2(geo, strokeDash, reporter, kS2);
911cb93a386Sopenharmony_ci    // Scale affects the dash and the stroke.
912cb93a386Sopenharmony_ci    strokeDashCase1.compare(reporter, strokeDashCase2,
913cb93a386Sopenharmony_ci                            TestCase::kSameUpToPE_ComparisonExpecation);
914cb93a386Sopenharmony_ci
915cb93a386Sopenharmony_ci    // Stroke and fill cases
916cb93a386Sopenharmony_ci    SkPaint strokeAndFill = stroke;
917cb93a386Sopenharmony_ci    strokeAndFill.setStyle(SkPaint::kStrokeAndFill_Style);
918cb93a386Sopenharmony_ci    TestCase strokeAndFillCase1(geo, strokeAndFill, reporter, kS1);
919cb93a386Sopenharmony_ci    TestCase strokeAndFillCase2(geo, strokeAndFill, reporter, kS2);
920cb93a386Sopenharmony_ci    SkPaint strokeAndFillDash = strokeDash;
921cb93a386Sopenharmony_ci    strokeAndFillDash.setStyle(SkPaint::kStrokeAndFill_Style);
922cb93a386Sopenharmony_ci    // Dash is ignored for stroke and fill
923cb93a386Sopenharmony_ci    TestCase strokeAndFillDashCase1(geo, strokeAndFillDash, reporter, kS1);
924cb93a386Sopenharmony_ci    TestCase strokeAndFillDashCase2(geo, strokeAndFillDash, reporter, kS2);
925cb93a386Sopenharmony_ci    // Scale affects the stroke, but check to make sure this didn't become a simpler shape (e.g.
926cb93a386Sopenharmony_ci    // stroke-and-filled rect can become a rect), in which case the scale shouldn't matter and the
927cb93a386Sopenharmony_ci    // geometries should agree.
928cb93a386Sopenharmony_ci    if (geo.strokeAndFillIsConvertedToFill(strokeAndFillDash)) {
929cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !strokeAndFillCase1.baseShape().style().applies());
930cb93a386Sopenharmony_ci        strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
931cb93a386Sopenharmony_ci                                   TestCase::kAllSame_ComparisonExpecation);
932cb93a386Sopenharmony_ci        strokeAndFillDashCase1.compare(reporter, strokeAndFillDashCase2,
933cb93a386Sopenharmony_ci                                       TestCase::kAllSame_ComparisonExpecation);
934cb93a386Sopenharmony_ci    } else {
935cb93a386Sopenharmony_ci        strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
936cb93a386Sopenharmony_ci                                   TestCase::kSameUpToStroke_ComparisonExpecation);
937cb93a386Sopenharmony_ci    }
938cb93a386Sopenharmony_ci    strokeAndFillDashCase1.compare(reporter, strokeAndFillCase1,
939cb93a386Sopenharmony_ci                                   TestCase::kAllSame_ComparisonExpecation);
940cb93a386Sopenharmony_ci    strokeAndFillDashCase2.compare(reporter, strokeAndFillCase2,
941cb93a386Sopenharmony_ci                                   TestCase::kAllSame_ComparisonExpecation);
942cb93a386Sopenharmony_ci}
943cb93a386Sopenharmony_ci
944cb93a386Sopenharmony_citemplate <typename T>
945cb93a386Sopenharmony_cistatic void test_stroke_param_impl(skiatest::Reporter* reporter, const Geo& geo,
946cb93a386Sopenharmony_ci                                   std::function<void(SkPaint*, T)> setter, T a, T b,
947cb93a386Sopenharmony_ci                                   bool paramAffectsStroke,
948cb93a386Sopenharmony_ci                                   bool paramAffectsDashAndStroke) {
949cb93a386Sopenharmony_ci    // Set the stroke width so that we don't get hairline. However, call the setter afterward so
950cb93a386Sopenharmony_ci    // that it can override the stroke width.
951cb93a386Sopenharmony_ci    SkPaint strokeA;
952cb93a386Sopenharmony_ci    strokeA.setStyle(SkPaint::kStroke_Style);
953cb93a386Sopenharmony_ci    strokeA.setStrokeWidth(2.f);
954cb93a386Sopenharmony_ci    setter(&strokeA, a);
955cb93a386Sopenharmony_ci    SkPaint strokeB;
956cb93a386Sopenharmony_ci    strokeB.setStyle(SkPaint::kStroke_Style);
957cb93a386Sopenharmony_ci    strokeB.setStrokeWidth(2.f);
958cb93a386Sopenharmony_ci    setter(&strokeB, b);
959cb93a386Sopenharmony_ci
960cb93a386Sopenharmony_ci    TestCase strokeACase(geo, strokeA, reporter);
961cb93a386Sopenharmony_ci    TestCase strokeBCase(geo, strokeB, reporter);
962cb93a386Sopenharmony_ci    if (paramAffectsStroke) {
963cb93a386Sopenharmony_ci        // If stroking is immediately incorporated into a geometric transformation then the base
964cb93a386Sopenharmony_ci        // shapes will differ.
965cb93a386Sopenharmony_ci        if (geo.strokeIsConvertedToFill()) {
966cb93a386Sopenharmony_ci            strokeACase.compare(reporter, strokeBCase,
967cb93a386Sopenharmony_ci                                TestCase::kAllDifferent_ComparisonExpecation);
968cb93a386Sopenharmony_ci        } else {
969cb93a386Sopenharmony_ci            strokeACase.compare(reporter, strokeBCase,
970cb93a386Sopenharmony_ci                                TestCase::kSameUpToStroke_ComparisonExpecation);
971cb93a386Sopenharmony_ci        }
972cb93a386Sopenharmony_ci    } else {
973cb93a386Sopenharmony_ci        strokeACase.compare(reporter, strokeBCase, TestCase::kAllSame_ComparisonExpecation);
974cb93a386Sopenharmony_ci    }
975cb93a386Sopenharmony_ci
976cb93a386Sopenharmony_ci    SkPaint strokeAndFillA = strokeA;
977cb93a386Sopenharmony_ci    SkPaint strokeAndFillB = strokeB;
978cb93a386Sopenharmony_ci    strokeAndFillA.setStyle(SkPaint::kStrokeAndFill_Style);
979cb93a386Sopenharmony_ci    strokeAndFillB.setStyle(SkPaint::kStrokeAndFill_Style);
980cb93a386Sopenharmony_ci    TestCase strokeAndFillACase(geo, strokeAndFillA, reporter);
981cb93a386Sopenharmony_ci    TestCase strokeAndFillBCase(geo, strokeAndFillB, reporter);
982cb93a386Sopenharmony_ci    if (paramAffectsStroke) {
983cb93a386Sopenharmony_ci        // If stroking is immediately incorporated into a geometric transformation then the base
984cb93a386Sopenharmony_ci        // shapes will differ.
985cb93a386Sopenharmony_ci        if (geo.strokeAndFillIsConvertedToFill(strokeAndFillA) ||
986cb93a386Sopenharmony_ci            geo.strokeAndFillIsConvertedToFill(strokeAndFillB)) {
987cb93a386Sopenharmony_ci            strokeAndFillACase.compare(reporter, strokeAndFillBCase,
988cb93a386Sopenharmony_ci                                       TestCase::kAllDifferent_ComparisonExpecation);
989cb93a386Sopenharmony_ci        } else {
990cb93a386Sopenharmony_ci            strokeAndFillACase.compare(reporter, strokeAndFillBCase,
991cb93a386Sopenharmony_ci                                       TestCase::kSameUpToStroke_ComparisonExpecation);
992cb93a386Sopenharmony_ci        }
993cb93a386Sopenharmony_ci    } else {
994cb93a386Sopenharmony_ci        strokeAndFillACase.compare(reporter, strokeAndFillBCase,
995cb93a386Sopenharmony_ci                                   TestCase::kAllSame_ComparisonExpecation);
996cb93a386Sopenharmony_ci    }
997cb93a386Sopenharmony_ci
998cb93a386Sopenharmony_ci    // Make sure stroking params don't affect fill style.
999cb93a386Sopenharmony_ci    SkPaint fillA = strokeA, fillB = strokeB;
1000cb93a386Sopenharmony_ci    fillA.setStyle(SkPaint::kFill_Style);
1001cb93a386Sopenharmony_ci    fillB.setStyle(SkPaint::kFill_Style);
1002cb93a386Sopenharmony_ci    TestCase fillACase(geo, fillA, reporter);
1003cb93a386Sopenharmony_ci    TestCase fillBCase(geo, fillB, reporter);
1004cb93a386Sopenharmony_ci    fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecation);
1005cb93a386Sopenharmony_ci
1006cb93a386Sopenharmony_ci    // Make sure just applying the dash but not stroke gives the same key for both stroking
1007cb93a386Sopenharmony_ci    // variations.
1008cb93a386Sopenharmony_ci    SkPaint dashA = strokeA, dashB = strokeB;
1009cb93a386Sopenharmony_ci    dashA.setPathEffect(make_dash());
1010cb93a386Sopenharmony_ci    dashB.setPathEffect(make_dash());
1011cb93a386Sopenharmony_ci    TestCase dashACase(geo, dashA, reporter);
1012cb93a386Sopenharmony_ci    TestCase dashBCase(geo, dashB, reporter);
1013cb93a386Sopenharmony_ci    if (paramAffectsDashAndStroke) {
1014cb93a386Sopenharmony_ci        dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1015cb93a386Sopenharmony_ci    } else {
1016cb93a386Sopenharmony_ci        dashACase.compare(reporter, dashBCase, TestCase::kAllSame_ComparisonExpecation);
1017cb93a386Sopenharmony_ci    }
1018cb93a386Sopenharmony_ci}
1019cb93a386Sopenharmony_ci
1020cb93a386Sopenharmony_citemplate <typename T>
1021cb93a386Sopenharmony_cistatic void test_stroke_param(skiatest::Reporter* reporter, const Geo& geo,
1022cb93a386Sopenharmony_ci                              std::function<void(SkPaint*, T)> setter, T a, T b) {
1023cb93a386Sopenharmony_ci    test_stroke_param_impl(reporter, geo, setter, a, b, true, true);
1024cb93a386Sopenharmony_ci};
1025cb93a386Sopenharmony_ci
1026cb93a386Sopenharmony_cistatic void test_stroke_cap(skiatest::Reporter* reporter, const Geo& geo) {
1027cb93a386Sopenharmony_ci    SkPaint hairline;
1028cb93a386Sopenharmony_ci    hairline.setStrokeWidth(0);
1029cb93a386Sopenharmony_ci    hairline.setStyle(SkPaint::kStroke_Style);
1030cb93a386Sopenharmony_ci    GrStyledShape shape = geo.makeShape(hairline);
1031cb93a386Sopenharmony_ci    // The cap should only affect shapes that may be open.
1032cb93a386Sopenharmony_ci    bool affectsStroke = !shape.knownToBeClosed();
1033cb93a386Sopenharmony_ci    // Dashing adds ends that need caps.
1034cb93a386Sopenharmony_ci    bool affectsDashAndStroke = true;
1035cb93a386Sopenharmony_ci    test_stroke_param_impl<SkPaint::Cap>(
1036cb93a386Sopenharmony_ci        reporter,
1037cb93a386Sopenharmony_ci        geo,
1038cb93a386Sopenharmony_ci        [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);},
1039cb93a386Sopenharmony_ci        SkPaint::kButt_Cap, SkPaint::kRound_Cap,
1040cb93a386Sopenharmony_ci        affectsStroke,
1041cb93a386Sopenharmony_ci        affectsDashAndStroke);
1042cb93a386Sopenharmony_ci};
1043cb93a386Sopenharmony_ci
1044cb93a386Sopenharmony_cistatic bool shape_known_not_to_have_joins(const GrStyledShape& shape) {
1045cb93a386Sopenharmony_ci    return shape.asLine(nullptr, nullptr) || shape.isEmpty();
1046cb93a386Sopenharmony_ci}
1047cb93a386Sopenharmony_ci
1048cb93a386Sopenharmony_cistatic void test_stroke_join(skiatest::Reporter* reporter, const Geo& geo) {
1049cb93a386Sopenharmony_ci    SkPaint hairline;
1050cb93a386Sopenharmony_ci    hairline.setStrokeWidth(0);
1051cb93a386Sopenharmony_ci    hairline.setStyle(SkPaint::kStroke_Style);
1052cb93a386Sopenharmony_ci    GrStyledShape shape = geo.makeShape(hairline);
1053cb93a386Sopenharmony_ci    // GrStyledShape recognizes certain types don't have joins and will prevent the join type from
1054cb93a386Sopenharmony_ci    // affecting the style key.
1055cb93a386Sopenharmony_ci    // Dashing doesn't add additional joins. However, GrStyledShape currently loses track of this
1056cb93a386Sopenharmony_ci    // after applying the dash.
1057cb93a386Sopenharmony_ci    bool affectsStroke = !shape_known_not_to_have_joins(shape);
1058cb93a386Sopenharmony_ci    test_stroke_param_impl<SkPaint::Join>(
1059cb93a386Sopenharmony_ci            reporter,
1060cb93a386Sopenharmony_ci            geo,
1061cb93a386Sopenharmony_ci            [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
1062cb93a386Sopenharmony_ci            SkPaint::kRound_Join, SkPaint::kBevel_Join,
1063cb93a386Sopenharmony_ci            affectsStroke, true);
1064cb93a386Sopenharmony_ci};
1065cb93a386Sopenharmony_ci
1066cb93a386Sopenharmony_cistatic void test_miter_limit(skiatest::Reporter* reporter, const Geo& geo) {
1067cb93a386Sopenharmony_ci    auto setMiterJoinAndLimit = [](SkPaint* p, SkScalar miter) {
1068cb93a386Sopenharmony_ci        p->setStrokeJoin(SkPaint::kMiter_Join);
1069cb93a386Sopenharmony_ci        p->setStrokeMiter(miter);
1070cb93a386Sopenharmony_ci    };
1071cb93a386Sopenharmony_ci
1072cb93a386Sopenharmony_ci    auto setOtherJoinAndLimit = [](SkPaint* p, SkScalar miter) {
1073cb93a386Sopenharmony_ci        p->setStrokeJoin(SkPaint::kRound_Join);
1074cb93a386Sopenharmony_ci        p->setStrokeMiter(miter);
1075cb93a386Sopenharmony_ci    };
1076cb93a386Sopenharmony_ci
1077cb93a386Sopenharmony_ci    SkPaint hairline;
1078cb93a386Sopenharmony_ci    hairline.setStrokeWidth(0);
1079cb93a386Sopenharmony_ci    hairline.setStyle(SkPaint::kStroke_Style);
1080cb93a386Sopenharmony_ci    GrStyledShape shape = geo.makeShape(hairline);
1081cb93a386Sopenharmony_ci    bool mayHaveJoins = !shape_known_not_to_have_joins(shape);
1082cb93a386Sopenharmony_ci
1083cb93a386Sopenharmony_ci    // The miter limit should affect stroked and dashed-stroked cases when the join type is
1084cb93a386Sopenharmony_ci    // miter.
1085cb93a386Sopenharmony_ci    test_stroke_param_impl<SkScalar>(
1086cb93a386Sopenharmony_ci        reporter,
1087cb93a386Sopenharmony_ci        geo,
1088cb93a386Sopenharmony_ci        setMiterJoinAndLimit,
1089cb93a386Sopenharmony_ci        0.5f, 0.75f,
1090cb93a386Sopenharmony_ci        mayHaveJoins,
1091cb93a386Sopenharmony_ci        true);
1092cb93a386Sopenharmony_ci
1093cb93a386Sopenharmony_ci    // The miter limit should not affect stroked and dashed-stroked cases when the join type is
1094cb93a386Sopenharmony_ci    // not miter.
1095cb93a386Sopenharmony_ci    test_stroke_param_impl<SkScalar>(
1096cb93a386Sopenharmony_ci        reporter,
1097cb93a386Sopenharmony_ci        geo,
1098cb93a386Sopenharmony_ci        setOtherJoinAndLimit,
1099cb93a386Sopenharmony_ci        0.5f, 0.75f,
1100cb93a386Sopenharmony_ci        false,
1101cb93a386Sopenharmony_ci        false);
1102cb93a386Sopenharmony_ci}
1103cb93a386Sopenharmony_ci
1104cb93a386Sopenharmony_cistatic void test_dash_fill(skiatest::Reporter* reporter, const Geo& geo) {
1105cb93a386Sopenharmony_ci    // A dash with no stroke should have no effect
1106cb93a386Sopenharmony_ci    using DashFactoryFn = sk_sp<SkPathEffect>(*)();
1107cb93a386Sopenharmony_ci    for (DashFactoryFn md : {&make_dash, &make_null_dash}) {
1108cb93a386Sopenharmony_ci        SkPaint dashFill;
1109cb93a386Sopenharmony_ci        dashFill.setPathEffect((*md)());
1110cb93a386Sopenharmony_ci        TestCase dashFillCase(geo, dashFill, reporter);
1111cb93a386Sopenharmony_ci
1112cb93a386Sopenharmony_ci        TestCase fillCase(geo, SkPaint(), reporter);
1113cb93a386Sopenharmony_ci        dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
1114cb93a386Sopenharmony_ci    }
1115cb93a386Sopenharmony_ci}
1116cb93a386Sopenharmony_ci
1117cb93a386Sopenharmony_civoid test_null_dash(skiatest::Reporter* reporter, const Geo& geo) {
1118cb93a386Sopenharmony_ci    SkPaint fill;
1119cb93a386Sopenharmony_ci    SkPaint stroke;
1120cb93a386Sopenharmony_ci    stroke.setStyle(SkPaint::kStroke_Style);
1121cb93a386Sopenharmony_ci    stroke.setStrokeWidth(1.f);
1122cb93a386Sopenharmony_ci    SkPaint dash;
1123cb93a386Sopenharmony_ci    dash.setStyle(SkPaint::kStroke_Style);
1124cb93a386Sopenharmony_ci    dash.setStrokeWidth(1.f);
1125cb93a386Sopenharmony_ci    dash.setPathEffect(make_dash());
1126cb93a386Sopenharmony_ci    SkPaint nullDash;
1127cb93a386Sopenharmony_ci    nullDash.setStyle(SkPaint::kStroke_Style);
1128cb93a386Sopenharmony_ci    nullDash.setStrokeWidth(1.f);
1129cb93a386Sopenharmony_ci    nullDash.setPathEffect(make_null_dash());
1130cb93a386Sopenharmony_ci
1131cb93a386Sopenharmony_ci    TestCase fillCase(geo, fill, reporter);
1132cb93a386Sopenharmony_ci    TestCase strokeCase(geo, stroke, reporter);
1133cb93a386Sopenharmony_ci    TestCase dashCase(geo, dash, reporter);
1134cb93a386Sopenharmony_ci    TestCase nullDashCase(geo, nullDash, reporter);
1135cb93a386Sopenharmony_ci
1136cb93a386Sopenharmony_ci    // We expect the null dash to be ignored so nullDashCase should match strokeCase, always.
1137cb93a386Sopenharmony_ci    nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpecation);
1138cb93a386Sopenharmony_ci    // Check whether the fillCase or strokeCase/nullDashCase would undergo a geometric tranformation
1139cb93a386Sopenharmony_ci    // on construction in order to determine how to compare the fill and stroke.
1140cb93a386Sopenharmony_ci    if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
1141cb93a386Sopenharmony_ci        nullDashCase.compare(reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
1142cb93a386Sopenharmony_ci    } else {
1143cb93a386Sopenharmony_ci        nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1144cb93a386Sopenharmony_ci    }
1145cb93a386Sopenharmony_ci    // In the null dash case we may immediately convert to a fill, but not for the normal dash case.
1146cb93a386Sopenharmony_ci    if (geo.strokeIsConvertedToFill()) {
1147cb93a386Sopenharmony_ci        nullDashCase.compare(reporter, dashCase, TestCase::kAllDifferent_ComparisonExpecation);
1148cb93a386Sopenharmony_ci    } else {
1149cb93a386Sopenharmony_ci        nullDashCase.compare(reporter, dashCase, TestCase::kSameUpToPE_ComparisonExpecation);
1150cb93a386Sopenharmony_ci    }
1151cb93a386Sopenharmony_ci}
1152cb93a386Sopenharmony_ci
1153cb93a386Sopenharmony_civoid test_path_effect_makes_rrect(skiatest::Reporter* reporter, const Geo& geo) {
1154cb93a386Sopenharmony_ci    /**
1155cb93a386Sopenharmony_ci     * This path effect takes any input path and turns it into a rrect. It passes through stroke
1156cb93a386Sopenharmony_ci     * info.
1157cb93a386Sopenharmony_ci     */
1158cb93a386Sopenharmony_ci    class RRectPathEffect : SkPathEffectBase {
1159cb93a386Sopenharmony_ci    public:
1160cb93a386Sopenharmony_ci        static const SkRRect& RRect() {
1161cb93a386Sopenharmony_ci            static const SkRRect kRRect = SkRRect::MakeRectXY(SkRect::MakeWH(12, 12), 3, 5);
1162cb93a386Sopenharmony_ci            return kRRect;
1163cb93a386Sopenharmony_ci        }
1164cb93a386Sopenharmony_ci
1165cb93a386Sopenharmony_ci        static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new RRectPathEffect); }
1166cb93a386Sopenharmony_ci        Factory getFactory() const override { return nullptr; }
1167cb93a386Sopenharmony_ci        const char* getTypeName() const override { return nullptr; }
1168cb93a386Sopenharmony_ci
1169cb93a386Sopenharmony_ci    protected:
1170cb93a386Sopenharmony_ci        bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1171cb93a386Sopenharmony_ci                          const SkRect* cullR, const SkMatrix&) const override {
1172cb93a386Sopenharmony_ci            dst->reset();
1173cb93a386Sopenharmony_ci            dst->addRRect(RRect());
1174cb93a386Sopenharmony_ci            return true;
1175cb93a386Sopenharmony_ci        }
1176cb93a386Sopenharmony_ci
1177cb93a386Sopenharmony_ci        bool computeFastBounds(SkRect* bounds) const override {
1178cb93a386Sopenharmony_ci            if (bounds) {
1179cb93a386Sopenharmony_ci                *bounds = RRect().getBounds();
1180cb93a386Sopenharmony_ci            }
1181cb93a386Sopenharmony_ci            return true;
1182cb93a386Sopenharmony_ci        }
1183cb93a386Sopenharmony_ci
1184cb93a386Sopenharmony_ci    private:
1185cb93a386Sopenharmony_ci        RRectPathEffect() {}
1186cb93a386Sopenharmony_ci    };
1187cb93a386Sopenharmony_ci
1188cb93a386Sopenharmony_ci    SkPaint fill;
1189cb93a386Sopenharmony_ci    TestCase fillGeoCase(geo, fill, reporter);
1190cb93a386Sopenharmony_ci
1191cb93a386Sopenharmony_ci    SkPaint pe;
1192cb93a386Sopenharmony_ci    pe.setPathEffect(RRectPathEffect::Make());
1193cb93a386Sopenharmony_ci    TestCase geoPECase(geo, pe, reporter);
1194cb93a386Sopenharmony_ci
1195cb93a386Sopenharmony_ci    SkPaint peStroke;
1196cb93a386Sopenharmony_ci    peStroke.setPathEffect(RRectPathEffect::Make());
1197cb93a386Sopenharmony_ci    peStroke.setStrokeWidth(2.f);
1198cb93a386Sopenharmony_ci    peStroke.setStyle(SkPaint::kStroke_Style);
1199cb93a386Sopenharmony_ci    TestCase geoPEStrokeCase(geo, peStroke, reporter);
1200cb93a386Sopenharmony_ci
1201cb93a386Sopenharmony_ci    // Check whether constructing the filled case would cause the base shape to have a different
1202cb93a386Sopenharmony_ci    // geometry (because of a geometric transformation upon initial GrStyledShape construction).
1203cb93a386Sopenharmony_ci    if (geo.fillChangesGeom()) {
1204cb93a386Sopenharmony_ci        fillGeoCase.compare(reporter, geoPECase, TestCase::kAllDifferent_ComparisonExpecation);
1205cb93a386Sopenharmony_ci        fillGeoCase.compare(reporter, geoPEStrokeCase,
1206cb93a386Sopenharmony_ci                            TestCase::kAllDifferent_ComparisonExpecation);
1207cb93a386Sopenharmony_ci    } else {
1208cb93a386Sopenharmony_ci        fillGeoCase.compare(reporter, geoPECase, TestCase::kSameUpToPE_ComparisonExpecation);
1209cb93a386Sopenharmony_ci        fillGeoCase.compare(reporter, geoPEStrokeCase, TestCase::kSameUpToPE_ComparisonExpecation);
1210cb93a386Sopenharmony_ci    }
1211cb93a386Sopenharmony_ci    geoPECase.compare(reporter, geoPEStrokeCase,
1212cb93a386Sopenharmony_ci                      TestCase::kSameUpToStroke_ComparisonExpecation);
1213cb93a386Sopenharmony_ci
1214cb93a386Sopenharmony_ci    TestCase rrectFillCase(reporter, RRectPathEffect::RRect(), fill);
1215cb93a386Sopenharmony_ci    SkPaint stroke = peStroke;
1216cb93a386Sopenharmony_ci    stroke.setPathEffect(nullptr);
1217cb93a386Sopenharmony_ci    TestCase rrectStrokeCase(reporter, RRectPathEffect::RRect(), stroke);
1218cb93a386Sopenharmony_ci
1219cb93a386Sopenharmony_ci    SkRRect rrect;
1220cb93a386Sopenharmony_ci    // Applying the path effect should make a SkRRect shape. There is no further stroking in the
1221cb93a386Sopenharmony_ci    // geoPECase, so the full style should be the same as just the PE.
1222cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectShape().asRRect(&rrect, nullptr, nullptr,
1223cb93a386Sopenharmony_ci                                                                         nullptr));
1224cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect());
1225cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectKey() == rrectFillCase.baseKey());
1226cb93a386Sopenharmony_ci
1227cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleShape().asRRect(&rrect, nullptr, nullptr,
1228cb93a386Sopenharmony_ci                                                                        nullptr));
1229cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect());
1230cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleKey() == rrectFillCase.baseKey());
1231cb93a386Sopenharmony_ci
1232cb93a386Sopenharmony_ci    // In the PE+stroke case applying the full style should be the same as just stroking the rrect.
1233cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectShape().asRRect(&rrect, nullptr,
1234cb93a386Sopenharmony_ci                                                                               nullptr, nullptr));
1235cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect());
1236cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectKey() == rrectFillCase.baseKey());
1237cb93a386Sopenharmony_ci
1238cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedFullStyleShape().asRRect(&rrect, nullptr,
1239cb93a386Sopenharmony_ci                                                                               nullptr, nullptr));
1240cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleKey() ==
1241cb93a386Sopenharmony_ci                              rrectStrokeCase.appliedFullStyleKey());
1242cb93a386Sopenharmony_ci}
1243cb93a386Sopenharmony_ci
1244cb93a386Sopenharmony_civoid test_unknown_path_effect(skiatest::Reporter* reporter, const Geo& geo) {
1245cb93a386Sopenharmony_ci    /**
1246cb93a386Sopenharmony_ci     * This path effect just adds two lineTos to the input path.
1247cb93a386Sopenharmony_ci     */
1248cb93a386Sopenharmony_ci    class AddLineTosPathEffect : SkPathEffectBase {
1249cb93a386Sopenharmony_ci    public:
1250cb93a386Sopenharmony_ci        static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new AddLineTosPathEffect); }
1251cb93a386Sopenharmony_ci        Factory getFactory() const override { return nullptr; }
1252cb93a386Sopenharmony_ci        const char* getTypeName() const override { return nullptr; }
1253cb93a386Sopenharmony_ci
1254cb93a386Sopenharmony_ci    protected:
1255cb93a386Sopenharmony_ci        bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1256cb93a386Sopenharmony_ci                          const SkRect* cullR, const SkMatrix&) const override {
1257cb93a386Sopenharmony_ci            *dst = src;
1258cb93a386Sopenharmony_ci            // To avoid triggering data-based keying of paths with few verbs we add many segments.
1259cb93a386Sopenharmony_ci            for (int i = 0; i < 100; ++i) {
1260cb93a386Sopenharmony_ci                dst->lineTo(SkIntToScalar(i), SkIntToScalar(i));
1261cb93a386Sopenharmony_ci            }
1262cb93a386Sopenharmony_ci            return true;
1263cb93a386Sopenharmony_ci        }
1264cb93a386Sopenharmony_ci        bool computeFastBounds(SkRect* bounds) const override {
1265cb93a386Sopenharmony_ci            if (bounds) {
1266cb93a386Sopenharmony_ci                SkRectPriv::GrowToInclude(bounds, {0, 0});
1267cb93a386Sopenharmony_ci                SkRectPriv::GrowToInclude(bounds, {100, 100});
1268cb93a386Sopenharmony_ci            }
1269cb93a386Sopenharmony_ci            return true;
1270cb93a386Sopenharmony_ci        }
1271cb93a386Sopenharmony_ci    private:
1272cb93a386Sopenharmony_ci        AddLineTosPathEffect() {}
1273cb93a386Sopenharmony_ci    };
1274cb93a386Sopenharmony_ci
1275cb93a386Sopenharmony_ci     // This path effect should make the keys invalid when it is applied. We only produce a path
1276cb93a386Sopenharmony_ci     // effect key for dash path effects. So the only way another arbitrary path effect can produce
1277cb93a386Sopenharmony_ci     // a styled result with a key is to produce a non-path shape that has a purely geometric key.
1278cb93a386Sopenharmony_ci    SkPaint peStroke;
1279cb93a386Sopenharmony_ci    peStroke.setPathEffect(AddLineTosPathEffect::Make());
1280cb93a386Sopenharmony_ci    peStroke.setStrokeWidth(2.f);
1281cb93a386Sopenharmony_ci    peStroke.setStyle(SkPaint::kStroke_Style);
1282cb93a386Sopenharmony_ci    TestCase geoPEStrokeCase(geo, peStroke, reporter);
1283cb93a386Sopenharmony_ci    TestCase::SelfExpectations expectations;
1284cb93a386Sopenharmony_ci    expectations.fPEHasEffect = true;
1285cb93a386Sopenharmony_ci    expectations.fPEHasValidKey = false;
1286cb93a386Sopenharmony_ci    expectations.fStrokeApplies = true;
1287cb93a386Sopenharmony_ci    geoPEStrokeCase.testExpectations(reporter, expectations);
1288cb93a386Sopenharmony_ci}
1289cb93a386Sopenharmony_ci
1290cb93a386Sopenharmony_civoid test_make_hairline_path_effect(skiatest::Reporter* reporter, const Geo& geo) {
1291cb93a386Sopenharmony_ci    /**
1292cb93a386Sopenharmony_ci     * This path effect just changes the stroke rec to hairline.
1293cb93a386Sopenharmony_ci     */
1294cb93a386Sopenharmony_ci    class MakeHairlinePathEffect : SkPathEffectBase {
1295cb93a386Sopenharmony_ci    public:
1296cb93a386Sopenharmony_ci        static sk_sp<SkPathEffect> Make() {
1297cb93a386Sopenharmony_ci            return sk_sp<SkPathEffect>(new MakeHairlinePathEffect);
1298cb93a386Sopenharmony_ci        }
1299cb93a386Sopenharmony_ci        Factory getFactory() const override { return nullptr; }
1300cb93a386Sopenharmony_ci        const char* getTypeName() const override { return nullptr; }
1301cb93a386Sopenharmony_ci
1302cb93a386Sopenharmony_ci    protected:
1303cb93a386Sopenharmony_ci        bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* strokeRec,
1304cb93a386Sopenharmony_ci                          const SkRect* cullR, const SkMatrix&) const override {
1305cb93a386Sopenharmony_ci            *dst = src;
1306cb93a386Sopenharmony_ci            strokeRec->setHairlineStyle();
1307cb93a386Sopenharmony_ci            return true;
1308cb93a386Sopenharmony_ci        }
1309cb93a386Sopenharmony_ci    private:
1310cb93a386Sopenharmony_ci        bool computeFastBounds(SkRect* bounds) const override { return true; }
1311cb93a386Sopenharmony_ci
1312cb93a386Sopenharmony_ci        MakeHairlinePathEffect() {}
1313cb93a386Sopenharmony_ci    };
1314cb93a386Sopenharmony_ci
1315cb93a386Sopenharmony_ci    SkPaint fill;
1316cb93a386Sopenharmony_ci    SkPaint pe;
1317cb93a386Sopenharmony_ci    pe.setPathEffect(MakeHairlinePathEffect::Make());
1318cb93a386Sopenharmony_ci
1319cb93a386Sopenharmony_ci    TestCase peCase(geo, pe, reporter);
1320cb93a386Sopenharmony_ci
1321cb93a386Sopenharmony_ci    SkPath a, b, c;
1322cb93a386Sopenharmony_ci    peCase.baseShape().asPath(&a);
1323cb93a386Sopenharmony_ci    peCase.appliedPathEffectShape().asPath(&b);
1324cb93a386Sopenharmony_ci    peCase.appliedFullStyleShape().asPath(&c);
1325cb93a386Sopenharmony_ci    if (geo.isNonPath(pe)) {
1326cb93a386Sopenharmony_ci        // RRect types can have a change in start index or direction after the PE is applied. This
1327cb93a386Sopenharmony_ci        // is because once the PE is applied, GrStyledShape may canonicalize the dir and index since
1328cb93a386Sopenharmony_ci        // it is not germane to the styling any longer.
1329cb93a386Sopenharmony_ci        // Instead we just check that the paths would fill the same both before and after styling.
1330cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, paths_fill_same(a, b));
1331cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, paths_fill_same(a, c));
1332cb93a386Sopenharmony_ci    } else {
1333cb93a386Sopenharmony_ci        // The base shape cannot perform canonicalization on the path's fill type because of an
1334cb93a386Sopenharmony_ci        // unknown path effect. However, after the path effect is applied the resulting hairline
1335cb93a386Sopenharmony_ci        // shape will canonicalize the path fill type since hairlines (and stroking in general)
1336cb93a386Sopenharmony_ci        // don't distinguish between even/odd and non-zero winding.
1337cb93a386Sopenharmony_ci        a.setFillType(b.getFillType());
1338cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, a == b);
1339cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, a == c);
1340cb93a386Sopenharmony_ci        // If the resulting path is small enough then it will have a key.
1341cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, paths_fill_same(a, b));
1342cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, paths_fill_same(a, c));
1343cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, peCase.appliedPathEffectKey().empty());
1344cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, peCase.appliedFullStyleKey().empty());
1345cb93a386Sopenharmony_ci    }
1346cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, peCase.appliedPathEffectShape().style().isSimpleHairline());
1347cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, peCase.appliedFullStyleShape().style().isSimpleHairline());
1348cb93a386Sopenharmony_ci}
1349cb93a386Sopenharmony_ci
1350cb93a386Sopenharmony_civoid test_volatile_path(skiatest::Reporter* reporter, const Geo& geo) {
1351cb93a386Sopenharmony_ci    SkPath vPath = geo.path();
1352cb93a386Sopenharmony_ci    vPath.setIsVolatile(true);
1353cb93a386Sopenharmony_ci
1354cb93a386Sopenharmony_ci    SkPaint dashAndStroke;
1355cb93a386Sopenharmony_ci    dashAndStroke.setPathEffect(make_dash());
1356cb93a386Sopenharmony_ci    dashAndStroke.setStrokeWidth(2.f);
1357cb93a386Sopenharmony_ci    dashAndStroke.setStyle(SkPaint::kStroke_Style);
1358cb93a386Sopenharmony_ci    TestCase volatileCase(reporter, vPath, dashAndStroke);
1359cb93a386Sopenharmony_ci    // We expect a shape made from a volatile path to have a key iff the shape is recognized
1360cb93a386Sopenharmony_ci    // as a specialized geometry.
1361cb93a386Sopenharmony_ci    if (geo.isNonPath(dashAndStroke)) {
1362cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, SkToBool(volatileCase.baseKey().count()));
1363cb93a386Sopenharmony_ci        // In this case all the keys should be identical to the non-volatile case.
1364cb93a386Sopenharmony_ci        TestCase nonVolatileCase(reporter, geo.path(), dashAndStroke);
1365cb93a386Sopenharmony_ci        volatileCase.compare(reporter, nonVolatileCase, TestCase::kAllSame_ComparisonExpecation);
1366cb93a386Sopenharmony_ci    } else {
1367cb93a386Sopenharmony_ci        // None of the keys should be valid.
1368cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !SkToBool(volatileCase.baseKey().count()));
1369cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !SkToBool(volatileCase.appliedPathEffectKey().count()));
1370cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !SkToBool(volatileCase.appliedFullStyleKey().count()));
1371cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !SkToBool(volatileCase.appliedPathEffectThenStrokeKey().count()));
1372cb93a386Sopenharmony_ci    }
1373cb93a386Sopenharmony_ci}
1374cb93a386Sopenharmony_ci
1375cb93a386Sopenharmony_civoid test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const Geo& geo) {
1376cb93a386Sopenharmony_ci    /**
1377cb93a386Sopenharmony_ci     * This path effect returns an empty path (possibly inverted)
1378cb93a386Sopenharmony_ci     */
1379cb93a386Sopenharmony_ci    class EmptyPathEffect : SkPathEffectBase {
1380cb93a386Sopenharmony_ci    public:
1381cb93a386Sopenharmony_ci        static sk_sp<SkPathEffect> Make(bool invert) {
1382cb93a386Sopenharmony_ci            return sk_sp<SkPathEffect>(new EmptyPathEffect(invert));
1383cb93a386Sopenharmony_ci        }
1384cb93a386Sopenharmony_ci        Factory getFactory() const override { return nullptr; }
1385cb93a386Sopenharmony_ci        const char* getTypeName() const override { return nullptr; }
1386cb93a386Sopenharmony_ci    protected:
1387cb93a386Sopenharmony_ci        bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1388cb93a386Sopenharmony_ci                          const SkRect* cullR, const SkMatrix&) const override {
1389cb93a386Sopenharmony_ci            dst->reset();
1390cb93a386Sopenharmony_ci            if (fInvert) {
1391cb93a386Sopenharmony_ci                dst->toggleInverseFillType();
1392cb93a386Sopenharmony_ci            }
1393cb93a386Sopenharmony_ci            return true;
1394cb93a386Sopenharmony_ci        }
1395cb93a386Sopenharmony_ci        bool computeFastBounds(SkRect* bounds) const override {
1396cb93a386Sopenharmony_ci            if (bounds) {
1397cb93a386Sopenharmony_ci                *bounds = { 0, 0, 0, 0 };
1398cb93a386Sopenharmony_ci            }
1399cb93a386Sopenharmony_ci            return true;
1400cb93a386Sopenharmony_ci        }
1401cb93a386Sopenharmony_ci    private:
1402cb93a386Sopenharmony_ci        bool fInvert;
1403cb93a386Sopenharmony_ci        EmptyPathEffect(bool invert) : fInvert(invert) {}
1404cb93a386Sopenharmony_ci    };
1405cb93a386Sopenharmony_ci
1406cb93a386Sopenharmony_ci    SkPath emptyPath;
1407cb93a386Sopenharmony_ci    GrStyledShape emptyShape(emptyPath);
1408cb93a386Sopenharmony_ci    Key emptyKey;
1409cb93a386Sopenharmony_ci    make_key(&emptyKey, emptyShape);
1410cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, emptyShape.isEmpty());
1411cb93a386Sopenharmony_ci
1412cb93a386Sopenharmony_ci    emptyPath.toggleInverseFillType();
1413cb93a386Sopenharmony_ci    GrStyledShape invertedEmptyShape(emptyPath);
1414cb93a386Sopenharmony_ci    Key invertedEmptyKey;
1415cb93a386Sopenharmony_ci    make_key(&invertedEmptyKey, invertedEmptyShape);
1416cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, invertedEmptyShape.isEmpty());
1417cb93a386Sopenharmony_ci
1418cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, invertedEmptyKey != emptyKey);
1419cb93a386Sopenharmony_ci
1420cb93a386Sopenharmony_ci    SkPaint pe;
1421cb93a386Sopenharmony_ci    pe.setPathEffect(EmptyPathEffect::Make(false));
1422cb93a386Sopenharmony_ci    TestCase geoPECase(geo, pe, reporter);
1423cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleKey() == emptyKey);
1424cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectKey() == emptyKey);
1425cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectThenStrokeKey() == emptyKey);
1426cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectShape().isEmpty());
1427cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleShape().isEmpty());
1428cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !geoPECase.appliedPathEffectShape().inverseFilled());
1429cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !geoPECase.appliedFullStyleShape().inverseFilled());
1430cb93a386Sopenharmony_ci
1431cb93a386Sopenharmony_ci    SkPaint peStroke;
1432cb93a386Sopenharmony_ci    peStroke.setPathEffect(EmptyPathEffect::Make(false));
1433cb93a386Sopenharmony_ci    peStroke.setStrokeWidth(2.f);
1434cb93a386Sopenharmony_ci    peStroke.setStyle(SkPaint::kStroke_Style);
1435cb93a386Sopenharmony_ci    TestCase geoPEStrokeCase(geo, peStroke, reporter);
1436cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleKey() == emptyKey);
1437cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectKey() == emptyKey);
1438cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectThenStrokeKey() == emptyKey);
1439cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectShape().isEmpty());
1440cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleShape().isEmpty());
1441cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedPathEffectShape().inverseFilled());
1442cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedFullStyleShape().inverseFilled());
1443cb93a386Sopenharmony_ci    pe.setPathEffect(EmptyPathEffect::Make(true));
1444cb93a386Sopenharmony_ci
1445cb93a386Sopenharmony_ci    TestCase geoPEInvertCase(geo, pe, reporter);
1446cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedFullStyleKey() == invertedEmptyKey);
1447cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectKey() == invertedEmptyKey);
1448cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectThenStrokeKey() == invertedEmptyKey);
1449cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectShape().isEmpty());
1450cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedFullStyleShape().isEmpty());
1451cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectShape().inverseFilled());
1452cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertCase.appliedFullStyleShape().inverseFilled());
1453cb93a386Sopenharmony_ci
1454cb93a386Sopenharmony_ci    peStroke.setPathEffect(EmptyPathEffect::Make(true));
1455cb93a386Sopenharmony_ci    TestCase geoPEInvertStrokeCase(geo, peStroke, reporter);
1456cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedFullStyleKey() == invertedEmptyKey);
1457cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedPathEffectKey() == invertedEmptyKey);
1458cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter,
1459cb93a386Sopenharmony_ci                    geoPEInvertStrokeCase.appliedPathEffectThenStrokeKey() == invertedEmptyKey);
1460cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedPathEffectShape().isEmpty());
1461cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedFullStyleShape().isEmpty());
1462cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedPathEffectShape().inverseFilled());
1463cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedFullStyleShape().inverseFilled());
1464cb93a386Sopenharmony_ci}
1465cb93a386Sopenharmony_ci
1466cb93a386Sopenharmony_civoid test_path_effect_fails(skiatest::Reporter* reporter, const Geo& geo) {
1467cb93a386Sopenharmony_ci    /**
1468cb93a386Sopenharmony_ci     * This path effect always fails to apply.
1469cb93a386Sopenharmony_ci     */
1470cb93a386Sopenharmony_ci    class FailurePathEffect : SkPathEffectBase {
1471cb93a386Sopenharmony_ci    public:
1472cb93a386Sopenharmony_ci        static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new FailurePathEffect); }
1473cb93a386Sopenharmony_ci        Factory getFactory() const override { return nullptr; }
1474cb93a386Sopenharmony_ci        const char* getTypeName() const override { return nullptr; }
1475cb93a386Sopenharmony_ci    protected:
1476cb93a386Sopenharmony_ci        bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1477cb93a386Sopenharmony_ci                          const SkRect* cullR, const SkMatrix&) const override {
1478cb93a386Sopenharmony_ci            return false;
1479cb93a386Sopenharmony_ci        }
1480cb93a386Sopenharmony_ci    private:
1481cb93a386Sopenharmony_ci        bool computeFastBounds(SkRect* bounds) const override { return false; }
1482cb93a386Sopenharmony_ci
1483cb93a386Sopenharmony_ci        FailurePathEffect() {}
1484cb93a386Sopenharmony_ci    };
1485cb93a386Sopenharmony_ci
1486cb93a386Sopenharmony_ci    SkPaint fill;
1487cb93a386Sopenharmony_ci    TestCase fillCase(geo, fill, reporter);
1488cb93a386Sopenharmony_ci
1489cb93a386Sopenharmony_ci    SkPaint pe;
1490cb93a386Sopenharmony_ci    pe.setPathEffect(FailurePathEffect::Make());
1491cb93a386Sopenharmony_ci    TestCase peCase(geo, pe, reporter);
1492cb93a386Sopenharmony_ci
1493cb93a386Sopenharmony_ci    SkPaint stroke;
1494cb93a386Sopenharmony_ci    stroke.setStrokeWidth(2.f);
1495cb93a386Sopenharmony_ci    stroke.setStyle(SkPaint::kStroke_Style);
1496cb93a386Sopenharmony_ci    TestCase strokeCase(geo, stroke, reporter);
1497cb93a386Sopenharmony_ci
1498cb93a386Sopenharmony_ci    SkPaint peStroke = stroke;
1499cb93a386Sopenharmony_ci    peStroke.setPathEffect(FailurePathEffect::Make());
1500cb93a386Sopenharmony_ci    TestCase peStrokeCase(geo, peStroke, reporter);
1501cb93a386Sopenharmony_ci
1502cb93a386Sopenharmony_ci    // In general the path effect failure can cause some of the TestCase::compare() tests to fail
1503cb93a386Sopenharmony_ci    // for at least two reasons: 1) We will initially treat the shape as unkeyable because of the
1504cb93a386Sopenharmony_ci    // path effect, but then when the path effect fails we can key it. 2) GrStyledShape will change
1505cb93a386Sopenharmony_ci    // its mind about whether a unclosed rect is actually rect. The path effect initially bars us
1506cb93a386Sopenharmony_ci    // from closing it but after the effect fails we can (for the fill+pe case). This causes
1507cb93a386Sopenharmony_ci    // different routes through GrStyledShape to have equivalent but different representations of
1508cb93a386Sopenharmony_ci    // the path (closed or not) but that fill the same.
1509cb93a386Sopenharmony_ci    SkPath a;
1510cb93a386Sopenharmony_ci    SkPath b;
1511cb93a386Sopenharmony_ci    fillCase.appliedPathEffectShape().asPath(&a);
1512cb93a386Sopenharmony_ci    peCase.appliedPathEffectShape().asPath(&b);
1513cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, paths_fill_same(a, b));
1514cb93a386Sopenharmony_ci
1515cb93a386Sopenharmony_ci    fillCase.appliedFullStyleShape().asPath(&a);
1516cb93a386Sopenharmony_ci    peCase.appliedFullStyleShape().asPath(&b);
1517cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, paths_fill_same(a, b));
1518cb93a386Sopenharmony_ci
1519cb93a386Sopenharmony_ci    strokeCase.appliedPathEffectShape().asPath(&a);
1520cb93a386Sopenharmony_ci    peStrokeCase.appliedPathEffectShape().asPath(&b);
1521cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, paths_fill_same(a, b));
1522cb93a386Sopenharmony_ci
1523cb93a386Sopenharmony_ci    strokeCase.appliedFullStyleShape().asPath(&a);
1524cb93a386Sopenharmony_ci    peStrokeCase.appliedFullStyleShape().asPath(&b);
1525cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, paths_fill_same(a, b));
1526cb93a386Sopenharmony_ci}
1527cb93a386Sopenharmony_ci
1528cb93a386Sopenharmony_ciDEF_TEST(GrStyledShape_empty_shape, reporter) {
1529cb93a386Sopenharmony_ci    SkPath emptyPath;
1530cb93a386Sopenharmony_ci    SkPath invertedEmptyPath;
1531cb93a386Sopenharmony_ci    invertedEmptyPath.toggleInverseFillType();
1532cb93a386Sopenharmony_ci    SkPaint fill;
1533cb93a386Sopenharmony_ci    TestCase fillEmptyCase(reporter, emptyPath, fill);
1534cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillEmptyCase.baseShape().isEmpty());
1535cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillEmptyCase.appliedPathEffectShape().isEmpty());
1536cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillEmptyCase.appliedFullStyleShape().isEmpty());
1537cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !fillEmptyCase.baseShape().inverseFilled());
1538cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !fillEmptyCase.appliedPathEffectShape().inverseFilled());
1539cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !fillEmptyCase.appliedFullStyleShape().inverseFilled());
1540cb93a386Sopenharmony_ci    TestCase fillInvertedEmptyCase(reporter, invertedEmptyPath, fill);
1541cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillInvertedEmptyCase.baseShape().isEmpty());
1542cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedPathEffectShape().isEmpty());
1543cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedFullStyleShape().isEmpty());
1544cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillInvertedEmptyCase.baseShape().inverseFilled());
1545cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedPathEffectShape().inverseFilled());
1546cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedFullStyleShape().inverseFilled());
1547cb93a386Sopenharmony_ci
1548cb93a386Sopenharmony_ci    const Key& emptyKey = fillEmptyCase.baseKey();
1549cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, emptyKey.count());
1550cb93a386Sopenharmony_ci    const Key& inverseEmptyKey = fillInvertedEmptyCase.baseKey();
1551cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, inverseEmptyKey.count());
1552cb93a386Sopenharmony_ci    TestCase::SelfExpectations expectations;
1553cb93a386Sopenharmony_ci    expectations.fStrokeApplies = false;
1554cb93a386Sopenharmony_ci    expectations.fPEHasEffect = false;
1555cb93a386Sopenharmony_ci    // This will test whether applying style preserves emptiness
1556cb93a386Sopenharmony_ci    fillEmptyCase.testExpectations(reporter, expectations);
1557cb93a386Sopenharmony_ci    fillInvertedEmptyCase.testExpectations(reporter, expectations);
1558cb93a386Sopenharmony_ci
1559cb93a386Sopenharmony_ci    // Stroking an empty path should have no effect
1560cb93a386Sopenharmony_ci    SkPaint stroke;
1561cb93a386Sopenharmony_ci    stroke.setStrokeWidth(2.f);
1562cb93a386Sopenharmony_ci    stroke.setStyle(SkPaint::kStroke_Style);
1563cb93a386Sopenharmony_ci    stroke.setStrokeJoin(SkPaint::kRound_Join);
1564cb93a386Sopenharmony_ci    stroke.setStrokeCap(SkPaint::kRound_Cap);
1565cb93a386Sopenharmony_ci    TestCase strokeEmptyCase(reporter, emptyPath, stroke);
1566cb93a386Sopenharmony_ci    strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1567cb93a386Sopenharmony_ci    TestCase strokeInvertedEmptyCase(reporter, invertedEmptyPath, stroke);
1568cb93a386Sopenharmony_ci    strokeInvertedEmptyCase.compare(reporter, fillInvertedEmptyCase,
1569cb93a386Sopenharmony_ci                                    TestCase::kAllSame_ComparisonExpecation);
1570cb93a386Sopenharmony_ci
1571cb93a386Sopenharmony_ci    // Dashing and stroking an empty path should have no effect
1572cb93a386Sopenharmony_ci    SkPaint dashAndStroke;
1573cb93a386Sopenharmony_ci    dashAndStroke.setPathEffect(make_dash());
1574cb93a386Sopenharmony_ci    dashAndStroke.setStrokeWidth(2.f);
1575cb93a386Sopenharmony_ci    dashAndStroke.setStyle(SkPaint::kStroke_Style);
1576cb93a386Sopenharmony_ci    TestCase dashAndStrokeEmptyCase(reporter, emptyPath, dashAndStroke);
1577cb93a386Sopenharmony_ci    dashAndStrokeEmptyCase.compare(reporter, fillEmptyCase,
1578cb93a386Sopenharmony_ci                                   TestCase::kAllSame_ComparisonExpecation);
1579cb93a386Sopenharmony_ci    TestCase dashAndStrokeInvertexEmptyCase(reporter, invertedEmptyPath, dashAndStroke);
1580cb93a386Sopenharmony_ci    // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
1581cb93a386Sopenharmony_ci    dashAndStrokeInvertexEmptyCase.compare(reporter, fillEmptyCase,
1582cb93a386Sopenharmony_ci                                           TestCase::kAllSame_ComparisonExpecation);
1583cb93a386Sopenharmony_ci
1584cb93a386Sopenharmony_ci    // A shape made from an empty rrect should behave the same as an empty path when filled and
1585cb93a386Sopenharmony_ci    // when stroked. The shape is closed so it does not produce caps when stroked. When dashed there
1586cb93a386Sopenharmony_ci    // is no path to dash along, making it equivalent as well.
1587cb93a386Sopenharmony_ci    SkRRect emptyRRect = SkRRect::MakeEmpty();
1588cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, emptyRRect.getType() == SkRRect::kEmpty_Type);
1589cb93a386Sopenharmony_ci
1590cb93a386Sopenharmony_ci    TestCase fillEmptyRRectCase(reporter, emptyRRect, fill);
1591cb93a386Sopenharmony_ci    fillEmptyRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1592cb93a386Sopenharmony_ci
1593cb93a386Sopenharmony_ci    TestCase strokeEmptyRRectCase(reporter, emptyRRect, stroke);
1594cb93a386Sopenharmony_ci    strokeEmptyRRectCase.compare(reporter, strokeEmptyCase,
1595cb93a386Sopenharmony_ci                                 TestCase::kAllSame_ComparisonExpecation);
1596cb93a386Sopenharmony_ci
1597cb93a386Sopenharmony_ci    TestCase dashAndStrokeEmptyRRectCase(reporter, emptyRRect, dashAndStroke);
1598cb93a386Sopenharmony_ci    dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase,
1599cb93a386Sopenharmony_ci                                        TestCase::kAllSame_ComparisonExpecation);
1600cb93a386Sopenharmony_ci
1601cb93a386Sopenharmony_ci    static constexpr SkPathDirection kDir = SkPathDirection::kCCW;
1602cb93a386Sopenharmony_ci    static constexpr int kStart = 0;
1603cb93a386Sopenharmony_ci
1604cb93a386Sopenharmony_ci    TestCase fillInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true, GrStyle(fill));
1605cb93a386Sopenharmony_ci    fillInvertedEmptyRRectCase.compare(reporter, fillInvertedEmptyCase,
1606cb93a386Sopenharmony_ci                                       TestCase::kAllSame_ComparisonExpecation);
1607cb93a386Sopenharmony_ci
1608cb93a386Sopenharmony_ci    TestCase strokeInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true,
1609cb93a386Sopenharmony_ci                                          GrStyle(stroke));
1610cb93a386Sopenharmony_ci    strokeInvertedEmptyRRectCase.compare(reporter, strokeInvertedEmptyCase,
1611cb93a386Sopenharmony_ci                                         TestCase::kAllSame_ComparisonExpecation);
1612cb93a386Sopenharmony_ci
1613cb93a386Sopenharmony_ci    TestCase dashAndStrokeEmptyInvertedRRectCase(reporter, emptyRRect, kDir, kStart, true,
1614cb93a386Sopenharmony_ci                                                 GrStyle(dashAndStroke));
1615cb93a386Sopenharmony_ci    dashAndStrokeEmptyInvertedRRectCase.compare(reporter, fillEmptyCase,
1616cb93a386Sopenharmony_ci                                                TestCase::kAllSame_ComparisonExpecation);
1617cb93a386Sopenharmony_ci
1618cb93a386Sopenharmony_ci    // Same for a rect.
1619cb93a386Sopenharmony_ci    SkRect emptyRect = SkRect::MakeEmpty();
1620cb93a386Sopenharmony_ci    TestCase fillEmptyRectCase(reporter, emptyRect, fill);
1621cb93a386Sopenharmony_ci    fillEmptyRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1622cb93a386Sopenharmony_ci
1623cb93a386Sopenharmony_ci    TestCase dashAndStrokeEmptyRectCase(reporter, emptyRect, dashAndStroke);
1624cb93a386Sopenharmony_ci    dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase,
1625cb93a386Sopenharmony_ci                                       TestCase::kAllSame_ComparisonExpecation);
1626cb93a386Sopenharmony_ci
1627cb93a386Sopenharmony_ci    TestCase dashAndStrokeEmptyInvertedRectCase(reporter, SkRRect::MakeRect(emptyRect), kDir,
1628cb93a386Sopenharmony_ci                                                kStart, true, GrStyle(dashAndStroke));
1629cb93a386Sopenharmony_ci    // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
1630cb93a386Sopenharmony_ci    dashAndStrokeEmptyInvertedRectCase.compare(reporter, fillEmptyCase,
1631cb93a386Sopenharmony_ci                                               TestCase::kAllSame_ComparisonExpecation);
1632cb93a386Sopenharmony_ci}
1633cb93a386Sopenharmony_ci
1634cb93a386Sopenharmony_ci// rect and oval types have rrect start indices that collapse to the same point. Here we select the
1635cb93a386Sopenharmony_ci// canonical point in these cases.
1636cb93a386Sopenharmony_ciunsigned canonicalize_rrect_start(int s, const SkRRect& rrect) {
1637cb93a386Sopenharmony_ci    switch (rrect.getType()) {
1638cb93a386Sopenharmony_ci        case SkRRect::kRect_Type:
1639cb93a386Sopenharmony_ci            return (s + 1) & 0b110;
1640cb93a386Sopenharmony_ci        case SkRRect::kOval_Type:
1641cb93a386Sopenharmony_ci            return s & 0b110;
1642cb93a386Sopenharmony_ci        default:
1643cb93a386Sopenharmony_ci            return s;
1644cb93a386Sopenharmony_ci    }
1645cb93a386Sopenharmony_ci}
1646cb93a386Sopenharmony_ci
1647cb93a386Sopenharmony_civoid test_rrect(skiatest::Reporter* r, const SkRRect& rrect) {
1648cb93a386Sopenharmony_ci    enum Style {
1649cb93a386Sopenharmony_ci        kFill,
1650cb93a386Sopenharmony_ci        kStroke,
1651cb93a386Sopenharmony_ci        kHairline,
1652cb93a386Sopenharmony_ci        kStrokeAndFill
1653cb93a386Sopenharmony_ci    };
1654cb93a386Sopenharmony_ci
1655cb93a386Sopenharmony_ci    // SkStrokeRec has no default cons., so init with kFill before calling the setters below.
1656cb93a386Sopenharmony_ci    SkStrokeRec strokeRecs[4] { SkStrokeRec::kFill_InitStyle, SkStrokeRec::kFill_InitStyle,
1657cb93a386Sopenharmony_ci                                SkStrokeRec::kFill_InitStyle, SkStrokeRec::kFill_InitStyle};
1658cb93a386Sopenharmony_ci    strokeRecs[kFill].setFillStyle();
1659cb93a386Sopenharmony_ci    strokeRecs[kStroke].setStrokeStyle(2.f);
1660cb93a386Sopenharmony_ci    strokeRecs[kHairline].setHairlineStyle();
1661cb93a386Sopenharmony_ci    strokeRecs[kStrokeAndFill].setStrokeStyle(3.f, true);
1662cb93a386Sopenharmony_ci    // Use a bevel join to avoid complications of stroke+filled rects becoming filled rects before
1663cb93a386Sopenharmony_ci    // applyStyle() is called.
1664cb93a386Sopenharmony_ci    strokeRecs[kStrokeAndFill].setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 1.f);
1665cb93a386Sopenharmony_ci    sk_sp<SkPathEffect> dashEffect = make_dash();
1666cb93a386Sopenharmony_ci
1667cb93a386Sopenharmony_ci    static constexpr Style kStyleCnt = static_cast<Style>(SK_ARRAY_COUNT(strokeRecs));
1668cb93a386Sopenharmony_ci
1669cb93a386Sopenharmony_ci    auto index = [](bool inverted,
1670cb93a386Sopenharmony_ci                    SkPathDirection dir,
1671cb93a386Sopenharmony_ci                    unsigned start,
1672cb93a386Sopenharmony_ci                    Style style,
1673cb93a386Sopenharmony_ci                    bool dash) -> int {
1674cb93a386Sopenharmony_ci        return inverted * (2 * 8 * kStyleCnt * 2) +
1675cb93a386Sopenharmony_ci               (int)dir * (    8 * kStyleCnt * 2) +
1676cb93a386Sopenharmony_ci               start    * (        kStyleCnt * 2) +
1677cb93a386Sopenharmony_ci               style    * (                    2) +
1678cb93a386Sopenharmony_ci               dash;
1679cb93a386Sopenharmony_ci    };
1680cb93a386Sopenharmony_ci    static const SkPathDirection kSecondDirection = static_cast<SkPathDirection>(1);
1681cb93a386Sopenharmony_ci    const int cnt = index(true, kSecondDirection, 7, static_cast<Style>(kStyleCnt - 1), true) + 1;
1682cb93a386Sopenharmony_ci    SkAutoTArray<GrStyledShape> shapes(cnt);
1683cb93a386Sopenharmony_ci    for (bool inverted : {false, true}) {
1684cb93a386Sopenharmony_ci        for (SkPathDirection dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
1685cb93a386Sopenharmony_ci            for (unsigned start = 0; start < 8; ++start) {
1686cb93a386Sopenharmony_ci                for (Style style : {kFill, kStroke, kHairline, kStrokeAndFill}) {
1687cb93a386Sopenharmony_ci                    for (bool dash : {false, true}) {
1688cb93a386Sopenharmony_ci                        sk_sp<SkPathEffect> pe = dash ? dashEffect : nullptr;
1689cb93a386Sopenharmony_ci                        shapes[index(inverted, dir, start, style, dash)] =
1690cb93a386Sopenharmony_ci                                GrStyledShape(rrect, dir, start, SkToBool(inverted),
1691cb93a386Sopenharmony_ci                                        GrStyle(strokeRecs[style], std::move(pe)));
1692cb93a386Sopenharmony_ci                    }
1693cb93a386Sopenharmony_ci                }
1694cb93a386Sopenharmony_ci            }
1695cb93a386Sopenharmony_ci        }
1696cb93a386Sopenharmony_ci    }
1697cb93a386Sopenharmony_ci
1698cb93a386Sopenharmony_ci    // Get the keys for some example shape instances that we'll use for comparision against the
1699cb93a386Sopenharmony_ci    // rest.
1700cb93a386Sopenharmony_ci    static constexpr SkPathDirection kExamplesDir = SkPathDirection::kCW;
1701cb93a386Sopenharmony_ci    static constexpr unsigned kExamplesStart = 0;
1702cb93a386Sopenharmony_ci    const GrStyledShape& exampleFillCase = shapes[index(false, kExamplesDir, kExamplesStart, kFill,
1703cb93a386Sopenharmony_ci                                                  false)];
1704cb93a386Sopenharmony_ci    Key exampleFillCaseKey;
1705cb93a386Sopenharmony_ci    make_key(&exampleFillCaseKey, exampleFillCase);
1706cb93a386Sopenharmony_ci
1707cb93a386Sopenharmony_ci    const GrStyledShape& exampleStrokeAndFillCase = shapes[index(false, kExamplesDir,
1708cb93a386Sopenharmony_ci                                                           kExamplesStart, kStrokeAndFill, false)];
1709cb93a386Sopenharmony_ci    Key exampleStrokeAndFillCaseKey;
1710cb93a386Sopenharmony_ci    make_key(&exampleStrokeAndFillCaseKey, exampleStrokeAndFillCase);
1711cb93a386Sopenharmony_ci
1712cb93a386Sopenharmony_ci    const GrStyledShape& exampleInvFillCase = shapes[index(true, kExamplesDir,
1713cb93a386Sopenharmony_ci                                                     kExamplesStart, kFill, false)];
1714cb93a386Sopenharmony_ci    Key exampleInvFillCaseKey;
1715cb93a386Sopenharmony_ci    make_key(&exampleInvFillCaseKey, exampleInvFillCase);
1716cb93a386Sopenharmony_ci
1717cb93a386Sopenharmony_ci    const GrStyledShape& exampleInvStrokeAndFillCase = shapes[index(true, kExamplesDir,
1718cb93a386Sopenharmony_ci                                                              kExamplesStart, kStrokeAndFill,
1719cb93a386Sopenharmony_ci                                                              false)];
1720cb93a386Sopenharmony_ci    Key exampleInvStrokeAndFillCaseKey;
1721cb93a386Sopenharmony_ci    make_key(&exampleInvStrokeAndFillCaseKey, exampleInvStrokeAndFillCase);
1722cb93a386Sopenharmony_ci
1723cb93a386Sopenharmony_ci    const GrStyledShape& exampleStrokeCase = shapes[index(false, kExamplesDir, kExamplesStart,
1724cb93a386Sopenharmony_ci                                                    kStroke, false)];
1725cb93a386Sopenharmony_ci    Key exampleStrokeCaseKey;
1726cb93a386Sopenharmony_ci    make_key(&exampleStrokeCaseKey, exampleStrokeCase);
1727cb93a386Sopenharmony_ci
1728cb93a386Sopenharmony_ci    const GrStyledShape& exampleInvStrokeCase = shapes[index(true, kExamplesDir, kExamplesStart,
1729cb93a386Sopenharmony_ci                                                       kStroke, false)];
1730cb93a386Sopenharmony_ci    Key exampleInvStrokeCaseKey;
1731cb93a386Sopenharmony_ci    make_key(&exampleInvStrokeCaseKey, exampleInvStrokeCase);
1732cb93a386Sopenharmony_ci
1733cb93a386Sopenharmony_ci    const GrStyledShape& exampleHairlineCase = shapes[index(false, kExamplesDir, kExamplesStart,
1734cb93a386Sopenharmony_ci                                                      kHairline, false)];
1735cb93a386Sopenharmony_ci    Key exampleHairlineCaseKey;
1736cb93a386Sopenharmony_ci    make_key(&exampleHairlineCaseKey, exampleHairlineCase);
1737cb93a386Sopenharmony_ci
1738cb93a386Sopenharmony_ci    const GrStyledShape& exampleInvHairlineCase = shapes[index(true, kExamplesDir, kExamplesStart,
1739cb93a386Sopenharmony_ci                                                         kHairline, false)];
1740cb93a386Sopenharmony_ci    Key exampleInvHairlineCaseKey;
1741cb93a386Sopenharmony_ci    make_key(&exampleInvHairlineCaseKey, exampleInvHairlineCase);
1742cb93a386Sopenharmony_ci
1743cb93a386Sopenharmony_ci    // These initializations suppress warnings.
1744cb93a386Sopenharmony_ci    SkRRect queryRR = SkRRect::MakeEmpty();
1745cb93a386Sopenharmony_ci    SkPathDirection queryDir = SkPathDirection::kCW;
1746cb93a386Sopenharmony_ci    unsigned queryStart = ~0U;
1747cb93a386Sopenharmony_ci    bool queryInverted = true;
1748cb93a386Sopenharmony_ci
1749cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCase.asRRect(&queryRR, &queryDir, &queryStart, &queryInverted));
1750cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1751cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1752cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1753cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !queryInverted);
1754cb93a386Sopenharmony_ci
1755cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvFillCase.asRRect(&queryRR, &queryDir, &queryStart,
1756cb93a386Sopenharmony_ci                                                  &queryInverted));
1757cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1758cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1759cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1760cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryInverted);
1761cb93a386Sopenharmony_ci
1762cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleStrokeAndFillCase.asRRect(&queryRR, &queryDir, &queryStart,
1763cb93a386Sopenharmony_ci                                                        &queryInverted));
1764cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1765cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1766cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1767cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !queryInverted);
1768cb93a386Sopenharmony_ci
1769cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvStrokeAndFillCase.asRRect(&queryRR, &queryDir, &queryStart,
1770cb93a386Sopenharmony_ci                                                           &queryInverted));
1771cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1772cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1773cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1774cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryInverted);
1775cb93a386Sopenharmony_ci
1776cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleHairlineCase.asRRect(&queryRR, &queryDir, &queryStart,
1777cb93a386Sopenharmony_ci                                                   &queryInverted));
1778cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1779cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1780cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1781cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !queryInverted);
1782cb93a386Sopenharmony_ci
1783cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvHairlineCase.asRRect(&queryRR, &queryDir, &queryStart,
1784cb93a386Sopenharmony_ci                                                      &queryInverted));
1785cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1786cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1787cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1788cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryInverted);
1789cb93a386Sopenharmony_ci
1790cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleStrokeCase.asRRect(&queryRR, &queryDir, &queryStart, &queryInverted));
1791cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1792cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1793cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1794cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !queryInverted);
1795cb93a386Sopenharmony_ci
1796cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvStrokeCase.asRRect(&queryRR, &queryDir, &queryStart,
1797cb93a386Sopenharmony_ci                                                    &queryInverted));
1798cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryRR == rrect);
1799cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1800cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 0 == queryStart);
1801cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, queryInverted);
1802cb93a386Sopenharmony_ci
1803cb93a386Sopenharmony_ci    // Remember that the key reflects the geometry before styling is applied.
1804cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvFillCaseKey);
1805cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeAndFillCaseKey);
1806cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeAndFillCaseKey);
1807cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeCaseKey);
1808cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeCaseKey);
1809cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey == exampleHairlineCaseKey);
1810cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvHairlineCaseKey);
1811cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvFillCaseKey);
1812cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvStrokeCaseKey);
1813cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvHairlineCaseKey);
1814cb93a386Sopenharmony_ci
1815cb93a386Sopenharmony_ci    for (bool inverted : {false, true}) {
1816cb93a386Sopenharmony_ci        for (SkPathDirection dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
1817cb93a386Sopenharmony_ci            for (unsigned start = 0; start < 8; ++start) {
1818cb93a386Sopenharmony_ci                for (bool dash : {false, true}) {
1819cb93a386Sopenharmony_ci                    const GrStyledShape& fillCase = shapes[index(inverted, dir, start, kFill,
1820cb93a386Sopenharmony_ci                                                           dash)];
1821cb93a386Sopenharmony_ci                    Key fillCaseKey;
1822cb93a386Sopenharmony_ci                    make_key(&fillCaseKey, fillCase);
1823cb93a386Sopenharmony_ci
1824cb93a386Sopenharmony_ci                    const GrStyledShape& strokeAndFillCase = shapes[index(inverted, dir, start,
1825cb93a386Sopenharmony_ci                                                                    kStrokeAndFill, dash)];
1826cb93a386Sopenharmony_ci                    Key strokeAndFillCaseKey;
1827cb93a386Sopenharmony_ci                    make_key(&strokeAndFillCaseKey, strokeAndFillCase);
1828cb93a386Sopenharmony_ci
1829cb93a386Sopenharmony_ci                    // Both fill and stroke-and-fill shapes must respect the inverseness and both
1830cb93a386Sopenharmony_ci                    // ignore dashing.
1831cb93a386Sopenharmony_ci                    REPORTER_ASSERT(r, !fillCase.style().pathEffect());
1832cb93a386Sopenharmony_ci                    REPORTER_ASSERT(r, !strokeAndFillCase.style().pathEffect());
1833cb93a386Sopenharmony_ci                    TestCase a(fillCase, r);
1834cb93a386Sopenharmony_ci                    TestCase b(inverted ? exampleInvFillCase : exampleFillCase, r);
1835cb93a386Sopenharmony_ci                    TestCase c(strokeAndFillCase, r);
1836cb93a386Sopenharmony_ci                    TestCase d(inverted ? exampleInvStrokeAndFillCase
1837cb93a386Sopenharmony_ci                                        : exampleStrokeAndFillCase, r);
1838cb93a386Sopenharmony_ci                    a.compare(r, b, TestCase::kAllSame_ComparisonExpecation);
1839cb93a386Sopenharmony_ci                    c.compare(r, d, TestCase::kAllSame_ComparisonExpecation);
1840cb93a386Sopenharmony_ci
1841cb93a386Sopenharmony_ci                    const GrStyledShape& strokeCase = shapes[index(inverted, dir, start, kStroke,
1842cb93a386Sopenharmony_ci                                                             dash)];
1843cb93a386Sopenharmony_ci                    const GrStyledShape& hairlineCase = shapes[index(inverted, dir, start,
1844cb93a386Sopenharmony_ci                                                               kHairline, dash)];
1845cb93a386Sopenharmony_ci
1846cb93a386Sopenharmony_ci                    TestCase e(strokeCase, r);
1847cb93a386Sopenharmony_ci                    TestCase g(hairlineCase, r);
1848cb93a386Sopenharmony_ci
1849cb93a386Sopenharmony_ci                    // Both hairline and stroke shapes must respect the dashing.
1850cb93a386Sopenharmony_ci                    if (dash) {
1851cb93a386Sopenharmony_ci                        // Dashing always ignores the inverseness. skbug.com/5421
1852cb93a386Sopenharmony_ci                        TestCase f(exampleStrokeCase, r);
1853cb93a386Sopenharmony_ci                        TestCase h(exampleHairlineCase, r);
1854cb93a386Sopenharmony_ci                        unsigned expectedStart = canonicalize_rrect_start(start, rrect);
1855cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, strokeCase.style().pathEffect());
1856cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, hairlineCase.style().pathEffect());
1857cb93a386Sopenharmony_ci
1858cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, strokeCase.asRRect(&queryRR, &queryDir, &queryStart,
1859cb93a386Sopenharmony_ci                                                              &queryInverted));
1860cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, queryRR == rrect);
1861cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, queryDir == dir);
1862cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, queryStart == expectedStart);
1863cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, !queryInverted);
1864cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, hairlineCase.asRRect(&queryRR, &queryDir, &queryStart,
1865cb93a386Sopenharmony_ci                                                                &queryInverted));
1866cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, queryRR == rrect);
1867cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, queryDir == dir);
1868cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, queryStart == expectedStart);
1869cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, !queryInverted);
1870cb93a386Sopenharmony_ci
1871cb93a386Sopenharmony_ci                        // The pre-style case for the dash will match the non-dash example iff the
1872cb93a386Sopenharmony_ci                        // dir and start match (dir=cw, start=0).
1873cb93a386Sopenharmony_ci                        if (0 == expectedStart && SkPathDirection::kCW == dir) {
1874cb93a386Sopenharmony_ci                            e.compare(r, f, TestCase::kSameUpToPE_ComparisonExpecation);
1875cb93a386Sopenharmony_ci                            g.compare(r, h, TestCase::kSameUpToPE_ComparisonExpecation);
1876cb93a386Sopenharmony_ci                        } else {
1877cb93a386Sopenharmony_ci                            e.compare(r, f, TestCase::kAllDifferent_ComparisonExpecation);
1878cb93a386Sopenharmony_ci                            g.compare(r, h, TestCase::kAllDifferent_ComparisonExpecation);
1879cb93a386Sopenharmony_ci                        }
1880cb93a386Sopenharmony_ci                    } else {
1881cb93a386Sopenharmony_ci                        TestCase f(inverted ? exampleInvStrokeCase : exampleStrokeCase, r);
1882cb93a386Sopenharmony_ci                        TestCase h(inverted ? exampleInvHairlineCase : exampleHairlineCase, r);
1883cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, !strokeCase.style().pathEffect());
1884cb93a386Sopenharmony_ci                        REPORTER_ASSERT(r, !hairlineCase.style().pathEffect());
1885cb93a386Sopenharmony_ci                        e.compare(r, f, TestCase::kAllSame_ComparisonExpecation);
1886cb93a386Sopenharmony_ci                        g.compare(r, h, TestCase::kAllSame_ComparisonExpecation);
1887cb93a386Sopenharmony_ci                    }
1888cb93a386Sopenharmony_ci                }
1889cb93a386Sopenharmony_ci            }
1890cb93a386Sopenharmony_ci        }
1891cb93a386Sopenharmony_ci    }
1892cb93a386Sopenharmony_ci}
1893cb93a386Sopenharmony_ci
1894cb93a386Sopenharmony_ciDEF_TEST(GrStyledShape_lines, r) {
1895cb93a386Sopenharmony_ci    static constexpr SkPoint kA { 1,  1};
1896cb93a386Sopenharmony_ci    static constexpr SkPoint kB { 5, -9};
1897cb93a386Sopenharmony_ci    static constexpr SkPoint kC {-3, 17};
1898cb93a386Sopenharmony_ci
1899cb93a386Sopenharmony_ci    SkPath lineAB = SkPath::Line(kA, kB);
1900cb93a386Sopenharmony_ci    SkPath lineBA = SkPath::Line(kB, kA);
1901cb93a386Sopenharmony_ci    SkPath lineAC = SkPath::Line(kB, kC);
1902cb93a386Sopenharmony_ci    SkPath invLineAB = lineAB;
1903cb93a386Sopenharmony_ci
1904cb93a386Sopenharmony_ci    invLineAB.setFillType(SkPathFillType::kInverseEvenOdd);
1905cb93a386Sopenharmony_ci
1906cb93a386Sopenharmony_ci    SkPaint fill;
1907cb93a386Sopenharmony_ci    SkPaint stroke;
1908cb93a386Sopenharmony_ci    stroke.setStyle(SkPaint::kStroke_Style);
1909cb93a386Sopenharmony_ci    stroke.setStrokeWidth(2.f);
1910cb93a386Sopenharmony_ci    SkPaint hairline;
1911cb93a386Sopenharmony_ci    hairline.setStyle(SkPaint::kStroke_Style);
1912cb93a386Sopenharmony_ci    hairline.setStrokeWidth(0.f);
1913cb93a386Sopenharmony_ci    SkPaint dash = stroke;
1914cb93a386Sopenharmony_ci    dash.setPathEffect(make_dash());
1915cb93a386Sopenharmony_ci
1916cb93a386Sopenharmony_ci    TestCase fillAB(r, lineAB, fill);
1917cb93a386Sopenharmony_ci    TestCase fillEmpty(r, SkPath(), fill);
1918cb93a386Sopenharmony_ci    fillAB.compare(r, fillEmpty, TestCase::kAllSame_ComparisonExpecation);
1919cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !fillAB.baseShape().asLine(nullptr, nullptr));
1920cb93a386Sopenharmony_ci
1921cb93a386Sopenharmony_ci    SkPath path;
1922cb93a386Sopenharmony_ci    path.toggleInverseFillType();
1923cb93a386Sopenharmony_ci    TestCase fillEmptyInverted(r, path, fill);
1924cb93a386Sopenharmony_ci    TestCase fillABInverted(r, invLineAB, fill);
1925cb93a386Sopenharmony_ci    fillABInverted.compare(r, fillEmptyInverted, TestCase::kAllSame_ComparisonExpecation);
1926cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !fillABInverted.baseShape().asLine(nullptr, nullptr));
1927cb93a386Sopenharmony_ci
1928cb93a386Sopenharmony_ci    TestCase strokeAB(r, lineAB, stroke);
1929cb93a386Sopenharmony_ci    TestCase strokeBA(r, lineBA, stroke);
1930cb93a386Sopenharmony_ci    TestCase strokeAC(r, lineAC, stroke);
1931cb93a386Sopenharmony_ci
1932cb93a386Sopenharmony_ci    TestCase hairlineAB(r, lineAB, hairline);
1933cb93a386Sopenharmony_ci    TestCase hairlineBA(r, lineBA, hairline);
1934cb93a386Sopenharmony_ci    TestCase hairlineAC(r, lineAC, hairline);
1935cb93a386Sopenharmony_ci
1936cb93a386Sopenharmony_ci    TestCase dashAB(r, lineAB, dash);
1937cb93a386Sopenharmony_ci    TestCase dashBA(r, lineBA, dash);
1938cb93a386Sopenharmony_ci    TestCase dashAC(r, lineAC, dash);
1939cb93a386Sopenharmony_ci
1940cb93a386Sopenharmony_ci    strokeAB.compare(r, fillAB, TestCase::kAllDifferent_ComparisonExpecation);
1941cb93a386Sopenharmony_ci
1942cb93a386Sopenharmony_ci    strokeAB.compare(r, strokeBA, TestCase::kAllSame_ComparisonExpecation);
1943cb93a386Sopenharmony_ci    strokeAB.compare(r, strokeAC, TestCase::kAllDifferent_ComparisonExpecation);
1944cb93a386Sopenharmony_ci
1945cb93a386Sopenharmony_ci    hairlineAB.compare(r, hairlineBA, TestCase::kAllSame_ComparisonExpecation);
1946cb93a386Sopenharmony_ci    hairlineAB.compare(r, hairlineAC, TestCase::kAllDifferent_ComparisonExpecation);
1947cb93a386Sopenharmony_ci
1948cb93a386Sopenharmony_ci    dashAB.compare(r, dashBA, TestCase::kAllDifferent_ComparisonExpecation);
1949cb93a386Sopenharmony_ci    dashAB.compare(r, dashAC, TestCase::kAllDifferent_ComparisonExpecation);
1950cb93a386Sopenharmony_ci
1951cb93a386Sopenharmony_ci    strokeAB.compare(r, hairlineAB, TestCase::kSameUpToStroke_ComparisonExpecation);
1952cb93a386Sopenharmony_ci
1953cb93a386Sopenharmony_ci    // One of dashAB or dashBA should have the same line as strokeAB. It depends upon how
1954cb93a386Sopenharmony_ci    // GrStyledShape canonicalizes line endpoints (when it can, i.e. when not dashed).
1955cb93a386Sopenharmony_ci    bool canonicalizeAsAB;
1956cb93a386Sopenharmony_ci    SkPoint canonicalPts[2] {kA, kB};
1957cb93a386Sopenharmony_ci    // Init these to suppress warnings.
1958cb93a386Sopenharmony_ci    bool inverted = true;
1959cb93a386Sopenharmony_ci    SkPoint pts[2] {{0, 0}, {0, 0}};
1960cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted);
1961cb93a386Sopenharmony_ci    if (pts[0] == kA && pts[1] == kB) {
1962cb93a386Sopenharmony_ci        canonicalizeAsAB = true;
1963cb93a386Sopenharmony_ci    } else if (pts[1] == kA && pts[0] == kB) {
1964cb93a386Sopenharmony_ci        canonicalizeAsAB = false;
1965cb93a386Sopenharmony_ci        using std::swap;
1966cb93a386Sopenharmony_ci        swap(canonicalPts[0], canonicalPts[1]);
1967cb93a386Sopenharmony_ci    } else {
1968cb93a386Sopenharmony_ci        ERRORF(r, "Should return pts (a,b) or (b, a)");
1969cb93a386Sopenharmony_ci        return;
1970cb93a386Sopenharmony_ci    }
1971cb93a386Sopenharmony_ci
1972cb93a386Sopenharmony_ci    strokeAB.compare(r, canonicalizeAsAB ? dashAB : dashBA,
1973cb93a386Sopenharmony_ci                     TestCase::kSameUpToPE_ComparisonExpecation);
1974cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted &&
1975cb93a386Sopenharmony_ci                       pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1976cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, hairlineAB.baseShape().asLine(pts, &inverted) && !inverted &&
1977cb93a386Sopenharmony_ci                       pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1978cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dashAB.baseShape().asLine(pts, &inverted) && !inverted &&
1979cb93a386Sopenharmony_ci                       pts[0] == kA && pts[1] == kB);
1980cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dashBA.baseShape().asLine(pts, &inverted) && !inverted &&
1981cb93a386Sopenharmony_ci                       pts[0] == kB && pts[1] == kA);
1982cb93a386Sopenharmony_ci
1983cb93a386Sopenharmony_ci
1984cb93a386Sopenharmony_ci    TestCase strokeInvAB(r, invLineAB, stroke);
1985cb93a386Sopenharmony_ci    TestCase hairlineInvAB(r, invLineAB, hairline);
1986cb93a386Sopenharmony_ci    TestCase dashInvAB(r, invLineAB, dash);
1987cb93a386Sopenharmony_ci    strokeInvAB.compare(r, strokeAB, TestCase::kAllDifferent_ComparisonExpecation);
1988cb93a386Sopenharmony_ci    hairlineInvAB.compare(r, hairlineAB, TestCase::kAllDifferent_ComparisonExpecation);
1989cb93a386Sopenharmony_ci    // Dashing ignores inverse.
1990cb93a386Sopenharmony_ci    dashInvAB.compare(r, dashAB, TestCase::kAllSame_ComparisonExpecation);
1991cb93a386Sopenharmony_ci
1992cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, strokeInvAB.baseShape().asLine(pts, &inverted) && inverted &&
1993cb93a386Sopenharmony_ci                       pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1994cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, hairlineInvAB.baseShape().asLine(pts, &inverted) && inverted &&
1995cb93a386Sopenharmony_ci                       pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1996cb93a386Sopenharmony_ci    // Dashing ignores inverse.
1997cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dashInvAB.baseShape().asLine(pts, &inverted) && !inverted &&
1998cb93a386Sopenharmony_ci                       pts[0] == kA && pts[1] == kB);
1999cb93a386Sopenharmony_ci
2000cb93a386Sopenharmony_ci}
2001cb93a386Sopenharmony_ci
2002cb93a386Sopenharmony_ciDEF_TEST(GrStyledShape_stroked_lines, r) {
2003cb93a386Sopenharmony_ci    static constexpr SkScalar kIntervals1[] = {1.f, 0.f};
2004cb93a386Sopenharmony_ci    auto dash1 = SkDashPathEffect::Make(kIntervals1, SK_ARRAY_COUNT(kIntervals1), 0.f);
2005cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dash1);
2006cb93a386Sopenharmony_ci    static constexpr SkScalar kIntervals2[] = {10.f, 0.f, 5.f, 0.f};
2007cb93a386Sopenharmony_ci    auto dash2 = SkDashPathEffect::Make(kIntervals2, SK_ARRAY_COUNT(kIntervals2), 10.f);
2008cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dash2);
2009cb93a386Sopenharmony_ci
2010cb93a386Sopenharmony_ci    sk_sp<SkPathEffect> pathEffects[] = {nullptr, std::move(dash1), std::move(dash2)};
2011cb93a386Sopenharmony_ci
2012cb93a386Sopenharmony_ci    for (const auto& pe : pathEffects) {
2013cb93a386Sopenharmony_ci        // Paints to try
2014cb93a386Sopenharmony_ci        SkPaint buttCap;
2015cb93a386Sopenharmony_ci        buttCap.setStyle(SkPaint::kStroke_Style);
2016cb93a386Sopenharmony_ci        buttCap.setStrokeWidth(4);
2017cb93a386Sopenharmony_ci        buttCap.setStrokeCap(SkPaint::kButt_Cap);
2018cb93a386Sopenharmony_ci        buttCap.setPathEffect(pe);
2019cb93a386Sopenharmony_ci
2020cb93a386Sopenharmony_ci        SkPaint squareCap = buttCap;
2021cb93a386Sopenharmony_ci        squareCap.setStrokeCap(SkPaint::kSquare_Cap);
2022cb93a386Sopenharmony_ci        squareCap.setPathEffect(pe);
2023cb93a386Sopenharmony_ci
2024cb93a386Sopenharmony_ci        SkPaint roundCap = buttCap;
2025cb93a386Sopenharmony_ci        roundCap.setStrokeCap(SkPaint::kRound_Cap);
2026cb93a386Sopenharmony_ci        roundCap.setPathEffect(pe);
2027cb93a386Sopenharmony_ci
2028cb93a386Sopenharmony_ci        // vertical
2029cb93a386Sopenharmony_ci        SkPath linePath;
2030cb93a386Sopenharmony_ci        linePath.moveTo(4, 4);
2031cb93a386Sopenharmony_ci        linePath.lineTo(4, 5);
2032cb93a386Sopenharmony_ci
2033cb93a386Sopenharmony_ci        SkPaint fill;
2034cb93a386Sopenharmony_ci
2035cb93a386Sopenharmony_ci        make_TestCase(r, linePath, buttCap)->compare(
2036cb93a386Sopenharmony_ci                r, TestCase(r, SkRect::MakeLTRB(2, 4, 6, 5), fill),
2037cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2038cb93a386Sopenharmony_ci
2039cb93a386Sopenharmony_ci        make_TestCase(r, linePath, squareCap)->compare(
2040cb93a386Sopenharmony_ci                r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 7), fill),
2041cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2042cb93a386Sopenharmony_ci
2043cb93a386Sopenharmony_ci        make_TestCase(r, linePath, roundCap)->compare(r,
2044cb93a386Sopenharmony_ci                TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 7), 2, 2), fill),
2045cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2046cb93a386Sopenharmony_ci
2047cb93a386Sopenharmony_ci        // horizontal
2048cb93a386Sopenharmony_ci        linePath.reset();
2049cb93a386Sopenharmony_ci        linePath.moveTo(4, 4);
2050cb93a386Sopenharmony_ci        linePath.lineTo(5, 4);
2051cb93a386Sopenharmony_ci
2052cb93a386Sopenharmony_ci        make_TestCase(r, linePath, buttCap)->compare(
2053cb93a386Sopenharmony_ci                r, TestCase(r, SkRect::MakeLTRB(4, 2, 5, 6), fill),
2054cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2055cb93a386Sopenharmony_ci        make_TestCase(r, linePath, squareCap)->compare(
2056cb93a386Sopenharmony_ci                r, TestCase(r, SkRect::MakeLTRB(2, 2, 7, 6), fill),
2057cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2058cb93a386Sopenharmony_ci        make_TestCase(r, linePath, roundCap)->compare(
2059cb93a386Sopenharmony_ci                r, TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 7, 6), 2, 2), fill),
2060cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2061cb93a386Sopenharmony_ci
2062cb93a386Sopenharmony_ci        // point
2063cb93a386Sopenharmony_ci        linePath.reset();
2064cb93a386Sopenharmony_ci        linePath.moveTo(4, 4);
2065cb93a386Sopenharmony_ci        linePath.lineTo(4, 4);
2066cb93a386Sopenharmony_ci
2067cb93a386Sopenharmony_ci        make_TestCase(r, linePath, buttCap)->compare(
2068cb93a386Sopenharmony_ci                r, TestCase(r, SkRect::MakeEmpty(), fill),
2069cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2070cb93a386Sopenharmony_ci        make_TestCase(r, linePath, squareCap)->compare(
2071cb93a386Sopenharmony_ci                r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 6), fill),
2072cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2073cb93a386Sopenharmony_ci        make_TestCase(r, linePath, roundCap)->compare(
2074cb93a386Sopenharmony_ci                r, TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 6), 2, 2), fill),
2075cb93a386Sopenharmony_ci                TestCase::kAllSame_ComparisonExpecation);
2076cb93a386Sopenharmony_ci    }
2077cb93a386Sopenharmony_ci}
2078cb93a386Sopenharmony_ci
2079cb93a386Sopenharmony_ciDEF_TEST(GrStyledShape_short_path_keys, r) {
2080cb93a386Sopenharmony_ci    SkPaint paints[4];
2081cb93a386Sopenharmony_ci    paints[1].setStyle(SkPaint::kStroke_Style);
2082cb93a386Sopenharmony_ci    paints[1].setStrokeWidth(5.f);
2083cb93a386Sopenharmony_ci    paints[2].setStyle(SkPaint::kStroke_Style);
2084cb93a386Sopenharmony_ci    paints[2].setStrokeWidth(0.f);
2085cb93a386Sopenharmony_ci    paints[3].setStyle(SkPaint::kStrokeAndFill_Style);
2086cb93a386Sopenharmony_ci    paints[3].setStrokeWidth(5.f);
2087cb93a386Sopenharmony_ci
2088cb93a386Sopenharmony_ci    auto compare = [r, &paints] (const SkPath& pathA, const SkPath& pathB,
2089cb93a386Sopenharmony_ci                                 TestCase::ComparisonExpecation expectation) {
2090cb93a386Sopenharmony_ci        SkPath volatileA = pathA;
2091cb93a386Sopenharmony_ci        SkPath volatileB = pathB;
2092cb93a386Sopenharmony_ci        volatileA.setIsVolatile(true);
2093cb93a386Sopenharmony_ci        volatileB.setIsVolatile(true);
2094cb93a386Sopenharmony_ci        for (const SkPaint& paint : paints) {
2095cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, !GrStyledShape(volatileA, paint).hasUnstyledKey());
2096cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, !GrStyledShape(volatileB, paint).hasUnstyledKey());
2097cb93a386Sopenharmony_ci            for (PathGeo::Invert invert : {PathGeo::Invert::kNo, PathGeo::Invert::kYes}) {
2098cb93a386Sopenharmony_ci                TestCase caseA(PathGeo(pathA, invert), paint, r);
2099cb93a386Sopenharmony_ci                TestCase caseB(PathGeo(pathB, invert), paint, r);
2100cb93a386Sopenharmony_ci                caseA.compare(r, caseB, expectation);
2101cb93a386Sopenharmony_ci            }
2102cb93a386Sopenharmony_ci        }
2103cb93a386Sopenharmony_ci    };
2104cb93a386Sopenharmony_ci
2105cb93a386Sopenharmony_ci    SkPath pathA;
2106cb93a386Sopenharmony_ci    SkPath pathB;
2107cb93a386Sopenharmony_ci
2108cb93a386Sopenharmony_ci    // Two identical paths
2109cb93a386Sopenharmony_ci    pathA.lineTo(10.f, 10.f);
2110cb93a386Sopenharmony_ci    pathA.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2111cb93a386Sopenharmony_ci
2112cb93a386Sopenharmony_ci    pathB.lineTo(10.f, 10.f);
2113cb93a386Sopenharmony_ci    pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2114cb93a386Sopenharmony_ci    compare(pathA, pathB, TestCase::kAllSame_ComparisonExpecation);
2115cb93a386Sopenharmony_ci
2116cb93a386Sopenharmony_ci    // Give path b a different point
2117cb93a386Sopenharmony_ci    pathB.reset();
2118cb93a386Sopenharmony_ci    pathB.lineTo(10.f, 10.f);
2119cb93a386Sopenharmony_ci    pathB.conicTo(21.f, 20.f, 20.f, 30.f, 0.7f);
2120cb93a386Sopenharmony_ci    compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2121cb93a386Sopenharmony_ci
2122cb93a386Sopenharmony_ci    // Give path b a different conic weight
2123cb93a386Sopenharmony_ci    pathB.reset();
2124cb93a386Sopenharmony_ci    pathB.lineTo(10.f, 10.f);
2125cb93a386Sopenharmony_ci    pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2126cb93a386Sopenharmony_ci    compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2127cb93a386Sopenharmony_ci
2128cb93a386Sopenharmony_ci    // Give path b an extra lineTo verb
2129cb93a386Sopenharmony_ci    pathB.reset();
2130cb93a386Sopenharmony_ci    pathB.lineTo(10.f, 10.f);
2131cb93a386Sopenharmony_ci    pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2132cb93a386Sopenharmony_ci    pathB.lineTo(50.f, 50.f);
2133cb93a386Sopenharmony_ci    compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2134cb93a386Sopenharmony_ci
2135cb93a386Sopenharmony_ci    // Give path b a close
2136cb93a386Sopenharmony_ci    pathB.reset();
2137cb93a386Sopenharmony_ci    pathB.lineTo(10.f, 10.f);
2138cb93a386Sopenharmony_ci    pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2139cb93a386Sopenharmony_ci    pathB.close();
2140cb93a386Sopenharmony_ci    compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2141cb93a386Sopenharmony_ci}
2142cb93a386Sopenharmony_ci
2143cb93a386Sopenharmony_ciDEF_TEST(GrStyledShape, reporter) {
2144cb93a386Sopenharmony_ci    SkTArray<std::unique_ptr<Geo>> geos;
2145cb93a386Sopenharmony_ci    SkTArray<std::unique_ptr<RRectPathGeo>> rrectPathGeos;
2146cb93a386Sopenharmony_ci
2147cb93a386Sopenharmony_ci    for (auto r : { SkRect::MakeWH(10, 20),
2148cb93a386Sopenharmony_ci                    SkRect::MakeWH(-10, -20),
2149cb93a386Sopenharmony_ci                    SkRect::MakeWH(-10, 20),
2150cb93a386Sopenharmony_ci                    SkRect::MakeWH(10, -20)}) {
2151cb93a386Sopenharmony_ci        geos.emplace_back(new RectGeo(r));
2152cb93a386Sopenharmony_ci        SkPath rectPath;
2153cb93a386Sopenharmony_ci        rectPath.addRect(r);
2154cb93a386Sopenharmony_ci        geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2155cb93a386Sopenharmony_ci                                           PathGeo::Invert::kNo));
2156cb93a386Sopenharmony_ci        geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2157cb93a386Sopenharmony_ci                                           PathGeo::Invert::kYes));
2158cb93a386Sopenharmony_ci        rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2159cb93a386Sopenharmony_ci                                                    PathGeo::Invert::kNo));
2160cb93a386Sopenharmony_ci    }
2161cb93a386Sopenharmony_ci    for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)),
2162cb93a386Sopenharmony_ci                     SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4),
2163cb93a386Sopenharmony_ci                     SkRRect::MakeOval(SkRect::MakeWH(20, 20))}) {
2164cb93a386Sopenharmony_ci        geos.emplace_back(new RRectGeo(rr));
2165cb93a386Sopenharmony_ci        test_rrect(reporter, rr);
2166cb93a386Sopenharmony_ci        SkPath rectPath;
2167cb93a386Sopenharmony_ci        rectPath.addRRect(rr);
2168cb93a386Sopenharmony_ci        geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2169cb93a386Sopenharmony_ci                                           PathGeo::Invert::kNo));
2170cb93a386Sopenharmony_ci        geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2171cb93a386Sopenharmony_ci                                           PathGeo::Invert::kYes));
2172cb93a386Sopenharmony_ci        rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, rr,
2173cb93a386Sopenharmony_ci                                                    RRectPathGeo::RRectForStroke::kYes,
2174cb93a386Sopenharmony_ci                                                    PathGeo::Invert::kNo));
2175cb93a386Sopenharmony_ci    }
2176cb93a386Sopenharmony_ci
2177cb93a386Sopenharmony_ci    // Arcs
2178cb93a386Sopenharmony_ci    geos.emplace_back(new ArcGeo(SkRect::MakeWH(200, 100), 12.f, 110.f, false));
2179cb93a386Sopenharmony_ci    geos.emplace_back(new ArcGeo(SkRect::MakeWH(200, 100), 12.f, 110.f, true));
2180cb93a386Sopenharmony_ci
2181cb93a386Sopenharmony_ci    {
2182cb93a386Sopenharmony_ci        SkPath openRectPath;
2183cb93a386Sopenharmony_ci        openRectPath.moveTo(0, 0);
2184cb93a386Sopenharmony_ci        openRectPath.lineTo(10, 0);
2185cb93a386Sopenharmony_ci        openRectPath.lineTo(10, 10);
2186cb93a386Sopenharmony_ci        openRectPath.lineTo(0, 10);
2187cb93a386Sopenharmony_ci        geos.emplace_back(new RRectPathGeo(
2188cb93a386Sopenharmony_ci                    openRectPath, SkRect::MakeWH(10, 10),
2189cb93a386Sopenharmony_ci                    RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2190cb93a386Sopenharmony_ci        geos.emplace_back(new RRectPathGeo(
2191cb93a386Sopenharmony_ci                    openRectPath, SkRect::MakeWH(10, 10),
2192cb93a386Sopenharmony_ci                    RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kYes));
2193cb93a386Sopenharmony_ci        rrectPathGeos.emplace_back(new RRectPathGeo(
2194cb93a386Sopenharmony_ci                    openRectPath, SkRect::MakeWH(10, 10),
2195cb93a386Sopenharmony_ci                    RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2196cb93a386Sopenharmony_ci    }
2197cb93a386Sopenharmony_ci
2198cb93a386Sopenharmony_ci    {
2199cb93a386Sopenharmony_ci        SkPath quadPath;
2200cb93a386Sopenharmony_ci        quadPath.quadTo(10, 10, 5, 8);
2201cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kNo));
2202cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kYes));
2203cb93a386Sopenharmony_ci    }
2204cb93a386Sopenharmony_ci
2205cb93a386Sopenharmony_ci    {
2206cb93a386Sopenharmony_ci        SkPath linePath;
2207cb93a386Sopenharmony_ci        linePath.lineTo(10, 10);
2208cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kNo));
2209cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kYes));
2210cb93a386Sopenharmony_ci    }
2211cb93a386Sopenharmony_ci
2212cb93a386Sopenharmony_ci    // Horizontal and vertical paths become rrects when stroked.
2213cb93a386Sopenharmony_ci    {
2214cb93a386Sopenharmony_ci        SkPath vLinePath;
2215cb93a386Sopenharmony_ci        vLinePath.lineTo(0, 10);
2216cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kNo));
2217cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kYes));
2218cb93a386Sopenharmony_ci    }
2219cb93a386Sopenharmony_ci
2220cb93a386Sopenharmony_ci    {
2221cb93a386Sopenharmony_ci        SkPath hLinePath;
2222cb93a386Sopenharmony_ci        hLinePath.lineTo(10, 0);
2223cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kNo));
2224cb93a386Sopenharmony_ci        geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kYes));
2225cb93a386Sopenharmony_ci    }
2226cb93a386Sopenharmony_ci
2227cb93a386Sopenharmony_ci    for (int i = 0; i < geos.count(); ++i) {
2228cb93a386Sopenharmony_ci        test_basic(reporter, *geos[i]);
2229cb93a386Sopenharmony_ci        test_scale(reporter, *geos[i]);
2230cb93a386Sopenharmony_ci        test_dash_fill(reporter, *geos[i]);
2231cb93a386Sopenharmony_ci        test_null_dash(reporter, *geos[i]);
2232cb93a386Sopenharmony_ci        // Test modifying various stroke params.
2233cb93a386Sopenharmony_ci        test_stroke_param<SkScalar>(
2234cb93a386Sopenharmony_ci                reporter, *geos[i],
2235cb93a386Sopenharmony_ci                [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
2236cb93a386Sopenharmony_ci                SkIntToScalar(2), SkIntToScalar(4));
2237cb93a386Sopenharmony_ci        test_stroke_join(reporter, *geos[i]);
2238cb93a386Sopenharmony_ci        test_stroke_cap(reporter, *geos[i]);
2239cb93a386Sopenharmony_ci        test_miter_limit(reporter, *geos[i]);
2240cb93a386Sopenharmony_ci        test_path_effect_makes_rrect(reporter, *geos[i]);
2241cb93a386Sopenharmony_ci        test_unknown_path_effect(reporter, *geos[i]);
2242cb93a386Sopenharmony_ci        test_path_effect_makes_empty_shape(reporter, *geos[i]);
2243cb93a386Sopenharmony_ci        test_path_effect_fails(reporter, *geos[i]);
2244cb93a386Sopenharmony_ci        test_make_hairline_path_effect(reporter, *geos[i]);
2245cb93a386Sopenharmony_ci        test_volatile_path(reporter, *geos[i]);
2246cb93a386Sopenharmony_ci    }
2247cb93a386Sopenharmony_ci
2248cb93a386Sopenharmony_ci    for (int i = 0; i < rrectPathGeos.count(); ++i) {
2249cb93a386Sopenharmony_ci        const RRectPathGeo& rrgeo = *rrectPathGeos[i];
2250cb93a386Sopenharmony_ci        SkPaint fillPaint;
2251cb93a386Sopenharmony_ci        TestCase fillPathCase(reporter, rrgeo.path(), fillPaint);
2252cb93a386Sopenharmony_ci        SkRRect rrect;
2253cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, rrgeo.isNonPath(fillPaint) ==
2254cb93a386Sopenharmony_ci                                  fillPathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
2255cb93a386Sopenharmony_ci                                                                   nullptr));
2256cb93a386Sopenharmony_ci        if (rrgeo.isNonPath(fillPaint)) {
2257cb93a386Sopenharmony_ci            TestCase fillPathCase2(reporter, rrgeo.path(), fillPaint);
2258cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
2259cb93a386Sopenharmony_ci            TestCase fillRRectCase(reporter, rrect, fillPaint);
2260cb93a386Sopenharmony_ci            fillPathCase2.compare(reporter, fillRRectCase,
2261cb93a386Sopenharmony_ci                                  TestCase::kAllSame_ComparisonExpecation);
2262cb93a386Sopenharmony_ci        }
2263cb93a386Sopenharmony_ci        SkPaint strokePaint;
2264cb93a386Sopenharmony_ci        strokePaint.setStrokeWidth(3.f);
2265cb93a386Sopenharmony_ci        strokePaint.setStyle(SkPaint::kStroke_Style);
2266cb93a386Sopenharmony_ci        TestCase strokePathCase(reporter, rrgeo.path(), strokePaint);
2267cb93a386Sopenharmony_ci        if (rrgeo.isNonPath(strokePaint)) {
2268cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, strokePathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
2269cb93a386Sopenharmony_ci                                                                         nullptr));
2270cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
2271cb93a386Sopenharmony_ci            TestCase strokeRRectCase(reporter, rrect, strokePaint);
2272cb93a386Sopenharmony_ci            strokePathCase.compare(reporter, strokeRRectCase,
2273cb93a386Sopenharmony_ci                                   TestCase::kAllSame_ComparisonExpecation);
2274cb93a386Sopenharmony_ci        }
2275cb93a386Sopenharmony_ci    }
2276cb93a386Sopenharmony_ci
2277cb93a386Sopenharmony_ci    // Test a volatile empty path.
2278cb93a386Sopenharmony_ci    test_volatile_path(reporter, PathGeo(SkPath(), PathGeo::Invert::kNo));
2279cb93a386Sopenharmony_ci}
2280cb93a386Sopenharmony_ci
2281cb93a386Sopenharmony_ciDEF_TEST(GrStyledShape_arcs, reporter) {
2282cb93a386Sopenharmony_ci    SkStrokeRec roundStroke(SkStrokeRec::kFill_InitStyle);
2283cb93a386Sopenharmony_ci    roundStroke.setStrokeStyle(2.f);
2284cb93a386Sopenharmony_ci    roundStroke.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 1.f);
2285cb93a386Sopenharmony_ci
2286cb93a386Sopenharmony_ci    SkStrokeRec squareStroke(roundStroke);
2287cb93a386Sopenharmony_ci    squareStroke.setStrokeParams(SkPaint::kSquare_Cap, SkPaint::kRound_Join, 1.f);
2288cb93a386Sopenharmony_ci
2289cb93a386Sopenharmony_ci    SkStrokeRec roundStrokeAndFill(roundStroke);
2290cb93a386Sopenharmony_ci    roundStrokeAndFill.setStrokeStyle(2.f, true);
2291cb93a386Sopenharmony_ci
2292cb93a386Sopenharmony_ci    static constexpr SkScalar kIntervals[] = {1, 2};
2293cb93a386Sopenharmony_ci    auto dash = SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 1.5f);
2294cb93a386Sopenharmony_ci
2295cb93a386Sopenharmony_ci    SkTArray<GrStyle> styles;
2296cb93a386Sopenharmony_ci    styles.push_back(GrStyle::SimpleFill());
2297cb93a386Sopenharmony_ci    styles.push_back(GrStyle::SimpleHairline());
2298cb93a386Sopenharmony_ci    styles.push_back(GrStyle(roundStroke, nullptr));
2299cb93a386Sopenharmony_ci    styles.push_back(GrStyle(squareStroke, nullptr));
2300cb93a386Sopenharmony_ci    styles.push_back(GrStyle(roundStrokeAndFill, nullptr));
2301cb93a386Sopenharmony_ci    styles.push_back(GrStyle(roundStroke, dash));
2302cb93a386Sopenharmony_ci
2303cb93a386Sopenharmony_ci    for (const auto& style : styles) {
2304cb93a386Sopenharmony_ci        // An empty rect never draws anything according to SkCanvas::drawArc() docs.
2305cb93a386Sopenharmony_ci        TestCase emptyArc(GrStyledShape::MakeArc(SkRect::MakeEmpty(), 0, 90.f, false, style),
2306cb93a386Sopenharmony_ci                                                 reporter);
2307cb93a386Sopenharmony_ci        TestCase emptyPath(reporter, SkPath(), style);
2308cb93a386Sopenharmony_ci        emptyArc.compare(reporter, emptyPath, TestCase::kAllSame_ComparisonExpecation);
2309cb93a386Sopenharmony_ci
2310cb93a386Sopenharmony_ci        static constexpr SkRect kOval1{0, 0, 50, 50};
2311cb93a386Sopenharmony_ci        static constexpr SkRect kOval2{50, 0, 100, 50};
2312cb93a386Sopenharmony_ci        // Test that swapping starting and ending angle doesn't change the shape unless the arc
2313cb93a386Sopenharmony_ci        // has a path effect. Also test that different ovals produce different shapes.
2314cb93a386Sopenharmony_ci        TestCase arc1CW(GrStyledShape::MakeArc(kOval1, 0, 90.f, false, style), reporter);
2315cb93a386Sopenharmony_ci        TestCase arc1CCW(GrStyledShape::MakeArc(kOval1, 90.f, -90.f, false, style), reporter);
2316cb93a386Sopenharmony_ci
2317cb93a386Sopenharmony_ci        TestCase arc1CWWithCenter(GrStyledShape::MakeArc(kOval1, 0, 90.f, true, style), reporter);
2318cb93a386Sopenharmony_ci        TestCase arc1CCWWithCenter(GrStyledShape::MakeArc(kOval1, 90.f, -90.f, true, style),
2319cb93a386Sopenharmony_ci                                   reporter);
2320cb93a386Sopenharmony_ci
2321cb93a386Sopenharmony_ci        TestCase arc2CW(GrStyledShape::MakeArc(kOval2, 0, 90.f, false, style), reporter);
2322cb93a386Sopenharmony_ci        TestCase arc2CWWithCenter(GrStyledShape::MakeArc(kOval2, 0, 90.f, true, style), reporter);
2323cb93a386Sopenharmony_ci
2324cb93a386Sopenharmony_ci        auto reversedExepectations = style.hasPathEffect()
2325cb93a386Sopenharmony_ci                                             ? TestCase::kAllDifferent_ComparisonExpecation
2326cb93a386Sopenharmony_ci                                             : TestCase::kAllSame_ComparisonExpecation;
2327cb93a386Sopenharmony_ci        arc1CW.compare(reporter, arc1CCW, reversedExepectations);
2328cb93a386Sopenharmony_ci        arc1CWWithCenter.compare(reporter, arc1CCWWithCenter, reversedExepectations);
2329cb93a386Sopenharmony_ci        arc1CW.compare(reporter, arc2CW, TestCase::kAllDifferent_ComparisonExpecation);
2330cb93a386Sopenharmony_ci        arc1CW.compare(reporter, arc1CWWithCenter, TestCase::kAllDifferent_ComparisonExpecation);
2331cb93a386Sopenharmony_ci        arc1CWWithCenter.compare(reporter, arc2CWWithCenter,
2332cb93a386Sopenharmony_ci                                 TestCase::kAllDifferent_ComparisonExpecation);
2333cb93a386Sopenharmony_ci
2334cb93a386Sopenharmony_ci        // Test that two arcs that start at the same angle but specified differently are equivalent.
2335cb93a386Sopenharmony_ci        TestCase arc3A(GrStyledShape::MakeArc(kOval1, 224.f, 73.f, false, style), reporter);
2336cb93a386Sopenharmony_ci        TestCase arc3B(GrStyledShape::MakeArc(kOval1, 224.f - 360.f, 73.f, false, style), reporter);
2337cb93a386Sopenharmony_ci        arc3A.compare(reporter, arc3B, TestCase::kAllDifferent_ComparisonExpecation);
2338cb93a386Sopenharmony_ci
2339cb93a386Sopenharmony_ci        // Test that an arc that traverses the entire oval (and then some) is equivalent to the
2340cb93a386Sopenharmony_ci        // oval itself unless there is a path effect.
2341cb93a386Sopenharmony_ci        TestCase ovalArc(GrStyledShape::MakeArc(kOval1, 150.f, -790.f, false, style), reporter);
2342cb93a386Sopenharmony_ci        TestCase oval(GrStyledShape(SkRRect::MakeOval(kOval1)), reporter);
2343cb93a386Sopenharmony_ci        auto ovalExpectations = style.hasPathEffect() ? TestCase::kAllDifferent_ComparisonExpecation
2344cb93a386Sopenharmony_ci                                                      : TestCase::kAllSame_ComparisonExpecation;
2345cb93a386Sopenharmony_ci        if (style.strokeRec().getWidth() >= 0 && style.strokeRec().getCap() != SkPaint::kButt_Cap) {
2346cb93a386Sopenharmony_ci            ovalExpectations = TestCase::kAllDifferent_ComparisonExpecation;
2347cb93a386Sopenharmony_ci        }
2348cb93a386Sopenharmony_ci        ovalArc.compare(reporter, oval, ovalExpectations);
2349cb93a386Sopenharmony_ci
2350cb93a386Sopenharmony_ci        // If the the arc starts/ends at the center then it is then equivalent to the oval only for
2351cb93a386Sopenharmony_ci        // simple fills.
2352cb93a386Sopenharmony_ci        TestCase ovalArcWithCenter(GrStyledShape::MakeArc(kOval1, 304.f, 1225.f, true, style),
2353cb93a386Sopenharmony_ci                                   reporter);
2354cb93a386Sopenharmony_ci        ovalExpectations = style.isSimpleFill() ? TestCase::kAllSame_ComparisonExpecation
2355cb93a386Sopenharmony_ci                                                : TestCase::kAllDifferent_ComparisonExpecation;
2356cb93a386Sopenharmony_ci        ovalArcWithCenter.compare(reporter, oval, ovalExpectations);
2357cb93a386Sopenharmony_ci    }
2358cb93a386Sopenharmony_ci}
2359cb93a386Sopenharmony_ci
2360cb93a386Sopenharmony_ciDEF_TEST(GrShapeInversion, r) {
2361cb93a386Sopenharmony_ci    SkPath path;
2362cb93a386Sopenharmony_ci    SkScalar radii[] = {10.f, 10.f, 10.f, 10.f,
2363cb93a386Sopenharmony_ci                        10.f, 10.f, 10.f, 10.f};
2364cb93a386Sopenharmony_ci    path.addRoundRect(SkRect::MakeWH(50, 50), radii);
2365cb93a386Sopenharmony_ci    path.toggleInverseFillType();
2366cb93a386Sopenharmony_ci
2367cb93a386Sopenharmony_ci    GrShape inverseRRect(path);
2368cb93a386Sopenharmony_ci    GrShape rrect(inverseRRect);
2369cb93a386Sopenharmony_ci    rrect.setInverted(false);
2370cb93a386Sopenharmony_ci
2371cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, inverseRRect.inverted() && inverseRRect.isPath());
2372cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !rrect.inverted() && rrect.isPath());
2373cb93a386Sopenharmony_ci
2374cb93a386Sopenharmony_ci    // Invertedness should be preserved after simplification
2375cb93a386Sopenharmony_ci    inverseRRect.simplify();
2376cb93a386Sopenharmony_ci    rrect.simplify();
2377cb93a386Sopenharmony_ci
2378cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, inverseRRect.inverted() && inverseRRect.isRRect());
2379cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !rrect.inverted() && rrect.isRRect());
2380cb93a386Sopenharmony_ci
2381cb93a386Sopenharmony_ci    // Invertedness should be reset when calling reset().
2382cb93a386Sopenharmony_ci    inverseRRect.reset();
2383cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !inverseRRect.inverted() && inverseRRect.isEmpty());
2384cb93a386Sopenharmony_ci    inverseRRect.setPath(path);
2385cb93a386Sopenharmony_ci    inverseRRect.reset();
2386cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !inverseRRect.inverted() && inverseRRect.isEmpty());
2387cb93a386Sopenharmony_ci}
2388