• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
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 "src/shaders/gradients/SkLinearGradient.h"
9 
10 #include "src/core/SkReadBuffer.h"
11 #include "src/core/SkWriteBuffer.h"
12 #include "src/shaders/SkLocalMatrixShader.h"
13 
14 #if defined(SK_GRAPHITE)
15 #include "src/gpu/graphite/KeyContext.h"
16 #include "src/gpu/graphite/KeyHelpers.h"
17 #include "src/gpu/graphite/PaintParamsKey.h"
18 #endif
19 
pts_to_unit_matrix(const SkPoint pts[2])20 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
21     SkVector    vec = pts[1] - pts[0];
22     SkScalar    mag = vec.length();
23     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
24 
25     vec.scale(inv);
26     SkMatrix matrix;
27     matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
28     matrix.postTranslate(-pts[0].fX, -pts[0].fY);
29     matrix.postScale(inv, inv);
30     return matrix;
31 }
32 
33 ///////////////////////////////////////////////////////////////////////////////
34 
SkLinearGradient(const SkPoint pts[2],const Descriptor & desc)35 SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
36     : SkGradientShaderBase(desc, pts_to_unit_matrix(pts))
37     , fStart(pts[0])
38     , fEnd(pts[1]) {
39 }
40 
CreateProc(SkReadBuffer & buffer)41 sk_sp<SkFlattenable> SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
42     DescriptorScope desc;
43     SkMatrix legacyLocalMatrix;
44     if (!desc.unflatten(buffer, &legacyLocalMatrix)) {
45         return nullptr;
46     }
47     SkPoint pts[2];
48     pts[0] = buffer.readPoint();
49     pts[1] = buffer.readPoint();
50     return SkGradientShader::MakeLinear(pts,
51                                         desc.fColors,
52                                         std::move(desc.fColorSpace),
53                                         desc.fPositions,
54                                         desc.fColorCount,
55                                         desc.fTileMode,
56                                         desc.fInterpolation,
57                                         &legacyLocalMatrix);
58 }
59 
flatten(SkWriteBuffer & buffer) const60 void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
61     this->INHERITED::flatten(buffer);
62     buffer.writePoint(fStart);
63     buffer.writePoint(fEnd);
64 }
65 
appendGradientStages(SkArenaAlloc *,SkRasterPipeline *,SkRasterPipeline *) const66 void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*,
67                                             SkRasterPipeline*) const {
68     // No extra stage needed for linear gradients.
69 }
70 
transformT(skvm::Builder * p,skvm::Uniforms *,skvm::Coord coord,skvm::I32 * mask) const71 skvm::F32 SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
72                                        skvm::Coord coord, skvm::I32* mask) const {
73     // We've baked getting t in x into the matrix, so this is pretty trivial.
74     return coord.x;
75 }
76 
asGradient(GradientInfo * info,SkMatrix * localMatrix) const77 SkShaderBase::GradientType SkLinearGradient::asGradient(GradientInfo* info,
78                                                         SkMatrix* localMatrix) const {
79     if (info) {
80         commonAsAGradient(info);
81         info->fPoint[0] = fStart;
82         info->fPoint[1] = fEnd;
83     }
84     if (localMatrix) {
85         *localMatrix = SkMatrix::I();
86     }
87     return GradientType::kLinear;
88 }
89 
90 /////////////////////////////////////////////////////////////////////
91 
92 #if defined(SK_GANESH)
93 
94 #include "src/gpu/ganesh/gradients/GrGradientShader.h"
95 
asFragmentProcessor(const GrFPArgs & args,const MatrixRec & mRec) const96 std::unique_ptr<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor(
97         const GrFPArgs& args, const MatrixRec& mRec) const {
98     return GrGradientShader::MakeLinear(*this, args, mRec);
99 }
100 
101 #endif
102 
103 #if defined(SK_GRAPHITE)
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const104 void SkLinearGradient::addToKey(const skgpu::graphite::KeyContext& keyContext,
105                                 skgpu::graphite::PaintParamsKeyBuilder* builder,
106                                 skgpu::graphite::PipelineDataGatherer* gatherer) const {
107     using namespace skgpu::graphite;
108 
109     SkColor4fXformer xformedColors(this, keyContext.dstColorInfo().colorSpace());
110     const SkPMColor4f* colors = xformedColors.fColors.begin();
111 
112     GradientShaderBlocks::GradientData data(GradientType::kLinear,
113                                             fStart, fEnd,
114                                             0.0f, 0.0f,
115                                             0.0f, 0.0f,
116                                             fTileMode,
117                                             fColorCount,
118                                             colors,
119                                             fPositions,
120                                             fInterpolation);
121 
122     MakeInterpolatedToDst(keyContext, builder, gatherer,
123                           data, fInterpolation,
124                           xformedColors.fIntermediateColorSpace.get());
125 }
126 #endif
127 
MakeLinear(const SkPoint pts[2],const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int colorCount,SkTileMode mode,const Interpolation & interpolation,const SkMatrix * localMatrix)128 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
129                                              const SkColor4f colors[],
130                                              sk_sp<SkColorSpace> colorSpace,
131                                              const SkScalar pos[],
132                                              int colorCount,
133                                              SkTileMode mode,
134                                              const Interpolation& interpolation,
135                                              const SkMatrix* localMatrix) {
136     if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
137         return nullptr;
138     }
139     if (!SkGradientShaderBase::ValidGradient(colors, colorCount, mode, interpolation)) {
140         return nullptr;
141     }
142     if (1 == colorCount) {
143         return SkShaders::Color(colors[0], std::move(colorSpace));
144     }
145     if (localMatrix && !localMatrix->invert(nullptr)) {
146         return nullptr;
147     }
148 
149     if (SkScalarNearlyZero((pts[1] - pts[0]).length(),
150                            SkGradientShaderBase::kDegenerateThreshold)) {
151         // Degenerate gradient, the only tricky complication is when in clamp mode, the limit of
152         // the gradient approaches two half planes of solid color (first and last). However, they
153         // are divided by the line perpendicular to the start and end point, which becomes undefined
154         // once start and end are exactly the same, so just use the end color for a stable solution.
155         return SkGradientShaderBase::MakeDegenerateGradient(colors, pos, colorCount,
156                                                             std::move(colorSpace), mode);
157     }
158 
159     SkGradientShaderBase::ColorStopOptimizer opt(colors, pos, colorCount, mode);
160 
161     SkGradientShaderBase::Descriptor desc(opt.fColors, std::move(colorSpace), opt.fPos,
162                                           opt.fCount, mode, interpolation);
163     return SkLocalMatrixShader::MakeWrapped<SkLinearGradient>(localMatrix, pts, desc);
164 }
165 
MakeLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkTileMode mode,uint32_t flags,const SkMatrix * localMatrix)166 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
167                                              const SkColor colors[],
168                                              const SkScalar pos[],
169                                              int colorCount,
170                                              SkTileMode mode,
171                                              uint32_t flags,
172                                              const SkMatrix* localMatrix) {
173     SkColorConverter converter(colors, colorCount);
174     return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
175                       localMatrix);
176 }
177 
SkRegisterLinearGradientShaderFlattenable()178 void SkRegisterLinearGradientShaderFlattenable() {
179     SK_REGISTER_FLATTENABLE(SkLinearGradient);
180 }
181