Flutter Engine
The Flutter Engine
Typedefs | Functions
GrStyledShapeTest.cpp File Reference
#include "include/core/SkArc.h"
#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 65 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 125 of file GrStyledShapeTest.cpp.

125 {
126 SkPath path;
127 shape.asPath(&path);
128 if (shape.style().hasNonDashPathEffect()) {
129 return false;
130 }
131 const SkStrokeRec::Style strokeRecStyle = shape.style().strokeRec().getStyle();
132 return strokeRecStyle == SkStrokeRec::kStroke_Style ||
133 strokeRecStyle == SkStrokeRec::kHairline_Style ||
134 (shape.style().isSimpleFill() && path.isConvex());
135}
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
Definition: SkPath.h:59
Style getStyle() const
Definition: SkStrokeRec.cpp:71
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 1648 of file GrStyledShapeTest.cpp.

1648 {
1649 switch (rrect.getType()) {
1651 return (s + 1) & 0b110;
1653 return s & 0b110;
1654 default:
1655 return s;
1656 }
1657}
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 137 of file GrStyledShapeTest.cpp.

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

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

◆ DEF_TEST() [1/7]

DEF_TEST ( GrShapeInversion  ,
 
)

Definition at line 2364 of file GrStyledShapeTest.cpp.

2364 {
2365 SkPath path;
2366 SkScalar radii[] = {10.f, 10.f, 10.f, 10.f,
2367 10.f, 10.f, 10.f, 10.f};
2368 path.addRoundRect(SkRect::MakeWH(50, 50), radii);
2369 path.toggleInverseFillType();
2370
2371 GrShape inverseRRect(path);
2372 GrShape rrect(inverseRRect);
2373 rrect.setInverted(false);
2374
2375 REPORTER_ASSERT(r, inverseRRect.inverted() && inverseRRect.isPath());
2376 REPORTER_ASSERT(r, !rrect.inverted() && rrect.isPath());
2377
2378 // Invertedness should be preserved after simplification
2379 inverseRRect.simplify();
2380 rrect.simplify();
2381
2382 REPORTER_ASSERT(r, inverseRRect.inverted() && inverseRRect.isRRect());
2383 REPORTER_ASSERT(r, !rrect.inverted() && rrect.isRRect());
2384
2385 // Invertedness should be reset when calling reset().
2386 inverseRRect.reset();
2387 REPORTER_ASSERT(r, !inverseRRect.inverted() && inverseRRect.isEmpty());
2388 inverseRRect.setPath(path);
2389 inverseRRect.reset();
2390 REPORTER_ASSERT(r, !inverseRRect.inverted() && inverseRRect.isEmpty());
2391}
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 2125 of file GrStyledShapeTest.cpp.

2125 {
2128
2129 for (auto r : { SkRect::MakeWH(10, 20),
2130 SkRect::MakeWH(-10, -20),
2131 SkRect::MakeWH(-10, 20),
2132 SkRect::MakeWH(10, -20)}) {
2133 geos.emplace_back(new RectGeo(r));
2134 SkPath rectPath;
2135 rectPath.addRect(r);
2136 geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2137 PathGeo::Invert::kNo));
2138 geos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2139 PathGeo::Invert::kYes));
2140 rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2141 PathGeo::Invert::kNo));
2142 }
2143 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)),
2144 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4),
2146 geos.emplace_back(new RRectGeo(rr));
2147 test_rrect(reporter, rr);
2148 SkPath rectPath;
2149 rectPath.addRRect(rr);
2150 geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2151 PathGeo::Invert::kNo));
2152 geos.emplace_back(new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2153 PathGeo::Invert::kYes));
2154 rrectPathGeos.emplace_back(new RRectPathGeo(rectPath, rr,
2155 RRectPathGeo::RRectForStroke::kYes,
2156 PathGeo::Invert::kNo));
2157 }
2158
2159 // Arcs
2160 geos.emplace_back(
2161 new ArcGeo(SkArc::Make(SkRect::MakeWH(200, 100), 12.f, 110.f, SkArc::Type::kArc)));
2162 geos.emplace_back(
2163 new ArcGeo(SkArc::Make(SkRect::MakeWH(200, 100), 12.f, 110.f, SkArc::Type::kWedge)));
2164
2165 {
2166 SkPath openRectPath;
2167 openRectPath.moveTo(0, 0);
2168 openRectPath.lineTo(10, 0);
2169 openRectPath.lineTo(10, 10);
2170 openRectPath.lineTo(0, 10);
2171 geos.emplace_back(new RRectPathGeo(
2172 openRectPath, SkRect::MakeWH(10, 10),
2173 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2174 geos.emplace_back(new RRectPathGeo(
2175 openRectPath, SkRect::MakeWH(10, 10),
2176 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kYes));
2177 rrectPathGeos.emplace_back(new RRectPathGeo(
2178 openRectPath, SkRect::MakeWH(10, 10),
2179 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2180 }
2181
2182 {
2183 SkPath quadPath;
2184 quadPath.quadTo(10, 10, 5, 8);
2185 geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kNo));
2186 geos.emplace_back(new PathGeo(quadPath, PathGeo::Invert::kYes));
2187 }
2188
2189 {
2190 SkPath linePath;
2191 linePath.lineTo(10, 10);
2192 geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kNo));
2193 geos.emplace_back(new PathGeo(linePath, PathGeo::Invert::kYes));
2194 }
2195
2196 // Horizontal and vertical paths become rrects when stroked.
2197 {
2198 SkPath vLinePath;
2199 vLinePath.lineTo(0, 10);
2200 geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kNo));
2201 geos.emplace_back(new PathGeo(vLinePath, PathGeo::Invert::kYes));
2202 }
2203
2204 {
2205 SkPath hLinePath;
2206 hLinePath.lineTo(10, 0);
2207 geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kNo));
2208 geos.emplace_back(new PathGeo(hLinePath, PathGeo::Invert::kYes));
2209 }
2210
2211 for (int i = 0; i < geos.size(); ++i) {
2212 test_basic(reporter, *geos[i]);
2213 test_scale(reporter, *geos[i]);
2214 test_dash_fill(reporter, *geos[i]);
2215 test_null_dash(reporter, *geos[i]);
2216 // Test modifying various stroke params.
2217 test_stroke_param<SkScalar>(
2218 reporter, *geos[i],
2219 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
2221 test_stroke_join(reporter, *geos[i]);
2222 test_stroke_cap(reporter, *geos[i]);
2223 test_miter_limit(reporter, *geos[i]);
2229 test_volatile_path(reporter, *geos[i]);
2230 }
2231
2232 for (int i = 0; i < rrectPathGeos.size(); ++i) {
2233 const RRectPathGeo& rrgeo = *rrectPathGeos[i];
2234 SkPaint fillPaint;
2235 TestCase fillPathCase(reporter, rrgeo.path(), fillPaint);
2236 SkRRect rrect;
2237 REPORTER_ASSERT(reporter, rrgeo.isNonPath(fillPaint) ==
2238 fillPathCase.baseShape().asRRect(&rrect, nullptr));
2239 if (rrgeo.isNonPath(fillPaint)) {
2240 TestCase fillPathCase2(reporter, rrgeo.path(), fillPaint);
2241 REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
2242 TestCase fillRRectCase(reporter, rrect, fillPaint);
2243 fillPathCase2.compare(reporter, fillRRectCase,
2244 TestCase::kAllSame_ComparisonExpecation);
2245 }
2246 SkPaint strokePaint;
2247 strokePaint.setStrokeWidth(3.f);
2248 strokePaint.setStyle(SkPaint::kStroke_Style);
2249 TestCase strokePathCase(reporter, rrgeo.path(), strokePaint);
2250 if (rrgeo.isNonPath(strokePaint)) {
2251 REPORTER_ASSERT(reporter, strokePathCase.baseShape().asRRect(&rrect, nullptr));
2252 REPORTER_ASSERT(reporter, rrect == rrgeo.rrect());
2253 TestCase strokeRRectCase(reporter, rrect, strokePaint);
2254 strokePathCase.compare(reporter, strokeRRectCase,
2255 TestCase::kAllSame_ComparisonExpecation);
2256 }
2257 }
2258
2259 // Test a volatile empty path.
2260 test_volatile_path(reporter, PathGeo(SkPath(), PathGeo::Invert::kNo));
2261}
reporter
Definition: FontMgrTest.cpp:39
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:688
SkPath & lineTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:728
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1000
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Definition: SkPath.cpp:746
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition: SkPath.cpp:864
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:421
T & emplace_back(Args &&... args)
Definition: SkTArray.h:248
SkScalar w
static SkArc Make(const SkRect &oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, Type type)
Definition: SkArc.h:38

◆ DEF_TEST() [3/7]

DEF_TEST ( GrStyledShape_arcs  ,
reporter   
)

Definition at line 2263 of file GrStyledShapeTest.cpp.

2263 {
2265 roundStroke.setStrokeStyle(2.f);
2266 roundStroke.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 1.f);
2267
2268 SkStrokeRec squareStroke(roundStroke);
2269 squareStroke.setStrokeParams(SkPaint::kSquare_Cap, SkPaint::kRound_Join, 1.f);
2270
2271 SkStrokeRec roundStrokeAndFill(roundStroke);
2272 roundStrokeAndFill.setStrokeStyle(2.f, true);
2273
2274 static constexpr SkScalar kIntervals[] = {1, 2};
2275 auto dash = SkDashPathEffect::Make(kIntervals, std::size(kIntervals), 1.5f);
2276
2277 TArray<GrStyle> styles;
2280 styles.push_back(GrStyle(roundStroke, nullptr));
2281 styles.push_back(GrStyle(squareStroke, nullptr));
2282 styles.push_back(GrStyle(roundStrokeAndFill, nullptr));
2283 styles.push_back(GrStyle(roundStroke, dash));
2284
2285 for (const auto& style : styles) {
2286 // An empty rect never draws anything according to SkCanvas::drawArc() docs.
2287 TestCase emptyArc(
2289 style),
2290 reporter);
2291 TestCase emptyPath(reporter, SkPath(), style);
2292 emptyArc.compare(reporter, emptyPath, TestCase::kAllSame_ComparisonExpecation);
2293
2294 static constexpr SkRect kOval1{0, 0, 50, 50};
2295 static constexpr SkRect kOval2{50, 0, 100, 50};
2296 // Test that swapping starting and ending angle doesn't change the shape unless the arc
2297 // has a path effect. Also test that different ovals produce different shapes.
2298 TestCase arc1CW(
2299 GrStyledShape::MakeArc(SkArc::Make(kOval1, 0, 90.f, SkArc::Type::kArc), style),
2300 reporter);
2301 TestCase arc1CCW(
2302 GrStyledShape::MakeArc(SkArc::Make(kOval1, 90.f, -90.f, SkArc::Type::kArc), style),
2303 reporter);
2304
2305 TestCase arc1CWWithCenter(
2306 GrStyledShape::MakeArc(SkArc::Make(kOval1, 0, 90.f, SkArc::Type::kWedge), style),
2307 reporter);
2308 TestCase arc1CCWWithCenter(
2310 style),
2311 reporter);
2312
2313 TestCase arc2CW(
2314 GrStyledShape::MakeArc(SkArc::Make(kOval2, 0, 90.f, SkArc::Type::kArc), style),
2315 reporter);
2316 TestCase arc2CWWithCenter(
2317 GrStyledShape::MakeArc(SkArc::Make(kOval2, 0, 90.f, SkArc::Type::kWedge), style),
2318 reporter);
2319
2320 auto reversedExepectations = style.hasPathEffect()
2321 ? TestCase::kAllDifferent_ComparisonExpecation
2322 : TestCase::kAllSame_ComparisonExpecation;
2323 arc1CW.compare(reporter, arc1CCW, reversedExepectations);
2324 arc1CWWithCenter.compare(reporter, arc1CCWWithCenter, reversedExepectations);
2325 arc1CW.compare(reporter, arc2CW, TestCase::kAllDifferent_ComparisonExpecation);
2326 arc1CW.compare(reporter, arc1CWWithCenter, TestCase::kAllDifferent_ComparisonExpecation);
2327 arc1CWWithCenter.compare(reporter, arc2CWWithCenter,
2328 TestCase::kAllDifferent_ComparisonExpecation);
2329
2330 // Test that two arcs that start at the same angle but specified differently are equivalent.
2331 TestCase arc3A(
2332 GrStyledShape::MakeArc(SkArc::Make(kOval1, 224.f, 73.f, SkArc::Type::kArc), style),
2333 reporter);
2334 TestCase arc3B(GrStyledShape::MakeArc(
2335 SkArc::Make(kOval1, 224.f - 360.f, 73.f, SkArc::Type::kArc), style),
2336 reporter);
2337 arc3A.compare(reporter, arc3B, TestCase::kAllDifferent_ComparisonExpecation);
2338
2339 // Test that an arc that traverses the entire oval (and then some) is equivalent to the
2340 // oval itself unless there is a path effect.
2341 TestCase ovalArc(GrStyledShape::MakeArc(
2342 SkArc::Make(kOval1, 150.f, -790.f, SkArc::Type::kArc), style),
2343 reporter);
2344 TestCase oval(GrStyledShape(SkRRect::MakeOval(kOval1)), reporter);
2345 auto ovalExpectations = style.hasPathEffect() ? TestCase::kAllDifferent_ComparisonExpecation
2346 : TestCase::kAllSame_ComparisonExpecation;
2347 if (style.strokeRec().getWidth() >= 0 && style.strokeRec().getCap() != SkPaint::kButt_Cap) {
2348 ovalExpectations = TestCase::kAllDifferent_ComparisonExpecation;
2349 }
2350 ovalArc.compare(reporter, oval, ovalExpectations);
2351
2352 // If the the arc starts/ends at the center then it is then equivalent to the oval only for
2353 // simple fills.
2354 TestCase ovalArcWithCenter(
2356 style),
2357 reporter);
2358 ovalExpectations = style.isSimpleFill() ? TestCase::kAllSame_ComparisonExpecation
2359 : TestCase::kAllDifferent_ComparisonExpecation;
2360 ovalArcWithCenter.compare(reporter, oval, ovalExpectations);
2361 }
2362}
static const GrStyle & SimpleHairline()
Definition: GrStyle.h:39
static const GrStyle & SimpleFill()
Definition: GrStyle.h:30
static GrStyledShape MakeArc(const SkArc &arc, 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
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
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595

◆ DEF_TEST() [4/7]

DEF_TEST ( GrStyledShape_empty_shape  ,
reporter   
)

Definition at line 1540 of file GrStyledShapeTest.cpp.

1540 {
1541 SkPath emptyPath;
1542 SkPath invertedEmptyPath;
1543 invertedEmptyPath.toggleInverseFillType();
1544 SkPaint fill;
1545 TestCase fillEmptyCase(reporter, emptyPath, fill);
1546 REPORTER_ASSERT(reporter, fillEmptyCase.baseShape().isEmpty());
1547 REPORTER_ASSERT(reporter, fillEmptyCase.appliedPathEffectShape().isEmpty());
1548 REPORTER_ASSERT(reporter, fillEmptyCase.appliedFullStyleShape().isEmpty());
1549 REPORTER_ASSERT(reporter, !fillEmptyCase.baseShape().inverseFilled());
1550 REPORTER_ASSERT(reporter, !fillEmptyCase.appliedPathEffectShape().inverseFilled());
1551 REPORTER_ASSERT(reporter, !fillEmptyCase.appliedFullStyleShape().inverseFilled());
1552 TestCase fillInvertedEmptyCase(reporter, invertedEmptyPath, fill);
1553 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.baseShape().isEmpty());
1554 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedPathEffectShape().isEmpty());
1555 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedFullStyleShape().isEmpty());
1556 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.baseShape().inverseFilled());
1557 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedPathEffectShape().inverseFilled());
1558 REPORTER_ASSERT(reporter, fillInvertedEmptyCase.appliedFullStyleShape().inverseFilled());
1559
1560 const Key& emptyKey = fillEmptyCase.baseKey();
1561 REPORTER_ASSERT(reporter, emptyKey.size());
1562 const Key& inverseEmptyKey = fillInvertedEmptyCase.baseKey();
1563 REPORTER_ASSERT(reporter, inverseEmptyKey.size());
1564 TestCase::SelfExpectations expectations;
1565 expectations.fStrokeApplies = false;
1566 expectations.fPEHasEffect = false;
1567 // This will test whether applying style preserves emptiness
1568 fillEmptyCase.testExpectations(reporter, expectations);
1569 fillInvertedEmptyCase.testExpectations(reporter, expectations);
1570
1571 // Stroking an empty path should have no effect
1573 stroke.setStrokeWidth(2.f);
1575 stroke.setStrokeJoin(SkPaint::kRound_Join);
1576 stroke.setStrokeCap(SkPaint::kRound_Cap);
1577 TestCase strokeEmptyCase(reporter, emptyPath, stroke);
1578 strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1579 TestCase strokeInvertedEmptyCase(reporter, invertedEmptyPath, stroke);
1580 strokeInvertedEmptyCase.compare(reporter, fillInvertedEmptyCase,
1581 TestCase::kAllSame_ComparisonExpecation);
1582
1583 // Dashing and stroking an empty path should have no effect
1584 SkPaint dashAndStroke;
1585 dashAndStroke.setPathEffect(make_dash());
1586 dashAndStroke.setStrokeWidth(2.f);
1587 dashAndStroke.setStyle(SkPaint::kStroke_Style);
1588 TestCase dashAndStrokeEmptyCase(reporter, emptyPath, dashAndStroke);
1589 dashAndStrokeEmptyCase.compare(reporter, fillEmptyCase,
1590 TestCase::kAllSame_ComparisonExpecation);
1591 TestCase dashAndStrokeInvertexEmptyCase(reporter, invertedEmptyPath, dashAndStroke);
1592 // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
1593 dashAndStrokeInvertexEmptyCase.compare(reporter, fillEmptyCase,
1594 TestCase::kAllSame_ComparisonExpecation);
1595
1596 // A shape made from an empty rrect should behave the same as an empty path when filled and
1597 // when stroked. The shape is closed so it does not produce caps when stroked. When dashed there
1598 // is no path to dash along, making it equivalent as well.
1599 SkRRect emptyRRect = SkRRect::MakeEmpty();
1601
1602 TestCase fillEmptyRRectCase(reporter, emptyRRect, fill);
1603 fillEmptyRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1604
1605 TestCase strokeEmptyRRectCase(reporter, emptyRRect, stroke);
1606 strokeEmptyRRectCase.compare(reporter, strokeEmptyCase,
1607 TestCase::kAllSame_ComparisonExpecation);
1608
1609 TestCase dashAndStrokeEmptyRRectCase(reporter, emptyRRect, dashAndStroke);
1610 dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase,
1611 TestCase::kAllSame_ComparisonExpecation);
1612
1613 static constexpr SkPathDirection kDir = SkPathDirection::kCCW;
1614 static constexpr int kStart = 0;
1615
1616 TestCase fillInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true, GrStyle(fill));
1617 fillInvertedEmptyRRectCase.compare(reporter, fillInvertedEmptyCase,
1618 TestCase::kAllSame_ComparisonExpecation);
1619
1620 TestCase strokeInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true,
1621 GrStyle(stroke));
1622 strokeInvertedEmptyRRectCase.compare(reporter, strokeInvertedEmptyCase,
1623 TestCase::kAllSame_ComparisonExpecation);
1624
1625 TestCase dashAndStrokeEmptyInvertedRRectCase(reporter, emptyRRect, kDir, kStart, true,
1626 GrStyle(dashAndStroke));
1627 dashAndStrokeEmptyInvertedRRectCase.compare(reporter, fillEmptyCase,
1628 TestCase::kAllSame_ComparisonExpecation);
1629
1630 // Same for a rect.
1631 SkRect emptyRect = SkRect::MakeEmpty();
1632 TestCase fillEmptyRectCase(reporter, emptyRect, fill);
1633 fillEmptyRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1634
1635 TestCase dashAndStrokeEmptyRectCase(reporter, emptyRect, dashAndStroke);
1636 dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase,
1637 TestCase::kAllSame_ComparisonExpecation);
1638
1639 TestCase dashAndStrokeEmptyInvertedRectCase(reporter, SkRRect::MakeRect(emptyRect), kDir,
1640 kStart, true, GrStyle(dashAndStroke));
1641 // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
1642 dashAndStrokeEmptyInvertedRectCase.compare(reporter, fillEmptyCase,
1643 TestCase::kAllSame_ComparisonExpecation);
1644}
static sk_sp< SkPathEffect > make_dash()
SkPathDirection
Definition: SkPathTypes.h:34
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 1876 of file GrStyledShapeTest.cpp.

1876 {
1877 static constexpr SkPoint kA { 1, 1};
1878 static constexpr SkPoint kB { 5, -9};
1879 static constexpr SkPoint kC {-3, 17};
1880
1881 SkPath lineAB = SkPath::Line(kA, kB);
1882 SkPath lineBA = SkPath::Line(kB, kA);
1883 SkPath lineAC = SkPath::Line(kB, kC);
1884 SkPath invLineAB = lineAB;
1885
1887
1888 SkPaint fill;
1891 stroke.setStrokeWidth(2.f);
1892 SkPaint hairline;
1894 hairline.setStrokeWidth(0.f);
1895 SkPaint dash = stroke;
1896 dash.setPathEffect(make_dash());
1897
1898 TestCase fillAB(r, lineAB, fill);
1899 TestCase fillEmpty(r, SkPath(), fill);
1900 fillAB.compare(r, fillEmpty, TestCase::kAllSame_ComparisonExpecation);
1901 REPORTER_ASSERT(r, !fillAB.baseShape().asLine(nullptr, nullptr));
1902
1903 SkPath path;
1904 path.toggleInverseFillType();
1905 TestCase fillEmptyInverted(r, path, fill);
1906 TestCase fillABInverted(r, invLineAB, fill);
1907 fillABInverted.compare(r, fillEmptyInverted, TestCase::kAllSame_ComparisonExpecation);
1908 REPORTER_ASSERT(r, !fillABInverted.baseShape().asLine(nullptr, nullptr));
1909
1910 TestCase strokeAB(r, lineAB, stroke);
1911 TestCase strokeBA(r, lineBA, stroke);
1912 TestCase strokeAC(r, lineAC, stroke);
1913
1914 TestCase hairlineAB(r, lineAB, hairline);
1915 TestCase hairlineBA(r, lineBA, hairline);
1916 TestCase hairlineAC(r, lineAC, hairline);
1917
1918 TestCase dashAB(r, lineAB, dash);
1919 TestCase dashBA(r, lineBA, dash);
1920 TestCase dashAC(r, lineAC, dash);
1921
1922 strokeAB.compare(r, fillAB, TestCase::kAllDifferent_ComparisonExpecation);
1923
1924 strokeAB.compare(r, strokeBA, TestCase::kAllSame_ComparisonExpecation);
1925 strokeAB.compare(r, strokeAC, TestCase::kAllDifferent_ComparisonExpecation);
1926
1927 hairlineAB.compare(r, hairlineBA, TestCase::kAllSame_ComparisonExpecation);
1928 hairlineAB.compare(r, hairlineAC, TestCase::kAllDifferent_ComparisonExpecation);
1929
1930 dashAB.compare(r, dashBA, TestCase::kAllDifferent_ComparisonExpecation);
1931 dashAB.compare(r, dashAC, TestCase::kAllDifferent_ComparisonExpecation);
1932
1933 strokeAB.compare(r, hairlineAB, TestCase::kSameUpToStroke_ComparisonExpecation);
1934
1935 // One of dashAB or dashBA should have the same line as strokeAB. It depends upon how
1936 // GrStyledShape canonicalizes line endpoints (when it can, i.e. when not dashed).
1937 bool canonicalizeAsAB;
1938 SkPoint canonicalPts[2] {kA, kB};
1939 // Init these to suppress warnings.
1940 bool inverted = true;
1941 SkPoint pts[2] {{0, 0}, {0, 0}};
1942 REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted);
1943 if (pts[0] == kA && pts[1] == kB) {
1944 canonicalizeAsAB = true;
1945 } else if (pts[1] == kA && pts[0] == kB) {
1946 canonicalizeAsAB = false;
1947 using std::swap;
1948 swap(canonicalPts[0], canonicalPts[1]);
1949 } else {
1950 ERRORF(r, "Should return pts (a,b) or (b, a)");
1951 return;
1952 }
1953
1954 strokeAB.compare(r, canonicalizeAsAB ? dashAB : dashBA,
1955 TestCase::kSameUpToPE_ComparisonExpecation);
1956 REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted &&
1957 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1958 REPORTER_ASSERT(r, hairlineAB.baseShape().asLine(pts, &inverted) && !inverted &&
1959 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1960 REPORTER_ASSERT(r, dashAB.baseShape().asLine(pts, &inverted) && !inverted &&
1961 pts[0] == kA && pts[1] == kB);
1962 REPORTER_ASSERT(r, dashBA.baseShape().asLine(pts, &inverted) && !inverted &&
1963 pts[0] == kB && pts[1] == kA);
1964
1965
1966 TestCase strokeInvAB(r, invLineAB, stroke);
1967 TestCase hairlineInvAB(r, invLineAB, hairline);
1968 TestCase dashInvAB(r, invLineAB, dash);
1969 strokeInvAB.compare(r, strokeAB, TestCase::kAllDifferent_ComparisonExpecation);
1970 hairlineInvAB.compare(r, hairlineAB, TestCase::kAllDifferent_ComparisonExpecation);
1971 // Dashing ignores inverse.
1972 dashInvAB.compare(r, dashAB, TestCase::kAllSame_ComparisonExpecation);
1973
1974 REPORTER_ASSERT(r, strokeInvAB.baseShape().asLine(pts, &inverted) && inverted &&
1975 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1976 REPORTER_ASSERT(r, hairlineInvAB.baseShape().asLine(pts, &inverted) && inverted &&
1977 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
1978 // Dashing ignores inverse.
1979 REPORTER_ASSERT(r, dashInvAB.baseShape().asLine(pts, &inverted) && !inverted &&
1980 pts[0] == kA && pts[1] == kB);
1981
1982}
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define ERRORF(r,...)
Definition: Test.h:293
static SkPath Line(const SkPoint a, const SkPoint b)
Definition: SkPath.h:106
const auto kC
const auto kB
const auto kA

◆ DEF_TEST() [6/7]

DEF_TEST ( GrStyledShape_short_path_keys  ,
 
)

Definition at line 2061 of file GrStyledShapeTest.cpp.

2061 {
2062 SkPaint paints[4];
2064 paints[1].setStrokeWidth(5.f);
2066 paints[2].setStrokeWidth(0.f);
2068 paints[3].setStrokeWidth(5.f);
2069
2070 auto compare = [r, &paints] (const SkPath& pathA, const SkPath& pathB,
2071 TestCase::ComparisonExpecation expectation) {
2072 SkPath volatileA = pathA;
2073 SkPath volatileB = pathB;
2074 volatileA.setIsVolatile(true);
2075 volatileB.setIsVolatile(true);
2076 for (const SkPaint& paint : paints) {
2077 REPORTER_ASSERT(r, !GrStyledShape(volatileA, paint).hasUnstyledKey());
2078 REPORTER_ASSERT(r, !GrStyledShape(volatileB, paint).hasUnstyledKey());
2079 for (PathGeo::Invert invert : {PathGeo::Invert::kNo, PathGeo::Invert::kYes}) {
2080 TestCase caseA(PathGeo(pathA, invert), paint, r);
2081 TestCase caseB(PathGeo(pathB, invert), paint, r);
2082 caseA.compare(r, caseB, expectation);
2083 }
2084 }
2085 };
2086
2087 SkPath pathA;
2088 SkPath pathB;
2089
2090 // Two identical paths
2091 pathA.lineTo(10.f, 10.f);
2092 pathA.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2093
2094 pathB.lineTo(10.f, 10.f);
2095 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2096 compare(pathA, pathB, TestCase::kAllSame_ComparisonExpecation);
2097
2098 // Give path b a different point
2099 pathB.reset();
2100 pathB.lineTo(10.f, 10.f);
2101 pathB.conicTo(21.f, 20.f, 20.f, 30.f, 0.7f);
2102 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2103
2104 // Give path b a different conic weight
2105 pathB.reset();
2106 pathB.lineTo(10.f, 10.f);
2107 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2108 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2109
2110 // Give path b an extra lineTo verb
2111 pathB.reset();
2112 pathB.lineTo(10.f, 10.f);
2113 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2114 pathB.lineTo(50.f, 50.f);
2115 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2116
2117 // Give path b a close
2118 pathB.reset();
2119 pathB.lineTo(10.f, 10.f);
2120 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2121 pathB.close();
2122 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2123}
@ 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:370
SkPath & conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
Definition: SkPath.cpp:766
const Paint & paint
Definition: color_source.cc:38
gboolean invert
int compare(const void *untyped_lhs, const void *untyped_rhs)
Definition: skdiff.h:161

◆ DEF_TEST() [7/7]

DEF_TEST ( GrStyledShape_stroked_lines  ,
 
)

Definition at line 1984 of file GrStyledShapeTest.cpp.

1984 {
1985 static constexpr SkScalar kIntervals1[] = {1.f, 0.f};
1986 auto dash1 = SkDashPathEffect::Make(kIntervals1, std::size(kIntervals1), 0.f);
1988 static constexpr SkScalar kIntervals2[] = {10.f, 0.f, 5.f, 0.f};
1989 auto dash2 = SkDashPathEffect::Make(kIntervals2, std::size(kIntervals2), 10.f);
1991
1992 sk_sp<SkPathEffect> pathEffects[] = {nullptr, std::move(dash1), std::move(dash2)};
1993
1994 for (const auto& pe : pathEffects) {
1995 // Paints to try
1996 SkPaint buttCap;
1998 buttCap.setStrokeWidth(4);
2000 buttCap.setPathEffect(pe);
2001
2002 SkPaint squareCap = buttCap;
2004 squareCap.setPathEffect(pe);
2005
2006 SkPaint roundCap = buttCap;
2008 roundCap.setPathEffect(pe);
2009
2010 // vertical
2011 SkPath linePath;
2012 linePath.moveTo(4, 4);
2013 linePath.lineTo(4, 5);
2014
2015 SkPaint fill;
2016
2017 make_TestCase(r, linePath, buttCap)->compare(
2018 r, TestCase(r, SkRect::MakeLTRB(2, 4, 6, 5), fill),
2019 TestCase::kAllSame_ComparisonExpecation);
2020
2021 make_TestCase(r, linePath, squareCap)->compare(
2022 r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 7), fill),
2023 TestCase::kAllSame_ComparisonExpecation);
2024
2025 make_TestCase(r, linePath, roundCap)->compare(r,
2026 TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 7), 2, 2), fill),
2027 TestCase::kAllSame_ComparisonExpecation);
2028
2029 // horizontal
2030 linePath.reset();
2031 linePath.moveTo(4, 4);
2032 linePath.lineTo(5, 4);
2033
2034 make_TestCase(r, linePath, buttCap)->compare(
2035 r, TestCase(r, SkRect::MakeLTRB(4, 2, 5, 6), fill),
2036 TestCase::kAllSame_ComparisonExpecation);
2037 make_TestCase(r, linePath, squareCap)->compare(
2038 r, TestCase(r, SkRect::MakeLTRB(2, 2, 7, 6), fill),
2039 TestCase::kAllSame_ComparisonExpecation);
2040 make_TestCase(r, linePath, roundCap)->compare(
2041 r, TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 7, 6), 2, 2), fill),
2042 TestCase::kAllSame_ComparisonExpecation);
2043
2044 // point
2045 linePath.reset();
2046 linePath.moveTo(4, 4);
2047 linePath.lineTo(4, 4);
2048
2049 make_TestCase(r, linePath, buttCap)->compare(
2050 r, TestCase(r, SkRect::MakeEmpty(), fill),
2051 TestCase::kAllSame_ComparisonExpecation);
2052 make_TestCase(r, linePath, squareCap)->compare(
2053 r, TestCase(r, SkRect::MakeLTRB(2, 2, 6, 6), fill),
2054 TestCase::kAllSame_ComparisonExpecation);
2055 make_TestCase(r, linePath, roundCap)->compare(
2056 r, TestCase(r, SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 6), 2, 2), fill),
2057 TestCase::kAllSame_ComparisonExpecation);
2058 }
2059}
static std::unique_ptr< TestCase > make_TestCase(Args &&... args)
void setStrokeCap(Cap cap)
Definition: SkPaint.cpp:179
int dash2[]
Definition: dashcircle.cpp:25
int dash1[]
Definition: dashcircle.cpp:24
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 775 of file GrStyledShapeTest.cpp.

775 {
776 static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f };
777 static const SkScalar kPhase = 0.75;
778 return SkDashPathEffect::Make(kIntervals, std::size(kIntervals), kPhase);
779}

◆ make_key()

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

Definition at line 67 of file GrStyledShapeTest.cpp.

67 {
68 int size = shape.unstyledKeySize();
69 if (size <= 0) {
70 key->reset(0);
71 return false;
72 }
74 key->reset(size);
75 shape.writeUnstyledKey(key->begin());
76 return true;
77}
#define SkASSERT(cond)
Definition: SkAssert.h:116
void writeUnstyledKey(uint32_t *key) const
int unstyledKeySize() const

◆ make_null_dash()

static sk_sp< SkPathEffect > make_null_dash ( )
static

Definition at line 781 of file GrStyledShapeTest.cpp.

781 {
782 static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0};
783 return SkDashPathEffect::Make(kNullIntervals, std::size(kNullIntervals), 0.f);
784}

◆ make_TestCase()

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

Definition at line 789 of file GrStyledShapeTest.cpp.

789 {
790 return std::make_unique<TestCase>( std::forward<Args>(args)... );
791}
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 79 of file GrStyledShapeTest.cpp.

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

◆ shape_known_not_to_have_joins()

static bool shape_known_not_to_have_joins ( const GrStyledShape shape)
static

Definition at line 1060 of file GrStyledShapeTest.cpp.

1060 {
1061 return shape.asLine(nullptr, nullptr) || shape.isEmpty();
1062}
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 793 of file GrStyledShapeTest.cpp.

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

85 {
86 // We test the bounds by rasterizing the path into a kRes by kRes grid. The bounds is
87 // mapped to the range kRes/4 to 3*kRes/4 in x and y. A difference clip is used to avoid
88 // rendering within the bounds (with a tolerance). Then we render the path and check that
89 // everything got clipped out.
90 static constexpr int kRes = 2000;
91 // This tolerance is in units of 1/kRes fractions of the bounds width/height.
92 static constexpr int kTol = 2;
93 static_assert(kRes % 4 == 0);
96 surface->getCanvas()->clear(0x0);
97 SkRect clip = SkRect::MakeXYWH(kRes/4, kRes/4, kRes/2, kRes/2);
99 clip.outset(SkIntToScalar(kTol), SkIntToScalar(kTol));
100 surface->getCanvas()->clipRect(clip, SkClipOp::kDifference);
101 surface->getCanvas()->concat(matrix);
102 SkPaint whitePaint;
103 whitePaint.setColor(SK_ColorWHITE);
104 surface->getCanvas()->drawPath(path, whitePaint);
105 SkPixmap pixmap;
106 surface->getCanvas()->peekPixels(&pixmap);
107#if defined(SK_BUILD_FOR_WIN)
108 // The static constexpr version in #else causes cl.exe to crash.
109 const uint8_t* kZeros = reinterpret_cast<uint8_t*>(calloc(kRes, 1));
110#else
111 static constexpr uint8_t kZeros[kRes] = {0};
112#endif
113 for (int y = 0; y < kRes; ++y) {
114 const uint8_t* row = pixmap.addr8(0, y);
115 if (0 != memcmp(kZeros, row, kRes)) {
116 return false;
117 }
118 }
119#ifdef SK_BUILD_FOR_WIN
120 free(const_cast<uint8_t*>(kZeros));
121#endif
122 return true;
123}
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:3892
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
Optional< SkRect > bounds
Definition: SkRecords.h:189
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 1120 of file GrStyledShapeTest.cpp.

1120 {
1121 // A dash with no stroke should have no effect
1122 using DashFactoryFn = sk_sp<SkPathEffect>(*)();
1123 for (DashFactoryFn md : {&make_dash, &make_null_dash}) {
1124 SkPaint dashFill;
1125 dashFill.setPathEffect((*md)());
1126 TestCase dashFillCase(geo, dashFill, reporter);
1127
1128 TestCase fillCase(geo, SkPaint(), reporter);
1129 dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
1130 }
1131}
static sk_sp< SkPathEffect > make_null_dash()

◆ test_inversions()

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

Definition at line 303 of file GrStyledShapeTest.cpp.

303 {
306 Key preserveKey;
307 make_key(&preserveKey, preserve);
308
310 Key flipKey;
311 make_key(&flipKey, flip);
312
315 Key invertedKey;
316 make_key(&invertedKey, inverted);
317
320 Key noninvertedKey;
321 make_key(&noninvertedKey, noninverted);
322
323 if (invertedKey.size() || noninvertedKey.size()) {
324 REPORTER_ASSERT(r, invertedKey != noninvertedKey);
325 }
326 if (shape.style().isSimpleFill()) {
327 check_equivalence(r, shape, preserve, shapeKey, preserveKey);
328 }
329 if (shape.inverseFilled()) {
330 check_equivalence(r, preserve, inverted, preserveKey, invertedKey);
331 check_equivalence(r, flip, noninverted, flipKey, noninvertedKey);
332 } else {
333 check_equivalence(r, preserve, noninverted, preserveKey, noninvertedKey);
334 check_equivalence(r, flip, inverted, flipKey, invertedKey);
335 }
336
338 Key doubleFlipKey;
339 make_key(&doubleFlipKey, doubleFlip);
340 // It can be the case that the double flip has no key but preserve does. This happens when the
341 // original shape has an inherited style key. That gets dropped on the first inversion flip.
342 if (preserveKey.size() && !doubleFlipKey.size()) {
343 preserveKey.clear();
344 }
345 check_equivalence(r, preserve, doubleFlip, preserveKey, doubleFlipKey);
346}
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 1302 of file GrStyledShapeTest.cpp.

1302 {
1303 /**
1304 * This path effect just changes the stroke rec to hairline.
1305 */
1306 class MakeHairlinePathEffect : SkPathEffectBase {
1307 public:
1308 static sk_sp<SkPathEffect> Make() {
1309 return sk_sp<SkPathEffect>(new MakeHairlinePathEffect);
1310 }
1311 Factory getFactory() const override { return nullptr; }
1312 const char* getTypeName() const override { return nullptr; }
1313
1314 protected:
1315 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* strokeRec,
1316 const SkRect* cullR, const SkMatrix&) const override {
1317 *dst = src;
1318 strokeRec->setHairlineStyle();
1319 return true;
1320 }
1321 private:
1322 bool computeFastBounds(SkRect* bounds) const override { return true; }
1323
1324 MakeHairlinePathEffect() {}
1325 };
1326
1327 SkPaint fill;
1328 SkPaint pe;
1330
1331 TestCase peCase(geo, pe, reporter);
1332
1333 SkPath a, b, c;
1334 peCase.baseShape().asPath(&a);
1335 peCase.appliedPathEffectShape().asPath(&b);
1336 peCase.appliedFullStyleShape().asPath(&c);
1337 if (geo.isNonPath(pe)) {
1338 // RRect types can have a change in start index or direction after the PE is applied. This
1339 // is because once the PE is applied, GrStyledShape may canonicalize the dir and index since
1340 // it is not germane to the styling any longer.
1341 // Instead we just check that the paths would fill the same both before and after styling.
1344 } else {
1345 // The base shape cannot perform canonicalization on the path's fill type because of an
1346 // unknown path effect. However, after the path effect is applied the resulting hairline
1347 // shape will canonicalize the path fill type since hairlines (and stroking in general)
1348 // don't distinguish between even/odd and non-zero winding.
1349 a.setFillType(b.getFillType());
1351 REPORTER_ASSERT(reporter, a == c);
1352 // If the resulting path is small enough then it will have a key.
1355 REPORTER_ASSERT(reporter, peCase.appliedPathEffectKey().empty());
1356 REPORTER_ASSERT(reporter, peCase.appliedFullStyleKey().empty());
1357 }
1358 REPORTER_ASSERT(reporter, peCase.appliedPathEffectShape().style().isSimpleHairline());
1359 REPORTER_ASSERT(reporter, peCase.appliedFullStyleShape().style().isSimpleHairline());
1360}
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()
Definition: SkStrokeRec.cpp:86
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
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 1082 of file GrStyledShapeTest.cpp.

1082 {
1083 auto setMiterJoinAndLimit = [](SkPaint* p, SkScalar miter) {
1084 p->setStrokeJoin(SkPaint::kMiter_Join);
1085 p->setStrokeMiter(miter);
1086 };
1087
1088 auto setOtherJoinAndLimit = [](SkPaint* p, SkScalar miter) {
1089 p->setStrokeJoin(SkPaint::kRound_Join);
1090 p->setStrokeMiter(miter);
1091 };
1092
1093 SkPaint hairline;
1094 hairline.setStrokeWidth(0);
1096 GrStyledShape shape = geo.makeShape(hairline);
1097 bool mayHaveJoins = !shape_known_not_to_have_joins(shape);
1098
1099 // The miter limit should affect stroked and dashed-stroked cases when the join type is
1100 // miter.
1101 test_stroke_param_impl<SkScalar>(
1102 reporter,
1103 geo,
1104 setMiterJoinAndLimit,
1105 0.5f, 0.75f,
1106 mayHaveJoins,
1107 true);
1108
1109 // The miter limit should not affect stroked and dashed-stroked cases when the join type is
1110 // not miter.
1111 test_stroke_param_impl<SkScalar>(
1112 reporter,
1113 geo,
1114 setOtherJoinAndLimit,
1115 0.5f, 0.75f,
1116 false,
1117 false);
1118}
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 1133 of file GrStyledShapeTest.cpp.

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

◆ 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 1478 of file GrStyledShapeTest.cpp.

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

◆ 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 1387 of file GrStyledShapeTest.cpp.

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

◆ 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 1169 of file GrStyledShapeTest.cpp.

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

◆ test_rrect()

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

Definition at line 1659 of file GrStyledShapeTest.cpp.

1659 {
1660 enum Style {
1661 kFill,
1662 kStroke,
1663 kHairline,
1665 };
1666
1667 // SkStrokeRec has no default cons., so init with kFill before calling the setters below.
1670 strokeRecs[kFill].setFillStyle();
1671 strokeRecs[kStroke].setStrokeStyle(2.f);
1672 strokeRecs[kHairline].setHairlineStyle();
1673 strokeRecs[kStrokeAndFill].setStrokeStyle(3.f, true);
1674 // Use a bevel join to avoid complications of stroke+filled rects becoming filled rects before
1675 // applyStyle() is called.
1676 strokeRecs[kStrokeAndFill].setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 1.f);
1677 sk_sp<SkPathEffect> dashEffect = make_dash();
1678
1679 static constexpr size_t kStyleCnt = std::size(strokeRecs);
1680
1681 auto index = [](bool inverted,
1683 unsigned start,
1684 Style style,
1685 bool dash) -> int {
1686 return inverted * (2 * 8 * kStyleCnt * 2) +
1687 (int)dir * ( 8 * kStyleCnt * 2) +
1688 start * ( kStyleCnt * 2) +
1689 style * ( 2) +
1690 dash;
1691 };
1692 static const SkPathDirection kSecondDirection = static_cast<SkPathDirection>(1);
1693 const int cnt = index(true, kSecondDirection, 7, static_cast<Style>(kStyleCnt - 1), true) + 1;
1694 AutoTArray<GrStyledShape> shapes(cnt);
1695 for (bool inverted : {false, true}) {
1697 for (unsigned start = 0; start < 8; ++start) {
1698 for (Style style : {kFill, kStroke, kHairline, kStrokeAndFill}) {
1699 for (bool dash : {false, true}) {
1700 sk_sp<SkPathEffect> pe = dash ? dashEffect : nullptr;
1701 shapes[index(inverted, dir, start, style, dash)] =
1702 GrStyledShape(rrect, dir, start, SkToBool(inverted),
1703 GrStyle(strokeRecs[style], std::move(pe)));
1704 }
1705 }
1706 }
1707 }
1708 }
1709
1710 // Get the keys for some example shape instances that we'll use for comparision against the
1711 // rest.
1712 static constexpr SkPathDirection kExamplesDir = SkPathDirection::kCW;
1713 static constexpr unsigned kExamplesStart = 0;
1714 const GrStyledShape& exampleFillCase = shapes[index(false, kExamplesDir, kExamplesStart, kFill,
1715 false)];
1716 Key exampleFillCaseKey;
1717 make_key(&exampleFillCaseKey, exampleFillCase);
1718
1719 const GrStyledShape& exampleStrokeAndFillCase = shapes[index(false, kExamplesDir,
1720 kExamplesStart, kStrokeAndFill, false)];
1721 Key exampleStrokeAndFillCaseKey;
1722 make_key(&exampleStrokeAndFillCaseKey, exampleStrokeAndFillCase);
1723
1724 const GrStyledShape& exampleInvFillCase = shapes[index(true, kExamplesDir,
1725 kExamplesStart, kFill, false)];
1726 Key exampleInvFillCaseKey;
1727 make_key(&exampleInvFillCaseKey, exampleInvFillCase);
1728
1729 const GrStyledShape& exampleInvStrokeAndFillCase = shapes[index(true, kExamplesDir,
1730 kExamplesStart, kStrokeAndFill,
1731 false)];
1732 Key exampleInvStrokeAndFillCaseKey;
1733 make_key(&exampleInvStrokeAndFillCaseKey, exampleInvStrokeAndFillCase);
1734
1735 const GrStyledShape& exampleStrokeCase = shapes[index(false, kExamplesDir, kExamplesStart,
1736 kStroke, false)];
1737 Key exampleStrokeCaseKey;
1738 make_key(&exampleStrokeCaseKey, exampleStrokeCase);
1739
1740 const GrStyledShape& exampleInvStrokeCase = shapes[index(true, kExamplesDir, kExamplesStart,
1741 kStroke, false)];
1742 Key exampleInvStrokeCaseKey;
1743 make_key(&exampleInvStrokeCaseKey, exampleInvStrokeCase);
1744
1745 const GrStyledShape& exampleHairlineCase = shapes[index(false, kExamplesDir, kExamplesStart,
1746 kHairline, false)];
1747 Key exampleHairlineCaseKey;
1748 make_key(&exampleHairlineCaseKey, exampleHairlineCase);
1749
1750 const GrStyledShape& exampleInvHairlineCase = shapes[index(true, kExamplesDir, kExamplesStart,
1751 kHairline, false)];
1752 Key exampleInvHairlineCaseKey;
1753 make_key(&exampleInvHairlineCaseKey, exampleInvHairlineCase);
1754
1755 // These initializations suppress warnings.
1756 SkRRect queryRR = SkRRect::MakeEmpty();
1757 bool queryInverted = true;
1758
1759 REPORTER_ASSERT(r, exampleFillCase.asRRect(&queryRR, &queryInverted));
1760 REPORTER_ASSERT(r, queryRR == rrect);
1761 REPORTER_ASSERT(r, !queryInverted);
1762
1763 REPORTER_ASSERT(r, exampleInvFillCase.asRRect(&queryRR, &queryInverted));
1764 REPORTER_ASSERT(r, queryRR == rrect);
1765 REPORTER_ASSERT(r, queryInverted);
1766
1767 REPORTER_ASSERT(r, exampleStrokeAndFillCase.asRRect(&queryRR, &queryInverted));
1768 REPORTER_ASSERT(r, queryRR == rrect);
1769 REPORTER_ASSERT(r, !queryInverted);
1770
1771 REPORTER_ASSERT(r, exampleInvStrokeAndFillCase.asRRect(&queryRR, &queryInverted));
1772 REPORTER_ASSERT(r, queryRR == rrect);
1773 REPORTER_ASSERT(r, queryInverted);
1774
1775 REPORTER_ASSERT(r, exampleHairlineCase.asRRect(&queryRR, &queryInverted));
1776 REPORTER_ASSERT(r, queryRR == rrect);
1777 REPORTER_ASSERT(r, !queryInverted);
1778
1779 REPORTER_ASSERT(r, exampleInvHairlineCase.asRRect(&queryRR, &queryInverted));
1780 REPORTER_ASSERT(r, queryRR == rrect);
1781 REPORTER_ASSERT(r, queryInverted);
1782
1783 REPORTER_ASSERT(r, exampleStrokeCase.asRRect(&queryRR, &queryInverted));
1784 REPORTER_ASSERT(r, queryRR == rrect);
1785 REPORTER_ASSERT(r, !queryInverted);
1786
1787 REPORTER_ASSERT(r, exampleInvStrokeCase.asRRect(&queryRR, &queryInverted));
1788 REPORTER_ASSERT(r, queryRR == rrect);
1789 REPORTER_ASSERT(r, queryInverted);
1790
1791 // Remember that the key reflects the geometry before styling is applied.
1792 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvFillCaseKey);
1793 REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeAndFillCaseKey);
1794 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeAndFillCaseKey);
1795 REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeCaseKey);
1796 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeCaseKey);
1797 REPORTER_ASSERT(r, exampleFillCaseKey == exampleHairlineCaseKey);
1798 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvHairlineCaseKey);
1799 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvFillCaseKey);
1800 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvStrokeCaseKey);
1801 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvHairlineCaseKey);
1802
1803 for (bool inverted : {false, true}) {
1805 for (unsigned start = 0; start < 8; ++start) {
1806 for (bool dash : {false, true}) {
1807 const GrStyledShape& fillCase = shapes[index(inverted, dir, start, kFill,
1808 dash)];
1809 Key fillCaseKey;
1810 make_key(&fillCaseKey, fillCase);
1811
1812 const GrStyledShape& strokeAndFillCase = shapes[index(inverted, dir, start,
1813 kStrokeAndFill, dash)];
1814 Key strokeAndFillCaseKey;
1815 make_key(&strokeAndFillCaseKey, strokeAndFillCase);
1816
1817 // Both fill and stroke-and-fill shapes must respect the inverseness and both
1818 // ignore dashing.
1819 REPORTER_ASSERT(r, !fillCase.style().pathEffect());
1820 REPORTER_ASSERT(r, !strokeAndFillCase.style().pathEffect());
1821 TestCase a(fillCase, r);
1822 TestCase b(inverted ? exampleInvFillCase : exampleFillCase, r);
1823 TestCase c(strokeAndFillCase, r);
1824 TestCase d(inverted ? exampleInvStrokeAndFillCase
1825 : exampleStrokeAndFillCase, r);
1826 a.compare(r, b, TestCase::kAllSame_ComparisonExpecation);
1827 c.compare(r, d, TestCase::kAllSame_ComparisonExpecation);
1828
1829 const GrStyledShape& strokeCase = shapes[index(inverted, dir, start, kStroke,
1830 dash)];
1831 const GrStyledShape& hairlineCase = shapes[index(inverted, dir, start,
1832 kHairline, dash)];
1833
1834 TestCase e(strokeCase, r);
1835 TestCase g(hairlineCase, r);
1836
1837 // Both hairline and stroke shapes must respect the dashing.
1838 if (dash) {
1839 // Dashing always ignores the inverseness. skbug.com/5421
1840 TestCase f(exampleStrokeCase, r);
1841 TestCase h(exampleHairlineCase, r);
1842 unsigned expectedStart = canonicalize_rrect_start(start, rrect);
1843 REPORTER_ASSERT(r, strokeCase.style().pathEffect());
1844 REPORTER_ASSERT(r, hairlineCase.style().pathEffect());
1845
1846 REPORTER_ASSERT(r, strokeCase.asRRect(&queryRR, &queryInverted));
1847 REPORTER_ASSERT(r, queryRR == rrect);
1848 REPORTER_ASSERT(r, !queryInverted);
1849 REPORTER_ASSERT(r, hairlineCase.asRRect(&queryRR, &queryInverted));
1850 REPORTER_ASSERT(r, queryRR == rrect);
1851 REPORTER_ASSERT(r, !queryInverted);
1852
1853 // The pre-style case for the dash will match the non-dash example iff the
1854 // dir and start match (dir=cw, start=0).
1855 if (0 == expectedStart && SkPathDirection::kCW == dir) {
1856 e.compare(r, f, TestCase::kSameUpToPE_ComparisonExpecation);
1857 g.compare(r, h, TestCase::kSameUpToPE_ComparisonExpecation);
1858 } else {
1859 e.compare(r, f, TestCase::kAllDifferent_ComparisonExpecation);
1860 g.compare(r, h, TestCase::kAllDifferent_ComparisonExpecation);
1861 }
1862 } else {
1863 TestCase f(inverted ? exampleInvStrokeCase : exampleStrokeCase, r);
1864 TestCase h(inverted ? exampleInvHairlineCase : exampleHairlineCase, r);
1865 REPORTER_ASSERT(r, !strokeCase.style().pathEffect());
1866 REPORTER_ASSERT(r, !hairlineCase.style().pathEffect());
1867 e.compare(r, f, TestCase::kAllSame_ComparisonExpecation);
1868 g.compare(r, h, TestCase::kAllSame_ComparisonExpecation);
1869 }
1870 }
1871 }
1872 }
1873 }
1874}
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, bool *inverted) const
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
@ kStrokeAndFill
both strokes and fills shapes
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of 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 890 of file GrStyledShapeTest.cpp.

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

◆ test_stroke_cap()

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

Definition at line 1042 of file GrStyledShapeTest.cpp.

1042 {
1043 SkPaint hairline;
1044 hairline.setStrokeWidth(0);
1046 GrStyledShape shape = geo.makeShape(hairline);
1047 // The cap should only affect shapes that may be open.
1048 bool affectsStroke = !shape.knownToBeClosed();
1049 // Dashing adds ends that need caps.
1050 bool affectsDashAndStroke = true;
1051 test_stroke_param_impl<SkPaint::Cap>(
1052 reporter,
1053 geo,
1054 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);},
1056 affectsStroke,
1057 affectsDashAndStroke);
1058}
bool knownToBeClosed() const

◆ test_stroke_join()

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

Definition at line 1064 of file GrStyledShapeTest.cpp.

1064 {
1065 SkPaint hairline;
1066 hairline.setStrokeWidth(0);
1068 GrStyledShape shape = geo.makeShape(hairline);
1069 // GrStyledShape recognizes certain types don't have joins and will prevent the join type from
1070 // affecting the style key.
1071 // Dashing doesn't add additional joins. However, GrStyledShape currently loses track of this
1072 // after applying the dash.
1073 bool affectsStroke = !shape_known_not_to_have_joins(shape);
1074 test_stroke_param_impl<SkPaint::Join>(
1075 reporter,
1076 geo,
1077 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
1079 affectsStroke, true);
1080}

◆ 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 1037 of file GrStyledShapeTest.cpp.

1038 {
1039 test_stroke_param_impl(reporter, geo, setter, a, b, true, true);
1040}
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 961 of file GrStyledShapeTest.cpp.

964 {
965 // Set the stroke width so that we don't get hairline. However, call the setter afterward so
966 // that it can override the stroke width.
967 SkPaint strokeA;
969 strokeA.setStrokeWidth(2.f);
970 setter(&strokeA, a);
971 SkPaint strokeB;
973 strokeB.setStrokeWidth(2.f);
974 setter(&strokeB, b);
975
976 TestCase strokeACase(geo, strokeA, reporter);
977 TestCase strokeBCase(geo, strokeB, reporter);
978 if (paramAffectsStroke) {
979 // If stroking is immediately incorporated into a geometric transformation then the base
980 // shapes will differ.
981 if (geo.strokeIsConvertedToFill()) {
982 strokeACase.compare(reporter, strokeBCase,
983 TestCase::kAllDifferent_ComparisonExpecation);
984 } else {
985 strokeACase.compare(reporter, strokeBCase,
986 TestCase::kSameUpToStroke_ComparisonExpecation);
987 }
988 } else {
989 strokeACase.compare(reporter, strokeBCase, TestCase::kAllSame_ComparisonExpecation);
990 }
991
992 SkPaint strokeAndFillA = strokeA;
993 SkPaint strokeAndFillB = strokeB;
996 TestCase strokeAndFillACase(geo, strokeAndFillA, reporter);
997 TestCase strokeAndFillBCase(geo, strokeAndFillB, reporter);
998 if (paramAffectsStroke) {
999 // If stroking is immediately incorporated into a geometric transformation then the base
1000 // shapes will differ.
1001 if (geo.strokeAndFillIsConvertedToFill(strokeAndFillA) ||
1002 geo.strokeAndFillIsConvertedToFill(strokeAndFillB)) {
1003 strokeAndFillACase.compare(reporter, strokeAndFillBCase,
1004 TestCase::kAllDifferent_ComparisonExpecation);
1005 } else {
1006 strokeAndFillACase.compare(reporter, strokeAndFillBCase,
1007 TestCase::kSameUpToStroke_ComparisonExpecation);
1008 }
1009 } else {
1010 strokeAndFillACase.compare(reporter, strokeAndFillBCase,
1011 TestCase::kAllSame_ComparisonExpecation);
1012 }
1013
1014 // Make sure stroking params don't affect fill style.
1015 SkPaint fillA = strokeA, fillB = strokeB;
1017 fillB.setStyle(SkPaint::kFill_Style);
1018 TestCase fillACase(geo, fillA, reporter);
1019 TestCase fillBCase(geo, fillB, reporter);
1020 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecation);
1021
1022 // Make sure just applying the dash but not stroke gives the same key for both stroking
1023 // variations.
1024 SkPaint dashA = strokeA, dashB = strokeB;
1025 dashA.setPathEffect(make_dash());
1026 dashB.setPathEffect(make_dash());
1027 TestCase dashACase(geo, dashA, reporter);
1028 TestCase dashBCase(geo, dashB, reporter);
1029 if (paramAffectsDashAndStroke) {
1030 dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1031 } else {
1032 dashACase.compare(reporter, dashBCase, TestCase::kAllSame_ComparisonExpecation);
1033 }
1034}
@ 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 1256 of file GrStyledShapeTest.cpp.

1256 {
1257 /**
1258 * This path effect just adds two lineTos to the input path.
1259 */
1260 class AddLineTosPathEffect : SkPathEffectBase {
1261 public:
1262 static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new AddLineTosPathEffect); }
1263 Factory getFactory() const override { return nullptr; }
1264 const char* getTypeName() const override { return nullptr; }
1265
1266 protected:
1267 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*,
1268 const SkRect* cullR, const SkMatrix&) const override {
1269 *dst = src;
1270 // To avoid triggering data-based keying of paths with few verbs we add many segments.
1271 for (int i = 0; i < 100; ++i) {
1272 dst->lineTo(SkIntToScalar(i), SkIntToScalar(i));
1273 }
1274 return true;
1275 }
1276 bool computeFastBounds(SkRect* bounds) const override {
1277 if (bounds) {
1279 SkRectPriv::GrowToInclude(bounds, {100, 100});
1280 }
1281 return true;
1282 }
1283 private:
1284 AddLineTosPathEffect() {}
1285 };
1286
1287 // This path effect should make the keys invalid when it is applied. We only produce a path
1288 // effect key for dash path effects. So the only way another arbitrary path effect can produce
1289 // a styled result with a key is to produce a non-path shape that has a purely geometric key.
1290 SkPaint peStroke;
1292 peStroke.setStrokeWidth(2.f);
1294 TestCase geoPEStrokeCase(geo, peStroke, reporter);
1295 TestCase::SelfExpectations expectations;
1296 expectations.fPEHasEffect = true;
1297 expectations.fPEHasValidKey = false;
1298 expectations.fStrokeApplies = true;
1299 geoPEStrokeCase.testExpectations(reporter, expectations);
1300}
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 1362 of file GrStyledShapeTest.cpp.

1362 {
1363 SkPath vPath = geo.path();
1364 vPath.setIsVolatile(true);
1365
1366 SkPaint dashAndStroke;
1367 dashAndStroke.setPathEffect(make_dash());
1368 dashAndStroke.setStrokeWidth(2.f);
1369 dashAndStroke.setStyle(SkPaint::kStroke_Style);
1370 TestCase volatileCase(reporter, vPath, dashAndStroke);
1371 // We expect a shape made from a volatile path to have a key iff the shape is recognized
1372 // as a specialized geometry.
1373 if (geo.isNonPath(dashAndStroke)) {
1374 REPORTER_ASSERT(reporter, SkToBool(volatileCase.baseKey().size()));
1375 // In this case all the keys should be identical to the non-volatile case.
1376 TestCase nonVolatileCase(reporter, geo.path(), dashAndStroke);
1377 volatileCase.compare(reporter, nonVolatileCase, TestCase::kAllSame_ComparisonExpecation);
1378 } else {
1379 // None of the keys should be valid.
1380 REPORTER_ASSERT(reporter, SkToBool(volatileCase.baseKey().empty()));
1381 REPORTER_ASSERT(reporter, SkToBool(volatileCase.appliedPathEffectKey().empty()));
1382 REPORTER_ASSERT(reporter, SkToBool(volatileCase.appliedFullStyleKey().empty()));
1383 REPORTER_ASSERT(reporter, SkToBool(volatileCase.appliedPathEffectThenStrokeKey().empty()));
1384 }
1385}