1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2012 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkGradientShaderPriv_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkGradientShaderPriv_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h" 22*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h" 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 25*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 26*c8dee2aaSAndroid Build Coastguard Worker 27*c8dee2aaSAndroid Build Coastguard Worker class SkArenaAlloc; 28*c8dee2aaSAndroid Build Coastguard Worker class SkRasterPipeline; 29*c8dee2aaSAndroid Build Coastguard Worker class SkReadBuffer; 30*c8dee2aaSAndroid Build Coastguard Worker class SkShader; 31*c8dee2aaSAndroid Build Coastguard Worker class SkWriteBuffer; 32*c8dee2aaSAndroid Build Coastguard Worker enum class SkTileMode; 33*c8dee2aaSAndroid Build Coastguard Worker struct SkStageRec; 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker class SkGradientBaseShader : public SkShaderBase { 36*c8dee2aaSAndroid Build Coastguard Worker public: 37*c8dee2aaSAndroid Build Coastguard Worker using Interpolation = SkGradientShader::Interpolation; 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker struct Descriptor { 40*c8dee2aaSAndroid Build Coastguard Worker Descriptor(); 41*c8dee2aaSAndroid Build Coastguard Worker ~Descriptor(); 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker Descriptor(const SkColor4f colors[], 44*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> colorSpace, 45*c8dee2aaSAndroid Build Coastguard Worker const SkScalar positions[], 46*c8dee2aaSAndroid Build Coastguard Worker int colorCount, 47*c8dee2aaSAndroid Build Coastguard Worker SkTileMode mode, 48*c8dee2aaSAndroid Build Coastguard Worker const Interpolation& interpolation); 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Worker const SkColor4f* fColors; 51*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> fColorSpace; 52*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* fPositions; 53*c8dee2aaSAndroid Build Coastguard Worker int fColorCount; // length of fColors (and fPositions, if not nullptr) 54*c8dee2aaSAndroid Build Coastguard Worker SkTileMode fTileMode; 55*c8dee2aaSAndroid Build Coastguard Worker Interpolation fInterpolation; 56*c8dee2aaSAndroid Build Coastguard Worker }; 57*c8dee2aaSAndroid Build Coastguard Worker 58*c8dee2aaSAndroid Build Coastguard Worker class DescriptorScope : public Descriptor { 59*c8dee2aaSAndroid Build Coastguard Worker public: DescriptorScope()60*c8dee2aaSAndroid Build Coastguard Worker DescriptorScope() {} 61*c8dee2aaSAndroid Build Coastguard Worker 62*c8dee2aaSAndroid Build Coastguard Worker bool unflatten(SkReadBuffer&, SkMatrix* legacyLocalMatrix); 63*c8dee2aaSAndroid Build Coastguard Worker 64*c8dee2aaSAndroid Build Coastguard Worker private: 65*c8dee2aaSAndroid Build Coastguard Worker skia_private::STArray<16, SkColor4f> fColorStorage; 66*c8dee2aaSAndroid Build Coastguard Worker skia_private::STArray<16, SkScalar> fPositionStorage; 67*c8dee2aaSAndroid Build Coastguard Worker }; 68*c8dee2aaSAndroid Build Coastguard Worker 69*c8dee2aaSAndroid Build Coastguard Worker SkGradientBaseShader(const Descriptor& desc, const SkMatrix& ptsToUnit); 70*c8dee2aaSAndroid Build Coastguard Worker ~SkGradientBaseShader() override; 71*c8dee2aaSAndroid Build Coastguard Worker type()72*c8dee2aaSAndroid Build Coastguard Worker ShaderType type() const final { return ShaderType::kGradientBase; } 73*c8dee2aaSAndroid Build Coastguard Worker 74*c8dee2aaSAndroid Build Coastguard Worker bool isOpaque() const override; 75*c8dee2aaSAndroid Build Coastguard Worker interpolateInPremul()76*c8dee2aaSAndroid Build Coastguard Worker bool interpolateInPremul() const { 77*c8dee2aaSAndroid Build Coastguard Worker return fInterpolation.fInPremul == SkGradientShader::Interpolation::InPremul::kYes; 78*c8dee2aaSAndroid Build Coastguard Worker } 79*c8dee2aaSAndroid Build Coastguard Worker getGradientMatrix()80*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& getGradientMatrix() const { return fPtsToUnit; } getColorCount()81*c8dee2aaSAndroid Build Coastguard Worker int getColorCount() const { return fColorCount; } getPositions()82*c8dee2aaSAndroid Build Coastguard Worker const float* getPositions() const { return fPositions; } getInterpolation()83*c8dee2aaSAndroid Build Coastguard Worker const Interpolation& getInterpolation() const { return fInterpolation; } 84*c8dee2aaSAndroid Build Coastguard Worker 85*c8dee2aaSAndroid Build Coastguard Worker static bool ValidGradient(const SkColor4f colors[], 86*c8dee2aaSAndroid Build Coastguard Worker int count, 87*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tileMode, 88*c8dee2aaSAndroid Build Coastguard Worker const Interpolation& interpolation); 89*c8dee2aaSAndroid Build Coastguard Worker 90*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeDegenerateGradient(const SkColor4f colors[], 91*c8dee2aaSAndroid Build Coastguard Worker const SkScalar pos[], 92*c8dee2aaSAndroid Build Coastguard Worker int colorCount, 93*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> colorSpace, 94*c8dee2aaSAndroid Build Coastguard Worker SkTileMode mode); 95*c8dee2aaSAndroid Build Coastguard Worker 96*c8dee2aaSAndroid Build Coastguard Worker // The default SkScalarNearlyZero threshold of .0024 is too big and causes regressions for svg 97*c8dee2aaSAndroid Build Coastguard Worker // gradients defined in the wild. 98*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kDegenerateThreshold = SK_Scalar1 / (1 << 15); 99*c8dee2aaSAndroid Build Coastguard Worker 100*c8dee2aaSAndroid Build Coastguard Worker protected: 101*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer&) const override; 102*c8dee2aaSAndroid Build Coastguard Worker 103*c8dee2aaSAndroid Build Coastguard Worker void commonAsAGradient(GradientInfo*) const; 104*c8dee2aaSAndroid Build Coastguard Worker 105*c8dee2aaSAndroid Build Coastguard Worker bool onAsLuminanceColor(SkColor4f*) const override; 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker bool appendStages(const SkStageRec&, const SkShaders::MatrixRec&) const override; 108*c8dee2aaSAndroid Build Coastguard Worker 109*c8dee2aaSAndroid Build Coastguard Worker virtual void appendGradientStages(SkArenaAlloc* alloc, 110*c8dee2aaSAndroid Build Coastguard Worker SkRasterPipeline* tPipeline, 111*c8dee2aaSAndroid Build Coastguard Worker SkRasterPipeline* postPipeline) const = 0; 112*c8dee2aaSAndroid Build Coastguard Worker 113*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix fPtsToUnit; 114*c8dee2aaSAndroid Build Coastguard Worker SkTileMode fTileMode; 115*c8dee2aaSAndroid Build Coastguard Worker 116*c8dee2aaSAndroid Build Coastguard Worker public: 117*c8dee2aaSAndroid Build Coastguard Worker static void AppendGradientFillStages(SkRasterPipeline* p, 118*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* alloc, 119*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f* colors, 120*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* positions, 121*c8dee2aaSAndroid Build Coastguard Worker int count); 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker static void AppendInterpolatedToDstStages(SkRasterPipeline* p, 124*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* alloc, 125*c8dee2aaSAndroid Build Coastguard Worker bool colorsAreOpaque, 126*c8dee2aaSAndroid Build Coastguard Worker const Interpolation& interpolation, 127*c8dee2aaSAndroid Build Coastguard Worker const SkColorSpace* intermediateColorSpace, 128*c8dee2aaSAndroid Build Coastguard Worker const SkColorSpace* dstColorSpace); 129*c8dee2aaSAndroid Build Coastguard Worker getPos(int i)130*c8dee2aaSAndroid Build Coastguard Worker SkScalar getPos(int i) const { 131*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i < fColorCount); 132*c8dee2aaSAndroid Build Coastguard Worker return fPositions ? fPositions[i] : SkIntToScalar(i) / (fColorCount - 1); 133*c8dee2aaSAndroid Build Coastguard Worker } 134*c8dee2aaSAndroid Build Coastguard Worker getLegacyColor(int i)135*c8dee2aaSAndroid Build Coastguard Worker SkColor getLegacyColor(int i) const { 136*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i < fColorCount); 137*c8dee2aaSAndroid Build Coastguard Worker return fColors[i].toSkColor(); 138*c8dee2aaSAndroid Build Coastguard Worker } 139*c8dee2aaSAndroid Build Coastguard Worker 140*c8dee2aaSAndroid Build Coastguard Worker SkColor4f* fColors; // points into fStorage 141*c8dee2aaSAndroid Build Coastguard Worker SkScalar* fPositions; // points into fStorage, or nullptr 142*c8dee2aaSAndroid Build Coastguard Worker int fColorCount; // length of fColors (and fPositions, if not nullptr) 143*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops 144*c8dee2aaSAndroid Build Coastguard Worker Interpolation fInterpolation; 145*c8dee2aaSAndroid Build Coastguard Worker bool fFirstStopIsImplicit; 146*c8dee2aaSAndroid Build Coastguard Worker bool fLastStopIsImplicit; 147*c8dee2aaSAndroid Build Coastguard Worker colorsAreOpaque()148*c8dee2aaSAndroid Build Coastguard Worker bool colorsAreOpaque() const { return fColorsAreOpaque; } 149*c8dee2aaSAndroid Build Coastguard Worker getTileMode()150*c8dee2aaSAndroid Build Coastguard Worker SkTileMode getTileMode() const { return fTileMode; } 151*c8dee2aaSAndroid Build Coastguard Worker cachedBitmap()152*c8dee2aaSAndroid Build Coastguard Worker const SkBitmap& cachedBitmap() const { return fColorsAndOffsetsBitmap; } setCachedBitmap(SkBitmap b)153*c8dee2aaSAndroid Build Coastguard Worker void setCachedBitmap(SkBitmap b) const { fColorsAndOffsetsBitmap = b; } 154*c8dee2aaSAndroid Build Coastguard Worker 155*c8dee2aaSAndroid Build Coastguard Worker private: 156*c8dee2aaSAndroid Build Coastguard Worker // When the number of stops exceeds Graphite's uniform-based limit the colors and offsets 157*c8dee2aaSAndroid Build Coastguard Worker // are stored in this bitmap. It is stored in the shader so it can be cached with a stable 158*c8dee2aaSAndroid Build Coastguard Worker // id and easily regenerated if purged. 159*c8dee2aaSAndroid Build Coastguard Worker // TODO(b/293160919) remove this field when we can store bitmaps in the cache by id. 160*c8dee2aaSAndroid Build Coastguard Worker mutable SkBitmap fColorsAndOffsetsBitmap; 161*c8dee2aaSAndroid Build Coastguard Worker 162*c8dee2aaSAndroid Build Coastguard Worker // Reserve inline space for up to 4 stops. 163*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr size_t kInlineStopCount = 4; 164*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr size_t kInlineStorageSize = 165*c8dee2aaSAndroid Build Coastguard Worker (sizeof(SkColor4f) + sizeof(SkScalar)) * kInlineStopCount; 166*c8dee2aaSAndroid Build Coastguard Worker skia_private::AutoSTMalloc<kInlineStorageSize, uint8_t> fStorage; 167*c8dee2aaSAndroid Build Coastguard Worker 168*c8dee2aaSAndroid Build Coastguard Worker bool fColorsAreOpaque; 169*c8dee2aaSAndroid Build Coastguard Worker }; 170*c8dee2aaSAndroid Build Coastguard Worker 171*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////// 172*c8dee2aaSAndroid Build Coastguard Worker 173*c8dee2aaSAndroid Build Coastguard Worker struct SkColor4fXformer { 174*c8dee2aaSAndroid Build Coastguard Worker SkColor4fXformer(const SkGradientBaseShader* shader, 175*c8dee2aaSAndroid Build Coastguard Worker SkColorSpace* dst, 176*c8dee2aaSAndroid Build Coastguard Worker bool forceExplicitPositions = false); 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Worker using ColorStorage = skia_private::STArray<4, SkPMColor4f>; 179*c8dee2aaSAndroid Build Coastguard Worker using PositionStorage = skia_private::STArray<4, float>; 180*c8dee2aaSAndroid Build Coastguard Worker 181*c8dee2aaSAndroid Build Coastguard Worker ColorStorage fColors; 182*c8dee2aaSAndroid Build Coastguard Worker PositionStorage fPositionStorage; 183*c8dee2aaSAndroid Build Coastguard Worker float* fPositions; 184*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> fIntermediateColorSpace; 185*c8dee2aaSAndroid Build Coastguard Worker }; 186*c8dee2aaSAndroid Build Coastguard Worker 187*c8dee2aaSAndroid Build Coastguard Worker struct SkColorConverter { 188*c8dee2aaSAndroid Build Coastguard Worker SkColorConverter(const SkColor* colors, int count); 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker skia_private::STArray<2, SkColor4f> fColors4f; 191*c8dee2aaSAndroid Build Coastguard Worker }; 192*c8dee2aaSAndroid Build Coastguard Worker 193*c8dee2aaSAndroid Build Coastguard Worker void SkRegisterConicalGradientShaderFlattenable(); 194*c8dee2aaSAndroid Build Coastguard Worker void SkRegisterLinearGradientShaderFlattenable(); 195*c8dee2aaSAndroid Build Coastguard Worker void SkRegisterRadialGradientShaderFlattenable(); 196*c8dee2aaSAndroid Build Coastguard Worker void SkRegisterSweepGradientShaderFlattenable(); 197*c8dee2aaSAndroid Build Coastguard Worker 198*c8dee2aaSAndroid Build Coastguard Worker #endif 199