• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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