blob: 4d93fae327dcef665b8ab586f216c6ceea9d5f53 [file] [log] [blame]
Matt Sarettcdc651d2017-03-30 12:41:48 -04001/*
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"
Matt Sarette6844832017-04-03 10:35:42 -040014#include "SkImagePriv.h"
Matt Sarettcdc651d2017-03-30 12:41:48 -040015#include "SkMakeUnique.h"
16
17std::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
30sk_sp<SkImage> SkColorSpaceXformer::apply(const SkImage* src) {
31 return as_IB(src)->makeColorSpace(fDst);
32}
33
Matt Sarette6844832017-04-03 10:35:42 -040034sk_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
Matt Sarettcdc651d2017-03-30 12:41:48 -040046void 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
52SkColor 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?
59sk_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 }
64
65 SkShader::TileMode xy[2];
66 SkMatrix local;
67 if (auto img = shader->isAImage(&local, xy)) {
68 return this->apply(img)->makeShader(xy[0], xy[1], &local);
69 }
70
71 SkShader::ComposeRec compose;
72 if (shader->asACompose(&compose)) {
73 auto A = this->apply(compose.fShaderA),
74 B = this->apply(compose.fShaderB);
75 if (A && B) {
76 return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode);
77 }
78 }
79
80 SkShader::GradientInfo gradient;
81 sk_bzero(&gradient, sizeof(gradient));
82 if (auto type = shader->asAGradient(&gradient)) {
83 SkSTArray<8, SkColor> colors(gradient.fColorCount);
84 SkSTArray<8, SkScalar> pos(gradient.fColorCount);
85
86 gradient.fColors = colors.begin();
87 gradient.fColorOffsets = pos.begin();
88 shader->asAGradient(&gradient);
89
90 SkSTArray<8, SkColor> xformed(gradient.fColorCount);
91 this->apply(xformed.begin(), gradient.fColors, gradient.fColorCount);
92
93 switch (type) {
94 case SkShader::kNone_GradientType:
95 case SkShader::kColor_GradientType:
96 SkASSERT(false); // Should be unreachable.
97 break;
98
99 case SkShader::kLinear_GradientType:
100 return SkGradientShader::MakeLinear(gradient.fPoint,
101 xformed.begin(),
102 gradient.fColorOffsets,
103 gradient.fColorCount,
104 gradient.fTileMode,
105 gradient.fGradientFlags,
106 &shader->getLocalMatrix());
107 case SkShader::kRadial_GradientType:
108 return SkGradientShader::MakeRadial(gradient.fPoint[0],
109 gradient.fRadius[0],
110 xformed.begin(),
111 gradient.fColorOffsets,
112 gradient.fColorCount,
113 gradient.fTileMode,
114 gradient.fGradientFlags,
115 &shader->getLocalMatrix());
116 case SkShader::kSweep_GradientType:
117 return SkGradientShader::MakeSweep(gradient.fPoint[0].fX,
118 gradient.fPoint[0].fY,
119 xformed.begin(),
120 gradient.fColorOffsets,
121 gradient.fColorCount,
122 gradient.fGradientFlags,
123 &shader->getLocalMatrix());
124 case SkShader::kConical_GradientType:
125 return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0],
126 gradient.fRadius[0],
127 gradient.fPoint[1],
128 gradient.fRadius[1],
129 xformed.begin(),
130 gradient.fColorOffsets,
131 gradient.fColorCount,
132 gradient.fTileMode,
133 gradient.fGradientFlags,
134 &shader->getLocalMatrix());
135 }
136 }
137
138 return nullptr;
139}
140
141const SkPaint& SkColorSpaceXformer::apply(const SkPaint& src) {
142 const SkPaint* result = &src;
143 auto get_dst = [&] {
144 if (result == &src) {
145 fDstPaint = src;
146 result = &fDstPaint;
147 }
148 return &fDstPaint;
149 };
150
151 // All SkColorSpaces have the same black point.
152 if (src.getColor() & 0xffffff) {
153 get_dst()->setColor(this->apply(src.getColor()));
154 }
155
156 if (auto shader = src.getShader()) {
157 if (auto replacement = this->apply(shader)) {
158 get_dst()->setShader(std::move(replacement));
159 }
160 }
161
162 // As far as I know, SkModeColorFilter is the only color filter that holds a color.
163 if (auto cf = src.getColorFilter()) {
164 SkColor color;
165 SkBlendMode mode;
166 if (cf->asColorMode(&color, &mode)) {
167 get_dst()->setColorFilter(SkColorFilter::MakeModeFilter(this->apply(color), mode));
168 }
169 }
170
171 if (auto looper = src.getDrawLooper()) {
172 get_dst()->setDrawLooper(looper->makeColorSpace(this));
173 }
174
175 // TODO:
176 // - image filters?
177 return *result;
178}
179
180const SkPaint* SkColorSpaceXformer::apply(const SkPaint* src) {
181 return src ? &this->apply(*src) : nullptr;
182}