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