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 15static 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 30SkLinearGradient::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 36sk_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 49void SkLinearGradient::flatten(SkWriteBuffer& buffer) const { 50 this->INHERITED::flatten(buffer); 51 buffer.writePoint(fStart); 52 buffer.writePoint(fEnd); 53} 54 55SkShaderBase::Context* SkLinearGradient::onMakeContext( 56 const ContextRec& rec, SkArenaAlloc* alloc) const 57{ 58 return CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec); 59} 60 61SkShaderBase::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 69void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*, 70 SkRasterPipeline*) const { 71 // No extra stage needed for linear gradients. 72} 73 74sk_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 81SkShader::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 98class GrLinearGradient : public GrGradientEffect { 99public: 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 114private: 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 130class GrLinearGradient::GLSLLinearProcessor : public GrGradientEffect::GLSLProcessor { 131public: 132 GLSLLinearProcessor(const GrProcessor&) {} 133 134 virtual void emitCode(EmitArgs&) override; 135 136private: 137 typedef GrGradientEffect::GLSLProcessor INHERITED; 138}; 139 140///////////////////////////////////////////////////////////////////// 141 142GrGLSLFragmentProcessor* GrLinearGradient::onCreateGLSLInstance() const { 143 return new GrLinearGradient::GLSLLinearProcessor(*this); 144} 145 146///////////////////////////////////////////////////////////////////// 147 148GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradient); 149 150#if GR_TEST_UTILS 151std::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 170void 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 187std::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 212void 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