blob: 10a0debe4e4dcf9b9078bbdaaef787042eede440 [file] [log] [blame]
bsalomon47cc7692016-04-26 12:56:00 -07001/*
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
8#include "GrStyle.h"
bsalomon398e3f42016-06-13 10:22:48 -07009#include "SkDashPathPriv.h"
bsalomon47cc7692016-04-26 12:56:00 -070010
bsalomon06077562016-05-04 13:50:29 -070011int GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) {
bsalomonfb083272016-05-04 08:27:41 -070012 GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
13 int size = 0;
14 if (style.isDashed()) {
bsalomon97fd2d42016-05-09 13:02:01 -070015 // One scalar for scale, one for dash phase, and one for each dash value.
16 size += 2 + style.dashIntervalCnt();
bsalomonfb083272016-05-04 08:27:41 -070017 } else if (style.pathEffect()) {
18 // No key for a generic path effect.
19 return -1;
20 }
21
22 if (Apply::kPathEffectOnly == apply) {
23 return size;
24 }
25
26 if (style.strokeRec().needToApply()) {
bsalomon97fd2d42016-05-09 13:02:01 -070027 // One for res scale, one for style/cap/join, one for miter limit, and one for width.
28 size += 4;
bsalomonfb083272016-05-04 08:27:41 -070029 }
30 return size;
31}
32
bsalomon97fd2d42016-05-09 13:02:01 -070033void GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, SkScalar scale,
34 uint32_t flags) {
bsalomonfb083272016-05-04 08:27:41 -070035 SkASSERT(key);
36 SkASSERT(KeySize(style, apply) >= 0);
37 GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
38
39 int i = 0;
bsalomon97fd2d42016-05-09 13:02:01 -070040 // The scale can influence both the path effect and stroking. We want to preserve the
41 // property that the following two are equal:
42 // 1. WriteKey with apply == kPathEffectAndStrokeRec
43 // 2. WriteKey with apply == kPathEffectOnly followed by WriteKey of a GrStyle made
44 // from SkStrokeRec output by the the path effect (and no additional path effect).
45 // Since the scale can affect both parts of 2 we write it into the key twice.
bsalomonfb083272016-05-04 08:27:41 -070046 if (style.isDashed()) {
47 GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t));
48 SkScalar phase = style.dashPhase();
bsalomon97fd2d42016-05-09 13:02:01 -070049 memcpy(&key[i++], &scale, sizeof(SkScalar));
bsalomonfb083272016-05-04 08:27:41 -070050 memcpy(&key[i++], &phase, sizeof(SkScalar));
51
52 int32_t count = style.dashIntervalCnt();
53 // Dash count should always be even.
54 SkASSERT(0 == (count & 0x1));
55 const SkScalar *intervals = style.dashIntervals();
56 int intervalByteCnt = count * sizeof(SkScalar);
57 memcpy(&key[i], intervals, intervalByteCnt);
58 i += count;
59 } else {
60 SkASSERT(!style.pathEffect());
61 }
62
63 if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) {
bsalomon97fd2d42016-05-09 13:02:01 -070064 memcpy(&key[i++], &scale, sizeof(SkScalar));
bsalomonfb083272016-05-04 08:27:41 -070065 enum {
66 kStyleBits = 2,
67 kJoinBits = 2,
68 kCapBits = 32 - kStyleBits - kJoinBits,
69
70 kJoinShift = kStyleBits,
71 kCapShift = kJoinShift + kJoinBits,
72 };
73 GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
74 GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits));
75 GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits));
bsalomon06077562016-05-04 13:50:29 -070076 // The cap type only matters for unclosed shapes. However, a path effect could unclose
77 // the shape before it is stroked.
78 SkPaint::Cap cap;
79 if ((flags & kClosed_KeyFlag) && !style.pathEffect()) {
80 cap = SkPaint::kButt_Cap;
81 } else {
82 cap = style.strokeRec().getCap();
83 }
bsalomonfb083272016-05-04 08:27:41 -070084 key[i++] = style.strokeRec().getStyle() |
85 style.strokeRec().getJoin() << kJoinShift |
bsalomon06077562016-05-04 13:50:29 -070086 cap << kCapShift;
bsalomonfb083272016-05-04 08:27:41 -070087
88 SkScalar scalar;
89 // Miter limit only affects miter joins
90 scalar = SkPaint::kMiter_Join == style.strokeRec().getJoin()
91 ? style.strokeRec().getMiter()
92 : -1.f;
93 memcpy(&key[i++], &scalar, sizeof(scalar));
94
95 scalar = style.strokeRec().getWidth();
96 memcpy(&key[i++], &scalar, sizeof(scalar));
97 }
98 SkASSERT(KeySize(style, apply) == i);
99}
100
bsalomon308feba2016-05-03 10:11:55 -0700101void GrStyle::initPathEffect(SkPathEffect* pe) {
bsalomonfb083272016-05-04 08:27:41 -0700102 SkASSERT(!fPathEffect)
103 SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType);
104 SkASSERT(0 == fDashInfo.fIntervals.count());
bsalomon47cc7692016-04-26 12:56:00 -0700105 if (!pe) {
bsalomon47cc7692016-04-26 12:56:00 -0700106 return;
107 }
108 SkPathEffect::DashInfo info;
109 if (SkPathEffect::kDash_DashType == pe->asADash(&info)) {
bsalomona0587862016-06-09 06:03:38 -0700110 SkStrokeRec::Style recStyle = fStrokeRec.getStyle();
111 if (recStyle != SkStrokeRec::kFill_Style && recStyle != SkStrokeRec::kStrokeAndFill_Style) {
bsalomon47cc7692016-04-26 12:56:00 -0700112 fDashInfo.fType = SkPathEffect::kDash_DashType;
113 fDashInfo.fIntervals.reset(info.fCount);
114 fDashInfo.fPhase = info.fPhase;
115 info.fIntervals = fDashInfo.fIntervals.get();
116 pe->asADash(&info);
bsalomonfb083272016-05-04 08:27:41 -0700117 fPathEffect.reset(SkSafeRef(pe));
bsalomon47cc7692016-04-26 12:56:00 -0700118 }
119 } else {
bsalomon308feba2016-05-03 10:11:55 -0700120 fPathEffect.reset(SkSafeRef(pe));
bsalomon47cc7692016-04-26 12:56:00 -0700121 }
bsalomonfb083272016-05-04 08:27:41 -0700122}
123
bsalomon398e3f42016-06-13 10:22:48 -0700124bool GrStyle::applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const {
125 if (!fPathEffect) {
bsalomonfb083272016-05-04 08:27:41 -0700126 return false;
127 }
bsalomon398e3f42016-06-13 10:22:48 -0700128 if (SkPathEffect::kDash_DashType == fDashInfo.fType) {
129 // We apply the dash ourselves here rather than using the path effect. This is so that
130 // we can control whether the dasher applies the strokeRec for special cases. Our keying
131 // depends on the strokeRec being applied separately.
132 SkScalar phase = fDashInfo.fPhase;
133 const SkScalar* intervals = fDashInfo.fIntervals.get();
134 int intervalCnt = fDashInfo.fIntervals.count();
135 SkScalar initialLength;
136 int initialIndex;
137 SkScalar intervalLength;
138 SkDashPath::CalcDashParameters(phase, intervals, intervalCnt, &initialLength,
139 &initialIndex, &intervalLength);
140 if (!SkDashPath::InternalFilter(dst, src, strokeRec,
141 nullptr, intervals, intervalCnt,
142 initialLength, initialIndex, intervalLength,
143 SkDashPath::StrokeRecApplication::kDisallow)) {
144 return false;
145 }
146 } else if (!fPathEffect->filterPath(dst, src, strokeRec, nullptr)) {
bsalomonfb083272016-05-04 08:27:41 -0700147 return false;
148 }
149 dst->setIsVolatile(true);
150 return true;
151}
152
153bool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke,
bsalomon97fd2d42016-05-09 13:02:01 -0700154 const SkPath &src, SkScalar resScale) const {
bsalomonfb083272016-05-04 08:27:41 -0700155 SkASSERT(dst);
156 SkStrokeRec strokeRec = fStrokeRec;
bsalomon97fd2d42016-05-09 13:02:01 -0700157 strokeRec.setResScale(resScale);
bsalomon398e3f42016-06-13 10:22:48 -0700158 if (!this->applyPathEffect(dst, &strokeRec, src)) {
bsalomonfb083272016-05-04 08:27:41 -0700159 return false;
160 }
161 *remainingStroke = strokeRec;
162 return true;
163}
164
bsalomon97fd2d42016-05-09 13:02:01 -0700165bool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src,
166 SkScalar resScale) const {
bsalomonfb083272016-05-04 08:27:41 -0700167 SkASSERT(style);
168 SkASSERT(dst);
169 SkStrokeRec strokeRec = fStrokeRec;
bsalomon97fd2d42016-05-09 13:02:01 -0700170 strokeRec.setResScale(resScale);
bsalomon1a0b9ed2016-05-06 11:07:03 -0700171 const SkPath* pathForStrokeRec = &src;
bsalomon398e3f42016-06-13 10:22:48 -0700172 if (this->applyPathEffect(dst, &strokeRec, src)) {
bsalomon1a0b9ed2016-05-06 11:07:03 -0700173 pathForStrokeRec = dst;
174 } else if (fPathEffect) {
bsalomonfb083272016-05-04 08:27:41 -0700175 return false;
176 }
177 if (strokeRec.needToApply()) {
bsalomon1a0b9ed2016-05-06 11:07:03 -0700178 if (!strokeRec.applyToPath(dst, *pathForStrokeRec)) {
bsalomonfb083272016-05-04 08:27:41 -0700179 return false;
180 }
181 *style = SkStrokeRec::kFill_InitStyle;
bsalomon1a0b9ed2016-05-06 11:07:03 -0700182 } else if (!fPathEffect) {
183 // Nothing to do for path effect or stroke, fail.
184 return false;
bsalomonfb083272016-05-04 08:27:41 -0700185 } else {
186 SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() ||
187 SkStrokeRec::kHairline_Style == strokeRec.getStyle());
188 *style = strokeRec.getStyle() == SkStrokeRec::kFill_Style
189 ? SkStrokeRec::kFill_InitStyle
190 : SkStrokeRec::kHairline_InitStyle;
191 }
192 return true;
bsalomon47cc7692016-04-26 12:56:00 -0700193}