+ SkColorSpace* dstCS = dst.colorSpace();
+ auto paintColor = alloc->make<SkPM4f>(SkPM4f_from_SkColor(paint.getColor(), dstCS));
+ auto shader = paint.getShader();
+
+ SkRasterPipeline_<256> shaderPipeline;
+ if (!shader) {
+ // Having no shader makes things nice and easy... just use the paint color.
+ shaderPipeline.append(SkRasterPipeline::constant_color, paintColor);
+ bool is_opaque = paintColor->a() == 1.0f,
+ is_constant = true,
+ wants_dither = false;
+ return SkRasterPipelineBlitter::Create(dst, paint, alloc,
+ shaderPipeline, nullptr,
+ is_opaque, is_constant, wants_dither);
+ }
+
+ bool is_opaque = shader->isOpaque() && paintColor->a() == 1.0f;
+ bool is_constant = shader->isConstant();
+ bool wants_dither = shader->asAGradient(nullptr) >= SkShader::kLinear_GradientType;
+
+ // See if the shader can express itself by appending pipeline stages.
+ if (shader->appendStages(&shaderPipeline, dstCS, alloc, ctm, paint)) {
+ if (paintColor->a() != 1.0f) {
+ shaderPipeline.append(SkRasterPipeline::scale_1_float, &paintColor->fVec[SkPM4f::A]);
+ }
+ return SkRasterPipelineBlitter::Create(dst, paint, alloc,
+ shaderPipeline, nullptr,
+ is_opaque, is_constant, wants_dither);
+ }
+
+ // No, the shader wants us to create a context and call shadeSpan4f().
+ SkASSERT(!is_constant); // All constant shaders should be able to appendStages().
+
+ if (dstCS) {
+ // We need to transform the shader into the dst color space, and extend its lifetime.
+ sk_sp<SkShader> in_dstCS = SkColorSpaceXformer::Make(sk_ref_sp(dstCS))->apply(shader);
+ shader = in_dstCS.get();
+ alloc->make<sk_sp<SkShader>>(std::move(in_dstCS));
+ }
+ SkShader::ContextRec rec(paint, ctm, nullptr, SkShader::ContextRec::kPM4f_DstType, dstCS);
+ SkShader::Context* shaderCtx = shader->makeContext(rec, alloc);
+ if (!shaderCtx) {
+ // When a shader fails to create a context, it has vetoed drawing entirely.
+ return alloc->make<SkNullBlitter>();
+ }
+ return SkRasterPipelineBlitter::Create(dst, paint, alloc,
+ shaderPipeline, shaderCtx,
+ is_opaque, is_constant, wants_dither);