1 /*
2  * Copyright 2012 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 "SkLinearGradient.h"
9 
10 #include "Sk4fLinearGradient.h"
11 #include "SkColorSpaceXformer.h"
12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h"
14 
15 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
16     SkVector    vec = pts[1] - pts[0];
17     SkScalar    mag = vec.length();
18     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
19 
20     vec.scale(inv);
21     SkMatrix matrix;
22     matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
23     matrix.postTranslate(-pts[0].fX, -pts[0].fY);
24     matrix.postScale(inv, inv);
25     return matrix;
26 }
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 
30 SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
31     : SkGradientShaderBase(desc, pts_to_unit_matrix(pts))
32     , fStart(pts[0])
33     , fEnd(pts[1]) {
34 }
35 
36 sk_sp<SkFlattenable> SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
37     DescriptorScope desc;
38     if (!desc.unflatten(buffer)) {
39         return nullptr;
40     }
41     SkPoint pts[2];
42     pts[0] = buffer.readPoint();
43     pts[1] = buffer.readPoint();
44     return SkGradientShader::MakeLinear(pts, desc.fColors, std::move(desc.fColorSpace), desc.fPos,
45                                         desc.fCount, desc.fTileMode, desc.fGradFlags,
46                                         desc.fLocalMatrix);
47 }
48 
49 void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
50     this->INHERITED::flatten(buffer);
51     buffer.writePoint(fStart);
52     buffer.writePoint(fEnd);
53 }
54 
55 SkShaderBase::Context* SkLinearGradient::onMakeContext(
56     const ContextRec& rec, SkArenaAlloc* alloc) const
57 {
58     return CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec);
59 }
60 
61 SkShaderBase::Context* SkLinearGradient::onMakeBurstPipelineContext(
62     const ContextRec& rec, SkArenaAlloc* alloc) const {
63 
64     // Raster pipeline has a 2-stop specialization faster than our burst.
65     return fColorCount > 2 ? CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec)
66                            : nullptr;
67 }
68 
69 void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*,
70                                             SkRasterPipeline*) const {
71     // No extra stage needed for linear gradients.
72 }
73 
74 sk_sp<SkShader> SkLinearGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
75     const AutoXformColors xformedColors(*this, xformer);
76     SkPoint pts[2] = { fStart, fEnd };
77     return SkGradientShader::MakeLinear(pts, xformedColors.fColors.get(), fOrigPos, fColorCount,
78                                         fTileMode, fGradFlags, &this->getLocalMatrix());
79 }
80 
81 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
82     if (info) {
83         commonAsAGradient(info);
84         info->fPoint[0] = fStart;
85         info->fPoint[1] = fEnd;
86     }
87     return kLinear_GradientType;
88 }
89 
90 #if SK_SUPPORT_GPU
91 
92 #include "GrShaderCaps.h"
93 #include "glsl/GrGLSLFragmentShaderBuilder.h"
94 #include "SkGr.h"
95 
96 /////////////////////////////////////////////////////////////////////
97 
98 class GrLinearGradient : public GrGradientEffect {
99 public:
100     class GLSLLinearProcessor;
101 
102     static std::unique_ptr<GrFragmentProcessor> Make(const CreateArgs& args) {
103         return GrGradientEffect::AdjustFP(std::unique_ptr<GrLinearGradient>(
104                 new GrLinearGradient(args)),
105                 args);
106     }
107 
108     const char* name() const override { return "Linear Gradient"; }
109 
110     std::unique_ptr<GrFragmentProcessor> clone() const override {
111         return std::unique_ptr<GrFragmentProcessor>(new GrLinearGradient(*this));
112     }
113 
114 private:
115     explicit GrLinearGradient(const CreateArgs& args)
116             : INHERITED(kGrLinearGradient_ClassID, args, args.fShader->colorsAreOpaque()) {
117     }
118 
119     explicit GrLinearGradient(const GrLinearGradient& that) : INHERITED(that) {}
120 
121     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
122 
123     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
124 
125     typedef GrGradientEffect INHERITED;
126 };
127 
128 /////////////////////////////////////////////////////////////////////
129 
130 class GrLinearGradient::GLSLLinearProcessor : public GrGradientEffect::GLSLProcessor {
131 public:
132     GLSLLinearProcessor(const GrProcessor&) {}
133 
134     virtual void emitCode(EmitArgs&) override;
135 
136 private:
137     typedef GrGradientEffect::GLSLProcessor INHERITED;
138 };
139 
140 /////////////////////////////////////////////////////////////////////
141 
142 GrGLSLFragmentProcessor* GrLinearGradient::onCreateGLSLInstance() const {
143     return new GrLinearGradient::GLSLLinearProcessor(*this);
144 }
145 
146 /////////////////////////////////////////////////////////////////////
147 
148 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradient);
149 
150 #if GR_TEST_UTILS
151 std::unique_ptr<GrFragmentProcessor> GrLinearGradient::TestCreate(GrProcessorTestData* d) {
152     SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()},
153                         {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}};
154 
155     RandomGradientParams params(d->fRandom);
156     auto shader = params.fUseColors4f ?
157         SkGradientShader::MakeLinear(points, params.fColors4f, params.fColorSpace, params.fStops,
158                                      params.fColorCount, params.fTileMode) :
159         SkGradientShader::MakeLinear(points, params.fColors, params.fStops,
160                                      params.fColorCount, params.fTileMode);
161     GrTest::TestAsFPArgs asFPArgs(d);
162     std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
163     GrAlwaysAssert(fp);
164     return fp;
165 }
166 #endif
167 
168 /////////////////////////////////////////////////////////////////////
169 
170 void GrLinearGradient::GLSLLinearProcessor::emitCode(EmitArgs& args) {
171     const GrLinearGradient& ge = args.fFp.cast<GrLinearGradient>();
172     this->emitUniforms(args.fUniformHandler, ge);
173     SkString t = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
174     t.append(".x");
175     this->emitColor(args.fFragBuilder,
176                     args.fUniformHandler,
177                     args.fShaderCaps,
178                     ge,
179                     t.c_str(),
180                     args.fOutputColor,
181                     args.fInputColor,
182                     args.fTexSamplers);
183 }
184 
185 /////////////////////////////////////////////////////////////////////
186 
187 std::unique_ptr<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor(
188         const GrFPArgs& args) const {
189     SkASSERT(args.fContext);
190 
191     SkMatrix matrix;
192     if (!this->getLocalMatrix().invert(&matrix)) {
193         return nullptr;
194     }
195     if (args.fLocalMatrix) {
196         SkMatrix inv;
197         if (!args.fLocalMatrix->invert(&inv)) {
198             return nullptr;
199         }
200         matrix.postConcat(inv);
201     }
202     matrix.postConcat(fPtsToUnit);
203 
204     return GrLinearGradient::Make(GrGradientEffect::CreateArgs(
205             args.fContext, this, &matrix, fTileMode, args.fDstColorSpaceInfo->colorSpace()));
206 }
207 
208 
209 #endif
210 
211 #ifndef SK_IGNORE_TO_STRING
212 void SkLinearGradient::toString(SkString* str) const {
213     str->append("SkLinearGradient (");
214 
215     str->appendf("start: (%f, %f)", fStart.fX, fStart.fY);
216     str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY);
217 
218     this->INHERITED::toString(str);
219 
220     str->append(")");
221 }
222 #endif
223