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/SkData.h"
11#include "include/core/SkGraphics.h"
12#include "include/core/SkImageFilter.h"
13#include "include/core/SkMaskFilter.h"
14#include "include/core/SkPathEffect.h"
15#include "include/core/SkScalar.h"
16#include "include/core/SkShader.h"
17#include "include/core/SkStrokeRec.h"
18#include "include/core/SkTypeface.h"
19#include "include/private/SkMutex.h"
20#include "include/private/SkTo.h"
21#include "src/core/SkColorFilterBase.h"
22#include "src/core/SkColorSpacePriv.h"
23#include "src/core/SkColorSpaceXformSteps.h"
24#include "src/core/SkDraw.h"
25#include "src/core/SkMaskGamma.h"
26#include "src/core/SkOpts.h"
27#include "src/core/SkPaintDefaults.h"
28#include "src/core/SkPaintPriv.h"
29#include "src/core/SkReadBuffer.h"
30#include "src/core/SkSafeRange.h"
31#include "src/core/SkStringUtils.h"
32#include "src/core/SkStroke.h"
33#include "src/core/SkSurfacePriv.h"
34#include "src/core/SkTLazy.h"
35#include "src/core/SkWriteBuffer.h"
36#include "src/shaders/SkShaderBase.h"
37
38// define this to get a printf for out-of-range parameter in setters
39// e.g. setTextSize(-1)
40//#define SK_REPORT_API_RANGE_CHECK
41
42
43SkPaint::SkPaint()
44 : fColor4f{0, 0, 0, 1} // opaque black
45 , fWidth{0}
46 , fMiterLimit{SkPaintDefaults_MiterLimit}
47 , fBitfields{(unsigned)false, // fAntiAlias
48 (unsigned)false, // fDither
49 (unsigned)SkPaint::kDefault_Cap, // fCapType
50 (unsigned)SkPaint::kDefault_Join, // fJoinType
51 (unsigned)SkPaint::kFill_Style, // fStyle
52 (unsigned)kNone_SkFilterQuality, // fFilterQuality
53 (unsigned)SkBlendMode::kSrcOver, // fBlendMode
54 0} // fPadding
55{
56 static_assert(sizeof(fBitfields) == sizeof(fBitfieldsUInt), "");
57}
58
59SkPaint::SkPaint(const SkColor4f& color, SkColorSpace* colorSpace) : SkPaint() {
60 this->setColor(color, colorSpace);
61}
62
63SkPaint::SkPaint(const SkPaint& src) = default;
64
65SkPaint::SkPaint(SkPaint&& src) = default;
66
67SkPaint::~SkPaint() = default;
68
69SkPaint& SkPaint::operator=(const SkPaint& src) = default;
70
71SkPaint& SkPaint::operator=(SkPaint&& src) = default;
72
73bool operator==(const SkPaint& a, const SkPaint& b) {
74#define EQUAL(field) (a.field == b.field)
75 return EQUAL(fPathEffect)
76 && EQUAL(fShader)
77 && EQUAL(fMaskFilter)
78 && EQUAL(fColorFilter)
79 && EQUAL(fImageFilter)
80 && EQUAL(fColor4f)
81 && EQUAL(fWidth)
82 && EQUAL(fMiterLimit)
83 && EQUAL(fBitfieldsUInt)
84 ;
85#undef EQUAL
86}
87
88#define DEFINE_REF_FOO(type) sk_sp<Sk##type> SkPaint::ref##type() const { return f##type; }
89DEFINE_REF_FOO(ColorFilter)
90DEFINE_REF_FOO(ImageFilter)
91DEFINE_REF_FOO(MaskFilter)
92DEFINE_REF_FOO(PathEffect)
93DEFINE_REF_FOO(Shader)
94#undef DEFINE_REF_FOO
95
96void SkPaint::reset() { *this = SkPaint(); }
97
98void SkPaint::setFilterQuality(SkFilterQuality quality) {
99 fBitfields.fFilterQuality = quality;
100}
101
102void SkPaint::setStyle(Style style) {
103 if ((unsigned)style < kStyleCount) {
104 fBitfields.fStyle = style;
105 } else {
106#ifdef SK_REPORT_API_RANGE_CHECK
107 SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
108#endif
109 }
110}
111
112void SkPaint::setStroke(bool isStroke) {
113 fBitfields.fStyle = isStroke ? kStroke_Style : kFill_Style;
114}
115
116void SkPaint::setColor(SkColor color) {
117 fColor4f = SkColor4f::FromColor(color);
118}
119
120void SkPaint::setColor(const SkColor4f& color, SkColorSpace* colorSpace) {
121 SkASSERT(fColor4f.fA >= 0 && fColor4f.fA <= 1.0f);
122
123 SkColorSpaceXformSteps steps{colorSpace, kUnpremul_SkAlphaType,
124 sk_srgb_singleton(), kUnpremul_SkAlphaType};
125 fColor4f = color;
126 steps.apply(fColor4f.vec());
127}
128
129void SkPaint::setAlphaf(float a) {
130 SkASSERT(a >= 0 && a <= 1.0f);
131 fColor4f.fA = a;
132}
133
134void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
135 this->setColor(SkColorSetARGB(a, r, g, b));
136}
137
138void SkPaint::setStrokeWidth(SkScalar width) {
139 if (width >= 0) {
140 fWidth = width;
141 } else {
142#ifdef SK_REPORT_API_RANGE_CHECK
143 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
144#endif
145 }
146}
147
148void SkPaint::setStrokeMiter(SkScalar limit) {
149 if (limit >= 0) {
150 fMiterLimit = limit;
151 } else {
152#ifdef SK_REPORT_API_RANGE_CHECK
153 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
154#endif
155 }
156}
157
158void SkPaint::setStrokeCap(Cap ct) {
159 if ((unsigned)ct < kCapCount) {
160 fBitfields.fCapType = SkToU8(ct);
161 } else {
162#ifdef SK_REPORT_API_RANGE_CHECK
163 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
164#endif
165 }
166}
167
168void SkPaint::setStrokeJoin(Join jt) {
169 if ((unsigned)jt < kJoinCount) {
170 fBitfields.fJoinType = SkToU8(jt);
171 } else {
172#ifdef SK_REPORT_API_RANGE_CHECK
173 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
174#endif
175 }
176}
177
178///////////////////////////////////////////////////////////////////////////////
179
180#define MOVE_FIELD(Field) void SkPaint::set##Field(sk_sp<Sk##Field> f) { f##Field = std::move(f); }
181MOVE_FIELD(ImageFilter)
182MOVE_FIELD(Shader)
183MOVE_FIELD(ColorFilter)
184MOVE_FIELD(PathEffect)
185MOVE_FIELD(MaskFilter)
186#undef MOVE_FIELD
187
188///////////////////////////////////////////////////////////////////////////////
189
190#include "include/core/SkStream.h"
191
192#ifdef SK_DEBUG
193 static void ASSERT_FITS_IN(uint32_t value, int bitCount) {
194 SkASSERT(bitCount > 0 && bitCount <= 32);
195 uint32_t mask = ~0U;
196 mask >>= (32 - bitCount);
197 SkASSERT(0 == (value & ~mask));
198 }
199#else
200 #define ASSERT_FITS_IN(value, bitcount)
201#endif
202
203enum FlatFlags {
204 kHasTypeface_FlatFlag = 0x1,
205 kHasEffects_FlatFlag = 0x2,
206
207 kFlatFlagMask = 0x3,
208};
209
210// SkPaint originally defined flags, some of which now apply to SkFont. These are renames
211// of those flags, split into categories depending on which objects they (now) apply to.
212
213template <typename T> uint32_t shift_bits(T value, unsigned shift, unsigned bits) {
214 SkASSERT(shift + bits <= 32);
215 uint32_t v = static_cast<uint32_t>(value);
216 ASSERT_FITS_IN(v, bits);
217 return v << shift;
218}
219
220/* Packing the paint
221 flags : 8 // 2...
222 blend : 8 // 30+
223 cap : 2 // 3
224 join : 2 // 3
225 style : 2 // 3
226 filter: 2 // 4
227 flat : 8 // 1...
228 total : 32
229 */
230static uint32_t pack_v68(const SkPaint& paint, unsigned flatFlags) {
231 uint32_t packed = 0;
232 packed |= shift_bits(((unsigned)paint.isDither() << 1) |
233 (unsigned)paint.isAntiAlias(), 0, 8);
234 packed |= shift_bits(paint.getBlendMode(), 8, 8);
235 packed |= shift_bits(paint.getStrokeCap(), 16, 2);
236 packed |= shift_bits(paint.getStrokeJoin(), 18, 2);
237 packed |= shift_bits(paint.getStyle(), 20, 2);
238 packed |= shift_bits(paint.getFilterQuality(), 22, 2);
239 packed |= shift_bits(flatFlags, 24, 8);
240 return packed;
241}
242
243static uint32_t unpack_v68(SkPaint* paint, uint32_t packed, SkSafeRange& safe) {
244 paint->setAntiAlias((packed & 1) != 0);
245 paint->setDither((packed & 2) != 0);
246 packed >>= 8;
247 paint->setBlendMode(safe.checkLE(packed & 0xFF, SkBlendMode::kLastMode));
248 packed >>= 8;
249 paint->setStrokeCap(safe.checkLE(packed & 0x3, SkPaint::kLast_Cap));
250 packed >>= 2;
251 paint->setStrokeJoin(safe.checkLE(packed & 0x3, SkPaint::kLast_Join));
252 packed >>= 2;
253 paint->setStyle(safe.checkLE(packed & 0x3, SkPaint::kStrokeAndFill_Style));
254 packed >>= 2;
255 paint->setFilterQuality(safe.checkLE(packed & 0x3, kLast_SkFilterQuality));
256 packed >>= 2;
257 return packed;
258}
259
260/* To save space/time, we analyze the paint, and write a truncated version of
261 it if there are not tricky elements like shaders, etc.
262 */
263void SkPaintPriv::Flatten(const SkPaint& paint, SkWriteBuffer& buffer) {
264 uint8_t flatFlags = 0;
265
266 if (paint.getPathEffect() ||
267 paint.getShader() ||
268 paint.getMaskFilter() ||
269 paint.getColorFilter() ||
270 paint.getImageFilter()) {
271 flatFlags |= kHasEffects_FlatFlag;
272 }
273
274 buffer.writeScalar(paint.getStrokeWidth());
275 buffer.writeScalar(paint.getStrokeMiter());
276 buffer.writeColor4f(paint.getColor4f());
277
278 buffer.write32(pack_v68(paint, flatFlags));
279
280 if (flatFlags & kHasEffects_FlatFlag) {
281 buffer.writeFlattenable(paint.getPathEffect());
282 buffer.writeFlattenable(paint.getShader());
283 buffer.writeFlattenable(paint.getMaskFilter());
284 buffer.writeFlattenable(paint.getColorFilter());
285 buffer.write32(0); // legacy, was drawlooper
286 buffer.writeFlattenable(paint.getImageFilter());
287 }
288}
289
290SkReadPaintResult SkPaintPriv::Unflatten(SkPaint* paint, SkReadBuffer& buffer, SkFont* font) {
291 SkSafeRange safe;
292
293 paint->setStrokeWidth(buffer.readScalar());
294 paint->setStrokeMiter(buffer.readScalar());
295 {
296 SkColor4f color;
297 buffer.readColor4f(&color);
298 paint->setColor(color, sk_srgb_singleton());
299 }
300
301 unsigned flatFlags = unpack_v68(paint, buffer.readUInt(), safe);
302
303 if (flatFlags & kHasEffects_FlatFlag) {
304 paint->setPathEffect(buffer.readPathEffect());
305 paint->setShader(buffer.readShader());
306 paint->setMaskFilter(buffer.readMaskFilter());
307 paint->setColorFilter(buffer.readColorFilter());
308 (void)buffer.readDrawLooper();
309 paint->setImageFilter(buffer.readImageFilter());
310 } else {
311 paint->setPathEffect(nullptr);
312 paint->setShader(nullptr);
313 paint->setMaskFilter(nullptr);
314 paint->setColorFilter(nullptr);
315 paint->setImageFilter(nullptr);
316 }
317
318 if (!buffer.validate(safe)) {
319 paint->reset();
320 return kFailed_ReadPaint;
321 }
322 return kSuccess_JustPaint;
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
327bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect,
328 SkScalar resScale) const {
329 if (!src.isFinite()) {
330 dst->reset();
331 return false;
332 }
333
334 SkStrokeRec rec(*this, resScale);
335
336 const SkPath* srcPtr = &src;
337 SkPath tmpPath;
338
339 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) {
340 srcPtr = &tmpPath;
341 }
342
343 if (!rec.applyToPath(dst, *srcPtr)) {
344 if (srcPtr == &tmpPath) {
345 // If path's were copy-on-write, this trick would not be needed.
346 // As it is, we want to save making a deep-copy from tmpPath -> dst
347 // since we know we're just going to delete tmpPath when we return,
348 // so the swap saves that copy.
349 dst->swap(tmpPath);
350 } else {
351 *dst = *srcPtr;
352 }
353 }
354
355 if (!dst->isFinite()) {
356 dst->reset();
357 return false;
358 }
359 return !rec.isHairlineStyle();
360}
361
362bool SkPaint::canComputeFastBounds() const {
363 if (this->getImageFilter() && !this->getImageFilter()->canComputeFastBounds()) {
364 return false;
365 }
366 return true;
367}
368
369const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
370 SkRect* storage,
371 Style style) const {
372 SkASSERT(storage);
373
374 const SkRect* src = &origSrc;
375
376 SkRect tmpSrc;
377 if (this->getPathEffect()) {
378 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc);
379 src = &tmpSrc;
380 }
381
382 SkScalar radius = SkStrokeRec::GetInflationRadius(*this, style);
383 *storage = src->makeOutset(radius, radius);
384
385 if (this->getMaskFilter()) {
386 as_MFB(this->getMaskFilter())->computeFastBounds(*storage, storage);
387 }
388
389 if (this->getImageFilter()) {
390 *storage = this->getImageFilter()->computeFastBounds(*storage);
391 }
392
393 return *storage;
394}
395
396///////////////////////////////////////////////////////////////////////////////
397
398// return true if the filter exists, and may affect alpha
399static bool affects_alpha(const SkColorFilter* cf) {
400 return cf && !as_CFB(cf)->isAlphaUnchanged();
401}
402
403// return true if the filter exists, and may affect alpha
404static bool affects_alpha(const SkImageFilter* imf) {
405 // TODO: check if we should allow imagefilters to broadcast that they don't affect alpha
406 // ala colorfilters
407 return imf != nullptr;
408}
409
410bool SkPaint::nothingToDraw() const {
411 switch (this->getBlendMode()) {
412 case SkBlendMode::kSrcOver:
413 case SkBlendMode::kSrcATop:
414 case SkBlendMode::kDstOut:
415 case SkBlendMode::kDstOver:
416 case SkBlendMode::kPlus:
417 if (0 == this->getAlpha()) {
418 return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get());
419 }
420 break;
421 case SkBlendMode::kDst:
422 return true;
423 default:
424 break;
425 }
426 return false;
427}
428
429uint32_t SkPaint::getHash() const {
430 // We're going to hash 5 pointers and 6 floats, finishing up with fBitfields,
431 // so fBitfields should be 5 pointers and 6 floats from the start.
432 static_assert(offsetof(SkPaint, fBitfieldsUInt) == 5 * sizeof(void*) + 6 * sizeof(float),
433 "SkPaint_notPackedTightly");
434 return SkOpts::hash(reinterpret_cast<const uint32_t*>(this),
435 offsetof(SkPaint, fBitfieldsUInt) + sizeof(fBitfieldsUInt));
436}
437