Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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
30
31#include <cstdint>
32#include <optional>
33
34class SkColorSpace;
35
36static bool changes_alpha(const SkPaint& paint) {
37 SkColorFilter* cf = paint.getColorFilter();
38 return cf && !as_CFB(cf)->isAlphaUnchanged();
39}
40
42 // The src color is known to be opaque (alpha == 255)
44 // The src color is known to be fully transparent (color == 0)
46 // The src alpha is known to be fully transparent (alpha == 0)
48 // The src color opacity is unknown
50};
51
54 if (!SkBlendMode_AsCoeff(mode, &src, &dst)) {
55 return false;
56 }
57
58 switch (src) {
63 return false;
64 default:
65 break;
66 }
67
68 switch (dst) {
70 return true;
72 return kOpaque_SrcColorOpacity == opacityType;
74 return kTransparentBlack_SrcColorOpacity == opacityType ||
77 return kTransparentBlack_SrcColorOpacity == opacityType;
78 default:
79 return false;
80 }
81}
82
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
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()) {
100 } else {
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
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 :(
135static 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
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
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(sk_make_sp<SkColorFilterShader>(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
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
191
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
198template <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);
202 return v << shift;
203}
204
205constexpr 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 */
217static 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())
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
234static 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 */
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
291
292 paint.setStrokeWidth(buffer.readScalar());
293 paint.setStrokeMiter(buffer.readScalar());
294 {
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}
#define SkASSERT(cond)
Definition: SkAssert.h:116
SK_API bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff *src, SkBlendModeCoeff *dst)
Definition: SkBlendMode.cpp:57
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)
Definition: SkPaintPriv.cpp:52
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
Definition: SkPaintPriv.cpp:41
@ kTransparentBlack_SrcColorOpacity
Definition: SkPaintPriv.cpp:45
@ kTransparentAlpha_SrcColorOpacity
Definition: SkPaintPriv.cpp:47
@ kUnknown_SrcColorOpacity
Definition: SkPaintPriv.cpp:49
@ kOpaque_SrcColorOpacity
Definition: SkPaintPriv.cpp:43
static bool changes_alpha(const SkPaint &paint)
Definition: SkPaintPriv.cpp:36
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)
Definition: SkShaderBase.h:412
bool isAlphaUnchanged() const
static void RemoveColorFilter(SkPaint *, SkColorSpace *dstCS)
static SkPaint Unflatten(SkReadBuffer &buffer)
static bool Overwrites(const SkPaint *paint, ShaderOverrideOpacity)
Definition: SkPaintPriv.cpp:83
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
Definition: SkShaderBase.h:197
const Paint & paint
Definition: color_source.cc:38
DlColor color
uint8_t value
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
dst
Definition: cp.py:12
#define T
Definition: precompiler.cc:65