1 | /* |
2 | * Copyright 2012 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 SkStrokeRec_DEFINED |
9 | #define SkStrokeRec_DEFINED |
10 | |
11 | #include "include/core/SkPaint.h" |
12 | #include "include/private/SkMacros.h" |
13 | |
14 | class SkPath; |
15 | |
16 | SK_BEGIN_REQUIRE_DENSE |
17 | class SK_API SkStrokeRec { |
18 | public: |
19 | enum InitStyle { |
20 | kHairline_InitStyle, |
21 | kFill_InitStyle |
22 | }; |
23 | SkStrokeRec(InitStyle style); |
24 | SkStrokeRec(const SkPaint&, SkPaint::Style, SkScalar resScale = 1); |
25 | explicit SkStrokeRec(const SkPaint&, SkScalar resScale = 1); |
26 | |
27 | enum Style { |
28 | kHairline_Style, |
29 | kFill_Style, |
30 | kStroke_Style, |
31 | kStrokeAndFill_Style |
32 | }; |
33 | |
34 | static constexpr int kStyleCount = kStrokeAndFill_Style + 1; |
35 | |
36 | Style getStyle() const; |
37 | SkScalar getWidth() const { return fWidth; } |
38 | SkScalar getMiter() const { return fMiterLimit; } |
39 | SkPaint::Cap getCap() const { return (SkPaint::Cap)fCap; } |
40 | SkPaint::Join getJoin() const { return (SkPaint::Join)fJoin; } |
41 | |
42 | bool isHairlineStyle() const { |
43 | return kHairline_Style == this->getStyle(); |
44 | } |
45 | |
46 | bool isFillStyle() const { |
47 | return kFill_Style == this->getStyle(); |
48 | } |
49 | |
50 | void setFillStyle(); |
51 | void setHairlineStyle(); |
52 | /** |
53 | * Specify the strokewidth, and optionally if you want stroke + fill. |
54 | * Note, if width==0, then this request is taken to mean: |
55 | * strokeAndFill==true -> new style will be Fill |
56 | * strokeAndFill==false -> new style will be Hairline |
57 | */ |
58 | void setStrokeStyle(SkScalar width, bool strokeAndFill = false); |
59 | |
60 | void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) { |
61 | fCap = cap; |
62 | fJoin = join; |
63 | fMiterLimit = miterLimit; |
64 | } |
65 | |
66 | SkScalar getResScale() const { |
67 | return fResScale; |
68 | } |
69 | |
70 | void setResScale(SkScalar rs) { |
71 | SkASSERT(rs > 0 && SkScalarIsFinite(rs)); |
72 | fResScale = rs; |
73 | } |
74 | |
75 | /** |
76 | * Returns true if this specifes any thick stroking, i.e. applyToPath() |
77 | * will return true. |
78 | */ |
79 | bool needToApply() const { |
80 | Style style = this->getStyle(); |
81 | return (kStroke_Style == style) || (kStrokeAndFill_Style == style); |
82 | } |
83 | |
84 | /** |
85 | * Apply these stroke parameters to the src path, returning the result |
86 | * in dst. |
87 | * |
88 | * If there was no change (i.e. style == hairline or fill) this returns |
89 | * false and dst is unchanged. Otherwise returns true and the result is |
90 | * stored in dst. |
91 | * |
92 | * src and dst may be the same path. |
93 | */ |
94 | bool applyToPath(SkPath* dst, const SkPath& src) const; |
95 | |
96 | /** |
97 | * Apply these stroke parameters to a paint. |
98 | */ |
99 | void applyToPaint(SkPaint* paint) const; |
100 | |
101 | /** |
102 | * Gives a conservative value for the outset that should applied to a |
103 | * geometries bounds to account for any inflation due to applying this |
104 | * strokeRec to the geometry. |
105 | */ |
106 | SkScalar getInflationRadius() const; |
107 | |
108 | /** |
109 | * Equivalent to: |
110 | * SkStrokeRec rec(paint, style); |
111 | * rec.getInflationRadius(); |
112 | * This does not account for other effects on the paint (i.e. path |
113 | * effect). |
114 | */ |
115 | static SkScalar GetInflationRadius(const SkPaint&, SkPaint::Style); |
116 | |
117 | static SkScalar GetInflationRadius(SkPaint::Join, SkScalar miterLimit, SkPaint::Cap, |
118 | SkScalar strokeWidth); |
119 | |
120 | /** |
121 | * Compare if two SkStrokeRecs have an equal effect on a path. |
122 | * Equal SkStrokeRecs produce equal paths. Equality of produced |
123 | * paths does not take the ResScale parameter into account. |
124 | */ |
125 | bool hasEqualEffect(const SkStrokeRec& other) const { |
126 | if (!this->needToApply()) { |
127 | return this->getStyle() == other.getStyle(); |
128 | } |
129 | return fWidth == other.fWidth && |
130 | fMiterLimit == other.fMiterLimit && |
131 | fCap == other.fCap && |
132 | fJoin == other.fJoin && |
133 | fStrokeAndFill == other.fStrokeAndFill; |
134 | } |
135 | |
136 | private: |
137 | void init(const SkPaint&, SkPaint::Style, SkScalar resScale); |
138 | |
139 | SkScalar fResScale; |
140 | SkScalar fWidth; |
141 | SkScalar fMiterLimit; |
142 | // The following three members are packed together into a single u32. |
143 | // This is to avoid unnecessary padding and ensure binary equality for |
144 | // hashing (because the padded areas might contain garbage values). |
145 | // |
146 | // fCap and fJoin are larger than needed to avoid having to initialize |
147 | // any pad values |
148 | uint32_t fCap : 16; // SkPaint::Cap |
149 | uint32_t fJoin : 15; // SkPaint::Join |
150 | uint32_t fStrokeAndFill : 1; // bool |
151 | }; |
152 | SK_END_REQUIRE_DENSE |
153 | |
154 | #endif |
155 | |