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