1 /*
2 * Copyright 2013 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 #include "src/core/SkPaintPriv.h"
9
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkBlender.h"
12 #include "include/core/SkColorFilter.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImageFilter.h"
15 #include "include/core/SkMaskFilter.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPathEffect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkShader.h"
20 #include "include/private/base/SkAssert.h"
21 #include "include/private/base/SkDebug.h"
22 #include "src/core/SkColorSpacePriv.h"
23 #include "src/core/SkPicturePriv.h"
24 #include "src/core/SkReadBuffer.h"
25 #include "src/core/SkSafeRange.h"
26 #include "src/core/SkWriteBuffer.h"
27 #include "src/effects/colorfilters/SkColorFilterBase.h"
28 #include "src/shaders/SkColorFilterShader.h"
29 #include "src/shaders/SkShaderBase.h"
30
31 #include <cstdint>
32 #include <optional>
33
34 class SkColorSpace;
35
changes_alpha(const SkPaint & paint)36 static bool changes_alpha(const SkPaint& paint) {
37 SkColorFilter* cf = paint.getColorFilter();
38 return cf && !as_CFB(cf)->isAlphaUnchanged();
39 }
40
41 enum SrcColorOpacity {
42 // The src color is known to be opaque (alpha == 255)
43 kOpaque_SrcColorOpacity = 0,
44 // The src color is known to be fully transparent (color == 0)
45 kTransparentBlack_SrcColorOpacity = 1,
46 // The src alpha is known to be fully transparent (alpha == 0)
47 kTransparentAlpha_SrcColorOpacity = 2,
48 // The src color opacity is unknown
49 kUnknown_SrcColorOpacity = 3
50 };
51
blend_mode_is_opaque(SkBlendMode mode,SrcColorOpacity opacityType)52 static bool blend_mode_is_opaque(SkBlendMode mode, SrcColorOpacity opacityType) {
53 SkBlendModeCoeff src, dst;
54 if (!SkBlendMode_AsCoeff(mode, &src, &dst)) {
55 return false;
56 }
57
58 switch (src) {
59 case SkBlendModeCoeff::kDA:
60 case SkBlendModeCoeff::kDC:
61 case SkBlendModeCoeff::kIDA:
62 case SkBlendModeCoeff::kIDC:
63 return false;
64 default:
65 break;
66 }
67
68 switch (dst) {
69 case SkBlendModeCoeff::kZero:
70 return true;
71 case SkBlendModeCoeff::kISA:
72 return kOpaque_SrcColorOpacity == opacityType;
73 case SkBlendModeCoeff::kSA:
74 return kTransparentBlack_SrcColorOpacity == opacityType ||
75 kTransparentAlpha_SrcColorOpacity == opacityType;
76 case SkBlendModeCoeff::kSC:
77 return kTransparentBlack_SrcColorOpacity == opacityType;
78 default:
79 return false;
80 }
81 }
82
Overwrites(const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)83 bool SkPaintPriv::Overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) {
84 if (!paint) {
85 // No paint means we default to SRC_OVER, so we overwrite iff our shader-override
86 // is opaque, or we don't have one.
87 return overrideOpacity != kNotOpaque_ShaderOverrideOpacity;
88 }
89
90 SrcColorOpacity opacityType = kUnknown_SrcColorOpacity;
91
92 if (!changes_alpha(*paint)) {
93 const unsigned paintAlpha = paint->getAlpha();
94 if (0xff == paintAlpha && overrideOpacity != kNotOpaque_ShaderOverrideOpacity &&
95 (!paint->getShader() || paint->getShader()->isOpaque())) {
96 opacityType = kOpaque_SrcColorOpacity;
97 } else if (0 == paintAlpha) {
98 if (overrideOpacity == kNone_ShaderOverrideOpacity && !paint->getShader()) {
99 opacityType = kTransparentBlack_SrcColorOpacity;
100 } else {
101 opacityType = kTransparentAlpha_SrcColorOpacity;
102 }
103 }
104 }
105
106 const auto bm = paint->asBlendMode();
107 if (!bm) {
108 return false; // don't know for sure, so we play it safe and return false.
109 }
110 return blend_mode_is_opaque(bm.value(), opacityType);
111 }
112
ShouldDither(const SkPaint & p,SkColorType dstCT)113 bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) {
114 // The paint dither flag can veto.
115 if (!p.isDither()) {
116 return false;
117 }
118
119 if (dstCT == kUnknown_SkColorType) {
120 return false;
121 }
122
123 // We always dither 565 or 4444 when requested.
124 if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
125 return true;
126 }
127
128 // Otherwise, dither is only needed for non-const paints.
129 return p.getImageFilter() || p.getMaskFilter() ||
130 (p.getShader() && !as_SB(p.getShader())->isConstant());
131 }
132
133 // return true if the paint is just a single color (i.e. not a shader). If its
134 // a shader, then we can't compute a const luminance for it :(
just_a_color(const SkPaint & paint,SkColor4f * color)135 static bool just_a_color(const SkPaint& paint, SkColor4f* color) {
136 SkColor4f c = paint.getColor4f();
137
138 const auto* shader = as_SB(paint.getShader());
139 if (shader && !shader->asLuminanceColor(&c)) {
140 return false;
141 }
142 if (paint.getColorFilter()) {
143 // TODO: This colorspace is meaningless, replace it with something else
144 SkColorSpace* cs = nullptr;
145 c = paint.getColorFilter()->filterColor4f(c, cs, cs);
146 }
147 if (color) {
148 *color = c;
149 }
150 return true;
151 }
152
ComputeLuminanceColor(const SkPaint & paint)153 SkColor SkPaintPriv::ComputeLuminanceColor(const SkPaint& paint) {
154 SkColor4f c;
155 if (!just_a_color(paint, &c)) {
156 c = { 0.5f, 0.5f, 0.5f, 1.0f};
157 }
158 return c.toSkColor();
159 }
160
RemoveColorFilter(SkPaint * p,SkColorSpace * dstCS)161 void SkPaintPriv::RemoveColorFilter(SkPaint* p, SkColorSpace* dstCS) {
162 if (SkColorFilter* filter = p->getColorFilter()) {
163 if (SkShader* shader = p->getShader()) {
164 // SkColorFilterShader will modulate the shader color by paint alpha
165 // before applying the filter, so we'll reset it to opaque.
166 p->setShader(SkColorFilterShader::Make(sk_ref_sp(shader),
167 p->getAlphaf(),
168 sk_ref_sp(filter)));
169 p->setAlphaf(1.0f);
170 } else {
171 p->setColor(filter->filterColor4f(p->getColor4f(), sk_srgb_singleton(), dstCS), dstCS);
172 }
173 p->setColorFilter(nullptr);
174 }
175 }
176
177 #ifdef SK_DEBUG
ASSERT_FITS_IN(uint32_t value,int bitCount)178 static void ASSERT_FITS_IN(uint32_t value, int bitCount) {
179 SkASSERT(bitCount > 0 && bitCount <= 32);
180 uint32_t mask = ~0U;
181 mask >>= (32 - bitCount);
182 SkASSERT(0 == (value & ~mask));
183 }
184 #else
185 #define ASSERT_FITS_IN(value, bitcount)
186 #endif
187
188 enum FlatFlags {
189 kHasTypeface_FlatFlag = 0x1,
190 kHasEffects_FlatFlag = 0x2,
191
192 kFlatFlagMask = 0x3,
193 };
194
195 // SkPaint originally defined flags, some of which now apply to SkFont. These are renames
196 // of those flags, split into categories depending on which objects they (now) apply to.
197
shift_bits(T value,unsigned shift,unsigned bits)198 template <typename T> uint32_t shift_bits(T value, unsigned shift, unsigned bits) {
199 SkASSERT(shift + bits <= 32);
200 uint32_t v = static_cast<uint32_t>(value);
201 ASSERT_FITS_IN(v, bits);
202 return v << shift;
203 }
204
205 constexpr uint8_t CUSTOM_BLEND_MODE_SENTINEL = 0xFF;
206
207 /* Packing the paint
208 flags : 8 // 2...
209 blend : 8 // 30+
210 cap : 2 // 3
211 join : 2 // 3
212 style : 2 // 3
213 filter: 2 // 4
214 flat : 8 // 1...
215 total : 32
216 */
pack_v68(const SkPaint & paint,unsigned flatFlags)217 static uint32_t pack_v68(const SkPaint& paint, unsigned flatFlags) {
218 uint32_t packed = 0;
219 const auto bm = paint.asBlendMode();
220 const unsigned mode = bm ? static_cast<unsigned>(bm.value())
221 : CUSTOM_BLEND_MODE_SENTINEL;
222
223 packed |= shift_bits(((unsigned)paint.isDither() << 1) |
224 (unsigned)paint.isAntiAlias(), 0, 8);
225 packed |= shift_bits(mode, 8, 8);
226 packed |= shift_bits(paint.getStrokeCap(), 16, 2);
227 packed |= shift_bits(paint.getStrokeJoin(), 18, 2);
228 packed |= shift_bits(paint.getStyle(), 20, 2);
229 packed |= shift_bits(0, 22, 2); // was filterquality
230 packed |= shift_bits(flatFlags, 24, 8);
231 return packed;
232 }
233
unpack_v68(SkPaint * paint,uint32_t packed,SkSafeRange & safe)234 static uint32_t unpack_v68(SkPaint* paint, uint32_t packed, SkSafeRange& safe) {
235 paint->setAntiAlias((packed & 1) != 0);
236 paint->setDither((packed & 2) != 0);
237 packed >>= 8;
238 {
239 unsigned mode = packed & 0xFF;
240 if (mode != CUSTOM_BLEND_MODE_SENTINEL) { // sentinel for custom blender
241 paint->setBlendMode(safe.checkLE(mode, SkBlendMode::kLastMode));
242 }
243 // else we will unflatten the custom blender
244 }
245 packed >>= 8;
246 paint->setStrokeCap(safe.checkLE(packed & 0x3, SkPaint::kLast_Cap));
247 packed >>= 2;
248 paint->setStrokeJoin(safe.checkLE(packed & 0x3, SkPaint::kLast_Join));
249 packed >>= 2;
250 paint->setStyle(safe.checkLE(packed & 0x3, SkPaint::kStrokeAndFill_Style));
251 packed >>= 2;
252 // skip the (now ignored) filterquality bits
253 packed >>= 2;
254
255 return packed;
256 }
257
258 /* To save space/time, we analyze the paint, and write a truncated version of
259 it if there are not tricky elements like shaders, etc.
260 */
Flatten(const SkPaint & paint,SkWriteBuffer & buffer)261 void SkPaintPriv::Flatten(const SkPaint& paint, SkWriteBuffer& buffer) {
262 uint8_t flatFlags = 0;
263
264 if (paint.getPathEffect() ||
265 paint.getShader() ||
266 paint.getMaskFilter() ||
267 paint.getColorFilter() ||
268 paint.getImageFilter() ||
269 !paint.asBlendMode()) {
270 flatFlags |= kHasEffects_FlatFlag;
271 }
272
273 buffer.writeScalar(paint.getStrokeWidth());
274 buffer.writeScalar(paint.getStrokeMiter());
275 buffer.writeColor4f(paint.getColor4f());
276
277 buffer.write32(pack_v68(paint, flatFlags));
278
279 if (flatFlags & kHasEffects_FlatFlag) {
280 buffer.writeFlattenable(paint.getPathEffect());
281 buffer.writeFlattenable(paint.getShader());
282 buffer.writeFlattenable(paint.getMaskFilter());
283 buffer.writeFlattenable(paint.getColorFilter());
284 buffer.writeFlattenable(paint.getImageFilter());
285 buffer.writeFlattenable(paint.getBlender());
286 }
287 }
288
Unflatten(SkReadBuffer & buffer)289 SkPaint SkPaintPriv::Unflatten(SkReadBuffer& buffer) {
290 SkPaint paint;
291
292 paint.setStrokeWidth(buffer.readScalar());
293 paint.setStrokeMiter(buffer.readScalar());
294 {
295 SkColor4f color;
296 buffer.readColor4f(&color);
297 paint.setColor(color, sk_srgb_singleton());
298 }
299
300 SkSafeRange safe;
301 unsigned flatFlags = unpack_v68(&paint, buffer.readUInt(), safe);
302
303 if (!(flatFlags & kHasEffects_FlatFlag)) {
304 // This is a simple SkPaint without any effects, so clear all the effect-related fields.
305 paint.setPathEffect(nullptr);
306 paint.setShader(nullptr);
307 paint.setMaskFilter(nullptr);
308 paint.setColorFilter(nullptr);
309 paint.setImageFilter(nullptr);
310 } else if (buffer.isVersionLT(SkPicturePriv::kSkBlenderInSkPaint)) {
311 // This paint predates the introduction of user blend functions (via SkBlender).
312 paint.setPathEffect(buffer.readPathEffect());
313 paint.setShader(buffer.readShader());
314 paint.setMaskFilter(buffer.readMaskFilter());
315 paint.setColorFilter(buffer.readColorFilter());
316 (void)buffer.read32(); // was drawLooper (now deprecated)
317 paint.setImageFilter(buffer.readImageFilter());
318 } else {
319 paint.setPathEffect(buffer.readPathEffect());
320 paint.setShader(buffer.readShader());
321 paint.setMaskFilter(buffer.readMaskFilter());
322 paint.setColorFilter(buffer.readColorFilter());
323 paint.setImageFilter(buffer.readImageFilter());
324 paint.setBlender(buffer.readBlender());
325 }
326
327 if (!buffer.validate(safe.ok())) {
328 paint.reset();
329 }
330 return paint;
331 }
332