1 /* 2 * Copyright 2006 The Android Open Source Project 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 "include/core/SkMallocPixelRef.h" 9 #include "include/core/SkPaint.h" 10 #include "include/core/SkPicture.h" 11 #include "include/core/SkScalar.h" 12 #include "src/core/SkArenaAlloc.h" 13 #include "src/core/SkColorSpacePriv.h" 14 #include "src/core/SkColorSpaceXformSteps.h" 15 #include "src/core/SkRasterPipeline.h" 16 #include "src/core/SkReadBuffer.h" 17 #include "src/core/SkTLazy.h" 18 #include "src/core/SkWriteBuffer.h" 19 #include "src/shaders/SkBitmapProcShader.h" 20 #include "src/shaders/SkColorShader.h" 21 #include "src/shaders/SkEmptyShader.h" 22 #include "src/shaders/SkPictureShader.h" 23 #include "src/shaders/SkShaderBase.h" 24 25 #if SK_SUPPORT_GPU 26 #include "src/gpu/GrFragmentProcessor.h" 27 #endif 28 SkShaderBase(const SkMatrix * localMatrix)29 SkShaderBase::SkShaderBase(const SkMatrix* localMatrix) 30 : fLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()) { 31 // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe. 32 (void)fLocalMatrix.getType(); 33 } 34 ~SkShaderBase()35 SkShaderBase::~SkShaderBase() {} 36 flatten(SkWriteBuffer & buffer) const37 void SkShaderBase::flatten(SkWriteBuffer& buffer) const { 38 this->INHERITED::flatten(buffer); 39 bool hasLocalM = !fLocalMatrix.isIdentity(); 40 buffer.writeBool(hasLocalM); 41 if (hasLocalM) { 42 buffer.writeMatrix(fLocalMatrix); 43 } 44 } 45 46 SkTCopyOnFirstWrite<SkMatrix> totalLocalMatrix(const SkMatrix * preLocalMatrix,const SkMatrix * postLocalMatrix) const47 SkShaderBase::totalLocalMatrix(const SkMatrix* preLocalMatrix, 48 const SkMatrix* postLocalMatrix) const { 49 SkTCopyOnFirstWrite<SkMatrix> m(fLocalMatrix); 50 51 if (preLocalMatrix) { 52 m.writable()->preConcat(*preLocalMatrix); 53 } 54 55 if (postLocalMatrix) { 56 m.writable()->postConcat(*postLocalMatrix); 57 } 58 59 return m; 60 } 61 computeTotalInverse(const SkMatrix & ctm,const SkMatrix * outerLocalMatrix,SkMatrix * totalInverse) const62 bool SkShaderBase::computeTotalInverse(const SkMatrix& ctm, 63 const SkMatrix* outerLocalMatrix, 64 SkMatrix* totalInverse) const { 65 return SkMatrix::Concat(ctm, *this->totalLocalMatrix(outerLocalMatrix)).invert(totalInverse); 66 } 67 asLuminanceColor(SkColor * colorPtr) const68 bool SkShaderBase::asLuminanceColor(SkColor* colorPtr) const { 69 SkColor storage; 70 if (nullptr == colorPtr) { 71 colorPtr = &storage; 72 } 73 if (this->onAsLuminanceColor(colorPtr)) { 74 *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque 75 return true; 76 } 77 return false; 78 } 79 makeContext(const ContextRec & rec,SkArenaAlloc * alloc) const80 SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { 81 #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT 82 // We always fall back to raster pipeline when perspective is present. 83 if (rec.fMatrix->hasPerspective() || 84 fLocalMatrix.hasPerspective() || 85 (rec.fLocalMatrix && rec.fLocalMatrix->hasPerspective()) || 86 !this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr)) { 87 return nullptr; 88 } 89 90 return this->onMakeContext(rec, alloc); 91 #else 92 return nullptr; 93 #endif 94 } 95 Context(const SkShaderBase & shader,const ContextRec & rec)96 SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec) 97 : fShader(shader), fCTM(*rec.fMatrix) 98 { 99 // We should never use a context with perspective. 100 SkASSERT(!rec.fMatrix->hasPerspective()); 101 SkASSERT(!rec.fLocalMatrix || !rec.fLocalMatrix->hasPerspective()); 102 SkASSERT(!shader.getLocalMatrix().hasPerspective()); 103 104 // Because the context parameters must be valid at this point, we know that the matrix is 105 // invertible. 106 SkAssertResult(fShader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &fTotalInverse)); 107 108 fPaintAlpha = rec.fPaint->getAlpha(); 109 } 110 ~Context()111 SkShaderBase::Context::~Context() {} 112 isLegacyCompatible(SkColorSpace * shaderColorSpace) const113 bool SkShaderBase::ContextRec::isLegacyCompatible(SkColorSpace* shaderColorSpace) const { 114 return !SkColorSpaceXformSteps::Required(shaderColorSpace, fDstColorSpace); 115 } 116 isAImage(SkMatrix * localMatrix,SkTileMode xy[2]) const117 SkImage* SkShader::isAImage(SkMatrix* localMatrix, SkTileMode xy[2]) const { 118 return as_SB(this)->onIsAImage(localMatrix, xy); 119 } 120 asAGradient(GradientInfo * info) const121 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 122 return kNone_GradientType; 123 } 124 125 #if SK_SUPPORT_GPU asFragmentProcessor(const GrFPArgs &) const126 std::unique_ptr<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const GrFPArgs&) const { 127 return nullptr; 128 } 129 #endif 130 makeAsALocalMatrixShader(SkMatrix *) const131 sk_sp<SkShader> SkShaderBase::makeAsALocalMatrixShader(SkMatrix*) const { 132 return nullptr; 133 } 134 Empty()135 sk_sp<SkShader> SkShaders::Empty() { return sk_make_sp<SkEmptyShader>(); } Color(SkColor color)136 sk_sp<SkShader> SkShaders::Color(SkColor color) { return sk_make_sp<SkColorShader>(color); } 137 makeShader(SkTileMode tmx,SkTileMode tmy,const SkMatrix * lm) const138 sk_sp<SkShader> SkBitmap::makeShader(SkTileMode tmx, SkTileMode tmy, const SkMatrix* lm) const { 139 if (lm && !lm->invert(nullptr)) { 140 return nullptr; 141 } 142 return SkMakeBitmapShader(*this, tmx, tmy, lm, kIfMutable_SkCopyPixelsMode); 143 } 144 makeShader(const SkMatrix * lm) const145 sk_sp<SkShader> SkBitmap::makeShader(const SkMatrix* lm) const { 146 return this->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, lm); 147 } 148 appendStages(const SkStageRec & rec) const149 bool SkShaderBase::appendStages(const SkStageRec& rec) const { 150 return this->onAppendStages(rec); 151 } 152 onAppendStages(const SkStageRec & rec) const153 bool SkShaderBase::onAppendStages(const SkStageRec& rec) const { 154 // SkShader::Context::shadeSpan() handles the paint opacity internally, 155 // but SkRasterPipelineBlitter applies it as a separate stage. 156 // We skip the internal shadeSpan() step by forcing the paint opaque. 157 SkTCopyOnFirstWrite<SkPaint> opaquePaint(rec.fPaint); 158 if (rec.fPaint.getAlpha() != SK_AlphaOPAQUE) { 159 opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE); 160 } 161 162 ContextRec cr(*opaquePaint, rec.fCTM, rec.fLocalM, rec.fDstColorType, sk_srgb_singleton()); 163 164 struct CallbackCtx : SkRasterPipeline_CallbackCtx { 165 sk_sp<const SkShader> shader; 166 Context* ctx; 167 }; 168 auto cb = rec.fAlloc->make<CallbackCtx>(); 169 cb->shader = sk_ref_sp(this); 170 cb->ctx = as_SB(this)->makeContext(cr, rec.fAlloc); 171 cb->fn = [](SkRasterPipeline_CallbackCtx* self, int active_pixels) { 172 auto c = (CallbackCtx*)self; 173 int x = (int)c->rgba[0], 174 y = (int)c->rgba[1]; 175 SkPMColor tmp[SkRasterPipeline_kMaxStride]; 176 c->ctx->shadeSpan(x,y, tmp, active_pixels); 177 178 for (int i = 0; i < active_pixels; i++) { 179 auto rgba_4f = SkPMColor4f::FromPMColor(tmp[i]); 180 memcpy(c->rgba + 4*i, rgba_4f.vec(), 4*sizeof(float)); 181 } 182 }; 183 184 if (cb->ctx) { 185 rec.fPipeline->append(SkRasterPipeline::seed_shader); 186 rec.fPipeline->append(SkRasterPipeline::callback, cb); 187 rec.fAlloc->make<SkColorSpaceXformSteps>(sk_srgb_singleton(), kPremul_SkAlphaType, 188 rec.fDstCS, kPremul_SkAlphaType) 189 ->apply(rec.fPipeline, true); 190 return true; 191 } 192 return false; 193 } 194 195 /////////////////////////////////////////////////////////////////////////////////////////////////// 196 CreateProc(SkReadBuffer &)197 sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) { 198 return SkShaders::Empty(); 199 } 200