Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Typedefs | Functions
GrStyledShapeTest.cpp File Reference
#include "include/core/SkCanvas.h"
#include "include/core/SkClipOp.h"
#include "include/core/SkColor.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkStrokeRec.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkDashPathEffect.h"
#include "include/pathops/SkPathOps.h"
#include "include/private/base/SkTArray.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkPathEffectBase.h"
#include "src/core/SkPathPriv.h"
#include "src/core/SkRectPriv.h"
#include "src/gpu/ganesh/GrStyle.h"
#include "src/gpu/ganesh/geometry/GrShape.h"
#include "src/gpu/ganesh/geometry/GrStyledShape.h"
#include "tests/Test.h"
#include <cstdint>
#include <cstring>
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <utility>

Go to the source code of this file.

Typedefs

using Key = TArray< uint32_t >
 

Functions

static bool make_key (Key *key, const GrStyledShape &shape)
 
static bool paths_fill_same (const SkPath &a, const SkPath &b)
 
static bool test_bounds_by_rasterizing (const SkPath &path, const SkRect &bounds)
 
static bool can_interchange_winding_and_even_odd_fill (const GrStyledShape &shape)
 
static void check_equivalence (skiatest::Reporter *r, const GrStyledShape &a, const GrStyledShape &b, const Key &keyA, const Key &keyB)
 
static void check_original_path_ids (skiatest::Reporter *r, const GrStyledShape &base, const GrStyledShape &pe, const GrStyledShape &peStroke, const GrStyledShape &full)
 
void test_inversions (skiatest::Reporter *r, const GrStyledShape &shape, const Key &shapeKey)
 
static sk_sp< SkPathEffectmake_dash ()
 
static sk_sp< SkPathEffectmake_null_dash ()
 
template<typename... Args>
static std::unique_ptr< TestCasemake_TestCase (Args &&... args)
 
static void test_basic (skiatest::Reporter *reporter, const Geo &geo)
 
static void test_scale (skiatest::Reporter *reporter, const Geo &geo)
 
template<typename T >
static void test_stroke_param_impl (skiatest::Reporter *reporter, const Geo &geo, std::function< void(SkPaint *, T)> setter, T a, T b, bool paramAffectsStroke, bool paramAffectsDashAndStroke)
 
template<typename T >
static void test_stroke_param (skiatest::Reporter *reporter, const Geo &geo, std::function< void(SkPaint *, T)> setter, T a, T b)
 
static void test_stroke_cap (skiatest::Reporter *reporter, const Geo &geo)
 
static bool shape_known_not_to_have_joins (const GrStyledShape &shape)
 
static void test_stroke_join (skiatest::Reporter *reporter, const Geo &geo)
 
static void test_miter_limit (skiatest::Reporter *reporter, const Geo &geo)
 
static void test_dash_fill (skiatest::Reporter *reporter, const Geo &geo)
 
void test_null_dash (skiatest::Reporter *reporter, const Geo &geo)
 
void test_path_effect_makes_rrect (skiatest::Reporter *reporter, const Geo &geo)
 
void test_unknown_path_effect (skiatest::Reporter *reporter, const Geo &geo)
 
void test_make_hairline_path_effect (skiatest::Reporter *reporter, const Geo &geo)
 
void test_volatile_path (skiatest::Reporter *reporter, const Geo &geo)
 
void test_path_effect_makes_empty_shape (skiatest::Reporter *reporter, const Geo &geo)
 
void test_path_effect_fails (skiatest::Reporter *reporter, const Geo &geo)
 
 DEF_TEST (GrStyledShape_empty_shape, reporter)
 
unsigned canonicalize_rrect_start (int s, const SkRRect &rrect)
 
void test_rrect (skiatest::Reporter *r, const SkRRect &rrect)
 
 DEF_TEST (GrStyledShape_lines, r)
 
 DEF_TEST (GrStyledShape_stroked_lines, r)
 
 DEF_TEST (GrStyledShape_short_path_keys, r)
 
 DEF_TEST (GrStyledShape, reporter)
 
 DEF_TEST (GrStyledShape_arcs, reporter)
 
 DEF_TEST (GrShapeInversion, r)
 

Typedef Documentation

◆ Key

using Key = TArray<uint32_t>

Definition at line 64 of file GrStyledShapeTest.cpp.

Function Documentation

◆ can_interchange_winding_and_even_odd_fill()

static bool can_interchange_winding_and_even_odd_fill ( const GrStyledShape shape)
static

Definition at line 124 of file GrStyledShapeTest.cpp.

124 {
125 SkPath path;
126 shape.asPath(&path);
127 if (shape.style().hasNonDashPathEffect()) {
128 return false;
129 }
130 const SkStrokeRec::Style strokeRecStyle = shape.style().strokeRec().getStyle();
131 return strokeRecStyle == SkStrokeRec::kStroke_Style ||
132 strokeRecStyle == SkStrokeRec::kHairline_Style ||
133 (shape.style().isSimpleFill() && path.isConvex());
134}
bool hasNonDashPathEffect() const
Definition GrStyle.h:124
bool isSimpleFill() const
Definition GrStyle.h:114
const SkStrokeRec & strokeRec() const
Definition GrStyle.h:140
void asPath(SkPath *out) const
const GrStyle & style() const
Style getStyle() const
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57

◆ canonicalize_rrect_start()

unsigned canonicalize_rrect_start ( int  s,
const SkRRect rrect 
)

Definition at line 1662 of file GrStyledShapeTest.cpp.

1662 {
1663 switch (rrect.getType()) {
1665 return (s + 1) & 0b110;
1667 return s & 0b110;
1668 default:
1669 return s;
1670 }
1671}
Type getType() const
Definition SkRRect.h:76
@ kOval_Type
non-zero width and height filled with radii
Definition SkRRect.h:69
@ kRect_Type
non-zero width and height, and zeroed radii
Definition SkRRect.h:68
struct MyStruct s
SkRRect rrect
Definition SkRecords.h:232

◆ check_equivalence()

static void check_equivalence ( skiatest::Reporter r,
const GrStyledShape a,
const GrStyledShape b,
const Key keyA,
const Key keyB 
)
static

Definition at line 136 of file GrStyledShapeTest.cpp.

137 {
138 // GrStyledShape only respects the input winding direction and start point for rrect shapes
139 // when there is a path effect. Thus, if there are two GrStyledShapes representing the same
140 // rrect but one has a path effect in its style and the other doesn't then asPath() and the
141 // unstyled key will differ. GrStyledShape will have canonicalized the direction and start point
142 // for the shape without the path effect. If *both* have path effects then they should have both
143 // preserved the direction and starting point.
144
145 // The asRRect() output params are all initialized just to silence compiler warnings about
146 // uninitialized variables.
147 SkRRect rrectA = SkRRect::MakeEmpty(), rrectB = SkRRect::MakeEmpty();
149 unsigned startA = ~0U, startB = ~0U;
150 bool invertedA = true, invertedB = true;
151
152 bool aIsRRect = a.asRRect(&rrectA, &dirA, &startA, &invertedA);
153 bool bIsRRect = b.asRRect(&rrectB, &dirB, &startB, &invertedB);
154 bool aHasPE = a.style().hasPathEffect();
155 bool bHasPE = b.style().hasPathEffect();
156 bool allowSameRRectButDiffStartAndDir = (aIsRRect && bIsRRect) && (aHasPE != bHasPE);
157 // GrStyledShape will close paths with simple fill style.
158 bool allowedClosednessDiff = (a.style().isSimpleFill() != b.style().isSimpleFill());
159 SkPath pathA, pathB;
160 a.asPath(&pathA);
161 b.asPath(&pathB);
162
163 // Having a dash path effect can allow 'a' but not 'b' to turn a inverse fill type into a
164 // non-inverse fill type (or vice versa).
165 bool ignoreInversenessDifference = false;
166 if (pathA.isInverseFillType() != pathB.isInverseFillType()) {
167 const GrStyledShape* s1 = pathA.isInverseFillType() ? &a : &b;
168 const GrStyledShape* s2 = pathA.isInverseFillType() ? &b : &a;
169 bool canDropInverse1 = s1->style().isDashed();
170 bool canDropInverse2 = s2->style().isDashed();
171 ignoreInversenessDifference = (canDropInverse1 != canDropInverse2);
172 }
173 bool ignoreWindingVsEvenOdd = false;
178 if (aCanChange != bCanChange) {
179 ignoreWindingVsEvenOdd = true;
180 }
181 }
182 if (allowSameRRectButDiffStartAndDir) {
183 REPORTER_ASSERT(r, rrectA == rrectB);
184 REPORTER_ASSERT(r, paths_fill_same(pathA, pathB));
185 REPORTER_ASSERT(r, ignoreInversenessDifference || invertedA == invertedB);
186 } else {
187 SkPath pA = pathA;
188 SkPath pB = pathB;
189 REPORTER_ASSERT(r, a.inverseFilled() == pA.isInverseFillType());
190 REPORTER_ASSERT(r, b.inverseFilled() == pB.isInverseFillType());
191 if (ignoreInversenessDifference) {
194 }
195 if (ignoreWindingVsEvenOdd) {
200 }
201 if (!ignoreInversenessDifference && !ignoreWindingVsEvenOdd) {
202 REPORTER_ASSERT(r, keyA == keyB);
203 } else {
204 REPORTER_ASSERT(r, keyA != keyB);
205 }
206 if (allowedClosednessDiff) {
207 // GrStyledShape will close paths with simple fill style. Make the non-filled path
208 // closed so that the comparision will succeed. Make sure both are closed before
209 // comparing.
210 pA.close();
211 pB.close();
212 }
213 REPORTER_ASSERT(r, pA == pB);
214 REPORTER_ASSERT(r, aIsRRect == bIsRRect);
215 if (aIsRRect) {
216 REPORTER_ASSERT(r, rrectA == rrectB);
217 REPORTER_ASSERT(r, dirA == dirB);
218 REPORTER_ASSERT(r, startA == startB);
219 REPORTER_ASSERT(r, ignoreInversenessDifference || invertedA == invertedB);
220 }
221 }
222 REPORTER_ASSERT(r, a.isEmpty() == b.isEmpty());
223 REPORTER_ASSERT(r, allowedClosednessDiff || a.knownToBeClosed() == b.knownToBeClosed());
224 // closedness can affect convexity.
225 REPORTER_ASSERT(r, allowedClosednessDiff || a.knownToBeConvex() == b.knownToBeConvex());
226 if (a.knownToBeConvex()) {
227 REPORTER_ASSERT(r, pathA.isConvex());
228 }
229 if (b.knownToBeConvex()) {
230 REPORTER_ASSERT(r, pathB.isConvex());
231 }
232 REPORTER_ASSERT(r, a.bounds() == b.bounds());
233 REPORTER_ASSERT(r, a.segmentMask() == b.segmentMask());
234 // Init these to suppress warnings.
235 SkPoint pts[4] {{0, 0,}, {0, 0}, {0, 0}, {0, 0}} ;
236 bool invertedLine[2] {true, true};
237 REPORTER_ASSERT(r, a.asLine(pts, &invertedLine[0]) == b.asLine(pts + 2, &invertedLine[1]));
238 // mayBeInverseFilledAfterStyling() is allowed to differ if one has a arbitrary PE and the other
239 // doesn't (since the PE can set any fill type on its output path).
240 // Moreover, dash style explicitly ignores inverseness. So if one is dashed but not the other
241 // then they may disagree about inverseness.
242 if (a.style().hasNonDashPathEffect() == b.style().hasNonDashPathEffect() &&
243 a.style().isDashed() == b.style().isDashed()) {
244 REPORTER_ASSERT(r, a.mayBeInverseFilledAfterStyling() ==
245 b.mayBeInverseFilledAfterStyling());
246 }
247 if (a.asLine(nullptr, nullptr)) {
248 REPORTER_ASSERT(r, pts[2] == pts[0] && pts[3] == pts[1]);
249 REPORTER_ASSERT(r, ignoreInversenessDifference || invertedLine[0] == invertedLine[1]);
250 REPORTER_ASSERT(r, invertedLine[0] == a.inverseFilled());
251 REPORTER_ASSERT(r, invertedLine[1] == b.inverseFilled());
252 }
253 REPORTER_ASSERT(r, ignoreInversenessDifference || a.inverseFilled() == b.inverseFilled());
254}
static bool paths_fill_same(const SkPath &a, const SkPath &b)
static bool can_interchange_winding_and_even_odd_fill(const GrStyledShape &shape)
SkPathDirection
Definition SkPathTypes.h:34
static SkPathFillType SkPathFillType_ConvertToNonInverse(SkPathFillType ft)
Definition SkPathTypes.h:30
SkPathFillType
Definition SkPathTypes.h:11
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
bool isDashed() const
Definition GrStyle.h:126
bool isInverseFillType() const
Definition SkPath.h:244
SkPathFillType getFillType() const
Definition SkPath.h:230
void setFillType(SkPathFillType ft)
Definition SkPath.h:235
bool isConvex() const
Definition SkPath.cpp:416
SkPath & close()
Definition SkPath.cpp:813
static SkRRect MakeEmpty()
Definition SkRRect.h:142
static bool b
struct MyStruct a[10]

◆ check_original_path_ids()

static void check_original_path_ids ( skiatest::Reporter r,
const GrStyledShape base,
const GrStyledShape pe,
const GrStyledShape peStroke,
const GrStyledShape full 
)
static

Definition at line 256 of file GrStyledShapeTest.cpp.

258 {
259 bool baseIsNonVolatilePath = base.testingOnly_isNonVolatilePath();
260 bool peIsPath = pe.testingOnly_isPath();
261 bool peStrokeIsPath = peStroke.testingOnly_isPath();
262 bool fullIsPath = full.testingOnly_isPath();
263
264 REPORTER_ASSERT(r, peStrokeIsPath == fullIsPath);
265
266 uint32_t baseID = base.testingOnly_getOriginalGenerationID();
267 uint32_t peID = pe.testingOnly_getOriginalGenerationID();
268 uint32_t peStrokeID = peStroke.testingOnly_getOriginalGenerationID();
269 uint32_t fullID = full.testingOnly_getOriginalGenerationID();
270
271 // All empty paths have the same gen ID
272 uint32_t emptyID = SkPath().getGenerationID();
273
274 // If we started with a real path, then our genID should match that path's gen ID (and not be
275 // empty). If we started with a simple shape or a volatile path, our original path should have
276 // been reset.
277 REPORTER_ASSERT(r, baseIsNonVolatilePath == (baseID != emptyID));
278
279 // For the derived shapes, if they're simple types, their original paths should have been reset
280 REPORTER_ASSERT(r, peIsPath || (peID == emptyID));
281 REPORTER_ASSERT(r, peStrokeIsPath || (peStrokeID == emptyID));
282 REPORTER_ASSERT(r, fullIsPath || (fullID == emptyID));
283
284 if (!peIsPath) {
285 // If the path effect produces a simple shape, then there are no unbroken chains to test
286 return;
287 }
288
289 // From here on, we know that the path effect produced a shape that was a "real" path
290
291 if (baseIsNonVolatilePath) {
292 REPORTER_ASSERT(r, baseID == peID);
293 }
294
295 if (peStrokeIsPath) {
296 REPORTER_ASSERT(r, peID == peStrokeID);
297 REPORTER_ASSERT(r, peStrokeID == fullID);
298 }
299
300 if (baseIsNonVolatilePath && peStrokeIsPath) {
301 REPORTER_ASSERT(r, baseID == peStrokeID);
302 REPORTER_ASSERT(r, baseID == fullID);
303 }
304}
bool testingOnly_isPath() const
uint32_t testingOnly_getOriginalGenerationID() const
uint32_t getGenerationID() const
Definition SkPath.cpp:356
Definition full.py:1

◆ DEF_TEST() [1/7]

DEF_TEST ( GrShapeInversion  ,
 
)

Definition at line 2386 of file GrStyledShapeTest.cpp.

2386 {
2387 SkPath path;
2388 SkScalar radii[] = {10.f, 10.f, 10.f, 10.f,
2389 10.f, 10.f, 10.f, 10.f};
2390 path.addRoundRect(SkRect::MakeWH(50, 50), radii);
2391 path.toggleInverseFillType();
2392
2393 GrShape inverseRRect(path);
2394 GrShape rrect(inverseRRect);
2395 rrect.setInverted(false);
2396
2397 REPORTER_ASSERT(r, inverseRRect.inverted() && inverseRRect.isPath());
2398 REPORTER_ASSERT(r, !rrect.inverted() && rrect.isPath());
2399
2400 // Invertedness should be preserved after simplification
2401 inverseRRect.simplify();
2402 rrect.simplify();
2403
2404 REPORTER_ASSERT(r, inverseRRect.inverted() && inverseRRect.isRRect());
2405 REPORTER_ASSERT(r, !rrect.inverted() && rrect.isRRect());
2406
2407 // Invertedness should be reset when calling reset().
2408 inverseRRect.reset();
2409 REPORTER_ASSERT(r, !inverseRRect.inverted() && inverseRRect.isEmpty());
2410 inverseRRect.setPath(path);
2411 inverseRRect.reset();
2412 REPORTER_ASSERT(r, !inverseRRect.inverted() && inverseRRect.isEmpty());
2413}
float SkScalar
Definition extension.cpp:12
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609

◆ DEF_TEST() [2/7]

DEF_TEST ( GrStyledShape  ,
reporter   
)

Definition at line 2169 of file GrStyledShapeTest.cpp.

2169 {
2172
2173 for (auto r : { SkRect::MakeWH(10, 20),
2174 SkRect::MakeWH(-10, -20),
2175 SkRect::MakeWH(-10, 20),
2176 SkRect::MakeWH(10, -20)}) {
2177 geos.emplace_back(new RectGeo(r));
2178 SkPath rectPath;
2179 rectPath.addRect(r);
2180 geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2181 PathGeo::Invert::kNo));
2182 geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2183 PathGeo::Invert::kYes));
2184 rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2185 PathGeo::Invert::kNo));
2186 }
2187 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)),
2188 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4),
2190 geos.emplace_back(new RRectGeo(rr));
2191 test_rrect(reporter, rr);
2192 SkPath rectPath;
2193 rectPath.addRRect(rr);
2194 geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2195 PathGeo::Invert::kNo));
2196 geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2197 PathGeo::Invert::kYes));
2198 rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, rr,
2199 RRectPathGeo::RRectForStroke::kYes,
2200 PathGeo::Invert::kNo));
2201 }
2202
2203 // Arcs
2204 geos.emplace_back(new ArcGeo(SkRect::MakeWH(200, 100), 12.f, 110.f, false));
2205 geos.emplace_back(new ArcGeo(SkRect::MakeWH(200, 100), 12.f, 110.f, true));
2206
2207 {
2208 SkPath openRectPath;
2209 openRectPath.moveTo(0, 0);
2210 openRectPath.lineTo(10, 0);
2211 openRectPath.lineTo(10, 10);
2212 openRectPath.lineTo(0, 10);
2213 geos.emplace_back(new RRectPathGeo(
2214 openRectPath, SkRect::MakeWH(10, 10),
2215 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2216 geos.emplace_back(new RRectPathGeo(
2217 openRectPath, SkRect::MakeWH(10, 10),
2218 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kYes));
2219 rrectPathGeos.emplace_back(new RRectPathGeo(
2220 openRectPath, SkRect::MakeWH(10, 10),
2221 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2222 }
2223
2224 {
2225 SkPath quadPath;
2226 quadPath.quadTo(10, 10, 5, 8);
2227 geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kNo));
2228 geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kYes));
2229 }
2230
2231 {
2232 SkPath linePath;
2233 linePath.lineTo(10, 10);
2234 geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kNo));
2235 geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kYes));
2236 }
2237
2238 // Horizontal and vertical paths become rrects when stroked.
2239 {
2240 SkPath vLinePath;
2241 vLinePath.lineTo(0, 10);
2242 geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kNo));
2243 geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kYes));
2244 }
2245
2246 {
2247 SkPath hLinePath;
2248 hLinePath.lineTo(10, 0);
2249 geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kNo));
2250 geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kYes));
2251 }
2252
2253 for (int i = 0; i < geos.size(); ++i) {
2254 test_basic(reporter, *geos[i]);
2255 test_scale(reporter, *geos[i]);
2256 test_dash_fill(reporter, *geos[i]);
2257 test_null_dash(reporter, *geos[i]);
2258 // Test modifying various stroke params.
2259 test_stroke_param<SkScalar>(
2260 reporter, *geos[i],
2261 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
2263 test_stroke_join(reporter, *geos[i]);
2264 test_stroke_cap(reporter, *geos[i]);
2265 test_miter_limit(reporter, *geos[i]);
2271 test_volatile_path(reporter, *geos[i]);
2272 }
2273
2274 for (int i = 0; i < rrectPathGeos.size(); ++i) {
2275 const RRectPathGeo& rrgeo = *rrectPathGeos[i];
2276 SkPaint fillPaint;
2277 TestCase fillPathCase(reporter, rrgeo.path(), fillPaint);
2278 SkRRect rrect;
2279 REPORTER_ASSERT(reporter, rrgeo.isNonPath(fillPaint) ==
2280 fillPathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
2281 nullptr));
2282 if (rrgeo.isNonPath(fillPaint)) {
2283 TestCase fillPathCase2(reporter, rrgeo.path(), fillPaint);
2284 REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
2285 TestCase fillRRectCase(reporter, rrect, fillPaint);
2286 fillPathCase2.compare(reporter, fillRRectCase,
2287 TestCase::kAllSame_ComparisonExpecation);
2288 }
2289 SkPaint strokePaint;
2290 strokePaint.setStrokeWidth(3.f);
2291 strokePaint.setStyle(SkPaint::kStroke_Style);
2292 TestCase strokePathCase(reporter, rrgeo.path(), strokePaint);
2293 if (rrgeo.isNonPath(strokePaint)) {
2294 REPORTER_ASSERT(reporter, strokePathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
2295 nullptr));
2296 REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
2297 TestCase strokeRRectCase(reporter, rrect, strokePaint);
2298 strokePathCase.compare(reporter, strokeRRectCase,
2299 TestCase::kAllSame_ComparisonExpecation);
2300 }
2301 }
2302
2303 // Test a volatile empty path.
2304 test_volatile_path(reporter, PathGeo(SkPath(), PathGeo::Invert::kNo));
2305}
reporter
static void test_stroke_cap(skiatest::Reporter *reporter, const Geo &geo)
static void test_stroke_join(skiatest::Reporter *reporter, const Geo &geo)
void test_path_effect_makes_empty_shape(skiatest::Reporter *reporter, const Geo &geo)
static void test_scale(skiatest::Reporter *reporter, const Geo &geo)
void test_make_hairline_path_effect(skiatest::Reporter *reporter, const Geo &geo)
void test_path_effect_makes_rrect(skiatest::Reporter *reporter, const Geo &geo)
static void test_basic(skiatest::Reporter *reporter, const Geo &geo)
void test_rrect(skiatest::Reporter *r, const SkRRect &rrect)
void test_volatile_path(skiatest::Reporter *reporter, const Geo &geo)
void test_unknown_path_effect(skiatest::Reporter *reporter, const Geo &geo)
static void test_dash_fill(skiatest::Reporter *reporter, const Geo &geo)
void test_null_dash(skiatest::Reporter *reporter, const Geo &geo)
static void test_miter_limit(skiatest::Reporter *reporter, const Geo &geo)
void test_path_effect_fails(skiatest::Reporter *reporter, const Geo &geo)
#define SkIntToScalar(x)
Definition SkScalar.h:57
void setStyle(Style style)
Definition SkPaint.cpp:105
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
void setStrokeWidth(SkScalar width)
Definition SkPaint.cpp:159
SkPath & moveTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:678
SkPath & lineTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:718
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:990
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Definition SkPath.cpp:736
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition SkPath.cpp:854
static SkRRect MakeOval(const SkRect &oval)
Definition SkRRect.h:162
static SkRRect MakeRect(const SkRect &r)
Definition SkRRect.h:149
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.h:180
int size() const
Definition SkTArray.h:416
T & emplace_back(Args &&... args)
Definition SkTArray.h:243
SkScalar w

◆ DEF_TEST() [3/7]

DEF_TEST ( GrStyledShape_arcs  ,
reporter   
)

Definition at line 2307 of file GrStyledShapeTest.cpp.

2307 {
2309 roundStroke.setStrokeStyle(2.f);
2310 roundStroke.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 1.f);
2311
2312 SkStrokeRec squareStroke(roundStroke);
2313 squareStroke.setStrokeParams(SkPaint::kSquare_Cap, SkPaint::kRound_Join, 1.f);
2314
2315 SkStrokeRec roundStrokeAndFill(roundStroke);
2316 roundStrokeAndFill.setStrokeStyle(2.f, true);
2317
2318 static constexpr SkScalar kIntervals[] = {1, 2};
2319 auto dash = SkDashPathEffect::Make(kIntervals, std::size(kIntervals), 1.5f);
2320
2321 TArray<GrStyle> styles;
2324 styles.push_back(GrStyle(roundStroke, nullptr));
2325 styles.push_back(GrStyle(squareStroke, nullptr));
2326 styles.push_back(GrStyle(roundStrokeAndFill, nullptr));
2327 styles.push_back(GrStyle(roundStroke, dash));
2328
2329 for (const auto& style : styles) {
2330 // An empty rect never draws anything according to SkCanvas::drawArc() docs.
2331 TestCase emptyArc(GrStyledShape::MakeArc(SkRect::MakeEmpty(), 0, 90.f, false, style),
2332 reporter);
2333 TestCase emptyPath(reporter, SkPath(), style);
2334 emptyArc.compare(reporter, emptyPath, TestCase::kAllSame_ComparisonExpecation);
2335
2336 static constexpr SkRect kOval1{0, 0, 50, 50};
2337 static constexpr SkRect kOval2{50, 0, 100, 50};
2338 // Test that swapping starting and ending angle doesn't change the shape unless the arc
2339 // has a path effect. Also test that different ovals produce different shapes.
2340 TestCase arc1CW(GrStyledShape::MakeArc(kOval1, 0, 90.f, false, style), reporter);
2341 TestCase arc1CCW(GrStyledShape::MakeArc(kOval1, 90.f, -90.f, false, style), reporter);
2342
2343 TestCase arc1CWWithCenter(GrStyledShape::MakeArc(kOval1, 0, 90.f, true, style), reporter);
2344 TestCase arc1CCWWithCenter(GrStyledShape::MakeArc(kOval1, 90.f, -90.f, true, style),
2345 reporter);
2346
2347 TestCase arc2CW(GrStyledShape::MakeArc(kOval2, 0, 90.f, false, style), reporter);
2348 TestCase arc2CWWithCenter(GrStyledShape::MakeArc(kOval2, 0, 90.f, true, style), reporter);
2349
2350 auto reversedExepectations = style.hasPathEffect()
2351 ? TestCase::kAllDifferent_ComparisonExpecation
2352 : TestCase::kAllSame_ComparisonExpecation;
2353 arc1CW.compare(reporter, arc1CCW, reversedExepectations);
2354 arc1CWWithCenter.compare(reporter, arc1CCWWithCenter, reversedExepectations);
2355 arc1CW.compare(reporter, arc2CW, TestCase::kAllDifferent_ComparisonExpecation);
2356 arc1CW.compare(reporter, arc1CWWithCenter, TestCase::kAllDifferent_ComparisonExpecation);
2357 arc1CWWithCenter.compare(reporter, arc2CWWithCenter,
2358 TestCase::kAllDifferent_ComparisonExpecation);
2359
2360 // Test that two arcs that start at the same angle but specified differently are equivalent.
2361 TestCase arc3A(GrStyledShape::MakeArc(kOval1, 224.f, 73.f, false, style), reporter);
2362 TestCase arc3B(GrStyledShape::MakeArc(kOval1, 224.f - 360.f, 73.f, false, style), reporter);
2363 arc3A.compare(reporter, arc3B, TestCase::kAllDifferent_ComparisonExpecation);
2364
2365 // Test that an arc that traverses the entire oval (and then some) is equivalent to the
2366 // oval itself unless there is a path effect.
2367 TestCase ovalArc(GrStyledShape::MakeArc(kOval1, 150.f, -790.f, false, style), reporter);
2369 auto ovalExpectations = style.hasPathEffect() ? TestCase::kAllDifferent_ComparisonExpecation
2370 : TestCase::kAllSame_ComparisonExpecation;
2371 if (style.strokeRec().getWidth() >= 0 && style.strokeRec().getCap() != SkPaint::kButt_Cap) {
2372 ovalExpectations = TestCase::kAllDifferent_ComparisonExpecation;
2373 }
2374 ovalArc.compare(reporter, oval, ovalExpectations);
2375
2376 // If the the arc starts/ends at the center then it is then equivalent to the oval only for
2377 // simple fills.
2378 TestCase ovalArcWithCenter(GrStyledShape::MakeArc(kOval1, 304.f, 1225.f, true, style),
2379 reporter);
2380 ovalExpectations = style.isSimpleFill() ? TestCase::kAllSame_ComparisonExpecation
2381 : TestCase::kAllDifferent_ComparisonExpecation;
2382 ovalArcWithCenter.compare(reporter, oval, ovalExpectations);
2383 }
2384}
static const GrStyle & SimpleHairline()
Definition GrStyle.h:39
static const GrStyle & SimpleFill()
Definition GrStyle.h:30
static GrStyledShape MakeArc(const SkRect &oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, bool useCenter, const GrStyle &style, DoSimplify=DoSimplify::kYes)
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
@ kRound_Cap
adds circle
Definition SkPaint.h:335
@ kButt_Cap
no stroke extension
Definition SkPaint.h:334
@ kSquare_Cap
adds square
Definition SkPaint.h:336
@ kRound_Join
adds circle
Definition SkPaint.h:360
SkRect oval
Definition SkRecords.h:249
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595

◆ DEF_TEST() [4/7]

DEF_TEST ( GrStyledShape_empty_shape  ,
reporter   
)

Definition at line 1554 of file GrStyledShapeTest.cpp.

1554 {
1555 SkPath emptyPath;
1556 SkPath invertedEmptyPath;
1557 invertedEmptyPath.toggleInverseFillType();
1558 SkPaint fill;
1559 TestCase fillEmptyCase(reporter, emptyPath, fill);
1560 REPORTER_ASSERT(reporter, fillEmptyCase.baseShape().isEmpty());
1561 REPORTER_ASSERT(reporter, fillEmptyCase.appliedPathEffectShape().isEmpty());
1562 REPORTER_ASSERT(reporter, fillEmptyCase.appliedFullStyleShape().isEmpty());
1563 REPORTER_ASSERT(reporter, !fillEmptyCase.baseShape().inverseFilled());
1564 REPORTER_ASSERT(reporter, !fillEmptyCase.appliedPathEffectShape().inverseFilled());
1565 REPORTER_ASSERT(reporter, !fillEmptyCase.appliedFullStyleShape().inverseFilled());
1566 TestCase fillInvertedEmptyCase(reporter, invertedEmptyPath, fill);
1567 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.baseShape().isEmpty());
1568 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedPathEffectShape().isEmpty());
1569 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedFullStyleShape().isEmpty());
1570 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.baseShape().inverseFilled());
1571 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedPathEffectShape().inverseFilled());
1572 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedFullStyleShape().inverseFilled());
1573
1574 const Key& emptyKey = fillEmptyCase.baseKey();
1575 REPORTER_ASSERT(reporter, emptyKey.size());
1576 const Key& inverseEmptyKey = fillInvertedEmptyCase.baseKey();
1577 REPORTER_ASSERT(reporter, inverseEmptyKey.size());
1578 TestCase::SelfExpectations expectations;
1579 expectations.fStrokeApplies = false;
1580 expectations.fPEHasEffect = false;
1581 // This will test whether applying style preserves emptiness
1582 fillEmptyCase.testExpectations(reporter, expectations);
1583 fillInvertedEmptyCase.testExpectations(reporter, expectations);
1584
1585 // Stroking an empty path should have no effect
1586 SkPaint stroke;
1587 stroke.setStrokeWidth(2.f);
1591 TestCase strokeEmptyCase(reporter, emptyPath, stroke);
1592 strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1593 TestCase strokeInvertedEmptyCase(reporter, invertedEmptyPath, stroke);
1594 strokeInvertedEmptyCase.compare(reporter, fillInvertedEmptyCase,
1595 TestCase::kAllSame_ComparisonExpecation);
1596
1597 // Dashing and stroking an empty path should have no effect
1598 SkPaint dashAndStroke;
1599 dashAndStroke.setPathEffect(make_dash());
1600 dashAndStroke.setStrokeWidth(2.f);
1601 dashAndStroke.setStyle(SkPaint::kStroke_Style);
1602 TestCase dashAndStrokeEmptyCase(reporter, emptyPath, dashAndStroke);
1603 dashAndStrokeEmptyCase.compare(reporter, fillEmptyCase,
1604 TestCase::kAllSame_ComparisonExpecation);
1605 TestCase dashAndStrokeInvertexEmptyCase(reporter, invertedEmptyPath, dashAndStroke);
1606 // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
1607 dashAndStrokeInvertexEmptyCase.compare(reporter, fillEmptyCase,
1608 TestCase::kAllSame_ComparisonExpecation);
1609
1610 // A shape made from an empty rrect should behave the same as an empty path when filled and
1611 // when stroked. The shape is closed so it does not produce caps when stroked. When dashed there
1612 // is no path to dash along, making it equivalent as well.
1613 SkRRect emptyRRect = SkRRect::MakeEmpty();
1615
1616 TestCase fillEmptyRRectCase(reporter, emptyRRect, fill);
1617 fillEmptyRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1618
1619 TestCase strokeEmptyRRectCase(reporter, emptyRRect, stroke);
1620 strokeEmptyRRectCase.compare(reporter, strokeEmptyCase,
1621 TestCase::kAllSame_ComparisonExpecation);
1622
1623 TestCase dashAndStrokeEmptyRRectCase(reporter, emptyRRect, dashAndStroke);
1624 dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase,
1625 TestCase::kAllSame_ComparisonExpecation);
1626
1627 static constexpr SkPathDirection kDir = SkPathDirection::kCCW;
1628 static constexpr int kStart = 0;
1629
1630 TestCase fillInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true, GrStyle(fill));
1631 fillInvertedEmptyRRectCase.compare(reporter, fillInvertedEmptyCase,
1632 TestCase::kAllSame_ComparisonExpecation);
1633
1634 TestCase strokeInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true,
1635 GrStyle(stroke));
1636 strokeInvertedEmptyRRectCase.compare(reporter, strokeInvertedEmptyCase,
1637 TestCase::kAllSame_ComparisonExpecation);
1638
1639 TestCase dashAndStrokeEmptyInvertedRRectCase(reporter, emptyRRect, kDir, kStart, true,
1640 GrStyle(dashAndStroke));
1641 dashAndStrokeEmptyInvertedRRectCase.compare(reporter, fillEmptyCase,
1642 TestCase::kAllSame_ComparisonExpecation);
1643
1644 // Same for a rect.
1645 SkRect emptyRect = SkRect::MakeEmpty();
1646 TestCase fillEmptyRectCase(reporter, emptyRect, fill);
1647 fillEmptyRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1648
1649 TestCase dashAndStrokeEmptyRectCase(reporter, emptyRect, dashAndStroke);
1650 dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase,
1651 TestCase::kAllSame_ComparisonExpecation);
1652
1653 TestCase dashAndStrokeEmptyInvertedRectCase(reporter, SkRRect::MakeRect(emptyRect), kDir,
1654 kStart, true, GrStyle(dashAndStroke));
1655 // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
1656 dashAndStrokeEmptyInvertedRectCase.compare(reporter, fillEmptyCase,
1657 TestCase::kAllSame_ComparisonExpecation);
1658}
static sk_sp< SkPathEffect > make_dash()
void setStrokeCap(Cap cap)
Definition SkPaint.cpp:179
void setStrokeJoin(Join join)
Definition SkPaint.cpp:189
void setPathEffect(sk_sp< SkPathEffect > pathEffect)
void toggleInverseFillType()
Definition SkPath.h:249
@ kEmpty_Type
zero width or height
Definition SkRRect.h:67

◆ DEF_TEST() [5/7]

DEF_TEST ( GrStyledShape_lines  ,
 
)

Definition at line 1920 of file GrStyledShapeTest.cpp.

1920 {
1921 static constexpr SkPoint kA { 1, 1};
1922 static constexpr SkPoint kB { 5, -9};
1923 static constexpr SkPoint kC {-3, 17};
1924
1925 SkPath lineAB = SkPath::Line(kA, kB);
1926 SkPath lineBA = SkPath::Line(kB, kA);
1927 SkPath lineAC = SkPath::Line(kB, kC);
1928 SkPath invLineAB = lineAB;
1929
1931
1932 SkPaint fill;
1933 SkPaint stroke;
1935 stroke.setStrokeWidth(2.f);
1936 SkPaint hairline;
1938 hairline.setStrokeWidth(0.f);
1939 SkPaint dash = stroke;
1940 dash.setPathEffect(make_dash());
1941
1942 TestCase fillAB(r, lineAB, fill);
1943 TestCase fillEmpty(r, SkPath(), fill);
1944 fillAB.compare(r, fillEmpty, TestCase::kAllSame_ComparisonExpecation);
1945 REPORTER_ASSERT(r, !fillAB.baseShape().asLine(nullptr, nullptr));
1946
1947 SkPath path;
1948 path.toggleInverseFillType();
1949 TestCase fillEmptyInverted(r, path, fill);
1950 TestCase fillABInverted(r, invLineAB, fill);
1951 fillABInverted.compare(r, fillEmptyInverted, TestCase::kAllSame_ComparisonExpecation);
1952 REPORTER_ASSERT(r, !fillABInverted.baseShape().asLine(nullptr, nullptr));
1953
1954 TestCase strokeAB(r, lineAB, stroke);
1955 TestCase strokeBA(r, lineBA, stroke);
1956 TestCase strokeAC(r, lineAC, stroke);
1957
1958 TestCase hairlineAB(r, lineAB, hairline);
1959 TestCase hairlineBA(r, lineBA, hairline);
1960 TestCase hairlineAC(r, lineAC, hairline);
1961
1962 TestCase dashAB(r, lineAB, dash);
1963 TestCase dashBA(r, lineBA, dash);
1964 TestCase dashAC(r, lineAC, dash);
1965
1966 strokeAB.compare(r, fillAB, TestCase::kAllDifferent_ComparisonExpecation);
1967
1968 strokeAB.compare(r, strokeBA, TestCase::kAllSame_ComparisonExpecation);
1969 strokeAB.compare(r, strokeAC, TestCase::kAllDifferent_ComparisonExpecation);
1970
1971 hairlineAB.compare(r, hairlineBA, TestCase::kAllSame_ComparisonExpecation);
1972 hairlineAB.compare(r, hairlineAC, TestCase::kAllDifferent_ComparisonExpecation);
1973
1974 dashAB.compare(r, dashBA, TestCase::kAllDifferent_ComparisonExpecation);
1975 dashAB.compare(r, dashAC, TestCase::kAllDifferent_ComparisonExpecation);
1976
1977 strokeAB.compare(r, hairlineAB, TestCase::kSameUpToStroke_ComparisonExpecation);
1978
1979 // One of dashAB or dashBA should have the same line as strokeAB. It depends upon how
1980 // GrStyledShape canonicalizes line endpoints (when it can, i.e. when not dashed).
1981 bool canonicalizeAsAB;
1982 SkPoint canonicalPts[2] {kA, kB};
1983 // Init these to suppress warnings.
1984 bool inverted = true;
1985 SkPoint pts[2] {{0, 0}, {0, 0}};
1986 REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted);
1987 if (pts[0] == kA && pts[1] == kB) {
1988 canonicalizeAsAB = true;
1989 } else if (pts[1] == kA && pts[0] == kB) {
1990 canonicalizeAsAB = false;
1991 using std::swap;
1992 swap(canonicalPts[0], canonicalPts[1]);
1993 } else {
1994 ERRORF(r, "Should return pts (a,b) or (b, a)");
1995 return;
1996 }
1997
1998 strokeAB.compare(r, canonicalizeAsAB ? dashAB : dashBA,
1999 TestCase::kSameUpToPE_ComparisonExpecation);
2000 REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted &&
2001 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2002 REPORTER_ASSERT(r, hairlineAB.baseShape().asLine(pts, &inverted) && !inverted &&
2003 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2004 REPORTER_ASSERT(r, dashAB.baseShape().asLine(pts, &inverted) && !inverted &&
2005 pts[0] == kA && pts[1] == kB);
2006 REPORTER_ASSERT(r, dashBA.baseShape().asLine(pts, &inverted) && !inverted &&
2007 pts[0] == kB && pts[1] == kA);
2008
2009
2010 TestCase strokeInvAB(r, invLineAB, stroke);
2011 TestCase hairlineInvAB(r, invLineAB, hairline);
2012 TestCase dashInvAB(r, invLineAB, dash);
2013 strokeInvAB.compare(r, strokeAB, TestCase::kAllDifferent_ComparisonExpecation);
2014 hairlineInvAB.compare(r, hairlineAB, TestCase::kAllDifferent_ComparisonExpecation);
2015 // Dashing ignores inverse.
2016 dashInvAB.compare(r, dashAB, TestCase::kAllSame_ComparisonExpecation);
2017
2018 REPORTER_ASSERT(r, strokeInvAB.baseShape().asLine(pts, &inverted) && inverted &&
2019 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2020 REPORTER_ASSERT(r, hairlineInvAB.baseShape().asLine(pts, &inverted) && inverted &&
2021 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2022 // Dashing ignores inverse.
2023 REPORTER_ASSERT(r, dashInvAB.baseShape().asLine(pts, &inverted) && !inverted &&
2024 pts[0] == kA && pts[1] == kB);
2025
2026}
@ kC
#define ERRORF(r,...)
Definition Test.h:293
static SkPath Line(const SkPoint a, const SkPoint b)
Definition SkPath.h:106
static void swap(TArray< T, M > &a, TArray< T, M > &b)
Definition SkTArray.h:737

◆ DEF_TEST() [6/7]

DEF_TEST ( GrStyledShape_short_path_keys  ,
 
)

Definition at line 2105 of file GrStyledShapeTest.cpp.

2105 {
2106 SkPaint paints[4];
2108 paints[1].setStrokeWidth(5.f);
2110 paints[2].setStrokeWidth(0.f);
2112 paints[3].setStrokeWidth(5.f);
2113
2114 auto compare = [r, &paints] (const SkPath& pathA, const SkPath& pathB,
2115 TestCase::ComparisonExpecation expectation) {
2116 SkPath volatileA = pathA;
2117 SkPath volatileB = pathB;
2118 volatileA.setIsVolatile(true);
2119 volatileB.setIsVolatile(true);
2120 for (const SkPaint& paint : paints) {
2121 REPORTER_ASSERT(r, !GrStyledShape(volatileA, paint).hasUnstyledKey());
2122 REPORTER_ASSERT(r, !GrStyledShape(volatileB, paint).hasUnstyledKey());
2123 for (PathGeo::Invert invert : {PathGeo::Invert::kNo, PathGeo::Invert::kYes}) {
2124 TestCase caseA(PathGeo(pathA, invert), paint, r);
2125 TestCase caseB(PathGeo(pathB, invert), paint, r);
2126 caseA.compare(r, caseB, expectation);
2127 }
2128 }
2129 };
2130
2131 SkPath pathA;
2132 SkPath pathB;
2133
2134 // Two identical paths
2135 pathA.lineTo(10.f, 10.f);
2136 pathA.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2137
2138 pathB.lineTo(10.f, 10.f);
2139 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2140 compare(pathA, pathB, TestCase::kAllSame_ComparisonExpecation);
2141
2142 // Give path b a different point
2143 pathB.reset();
2144 pathB.lineTo(10.f, 10.f);
2145 pathB.conicTo(21.f, 20.f, 20.f, 30.f, 0.7f);
2146 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2147
2148 // Give path b a different conic weight
2149 pathB.reset();
2150 pathB.lineTo(10.f, 10.f);
2151 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2152 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2153
2154 // Give path b an extra lineTo verb
2155 pathB.reset();
2156 pathB.lineTo(10.f, 10.f);
2157 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2158 pathB.lineTo(50.f, 50.f);
2159 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2160
2161 // Give path b a close
2162 pathB.reset();
2163 pathB.lineTo(10.f, 10.f);
2164 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2165 pathB.close();
2166 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2167}
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
Definition BlurTest.cpp:100
@ kStrokeAndFill_Style
sets to stroke and fill geometry
Definition SkPaint.h:195
SkPath & setIsVolatile(bool isVolatile)
Definition SkPath.h:370
SkPath & reset()
Definition SkPath.cpp:360
SkPath & conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
Definition SkPath.cpp:756
const Paint & paint
gboolean invert

◆ DEF_TEST() [7/7]

DEF_TEST ( GrStyledShape_stroked_lines  ,
 
)

Definition at line 2028 of file GrStyledShapeTest.cpp.

2028 {
2029 static constexpr SkScalar kIntervals1[] = {1.f, 0.f};
2030 auto dash1 = SkDashPathEffect::Make(kIntervals1, std::size(kIntervals1), 0.f);
2032 static constexpr SkScalar kIntervals2[] = {10.f, 0.f, 5.f, 0.f};
2033 auto dash2 = SkDashPathEffect::Make(kIntervals2, std::size(kIntervals2), 10.f);
2035
2036 sk_sp<SkPathEffect> pathEffects[] = {nullptr, std::move(dash1), std::move(dash2)};
2037
2038 for (const auto& pe : pathEffects) {
2039 // Paints to try
2040 SkPaint buttCap;
2042 buttCap.setStrokeWidth(4);
2044 buttCap.setPathEffect(pe);
2045
2046 SkPaint squareCap = buttCap;
2048 squareCap.setPathEffect(pe);
2049
2050 SkPaint roundCap = buttCap;
2052 roundCap.setPathEffect(pe);
2053
2054 // vertical
2055 SkPath linePath;
2056 linePath.moveTo(4, 4);
2057 linePath.lineTo(4, 5);
2058
2059 SkPaint fill;
2060
2061 make_TestCase(r, linePath, buttCap)->compare(
2062 r, TestCase(r, SkRect::MakeLTRB(2, 4, 6, 5), fill),
2063 TestCase::kAllSame_ComparisonExpecation);
2064
2065 make_TestCase(r, linePath, squareCap)->compare(
2066 r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 7), fill),
2067 TestCase::kAllSame_ComparisonExpecation);
2068
2069 make_TestCase(r, linePath, roundCap)->compare(r,
2070 TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 7), 2, 2), fill),
2071 TestCase::kAllSame_ComparisonExpecation);
2072
2073 // horizontal
2074 linePath.reset();
2075 linePath.moveTo(4, 4);
2076 linePath.lineTo(5, 4);
2077
2078 make_TestCase(r, linePath, buttCap)->compare(
2079 r, TestCase(r, SkRect::MakeLTRB(4, 2, 5, 6), fill),
2080 TestCase::kAllSame_ComparisonExpecation);
2081 make_TestCase(r, linePath, squareCap)->compare(
2082 r, TestCase(r, SkRect::MakeLTRB(2, 2, 7, 6), fill),
2083 TestCase::kAllSame_ComparisonExpecation);
2084 make_TestCase(r, linePath, roundCap)->compare(
2085 r, TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 7, 6), 2, 2), fill),
2086 TestCase::kAllSame_ComparisonExpecation);
2087
2088 // point
2089 linePath.reset();
2090 linePath.moveTo(4, 4);
2091 linePath.lineTo(4, 4);
2092
2093 make_TestCase(r, linePath, buttCap)->compare(
2094 r, TestCase(r, SkRect::MakeEmpty(), fill),
2095 TestCase::kAllSame_ComparisonExpecation);
2096 make_TestCase(r, linePath, squareCap)->compare(
2097 r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 6), fill),
2098 TestCase::kAllSame_ComparisonExpecation);
2099 make_TestCase(r, linePath, roundCap)->compare(
2100 r, TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 6), 2, 2), fill),
2101 TestCase::kAllSame_ComparisonExpecation);
2102 }
2103}
static std::unique_ptr< TestCase > make_TestCase(Args &&... args)
int dash2[]
int dash1[]
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646

◆ make_dash()

static sk_sp< SkPathEffect > make_dash ( )
static

Definition at line 785 of file GrStyledShapeTest.cpp.

785 {
786 static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f };
787 static const SkScalar kPhase = 0.75;
788 return SkDashPathEffect::Make(kIntervals, std::size(kIntervals), kPhase);
789}

◆ make_key()

static bool make_key ( Key key,
const GrStyledShape shape 
)
static

Definition at line 66 of file GrStyledShapeTest.cpp.

66 {
67 int size = shape.unstyledKeySize();
68 if (size <= 0) {
69 key->reset(0);
70 return false;
71 }
72 SkASSERT(size);
73 key->reset(size);
74 shape.writeUnstyledKey(key->begin());
75 return true;
76}
#define SkASSERT(cond)
Definition SkAssert.h:116
void writeUnstyledKey(uint32_t *key) const
int unstyledKeySize() const
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259

◆ make_null_dash()

static sk_sp< SkPathEffect > make_null_dash ( )
static

Definition at line 791 of file GrStyledShapeTest.cpp.

791 {
792 static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0};
793 return SkDashPathEffect::Make(kNullIntervals, std::size(kNullIntervals), 0.f);
794}

◆ make_TestCase()

template<typename... Args>
static std::unique_ptr< TestCase > make_TestCase ( Args &&...  args)
static

Definition at line 799 of file GrStyledShapeTest.cpp.

799 {
800 return std::make_unique<TestCase>( std::forward<Args>(args)... );
801}
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args

◆ paths_fill_same()

static bool paths_fill_same ( const SkPath a,
const SkPath b 
)
static

Definition at line 78 of file GrStyledShapeTest.cpp.

78 {
79 SkPath pathXor;
80 Op(a, b, SkPathOp::kXOR_SkPathOp, &pathXor);
81 return pathXor.isEmpty();
82}
@ kXOR_SkPathOp
exclusive-or the two paths
Definition SkPathOps.h:26
bool isEmpty() const
Definition SkPath.cpp:406

◆ shape_known_not_to_have_joins()

static bool shape_known_not_to_have_joins ( const GrStyledShape shape)
static

Definition at line 1070 of file GrStyledShapeTest.cpp.

1070 {
1071 return shape.asLine(nullptr, nullptr) || shape.isEmpty();
1072}
bool isEmpty() const
bool asLine(SkPoint pts[2], bool *inverted) const

◆ test_basic()

static void test_basic ( skiatest::Reporter reporter,
const Geo &  geo 
)
static

Definition at line 803 of file GrStyledShapeTest.cpp.

803 {
805
806 TestCase::SelfExpectations expectations;
807 SkPaint fill;
808
809 TestCase fillCase(geo, fill, reporter);
810 expectations.fPEHasEffect = false;
811 expectations.fPEHasValidKey = false;
812 expectations.fStrokeApplies = false;
813 fillCase.testExpectations(reporter, expectations);
814 // Test that another GrStyledShape instance built from the same primitive is the same.
815 make_TestCase(geo, fill, reporter)
816 ->compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
817
818 SkPaint stroke2RoundBevel;
819 stroke2RoundBevel.setStyle(SkPaint::kStroke_Style);
820 stroke2RoundBevel.setStrokeCap(SkPaint::kRound_Cap);
821 stroke2RoundBevel.setStrokeJoin(SkPaint::kBevel_Join);
822 stroke2RoundBevel.setStrokeWidth(2.f);
823 TestCase stroke2RoundBevelCase(geo, stroke2RoundBevel, reporter);
824 expectations.fPEHasValidKey = true;
825 expectations.fPEHasEffect = false;
826 expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
827 stroke2RoundBevelCase.testExpectations(reporter, expectations);
828 make_TestCase(geo, stroke2RoundBevel, reporter)
829 ->compare(reporter, stroke2RoundBevelCase, TestCase::kAllSame_ComparisonExpecation);
830
831 SkPaint stroke2RoundBevelDash = stroke2RoundBevel;
832 stroke2RoundBevelDash.setPathEffect(make_dash());
833 TestCase stroke2RoundBevelDashCase(geo, stroke2RoundBevelDash, reporter);
834 expectations.fPEHasValidKey = true;
835 expectations.fPEHasEffect = true;
836 expectations.fStrokeApplies = true;
837 stroke2RoundBevelDashCase.testExpectations(reporter, expectations);
838 make_TestCase(geo, stroke2RoundBevelDash, reporter)
839 ->compare(reporter, stroke2RoundBevelDashCase, TestCase::kAllSame_ComparisonExpecation);
840
841 if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
842 fillCase.compare(reporter, stroke2RoundBevelCase,
843 TestCase::kAllDifferent_ComparisonExpecation);
844 fillCase.compare(reporter, stroke2RoundBevelDashCase,
845 TestCase::kAllDifferent_ComparisonExpecation);
846 } else {
847 fillCase.compare(reporter, stroke2RoundBevelCase,
848 TestCase::kSameUpToStroke_ComparisonExpecation);
849 fillCase.compare(reporter, stroke2RoundBevelDashCase,
850 TestCase::kSameUpToPE_ComparisonExpecation);
851 }
852 if (geo.strokeIsConvertedToFill()) {
853 stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase,
854 TestCase::kAllDifferent_ComparisonExpecation);
855 } else {
856 stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase,
857 TestCase::kSameUpToPE_ComparisonExpecation);
858 }
859
860 // Stroke and fill cases
861 SkPaint stroke2RoundBevelAndFill = stroke2RoundBevel;
862 stroke2RoundBevelAndFill.setStyle(SkPaint::kStrokeAndFill_Style);
863 TestCase stroke2RoundBevelAndFillCase(geo, stroke2RoundBevelAndFill, reporter);
864 expectations.fPEHasValidKey = true;
865 expectations.fPEHasEffect = false;
866 expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
867 stroke2RoundBevelAndFillCase.testExpectations(reporter, expectations);
868 make_TestCase(geo, stroke2RoundBevelAndFill, reporter)->compare(
869 reporter, stroke2RoundBevelAndFillCase, TestCase::kAllSame_ComparisonExpecation);
870
871 SkPaint stroke2RoundBevelAndFillDash = stroke2RoundBevelDash;
872 stroke2RoundBevelAndFillDash.setStyle(SkPaint::kStrokeAndFill_Style);
873 TestCase stroke2RoundBevelAndFillDashCase(geo, stroke2RoundBevelAndFillDash, reporter);
874 expectations.fPEHasValidKey = true;
875 expectations.fPEHasEffect = false;
876 expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
877 stroke2RoundBevelAndFillDashCase.testExpectations(reporter, expectations);
878 make_TestCase(geo, stroke2RoundBevelAndFillDash, reporter)->compare(
879 reporter, stroke2RoundBevelAndFillDashCase, TestCase::kAllSame_ComparisonExpecation);
880 stroke2RoundBevelAndFillDashCase.compare(reporter, stroke2RoundBevelAndFillCase,
881 TestCase::kAllSame_ComparisonExpecation);
882
883 SkPaint hairline;
885 hairline.setStrokeWidth(0.f);
886 TestCase hairlineCase(geo, hairline, reporter);
887 // Since hairline style doesn't change the SkPath data, it is keyed identically to fill (except
888 // in the line and unclosed rect cases).
889 if (geo.fillChangesGeom()) {
890 hairlineCase.compare(reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
891 } else {
892 hairlineCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
893 }
894 REPORTER_ASSERT(reporter, hairlineCase.baseShape().style().isSimpleHairline());
895 REPORTER_ASSERT(reporter, hairlineCase.appliedFullStyleShape().style().isSimpleHairline());
896 REPORTER_ASSERT(reporter, hairlineCase.appliedPathEffectShape().style().isSimpleHairline());
897
898}
@ kBevel_Join
connects outside edges
Definition SkPaint.h:361

◆ test_bounds_by_rasterizing()

static bool test_bounds_by_rasterizing ( const SkPath path,
const SkRect bounds 
)
static

Definition at line 84 of file GrStyledShapeTest.cpp.

84 {
85 // We test the bounds by rasterizing the path into a kRes by kRes grid. The bounds is
86 // mapped to the range kRes/4 to 3*kRes/4 in x and y. A difference clip is used to avoid
87 // rendering within the bounds (with a tolerance). Then we render the path and check that
88 // everything got clipped out.
89 static constexpr int kRes = 2000;
90 // This tolerance is in units of 1/kRes fractions of the bounds width/height.
91 static constexpr int kTol = 2;
92 static_assert(kRes % 4 == 0);
95 surface->getCanvas()->clear(0x0);
96 SkRect clip = SkRect::MakeXYWH(kRes/4, kRes/4, kRes/2, kRes/2);
98 clip.outset(SkIntToScalar(kTol), SkIntToScalar(kTol));
99 surface->getCanvas()->clipRect(clip, SkClipOp::kDifference);
100 surface->getCanvas()->concat(matrix);
101 SkPaint whitePaint;
102 whitePaint.setColor(SK_ColorWHITE);
103 surface->getCanvas()->drawPath(path, whitePaint);
104 SkPixmap pixmap;
105 surface->getCanvas()->peekPixels(&pixmap);
106#if defined(SK_BUILD_FOR_WIN)
107 // The static constexpr version in #else causes cl.exe to crash.
108 const uint8_t* kZeros = reinterpret_cast<uint8_t*>(calloc(kRes, 1));
109#else
110 static constexpr uint8_t kZeros[kRes] = {0};
111#endif
112 for (int y = 0; y < kRes; ++y) {
113 const uint8_t* row = pixmap.addr8(0, y);
114 if (0 != memcmp(kZeros, row, kRes)) {
115 return false;
116 }
117 }
118#ifdef SK_BUILD_FOR_WIN
119 free(const_cast<uint8_t*>(kZeros));
120#endif
121 return true;
122}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition SkMatrix.h:157
void setColor(SkColor color)
Definition SkPaint.cpp:119
const uint8_t * addr8() const
Definition SkPixmap.h:326
VkSurfaceKHR surface
Definition main.cc:49
double y
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
void * calloc(size_t n, size_t size)
Definition allocation.cc:11
static SkImageInfo MakeA8(int width, int height)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659

◆ test_dash_fill()

static void test_dash_fill ( skiatest::Reporter reporter,
const Geo &  geo 
)
static

Definition at line 1130 of file GrStyledShapeTest.cpp.

1130 {
1131 // A dash with no stroke should have no effect
1132 using DashFactoryFn = sk_sp<SkPathEffect>(*)();
1133 for (DashFactoryFn md : {&make_dash, &make_null_dash}) {
1134 SkPaint dashFill;
1135 dashFill.setPathEffect((*md)());
1136 TestCase dashFillCase(geo, dashFill, reporter);
1137
1138 TestCase fillCase(geo, SkPaint(), reporter);
1139 dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
1140 }
1141}
static sk_sp< SkPathEffect > make_null_dash()

◆ test_inversions()

void test_inversions ( skiatest::Reporter r,
const GrStyledShape shape,
const Key shapeKey 
)

Definition at line 306 of file GrStyledShapeTest.cpp.

306 {
309 Key preserveKey;
310 make_key(&preserveKey, preserve);
311
313 Key flipKey;
314 make_key(&flipKey, flip);
315
318 Key invertedKey;
319 make_key(&invertedKey, inverted);
320
323 Key noninvertedKey;
324 make_key(&noninvertedKey, noninverted);
325
326 if (invertedKey.size() || noninvertedKey.size()) {
327 REPORTER_ASSERT(r, invertedKey != noninvertedKey);
328 }
329 if (shape.style().isSimpleFill()) {
330 check_equivalence(r, shape, preserve, shapeKey, preserveKey);
331 }
332 if (shape.inverseFilled()) {
333 check_equivalence(r, preserve, inverted, preserveKey, invertedKey);
334 check_equivalence(r, flip, noninverted, flipKey, noninvertedKey);
335 } else {
336 check_equivalence(r, preserve, noninverted, preserveKey, noninvertedKey);
337 check_equivalence(r, flip, inverted, flipKey, invertedKey);
338 }
339
341 Key doubleFlipKey;
342 make_key(&doubleFlipKey, doubleFlip);
343 // It can be the case that the double flip has no key but preserve does. This happens when the
344 // original shape has an inherited style key. That gets dropped on the first inversion flip.
345 if (preserveKey.size() && !doubleFlipKey.size()) {
346 preserveKey.clear();
347 }
348 check_equivalence(r, preserve, doubleFlip, preserveKey, doubleFlipKey);
349}
static void check_equivalence(skiatest::Reporter *r, const GrStyledShape &a, const GrStyledShape &b, const Key &keyA, const Key &keyB)
static bool make_key(Key *key, const GrStyledShape &shape)
bool inverseFilled() const
static GrStyledShape MakeFilled(const GrStyledShape &original, FillInversion=FillInversion::kPreserve)

◆ test_make_hairline_path_effect()

void test_make_hairline_path_effect ( skiatest::Reporter reporter,
const Geo &  geo 
)

This path effect just changes the stroke rec to hairline.

Definition at line 1316 of file GrStyledShapeTest.cpp.

1316 {
1317 /**
1318 * This path effect just changes the stroke rec to hairline.
1319 */
1320 class MakeHairlinePathEffect : SkPathEffectBase {
1321 public:
1322 static sk_sp<SkPathEffect> Make() {
1323 return sk_sp<SkPathEffect>(new MakeHairlinePathEffect);
1324 }
1325 Factory getFactory() const override { return nullptr; }
1326 const char* getTypeName() const override { return nullptr; }
1327
1328 protected:
1329 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* strokeRec,
1330 const SkRect* cullR, const SkMatrix&) const override {
1331 *dst = src;
1332 strokeRec->setHairlineStyle();
1333 return true;
1334 }
1335 private:
1336 bool computeFastBounds(SkRect* bounds) const override { return true; }
1337
1338 MakeHairlinePathEffect() {}
1339 };
1340
1341 SkPaint fill;
1342 SkPaint pe;
1343 pe.setPathEffect(MakeHairlinePathEffect::Make());
1344
1345 TestCase peCase(geo, pe, reporter);
1346
1347 SkPath a, b, c;
1348 peCase.baseShape().asPath(&a);
1349 peCase.appliedPathEffectShape().asPath(&b);
1350 peCase.appliedFullStyleShape().asPath(&c);
1351 if (geo.isNonPath(pe)) {
1352 // RRect types can have a change in start index or direction after the PE is applied. This
1353 // is because once the PE is applied, GrStyledShape may canonicalize the dir and index since
1354 // it is not germane to the styling any longer.
1355 // Instead we just check that the paths would fill the same both before and after styling.
1358 } else {
1359 // The base shape cannot perform canonicalization on the path's fill type because of an
1360 // unknown path effect. However, after the path effect is applied the resulting hairline
1361 // shape will canonicalize the path fill type since hairlines (and stroking in general)
1362 // don't distinguish between even/odd and non-zero winding.
1363 a.setFillType(b.getFillType());
1365 REPORTER_ASSERT(reporter, a == c);
1366 // If the resulting path is small enough then it will have a key.
1369 REPORTER_ASSERT(reporter, peCase.appliedPathEffectKey().empty());
1370 REPORTER_ASSERT(reporter, peCase.appliedFullStyleKey().empty());
1371 }
1372 REPORTER_ASSERT(reporter, peCase.appliedPathEffectShape().style().isSimpleHairline());
1373 REPORTER_ASSERT(reporter, peCase.appliedFullStyleShape().style().isSimpleHairline());
1374}
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
virtual const char * getTypeName() const =0
virtual Factory getFactory() const =0
virtual bool computeFastBounds(SkRect *bounds) const =0
virtual bool onFilterPath(SkPath *, const SkPath &, SkStrokeRec *, const SkRect *, const SkMatrix &) const =0
void setHairlineStyle()
SKSHAPER_API sk_sp< Factory > Factory()
dst
Definition cp.py:12

◆ test_miter_limit()

static void test_miter_limit ( skiatest::Reporter reporter,
const Geo &  geo 
)
static

Definition at line 1092 of file GrStyledShapeTest.cpp.

1092 {
1093 auto setMiterJoinAndLimit = [](SkPaint* p, SkScalar miter) {
1094 p->setStrokeJoin(SkPaint::kMiter_Join);
1095 p->setStrokeMiter(miter);
1096 };
1097
1098 auto setOtherJoinAndLimit = [](SkPaint* p, SkScalar miter) {
1099 p->setStrokeJoin(SkPaint::kRound_Join);
1100 p->setStrokeMiter(miter);
1101 };
1102
1103 SkPaint hairline;
1104 hairline.setStrokeWidth(0);
1106 GrStyledShape shape = geo.makeShape(hairline);
1107 bool mayHaveJoins = !shape_known_not_to_have_joins(shape);
1108
1109 // The miter limit should affect stroked and dashed-stroked cases when the join type is
1110 // miter.
1111 test_stroke_param_impl<SkScalar>(
1112 reporter,
1113 geo,
1114 setMiterJoinAndLimit,
1115 0.5f, 0.75f,
1116 mayHaveJoins,
1117 true);
1118
1119 // The miter limit should not affect stroked and dashed-stroked cases when the join type is
1120 // not miter.
1121 test_stroke_param_impl<SkScalar>(
1122 reporter,
1123 geo,
1124 setOtherJoinAndLimit,
1125 0.5f, 0.75f,
1126 false,
1127 false);
1128}
static bool shape_known_not_to_have_joins(const GrStyledShape &shape)
@ kMiter_Join
extends to miter limit
Definition SkPaint.h:359

◆ test_null_dash()

void test_null_dash ( skiatest::Reporter reporter,
const Geo &  geo 
)

Definition at line 1143 of file GrStyledShapeTest.cpp.

1143 {
1144 SkPaint fill;
1145 SkPaint stroke;
1147 stroke.setStrokeWidth(1.f);
1148 SkPaint dash;
1150 dash.setStrokeWidth(1.f);
1151 dash.setPathEffect(make_dash());
1152 SkPaint nullDash;
1154 nullDash.setStrokeWidth(1.f);
1155 nullDash.setPathEffect(make_null_dash());
1156
1157 TestCase fillCase(geo, fill, reporter);
1158 TestCase strokeCase(geo, stroke, reporter);
1159 TestCase dashCase(geo, dash, reporter);
1160 TestCase nullDashCase(geo, nullDash, reporter);
1161
1162 // We expect the null dash to be ignored so nullDashCase should match strokeCase, always.
1163 nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpecation);
1164 // Check whether the fillCase or strokeCase/nullDashCase would undergo a geometric tranformation
1165 // on construction in order to determine how to compare the fill and stroke.
1166 if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
1167 nullDashCase.compare(reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
1168 } else {
1169 nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1170 }
1171 // In the null dash case we may immediately convert to a fill, but not for the normal dash case.
1172 if (geo.strokeIsConvertedToFill()) {
1173 nullDashCase.compare(reporter, dashCase, TestCase::kAllDifferent_ComparisonExpecation);
1174 } else {
1175 nullDashCase.compare(reporter, dashCase, TestCase::kSameUpToPE_ComparisonExpecation);
1176 }
1177}

◆ test_path_effect_fails()

void test_path_effect_fails ( skiatest::Reporter reporter,
const Geo &  geo 
)

This path effect always fails to apply.

Definition at line 1492 of file GrStyledShapeTest.cpp.

1492 {
1493 /**
1494 * This path effect always fails to apply.
1495 */
1496 class FailurePathEffect : SkPathEffectBase {
1497 public:
1498 static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new FailurePathEffect); }
1499 Factory getFactory() const override { return nullptr; }
1500 const char* getTypeName() const override { return nullptr; }
1501 protected:
1502 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1503 const SkRect* cullR, const SkMatrix&) const override {
1504 return false;
1505 }
1506 private:
1507 bool computeFastBounds(SkRect* bounds) const override { return false; }
1508
1509 FailurePathEffect() {}
1510 };
1511
1512 SkPaint fill;
1513 TestCase fillCase(geo, fill, reporter);
1514
1515 SkPaint pe;
1516 pe.setPathEffect(FailurePathEffect::Make());
1517 TestCase peCase(geo, pe, reporter);
1518
1519 SkPaint stroke;
1520 stroke.setStrokeWidth(2.f);
1522 TestCase strokeCase(geo, stroke, reporter);
1523
1524 SkPaint peStroke = stroke;
1525 peStroke.setPathEffect(FailurePathEffect::Make());
1526 TestCase peStrokeCase(geo, peStroke, reporter);
1527
1528 // In general the path effect failure can cause some of the TestCase::compare() tests to fail
1529 // for at least two reasons: 1) We will initially treat the shape as unkeyable because of the
1530 // path effect, but then when the path effect fails we can key it. 2) GrStyledShape will change
1531 // its mind about whether a unclosed rect is actually rect. The path effect initially bars us
1532 // from closing it but after the effect fails we can (for the fill+pe case). This causes
1533 // different routes through GrStyledShape to have equivalent but different representations of
1534 // the path (closed or not) but that fill the same.
1535 SkPath a;
1536 SkPath b;
1537 fillCase.appliedPathEffectShape().asPath(&a);
1538 peCase.appliedPathEffectShape().asPath(&b);
1540
1541 fillCase.appliedFullStyleShape().asPath(&a);
1542 peCase.appliedFullStyleShape().asPath(&b);
1544
1545 strokeCase.appliedPathEffectShape().asPath(&a);
1546 peStrokeCase.appliedPathEffectShape().asPath(&b);
1548
1549 strokeCase.appliedFullStyleShape().asPath(&a);
1550 peStrokeCase.appliedFullStyleShape().asPath(&b);
1552}

◆ test_path_effect_makes_empty_shape()

void test_path_effect_makes_empty_shape ( skiatest::Reporter reporter,
const Geo &  geo 
)

This path effect returns an empty path (possibly inverted)

Definition at line 1401 of file GrStyledShapeTest.cpp.

1401 {
1402 /**
1403 * This path effect returns an empty path (possibly inverted)
1404 */
1405 class EmptyPathEffect : SkPathEffectBase {
1406 public:
1407 static sk_sp<SkPathEffect> Make(bool invert) {
1408 return sk_sp<SkPathEffect>(new EmptyPathEffect(invert));
1409 }
1410 Factory getFactory() const override { return nullptr; }
1411 const char* getTypeName() const override { return nullptr; }
1412 protected:
1413 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1414 const SkRect* cullR, const SkMatrix&) const override {
1415 dst->reset();
1416 if (fInvert) {
1417 dst->toggleInverseFillType();
1418 }
1419 return true;
1420 }
1421 bool computeFastBounds(SkRect* bounds) const override {
1422 if (bounds) {
1423 *bounds = { 0, 0, 0, 0 };
1424 }
1425 return true;
1426 }
1427 private:
1428 bool fInvert;
1429 EmptyPathEffect(bool invert) : fInvert(invert) {}
1430 };
1431
1432 SkPath emptyPath;
1433 GrStyledShape emptyShape(emptyPath);
1434 Key emptyKey;
1435 make_key(&emptyKey, emptyShape);
1436 REPORTER_ASSERT(reporter, emptyShape.isEmpty());
1437
1438 emptyPath.toggleInverseFillType();
1439 GrStyledShape invertedEmptyShape(emptyPath);
1440 Key invertedEmptyKey;
1441 make_key(&invertedEmptyKey, invertedEmptyShape);
1442 REPORTER_ASSERT(reporter, invertedEmptyShape.isEmpty());
1443
1444 REPORTER_ASSERT(reporter, invertedEmptyKey != emptyKey);
1445
1446 SkPaint pe;
1447 pe.setPathEffect(EmptyPathEffect::Make(false));
1448 TestCase geoPECase(geo, pe, reporter);
1449 REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleKey() == emptyKey);
1450 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectKey() == emptyKey);
1451 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectThenStrokeKey() == emptyKey);
1452 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectShape().isEmpty());
1453 REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleShape().isEmpty());
1454 REPORTER_ASSERT(reporter, !geoPECase.appliedPathEffectShape().inverseFilled());
1455 REPORTER_ASSERT(reporter, !geoPECase.appliedFullStyleShape().inverseFilled());
1456
1457 SkPaint peStroke;
1458 peStroke.setPathEffect(EmptyPathEffect::Make(false));
1459 peStroke.setStrokeWidth(2.f);
1461 TestCase geoPEStrokeCase(geo, peStroke, reporter);
1462 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleKey() == emptyKey);
1463 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectKey() == emptyKey);
1464 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectThenStrokeKey() == emptyKey);
1465 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectShape().isEmpty());
1466 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleShape().isEmpty());
1467 REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedPathEffectShape().inverseFilled());
1468 REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedFullStyleShape().inverseFilled());
1469 pe.setPathEffect(EmptyPathEffect::Make(true));
1470
1471 TestCase geoPEInvertCase(geo, pe, reporter);
1472 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedFullStyleKey() == invertedEmptyKey);
1473 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectKey() == invertedEmptyKey);
1474 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectThenStrokeKey() == invertedEmptyKey);
1475 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectShape().isEmpty());
1476 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedFullStyleShape().isEmpty());
1477 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedPathEffectShape().inverseFilled());
1478 REPORTER_ASSERT(reporter, geoPEInvertCase.appliedFullStyleShape().inverseFilled());
1479
1480 peStroke.setPathEffect(EmptyPathEffect::Make(true));
1481 TestCase geoPEInvertStrokeCase(geo, peStroke, reporter);
1482 REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedFullStyleKey() == invertedEmptyKey);
1483 REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedPathEffectKey() == invertedEmptyKey);
1485 geoPEInvertStrokeCase.appliedPathEffectThenStrokeKey() == invertedEmptyKey);
1486 REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedPathEffectShape().isEmpty());
1487 REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedFullStyleShape().isEmpty());
1488 REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedPathEffectShape().inverseFilled());
1489 REPORTER_ASSERT(reporter, geoPEInvertStrokeCase.appliedFullStyleShape().inverseFilled());
1490}
Optional< SkRect > bounds
Definition SkRecords.h:189

◆ test_path_effect_makes_rrect()

void test_path_effect_makes_rrect ( skiatest::Reporter reporter,
const Geo &  geo 
)

This path effect takes any input path and turns it into a rrect. It passes through stroke info.

Definition at line 1179 of file GrStyledShapeTest.cpp.

1179 {
1180 /**
1181 * This path effect takes any input path and turns it into a rrect. It passes through stroke
1182 * info.
1183 */
1184 class RRectPathEffect : SkPathEffectBase {
1185 public:
1186 static const SkRRect& RRect() {
1187 static const SkRRect kRRect = SkRRect::MakeRectXY(SkRect::MakeWH(12, 12), 3, 5);
1188 return kRRect;
1189 }
1190
1191 static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new RRectPathEffect); }
1192 Factory getFactory() const override { return nullptr; }
1193 const char* getTypeName() const override { return nullptr; }
1194
1195 protected:
1196 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1197 const SkRect* cullR, const SkMatrix&) const override {
1198 dst->reset();
1199 dst->addRRect(RRect());
1200 return true;
1201 }
1202
1203 bool computeFastBounds(SkRect* bounds) const override {
1204 if (bounds) {
1205 *bounds = RRect().getBounds();
1206 }
1207 return true;
1208 }
1209
1210 private:
1211 RRectPathEffect() {}
1212 };
1213
1214 SkPaint fill;
1215 TestCase fillGeoCase(geo, fill, reporter);
1216
1217 SkPaint pe;
1218 pe.setPathEffect(RRectPathEffect::Make());
1219 TestCase geoPECase(geo, pe, reporter);
1220
1221 SkPaint peStroke;
1222 peStroke.setPathEffect(RRectPathEffect::Make());
1223 peStroke.setStrokeWidth(2.f);
1225 TestCase geoPEStrokeCase(geo, peStroke, reporter);
1226
1227 // Check whether constructing the filled case would cause the base shape to have a different
1228 // geometry (because of a geometric transformation upon initial GrStyledShape construction).
1229 if (geo.fillChangesGeom()) {
1230 fillGeoCase.compare(reporter, geoPECase, TestCase::kAllDifferent_ComparisonExpecation);
1231 fillGeoCase.compare(reporter, geoPEStrokeCase,
1232 TestCase::kAllDifferent_ComparisonExpecation);
1233 } else {
1234 fillGeoCase.compare(reporter, geoPECase, TestCase::kSameUpToPE_ComparisonExpecation);
1235 fillGeoCase.compare(reporter, geoPEStrokeCase, TestCase::kSameUpToPE_ComparisonExpecation);
1236 }
1237 geoPECase.compare(reporter, geoPEStrokeCase,
1238 TestCase::kSameUpToStroke_ComparisonExpecation);
1239
1240 TestCase rrectFillCase(reporter, RRectPathEffect::RRect(), fill);
1241 SkPaint stroke = peStroke;
1242 stroke.setPathEffect(nullptr);
1243 TestCase rrectStrokeCase(reporter, RRectPathEffect::RRect(), stroke);
1244
1245 SkRRect rrect;
1246 // Applying the path effect should make a SkRRect shape. There is no further stroking in the
1247 // geoPECase, so the full style should be the same as just the PE.
1248 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectShape().asRRect(&rrect, nullptr, nullptr,
1249 nullptr));
1250 REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect());
1251 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectKey() == rrectFillCase.baseKey());
1252
1253 REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleShape().asRRect(&rrect, nullptr, nullptr,
1254 nullptr));
1255 REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect());
1256 REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleKey() == rrectFillCase.baseKey());
1257
1258 // In the PE+stroke case applying the full style should be the same as just stroking the rrect.
1259 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectShape().asRRect(&rrect, nullptr,
1260 nullptr, nullptr));
1261 REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect());
1262 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectKey() == rrectFillCase.baseKey());
1263
1264 REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedFullStyleShape().asRRect(&rrect, nullptr,
1265 nullptr, nullptr));
1266 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleKey() ==
1267 rrectStrokeCase.appliedFullStyleKey());
1268}
@ kRRect

◆ test_rrect()

void test_rrect ( skiatest::Reporter r,
const SkRRect rrect 
)

Definition at line 1673 of file GrStyledShapeTest.cpp.

1673 {
1674 enum Style {
1675 kFill,
1676 kStroke,
1677 kHairline,
1679 };
1680
1681 // SkStrokeRec has no default cons., so init with kFill before calling the setters below.
1684 strokeRecs[kFill].setFillStyle();
1685 strokeRecs[kStroke].setStrokeStyle(2.f);
1686 strokeRecs[kHairline].setHairlineStyle();
1687 strokeRecs[kStrokeAndFill].setStrokeStyle(3.f, true);
1688 // Use a bevel join to avoid complications of stroke+filled rects becoming filled rects before
1689 // applyStyle() is called.
1690 strokeRecs[kStrokeAndFill].setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 1.f);
1691 sk_sp<SkPathEffect> dashEffect = make_dash();
1692
1693 static constexpr size_t kStyleCnt = std::size(strokeRecs);
1694
1695 auto index = [](bool inverted,
1697 unsigned start,
1698 Style style,
1699 bool dash) -> int {
1700 return inverted * (2 * 8 * kStyleCnt * 2) +
1701 (int)dir * ( 8 * kStyleCnt * 2) +
1702 start * ( kStyleCnt * 2) +
1703 style * ( 2) +
1704 dash;
1705 };
1706 static const SkPathDirection kSecondDirection = static_cast<SkPathDirection>(1);
1707 const int cnt = index(true, kSecondDirection, 7, static_cast<Style>(kStyleCnt - 1), true) + 1;
1708 AutoTArray<GrStyledShape> shapes(cnt);
1709 for (bool inverted : {false, true}) {
1711 for (unsigned start = 0; start < 8; ++start) {
1712 for (Style style : {kFill, kStroke, kHairline, kStrokeAndFill}) {
1713 for (bool dash : {false, true}) {
1714 sk_sp<SkPathEffect> pe = dash ? dashEffect : nullptr;
1715 shapes[index(inverted, dir, start, style, dash)] =
1716 GrStyledShape(rrect, dir, start, SkToBool(inverted),
1717 GrStyle(strokeRecs[style], std::move(pe)));
1718 }
1719 }
1720 }
1721 }
1722 }
1723
1724 // Get the keys for some example shape instances that we'll use for comparision against the
1725 // rest.
1726 static constexpr SkPathDirection kExamplesDir = SkPathDirection::kCW;
1727 static constexpr unsigned kExamplesStart = 0;
1728 const GrStyledShape& exampleFillCase = shapes[index(false, kExamplesDir, kExamplesStart, kFill,
1729 false)];
1730 Key exampleFillCaseKey;
1731 make_key(&exampleFillCaseKey, exampleFillCase);
1732
1733 const GrStyledShape& exampleStrokeAndFillCase = shapes[index(false, kExamplesDir,
1734 kExamplesStart, kStrokeAndFill, false)];
1735 Key exampleStrokeAndFillCaseKey;
1736 make_key(&exampleStrokeAndFillCaseKey, exampleStrokeAndFillCase);
1737
1738 const GrStyledShape& exampleInvFillCase = shapes[index(true, kExamplesDir,
1739 kExamplesStart, kFill, false)];
1740 Key exampleInvFillCaseKey;
1741 make_key(&exampleInvFillCaseKey, exampleInvFillCase);
1742
1743 const GrStyledShape& exampleInvStrokeAndFillCase = shapes[index(true, kExamplesDir,
1744 kExamplesStart, kStrokeAndFill,
1745 false)];
1746 Key exampleInvStrokeAndFillCaseKey;
1747 make_key(&exampleInvStrokeAndFillCaseKey, exampleInvStrokeAndFillCase);
1748
1749 const GrStyledShape& exampleStrokeCase = shapes[index(false, kExamplesDir, kExamplesStart,
1750 kStroke, false)];
1751 Key exampleStrokeCaseKey;
1752 make_key(&exampleStrokeCaseKey, exampleStrokeCase);
1753
1754 const GrStyledShape& exampleInvStrokeCase = shapes[index(true, kExamplesDir, kExamplesStart,
1755 kStroke, false)];
1756 Key exampleInvStrokeCaseKey;
1757 make_key(&exampleInvStrokeCaseKey, exampleInvStrokeCase);
1758
1759 const GrStyledShape& exampleHairlineCase = shapes[index(false, kExamplesDir, kExamplesStart,
1760 kHairline, false)];
1761 Key exampleHairlineCaseKey;
1762 make_key(&exampleHairlineCaseKey, exampleHairlineCase);
1763
1764 const GrStyledShape& exampleInvHairlineCase = shapes[index(true, kExamplesDir, kExamplesStart,
1765 kHairline, false)];
1766 Key exampleInvHairlineCaseKey;
1767 make_key(&exampleInvHairlineCaseKey, exampleInvHairlineCase);
1768
1769 // These initializations suppress warnings.
1770 SkRRect queryRR = SkRRect::MakeEmpty();
1772 unsigned queryStart = ~0U;
1773 bool queryInverted = true;
1774
1775 REPORTER_ASSERT(r, exampleFillCase.asRRect(&queryRR, &queryDir, &queryStart, &queryInverted));
1776 REPORTER_ASSERT(r, queryRR == rrect);
1777 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1778 REPORTER_ASSERT(r, 0 == queryStart);
1779 REPORTER_ASSERT(r, !queryInverted);
1780
1781 REPORTER_ASSERT(r, exampleInvFillCase.asRRect(&queryRR, &queryDir, &queryStart,
1782 &queryInverted));
1783 REPORTER_ASSERT(r, queryRR == rrect);
1784 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1785 REPORTER_ASSERT(r, 0 == queryStart);
1786 REPORTER_ASSERT(r, queryInverted);
1787
1788 REPORTER_ASSERT(r, exampleStrokeAndFillCase.asRRect(&queryRR, &queryDir, &queryStart,
1789 &queryInverted));
1790 REPORTER_ASSERT(r, queryRR == rrect);
1791 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1792 REPORTER_ASSERT(r, 0 == queryStart);
1793 REPORTER_ASSERT(r, !queryInverted);
1794
1795 REPORTER_ASSERT(r, exampleInvStrokeAndFillCase.asRRect(&queryRR, &queryDir, &queryStart,
1796 &queryInverted));
1797 REPORTER_ASSERT(r, queryRR == rrect);
1798 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1799 REPORTER_ASSERT(r, 0 == queryStart);
1800 REPORTER_ASSERT(r, queryInverted);
1801
1802 REPORTER_ASSERT(r, exampleHairlineCase.asRRect(&queryRR, &queryDir, &queryStart,
1803 &queryInverted));
1804 REPORTER_ASSERT(r, queryRR == rrect);
1805 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1806 REPORTER_ASSERT(r, 0 == queryStart);
1807 REPORTER_ASSERT(r, !queryInverted);
1808
1809 REPORTER_ASSERT(r, exampleInvHairlineCase.asRRect(&queryRR, &queryDir, &queryStart,
1810 &queryInverted));
1811 REPORTER_ASSERT(r, queryRR == rrect);
1812 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1813 REPORTER_ASSERT(r, 0 == queryStart);
1814 REPORTER_ASSERT(r, queryInverted);
1815
1816 REPORTER_ASSERT(r, exampleStrokeCase.asRRect(&queryRR, &queryDir, &queryStart, &queryInverted));
1817 REPORTER_ASSERT(r, queryRR == rrect);
1818 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1819 REPORTER_ASSERT(r, 0 == queryStart);
1820 REPORTER_ASSERT(r, !queryInverted);
1821
1822 REPORTER_ASSERT(r, exampleInvStrokeCase.asRRect(&queryRR, &queryDir, &queryStart,
1823 &queryInverted));
1824 REPORTER_ASSERT(r, queryRR == rrect);
1825 REPORTER_ASSERT(r, SkPathDirection::kCW == queryDir);
1826 REPORTER_ASSERT(r, 0 == queryStart);
1827 REPORTER_ASSERT(r, queryInverted);
1828
1829 // Remember that the key reflects the geometry before styling is applied.
1830 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvFillCaseKey);
1831 REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeAndFillCaseKey);
1832 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeAndFillCaseKey);
1833 REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeCaseKey);
1834 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeCaseKey);
1835 REPORTER_ASSERT(r, exampleFillCaseKey == exampleHairlineCaseKey);
1836 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvHairlineCaseKey);
1837 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvFillCaseKey);
1838 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvStrokeCaseKey);
1839 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvHairlineCaseKey);
1840
1841 for (bool inverted : {false, true}) {
1843 for (unsigned start = 0; start < 8; ++start) {
1844 for (bool dash : {false, true}) {
1845 const GrStyledShape& fillCase = shapes[index(inverted, dir, start, kFill,
1846 dash)];
1847 Key fillCaseKey;
1848 make_key(&fillCaseKey, fillCase);
1849
1850 const GrStyledShape& strokeAndFillCase = shapes[index(inverted, dir, start,
1851 kStrokeAndFill, dash)];
1852 Key strokeAndFillCaseKey;
1853 make_key(&strokeAndFillCaseKey, strokeAndFillCase);
1854
1855 // Both fill and stroke-and-fill shapes must respect the inverseness and both
1856 // ignore dashing.
1857 REPORTER_ASSERT(r, !fillCase.style().pathEffect());
1858 REPORTER_ASSERT(r, !strokeAndFillCase.style().pathEffect());
1859 TestCase a(fillCase, r);
1860 TestCase b(inverted ? exampleInvFillCase : exampleFillCase, r);
1861 TestCase c(strokeAndFillCase, r);
1862 TestCase d(inverted ? exampleInvStrokeAndFillCase
1863 : exampleStrokeAndFillCase, r);
1864 a.compare(r, b, TestCase::kAllSame_ComparisonExpecation);
1865 c.compare(r, d, TestCase::kAllSame_ComparisonExpecation);
1866
1867 const GrStyledShape& strokeCase = shapes[index(inverted, dir, start, kStroke,
1868 dash)];
1869 const GrStyledShape& hairlineCase = shapes[index(inverted, dir, start,
1870 kHairline, dash)];
1871
1872 TestCase e(strokeCase, r);
1873 TestCase g(hairlineCase, r);
1874
1875 // Both hairline and stroke shapes must respect the dashing.
1876 if (dash) {
1877 // Dashing always ignores the inverseness. skbug.com/5421
1878 TestCase f(exampleStrokeCase, r);
1879 TestCase h(exampleHairlineCase, r);
1880 unsigned expectedStart = canonicalize_rrect_start(start, rrect);
1881 REPORTER_ASSERT(r, strokeCase.style().pathEffect());
1882 REPORTER_ASSERT(r, hairlineCase.style().pathEffect());
1883
1884 REPORTER_ASSERT(r, strokeCase.asRRect(&queryRR, &queryDir, &queryStart,
1885 &queryInverted));
1886 REPORTER_ASSERT(r, queryRR == rrect);
1887 REPORTER_ASSERT(r, queryDir == dir);
1888 REPORTER_ASSERT(r, queryStart == expectedStart);
1889 REPORTER_ASSERT(r, !queryInverted);
1890 REPORTER_ASSERT(r, hairlineCase.asRRect(&queryRR, &queryDir, &queryStart,
1891 &queryInverted));
1892 REPORTER_ASSERT(r, queryRR == rrect);
1893 REPORTER_ASSERT(r, queryDir == dir);
1894 REPORTER_ASSERT(r, queryStart == expectedStart);
1895 REPORTER_ASSERT(r, !queryInverted);
1896
1897 // The pre-style case for the dash will match the non-dash example iff the
1898 // dir and start match (dir=cw, start=0).
1899 if (0 == expectedStart && SkPathDirection::kCW == dir) {
1900 e.compare(r, f, TestCase::kSameUpToPE_ComparisonExpecation);
1901 g.compare(r, h, TestCase::kSameUpToPE_ComparisonExpecation);
1902 } else {
1903 e.compare(r, f, TestCase::kAllDifferent_ComparisonExpecation);
1904 g.compare(r, h, TestCase::kAllDifferent_ComparisonExpecation);
1905 }
1906 } else {
1907 TestCase f(inverted ? exampleInvStrokeCase : exampleStrokeCase, r);
1908 TestCase h(inverted ? exampleInvHairlineCase : exampleHairlineCase, r);
1909 REPORTER_ASSERT(r, !strokeCase.style().pathEffect());
1910 REPORTER_ASSERT(r, !hairlineCase.style().pathEffect());
1911 e.compare(r, f, TestCase::kAllSame_ComparisonExpecation);
1912 g.compare(r, h, TestCase::kAllSame_ComparisonExpecation);
1913 }
1914 }
1915 }
1916 }
1917 }
1918}
unsigned canonicalize_rrect_start(int s, const SkRRect &rrect)
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
SkPathEffect * pathEffect() const
Definition GrStyle.h:119
bool asRRect(SkRRect *rrect, SkPathDirection *dir, unsigned *start, bool *inverted) const
void setFillStyle()
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
@ kStrokeAndFill
both strokes and fills shapes
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition switches.h:145
SkScalar h

◆ test_scale()

static void test_scale ( skiatest::Reporter reporter,
const Geo &  geo 
)
static

Definition at line 900 of file GrStyledShapeTest.cpp.

900 {
902
903 static const SkScalar kS1 = 1.f;
904 static const SkScalar kS2 = 2.f;
905
906 SkPaint fill;
907 TestCase fillCase1(geo, fill, reporter, kS1);
908 TestCase fillCase2(geo, fill, reporter, kS2);
909 // Scale doesn't affect fills.
910 fillCase1.compare(reporter, fillCase2, TestCase::kAllSame_ComparisonExpecation);
911
912 SkPaint hairline;
914 hairline.setStrokeWidth(0.f);
915 TestCase hairlineCase1(geo, hairline, reporter, kS1);
916 TestCase hairlineCase2(geo, hairline, reporter, kS2);
917 // Scale doesn't affect hairlines.
918 hairlineCase1.compare(reporter, hairlineCase2, TestCase::kAllSame_ComparisonExpecation);
919
920 SkPaint stroke;
922 stroke.setStrokeWidth(2.f);
923 TestCase strokeCase1(geo, stroke, reporter, kS1);
924 TestCase strokeCase2(geo, stroke, reporter, kS2);
925 // Scale affects the stroke
926 if (geo.strokeIsConvertedToFill()) {
927 REPORTER_ASSERT(reporter, !strokeCase1.baseShape().style().applies());
928 strokeCase1.compare(reporter, strokeCase2, TestCase::kAllSame_ComparisonExpecation);
929 } else {
930 strokeCase1.compare(reporter, strokeCase2, TestCase::kSameUpToStroke_ComparisonExpecation);
931 }
932
933 SkPaint strokeDash = stroke;
934 strokeDash.setPathEffect(make_dash());
935 TestCase strokeDashCase1(geo, strokeDash, reporter, kS1);
936 TestCase strokeDashCase2(geo, strokeDash, reporter, kS2);
937 // Scale affects the dash and the stroke.
938 strokeDashCase1.compare(reporter, strokeDashCase2,
939 TestCase::kSameUpToPE_ComparisonExpecation);
940
941 // Stroke and fill cases
942 SkPaint strokeAndFill = stroke;
944 TestCase strokeAndFillCase1(geo, strokeAndFill, reporter, kS1);
945 TestCase strokeAndFillCase2(geo, strokeAndFill, reporter, kS2);
946 SkPaint strokeAndFillDash = strokeDash;
947 strokeAndFillDash.setStyle(SkPaint::kStrokeAndFill_Style);
948 // Dash is ignored for stroke and fill
949 TestCase strokeAndFillDashCase1(geo, strokeAndFillDash, reporter, kS1);
950 TestCase strokeAndFillDashCase2(geo, strokeAndFillDash, reporter, kS2);
951 // Scale affects the stroke, but check to make sure this didn't become a simpler shape (e.g.
952 // stroke-and-filled rect can become a rect), in which case the scale shouldn't matter and the
953 // geometries should agree.
954 if (geo.strokeAndFillIsConvertedToFill(strokeAndFillDash)) {
955 REPORTER_ASSERT(reporter, !strokeAndFillCase1.baseShape().style().applies());
956 strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
957 TestCase::kAllSame_ComparisonExpecation);
958 strokeAndFillDashCase1.compare(reporter, strokeAndFillDashCase2,
959 TestCase::kAllSame_ComparisonExpecation);
960 } else {
961 strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
962 TestCase::kSameUpToStroke_ComparisonExpecation);
963 }
964 strokeAndFillDashCase1.compare(reporter, strokeAndFillCase1,
965 TestCase::kAllSame_ComparisonExpecation);
966 strokeAndFillDashCase2.compare(reporter, strokeAndFillCase2,
967 TestCase::kAllSame_ComparisonExpecation);
968}

◆ test_stroke_cap()

static void test_stroke_cap ( skiatest::Reporter reporter,
const Geo &  geo 
)
static

Definition at line 1052 of file GrStyledShapeTest.cpp.

1052 {
1053 SkPaint hairline;
1054 hairline.setStrokeWidth(0);
1056 GrStyledShape shape = geo.makeShape(hairline);
1057 // The cap should only affect shapes that may be open.
1058 bool affectsStroke = !shape.knownToBeClosed();
1059 // Dashing adds ends that need caps.
1060 bool affectsDashAndStroke = true;
1061 test_stroke_param_impl<SkPaint::Cap>(
1062 reporter,
1063 geo,
1064 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);},
1066 affectsStroke,
1067 affectsDashAndStroke);
1068}
bool knownToBeClosed() const

◆ test_stroke_join()

static void test_stroke_join ( skiatest::Reporter reporter,
const Geo &  geo 
)
static

Definition at line 1074 of file GrStyledShapeTest.cpp.

1074 {
1075 SkPaint hairline;
1076 hairline.setStrokeWidth(0);
1078 GrStyledShape shape = geo.makeShape(hairline);
1079 // GrStyledShape recognizes certain types don't have joins and will prevent the join type from
1080 // affecting the style key.
1081 // Dashing doesn't add additional joins. However, GrStyledShape currently loses track of this
1082 // after applying the dash.
1083 bool affectsStroke = !shape_known_not_to_have_joins(shape);
1084 test_stroke_param_impl<SkPaint::Join>(
1085 reporter,
1086 geo,
1087 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
1089 affectsStroke, true);
1090}

◆ test_stroke_param()

template<typename T >
static void test_stroke_param ( skiatest::Reporter reporter,
const Geo &  geo,
std::function< void(SkPaint *, T)>  setter,
T  a,
T  b 
)
static

Definition at line 1047 of file GrStyledShapeTest.cpp.

1048 {
1049 test_stroke_param_impl(reporter, geo, setter, a, b, true, true);
1050}
static void test_stroke_param_impl(skiatest::Reporter *reporter, const Geo &geo, std::function< void(SkPaint *, T)> setter, T a, T b, bool paramAffectsStroke, bool paramAffectsDashAndStroke)

◆ test_stroke_param_impl()

template<typename T >
static void test_stroke_param_impl ( skiatest::Reporter reporter,
const Geo &  geo,
std::function< void(SkPaint *, T)>  setter,
T  a,
T  b,
bool  paramAffectsStroke,
bool  paramAffectsDashAndStroke 
)
static

Definition at line 971 of file GrStyledShapeTest.cpp.

974 {
975 // Set the stroke width so that we don't get hairline. However, call the setter afterward so
976 // that it can override the stroke width.
977 SkPaint strokeA;
979 strokeA.setStrokeWidth(2.f);
980 setter(&strokeA, a);
981 SkPaint strokeB;
983 strokeB.setStrokeWidth(2.f);
984 setter(&strokeB, b);
985
986 TestCase strokeACase(geo, strokeA, reporter);
987 TestCase strokeBCase(geo, strokeB, reporter);
988 if (paramAffectsStroke) {
989 // If stroking is immediately incorporated into a geometric transformation then the base
990 // shapes will differ.
991 if (geo.strokeIsConvertedToFill()) {
992 strokeACase.compare(reporter, strokeBCase,
993 TestCase::kAllDifferent_ComparisonExpecation);
994 } else {
995 strokeACase.compare(reporter, strokeBCase,
996 TestCase::kSameUpToStroke_ComparisonExpecation);
997 }
998 } else {
999 strokeACase.compare(reporter, strokeBCase, TestCase::kAllSame_ComparisonExpecation);
1000 }
1001
1002 SkPaint strokeAndFillA = strokeA;
1003 SkPaint strokeAndFillB = strokeB;
1006 TestCase strokeAndFillACase(geo, strokeAndFillA, reporter);
1007 TestCase strokeAndFillBCase(geo, strokeAndFillB, reporter);
1008 if (paramAffectsStroke) {
1009 // If stroking is immediately incorporated into a geometric transformation then the base
1010 // shapes will differ.
1011 if (geo.strokeAndFillIsConvertedToFill(strokeAndFillA) ||
1012 geo.strokeAndFillIsConvertedToFill(strokeAndFillB)) {
1013 strokeAndFillACase.compare(reporter, strokeAndFillBCase,
1014 TestCase::kAllDifferent_ComparisonExpecation);
1015 } else {
1016 strokeAndFillACase.compare(reporter, strokeAndFillBCase,
1017 TestCase::kSameUpToStroke_ComparisonExpecation);
1018 }
1019 } else {
1020 strokeAndFillACase.compare(reporter, strokeAndFillBCase,
1021 TestCase::kAllSame_ComparisonExpecation);
1022 }
1023
1024 // Make sure stroking params don't affect fill style.
1025 SkPaint fillA = strokeA, fillB = strokeB;
1027 fillB.setStyle(SkPaint::kFill_Style);
1028 TestCase fillACase(geo, fillA, reporter);
1029 TestCase fillBCase(geo, fillB, reporter);
1030 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecation);
1031
1032 // Make sure just applying the dash but not stroke gives the same key for both stroking
1033 // variations.
1034 SkPaint dashA = strokeA, dashB = strokeB;
1035 dashA.setPathEffect(make_dash());
1036 dashB.setPathEffect(make_dash());
1037 TestCase dashACase(geo, dashA, reporter);
1038 TestCase dashBCase(geo, dashB, reporter);
1039 if (paramAffectsDashAndStroke) {
1040 dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1041 } else {
1042 dashACase.compare(reporter, dashBCase, TestCase::kAllSame_ComparisonExpecation);
1043 }
1044}
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193

◆ test_unknown_path_effect()

void test_unknown_path_effect ( skiatest::Reporter reporter,
const Geo &  geo 
)

This path effect just adds two lineTos to the input path.

Definition at line 1270 of file GrStyledShapeTest.cpp.

1270 {
1271 /**
1272 * This path effect just adds two lineTos to the input path.
1273 */
1274 class AddLineTosPathEffect : SkPathEffectBase {
1275 public:
1276 static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new AddLineTosPathEffect); }
1277 Factory getFactory() const override { return nullptr; }
1278 const char* getTypeName() const override { return nullptr; }
1279
1280 protected:
1281 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1282 const SkRect* cullR, const SkMatrix&) const override {
1283 *dst = src;
1284 // To avoid triggering data-based keying of paths with few verbs we add many segments.
1285 for (int i = 0; i < 100; ++i) {
1286 dst->lineTo(SkIntToScalar(i), SkIntToScalar(i));
1287 }
1288 return true;
1289 }
1290 bool computeFastBounds(SkRect* bounds) const override {
1291 if (bounds) {
1292 SkRectPriv::GrowToInclude(bounds, {0, 0});
1293 SkRectPriv::GrowToInclude(bounds, {100, 100});
1294 }
1295 return true;
1296 }
1297 private:
1298 AddLineTosPathEffect() {}
1299 };
1300
1301 // This path effect should make the keys invalid when it is applied. We only produce a path
1302 // effect key for dash path effects. So the only way another arbitrary path effect can produce
1303 // a styled result with a key is to produce a non-path shape that has a purely geometric key.
1304 SkPaint peStroke;
1305 peStroke.setPathEffect(AddLineTosPathEffect::Make());
1306 peStroke.setStrokeWidth(2.f);
1308 TestCase geoPEStrokeCase(geo, peStroke, reporter);
1309 TestCase::SelfExpectations expectations;
1310 expectations.fPEHasEffect = true;
1311 expectations.fPEHasValidKey = false;
1312 expectations.fStrokeApplies = true;
1313 geoPEStrokeCase.testExpectations(reporter, expectations);
1314}
static void GrowToInclude(SkRect *r, const SkPoint &pt)
Definition SkRectPriv.h:47

◆ test_volatile_path()

void test_volatile_path ( skiatest::Reporter reporter,
const Geo &  geo 
)

Definition at line 1376 of file GrStyledShapeTest.cpp.

1376 {
1377 SkPath vPath = geo.path();
1378 vPath.setIsVolatile(true);
1379
1380 SkPaint dashAndStroke;
1381 dashAndStroke.setPathEffect(make_dash());
1382 dashAndStroke.setStrokeWidth(2.f);
1383 dashAndStroke.setStyle(SkPaint::kStroke_Style);
1384 TestCase volatileCase(reporter, vPath, dashAndStroke);
1385 // We expect a shape made from a volatile path to have a key iff the shape is recognized
1386 // as a specialized geometry.
1387 if (geo.isNonPath(dashAndStroke)) {
1388 REPORTER_ASSERT(reporter, SkToBool(volatileCase.baseKey().size()));
1389 // In this case all the keys should be identical to the non-volatile case.
1390 TestCase nonVolatileCase(reporter, geo.path(), dashAndStroke);
1391 volatileCase.compare(reporter, nonVolatileCase, TestCase::kAllSame_ComparisonExpecation);
1392 } else {
1393 // None of the keys should be valid.
1394 REPORTER_ASSERT(reporter, SkToBool(volatileCase.baseKey().empty()));
1395 REPORTER_ASSERT(reporter, SkToBool(volatileCase.appliedPathEffectKey().empty()));
1396 REPORTER_ASSERT(reporter, SkToBool(volatileCase.appliedFullStyleKey().empty()));
1397 REPORTER_ASSERT(reporter, SkToBool(volatileCase.appliedPathEffectThenStrokeKey().empty()));
1398 }
1399}