GrShapeTest.cpp 103 KB

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