1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "skia_shader_effect.h"
17
18 #include <vector>
19 #include "include/core/SkMatrix.h"
20 #include "include/core/SkSamplingOptions.h"
21 #include "include/core/SkTileMode.h"
22 #include "include/effects/SkGradientShader.h"
23 #include "include/effects/SkRuntimeEffect.h"
24 #include "src/core/SkReadBuffer.h"
25 #include "src/core/SkWriteBuffer.h"
26 #include "src/shaders/SkShaderBase.h"
27
28 #include "skia_helper.h"
29 #include "skia_image.h"
30 #include "skia_matrix.h"
31 #include "skia_picture.h"
32
33 #include "effect/shader_effect.h"
34 #include "image/image.h"
35 #include "image/picture.h"
36 #include "utils/matrix.h"
37 #include "utils/data.h"
38 #include "utils/log.h"
39 #ifdef RS_ENABLE_SDF
40 #include "draw/sdf_shape.h"
41 #endif
42
43 namespace OHOS {
44 namespace Rosen {
45 namespace Drawing {
46
SkiaShaderEffect()47 SkiaShaderEffect::SkiaShaderEffect() noexcept : shader_(nullptr) {}
48
InitWithColor(ColorQuad color)49 void SkiaShaderEffect::InitWithColor(ColorQuad color)
50 {
51 shader_ = SkShaders::Color(color);
52 }
53
InitWithColorSpace(const Color4f & color,std::shared_ptr<ColorSpace> colorSpace)54 void SkiaShaderEffect::InitWithColorSpace(const Color4f& color, std::shared_ptr<ColorSpace> colorSpace)
55 {
56 const SkColor4f& skC4f = { .fR = color.redF_, .fG = color.greenF_, .fB = color.blueF_, .fA = color.alphaF_ };
57 if (colorSpace == nullptr) {
58 shader_ = SkShaders::Color(skC4f, nullptr);
59 return;
60 }
61 auto skiaColorSpace = colorSpace->GetImpl<SkiaColorSpace>();
62 shader_ = SkShaders::Color(skC4f, skiaColorSpace ? skiaColorSpace->GetColorSpace() : nullptr);
63 }
64
InitWithBlend(const ShaderEffect & s1,const ShaderEffect & s2,BlendMode mode)65 void SkiaShaderEffect::InitWithBlend(const ShaderEffect& s1, const ShaderEffect& s2, BlendMode mode)
66 {
67 auto dst = s1.GetImpl<SkiaShaderEffect>();
68 auto src = s2.GetImpl<SkiaShaderEffect>();
69 if (dst != nullptr && src != nullptr) {
70 shader_ = SkShaders::Blend(static_cast<SkBlendMode>(mode), dst->GetShader(), src->GetShader());
71 }
72 }
73
InitWithImage(const Image & image,TileMode tileX,TileMode tileY,const SamplingOptions & sampling,const Matrix & matrix)74 void SkiaShaderEffect::InitWithImage(
75 const Image& image, TileMode tileX, TileMode tileY, const SamplingOptions& sampling, const Matrix& matrix)
76 {
77 SkTileMode modeX = static_cast<SkTileMode>(tileX);
78 SkTileMode modeY = static_cast<SkTileMode>(tileY);
79
80 auto m = matrix.GetImpl<SkiaMatrix>();
81 auto i = image.GetImpl<SkiaImage>();
82 SkMatrix skiaMatrix;
83 sk_sp<SkImage> skiaImage;
84 if (m != nullptr && i != nullptr) {
85 skiaMatrix = m->ExportSkiaMatrix();
86 skiaImage = i->GetImage();
87 if (skiaImage != nullptr) {
88 SkSamplingOptions samplingOptions;
89 if (sampling.GetUseCubic()) {
90 samplingOptions = SkSamplingOptions({ sampling.GetCubicCoffB(), sampling.GetCubicCoffC() });
91 } else {
92 samplingOptions = SkSamplingOptions(static_cast<SkFilterMode>(sampling.GetFilterMode()),
93 static_cast<SkMipmapMode>(sampling.GetMipmapMode()));
94 }
95 shader_ = skiaImage->makeShader(modeX, modeY, samplingOptions, &skiaMatrix);
96 }
97 }
98 }
99
InitWithPicture(const Picture & picture,TileMode tileX,TileMode tileY,FilterMode mode,const Matrix & matrix,const Rect & rect)100 void SkiaShaderEffect::InitWithPicture(
101 const Picture& picture, TileMode tileX, TileMode tileY, FilterMode mode, const Matrix& matrix, const Rect& rect)
102 {
103 SkTileMode modeX = static_cast<SkTileMode>(tileX);
104 SkTileMode modeY = static_cast<SkTileMode>(tileY);
105 SkRect r = SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
106
107 auto p = picture.GetImpl<SkiaPicture>();
108 auto m = matrix.GetImpl<SkiaMatrix>();
109 sk_sp<SkPicture> skiaPicture;
110 SkMatrix skiaMatrix;
111 if (p != nullptr && m != nullptr) {
112 skiaPicture = p->GetPicture();
113 skiaMatrix = m->ExportSkiaMatrix();
114 if (skiaPicture != nullptr) {
115 SkFilterMode skFilterMode = static_cast<SkFilterMode>(mode);
116 shader_ = skiaPicture->makeShader(modeX, modeY, skFilterMode, &skiaMatrix, &r);
117 }
118 }
119 }
120
InitWithLinearGradient(const Point & startPt,const Point & endPt,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,const Matrix * matrix)121 void SkiaShaderEffect::InitWithLinearGradient(const Point& startPt, const Point& endPt,
122 const std::vector<ColorQuad>& colors, const std::vector<scalar>& pos, TileMode mode, const Matrix *matrix)
123 {
124 SkPoint pts[2];
125 pts[0].set(startPt.GetX(), startPt.GetY());
126 pts[1].set(endPt.GetX(), endPt.GetY());
127
128 if (colors.empty()) {
129 return;
130 }
131 size_t colorsCount = colors.size();
132
133 std::vector<SkColor> c;
134 std::vector<SkScalar> p;
135 for (size_t i = 0; i < colorsCount; ++i) {
136 c.emplace_back(colors[i]);
137 }
138 for (size_t i = 0; i < pos.size(); ++i) {
139 p.emplace_back(pos[i]);
140 }
141 const SkMatrix *skMatrix = nullptr;
142 if (matrix != nullptr) {
143 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
144 }
145 shader_ = SkGradientShader::MakeLinear(pts, &c[0], pos.empty() ? nullptr : &p[0],
146 colorsCount, static_cast<SkTileMode>(mode), 0, skMatrix);
147 }
148
InitWithRadialGradient(const Point & centerPt,scalar radius,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,const Matrix * matrix)149 void SkiaShaderEffect::InitWithRadialGradient(const Point& centerPt, scalar radius,
150 const std::vector<ColorQuad>& colors, const std::vector<scalar>& pos, TileMode mode, const Matrix *matrix)
151 {
152 SkPoint center;
153 center.set(centerPt.GetX(), centerPt.GetY());
154
155 if (colors.empty()) {
156 return;
157 }
158 size_t colorsCount = colors.size();
159
160 std::vector<SkColor> c;
161 std::vector<SkScalar> p;
162 for (size_t i = 0; i < colorsCount; ++i) {
163 c.emplace_back(colors[i]);
164 }
165 for (size_t i = 0; i < pos.size(); ++i) {
166 p.emplace_back(pos[i]);
167 }
168 const SkMatrix *skMatrix = nullptr;
169 if (matrix != nullptr) {
170 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
171 }
172 shader_ = SkGradientShader::MakeRadial(center, radius, &c[0],
173 pos.empty() ? nullptr : &p[0], colorsCount, static_cast<SkTileMode>(mode), 0, skMatrix);
174 }
175
InitWithTwoPointConical(const Point & startPt,scalar startRadius,const Point & endPt,scalar endRadius,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,const Matrix * matrix)176 void SkiaShaderEffect::InitWithTwoPointConical(const Point& startPt, scalar startRadius, const Point& endPt,
177 scalar endRadius, const std::vector<ColorQuad>& colors, const std::vector<scalar>& pos, TileMode mode,
178 const Matrix *matrix)
179 {
180 SkPoint start;
181 SkPoint end;
182 start.set(startPt.GetX(), startPt.GetY());
183 end.set(endPt.GetX(), endPt.GetY());
184
185 if (colors.empty()) {
186 return;
187 }
188 size_t colorsCount = colors.size();
189
190 std::vector<SkColor> c;
191 std::vector<SkScalar> p;
192 for (size_t i = 0; i < colorsCount; ++i) {
193 c.emplace_back(colors[i]);
194 }
195 for (size_t i = 0; i < pos.size(); ++i) {
196 p.emplace_back(pos[i]);
197 }
198 const SkMatrix *skMatrix = nullptr;
199 if (matrix != nullptr) {
200 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
201 }
202
203 shader_ = SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
204 &c[0], pos.empty() ? nullptr : &p[0], colorsCount, static_cast<SkTileMode>(mode), 0, skMatrix);
205 }
206
InitWithSweepGradient(const Point & centerPt,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,scalar startAngle,scalar endAngle,const Matrix * matrix)207 void SkiaShaderEffect::InitWithSweepGradient(const Point& centerPt, const std::vector<ColorQuad>& colors,
208 const std::vector<scalar>& pos, TileMode mode, scalar startAngle, scalar endAngle, const Matrix *matrix)
209 {
210 if (colors.empty()) {
211 return;
212 }
213 size_t colorsCount = colors.size();
214
215 std::vector<SkColor> c;
216 std::vector<SkScalar> p;
217 for (size_t i = 0; i < colorsCount; ++i) {
218 c.emplace_back(colors[i]);
219 }
220 for (size_t i = 0; i < pos.size(); ++i) {
221 p.emplace_back(pos[i]);
222 }
223 const SkMatrix *skMatrix = nullptr;
224 if (matrix != nullptr) {
225 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
226 }
227 shader_ = SkGradientShader::MakeSweep(centerPt.GetX(), centerPt.GetY(), &c[0],
228 pos.empty() ? nullptr : &p[0], colorsCount,
229 static_cast<SkTileMode>(mode), startAngle, endAngle, 0, skMatrix);
230 }
231
InitWithSdf(const SDFShapeBase & shape)232 void SkiaShaderEffect::InitWithSdf(const SDFShapeBase& shape)
233 {
234 sk_sp<SkShader> skShader = shape.Build<sk_sp<SkShader>>();
235 if (skShader == nullptr) {
236 return;
237 }
238 shader_ = skShader;
239 }
240
GetShader() const241 sk_sp<SkShader> SkiaShaderEffect::GetShader() const
242 {
243 return shader_;
244 }
245
SetSkShader(const sk_sp<SkShader> & skShader)246 void SkiaShaderEffect::SetSkShader(const sk_sp<SkShader>& skShader)
247 {
248 shader_ = skShader;
249 }
250
Serialize() const251 std::shared_ptr<Data> SkiaShaderEffect::Serialize() const
252 {
253 if (shader_ == nullptr) {
254 LOGD("SkiaShaderEffect::Serialize, shader_ is nullptr!");
255 return nullptr;
256 }
257
258 SkBinaryWriteBuffer writer;
259 writer.writeFlattenable(shader_.get());
260 size_t length = writer.bytesWritten();
261 std::shared_ptr<Data> data = std::make_shared<Data>();
262 data->BuildUninitialized(length);
263 writer.writeToMemory(data->WritableData());
264 return data;
265 }
266
Deserialize(std::shared_ptr<Data> data)267 bool SkiaShaderEffect::Deserialize(std::shared_ptr<Data> data)
268 {
269 if (data == nullptr) {
270 LOGD("SkiaShaderEffect::Deserialize, data is invalid!");
271 return false;
272 }
273 SkReadBuffer reader(data->GetData(), data->GetSize());
274 shader_ = reader.readShader();
275 return true;
276 }
277
278 } // namespace Drawing
279 } // namespace Rosen
280 } // namespace OHOS