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