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