1/*
2 * Copyright 2013 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 "include/core/SkShader.h"
9#include "include/core/SkString.h"
10#include "src/core/SkArenaAlloc.h"
11#include "src/core/SkRasterPipeline.h"
12#include "src/core/SkReadBuffer.h"
13#include "src/core/SkVM.h"
14#include "src/core/SkWriteBuffer.h"
15#include "src/shaders/SkColorFilterShader.h"
16
17#if SK_SUPPORT_GPU
18#include "src/gpu/GrFragmentProcessor.h"
19#endif
20
21SkColorFilterShader::SkColorFilterShader(sk_sp<SkShader> shader,
22 float alpha,
23 sk_sp<SkColorFilter> filter)
24 : fShader(std::move(shader))
25 , fFilter(std::move(filter))
26 , fAlpha (alpha)
27{
28 SkASSERT(fShader);
29 SkASSERT(fFilter);
30}
31
32sk_sp<SkFlattenable> SkColorFilterShader::CreateProc(SkReadBuffer& buffer) {
33 auto shader = buffer.readShader();
34 auto filter = buffer.readColorFilter();
35 if (!shader || !filter) {
36 return nullptr;
37 }
38 return sk_make_sp<SkColorFilterShader>(shader, 1.0f, filter);
39}
40
41bool SkColorFilterShader::isOpaque() const {
42 return fShader->isOpaque()
43 && fAlpha == 1.0f
44 && (fFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) != 0;
45}
46
47void SkColorFilterShader::flatten(SkWriteBuffer& buffer) const {
48 buffer.writeFlattenable(fShader.get());
49 SkASSERT(fAlpha == 1.0f); // Not exposed in public API SkShader::makeWithColorFilter().
50 buffer.writeFlattenable(fFilter.get());
51}
52
53bool SkColorFilterShader::onAppendStages(const SkStageRec& rec) const {
54 if (!as_SB(fShader)->appendStages(rec)) {
55 return false;
56 }
57 if (fAlpha != 1.0f) {
58 rec.fPipeline->append(SkRasterPipeline::scale_1_float, rec.fAlloc->make<float>(fAlpha));
59 }
60 fFilter->appendStages(rec, fShader->isOpaque());
61 return true;
62}
63
64skvm::Color SkColorFilterShader::onProgram(skvm::Builder* p,
65 skvm::F32 x, skvm::F32 y, skvm::Color paint,
66 const SkMatrix& ctm, const SkMatrix* localM,
67 SkFilterQuality quality, const SkColorInfo& dst,
68 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
69 // Run the shader.
70 skvm::Color c = as_SB(fShader)->program(p, x,y, paint, ctm,localM, quality,dst, uniforms,alloc);
71 if (!c) {
72 return {};
73 }
74 // Scale that by alpha.
75 if (fAlpha != 1.0f) {
76 skvm::F32 A = p->uniformF(uniforms->pushF(fAlpha));
77 c.r *= A;
78 c.g *= A;
79 c.b *= A;
80 c.a *= A;
81 }
82
83 // Finally run that through the color filter.
84 return fFilter->program(p,c, dst.colorSpace(), uniforms,alloc);
85}
86
87#if SK_SUPPORT_GPU
88/////////////////////////////////////////////////////////////////////
89
90#include "include/gpu/GrContext.h"
91
92std::unique_ptr<GrFragmentProcessor> SkColorFilterShader::asFragmentProcessor(
93 const GrFPArgs& args) const {
94 auto fp1 = as_SB(fShader)->asFragmentProcessor(args);
95 if (!fp1) {
96 return nullptr;
97 }
98
99 // TODO I guess, but it shouldn't come up as used today.
100 SkASSERT(fAlpha == 1.0f);
101
102 auto fp2 = fFilter->asFragmentProcessor(args.fContext, *args.fDstColorInfo);
103 if (!fp2) {
104 return fp1;
105 }
106
107 std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(fp1), std::move(fp2) };
108 return GrFragmentProcessor::RunInSeries(fpSeries, 2);
109}
110#endif
111
112///////////////////////////////////////////////////////////////////////////////////////////////////
113
114sk_sp<SkShader> SkShader::makeWithColorFilter(sk_sp<SkColorFilter> filter) const {
115 SkShader* base = const_cast<SkShader*>(this);
116 if (!filter) {
117 return sk_ref_sp(base);
118 }
119 return sk_make_sp<SkColorFilterShader>(sk_ref_sp(base), 1.0f, filter);
120}
121