GrStyle.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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/GrStyle.h"
  8. #include "src/utils/SkDashPathPriv.h"
  9. int GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) {
  10. GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
  11. int size = 0;
  12. if (style.isDashed()) {
  13. // One scalar for scale, one for dash phase, and one for each dash value.
  14. size += 2 + style.dashIntervalCnt();
  15. } else if (style.pathEffect()) {
  16. // No key for a generic path effect.
  17. return -1;
  18. }
  19. if (Apply::kPathEffectOnly == apply) {
  20. return size;
  21. }
  22. if (style.strokeRec().needToApply()) {
  23. // One for res scale, one for style/cap/join, one for miter limit, and one for width.
  24. size += 4;
  25. }
  26. return size;
  27. }
  28. void GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, SkScalar scale,
  29. uint32_t flags) {
  30. SkASSERT(key);
  31. SkASSERT(KeySize(style, apply) >= 0);
  32. GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
  33. int i = 0;
  34. // The scale can influence both the path effect and stroking. We want to preserve the
  35. // property that the following two are equal:
  36. // 1. WriteKey with apply == kPathEffectAndStrokeRec
  37. // 2. WriteKey with apply == kPathEffectOnly followed by WriteKey of a GrStyle made
  38. // from SkStrokeRec output by the the path effect (and no additional path effect).
  39. // Since the scale can affect both parts of 2 we write it into the key twice.
  40. if (style.isDashed()) {
  41. GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t));
  42. SkScalar phase = style.dashPhase();
  43. memcpy(&key[i++], &scale, sizeof(SkScalar));
  44. memcpy(&key[i++], &phase, sizeof(SkScalar));
  45. int32_t count = style.dashIntervalCnt();
  46. // Dash count should always be even.
  47. SkASSERT(0 == (count & 0x1));
  48. const SkScalar *intervals = style.dashIntervals();
  49. int intervalByteCnt = count * sizeof(SkScalar);
  50. memcpy(&key[i], intervals, intervalByteCnt);
  51. i += count;
  52. } else {
  53. SkASSERT(!style.pathEffect());
  54. }
  55. if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) {
  56. memcpy(&key[i++], &scale, sizeof(SkScalar));
  57. enum {
  58. kStyleBits = 2,
  59. kJoinBits = 2,
  60. kCapBits = 32 - kStyleBits - kJoinBits,
  61. kJoinShift = kStyleBits,
  62. kCapShift = kJoinShift + kJoinBits,
  63. };
  64. GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
  65. GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits));
  66. GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits));
  67. // The cap type only matters for unclosed shapes. However, a path effect could unclose
  68. // the shape before it is stroked.
  69. SkPaint::Cap cap = SkPaint::kDefault_Cap;
  70. if (!(flags & kClosed_KeyFlag) || style.pathEffect()) {
  71. cap = style.strokeRec().getCap();
  72. }
  73. SkScalar miter = -1.f;
  74. SkPaint::Join join = SkPaint::kDefault_Join;
  75. // Dashing will not insert joins but other path effects may.
  76. if (!(flags & kNoJoins_KeyFlag) || style.hasNonDashPathEffect()) {
  77. join = style.strokeRec().getJoin();
  78. // Miter limit only affects miter joins
  79. if (SkPaint::kMiter_Join == join) {
  80. miter = style.strokeRec().getMiter();
  81. }
  82. }
  83. key[i++] = style.strokeRec().getStyle() |
  84. join << kJoinShift |
  85. cap << kCapShift;
  86. memcpy(&key[i++], &miter, sizeof(miter));
  87. SkScalar width = style.strokeRec().getWidth();
  88. memcpy(&key[i++], &width, sizeof(width));
  89. }
  90. SkASSERT(KeySize(style, apply) == i);
  91. }
  92. void GrStyle::initPathEffect(sk_sp<SkPathEffect> pe) {
  93. SkASSERT(!fPathEffect);
  94. SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType);
  95. SkASSERT(0 == fDashInfo.fIntervals.count());
  96. if (!pe) {
  97. return;
  98. }
  99. SkPathEffect::DashInfo info;
  100. if (SkPathEffect::kDash_DashType == pe->asADash(&info)) {
  101. SkStrokeRec::Style recStyle = fStrokeRec.getStyle();
  102. if (recStyle != SkStrokeRec::kFill_Style && recStyle != SkStrokeRec::kStrokeAndFill_Style) {
  103. fDashInfo.fType = SkPathEffect::kDash_DashType;
  104. fDashInfo.fIntervals.reset(info.fCount);
  105. fDashInfo.fPhase = info.fPhase;
  106. info.fIntervals = fDashInfo.fIntervals.get();
  107. pe->asADash(&info);
  108. fPathEffect = std::move(pe);
  109. }
  110. } else {
  111. fPathEffect = std::move(pe);
  112. }
  113. }
  114. bool GrStyle::applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const {
  115. if (!fPathEffect) {
  116. return false;
  117. }
  118. if (SkPathEffect::kDash_DashType == fDashInfo.fType) {
  119. // We apply the dash ourselves here rather than using the path effect. This is so that
  120. // we can control whether the dasher applies the strokeRec for special cases. Our keying
  121. // depends on the strokeRec being applied separately.
  122. SkScalar phase = fDashInfo.fPhase;
  123. const SkScalar* intervals = fDashInfo.fIntervals.get();
  124. int intervalCnt = fDashInfo.fIntervals.count();
  125. SkScalar initialLength;
  126. int initialIndex;
  127. SkScalar intervalLength;
  128. SkDashPath::CalcDashParameters(phase, intervals, intervalCnt, &initialLength,
  129. &initialIndex, &intervalLength);
  130. if (!SkDashPath::InternalFilter(dst, src, strokeRec,
  131. nullptr, intervals, intervalCnt,
  132. initialLength, initialIndex, intervalLength,
  133. SkDashPath::StrokeRecApplication::kDisallow)) {
  134. return false;
  135. }
  136. } else if (!fPathEffect->filterPath(dst, src, strokeRec, nullptr)) {
  137. return false;
  138. }
  139. dst->setIsVolatile(true);
  140. return true;
  141. }
  142. bool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke,
  143. const SkPath &src, SkScalar resScale) const {
  144. SkASSERT(dst);
  145. SkStrokeRec strokeRec = fStrokeRec;
  146. strokeRec.setResScale(resScale);
  147. if (!this->applyPathEffect(dst, &strokeRec, src)) {
  148. return false;
  149. }
  150. *remainingStroke = strokeRec;
  151. return true;
  152. }
  153. bool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src,
  154. SkScalar resScale) const {
  155. SkASSERT(style);
  156. SkASSERT(dst);
  157. SkStrokeRec strokeRec = fStrokeRec;
  158. strokeRec.setResScale(resScale);
  159. const SkPath* pathForStrokeRec = &src;
  160. if (this->applyPathEffect(dst, &strokeRec, src)) {
  161. pathForStrokeRec = dst;
  162. } else if (fPathEffect) {
  163. return false;
  164. }
  165. if (strokeRec.needToApply()) {
  166. if (!strokeRec.applyToPath(dst, *pathForStrokeRec)) {
  167. return false;
  168. }
  169. dst->setIsVolatile(true);
  170. *style = SkStrokeRec::kFill_InitStyle;
  171. } else if (!fPathEffect) {
  172. // Nothing to do for path effect or stroke, fail.
  173. return false;
  174. } else {
  175. SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() ||
  176. SkStrokeRec::kHairline_Style == strokeRec.getStyle());
  177. *style = strokeRec.getStyle() == SkStrokeRec::kFill_Style
  178. ? SkStrokeRec::kFill_InitStyle
  179. : SkStrokeRec::kHairline_InitStyle;
  180. }
  181. return true;
  182. }