xref: /aosp_15_r20/external/skia/src/shaders/gradients/SkGradientBaseShader.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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