blob: 22b82215067a49d17b982d411ec2d744560322e1 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
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
Herb Derbyac04fef2017-01-13 17:34:33 -05008#include "SkArenaAlloc.h"
Mike Klein4e92b822017-04-26 13:45:36 -04009#include "SkColorFilter.h"
10#include "SkColorSpaceXformer.h"
11#include "SkNx.h"
12#include "SkPM4f.h"
Mike Klein6dfceca2017-05-09 11:52:35 -040013#include "SkRasterPipeline.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070015#include "SkRefCnt.h"
reed5bd055c2015-03-01 19:16:38 -080016#include "SkString.h"
bungemand3ebb482015-08-05 13:57:49 -070017#include "SkTDArray.h"
18#include "SkUnPreMultiply.h"
reeddb873d82015-03-01 19:53:47 -080019#include "SkWriteBuffer.h"
Mike Klein6dfceca2017-05-09 11:52:35 -040020#include "../jumper/SkJumper.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
bsalomone25eea42015-09-29 06:38:55 -070022#if SK_SUPPORT_GPU
23#include "GrFragmentProcessor.h"
24#endif
bungemand3ebb482015-08-05 13:57:49 -070025
Mike Reedfaba3712016-11-03 14:45:31 -040026bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const {
reed@google.com43c50c82011-04-14 15:50:52 +000027 return false;
28}
29
reed@google.combada6442012-12-17 20:21:44 +000030bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const {
senorblanco@chromium.orge5ff3ce2011-12-20 20:58:18 +000031 return false;
32}
33
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000034bool SkColorFilter::asComponentTable(SkBitmap*) const {
reed@google.com71918402012-01-05 17:24:35 +000035 return false;
36}
37
bungeman06ca8ec2016-06-09 08:01:03 -070038#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -040039std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrContext*,
40 SkColorSpace*) const {
bungeman06ca8ec2016-06-09 08:01:03 -070041 return nullptr;
42}
43#endif
44
Mike Klein6dfceca2017-05-09 11:52:35 -040045void SkColorFilter::appendStages(SkRasterPipeline* p,
46 SkColorSpace* dstCS,
47 SkArenaAlloc* alloc,
Mike Klein744908e2016-11-11 12:51:36 -050048 bool shaderIsOpaque) const {
Mike Kleinfdf31032017-05-09 14:57:58 -040049 this->onAppendStages(p, dstCS, alloc, shaderIsOpaque);
50}
Mike Klein6dfceca2017-05-09 11:52:35 -040051
reed@google.combada6442012-12-17 20:21:44 +000052SkColor SkColorFilter::filterColor(SkColor c) const {
Mike Reed9c1d7802017-06-29 11:37:15 -040053 const float inv255 = 1.0f / 255;
54 SkColor4f c4 = this->filterColor4f({
55 SkColorGetR(c) * inv255,
56 SkColorGetG(c) * inv255,
57 SkColorGetB(c) * inv255,
58 SkColorGetA(c) * inv255,
59 });
60 return SkColorSetARGB(sk_float_round2int(c4.fA*255),
61 sk_float_round2int(c4.fR*255),
62 sk_float_round2int(c4.fG*255),
63 sk_float_round2int(c4.fB*255));
reed@google.com6b7aee32011-04-19 18:36:09 +000064}
65
Mike Reed25f38052017-05-31 15:03:02 -040066#include "SkRasterPipeline.h"
reedf7cdb062016-02-04 11:35:27 -080067SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c) const {
68 SkPM4f dst, src = c.premul();
Mike Reed25f38052017-05-31 15:03:02 -040069
70 SkSTArenaAlloc<128> alloc;
71 SkRasterPipeline pipeline(&alloc);
72
Mike Klein073073e2017-08-03 09:42:53 -040073 pipeline.append_constant_color(&alloc, src);
Mike Reed25f38052017-05-31 15:03:02 -040074 this->onAppendStages(&pipeline, nullptr, &alloc, c.fA == 1);
Mike Klein45c16fa2017-07-18 18:15:13 -040075 SkJumper_MemoryCtx dstPtr = { &dst, 0 };
Mike Reed25f38052017-05-31 15:03:02 -040076 pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
Mike Klein45c16fa2017-07-18 18:15:13 -040077 pipeline.run(0,0, 1,1);
Mike Reed25f38052017-05-31 15:03:02 -040078
reedf7cdb062016-02-04 11:35:27 -080079 return dst.unpremul();
reed6d3cef92016-01-22 01:04:29 -080080}
81
reeddb873d82015-03-01 19:53:47 -080082///////////////////////////////////////////////////////////////////////////////////////////////////
83
reeddc812222015-03-05 07:21:02 -080084/*
85 * Since colorfilters may be used on the GPU backend, and in that case we may string together
86 * many GrFragmentProcessors, we might exceed some internal instruction/resource limit.
87 *
88 * Since we don't yet know *what* those limits might be when we construct the final shader,
89 * we just set an arbitrary limit during construction. If later we find smarter ways to know what
90 * the limnits are, we can change this constant (or remove it).
91 */
92#define SK_MAX_COMPOSE_COLORFILTER_COUNT 4
93
reeddb873d82015-03-01 19:53:47 -080094class SkComposeColorFilter : public SkColorFilter {
95public:
mtklein36352bf2015-03-25 18:17:31 -070096 uint32_t getFlags() const override {
reedf7cdb062016-02-04 11:35:27 -080097 // Can only claim alphaunchanged and SkPM4f support if both our proxys do.
reeddb873d82015-03-01 19:53:47 -080098 return fOuter->getFlags() & fInner->getFlags();
99 }
halcanary9d524f22016-03-29 09:03:52 -0700100
reeddb873d82015-03-01 19:53:47 -0800101#ifndef SK_IGNORE_TO_STRING
mtklein36352bf2015-03-25 18:17:31 -0700102 void toString(SkString* str) const override {
reeddb873d82015-03-01 19:53:47 -0800103 SkString outerS, innerS;
104 fOuter->toString(&outerS);
105 fInner->toString(&innerS);
Hal Canary27bece82017-03-07 16:23:20 -0500106 // These strings can be long. SkString::appendf has limitations.
107 str->append(SkStringPrintf("SkComposeColorFilter: outer(%s) inner(%s)", outerS.c_str(),
108 innerS.c_str()));
reeddb873d82015-03-01 19:53:47 -0800109 }
110#endif
111
Mike Kleinfdf31032017-05-09 14:57:58 -0400112 void onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkArenaAlloc* scratch,
Mike Reed9444bdd2017-05-05 12:23:42 -0400113 bool shaderIsOpaque) const override {
114 bool innerIsOpaque = shaderIsOpaque;
115 if (!(fInner->getFlags() & kAlphaUnchanged_Flag)) {
116 innerIsOpaque = false;
117 }
Mike Klein6dfceca2017-05-09 11:52:35 -0400118 fInner->appendStages(p, dst, scratch, shaderIsOpaque);
119 fOuter->appendStages(p, dst, scratch, innerIsOpaque);
Mike Reed9444bdd2017-05-05 12:23:42 -0400120 }
121
reeddb873d82015-03-01 19:53:47 -0800122#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400123 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
124 GrContext* context, SkColorSpace* dstColorSpace) const override {
125 auto innerFP = fInner->asFragmentProcessor(context, dstColorSpace);
126 auto outerFP = fOuter->asFragmentProcessor(context, dstColorSpace);
bsalomone25eea42015-09-29 06:38:55 -0700127 if (!innerFP || !outerFP) {
128 return nullptr;
129 }
Brian Salomonaff329b2017-08-11 09:40:37 -0400130 std::unique_ptr<GrFragmentProcessor> series[] = { std::move(innerFP), std::move(outerFP) };
bsalomone25eea42015-09-29 06:38:55 -0700131 return GrFragmentProcessor::RunInSeries(series, 2);
reedcff10b22015-03-03 06:41:45 -0800132 }
reeddb873d82015-03-01 19:53:47 -0800133#endif
134
135 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeColorFilter)
halcanary9d524f22016-03-29 09:03:52 -0700136
reeddb873d82015-03-01 19:53:47 -0800137protected:
mtklein36352bf2015-03-25 18:17:31 -0700138 void flatten(SkWriteBuffer& buffer) const override {
reedd053ce92016-03-22 10:17:23 -0700139 buffer.writeFlattenable(fOuter.get());
140 buffer.writeFlattenable(fInner.get());
reeddb873d82015-03-01 19:53:47 -0800141 }
halcanary9d524f22016-03-29 09:03:52 -0700142
reeddb873d82015-03-01 19:53:47 -0800143private:
reedd053ce92016-03-22 10:17:23 -0700144 SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner,
145 int composedFilterCount)
146 : fOuter(std::move(outer))
147 , fInner(std::move(inner))
reeddc812222015-03-05 07:21:02 -0800148 , fComposedFilterCount(composedFilterCount)
149 {
150 SkASSERT(composedFilterCount >= 2);
151 SkASSERT(composedFilterCount <= SK_MAX_COMPOSE_COLORFILTER_COUNT);
152 }
153
mtklein36352bf2015-03-25 18:17:31 -0700154 int privateComposedFilterCount() const override {
reeddc812222015-03-05 07:21:02 -0800155 return fComposedFilterCount;
156 }
157
Mike Klein4e92b822017-04-26 13:45:36 -0400158 sk_sp<SkColorFilter> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
Mike Reed6d9f4292017-07-06 12:32:55 -0400159 auto outer = xformer->apply(fOuter.get());
160 auto inner = xformer->apply(fInner.get());
161 if (outer != fOuter || inner != fInner) {
162 return SkColorFilter::MakeComposeFilter(outer, inner);
163 }
164 return this->INHERITED::onMakeColorSpace(xformer);
Mike Klein4e92b822017-04-26 13:45:36 -0400165 }
166
reedd053ce92016-03-22 10:17:23 -0700167 sk_sp<SkColorFilter> fOuter;
168 sk_sp<SkColorFilter> fInner;
169 const int fComposedFilterCount;
reeddb873d82015-03-01 19:53:47 -0800170
171 friend class SkColorFilter;
172
173 typedef SkColorFilter INHERITED;
174};
175
reed60c9b582016-04-03 09:11:13 -0700176sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) {
reedd053ce92016-03-22 10:17:23 -0700177 sk_sp<SkColorFilter> outer(buffer.readColorFilter());
178 sk_sp<SkColorFilter> inner(buffer.readColorFilter());
reed60c9b582016-04-03 09:11:13 -0700179 return MakeComposeFilter(std::move(outer), std::move(inner));
reeddb873d82015-03-01 19:53:47 -0800180}
181
reedd053ce92016-03-22 10:17:23 -0700182sk_sp<SkColorFilter> SkColorFilter::MakeComposeFilter(sk_sp<SkColorFilter> outer,
183 sk_sp<SkColorFilter> inner) {
reeddb873d82015-03-01 19:53:47 -0800184 if (!outer) {
reedd053ce92016-03-22 10:17:23 -0700185 return inner;
reeddb873d82015-03-01 19:53:47 -0800186 }
187 if (!inner) {
reedd053ce92016-03-22 10:17:23 -0700188 return outer;
reeddb873d82015-03-01 19:53:47 -0800189 }
reed8a8d8412015-03-02 13:46:03 -0800190
191 // Give the subclass a shot at a more optimal composition...
reedd053ce92016-03-22 10:17:23 -0700192 auto composition = outer->makeComposed(inner);
reeddc812222015-03-05 07:21:02 -0800193 if (composition) {
194 return composition;
reed8a8d8412015-03-02 13:46:03 -0800195 }
reeddc812222015-03-05 07:21:02 -0800196
197 int count = inner->privateComposedFilterCount() + outer->privateComposedFilterCount();
198 if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) {
halcanary96fcdcc2015-08-27 07:41:13 -0700199 return nullptr;
reeddc812222015-03-05 07:21:02 -0800200 }
reedd053ce92016-03-22 10:17:23 -0700201 return sk_sp<SkColorFilter>(new SkComposeColorFilter(std::move(outer), std::move(inner),count));
reeddb873d82015-03-01 19:53:47 -0800202}
203
Mike Reed412cda72017-07-05 15:43:15 -0400204///////////////////////////////////////////////////////////////////////////////////////////////////
205
206#if SK_SUPPORT_GPU
207#include "../gpu/effects/GrSRGBEffect.h"
208#endif
209
210class SkSRGBGammaColorFilter : public SkColorFilter {
211public:
212 enum class Direction {
213 kLinearToSRGB,
214 kSRGBToLinear,
215 };
216 SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {}
217
218#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400219 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrContext* x,
220 SkColorSpace* cs) const override {
Mike Reed98308fb2017-07-07 08:28:13 -0400221 // wish our caller would let us know if our input was opaque...
222 GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul;
Mike Reed412cda72017-07-05 15:43:15 -0400223 switch (fDir) {
224 case Direction::kLinearToSRGB:
Mike Reed98308fb2017-07-07 08:28:13 -0400225 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha);
Mike Reed412cda72017-07-05 15:43:15 -0400226 case Direction::kSRGBToLinear:
Mike Reed98308fb2017-07-07 08:28:13 -0400227 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha);
Mike Reed412cda72017-07-05 15:43:15 -0400228 }
229 return nullptr;
230 }
231#endif
232
233 SK_TO_STRING_OVERRIDE()
234
235 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter)
236
237 void onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc,
238 bool shaderIsOpaque) const override {
Mike Reedbdf6c622017-07-05 22:40:23 -0400239 if (!shaderIsOpaque) {
240 p->append(SkRasterPipeline::unpremul);
241 }
Mike Reed412cda72017-07-05 15:43:15 -0400242 switch (fDir) {
243 case Direction::kLinearToSRGB:
244 p->append(SkRasterPipeline::to_srgb);
245 break;
246 case Direction::kSRGBToLinear:
Mike Reedbdf6c622017-07-05 22:40:23 -0400247 p->append_from_srgb(shaderIsOpaque ? kOpaque_SkAlphaType : kUnpremul_SkAlphaType);
Mike Reed412cda72017-07-05 15:43:15 -0400248 break;
249 }
Mike Reedbdf6c622017-07-05 22:40:23 -0400250 if (!shaderIsOpaque) {
251 p->append(SkRasterPipeline::premul);
252 }
Mike Reed412cda72017-07-05 15:43:15 -0400253 }
254
255protected:
256 void flatten(SkWriteBuffer& buffer) const override {
257 buffer.write32(static_cast<uint32_t>(fDir));
258 }
259
260private:
261 const Direction fDir;
262
263 friend class SkColorFilter;
264 typedef SkColorFilter INHERITED;
265};
266
267sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
268 uint32_t dir = buffer.read32();
269 if (dir <= 1) {
270 return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir)));
271 }
272 buffer.validate(false);
273 return nullptr;
274}
275
276#ifndef SK_IGNORE_TO_STRING
277void SkSRGBGammaColorFilter::toString(SkString* str) const {
278 str->append("srgbgamma");
279}
280#endif
281
Florin Malitafff3a402017-07-19 10:32:28 -0400282template <SkSRGBGammaColorFilter::Direction dir>
283sk_sp<SkColorFilter> MakeSRGBGammaCF() {
284 static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
285 return sk_ref_sp(gSingleton);
286}
287
Mike Reed412cda72017-07-05 15:43:15 -0400288sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() {
Florin Malitafff3a402017-07-19 10:32:28 -0400289 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
Mike Reed412cda72017-07-05 15:43:15 -0400290}
291
292sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() {
Florin Malitafff3a402017-07-19 10:32:28 -0400293 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>();
Mike Reed412cda72017-07-05 15:43:15 -0400294}
295
296///////////////////////////////////////////////////////////////////////////////////////////////////
297
reedc7141eb2016-01-11 13:08:59 -0800298#include "SkModeColorFilter.h"
299
reeddb873d82015-03-01 19:53:47 -0800300SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
301SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter)
reedc7141eb2016-01-11 13:08:59 -0800302SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
Mike Reed412cda72017-07-05 15:43:15 -0400303SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter)
reeddb873d82015-03-01 19:53:47 -0800304SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END