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 #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT 56 SkShaderBase::Context* SkLinearGradient::onMakeContext( 57 const ContextRec& rec, SkArenaAlloc* alloc) const 58 { 59 // make sure our colorspaces are compatible with legacy blits 60 if (!rec.isLegacyCompatible(fColorSpace.get())) { 61 return nullptr; 62 } 63 // Can't use legacy blit if we can't represent our colors as SkColors 64 if (!this->colorsCanConvertToSkColor()) { 65 return nullptr; 66 } 67 68 return fTileMode != kDecal_TileMode 69 ? CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec) 70 : nullptr; 71 } 72 73 SkShaderBase::Context* SkLinearGradient::onMakeBurstPipelineContext( 74 const ContextRec& rec, SkArenaAlloc* alloc) const { 75 76 if (fTileMode == SkShader::kDecal_TileMode) { 77 // we only support decal w/ stages 78 return nullptr; 79 } 80 // Raster pipeline has a 2-stop specialization faster than our burst. 81 return fColorCount > 2 ? CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec) 82 : nullptr; 83 } 84 #endif 85 86 void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*, 87 SkRasterPipeline*) const { 88 // No extra stage needed for linear gradients. 89 } 90 91 sk_sp<SkShader> SkLinearGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 92 const AutoXformColors xformedColors(*this, xformer); 93 SkPoint pts[2] = { fStart, fEnd }; 94 return SkGradientShader::MakeLinear(pts, xformedColors.fColors.get(), fOrigPos, fColorCount, 95 fTileMode, fGradFlags, &this->getLocalMatrix()); 96 } 97 98 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { 99 if (info) { 100 commonAsAGradient(info); 101 info->fPoint[0] = fStart; 102 info->fPoint[1] = fEnd; 103 } 104 return kLinear_GradientType; 105 } 106 107 ///////////////////////////////////////////////////////////////////// 108 109 #if SK_SUPPORT_GPU 110 111 #include "gradients/GrGradientShader.h" 112 113 std::unique_ptr<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor( 114 const GrFPArgs& args) const { 115 return GrGradientShader::MakeLinear(*this, args); 116 } 117 118 #endif 119