GrStyle.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 GrStyle_DEFINED
  8. #define GrStyle_DEFINED
  9. #include "include/core/SkPathEffect.h"
  10. #include "include/core/SkStrokeRec.h"
  11. #include "include/gpu/GrTypes.h"
  12. #include "include/private/SkTemplates.h"
  13. /**
  14. * Represents the various ways that a GrShape can be styled. It has fill/stroking information
  15. * as well as an optional path effect. If the path effect represents dashing, the dashing
  16. * information is extracted from the path effect and stored explicitly.
  17. *
  18. * This will replace GrStrokeInfo as GrShape is deployed.
  19. */
  20. class GrStyle {
  21. public:
  22. /**
  23. * A style object that represents a fill with no path effect.
  24. * TODO: constexpr with C++14
  25. */
  26. static const GrStyle& SimpleFill() {
  27. static const GrStyle kFill(SkStrokeRec::kFill_InitStyle);
  28. return kFill;
  29. }
  30. /**
  31. * A style object that represents a hairline stroke with no path effect.
  32. * TODO: constexpr with C++14
  33. */
  34. static const GrStyle& SimpleHairline() {
  35. static const GrStyle kHairline(SkStrokeRec::kHairline_InitStyle);
  36. return kHairline;
  37. }
  38. enum class Apply {
  39. kPathEffectOnly,
  40. kPathEffectAndStrokeRec
  41. };
  42. /**
  43. * Optional flags for computing keys that may remove unnecessary variation in the key due to
  44. * style settings that don't affect particular classes of geometry.
  45. */
  46. enum KeyFlags {
  47. // The shape being styled has no open contours.
  48. kClosed_KeyFlag = 0x1,
  49. // The shape being styled doesn't have any joins and so isn't affected by join type.
  50. kNoJoins_KeyFlag = 0x2
  51. };
  52. /**
  53. * Computes the key length for a GrStyle. The return will be negative if it cannot be turned
  54. * into a key. This occurs when there is a path effect that is not a dash. The key can
  55. * either reflect just the path effect (if one) or the path effect and the strokerec. Note
  56. * that a simple fill has a zero sized key.
  57. */
  58. static int KeySize(const GrStyle&, Apply, uint32_t flags = 0);
  59. /**
  60. * Writes a unique key for the style into the provided buffer. This function assumes the buffer
  61. * has room for at least KeySize() values. It assumes that KeySize() returns a non-negative
  62. * value for the combination of GrStyle, Apply and flags params. This is written so that the key
  63. * for just dash application followed by the key for the remaining SkStrokeRec is the same as
  64. * the key for applying dashing and SkStrokeRec all at once.
  65. */
  66. static void WriteKey(uint32_t*, const GrStyle&, Apply, SkScalar scale, uint32_t flags = 0);
  67. GrStyle() : GrStyle(SkStrokeRec::kFill_InitStyle) {}
  68. explicit GrStyle(SkStrokeRec::InitStyle initStyle) : fStrokeRec(initStyle) {}
  69. GrStyle(const SkStrokeRec& strokeRec, sk_sp<SkPathEffect> pe) : fStrokeRec(strokeRec) {
  70. this->initPathEffect(std::move(pe));
  71. }
  72. GrStyle(const GrStyle& that) = default;
  73. explicit GrStyle(const SkPaint& paint) : fStrokeRec(paint) {
  74. this->initPathEffect(paint.refPathEffect());
  75. }
  76. explicit GrStyle(const SkPaint& paint, SkPaint::Style overrideStyle)
  77. : fStrokeRec(paint, overrideStyle) {
  78. this->initPathEffect(paint.refPathEffect());
  79. }
  80. GrStyle& operator=(const GrStyle& that) {
  81. fPathEffect = that.fPathEffect;
  82. fDashInfo = that.fDashInfo;
  83. fStrokeRec = that.fStrokeRec;
  84. return *this;
  85. }
  86. void resetToInitStyle(SkStrokeRec::InitStyle fillOrHairline) {
  87. fDashInfo.reset();
  88. fPathEffect.reset(nullptr);
  89. if (SkStrokeRec::kFill_InitStyle == fillOrHairline) {
  90. fStrokeRec.setFillStyle();
  91. } else {
  92. fStrokeRec.setHairlineStyle();
  93. }
  94. }
  95. /** Is this style a fill with no path effect? */
  96. bool isSimpleFill() const { return fStrokeRec.isFillStyle() && !fPathEffect; }
  97. /** Is this style a hairline with no path effect? */
  98. bool isSimpleHairline() const { return fStrokeRec.isHairlineStyle() && !fPathEffect; }
  99. SkPathEffect* pathEffect() const { return fPathEffect.get(); }
  100. sk_sp<SkPathEffect> refPathEffect() const { return fPathEffect; }
  101. bool hasPathEffect() const { return SkToBool(fPathEffect.get()); }
  102. bool hasNonDashPathEffect() const { return fPathEffect.get() && !this->isDashed(); }
  103. bool isDashed() const { return SkPathEffect::kDash_DashType == fDashInfo.fType; }
  104. SkScalar dashPhase() const {
  105. SkASSERT(this->isDashed());
  106. return fDashInfo.fPhase;
  107. }
  108. int dashIntervalCnt() const {
  109. SkASSERT(this->isDashed());
  110. return fDashInfo.fIntervals.count();
  111. }
  112. const SkScalar* dashIntervals() const {
  113. SkASSERT(this->isDashed());
  114. return fDashInfo.fIntervals.get();
  115. }
  116. const SkStrokeRec& strokeRec() const { return fStrokeRec; }
  117. /** Hairline or fill styles without path effects make no alterations to a geometry. */
  118. bool applies() const {
  119. return this->pathEffect() || (!fStrokeRec.isFillStyle() && !fStrokeRec.isHairlineStyle());
  120. }
  121. static SkScalar MatrixToScaleFactor(const SkMatrix& matrix) {
  122. // getMaxScale will return -1 if the matrix has perspective. In that case we can use a scale
  123. // factor of 1. This isn't necessarily a good choice and in the future we might consider
  124. // taking a bounds here for the perspective case.
  125. return SkScalarAbs(matrix.getMaxScale());
  126. }
  127. /**
  128. * Applies just the path effect and returns remaining stroke information. This will fail if
  129. * there is no path effect. dst may or may not have been overwritten on failure. Scale controls
  130. * geometric approximations made by the path effect. It is typically computed from the view
  131. * matrix.
  132. */
  133. bool SK_WARN_UNUSED_RESULT applyPathEffectToPath(SkPath* dst, SkStrokeRec* remainingStoke,
  134. const SkPath& src, SkScalar scale) const;
  135. /**
  136. * If this succeeds then the result path should be filled or hairlined as indicated by the
  137. * returned SkStrokeRec::InitStyle value. Will fail if there is no path effect and the
  138. * strokerec doesn't change the geometry. When this fails the outputs may or may not have
  139. * been overwritten. Scale controls geometric approximations made by the path effect and
  140. * stroker. It is typically computed from the view matrix.
  141. */
  142. bool SK_WARN_UNUSED_RESULT applyToPath(SkPath* dst, SkStrokeRec::InitStyle* fillOrHairline,
  143. const SkPath& src, SkScalar scale) const;
  144. /** Given bounds of a path compute the bounds of path with the style applied. */
  145. void adjustBounds(SkRect* dst, const SkRect& src) const {
  146. if (this->pathEffect()) {
  147. this->pathEffect()->computeFastBounds(dst, src);
  148. // This may not be the correct SkStrokeRec to use. skbug.com/5299
  149. // It happens to work for dashing.
  150. SkScalar radius = fStrokeRec.getInflationRadius();
  151. dst->outset(radius, radius);
  152. } else {
  153. SkScalar radius = fStrokeRec.getInflationRadius();
  154. *dst = src.makeOutset(radius, radius);
  155. }
  156. }
  157. private:
  158. void initPathEffect(sk_sp<SkPathEffect> pe);
  159. struct DashInfo {
  160. DashInfo() : fType(SkPathEffect::kNone_DashType) {}
  161. DashInfo(const DashInfo& that) { *this = that; }
  162. DashInfo& operator=(const DashInfo& that) {
  163. fType = that.fType;
  164. fPhase = that.fPhase;
  165. fIntervals.reset(that.fIntervals.count());
  166. sk_careful_memcpy(fIntervals.get(), that.fIntervals.get(),
  167. sizeof(SkScalar) * that.fIntervals.count());
  168. return *this;
  169. }
  170. void reset() {
  171. fType = SkPathEffect::kNone_DashType;
  172. fIntervals.reset(0);
  173. }
  174. SkPathEffect::DashType fType;
  175. SkScalar fPhase{0};
  176. SkAutoSTArray<4, SkScalar> fIntervals;
  177. };
  178. bool applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const;
  179. SkStrokeRec fStrokeRec;
  180. sk_sp<SkPathEffect> fPathEffect;
  181. DashInfo fDashInfo;
  182. };
  183. #endif