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