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