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