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