/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/shaders/gradients/SkRadialGradient.h" #include "include/core/SkColor.h" #include "include/core/SkColorSpace.h" #include "include/core/SkMatrix.h" #include "include/core/SkRefCnt.h" #include "include/core/SkShader.h" #include "include/effects/SkGradientShader.h" #include "include/private/base/SkTArray.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkRasterPipelineOpList.h" #include "src/core/SkReadBuffer.h" #include "src/core/SkWriteBuffer.h" #include "src/shaders/SkShaderBase.h" #include "src/shaders/gradients/SkGradientBaseShader.h" #include #include class SkArenaAlloc; enum class SkTileMode; static SkMatrix rad_to_unit_matrix(const SkPoint& center, SkScalar radius) { SkScalar inv = SkScalarInvert(radius); SkMatrix matrix; matrix.setTranslate(-center.fX, -center.fY); matrix.postScale(inv, inv); return matrix; } SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc) : SkGradientBaseShader(desc, rad_to_unit_matrix(center, radius)) , fCenter(center) , fRadius(radius) {} SkShaderBase::GradientType SkRadialGradient::asGradient(GradientInfo* info, SkMatrix* localMatrix) const { if (info) { commonAsAGradient(info); info->fPoint[0] = fCenter; info->fRadius[0] = fRadius; } if (localMatrix) { *localMatrix = SkMatrix::I(); } return GradientType::kRadial; } sk_sp SkRadialGradient::CreateProc(SkReadBuffer& buffer) { DescriptorScope desc; SkMatrix legacyLocalMatrix, *lmPtr = nullptr; if (!desc.unflatten(buffer, &legacyLocalMatrix)) { return nullptr; } if (!legacyLocalMatrix.isIdentity()) { lmPtr = &legacyLocalMatrix; } const SkPoint center = buffer.readPoint(); const SkScalar radius = buffer.readScalar(); return SkGradientShader::MakeRadial(center, radius, desc.fColors, std::move(desc.fColorSpace), desc.fPositions, desc.fColorCount, desc.fTileMode, desc.fInterpolation, lmPtr); } void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { this->SkGradientBaseShader::flatten(buffer); buffer.writePoint(fCenter); buffer.writeScalar(fRadius); } void SkRadialGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p, SkRasterPipeline*) const { p->append(SkRasterPipelineOp::xy_to_radius); } sk_sp SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius, const SkColor4f colors[], sk_sp colorSpace, const SkScalar pos[], int colorCount, SkTileMode mode, const Interpolation& interpolation, const SkMatrix* localMatrix) { if (radius < 0) { return nullptr; } if (!SkGradientBaseShader::ValidGradient(colors, colorCount, mode, interpolation)) { return nullptr; } if (1 == colorCount) { return SkShaders::Color(colors[0], std::move(colorSpace)); } if (localMatrix && !localMatrix->invert(nullptr)) { return nullptr; } if (SkScalarNearlyZero(radius, SkGradientBaseShader::kDegenerateThreshold)) { // Degenerate gradient optimization, and no special logic needed for clamped radial gradient return SkGradientBaseShader::MakeDegenerateGradient( colors, pos, colorCount, std::move(colorSpace), mode); } SkGradientBaseShader::Descriptor desc( colors, std::move(colorSpace), pos, colorCount, mode, interpolation); sk_sp s = sk_make_sp(center, radius, desc); return s->makeWithLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()); } sk_sp SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int colorCount, SkTileMode mode, uint32_t flags, const SkMatrix* localMatrix) { SkColorConverter converter(colors, colorCount); return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags, localMatrix); } void SkRegisterRadialGradientShaderFlattenable() { SK_REGISTER_FLATTENABLE(SkRadialGradient); }