• 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 #include "src/core/SkBlenderBase.h"
10 #include "src/core/SkColorFilterBase.h"
11 #include "src/core/SkColorSpacePriv.h"
12 #include "src/core/SkKeyHelpers.h"
13 #include "src/core/SkPaintParamsKey.h"
14 #include "src/core/SkPaintPriv.h"
15 #include "src/core/SkXfermodePriv.h"
16 #include "src/shaders/SkColorFilterShader.h"
17 #include "src/shaders/SkShaderBase.h"
18 
changes_alpha(const SkPaint & paint)19 static bool changes_alpha(const SkPaint& paint) {
20     SkColorFilter* cf = paint.getColorFilter();
21     return cf && !as_CFB(cf)->isAlphaUnchanged();
22 }
23 
Overwrites(const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)24 bool SkPaintPriv::Overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) {
25     if (!paint) {
26         // No paint means we default to SRC_OVER, so we overwrite iff our shader-override
27         // is opaque, or we don't have one.
28         return overrideOpacity != kNotOpaque_ShaderOverrideOpacity;
29     }
30 
31     SkXfermode::SrcColorOpacity opacityType = SkXfermode::kUnknown_SrcColorOpacity;
32 
33     if (!changes_alpha(*paint)) {
34         const unsigned paintAlpha = paint->getAlpha();
35         if (0xff == paintAlpha && overrideOpacity != kNotOpaque_ShaderOverrideOpacity &&
36             (!paint->getShader() || paint->getShader()->isOpaque()))
37         {
38             opacityType = SkXfermode::kOpaque_SrcColorOpacity;
39         } else if (0 == paintAlpha) {
40             if (overrideOpacity == kNone_ShaderOverrideOpacity && !paint->getShader()) {
41                 opacityType = SkXfermode::kTransparentBlack_SrcColorOpacity;
42             } else {
43                 opacityType = SkXfermode::kTransparentAlpha_SrcColorOpacity;
44             }
45         }
46     }
47 
48     const auto bm = paint->asBlendMode();
49     if (!bm) {
50         return false;   // don't know for sure, so we play it safe and return false.
51     }
52     return SkXfermode::IsOpaque(bm.value(), opacityType);
53 }
54 
ShouldDither(const SkPaint & p,SkColorType dstCT)55 bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) {
56     // The paint dither flag can veto.
57     if (!p.isDither()) {
58         return false;
59     }
60 
61     // We always dither 565 or 4444 when requested.
62     if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
63         return true;
64     }
65 
66     // Otherwise, dither is only needed for non-const paints.
67     return p.getImageFilter() || p.getMaskFilter() ||
68            (p.getShader() && !as_SB(p.getShader())->isConstant());
69 }
70 
71 // return true if the paint is just a single color (i.e. not a shader). If its
72 // a shader, then we can't compute a const luminance for it :(
just_a_color(const SkPaint & paint,SkColor * color)73 static bool just_a_color(const SkPaint& paint, SkColor* color) {
74     SkColor c = paint.getColor();
75 
76     const auto* shader = as_SB(paint.getShader());
77     if (shader && !shader->asLuminanceColor(&c)) {
78         return false;
79     }
80     if (paint.getColorFilter()) {
81         c = paint.getColorFilter()->filterColor(c);
82     }
83     if (color) {
84         *color = c;
85     }
86     return true;
87 }
88 
ComputeLuminanceColor(const SkPaint & paint)89 SkColor SkPaintPriv::ComputeLuminanceColor(const SkPaint& paint) {
90     SkColor c;
91     if (!just_a_color(paint, &c)) {
92         c = SkColorSetRGB(0x7F, 0x80, 0x7F);
93     }
94     return c;
95 }
96 
RemoveColorFilter(SkPaint * p,SkColorSpace * dstCS)97 void SkPaintPriv::RemoveColorFilter(SkPaint* p, SkColorSpace* dstCS) {
98     if (SkColorFilter* filter = p->getColorFilter()) {
99         if (SkShader* shader = p->getShader()) {
100             // SkColorFilterShader will modulate the shader color by paint alpha
101             // before applying the filter, so we'll reset it to opaque.
102             p->setShader(sk_make_sp<SkColorFilterShader>(sk_ref_sp(shader),
103                                                          p->getAlphaf(),
104                                                          sk_ref_sp(filter)));
105             p->setAlphaf(1.0f);
106         } else {
107             p->setColor(filter->filterColor4f(p->getColor4f(), sk_srgb_singleton(), dstCS), dstCS);
108         }
109         p->setColorFilter(nullptr);
110     }
111 }
112 
ComputeResScaleForStroking(const SkMatrix & matrix)113 SkScalar SkPaintPriv::ComputeResScaleForStroking(const SkMatrix& matrix) {
114     // Not sure how to handle perspective differently, so we just don't try (yet)
115     SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
116     SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX],  matrix[SkMatrix::kMScaleY]);
117     if (SkScalarsAreFinite(sx, sy)) {
118         SkScalar scale = std::max(sx, sy);
119         if (scale > 0) {
120             return scale;
121         }
122     }
123     return 1;
124 }
125 
ToKeys(const SkPaint & paint,SkShaderCodeDictionary * dict,SkBackend backend)126 std::vector<std::unique_ptr<SkPaintParamsKey>> SkPaintPriv::ToKeys(const SkPaint& paint,
127                                                                    SkShaderCodeDictionary* dict,
128                                                                    SkBackend backend) {
129     std::vector<std::unique_ptr<SkPaintParamsKey>> keys;
130 
131     // TODO: actually split the SkPaint into multiple PaintParams and generate the keys
132     // for them separately.
133     // TODO: actually collect and return the SkUniformData vector for each PaintParams derived
134     // from the SkPaint
135     {
136         SkPaintParamsKeyBuilder builder(dict);
137 
138         if (paint.getShader()) {
139             as_SB(paint.getShader())->addToKey(dict, backend, &builder, nullptr);
140         } else {
141             SolidColorShaderBlock::AddToKey(dict, backend, &builder, nullptr, paint.getColor4f());
142         }
143 
144         if (paint.getBlender()) {
145             as_BB(paint.getBlender())->addToKey(dict, backend, &builder, nullptr);
146         } else {
147             BlendModeBlock::AddToKey(dict, backend, &builder, nullptr, SkBlendMode::kSrcOver);
148         }
149 
150         SkASSERT(builder.sizeInBytes() > 0);
151 
152         keys.push_back(builder.snap());
153     }
154 
155     return keys;
156 }
157