1 /* 2 * Copyright 2021 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 "src/shaders/SkTransformShader.h" 9 10 #include "include/core/SkMatrix.h" 11 #include "src/core/SkEffectPriv.h" 12 #include "src/core/SkRasterPipeline.h" 13 #include "src/core/SkRasterPipelineOpList.h" 14 15 #include <optional> 16 SkTransformShader(const SkShaderBase & shader,bool allowPerspective)17SkTransformShader::SkTransformShader(const SkShaderBase& shader, bool allowPerspective) 18 : fShader{shader}, fAllowPerspective{allowPerspective} { 19 SkMatrix::I().get9(fMatrixStorage); 20 } 21 update(const SkMatrix & matrix)22bool SkTransformShader::update(const SkMatrix& matrix) { 23 if (!fAllowPerspective && matrix.hasPerspective()) { 24 return false; 25 } 26 27 matrix.get9(fMatrixStorage); 28 return true; 29 } 30 appendStages(const SkStageRec & rec,const SkShaders::MatrixRec & mRec) const31bool SkTransformShader::appendStages(const SkStageRec& rec, 32 const SkShaders::MatrixRec& mRec) const { 33 // We have to seed and apply any constant matrices before appending our matrix that may 34 // mutate. We could try to add one matrix stage and then incorporate the parent matrix 35 // with the variable matrix in each call to update(). However, in practice our callers 36 // fold the CTM into the update() matrix and don't wrap the transform shader in local matrix 37 // shaders so the call to apply below should just seed the coordinates. If this assert fires 38 // it just indicates an optimization opportunity, not a correctness bug. 39 SkASSERT(!mRec.hasPendingMatrix()); 40 std::optional<SkShaders::MatrixRec> childMRec = mRec.apply(rec); 41 if (!childMRec.has_value()) { 42 return false; 43 } 44 // The matrix we're about to insert gets updated between uses of the pipeline so our children 45 // can't know the total transform when they add their stages. We don't even incorporate this 46 // matrix into the SkShaders::MatrixRec at all. 47 childMRec->markTotalMatrixInvalid(); 48 49 auto type = fAllowPerspective ? SkRasterPipelineOp::matrix_perspective 50 : SkRasterPipelineOp::matrix_2x3; 51 rec.fPipeline->append(type, fMatrixStorage); 52 53 fShader.appendStages(rec, *childMRec); 54 return true; 55 } 56