GrShape.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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. #ifndef GrShape_DEFINED
  8. #define GrShape_DEFINED
  9. #include "include/core/SkPath.h"
  10. #include "include/core/SkRRect.h"
  11. #include "include/private/SkTemplates.h"
  12. #include "src/core/SkPathPriv.h"
  13. #include "src/core/SkTLazy.h"
  14. #include "src/gpu/GrStyle.h"
  15. #include <new>
  16. /**
  17. * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with.
  18. * It is possible to apply the style to the GrShape to produce a new GrShape where the geometry
  19. * reflects the styling information (e.g. is stroked). It is also possible to apply just the
  20. * path effect from the style. In this case the resulting shape will include any remaining
  21. * stroking information that is to be applied after the path effect.
  22. *
  23. * Shapes can produce keys that represent only the geometry information, not the style. Note that
  24. * when styling information is applied to produce a new shape then the style has been converted
  25. * to geometric information and is included in the new shape's key. When the same style is applied
  26. * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes
  27. * will be the same.
  28. *
  29. * Currently this can only be constructed from a path, rect, or rrect though it can become a path
  30. * applying style to the geometry. The idea is to expand this to cover most or all of the geometries
  31. * that have fast paths in the GPU backend.
  32. */
  33. class GrShape {
  34. public:
  35. // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
  36. // to have to worry about this. This value is exposed for unit tests.
  37. static constexpr int kMaxKeyFromDataVerbCnt = 10;
  38. GrShape() { this->initType(Type::kEmpty); }
  39. explicit GrShape(const SkPath& path) : GrShape(path, GrStyle::SimpleFill()) {}
  40. explicit GrShape(const SkRRect& rrect) : GrShape(rrect, GrStyle::SimpleFill()) {}
  41. explicit GrShape(const SkRect& rect) : GrShape(rect, GrStyle::SimpleFill()) {}
  42. GrShape(const SkPath& path, const GrStyle& style) : fStyle(style) {
  43. this->initType(Type::kPath, &path);
  44. this->attemptToSimplifyPath();
  45. }
  46. GrShape(const SkRRect& rrect, const GrStyle& style) : fStyle(style) {
  47. this->initType(Type::kRRect);
  48. fRRectData.fRRect = rrect;
  49. fRRectData.fInverted = false;
  50. fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(),
  51. &fRRectData.fDir);
  52. this->attemptToSimplifyRRect();
  53. }
  54. GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, bool inverted,
  55. const GrStyle& style)
  56. : fStyle(style) {
  57. this->initType(Type::kRRect);
  58. fRRectData.fRRect = rrect;
  59. fRRectData.fInverted = inverted;
  60. if (style.pathEffect()) {
  61. fRRectData.fDir = dir;
  62. fRRectData.fStart = start;
  63. if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) {
  64. fRRectData.fStart = (fRRectData.fStart + 1) & 0b110;
  65. } else if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
  66. fRRectData.fStart &= 0b110;
  67. }
  68. } else {
  69. fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectData.fDir);
  70. }
  71. this->attemptToSimplifyRRect();
  72. }
  73. GrShape(const SkRect& rect, const GrStyle& style) : fStyle(style) {
  74. this->initType(Type::kRRect);
  75. fRRectData.fRRect = SkRRect::MakeRect(rect);
  76. fRRectData.fInverted = false;
  77. fRRectData.fStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(),
  78. &fRRectData.fDir);
  79. this->attemptToSimplifyRRect();
  80. }
  81. GrShape(const SkPath& path, const SkPaint& paint) : fStyle(paint) {
  82. this->initType(Type::kPath, &path);
  83. this->attemptToSimplifyPath();
  84. }
  85. GrShape(const SkRRect& rrect, const SkPaint& paint) : fStyle(paint) {
  86. this->initType(Type::kRRect);
  87. fRRectData.fRRect = rrect;
  88. fRRectData.fInverted = false;
  89. fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect(),
  90. &fRRectData.fDir);
  91. this->attemptToSimplifyRRect();
  92. }
  93. GrShape(const SkRect& rect, const SkPaint& paint) : fStyle(paint) {
  94. this->initType(Type::kRRect);
  95. fRRectData.fRRect = SkRRect::MakeRect(rect);
  96. fRRectData.fInverted = false;
  97. fRRectData.fStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(),
  98. &fRRectData.fDir);
  99. this->attemptToSimplifyRRect();
  100. }
  101. static GrShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
  102. SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style);
  103. GrShape(const GrShape&);
  104. GrShape& operator=(const GrShape& that);
  105. ~GrShape() { this->changeType(Type::kEmpty); }
  106. /**
  107. * Informs MakeFilled on how to modify that shape's fill rule when making a simple filled
  108. * version of the shape.
  109. */
  110. enum class FillInversion {
  111. kPreserve,
  112. kFlip,
  113. kForceNoninverted,
  114. kForceInverted
  115. };
  116. /**
  117. * Makes a filled shape from the pre-styled original shape and optionally modifies whether
  118. * the fill is inverted or not. It's important to note that the original shape's geometry
  119. * may already have been modified if doing so was neutral with respect to its style
  120. * (e.g. filled paths are always closed when stored in a shape and dashed paths are always
  121. * made non-inverted since dashing ignores inverseness).
  122. */
  123. static GrShape MakeFilled(const GrShape& original, FillInversion = FillInversion::kPreserve);
  124. const GrStyle& style() const { return fStyle; }
  125. /**
  126. * Returns a shape that has either applied the path effect or path effect and stroking
  127. * information from this shape's style to its geometry. Scale is used when approximating the
  128. * output geometry and typically is computed from the view matrix
  129. */
  130. GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) const {
  131. return GrShape(*this, apply, scale);
  132. }
  133. bool isRect() const {
  134. if (Type::kRRect != fType) {
  135. return false;
  136. }
  137. return fRRectData.fRRect.isRect();
  138. }
  139. /** Returns the unstyled geometry as a rrect if possible. */
  140. bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start, bool* inverted) const {
  141. if (Type::kRRect != fType) {
  142. return false;
  143. }
  144. if (rrect) {
  145. *rrect = fRRectData.fRRect;
  146. }
  147. if (dir) {
  148. *dir = fRRectData.fDir;
  149. }
  150. if (start) {
  151. *start = fRRectData.fStart;
  152. }
  153. if (inverted) {
  154. *inverted = fRRectData.fInverted;
  155. }
  156. return true;
  157. }
  158. /**
  159. * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
  160. * An inverse filled line path is still considered a line.
  161. */
  162. bool asLine(SkPoint pts[2], bool* inverted) const {
  163. if (fType != Type::kLine) {
  164. return false;
  165. }
  166. if (pts) {
  167. pts[0] = fLineData.fPts[0];
  168. pts[1] = fLineData.fPts[1];
  169. }
  170. if (inverted) {
  171. *inverted = fLineData.fInverted;
  172. }
  173. return true;
  174. }
  175. /** Returns the unstyled geometry as a path. */
  176. void asPath(SkPath* out) const {
  177. switch (fType) {
  178. case Type::kEmpty:
  179. out->reset();
  180. break;
  181. case Type::kInvertedEmpty:
  182. out->reset();
  183. out->setFillType(kDefaultPathInverseFillType);
  184. break;
  185. case Type::kRRect:
  186. out->reset();
  187. out->addRRect(fRRectData.fRRect, fRRectData.fDir, fRRectData.fStart);
  188. // Below matches the fill type that attemptToSimplifyPath uses.
  189. if (fRRectData.fInverted) {
  190. out->setFillType(kDefaultPathInverseFillType);
  191. } else {
  192. out->setFillType(kDefaultPathFillType);
  193. }
  194. break;
  195. case Type::kArc:
  196. SkPathPriv::CreateDrawArcPath(out, fArcData.fOval, fArcData.fStartAngleDegrees,
  197. fArcData.fSweepAngleDegrees, fArcData.fUseCenter,
  198. fStyle.isSimpleFill());
  199. if (fArcData.fInverted) {
  200. out->setFillType(kDefaultPathInverseFillType);
  201. } else {
  202. out->setFillType(kDefaultPathFillType);
  203. }
  204. break;
  205. case Type::kLine:
  206. out->reset();
  207. out->moveTo(fLineData.fPts[0]);
  208. out->lineTo(fLineData.fPts[1]);
  209. if (fLineData.fInverted) {
  210. out->setFillType(kDefaultPathInverseFillType);
  211. } else {
  212. out->setFillType(kDefaultPathFillType);
  213. }
  214. break;
  215. case Type::kPath:
  216. *out = this->path();
  217. break;
  218. }
  219. }
  220. // Can this shape be drawn as a pair of filled nested rectangles?
  221. bool asNestedRects(SkRect rects[2]) const {
  222. if (Type::kPath != fType) {
  223. return false;
  224. }
  225. // TODO: it would be better two store DRRects natively in the shape rather than converting
  226. // them to a path and then reextracting the nested rects
  227. if (this->path().isInverseFillType()) {
  228. return false;
  229. }
  230. SkPath::Direction dirs[2];
  231. if (!this->path().isNestedFillRects(rects, dirs)) {
  232. return false;
  233. }
  234. if (SkPath::kWinding_FillType == this->path().getFillType() && dirs[0] == dirs[1]) {
  235. // The two rects need to be wound opposite to each other
  236. return false;
  237. }
  238. // Right now, nested rects where the margin is not the same width
  239. // all around do not render correctly
  240. const SkScalar* outer = rects[0].asScalars();
  241. const SkScalar* inner = rects[1].asScalars();
  242. bool allEq = true;
  243. SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
  244. bool allGoE1 = margin >= SK_Scalar1;
  245. for (int i = 1; i < 4; ++i) {
  246. SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
  247. if (temp < SK_Scalar1) {
  248. allGoE1 = false;
  249. }
  250. if (!SkScalarNearlyEqual(margin, temp)) {
  251. allEq = false;
  252. }
  253. }
  254. return allEq || allGoE1;
  255. }
  256. /**
  257. * Returns whether the geometry is empty. Note that applying the style could produce a
  258. * non-empty shape. It also may have an inverse fill.
  259. */
  260. bool isEmpty() const { return Type::kEmpty == fType || Type::kInvertedEmpty == fType; }
  261. /**
  262. * Gets the bounds of the geometry without reflecting the shape's styling. This ignores
  263. * the inverse fill nature of the geometry.
  264. */
  265. SkRect bounds() const;
  266. /**
  267. * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill
  268. * status).
  269. */
  270. SkRect styledBounds() const;
  271. /**
  272. * Is this shape known to be convex, before styling is applied. An unclosed but otherwise
  273. * convex path is considered to be closed if they styling reflects a fill and not otherwise.
  274. * This is because filling closes all contours in the path.
  275. */
  276. bool knownToBeConvex() const {
  277. switch (fType) {
  278. case Type::kEmpty:
  279. return true;
  280. case Type::kInvertedEmpty:
  281. return true;
  282. case Type::kRRect:
  283. return true;
  284. case Type::kArc:
  285. return SkPathPriv::DrawArcIsConvex(fArcData.fSweepAngleDegrees,
  286. SkToBool(fArcData.fUseCenter),
  287. fStyle.isSimpleFill());
  288. case Type::kLine:
  289. return true;
  290. case Type::kPath:
  291. // SkPath.isConvex() really means "is this path convex were it to be closed" and
  292. // thus doesn't give the correct answer for stroked paths, hence we also check
  293. // whether the path is either filled or closed. Convex paths may only have one
  294. // contour hence isLastContourClosed() is a sufficient for a convex path.
  295. return (this->style().isSimpleFill() || this->path().isLastContourClosed()) &&
  296. this->path().isConvex();
  297. }
  298. return false;
  299. }
  300. /** Is the pre-styled geometry inverse filled? */
  301. bool inverseFilled() const {
  302. bool ret = false;
  303. switch (fType) {
  304. case Type::kEmpty:
  305. ret = false;
  306. break;
  307. case Type::kInvertedEmpty:
  308. ret = true;
  309. break;
  310. case Type::kRRect:
  311. ret = fRRectData.fInverted;
  312. break;
  313. case Type::kArc:
  314. ret = fArcData.fInverted;
  315. break;
  316. case Type::kLine:
  317. ret = fLineData.fInverted;
  318. break;
  319. case Type::kPath:
  320. ret = this->path().isInverseFillType();
  321. break;
  322. }
  323. // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421
  324. SkASSERT(!(ret && this->style().isDashed()));
  325. return ret;
  326. }
  327. /**
  328. * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in
  329. * because an arbitrary path effect could produce an inverse filled path. In other cases this
  330. * can be thought of as "inverseFilledAfterStyling()".
  331. */
  332. bool mayBeInverseFilledAfterStyling() const {
  333. // An arbitrary path effect can produce an arbitrary output path, which may be inverse
  334. // filled.
  335. if (this->style().hasNonDashPathEffect()) {
  336. return true;
  337. }
  338. return this->inverseFilled();
  339. }
  340. /**
  341. * Is it known that the unstyled geometry has no unclosed contours. This means that it will
  342. * not have any caps if stroked (modulo the effect of any path effect).
  343. */
  344. bool knownToBeClosed() const {
  345. switch (fType) {
  346. case Type::kEmpty:
  347. return true;
  348. case Type::kInvertedEmpty:
  349. return true;
  350. case Type::kRRect:
  351. return true;
  352. case Type::kArc:
  353. return fArcData.fUseCenter;
  354. case Type::kLine:
  355. return false;
  356. case Type::kPath:
  357. // SkPath doesn't keep track of the closed status of each contour.
  358. return SkPathPriv::IsClosedSingleContour(this->path());
  359. }
  360. return false;
  361. }
  362. uint32_t segmentMask() const {
  363. switch (fType) {
  364. case Type::kEmpty:
  365. return 0;
  366. case Type::kInvertedEmpty:
  367. return 0;
  368. case Type::kRRect:
  369. if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
  370. return SkPath::kConic_SegmentMask;
  371. } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type ||
  372. fRRectData.fRRect.getType() == SkRRect::kEmpty_Type) {
  373. return SkPath::kLine_SegmentMask;
  374. }
  375. return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask;
  376. case Type::kArc:
  377. if (fArcData.fUseCenter) {
  378. return SkPath::kConic_SegmentMask | SkPath::kLine_SegmentMask;
  379. }
  380. return SkPath::kConic_SegmentMask;
  381. case Type::kLine:
  382. return SkPath::kLine_SegmentMask;
  383. case Type::kPath:
  384. return this->path().getSegmentMasks();
  385. }
  386. return 0;
  387. }
  388. /**
  389. * Gets the size of the key for the shape represented by this GrShape (ignoring its styling).
  390. * A negative value is returned if the shape has no key (shouldn't be cached).
  391. */
  392. int unstyledKeySize() const;
  393. bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; }
  394. /**
  395. * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough
  396. * space allocated for the key and that unstyledKeySize() does not return a negative value
  397. * for this shape.
  398. */
  399. void writeUnstyledKey(uint32_t* key) const;
  400. /**
  401. * Adds a listener to the *original* path. Typically used to invalidate cached resources when
  402. * a path is no longer in-use. If the shape started out as something other than a path, this
  403. * does nothing.
  404. */
  405. void addGenIDChangeListener(sk_sp<SkPathRef::GenIDChangeListener>) const;
  406. /**
  407. * Helpers that are only exposed for unit tests, to determine if the shape is a path, and get
  408. * the generation ID of the *original* path. This is the path that will receive
  409. * GenIDChangeListeners added to this shape.
  410. */
  411. uint32_t testingOnly_getOriginalGenerationID() const;
  412. bool testingOnly_isPath() const;
  413. bool testingOnly_isNonVolatilePath() const;
  414. private:
  415. enum class Type {
  416. kEmpty,
  417. kInvertedEmpty,
  418. kRRect,
  419. kArc,
  420. kLine,
  421. kPath,
  422. };
  423. void initType(Type type, const SkPath* path = nullptr) {
  424. fType = Type::kEmpty;
  425. this->changeType(type, path);
  426. }
  427. void changeType(Type type, const SkPath* path = nullptr) {
  428. bool wasPath = Type::kPath == fType;
  429. fType = type;
  430. bool isPath = Type::kPath == type;
  431. SkASSERT(!path || isPath);
  432. if (wasPath && !isPath) {
  433. fPathData.fPath.~SkPath();
  434. } else if (!wasPath && isPath) {
  435. if (path) {
  436. new (&fPathData.fPath) SkPath(*path);
  437. } else {
  438. new (&fPathData.fPath) SkPath();
  439. }
  440. } else if (isPath && path) {
  441. fPathData.fPath = *path;
  442. }
  443. // Whether or not we use the path's gen ID is decided in attemptToSimplifyPath.
  444. fPathData.fGenID = 0;
  445. }
  446. SkPath& path() {
  447. SkASSERT(Type::kPath == fType);
  448. return fPathData.fPath;
  449. }
  450. const SkPath& path() const {
  451. SkASSERT(Type::kPath == fType);
  452. return fPathData.fPath;
  453. }
  454. /** Constructor used by the applyStyle() function */
  455. GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
  456. /**
  457. * Determines the key we should inherit from the input shape's geometry and style when
  458. * we are applying the style to create a new shape.
  459. */
  460. void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
  461. void attemptToSimplifyPath();
  462. void attemptToSimplifyRRect();
  463. void attemptToSimplifyLine();
  464. void attemptToSimplifyArc();
  465. bool attemptToSimplifyStrokedLineToRRect();
  466. /** Gets the path that gen id listeners should be added to. */
  467. const SkPath* originalPathForListeners() const;
  468. // Defaults to use when there is no distinction between even/odd and winding fills.
  469. static constexpr SkPath::FillType kDefaultPathFillType = SkPath::kEvenOdd_FillType;
  470. static constexpr SkPath::FillType kDefaultPathInverseFillType =
  471. SkPath::kInverseEvenOdd_FillType;
  472. static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction;
  473. static constexpr unsigned kDefaultRRectStart = 0;
  474. static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPathEffect,
  475. SkPath::Direction* dir) {
  476. *dir = kDefaultRRectDir;
  477. // This comes from SkPath's interface. The default for adding a SkRect is counter clockwise
  478. // beginning at index 0 (which happens to correspond to rrect index 0 or 7).
  479. if (!hasPathEffect) {
  480. // It doesn't matter what start we use, just be consistent to avoid redundant keys.
  481. return kDefaultRRectStart;
  482. }
  483. // In SkPath a rect starts at index 0 by default. This is the top left corner. However,
  484. // we store rects as rrects. RRects don't preserve the invertedness, but rather sort the
  485. // rect edges. Thus, we may need to modify the rrect's start index to account for the sort.
  486. bool swapX = rect.fLeft > rect.fRight;
  487. bool swapY = rect.fTop > rect.fBottom;
  488. if (swapX && swapY) {
  489. // 0 becomes start index 2 and times 2 to convert from rect the rrect indices.
  490. return 2 * 2;
  491. } else if (swapX) {
  492. *dir = SkPath::kCCW_Direction;
  493. // 0 becomes start index 1 and times 2 to convert from rect the rrect indices.
  494. return 2 * 1;
  495. } else if (swapY) {
  496. *dir = SkPath::kCCW_Direction;
  497. // 0 becomes start index 3 and times 2 to convert from rect the rrect indices.
  498. return 2 * 3;
  499. }
  500. return 0;
  501. }
  502. static unsigned DefaultRRectDirAndStartIndex(const SkRRect& rrect, bool hasPathEffect,
  503. SkPath::Direction* dir) {
  504. // This comes from SkPath's interface. The default for adding a SkRRect to a path is
  505. // clockwise beginning at starting index 6.
  506. static constexpr unsigned kPathRRectStartIdx = 6;
  507. *dir = kDefaultRRectDir;
  508. if (!hasPathEffect) {
  509. // It doesn't matter what start we use, just be consistent to avoid redundant keys.
  510. return kDefaultRRectStart;
  511. }
  512. return kPathRRectStartIdx;
  513. }
  514. union {
  515. struct {
  516. SkRRect fRRect;
  517. SkPath::Direction fDir;
  518. unsigned fStart;
  519. bool fInverted;
  520. } fRRectData;
  521. struct {
  522. SkRect fOval;
  523. SkScalar fStartAngleDegrees;
  524. SkScalar fSweepAngleDegrees;
  525. int16_t fUseCenter;
  526. int16_t fInverted;
  527. } fArcData;
  528. struct {
  529. SkPath fPath;
  530. // Gen ID of the original path (fPath may be modified)
  531. int32_t fGenID;
  532. } fPathData;
  533. struct {
  534. SkPoint fPts[2];
  535. bool fInverted;
  536. } fLineData;
  537. };
  538. GrStyle fStyle;
  539. SkTLazy<SkPath> fInheritedPathForListeners;
  540. SkAutoSTArray<8, uint32_t> fInheritedKey;
  541. Type fType;
  542. };
  543. #endif