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/SkColorFilter.h"
9#include "include/core/SkPaint.h"
10#include "src/core/SkColorSpacePriv.h"
11#include "src/core/SkPaintPriv.h"
12#include "src/core/SkXfermodePriv.h"
13#include "src/shaders/SkColorFilterShader.h"
14#include "src/shaders/SkShaderBase.h"
15
16static bool changes_alpha(const SkPaint& paint) {
17 SkColorFilter* cf = paint.getColorFilter();
18 return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
19}
20
21bool SkPaintPriv::Overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) {
22 if (!paint) {
23 // No paint means we default to SRC_OVER, so we overwrite iff our shader-override
24 // is opaque, or we don't have one.
25 return overrideOpacity != kNotOpaque_ShaderOverrideOpacity;
26 }
27
28 SkXfermode::SrcColorOpacity opacityType = SkXfermode::kUnknown_SrcColorOpacity;
29
30 if (!changes_alpha(*paint)) {
31 const unsigned paintAlpha = paint->getAlpha();
32 if (0xff == paintAlpha && overrideOpacity != kNotOpaque_ShaderOverrideOpacity &&
33 (!paint->getShader() || paint->getShader()->isOpaque()))
34 {
35 opacityType = SkXfermode::kOpaque_SrcColorOpacity;
36 } else if (0 == paintAlpha) {
37 if (overrideOpacity == kNone_ShaderOverrideOpacity && !paint->getShader()) {
38 opacityType = SkXfermode::kTransparentBlack_SrcColorOpacity;
39 } else {
40 opacityType = SkXfermode::kTransparentAlpha_SrcColorOpacity;
41 }
42 }
43 }
44
45 return SkXfermode::IsOpaque(paint->getBlendMode(), opacityType);
46}
47
48bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) {
49 // The paint dither flag can veto.
50 if (!p.isDither()) {
51 return false;
52 }
53
54 // We always dither 565 or 4444 when requested.
55 if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
56 return true;
57 }
58
59 // Otherwise, dither is only needed for non-const paints.
60 return p.getImageFilter() || p.getMaskFilter()
61 || !p.getShader() || !as_SB(p.getShader())->isConstant();
62}
63
64// return true if the paint is just a single color (i.e. not a shader). If its
65// a shader, then we can't compute a const luminance for it :(
66static bool just_a_color(const SkPaint& paint, SkColor* color) {
67 SkColor c = paint.getColor();
68
69 const auto* shader = as_SB(paint.getShader());
70 if (shader && !shader->asLuminanceColor(&c)) {
71 return false;
72 }
73 if (paint.getColorFilter()) {
74 c = paint.getColorFilter()->filterColor(c);
75 }
76 if (color) {
77 *color = c;
78 }
79 return true;
80}
81
82SkColor SkPaintPriv::ComputeLuminanceColor(const SkPaint& paint) {
83 SkColor c;
84 if (!just_a_color(paint, &c)) {
85 c = SkColorSetRGB(0x7F, 0x80, 0x7F);
86 }
87 return c;
88}
89
90void SkPaintPriv::RemoveColorFilter(SkPaint* p, SkColorSpace* dstCS) {
91 if (SkColorFilter* filter = p->getColorFilter()) {
92 if (SkShader* shader = p->getShader()) {
93 // SkColorFilterShader will modulate the shader color by paint alpha
94 // before applying the filter, so we'll reset it to opaque.
95 p->setShader(sk_make_sp<SkColorFilterShader>(sk_ref_sp(shader),
96 p->getAlphaf(),
97 sk_ref_sp(filter)));
98 p->setAlphaf(1.0f);
99 } else {
100 p->setColor(filter->filterColor4f(p->getColor4f(), sk_srgb_singleton(), dstCS), dstCS);
101 }
102 p->setColorFilter(nullptr);
103 }
104}
105