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
14class SkPath;
15
16SK_BEGIN_REQUIRE_DENSE
17class SK_API SkStrokeRec {
18public:
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
136private:
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};
152SK_END_REQUIRE_DENSE
153
154#endif
155