GrShape.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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 "src/gpu/geometry/GrShape.h"
  8. #include <utility>
  9. GrShape& GrShape::operator=(const GrShape& that) {
  10. fStyle = that.fStyle;
  11. this->changeType(that.fType, Type::kPath == that.fType ? &that.path() : nullptr);
  12. switch (fType) {
  13. case Type::kEmpty:
  14. break;
  15. case Type::kInvertedEmpty:
  16. break;
  17. case Type::kRRect:
  18. fRRectData = that.fRRectData;
  19. break;
  20. case Type::kArc:
  21. fArcData = that.fArcData;
  22. break;
  23. case Type::kLine:
  24. fLineData = that.fLineData;
  25. break;
  26. case Type::kPath:
  27. fPathData.fGenID = that.fPathData.fGenID;
  28. break;
  29. }
  30. fInheritedKey.reset(that.fInheritedKey.count());
  31. sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
  32. sizeof(uint32_t) * fInheritedKey.count());
  33. if (that.fInheritedPathForListeners.isValid()) {
  34. fInheritedPathForListeners.set(*that.fInheritedPathForListeners.get());
  35. } else {
  36. fInheritedPathForListeners.reset();
  37. }
  38. return *this;
  39. }
  40. static bool flip_inversion(bool originalIsInverted, GrShape::FillInversion inversion) {
  41. switch (inversion) {
  42. case GrShape::FillInversion::kPreserve:
  43. return false;
  44. case GrShape::FillInversion::kFlip:
  45. return true;
  46. case GrShape::FillInversion::kForceInverted:
  47. return !originalIsInverted;
  48. case GrShape::FillInversion::kForceNoninverted:
  49. return originalIsInverted;
  50. }
  51. return false;
  52. }
  53. static bool is_inverted(bool originalIsInverted, GrShape::FillInversion inversion) {
  54. switch (inversion) {
  55. case GrShape::FillInversion::kPreserve:
  56. return originalIsInverted;
  57. case GrShape::FillInversion::kFlip:
  58. return !originalIsInverted;
  59. case GrShape::FillInversion::kForceInverted:
  60. return true;
  61. case GrShape::FillInversion::kForceNoninverted:
  62. return false;
  63. }
  64. return false;
  65. }
  66. GrShape GrShape::MakeFilled(const GrShape& original, FillInversion inversion) {
  67. if (original.style().isSimpleFill() && !flip_inversion(original.inverseFilled(), inversion)) {
  68. // By returning the original rather than falling through we can preserve any inherited style
  69. // key. Otherwise, we wipe it out below since the style change invalidates it.
  70. return original;
  71. }
  72. GrShape result;
  73. if (original.fInheritedPathForListeners.isValid()) {
  74. result.fInheritedPathForListeners.set(*original.fInheritedPathForListeners.get());
  75. }
  76. switch (original.fType) {
  77. case Type::kRRect:
  78. result.fType = original.fType;
  79. result.fRRectData.fRRect = original.fRRectData.fRRect;
  80. result.fRRectData.fDir = kDefaultRRectDir;
  81. result.fRRectData.fStart = kDefaultRRectStart;
  82. result.fRRectData.fInverted = is_inverted(original.fRRectData.fInverted, inversion);
  83. break;
  84. case Type::kArc:
  85. result.fType = original.fType;
  86. result.fArcData.fOval = original.fArcData.fOval;
  87. result.fArcData.fStartAngleDegrees = original.fArcData.fStartAngleDegrees;
  88. result.fArcData.fSweepAngleDegrees = original.fArcData.fSweepAngleDegrees;
  89. result.fArcData.fUseCenter = original.fArcData.fUseCenter;
  90. result.fArcData.fInverted = is_inverted(original.fArcData.fInverted, inversion);
  91. break;
  92. case Type::kLine:
  93. // Lines don't fill.
  94. if (is_inverted(original.fLineData.fInverted, inversion)) {
  95. result.fType = Type::kInvertedEmpty;
  96. } else {
  97. result.fType = Type::kEmpty;
  98. }
  99. break;
  100. case Type::kEmpty:
  101. result.fType = is_inverted(false, inversion) ? Type::kInvertedEmpty : Type::kEmpty;
  102. break;
  103. case Type::kInvertedEmpty:
  104. result.fType = is_inverted(true, inversion) ? Type::kInvertedEmpty : Type::kEmpty;
  105. break;
  106. case Type::kPath:
  107. result.initType(Type::kPath, &original.fPathData.fPath);
  108. result.fPathData.fGenID = original.fPathData.fGenID;
  109. if (flip_inversion(original.fPathData.fPath.isInverseFillType(), inversion)) {
  110. result.fPathData.fPath.toggleInverseFillType();
  111. }
  112. if (!original.style().isSimpleFill()) {
  113. // Going from a non-filled style to fill may allow additional simplifications (e.g.
  114. // closing an open rect that wasn't closed in the original shape because it had
  115. // stroke style).
  116. result.attemptToSimplifyPath();
  117. }
  118. break;
  119. }
  120. // We don't copy the inherited key since it can contain path effect information that we just
  121. // stripped.
  122. return result;
  123. }
  124. SkRect GrShape::bounds() const {
  125. // Bounds where left == bottom or top == right can indicate a line or point shape. We return
  126. // inverted bounds for a truly empty shape.
  127. static constexpr SkRect kInverted = SkRect::MakeLTRB(1, 1, -1, -1);
  128. switch (fType) {
  129. case Type::kEmpty:
  130. return kInverted;
  131. case Type::kInvertedEmpty:
  132. return kInverted;
  133. case Type::kLine: {
  134. SkRect bounds;
  135. if (fLineData.fPts[0].fX < fLineData.fPts[1].fX) {
  136. bounds.fLeft = fLineData.fPts[0].fX;
  137. bounds.fRight = fLineData.fPts[1].fX;
  138. } else {
  139. bounds.fLeft = fLineData.fPts[1].fX;
  140. bounds.fRight = fLineData.fPts[0].fX;
  141. }
  142. if (fLineData.fPts[0].fY < fLineData.fPts[1].fY) {
  143. bounds.fTop = fLineData.fPts[0].fY;
  144. bounds.fBottom = fLineData.fPts[1].fY;
  145. } else {
  146. bounds.fTop = fLineData.fPts[1].fY;
  147. bounds.fBottom = fLineData.fPts[0].fY;
  148. }
  149. return bounds;
  150. }
  151. case Type::kRRect:
  152. return fRRectData.fRRect.getBounds();
  153. case Type::kArc:
  154. // Could make this less conservative by looking at angles.
  155. return fArcData.fOval;
  156. case Type::kPath:
  157. return this->path().getBounds();
  158. }
  159. SK_ABORT("Unknown shape type");
  160. return kInverted;
  161. }
  162. SkRect GrShape::styledBounds() const {
  163. if (this->isEmpty() && !fStyle.hasNonDashPathEffect()) {
  164. return SkRect::MakeEmpty();
  165. }
  166. SkRect bounds;
  167. fStyle.adjustBounds(&bounds, this->bounds());
  168. return bounds;
  169. }
  170. // If the path is small enough to be keyed from its data this returns key length, otherwise -1.
  171. static int path_key_from_data_size(const SkPath& path) {
  172. const int verbCnt = path.countVerbs();
  173. if (verbCnt > GrShape::kMaxKeyFromDataVerbCnt) {
  174. return -1;
  175. }
  176. const int pointCnt = path.countPoints();
  177. const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
  178. GR_STATIC_ASSERT(sizeof(SkPoint) == 2 * sizeof(uint32_t));
  179. GR_STATIC_ASSERT(sizeof(SkScalar) == sizeof(uint32_t));
  180. // 2 is for the verb cnt and a fill type. Each verb is a byte but we'll pad the verb data out to
  181. // a uint32_t length.
  182. return 2 + (SkAlign4(verbCnt) >> 2) + 2 * pointCnt + conicWeightCnt;
  183. }
  184. // Writes the path data key into the passed pointer.
  185. static void write_path_key_from_data(const SkPath& path, uint32_t* origKey) {
  186. uint32_t* key = origKey;
  187. // The check below should take care of negative values casted positive.
  188. const int verbCnt = path.countVerbs();
  189. const int pointCnt = path.countPoints();
  190. const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
  191. SkASSERT(verbCnt <= GrShape::kMaxKeyFromDataVerbCnt);
  192. SkASSERT(pointCnt && verbCnt);
  193. *key++ = path.getFillType();
  194. *key++ = verbCnt;
  195. memcpy(key, SkPathPriv::VerbData(path), verbCnt * sizeof(uint8_t));
  196. int verbKeySize = SkAlign4(verbCnt);
  197. // pad out to uint32_t alignment using value that will stand out when debugging.
  198. uint8_t* pad = reinterpret_cast<uint8_t*>(key)+ verbCnt;
  199. memset(pad, 0xDE, verbKeySize - verbCnt);
  200. key += verbKeySize >> 2;
  201. memcpy(key, SkPathPriv::PointData(path), sizeof(SkPoint) * pointCnt);
  202. GR_STATIC_ASSERT(sizeof(SkPoint) == 2 * sizeof(uint32_t));
  203. key += 2 * pointCnt;
  204. sk_careful_memcpy(key, SkPathPriv::ConicWeightData(path), sizeof(SkScalar) * conicWeightCnt);
  205. GR_STATIC_ASSERT(sizeof(SkScalar) == sizeof(uint32_t));
  206. SkDEBUGCODE(key += conicWeightCnt);
  207. SkASSERT(key - origKey == path_key_from_data_size(path));
  208. }
  209. int GrShape::unstyledKeySize() const {
  210. if (fInheritedKey.count()) {
  211. return fInheritedKey.count();
  212. }
  213. switch (fType) {
  214. case Type::kEmpty:
  215. return 1;
  216. case Type::kInvertedEmpty:
  217. return 1;
  218. case Type::kRRect:
  219. SkASSERT(!fInheritedKey.count());
  220. GR_STATIC_ASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
  221. // + 1 for the direction, start index, and inverseness.
  222. return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
  223. case Type::kArc:
  224. SkASSERT(!fInheritedKey.count());
  225. GR_STATIC_ASSERT(0 == sizeof(fArcData) % sizeof(uint32_t));
  226. return sizeof(fArcData) / sizeof(uint32_t);
  227. case Type::kLine:
  228. GR_STATIC_ASSERT(2 * sizeof(uint32_t) == sizeof(SkPoint));
  229. // 4 for the end points and 1 for the inverseness
  230. return 5;
  231. case Type::kPath: {
  232. if (0 == fPathData.fGenID) {
  233. return -1;
  234. }
  235. int dataKeySize = path_key_from_data_size(fPathData.fPath);
  236. if (dataKeySize >= 0) {
  237. return dataKeySize;
  238. }
  239. // The key is the path ID and fill type.
  240. return 2;
  241. }
  242. }
  243. SK_ABORT("Should never get here.");
  244. return 0;
  245. }
  246. void GrShape::writeUnstyledKey(uint32_t* key) const {
  247. SkASSERT(this->unstyledKeySize());
  248. SkDEBUGCODE(uint32_t* origKey = key;)
  249. if (fInheritedKey.count()) {
  250. memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count());
  251. SkDEBUGCODE(key += fInheritedKey.count();)
  252. } else {
  253. switch (fType) {
  254. case Type::kEmpty:
  255. *key++ = 1;
  256. break;
  257. case Type::kInvertedEmpty:
  258. *key++ = 2;
  259. break;
  260. case Type::kRRect:
  261. fRRectData.fRRect.writeToMemory(key);
  262. key += SkRRect::kSizeInMemory / sizeof(uint32_t);
  263. *key = (fRRectData.fDir == SkPath::kCCW_Direction) ? (1 << 31) : 0;
  264. *key |= fRRectData.fInverted ? (1 << 30) : 0;
  265. *key++ |= fRRectData.fStart;
  266. SkASSERT(fRRectData.fStart < 8);
  267. break;
  268. case Type::kArc:
  269. memcpy(key, &fArcData, sizeof(fArcData));
  270. key += sizeof(fArcData) / sizeof(uint32_t);
  271. break;
  272. case Type::kLine:
  273. memcpy(key, fLineData.fPts, 2 * sizeof(SkPoint));
  274. key += 4;
  275. *key++ = fLineData.fInverted ? 1 : 0;
  276. break;
  277. case Type::kPath: {
  278. SkASSERT(fPathData.fGenID);
  279. int dataKeySize = path_key_from_data_size(fPathData.fPath);
  280. if (dataKeySize >= 0) {
  281. write_path_key_from_data(fPathData.fPath, key);
  282. return;
  283. }
  284. *key++ = fPathData.fGenID;
  285. // We could canonicalize the fill rule for paths that don't differentiate between
  286. // even/odd or winding fill (e.g. convex).
  287. *key++ = this->path().getFillType();
  288. break;
  289. }
  290. }
  291. }
  292. SkASSERT(key - origKey == this->unstyledKeySize());
  293. }
  294. void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkScalar scale) {
  295. SkASSERT(!fInheritedKey.count());
  296. // If the output shape turns out to be simple, then we will just use its geometric key
  297. if (Type::kPath == fType) {
  298. // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key as
  299. // ApplyFullStyle(shape).
  300. // The full key is structured as (geo,path_effect,stroke).
  301. // If we do ApplyPathEffect we get geo,path_effect as the inherited key. If we then
  302. // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key
  303. // and then append the style key (which should now be stroke only) at the end.
  304. int parentCnt = parent.fInheritedKey.count();
  305. bool useParentGeoKey = !parentCnt;
  306. if (useParentGeoKey) {
  307. parentCnt = parent.unstyledKeySize();
  308. if (parentCnt < 0) {
  309. // The parent's geometry has no key so we will have no key.
  310. fPathData.fGenID = 0;
  311. return;
  312. }
  313. }
  314. uint32_t styleKeyFlags = 0;
  315. if (parent.knownToBeClosed()) {
  316. styleKeyFlags |= GrStyle::kClosed_KeyFlag;
  317. }
  318. if (parent.asLine(nullptr, nullptr)) {
  319. styleKeyFlags |= GrStyle::kNoJoins_KeyFlag;
  320. }
  321. int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags);
  322. if (styleCnt < 0) {
  323. // The style doesn't allow a key, set the path gen ID to 0 so that we fail when
  324. // we try to get a key for the shape.
  325. fPathData.fGenID = 0;
  326. return;
  327. }
  328. fInheritedKey.reset(parentCnt + styleCnt);
  329. if (useParentGeoKey) {
  330. // This will be the geo key.
  331. parent.writeUnstyledKey(fInheritedKey.get());
  332. } else {
  333. // This should be (geo,path_effect).
  334. memcpy(fInheritedKey.get(), parent.fInheritedKey.get(),
  335. parentCnt * sizeof(uint32_t));
  336. }
  337. // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke)
  338. GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply, scale,
  339. styleKeyFlags);
  340. }
  341. }
  342. const SkPath* GrShape::originalPathForListeners() const {
  343. if (fInheritedPathForListeners.isValid()) {
  344. return fInheritedPathForListeners.get();
  345. } else if (Type::kPath == fType && !fPathData.fPath.isVolatile()) {
  346. return &fPathData.fPath;
  347. }
  348. return nullptr;
  349. }
  350. void GrShape::addGenIDChangeListener(sk_sp<SkPathRef::GenIDChangeListener> listener) const {
  351. if (const auto* lp = this->originalPathForListeners()) {
  352. SkPathPriv::AddGenIDChangeListener(*lp, std::move(listener));
  353. }
  354. }
  355. GrShape GrShape::MakeArc(const SkRect& oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees,
  356. bool useCenter, const GrStyle& style) {
  357. GrShape result;
  358. result.changeType(Type::kArc);
  359. result.fArcData.fOval = oval;
  360. result.fArcData.fStartAngleDegrees = startAngleDegrees;
  361. result.fArcData.fSweepAngleDegrees = sweepAngleDegrees;
  362. result.fArcData.fUseCenter = useCenter;
  363. result.fArcData.fInverted = false;
  364. result.fStyle = style;
  365. result.attemptToSimplifyArc();
  366. return result;
  367. }
  368. GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
  369. const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr;
  370. this->initType(that.fType, thatPath);
  371. switch (fType) {
  372. case Type::kEmpty:
  373. break;
  374. case Type::kInvertedEmpty:
  375. break;
  376. case Type::kRRect:
  377. fRRectData = that.fRRectData;
  378. break;
  379. case Type::kArc:
  380. fArcData = that.fArcData;
  381. break;
  382. case Type::kLine:
  383. fLineData = that.fLineData;
  384. break;
  385. case Type::kPath:
  386. fPathData.fGenID = that.fPathData.fGenID;
  387. break;
  388. }
  389. fInheritedKey.reset(that.fInheritedKey.count());
  390. sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
  391. sizeof(uint32_t) * fInheritedKey.count());
  392. if (that.fInheritedPathForListeners.isValid()) {
  393. fInheritedPathForListeners.set(*that.fInheritedPathForListeners.get());
  394. }
  395. }
  396. GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) {
  397. // TODO: Add some quantization of scale for better cache performance here or leave that up
  398. // to caller?
  399. // TODO: For certain shapes and stroke params we could ignore the scale. (e.g. miter or bevel
  400. // stroke of a rect).
  401. if (!parent.style().applies() ||
  402. (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) {
  403. this->initType(Type::kEmpty);
  404. *this = parent;
  405. return;
  406. }
  407. SkPathEffect* pe = parent.fStyle.pathEffect();
  408. SkTLazy<SkPath> tmpPath;
  409. const GrShape* parentForKey = &parent;
  410. SkTLazy<GrShape> tmpParent;
  411. this->initType(Type::kPath);
  412. fPathData.fGenID = 0;
  413. if (pe) {
  414. const SkPath* srcForPathEffect;
  415. if (parent.fType == Type::kPath) {
  416. srcForPathEffect = &parent.path();
  417. } else {
  418. srcForPathEffect = tmpPath.init();
  419. parent.asPath(tmpPath.get());
  420. }
  421. // Should we consider bounds? Would have to include in key, but it'd be nice to know
  422. // if the bounds actually modified anything before including in key.
  423. SkStrokeRec strokeRec = parent.fStyle.strokeRec();
  424. if (!parent.fStyle.applyPathEffectToPath(&this->path(), &strokeRec, *srcForPathEffect,
  425. scale)) {
  426. tmpParent.init(*srcForPathEffect, GrStyle(strokeRec, nullptr));
  427. *this = tmpParent.get()->applyStyle(apply, scale);
  428. return;
  429. }
  430. // A path effect has access to change the res scale but we aren't expecting it to and it
  431. // would mess up our key computation.
  432. SkASSERT(scale == strokeRec.getResScale());
  433. if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needToApply()) {
  434. // The intermediate shape may not be a general path. If we we're just applying
  435. // the path effect then attemptToReduceFromPath would catch it. This means that
  436. // when we subsequently applied the remaining strokeRec we would have a non-path
  437. // parent shape that would be used to determine the the stroked path's key.
  438. // We detect that case here and change parentForKey to a temporary that represents
  439. // the simpler shape so that applying both path effect and the strokerec all at
  440. // once produces the same key.
  441. tmpParent.init(this->path(), GrStyle(strokeRec, nullptr));
  442. tmpParent.get()->setInheritedKey(parent, GrStyle::Apply::kPathEffectOnly, scale);
  443. if (!tmpPath.isValid()) {
  444. tmpPath.init();
  445. }
  446. tmpParent.get()->asPath(tmpPath.get());
  447. SkStrokeRec::InitStyle fillOrHairline;
  448. // The parent shape may have simplified away the strokeRec, check for that here.
  449. if (tmpParent.get()->style().applies()) {
  450. SkAssertResult(tmpParent.get()->style().applyToPath(&this->path(), &fillOrHairline,
  451. *tmpPath.get(), scale));
  452. } else if (tmpParent.get()->style().isSimpleFill()) {
  453. fillOrHairline = SkStrokeRec::kFill_InitStyle;
  454. } else {
  455. SkASSERT(tmpParent.get()->style().isSimpleHairline());
  456. fillOrHairline = SkStrokeRec::kHairline_InitStyle;
  457. }
  458. fStyle.resetToInitStyle(fillOrHairline);
  459. parentForKey = tmpParent.get();
  460. } else {
  461. fStyle = GrStyle(strokeRec, nullptr);
  462. }
  463. } else {
  464. const SkPath* srcForParentStyle;
  465. if (parent.fType == Type::kPath) {
  466. srcForParentStyle = &parent.path();
  467. } else {
  468. srcForParentStyle = tmpPath.init();
  469. parent.asPath(tmpPath.get());
  470. }
  471. SkStrokeRec::InitStyle fillOrHairline;
  472. SkASSERT(parent.fStyle.applies());
  473. SkASSERT(!parent.fStyle.pathEffect());
  474. SkAssertResult(parent.fStyle.applyToPath(&this->path(), &fillOrHairline, *srcForParentStyle,
  475. scale));
  476. fStyle.resetToInitStyle(fillOrHairline);
  477. }
  478. if (parent.fInheritedPathForListeners.isValid()) {
  479. fInheritedPathForListeners.set(*parent.fInheritedPathForListeners.get());
  480. } else if (Type::kPath == parent.fType && !parent.fPathData.fPath.isVolatile()) {
  481. fInheritedPathForListeners.set(parent.fPathData.fPath);
  482. }
  483. this->attemptToSimplifyPath();
  484. this->setInheritedKey(*parentForKey, apply, scale);
  485. }
  486. void GrShape::attemptToSimplifyPath() {
  487. SkRect rect;
  488. SkRRect rrect;
  489. SkPath::Direction rrectDir;
  490. unsigned rrectStart;
  491. bool inverted = this->path().isInverseFillType();
  492. SkPoint pts[2];
  493. if (this->path().isEmpty()) {
  494. // Dashing ignores inverseness skbug.com/5421.
  495. this->changeType(inverted && !this->style().isDashed() ? Type::kInvertedEmpty
  496. : Type::kEmpty);
  497. } else if (this->path().isLine(pts)) {
  498. this->changeType(Type::kLine);
  499. fLineData.fPts[0] = pts[0];
  500. fLineData.fPts[1] = pts[1];
  501. fLineData.fInverted = inverted;
  502. } else if (SkPathPriv::IsRRect(this->path(), &rrect, &rrectDir, &rrectStart)) {
  503. this->changeType(Type::kRRect);
  504. fRRectData.fRRect = rrect;
  505. fRRectData.fDir = rrectDir;
  506. fRRectData.fStart = rrectStart;
  507. fRRectData.fInverted = inverted;
  508. SkASSERT(!fRRectData.fRRect.isEmpty());
  509. } else if (SkPathPriv::IsOval(this->path(), &rect, &rrectDir, &rrectStart)) {
  510. this->changeType(Type::kRRect);
  511. fRRectData.fRRect.setOval(rect);
  512. fRRectData.fDir = rrectDir;
  513. fRRectData.fInverted = inverted;
  514. // convert from oval indexing to rrect indexiing.
  515. fRRectData.fStart = 2 * rrectStart;
  516. } else if (SkPathPriv::IsSimpleClosedRect(this->path(), &rect, &rrectDir, &rrectStart)) {
  517. this->changeType(Type::kRRect);
  518. // When there is a path effect we restrict rect detection to the narrower API that
  519. // gives us the starting position. Otherwise, we will retry with the more aggressive
  520. // isRect().
  521. fRRectData.fRRect.setRect(rect);
  522. fRRectData.fInverted = inverted;
  523. fRRectData.fDir = rrectDir;
  524. // convert from rect indexing to rrect indexiing.
  525. fRRectData.fStart = 2 * rrectStart;
  526. } else if (!this->style().hasPathEffect()) {
  527. bool closed;
  528. if (this->path().isRect(&rect, &closed, nullptr)) {
  529. if (closed || this->style().isSimpleFill()) {
  530. this->changeType(Type::kRRect);
  531. fRRectData.fRRect.setRect(rect);
  532. // Since there is no path effect the dir and start index is immaterial.
  533. fRRectData.fDir = kDefaultRRectDir;
  534. fRRectData.fStart = kDefaultRRectStart;
  535. // There isn't dashing so we will have to preserver inverseness.
  536. fRRectData.fInverted = inverted;
  537. }
  538. }
  539. }
  540. if (Type::kPath != fType) {
  541. fInheritedKey.reset(0);
  542. // Whenever we simplify to a non-path, break the chain so we no longer refer to the
  543. // original path. This prevents attaching genID listeners to temporary paths created when
  544. // drawing simple shapes.
  545. fInheritedPathForListeners.reset();
  546. if (Type::kRRect == fType) {
  547. this->attemptToSimplifyRRect();
  548. } else if (Type::kLine == fType) {
  549. this->attemptToSimplifyLine();
  550. }
  551. } else {
  552. if (fInheritedKey.count() || this->path().isVolatile()) {
  553. fPathData.fGenID = 0;
  554. } else {
  555. fPathData.fGenID = this->path().getGenerationID();
  556. }
  557. if (!this->style().hasNonDashPathEffect()) {
  558. if (this->style().strokeRec().getStyle() == SkStrokeRec::kStroke_Style ||
  559. this->style().strokeRec().getStyle() == SkStrokeRec::kHairline_Style) {
  560. // Stroke styles don't differentiate between winding and even/odd.
  561. // Moreover, dashing ignores inverseness (skbug.com/5421)
  562. bool inverse = !this->style().isDashed() && this->path().isInverseFillType();
  563. if (inverse) {
  564. this->path().setFillType(kDefaultPathInverseFillType);
  565. } else {
  566. this->path().setFillType(kDefaultPathFillType);
  567. }
  568. } else if (this->path().isConvex()) {
  569. // There is no distinction between even/odd and non-zero winding count for convex
  570. // paths.
  571. if (this->path().isInverseFillType()) {
  572. this->path().setFillType(kDefaultPathInverseFillType);
  573. } else {
  574. this->path().setFillType(kDefaultPathFillType);
  575. }
  576. }
  577. }
  578. }
  579. }
  580. void GrShape::attemptToSimplifyRRect() {
  581. SkASSERT(Type::kRRect == fType);
  582. SkASSERT(!fInheritedKey.count());
  583. if (fRRectData.fRRect.isEmpty()) {
  584. // An empty filled rrect is equivalent to a filled empty path with inversion preserved.
  585. if (fStyle.isSimpleFill()) {
  586. fType = fRRectData.fInverted ? Type::kInvertedEmpty : Type::kEmpty;
  587. fStyle = GrStyle::SimpleFill();
  588. return;
  589. }
  590. // Dashing a rrect with no width or height is equivalent to filling an emtpy path.
  591. // When skbug.com/7387 is fixed this should be modified or removed as a dashed zero length
  592. // line will produce cap geometry if the effect begins in an "on" interval.
  593. if (fStyle.isDashed() && !fRRectData.fRRect.width() && !fRRectData.fRRect.height()) {
  594. // Dashing ignores the inverseness (currently). skbug.com/5421.
  595. fType = Type::kEmpty;
  596. fStyle = GrStyle::SimpleFill();
  597. return;
  598. }
  599. }
  600. if (!this->style().hasPathEffect()) {
  601. fRRectData.fDir = kDefaultRRectDir;
  602. fRRectData.fStart = kDefaultRRectStart;
  603. } else if (fStyle.isDashed()) {
  604. // Dashing ignores the inverseness (currently). skbug.com/5421
  605. fRRectData.fInverted = false;
  606. // Possible TODO here: Check whether the dash results in a single arc or line.
  607. }
  608. // Turn a stroke-and-filled miter rect into a filled rect. TODO: more rrect stroke shortcuts.
  609. if (!fStyle.hasPathEffect() &&
  610. fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style &&
  611. fStyle.strokeRec().getJoin() == SkPaint::kMiter_Join &&
  612. fStyle.strokeRec().getMiter() >= SK_ScalarSqrt2 &&
  613. fRRectData.fRRect.isRect()) {
  614. SkScalar r = fStyle.strokeRec().getWidth() / 2;
  615. fRRectData.fRRect = SkRRect::MakeRect(fRRectData.fRRect.rect().makeOutset(r, r));
  616. fStyle = GrStyle::SimpleFill();
  617. }
  618. }
  619. void GrShape::attemptToSimplifyLine() {
  620. SkASSERT(Type::kLine == fType);
  621. SkASSERT(!fInheritedKey.count());
  622. if (fStyle.isDashed()) {
  623. bool allOffsZero = true;
  624. for (int i = 1; i < fStyle.dashIntervalCnt() && allOffsZero; i += 2) {
  625. allOffsZero = !fStyle.dashIntervals()[i];
  626. }
  627. if (allOffsZero && this->attemptToSimplifyStrokedLineToRRect()) {
  628. return;
  629. }
  630. // Dashing ignores inverseness.
  631. fLineData.fInverted = false;
  632. return;
  633. } else if (fStyle.hasPathEffect()) {
  634. return;
  635. }
  636. if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
  637. // Make stroke + fill be stroke since the fill is empty.
  638. SkStrokeRec rec = fStyle.strokeRec();
  639. rec.setStrokeStyle(fStyle.strokeRec().getWidth(), false);
  640. fStyle = GrStyle(rec, nullptr);
  641. }
  642. if (fStyle.isSimpleFill()) {
  643. this->changeType(fLineData.fInverted ? Type::kInvertedEmpty : Type::kEmpty);
  644. return;
  645. }
  646. if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style &&
  647. this->attemptToSimplifyStrokedLineToRRect()) {
  648. return;
  649. }
  650. // Only path effects could care about the order of the points. Otherwise canonicalize
  651. // the point order.
  652. SkPoint* pts = fLineData.fPts;
  653. if (pts[1].fY < pts[0].fY || (pts[1].fY == pts[0].fY && pts[1].fX < pts[0].fX)) {
  654. using std::swap;
  655. swap(pts[0], pts[1]);
  656. }
  657. }
  658. void GrShape::attemptToSimplifyArc() {
  659. SkASSERT(fType == Type::kArc);
  660. SkASSERT(!fArcData.fInverted);
  661. if (fArcData.fOval.isEmpty() || !fArcData.fSweepAngleDegrees) {
  662. this->changeType(Type::kEmpty);
  663. return;
  664. }
  665. // Assuming no path effect, a filled, stroked, hairline, or stroke-and-filled arc that traverses
  666. // the full circle and doesn't use the center point is an oval. Unless it has square or round
  667. // caps. They may protrude out of the oval. Round caps can't protrude out of a circle but we're
  668. // ignoring that for now.
  669. if (fStyle.isSimpleFill() || (!fStyle.pathEffect() && !fArcData.fUseCenter &&
  670. fStyle.strokeRec().getCap() == SkPaint::kButt_Cap)) {
  671. if (fArcData.fSweepAngleDegrees >= 360.f || fArcData.fSweepAngleDegrees <= -360.f) {
  672. auto oval = fArcData.fOval;
  673. this->changeType(Type::kRRect);
  674. this->fRRectData.fRRect.setOval(oval);
  675. this->fRRectData.fDir = kDefaultRRectDir;
  676. this->fRRectData.fStart = kDefaultRRectStart;
  677. this->fRRectData.fInverted = false;
  678. return;
  679. }
  680. }
  681. if (!fStyle.pathEffect()) {
  682. // Canonicalize the arc such that the start is always in [0, 360) and the sweep is always
  683. // positive.
  684. if (fArcData.fSweepAngleDegrees < 0) {
  685. fArcData.fStartAngleDegrees = fArcData.fStartAngleDegrees + fArcData.fSweepAngleDegrees;
  686. fArcData.fSweepAngleDegrees = -fArcData.fSweepAngleDegrees;
  687. }
  688. }
  689. if (this->fArcData.fStartAngleDegrees < 0 || this->fArcData.fStartAngleDegrees >= 360.f) {
  690. this->fArcData.fStartAngleDegrees = SkScalarMod(this->fArcData.fStartAngleDegrees, 360.f);
  691. }
  692. // Possible TODOs here: Look at whether dash pattern results in a single dash and convert to
  693. // non-dashed stroke. Stroke and fill can be fill if circular and no path effect. Just stroke
  694. // could as well if the stroke fills the center.
  695. }
  696. bool GrShape::attemptToSimplifyStrokedLineToRRect() {
  697. SkASSERT(Type::kLine == fType);
  698. SkASSERT(fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style);
  699. SkRect rect;
  700. SkVector outset;
  701. // If we allowed a rotation angle for rrects we could capture all cases here.
  702. if (fLineData.fPts[0].fY == fLineData.fPts[1].fY) {
  703. rect.fLeft = SkTMin(fLineData.fPts[0].fX, fLineData.fPts[1].fX);
  704. rect.fRight = SkTMax(fLineData.fPts[0].fX, fLineData.fPts[1].fX);
  705. rect.fTop = rect.fBottom = fLineData.fPts[0].fY;
  706. outset.fY = fStyle.strokeRec().getWidth() / 2.f;
  707. outset.fX = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fY;
  708. } else if (fLineData.fPts[0].fX == fLineData.fPts[1].fX) {
  709. rect.fTop = SkTMin(fLineData.fPts[0].fY, fLineData.fPts[1].fY);
  710. rect.fBottom = SkTMax(fLineData.fPts[0].fY, fLineData.fPts[1].fY);
  711. rect.fLeft = rect.fRight = fLineData.fPts[0].fX;
  712. outset.fX = fStyle.strokeRec().getWidth() / 2.f;
  713. outset.fY = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fX;
  714. } else {
  715. return false;
  716. }
  717. rect.outset(outset.fX, outset.fY);
  718. if (rect.isEmpty()) {
  719. this->changeType(Type::kEmpty);
  720. fStyle = GrStyle::SimpleFill();
  721. return true;
  722. }
  723. SkRRect rrect;
  724. if (fStyle.strokeRec().getCap() == SkPaint::kRound_Cap) {
  725. SkASSERT(outset.fX == outset.fY);
  726. rrect = SkRRect::MakeRectXY(rect, outset.fX, outset.fY);
  727. } else {
  728. rrect = SkRRect::MakeRect(rect);
  729. }
  730. bool inverted = fLineData.fInverted && !fStyle.hasPathEffect();
  731. this->changeType(Type::kRRect);
  732. fRRectData.fRRect = rrect;
  733. fRRectData.fInverted = inverted;
  734. fRRectData.fDir = kDefaultRRectDir;
  735. fRRectData.fStart = kDefaultRRectStart;
  736. fStyle = GrStyle::SimpleFill();
  737. return true;
  738. }