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