blob: 6480fb341a48a61219bc31488607d645d6dd08e8 [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"
9
bsalomon06077562016-05-04 13:50:29 -070010int GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) {
bsalomonfb083272016-05-04 08:27:41 -070011 GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
12 int size = 0;
13 if (style.isDashed()) {
14 // One scalar for dash phase and one for each dash value.
15 size += 1 + style.dashIntervalCnt();
16 } else if (style.pathEffect()) {
17 // No key for a generic path effect.
18 return -1;
19 }
20
21 if (Apply::kPathEffectOnly == apply) {
22 return size;
23 }
24
25 if (style.strokeRec().needToApply()) {
26 // One for style/cap/join, 2 for miter and width.
27 size += 3;
28 }
29 return size;
30}
31
bsalomon06077562016-05-04 13:50:29 -070032void GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, uint32_t flags) {
bsalomonfb083272016-05-04 08:27:41 -070033 SkASSERT(key);
34 SkASSERT(KeySize(style, apply) >= 0);
35 GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
36
37 int i = 0;
38 if (style.isDashed()) {
39 GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t));
40 SkScalar phase = style.dashPhase();
41 memcpy(&key[i++], &phase, sizeof(SkScalar));
42
43 int32_t count = style.dashIntervalCnt();
44 // Dash count should always be even.
45 SkASSERT(0 == (count & 0x1));
46 const SkScalar *intervals = style.dashIntervals();
47 int intervalByteCnt = count * sizeof(SkScalar);
48 memcpy(&key[i], intervals, intervalByteCnt);
49 i += count;
50 } else {
51 SkASSERT(!style.pathEffect());
52 }
53
54 if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) {
55 enum {
56 kStyleBits = 2,
57 kJoinBits = 2,
58 kCapBits = 32 - kStyleBits - kJoinBits,
59
60 kJoinShift = kStyleBits,
61 kCapShift = kJoinShift + kJoinBits,
62 };
63 GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
64 GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits));
65 GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits));
bsalomon06077562016-05-04 13:50:29 -070066 // The cap type only matters for unclosed shapes. However, a path effect could unclose
67 // the shape before it is stroked.
68 SkPaint::Cap cap;
69 if ((flags & kClosed_KeyFlag) && !style.pathEffect()) {
70 cap = SkPaint::kButt_Cap;
71 } else {
72 cap = style.strokeRec().getCap();
73 }
bsalomonfb083272016-05-04 08:27:41 -070074 key[i++] = style.strokeRec().getStyle() |
75 style.strokeRec().getJoin() << kJoinShift |
bsalomon06077562016-05-04 13:50:29 -070076 cap << kCapShift;
bsalomonfb083272016-05-04 08:27:41 -070077
78 SkScalar scalar;
79 // Miter limit only affects miter joins
80 scalar = SkPaint::kMiter_Join == style.strokeRec().getJoin()
81 ? style.strokeRec().getMiter()
82 : -1.f;
83 memcpy(&key[i++], &scalar, sizeof(scalar));
84
85 scalar = style.strokeRec().getWidth();
86 memcpy(&key[i++], &scalar, sizeof(scalar));
87 }
88 SkASSERT(KeySize(style, apply) == i);
89}
90
bsalomon308feba2016-05-03 10:11:55 -070091void GrStyle::initPathEffect(SkPathEffect* pe) {
bsalomonfb083272016-05-04 08:27:41 -070092 SkASSERT(!fPathEffect)
93 SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType);
94 SkASSERT(0 == fDashInfo.fIntervals.count());
bsalomon47cc7692016-04-26 12:56:00 -070095 if (!pe) {
bsalomon47cc7692016-04-26 12:56:00 -070096 return;
97 }
98 SkPathEffect::DashInfo info;
99 if (SkPathEffect::kDash_DashType == pe->asADash(&info)) {
bsalomonfb083272016-05-04 08:27:41 -0700100 if (fStrokeRec.getStyle() != SkStrokeRec::kFill_Style) {
bsalomon47cc7692016-04-26 12:56:00 -0700101 fDashInfo.fType = SkPathEffect::kDash_DashType;
102 fDashInfo.fIntervals.reset(info.fCount);
103 fDashInfo.fPhase = info.fPhase;
104 info.fIntervals = fDashInfo.fIntervals.get();
105 pe->asADash(&info);
bsalomonfb083272016-05-04 08:27:41 -0700106 fPathEffect.reset(SkSafeRef(pe));
bsalomon47cc7692016-04-26 12:56:00 -0700107 }
108 } else {
bsalomon308feba2016-05-03 10:11:55 -0700109 fPathEffect.reset(SkSafeRef(pe));
bsalomon47cc7692016-04-26 12:56:00 -0700110 }
bsalomonfb083272016-05-04 08:27:41 -0700111}
112
113static inline bool apply_path_effect(SkPath* dst, SkStrokeRec* strokeRec,
114 const sk_sp<SkPathEffect>& pe, const SkPath& src) {
115 if (!pe) {
116 return false;
117 }
118 if (!pe->filterPath(dst, src, strokeRec, nullptr)) {
119 return false;
120 }
121 dst->setIsVolatile(true);
122 return true;
123}
124
125bool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke,
126 const SkPath &src) const {
127 SkASSERT(dst);
128 SkStrokeRec strokeRec = fStrokeRec;
129 if (!apply_path_effect(dst, &strokeRec, fPathEffect, src)) {
130 return false;
131 }
132 *remainingStroke = strokeRec;
133 return true;
134}
135
136bool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src) const {
137 SkASSERT(style);
138 SkASSERT(dst);
139 SkStrokeRec strokeRec = fStrokeRec;
140 if (!apply_path_effect(dst, &strokeRec, fPathEffect, src)) {
141 return false;
142 }
143 if (strokeRec.needToApply()) {
144 if (!strokeRec.applyToPath(dst, *dst)) {
145 return false;
146 }
147 *style = SkStrokeRec::kFill_InitStyle;
148 } else {
149 SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() ||
150 SkStrokeRec::kHairline_Style == strokeRec.getStyle());
151 *style = strokeRec.getStyle() == SkStrokeRec::kFill_Style
152 ? SkStrokeRec::kFill_InitStyle
153 : SkStrokeRec::kHairline_InitStyle;
154 }
155 return true;
bsalomon47cc7692016-04-26 12:56:00 -0700156}