• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
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 #include "include/core/SkPaint.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBlendMode.h"
12 #include "include/core/SkBlender.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkImageFilter.h"
15 #include "include/core/SkMaskFilter.h"
16 #include "include/core/SkPathEffect.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkScalar.h"
19 #include "include/core/SkShader.h"
20 #include "include/core/SkStrokeRec.h"
21 #include "include/private/base/SkTPin.h"
22 #include "include/private/base/SkTo.h"
23 #include "src/core/SkBlenderBase.h"
24 #include "src/core/SkColorFilterBase.h"
25 #include "src/core/SkColorSpacePriv.h"
26 #include "src/core/SkColorSpaceXformSteps.h"
27 #include "src/core/SkMaskFilterBase.h"
28 #include "src/core/SkPaintDefaults.h"
29 #include "src/core/SkPathEffectBase.h"
30 
31 #include <utility>
32 
33 // define this to get a printf for out-of-range parameter in setters
34 // e.g. setTextSize(-1)
35 //#define SK_REPORT_API_RANGE_CHECK
36 
37 
SkPaint()38 SkPaint::SkPaint()
39     : fColor4f{0, 0, 0, 1}  // opaque black
40     , fWidth{0}
41     , fMiterLimit{SkPaintDefaults_MiterLimit}
42     , fBitfields{(unsigned)false,                   // fAntiAlias
43                  (unsigned)false,                   // fDither
44                  (unsigned)SkPaint::kDefault_Cap,   // fCapType
45                  (unsigned)SkPaint::kDefault_Join,  // fJoinType
46                  (unsigned)SkPaint::kFill_Style,    // fStyle
47                  0}                                 // fPadding
48 {
49     static_assert(sizeof(fBitfields) == sizeof(fBitfieldsUInt), "");
50 }
51 
SkPaint(const SkColor4f & color,SkColorSpace * colorSpace)52 SkPaint::SkPaint(const SkColor4f& color, SkColorSpace* colorSpace) : SkPaint() {
53     this->setColor(color, colorSpace);
54 }
55 
56 SkPaint::SkPaint(const SkPaint& src) = default;
57 
58 SkPaint::SkPaint(SkPaint&& src) = default;
59 
60 SkPaint::~SkPaint() = default;
61 
62 SkPaint& SkPaint::operator=(const SkPaint& src) = default;
63 
64 SkPaint& SkPaint::operator=(SkPaint&& src) = default;
65 
operator ==(const SkPaint & a,const SkPaint & b)66 bool operator==(const SkPaint& a, const SkPaint& b) {
67 #define EQUAL(field) (a.field == b.field)
68     return EQUAL(fPathEffect)
69         && EQUAL(fShader)
70         && EQUAL(fMaskFilter)
71         && EQUAL(fColorFilter)
72         && EQUAL(fBlender)
73         && EQUAL(fImageFilter)
74         && EQUAL(fColor4f)
75         && EQUAL(fWidth)
76         && EQUAL(fMiterLimit)
77         && EQUAL(fBitfieldsUInt)
78         ;
79 #undef EQUAL
80 }
81 
82 #define DEFINE_FIELD_REF(type) \
83     sk_sp<Sk##type> SkPaint::ref##type() const { return f##type; }
84 DEFINE_FIELD_REF(ColorFilter)
DEFINE_FIELD_REF(Blender)85 DEFINE_FIELD_REF(Blender)
86 DEFINE_FIELD_REF(ImageFilter)
87 DEFINE_FIELD_REF(MaskFilter)
88 DEFINE_FIELD_REF(PathEffect)
89 DEFINE_FIELD_REF(Shader)
90 #undef DEFINE_FIELD_REF
91 
92 #define DEFINE_FIELD_SET(Field) \
93     void SkPaint::set##Field(sk_sp<Sk##Field> f) { f##Field = std::move(f); }
94 DEFINE_FIELD_SET(ColorFilter)
95 DEFINE_FIELD_SET(ImageFilter)
96 DEFINE_FIELD_SET(MaskFilter)
97 DEFINE_FIELD_SET(PathEffect)
98 DEFINE_FIELD_SET(Shader)
99 #undef DEFINE_FIELD_SET
100 
101 ///////////////////////////////////////////////////////////////////////////////
102 
103 void SkPaint::reset() { *this = SkPaint(); }
104 
setStyle(Style style)105 void SkPaint::setStyle(Style style) {
106     if ((unsigned)style < kStyleCount) {
107         fBitfields.fStyle = style;
108     } else {
109 #ifdef SK_REPORT_API_RANGE_CHECK
110         SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
111 #endif
112     }
113 }
114 
setStroke(bool isStroke)115 void SkPaint::setStroke(bool isStroke) {
116     fBitfields.fStyle = isStroke ? kStroke_Style : kFill_Style;
117 }
118 
setColor(SkColor color)119 void SkPaint::setColor(SkColor color) {
120     fColor4f = SkColor4f::FromColor(color);
121 }
122 
setColor(const SkColor4f & color,SkColorSpace * colorSpace)123 void SkPaint::setColor(const SkColor4f& color, SkColorSpace* colorSpace) {
124     SkColorSpaceXformSteps steps{colorSpace,          kUnpremul_SkAlphaType,
125                                  sk_srgb_singleton(), kUnpremul_SkAlphaType};
126     fColor4f = {color.fR, color.fG, color.fB, SkTPin(color.fA, 0.0f, 1.0f)};
127     steps.apply(fColor4f.vec());
128 }
129 
setAlphaf(float a)130 void SkPaint::setAlphaf(float a) {
131     fColor4f.fA = SkTPin(a, 0.0f, 1.0f);
132 }
133 
setARGB(U8CPU a,U8CPU r,U8CPU g,U8CPU b)134 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
135     this->setColor(SkColorSetARGB(a, r, g, b));
136 }
137 
asBlendMode() const138 std::optional<SkBlendMode> SkPaint::asBlendMode() const {
139     return fBlender ? as_BB(fBlender)->asBlendMode()
140                     : SkBlendMode::kSrcOver;
141 }
142 
getBlendMode_or(SkBlendMode defaultMode) const143 SkBlendMode SkPaint::getBlendMode_or(SkBlendMode defaultMode) const {
144     return this->asBlendMode().value_or(defaultMode);
145 }
146 
isSrcOver() const147 bool SkPaint::isSrcOver() const {
148     return !fBlender || as_BB(fBlender)->asBlendMode() == SkBlendMode::kSrcOver;
149 }
150 
setBlendMode(SkBlendMode mode)151 void SkPaint::setBlendMode(SkBlendMode mode) {
152     this->setBlender(mode == SkBlendMode::kSrcOver ? nullptr : SkBlender::Mode(mode));
153 }
154 
setBlender(sk_sp<SkBlender> blender)155 void SkPaint::setBlender(sk_sp<SkBlender> blender) {
156     fBlender = std::move(blender);
157 }
158 
setStrokeWidth(SkScalar width)159 void SkPaint::setStrokeWidth(SkScalar width) {
160     if (width >= 0) {
161         fWidth = width;
162     } else {
163 #ifdef SK_REPORT_API_RANGE_CHECK
164         SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
165 #endif
166     }
167 }
168 
setStrokeMiter(SkScalar limit)169 void SkPaint::setStrokeMiter(SkScalar limit) {
170     if (limit >= 0) {
171         fMiterLimit = limit;
172     } else {
173 #ifdef SK_REPORT_API_RANGE_CHECK
174         SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
175 #endif
176     }
177 }
178 
setStrokeCap(Cap ct)179 void SkPaint::setStrokeCap(Cap ct) {
180     if ((unsigned)ct < kCapCount) {
181         fBitfields.fCapType = SkToU8(ct);
182     } else {
183 #ifdef SK_REPORT_API_RANGE_CHECK
184         SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
185 #endif
186     }
187 }
188 
setStrokeJoin(Join jt)189 void SkPaint::setStrokeJoin(Join jt) {
190     if ((unsigned)jt < kJoinCount) {
191         fBitfields.fJoinType = SkToU8(jt);
192     } else {
193 #ifdef SK_REPORT_API_RANGE_CHECK
194         SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
195 #endif
196     }
197 }
198 
199 ///////////////////////////////////////////////////////////////////////////////
200 
canComputeFastBounds() const201 bool SkPaint::canComputeFastBounds() const {
202     if (this->getImageFilter() && !this->getImageFilter()->canComputeFastBounds()) {
203         return false;
204     }
205     // Pass nullptr for the bounds to determine if they can be computed
206     if (this->getPathEffect() &&
207         !as_PEB(this->getPathEffect())->computeFastBounds(nullptr)) {
208         return false;
209     }
210     return true;
211 }
212 
computeFastBounds(const SkRect & orig,SkRect * storage) const213 const SkRect& SkPaint::computeFastBounds(const SkRect& orig, SkRect* storage) const {
214     // Things like stroking, etc... will do math on the bounds rect, assuming that it's sorted.
215     SkASSERT(orig.isSorted());
216     SkPaint::Style style = this->getStyle();
217     // ultra fast-case: filling with no effects that affect geometry
218     if (kFill_Style == style) {
219         uintptr_t effects = 0;
220         effects |= reinterpret_cast<uintptr_t>(this->getMaskFilter());
221         effects |= reinterpret_cast<uintptr_t>(this->getPathEffect());
222         effects |= reinterpret_cast<uintptr_t>(this->getImageFilter());
223         if (!effects) {
224             return orig;
225         }
226     }
227 
228     return this->doComputeFastBounds(orig, storage, style);
229 }
230 
doComputeFastBounds(const SkRect & origSrc,SkRect * storage,Style style) const231 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
232                                            SkRect* storage,
233                                            Style style) const {
234     SkASSERT(storage);
235 
236     const SkRect* src = &origSrc;
237 
238     SkRect tmpSrc;
239     if (this->getPathEffect()) {
240         tmpSrc = origSrc;
241         SkAssertResult(as_PEB(this->getPathEffect())->computeFastBounds(&tmpSrc));
242         src = &tmpSrc;
243     }
244 
245     SkScalar radius = SkStrokeRec::GetInflationRadius(*this, style);
246     *storage = src->makeOutset(radius, radius);
247 
248     if (this->getMaskFilter()) {
249         as_MFB(this->getMaskFilter())->computeFastBounds(*storage, storage);
250     }
251 
252     if (this->getImageFilter()) {
253         *storage = this->getImageFilter()->computeFastBounds(*storage);
254     }
255 
256     return *storage;
257 }
258 
259 ///////////////////////////////////////////////////////////////////////////////
260 
261 // return true if the filter exists, and may affect alpha
affects_alpha(const SkColorFilter * cf)262 static bool affects_alpha(const SkColorFilter* cf) {
263     return cf && !as_CFB(cf)->isAlphaUnchanged();
264 }
265 
266 // return true if the filter exists, and may affect alpha
affects_alpha(const SkImageFilter * imf)267 static bool affects_alpha(const SkImageFilter* imf) {
268     // TODO: check if we should allow imagefilters to broadcast that they don't affect alpha
269     // ala colorfilters
270     return imf != nullptr;
271 }
272 
nothingToDraw() const273 bool SkPaint::nothingToDraw() const {
274     auto bm = this->asBlendMode();
275     if (!bm) {
276         return false;
277     }
278     switch (bm.value()) {
279         case SkBlendMode::kSrcOver:
280         case SkBlendMode::kSrcATop:
281         case SkBlendMode::kDstOut:
282         case SkBlendMode::kDstOver:
283         case SkBlendMode::kPlus:
284             if (0 == this->getAlpha()) {
285                 return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get());
286             }
287             break;
288         case SkBlendMode::kDst:
289             return true;
290         default:
291             break;
292     }
293     return false;
294 }
295