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
20 #include "include/core/SkMatrix.h"
21 #include "include/core/SkSamplingOptions.h"
22 #include "include/core/SkTileMode.h"
23 #include "include/effects/SkGradientShader.h"
24 #include "include/effects/SkRuntimeEffect.h"
25 #include "src/core/SkReadBuffer.h"
26 #include "src/core/SkWriteBuffer.h"
27 #include "src/shaders/SkShaderBase.h"
28
29 #include "skia_helper.h"
30 #include "skia_image.h"
31 #include "skia_matrix.h"
32 #include "skia_picture.h"
33
34 #include "effect/shader_effect.h"
35 #include "image/image.h"
36 #include "image/picture.h"
37 #include "utils/matrix.h"
38 #include "utils/data.h"
39 #include "utils/log.h"
40
41 namespace OHOS {
42 namespace Rosen {
43 namespace Drawing {
SkiaShaderEffect()44 SkiaShaderEffect::SkiaShaderEffect() noexcept : shader_(nullptr) {}
45
InitWithColor(ColorQuad color)46 void SkiaShaderEffect::InitWithColor(ColorQuad color)
47 {
48 shader_ = SkShaders::Color(color);
49 }
50
InitWithColorSpace(const Color4f & color,std::shared_ptr<ColorSpace> colorSpace)51 void SkiaShaderEffect::InitWithColorSpace(const Color4f& color, std::shared_ptr<ColorSpace> colorSpace)
52 {
53 const SkColor4f& skC4f = { .fR = color.redF_, .fG = color.greenF_, .fB = color.blueF_, .fA = color.alphaF_ };
54 shader_ = SkShaders::Color(skC4f, colorSpace->GetSkColorSpace());
55 }
56
InitWithBlend(const ShaderEffect & s1,const ShaderEffect & s2,BlendMode mode)57 void SkiaShaderEffect::InitWithBlend(const ShaderEffect& s1, const ShaderEffect& s2, BlendMode mode)
58 {
59 auto dst = s1.GetImpl<SkiaShaderEffect>();
60 auto src = s2.GetImpl<SkiaShaderEffect>();
61 if (dst != nullptr && src != nullptr) {
62 shader_ = SkShaders::Blend(static_cast<SkBlendMode>(mode), dst->GetShader(), src->GetShader());
63 }
64 }
65
InitWithImage(const Image & image,TileMode tileX,TileMode tileY,const SamplingOptions & sampling,const Matrix & matrix)66 void SkiaShaderEffect::InitWithImage(
67 const Image& image, TileMode tileX, TileMode tileY, const SamplingOptions& sampling, const Matrix& matrix)
68 {
69 SkTileMode modeX = static_cast<SkTileMode>(tileX);
70 SkTileMode modeY = static_cast<SkTileMode>(tileY);
71
72 auto m = matrix.GetImpl<SkiaMatrix>();
73 auto i = image.GetImpl<SkiaImage>();
74 SkMatrix skiaMatrix;
75 sk_sp<SkImage> skiaImage;
76 if (m != nullptr && i != nullptr) {
77 skiaMatrix = m->ExportSkiaMatrix();
78 skiaImage = i->GetImage();
79 if (skiaImage != nullptr) {
80 SkSamplingOptions samplingOptions;
81 if (sampling.GetUseCubic()) {
82 samplingOptions = SkSamplingOptions({ sampling.GetCubicCoffB(), sampling.GetCubicCoffC() });
83 } else {
84 samplingOptions = SkSamplingOptions(static_cast<SkFilterMode>(sampling.GetFilterMode()),
85 static_cast<SkMipmapMode>(sampling.GetMipmapMode()));
86 }
87 shader_ = skiaImage->makeShader(modeX, modeY, samplingOptions, &skiaMatrix);
88 }
89 }
90 }
91
InitWithPicture(const Picture & picture,TileMode tileX,TileMode tileY,FilterMode mode,const Matrix & matrix,const Rect & rect)92 void SkiaShaderEffect::InitWithPicture(
93 const Picture& picture, TileMode tileX, TileMode tileY, FilterMode mode, const Matrix& matrix, const Rect& rect)
94 {
95 SkTileMode modeX = static_cast<SkTileMode>(tileX);
96 SkTileMode modeY = static_cast<SkTileMode>(tileY);
97 SkRect r = SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
98
99 auto p = picture.GetImpl<SkiaPicture>();
100 auto m = matrix.GetImpl<SkiaMatrix>();
101 sk_sp<SkPicture> skiaPicture;
102 SkMatrix skiaMatrix;
103 if (p != nullptr && m != nullptr) {
104 skiaPicture = p->GetPicture();
105 skiaMatrix = m->ExportSkiaMatrix();
106 if (skiaPicture != nullptr) {
107 SkFilterMode skFilterMode = static_cast<SkFilterMode>(mode);
108 shader_ = skiaPicture->makeShader(modeX, modeY, skFilterMode, &skiaMatrix, &r);
109 }
110 }
111 }
112
InitWithLinearGradient(const Point & startPt,const Point & endPt,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,const Matrix * matrix)113 void SkiaShaderEffect::InitWithLinearGradient(const Point& startPt, const Point& endPt,
114 const std::vector<ColorQuad>& colors, const std::vector<scalar>& pos, TileMode mode, const Matrix *matrix)
115 {
116 SkPoint pts[2];
117 pts[0].set(startPt.GetX(), startPt.GetY());
118 pts[1].set(endPt.GetX(), endPt.GetY());
119
120 if (colors.empty()) {
121 return;
122 }
123 size_t colorsCount = colors.size();
124
125 std::vector<SkColor> c;
126 std::vector<SkScalar> p;
127 for (size_t i = 0; i < colorsCount; ++i) {
128 c.emplace_back(colors[i]);
129 }
130 for (size_t i = 0; i < pos.size(); ++i) {
131 p.emplace_back(pos[i]);
132 }
133 const SkMatrix *skMatrix = nullptr;
134 if (matrix != nullptr) {
135 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
136 }
137 shader_ = SkGradientShader::MakeLinear(pts, &c[0], pos.empty() ? nullptr : &p[0],
138 colorsCount, static_cast<SkTileMode>(mode), 0, skMatrix);
139 }
140
InitWithRadialGradient(const Point & centerPt,scalar radius,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,const Matrix * matrix)141 void SkiaShaderEffect::InitWithRadialGradient(const Point& centerPt, scalar radius,
142 const std::vector<ColorQuad>& colors, const std::vector<scalar>& pos, TileMode mode, const Matrix *matrix)
143 {
144 SkPoint center;
145 center.set(centerPt.GetX(), centerPt.GetY());
146
147 if (colors.empty()) {
148 return;
149 }
150 size_t colorsCount = colors.size();
151
152 std::vector<SkColor> c;
153 std::vector<SkScalar> p;
154 for (size_t i = 0; i < colorsCount; ++i) {
155 c.emplace_back(colors[i]);
156 }
157 for (size_t i = 0; i < pos.size(); ++i) {
158 p.emplace_back(pos[i]);
159 }
160 const SkMatrix *skMatrix = nullptr;
161 if (matrix != nullptr) {
162 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
163 }
164 shader_ = SkGradientShader::MakeRadial(center, radius, &c[0],
165 pos.empty() ? nullptr : &p[0], colorsCount, static_cast<SkTileMode>(mode), 0, skMatrix);
166 }
167
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)168 void SkiaShaderEffect::InitWithTwoPointConical(const Point& startPt, scalar startRadius, const Point& endPt,
169 scalar endRadius, const std::vector<ColorQuad>& colors, const std::vector<scalar>& pos, TileMode mode,
170 const Matrix *matrix)
171 {
172 SkPoint start;
173 SkPoint end;
174 start.set(startPt.GetX(), startPt.GetY());
175 end.set(endPt.GetX(), endPt.GetY());
176
177 if (colors.empty()) {
178 return;
179 }
180 size_t colorsCount = colors.size();
181
182 std::vector<SkColor> c;
183 std::vector<SkScalar> p;
184 for (size_t i = 0; i < colorsCount; ++i) {
185 c.emplace_back(colors[i]);
186 }
187 for (size_t i = 0; i < pos.size(); ++i) {
188 p.emplace_back(pos[i]);
189 }
190 const SkMatrix *skMatrix = nullptr;
191 if (matrix != nullptr) {
192 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
193 }
194
195 shader_ = SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
196 &c[0], pos.empty() ? nullptr : &p[0], colorsCount, static_cast<SkTileMode>(mode), 0, skMatrix);
197 }
198
InitWithSweepGradient(const Point & centerPt,const std::vector<ColorQuad> & colors,const std::vector<scalar> & pos,TileMode mode,scalar startAngle,scalar endAngle,const Matrix * matrix)199 void SkiaShaderEffect::InitWithSweepGradient(const Point& centerPt, const std::vector<ColorQuad>& colors,
200 const std::vector<scalar>& pos, TileMode mode, scalar startAngle, scalar endAngle, const Matrix *matrix)
201 {
202 if (colors.empty()) {
203 return;
204 }
205 size_t colorsCount = colors.size();
206
207 std::vector<SkColor> c;
208 std::vector<SkScalar> p;
209 for (size_t i = 0; i < colorsCount; ++i) {
210 c.emplace_back(colors[i]);
211 }
212 for (size_t i = 0; i < pos.size(); ++i) {
213 p.emplace_back(pos[i]);
214 }
215 const SkMatrix *skMatrix = nullptr;
216 if (matrix != nullptr) {
217 skMatrix = &matrix->GetImpl<SkiaMatrix>()->ExportSkiaMatrix();
218 }
219 shader_ = SkGradientShader::MakeSweep(centerPt.GetX(), centerPt.GetY(), &c[0],
220 pos.empty() ? nullptr : &p[0], colorsCount,
221 static_cast<SkTileMode>(mode), startAngle, endAngle, 0, skMatrix);
222 }
223
InitWithLightUp(const float & lightUpDeg,const ShaderEffect & imageShader)224 void SkiaShaderEffect::InitWithLightUp(const float& lightUpDeg, const ShaderEffect& imageShader)
225 {
226 auto imageShaderImpl_ = imageShader.GetImpl<SkiaShaderEffect>();
227 if (imageShaderImpl_ != nullptr) {
228 static constexpr char prog[] = R"(
229 uniform half lightUpDeg;
230 uniform shader imageShader;
231 vec3 rgb2hsv(in vec3 c)
232 {
233 vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
234 vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
235 vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
236 float d = q.x - min(q.w, q.y);
237 float e = 1.0e-10;
238 return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
239 }
240 vec3 hsv2rgb(in vec3 c)
241 {
242 vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
243 return c.z * mix(vec3(1.0), rgb, c.y);
244 }
245 half4 main(float2 coord)
246 {
247 vec3 hsv = rgb2hsv(imageShader.eval(coord).rgb);
248 float satUpper = clamp(hsv.y * 1.2, 0.0, 1.0);
249 hsv.y = mix(satUpper, hsv.y, lightUpDeg);
250 hsv.z += lightUpDeg - 1.0;
251 return vec4(hsv2rgb(hsv), imageShader.eval(coord).a);
252 }
253 )";
254 auto [effect, err] = SkRuntimeEffect::MakeForShader(SkString(prog));
255 sk_sp<SkShader> children[] = {imageShaderImpl_->GetShader()};
256 size_t childCount = 1;
257 shader_ = effect->makeShader(SkData::MakeWithCopy(
258 &lightUpDeg, sizeof(lightUpDeg)), children, childCount, nullptr, false);
259 } else {
260 LOGE("SkiaShaderEffect::InitWithLightUp: imageShader is nullptr");
261 }
262 }
263
GetShader() const264 sk_sp<SkShader> SkiaShaderEffect::GetShader() const
265 {
266 return shader_;
267 }
268
SetSkShader(const sk_sp<SkShader> & skShader)269 void SkiaShaderEffect::SetSkShader(const sk_sp<SkShader>& skShader)
270 {
271 shader_ = skShader;
272 }
273
Serialize() const274 std::shared_ptr<Data> SkiaShaderEffect::Serialize() const
275 {
276 if (shader_ == nullptr) {
277 LOGD("SkiaShaderEffect::Serialize, shader_ is nullptr!");
278 return nullptr;
279 }
280
281 SkBinaryWriteBuffer writer;
282 writer.writeFlattenable(shader_.get());
283 size_t length = writer.bytesWritten();
284 std::shared_ptr<Data> data = std::make_shared<Data>();
285 data->BuildUninitialized(length);
286 writer.writeToMemory(data->WritableData());
287 return data;
288 }
289
Deserialize(std::shared_ptr<Data> data)290 bool SkiaShaderEffect::Deserialize(std::shared_ptr<Data> data)
291 {
292 if (data == nullptr) {
293 LOGD("SkiaShaderEffect::Deserialize, data is invalid!");
294 return false;
295 }
296 SkReadBuffer reader(data->GetData(), data->GetSize());
297 shader_ = reader.readShader();
298 return true;
299 }
300
301 } // namespace Drawing
302 } // namespace Rosen
303 } // namespace OHOS