1 /*
2 * Copyright 2017 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 "SkColorFilter.h"
9 #include "SkColorSpaceXformer.h"
10 #include "SkColorSpaceXform_Base.h"
11 #include "SkDrawLooper.h"
12 #include "SkGradientShader.h"
13 #include "SkImage_Base.h"
14 #include "SkImagePriv.h"
15 #include "SkMakeUnique.h"
16
Make(sk_sp<SkColorSpace> dst)17 std::unique_ptr<SkColorSpaceXformer> SkColorSpaceXformer::Make(sk_sp<SkColorSpace> dst) {
18 std::unique_ptr<SkColorSpaceXform> fromSRGB = SkColorSpaceXform_Base::New(
19 SkColorSpace::MakeSRGB().get(), dst.get(), SkTransferFunctionBehavior::kIgnore);
20 if (!fromSRGB) {
21 return nullptr;
22 }
23
24 auto xformer = std::unique_ptr<SkColorSpaceXformer>(new SkColorSpaceXformer());
25 xformer->fDst = std::move(dst);
26 xformer->fFromSRGB = std::move(fromSRGB);
27 return xformer;
28 }
29
apply(const SkImage * src)30 sk_sp<SkImage> SkColorSpaceXformer::apply(const SkImage* src) {
31 return as_IB(src)->makeColorSpace(fDst);
32 }
33
apply(const SkBitmap & src)34 sk_sp<SkImage> SkColorSpaceXformer::apply(const SkBitmap& src) {
35 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(src, kNever_SkCopyPixelsMode);
36 if (!image) {
37 return nullptr;
38 }
39
40 sk_sp<SkImage> xformed = as_IB(image)->makeColorSpace(fDst);
41 // We want to be sure we don't let the kNever_SkCopyPixelsMode image escape this stack frame.
42 SkASSERT(xformed != image);
43 return xformed;
44 }
45
apply(SkColor * xformed,const SkColor * srgb,int n)46 void SkColorSpaceXformer::apply(SkColor* xformed, const SkColor* srgb, int n) {
47 SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed,
48 SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb,
49 n, kUnpremul_SkAlphaType));
50 }
51
apply(SkColor srgb)52 SkColor SkColorSpaceXformer::apply(SkColor srgb) {
53 SkColor xformed;
54 this->apply(&xformed, &srgb, 1);
55 return xformed;
56 }
57
58 // TODO: Is this introspection going to be enough, or do we need a new SkShader method?
apply(const SkShader * shader)59 sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
60 SkColor color;
61 if (shader->isConstant() && shader->asLuminanceColor(&color)) {
62 return SkShader::MakeColorShader(this->apply(color))
63 ->makeWithLocalMatrix(shader->getLocalMatrix());
64 }
65
66 SkShader::TileMode xy[2];
67 SkMatrix local;
68 if (auto img = shader->isAImage(&local, xy)) {
69 return this->apply(img)->makeShader(xy[0], xy[1], &local);
70 }
71
72 SkShader::ComposeRec compose;
73 if (shader->asACompose(&compose)) {
74 auto A = this->apply(compose.fShaderA),
75 B = this->apply(compose.fShaderB);
76 if (A && B) {
77 return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode)
78 ->makeWithLocalMatrix(shader->getLocalMatrix());
79 }
80 }
81
82 SkShader::GradientInfo gradient;
83 sk_bzero(&gradient, sizeof(gradient));
84 if (auto type = shader->asAGradient(&gradient)) {
85 SkSTArray<8, SkColor> colors(gradient.fColorCount);
86 SkSTArray<8, SkScalar> pos(gradient.fColorCount);
87
88 gradient.fColors = colors.begin();
89 gradient.fColorOffsets = pos.begin();
90 shader->asAGradient(&gradient);
91
92 SkSTArray<8, SkColor> xformed(gradient.fColorCount);
93 this->apply(xformed.begin(), gradient.fColors, gradient.fColorCount);
94
95 switch (type) {
96 case SkShader::kNone_GradientType:
97 case SkShader::kColor_GradientType:
98 SkASSERT(false); // Should be unreachable.
99 break;
100
101 case SkShader::kLinear_GradientType:
102 return SkGradientShader::MakeLinear(gradient.fPoint,
103 xformed.begin(),
104 gradient.fColorOffsets,
105 gradient.fColorCount,
106 gradient.fTileMode,
107 gradient.fGradientFlags,
108 &shader->getLocalMatrix());
109 case SkShader::kRadial_GradientType:
110 return SkGradientShader::MakeRadial(gradient.fPoint[0],
111 gradient.fRadius[0],
112 xformed.begin(),
113 gradient.fColorOffsets,
114 gradient.fColorCount,
115 gradient.fTileMode,
116 gradient.fGradientFlags,
117 &shader->getLocalMatrix());
118 case SkShader::kSweep_GradientType:
119 return SkGradientShader::MakeSweep(gradient.fPoint[0].fX,
120 gradient.fPoint[0].fY,
121 xformed.begin(),
122 gradient.fColorOffsets,
123 gradient.fColorCount,
124 gradient.fGradientFlags,
125 &shader->getLocalMatrix());
126 case SkShader::kConical_GradientType:
127 return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0],
128 gradient.fRadius[0],
129 gradient.fPoint[1],
130 gradient.fRadius[1],
131 xformed.begin(),
132 gradient.fColorOffsets,
133 gradient.fColorCount,
134 gradient.fTileMode,
135 gradient.fGradientFlags,
136 &shader->getLocalMatrix());
137 }
138 }
139
140 return sk_ref_sp(const_cast<SkShader*>(shader));
141 }
142
apply(const SkPaint & src)143 SkPaint SkColorSpaceXformer::apply(const SkPaint& src) {
144 SkPaint dst = src;
145
146 // All SkColorSpaces have the same black point.
147 if (src.getColor() & 0xffffff) {
148 dst.setColor(this->apply(src.getColor()));
149 }
150
151 if (auto shader = src.getShader()) {
152 dst.setShader(this->apply(shader));
153 }
154
155 // As far as I know, SkModeColorFilter is the only color filter that holds a color.
156 if (auto cf = src.getColorFilter()) {
157 SkColor color;
158 SkBlendMode mode;
159 if (cf->asColorMode(&color, &mode)) {
160 dst.setColorFilter(SkColorFilter::MakeModeFilter(this->apply(color), mode));
161 }
162 }
163
164 if (auto looper = src.getDrawLooper()) {
165 dst.setDrawLooper(looper->makeColorSpace(this));
166 }
167
168 // TODO:
169 // - image filters?
170 return dst;
171 }
172