1 /*
2 * Copyright (c) 2024 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 #include "render/rs_linear_gradient_blur_filter.h"
16 #include "src/core/SkOpts.h"
17 #include "platform/common/rs_log.h"
18 #include "common/rs_optional_trace.h"
19
20 #ifndef USE_ROSEN_DRAWING
21 #else
22 #include "draw/surface.h"
23 #endif
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 constexpr static float FLOAT_ZERO_THRESHOLD = 0.001f;
29 constexpr static uint8_t DIRECTION_NUM = 4;
30 } // namespace
31
32 #ifndef USE_ROSEN_DRAWING
33 sk_sp<SkRuntimeEffect> horizontalMeanBlurShaderEffect_ = nullptr;
34 sk_sp<SkRuntimeEffect> verticalMeanBlurShaderEffect_ = nullptr;
35 sk_sp<SkRuntimeEffect> maskBlurShaderEffect_ = nullptr;
36 #else
37 std::shared_ptr<Drawing::RuntimeEffect> RSLinearGradientBlurFilter::horizontalMeanBlurShaderEffect_ = nullptr;
38 std::shared_ptr<Drawing::RuntimeEffect> RSLinearGradientBlurFilter::verticalMeanBlurShaderEffect_ = nullptr;
39 std::shared_ptr<Drawing::RuntimeEffect> RSLinearGradientBlurFilter::maskBlurShaderEffect_ = nullptr;
40 #endif
41
RSLinearGradientBlurFilter(const std::shared_ptr<RSLinearGradientBlurPara> & para,const float geoWidth,const float geoHeight)42 RSLinearGradientBlurFilter::RSLinearGradientBlurFilter(const std::shared_ptr<RSLinearGradientBlurPara>& para,
43 const float geoWidth, const float geoHeight)
44 #ifndef USE_ROSEN_DRAWING
45 : RSSkiaFilter(nullptr),
46 #else
47 : RSDrawingFilter(nullptr),
48 #endif
49 linearGradientBlurPara_(para)
50 {
51 geoWidth_ = geoWidth;
52 geoHeight_ = geoHeight;
53 type_ = FilterType::LINEAR_GRADIENT_BLUR;
54 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
55 hash_ = SkOpts::hash(&linearGradientBlurPara_, sizeof(linearGradientBlurPara_), hash_);
56 }
57
58 RSLinearGradientBlurFilter::~RSLinearGradientBlurFilter() = default;
59
60 #ifndef USE_ROSEN_DRAWING
DrawImageRect(SkCanvas & canvas,const sk_sp<SkImage> & image,const SkRect & src,const SkRect & dst) const61 void RSLinearGradientBlurFilter::DrawImageRect(
62 SkCanvas& canvas, const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst) const
63 #else
64 void RSLinearGradientBlurFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
65 const Drawing::Rect& src, const Drawing::Rect& dst) const
66 #endif
67 {
68 auto& para = linearGradientBlurPara_;
69 if (!image || para == nullptr || para->blurRadius_ <= 0) {
70 return;
71 }
72
73 RS_OPTIONAL_TRACE_NAME("DrawLinearGradientBlur");
74 uint8_t directionBias = CalcDirectionBias(mat_);
75 auto clipIPadding = ComputeRectBeforeClip(directionBias, dst);
76 #ifndef USE_ROSEN_DRAWING
77 ComputeScale(clipIPadding.width(), clipIPadding.height(), para->useMaskAlgorithm_);
78 auto scaledClipIPadding = SkRect::MakeLTRB(clipIPadding.GetLeft(), clipIPadding.GetTop(), clipIPadding.GetLeft() +
79 clipIPadding.GetWidth() * imageScale_, clipIPadding.GetTop() + clipIPadding.GetHeight() * imageScale_);
80 auto alphaGradientShader = MakeAlphaGradientShader(SkRect::Make(scaledClipIPadding), para, directionBias);
81 #else
82 ComputeScale(clipIPadding.GetWidth(), clipIPadding.GetHeight(), para->useMaskAlgorithm_);
83 auto scaledClipIPadding = Drawing::Rect(clipIPadding.GetLeft(), clipIPadding.GetTop(), clipIPadding.GetLeft() +
84 clipIPadding.GetWidth() * imageScale_, clipIPadding.GetTop() + clipIPadding.GetHeight() * imageScale_);
85 auto alphaGradientShader = MakeAlphaGradientShader(scaledClipIPadding, para, directionBias);
86 #endif
87 if (alphaGradientShader == nullptr) {
88 ROSEN_LOGE("RSLinearGradientBlurFilter::DrawImageRect alphaGradientShader null");
89 return;
90 }
91
92 if (RSSystemProperties::GetMaskLinearBlurEnabled() && para->useMaskAlgorithm_) {
93 // use faster LinearGradientBlur if valid
94 RS_OPTIONAL_TRACE_NAME("LinearGradientBlur_mask");
95 if (para->LinearGradientBlurFilter_ == nullptr) {
96 ROSEN_LOGE("RSPropertiesPainter::DrawLinearGradientBlur blurFilter null");
97 return;
98 }
99 auto& RSFilter = para->LinearGradientBlurFilter_;
100 #ifndef USE_ROSEN_DRAWING
101 auto filter = std::static_pointer_cast<RSSkiaFilter>(RSFilter);
102 #else
103 auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
104 #endif
105 DrawMaskLinearGradientBlur(image, canvas, filter, alphaGradientShader, dst);
106 } else {
107 // use original LinearGradientBlur
108 RS_OPTIONAL_TRACE_NAME("LinearGradientBlur_radius");
109 float radius = para->blurRadius_ - para->originalBase_;
110 radius = std::clamp(radius, 0.0f, 60.0f); // 60.0 represents largest blur radius
111 radius = radius / 2 * imageScale_; // 2 half blur radius
112 MakeHorizontalMeanBlurEffect();
113 MakeVerticalMeanBlurEffect();
114 DrawMeanLinearGradientBlur(image, canvas, radius, alphaGradientShader, dst);
115 }
116 }
117
118 #ifndef USE_ROSEN_DRAWING
ComputeRectBeforeClip(const uint8_t directionBias,const SkRect & dst)119 SkRect::Rect RSLinearGradientBlurFilter::ComputeRectBeforeClip(const uint8_t directionBias, const SkRect& dst)
120 #else
121 Drawing::Rect RSLinearGradientBlurFilter::ComputeRectBeforeClip(const uint8_t directionBias, const Drawing::Rect& dst)
122 #endif
123 {
124 auto clipIPadding = dst;
125 float width = geoWidth_;
126 float height = geoHeight_;
127 if (directionBias == 1 || directionBias == 3) { // 1 3: rotation 0 270
128 width = geoHeight_;
129 height = geoWidth_;
130 }
131
132 #ifndef USE_ROSEN_DRAWING
133 if (height - dst.GetHeight() > 1) {
134 if (mat_.getTranslateY() > surfaceHeight_ / 2) { // 2 half of height
135 clipIPadding = SkRect::MakeLTRB(dst.GetLeft(), dst.GetTop(), dst.GetRight(), dst.GetTop() + height);
136 } else {
137 clipIPadding = SkRect::MakeLTRB(dst.GetLeft(), dst.GetBottom() - height, dst.GetRight(), dst.GetBottom());
138 }
139 }
140 if (width - dst.GetWidth() > 1) {
141 if (mat_.getTranslateX() > surfaceWidth_ / 2) { // 2 half of width
142 clipIPadding = SkRect::MakeLTRB(clipIPadding.GetLeft(), clipIPadding.GetTop(), clipIPadding.GetLeft() +
143 width, clipIPadding.GetBottom());
144 } else {
145 clipIPadding = SkRect::MakeLTRB(clipIPadding.GetRight() - width, clipIPadding.GetTop(),
146 clipIPadding.GetRight(), clipIPadding.GetBottom());
147 }
148 }
149 #else
150 if (height - dst.GetHeight() > 1) {
151 if (mat_.Get(Drawing::Matrix::TRANS_Y) > surfaceHeight_ / 2) { // 2 half of height
152 clipIPadding = Drawing::Rect(dst.GetLeft(), dst.GetTop(), dst.GetRight(), dst.GetTop() + height);
153 } else {
154 clipIPadding = Drawing::Rect(dst.GetLeft(), dst.GetBottom() - height, dst.GetRight(), dst.GetBottom());
155 }
156 }
157 if (width - dst.GetWidth() > 1) {
158 if (mat_.Get(Drawing::Matrix::TRANS_X) > surfaceWidth_ / 2) { // 2 half of width
159 clipIPadding = Drawing::Rect(clipIPadding.GetLeft(), clipIPadding.GetTop(), clipIPadding.GetLeft() + width,
160 clipIPadding.GetBottom());
161 } else {
162 clipIPadding = Drawing::Rect(clipIPadding.GetRight() - width, clipIPadding.GetTop(),
163 clipIPadding.GetRight(), clipIPadding.GetBottom());
164 }
165 }
166 #endif
167 return clipIPadding;
168 }
169
ComputeScale(float width,float height,bool useMaskAlgorithm)170 void RSLinearGradientBlurFilter::ComputeScale(float width, float height, bool useMaskAlgorithm)
171 {
172 if (RSSystemProperties::GetMaskLinearBlurEnabled() && useMaskAlgorithm) {
173 imageScale_ = 1.f;
174 } else {
175 if (width * height < 10000) { // 10000 for 100 * 100 resolution
176 imageScale_ = 0.7f; // 0.7 for scale
177 } else {
178 imageScale_ = 0.5f; // 0.5 for scale
179 }
180 }
181 }
182
183 #ifndef USE_ROSEN_DRAWING
CalcDirectionBias(const SkMatrix & mat)184 uint8_t RSLinearGradientBlurFilter::CalcDirectionBias(const SkMatrix& mat)
185 {
186 uint8_t directionBias = 0;
187 // 1 and 3 represents rotate matrix's index
188 if ((mat.get(1) > FLOAT_ZERO_THRESHOLD) && (mat.get(3) < (0 - FLOAT_ZERO_THRESHOLD))) {
189 directionBias = 1; // 1 represents rotate 90 degree
190 // 0 and 4 represents rotate matrix's index
191 } else if ((mat.get(0) < (0 - FLOAT_ZERO_THRESHOLD)) && (mat.get(4) < (0 - FLOAT_ZERO_THRESHOLD))) {
192 directionBias = 2; // 2 represents rotate 180 degree
193 // 1 and 3 represents rotate matrix's index
194 } else if ((mat.get(1) < (0 - FLOAT_ZERO_THRESHOLD)) && (mat.get(3) > FLOAT_ZERO_THRESHOLD)) {
195 directionBias = 3; // 3 represents rotate 270 degree
196 }
197 return directionBias;
198 }
199 #else
CalcDirectionBias(const Drawing::Matrix & mat)200 uint8_t RSLinearGradientBlurFilter::CalcDirectionBias(const Drawing::Matrix& mat)
201 {
202 uint8_t directionBias = 0;
203 // 1 and 3 represents rotate matrix's index
204 if ((mat.Get(1) > FLOAT_ZERO_THRESHOLD) && (mat.Get(3) < (0 - FLOAT_ZERO_THRESHOLD))) {
205 directionBias = 1; // 1 represents rotate 90 degree
206 // 0 and 4 represents rotate matrix's index
207 } else if ((mat.Get(0) < (0 - FLOAT_ZERO_THRESHOLD)) && (mat.Get(4) < (0 - FLOAT_ZERO_THRESHOLD))) {
208 directionBias = 2; // 2 represents rotate 180 degree
209 // 1 and 3 represents rotate matrix's index
210 } else if ((mat.Get(1) < (0 - FLOAT_ZERO_THRESHOLD)) && (mat.Get(3) > FLOAT_ZERO_THRESHOLD)) {
211 directionBias = 3; // 3 represents rotate 270 degree
212 }
213 return directionBias;
214 }
215 #endif
216
TransformGradientBlurDirection(uint8_t & direction,const uint8_t directionBias)217 void RSLinearGradientBlurFilter::TransformGradientBlurDirection(uint8_t& direction, const uint8_t directionBias)
218 {
219 if (direction == static_cast<uint8_t>(GradientDirection::LEFT_BOTTOM)) {
220 direction += 2; // 2 is used to transtorm diagnal direction.
221 } else if (direction == static_cast<uint8_t>(GradientDirection::RIGHT_TOP) ||
222 direction == static_cast<uint8_t>(GradientDirection::RIGHT_BOTTOM)) {
223 direction -= 1; // 1 is used to transtorm diagnal direction.
224 }
225 if (direction <= static_cast<uint8_t>(GradientDirection::BOTTOM)) {
226 if (direction < directionBias) {
227 direction += DIRECTION_NUM;
228 }
229 direction -= directionBias;
230 } else {
231 direction -= DIRECTION_NUM;
232 if (direction < directionBias) {
233 direction += DIRECTION_NUM;
234 }
235 direction -= directionBias;
236 direction += DIRECTION_NUM;
237 }
238 if (direction == static_cast<uint8_t>(GradientDirection::RIGHT_BOTTOM)) {
239 direction -= 2; // 2 is used to restore diagnal direction.
240 } else if (direction == static_cast<uint8_t>(GradientDirection::LEFT_BOTTOM) ||
241 direction == static_cast<uint8_t>(GradientDirection::RIGHT_TOP)) {
242 direction += 1; // 1 is used to restore diagnal direction.
243 }
244 }
245
246 #ifndef USE_ROSEN_DRAWING
GetGradientDirectionPoints(SkPoint (& pts)[2],const SkRect & clipBounds,GradientDirection direction)247 bool RSLinearGradientBlurFilter::GetGradientDirectionPoints(
248 SkPoint (&pts)[2], const SkRect& clipBounds, GradientDirection direction)
249 {
250 switch (direction) {
251 case GradientDirection::BOTTOM: {
252 pts[0].set(clipBounds.width() / 2 + clipBounds.left(), clipBounds.top()); // 2 middle of width;
253 pts[1].set(clipBounds.width() / 2 + clipBounds.left(), clipBounds.bottom()); // 2 middle of width;
254 break;
255 }
256 case GradientDirection::TOP: {
257 pts[0].set(clipBounds.width() / 2 + clipBounds.left(), clipBounds.bottom()); // 2 middle of width;
258 pts[1].set(clipBounds.width() / 2 + clipBounds.left(), clipBounds.top()); // 2 middle of width;
259 break;
260 }
261 case GradientDirection::RIGHT: {
262 pts[0].set(clipBounds.left(), clipBounds.height() / 2 + clipBounds.top()); // 2 middle of height;
263 pts[1].set(clipBounds.right(), clipBounds.height() / 2 + clipBounds.top()); // 2 middle of height;
264 break;
265 }
266 case GradientDirection::LEFT: {
267 pts[0].set(clipBounds.right(), clipBounds.height() / 2 + clipBounds.top()); // 2 middle of height;
268 pts[1].set(clipBounds.left(), clipBounds.height() / 2 + clipBounds.top()); // 2 middle of height;
269 break;
270 }
271 case GradientDirection::RIGHT_BOTTOM: {
272 pts[0].set(clipBounds.left(), clipBounds.top());
273 pts[1].set(clipBounds.right(), clipBounds.bottom());
274 break;
275 }
276 case GradientDirection::LEFT_TOP: {
277 pts[0].set(clipBounds.right(), clipBounds.bottom());
278 pts[1].set(clipBounds.left(), clipBounds.top());
279 break;
280 }
281 case GradientDirection::LEFT_BOTTOM: {
282 pts[0].set(clipBounds.right(), clipBounds.top());
283 pts[1].set(clipBounds.left(), clipBounds.bottom());
284 break;
285 }
286 case GradientDirection::RIGHT_TOP: {
287 pts[0].set(clipBounds.left(), clipBounds.bottom());
288 pts[1].set(clipBounds.right(), clipBounds.top());
289 break;
290 }
291 default: {
292 return false;
293 }
294 }
295 return true;
296 }
297 #else
GetGradientDirectionPoints(Drawing::Point (& pts)[2],const Drawing::Rect & clipBounds,GradientDirection direction)298 bool RSLinearGradientBlurFilter::GetGradientDirectionPoints(
299 Drawing::Point (&pts)[2], const Drawing::Rect& clipBounds, GradientDirection direction)
300 {
301 switch (direction) {
302 case GradientDirection::BOTTOM: {
303 pts[0].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetTop()); // 2 middle of width;
304 pts[1].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetBottom()); // 2 middle of width;
305 break;
306 }
307 case GradientDirection::TOP: {
308 pts[0].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetBottom()); // 2 middle of width;
309 pts[1].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetTop()); // 2 middle of width;
310 break;
311 }
312 case GradientDirection::RIGHT: {
313 pts[0].Set(clipBounds.GetLeft(), clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
314 pts[1].Set(clipBounds.GetRight(), clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
315 break;
316 }
317 case GradientDirection::LEFT: {
318 pts[0].Set(clipBounds.GetRight(), clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
319 pts[1].Set(clipBounds.GetLeft(), clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
320 break;
321 }
322 case GradientDirection::RIGHT_BOTTOM: {
323 pts[0].Set(clipBounds.GetLeft(), clipBounds.GetTop());
324 pts[1].Set(clipBounds.GetRight(), clipBounds.GetBottom());
325 break;
326 }
327 case GradientDirection::LEFT_TOP: {
328 pts[0].Set(clipBounds.GetRight(), clipBounds.GetBottom());
329 pts[1].Set(clipBounds.GetLeft(), clipBounds.GetTop());
330 break;
331 }
332 case GradientDirection::LEFT_BOTTOM: {
333 pts[0].Set(clipBounds.GetRight(), clipBounds.GetTop());
334 pts[1].Set(clipBounds.GetLeft(), clipBounds.GetBottom());
335 break;
336 }
337 case GradientDirection::RIGHT_TOP: {
338 pts[0].Set(clipBounds.GetLeft(), clipBounds.GetBottom());
339 pts[1].Set(clipBounds.GetRight(), clipBounds.GetTop());
340 break;
341 }
342 default: {
343 return false;
344 }
345 }
346 return true;
347 }
348 #endif
349
350 #ifndef USE_ROSEN_DRAWING
MakeAlphaGradientShader(const SkRect & clipBounds,const std::shared_ptr<RSLinearGradientBlurPara> & para,uint8_t directionBias)351 sk_sp<SkShader> RSLinearGradientBlurFilter::MakeAlphaGradientShader(
352 const SkRect& clipBounds, const std::shared_ptr<RSLinearGradientBlurPara>& para, uint8_t directionBias)
353 {
354 std::vector<SkColor> c;
355 std::vector<SkScalar> p;
356 SkPoint pts[2];
357
358 uint8_t direction = static_cast<uint8_t>(para->direction_);
359 if (directionBias != 0) {
360 TransformGradientBlurDirection(direction, directionBias);
361 }
362 bool result = GetGradientDirectionPoints(pts, clipBounds, static_cast<GradientDirection>(direction));
363 if (!result) {
364 return nullptr;
365 }
366 uint8_t ColorMax = 255;
367 uint8_t ColorMin = 0;
368 if (para->fractionStops_[0].second > 0.01) { // 0.01 represents the fraction bias
369 c.emplace_back(SkColorSetARGB(ColorMin, ColorMax, ColorMax, ColorMax));
370 p.emplace_back(para->fractionStops_[0].second - 0.01); // 0.01 represents the fraction bias
371 }
372 for (size_t i = 0; i < para->fractionStops_.size(); i++) {
373 c.emplace_back(SkColorSetARGB(
374 static_cast<uint8_t>(para->fractionStops_[i].first * ColorMax), ColorMax, ColorMax, ColorMax));
375 p.emplace_back(para->fractionStops_[i].second);
376 }
377 // 0.01 represents the fraction bias
378 if (para->fractionStops_[para->fractionStops_.size() - 1].second < (1 - 0.01)) {
379 c.emplace_back(SkColorSetARGB(ColorMin, ColorMax, ColorMax, ColorMax));
380 // 0.01 represents the fraction bias
381 p.emplace_back(para->fractionStops_[para->fractionStops_.size() - 1].second + 0.01);
382 }
383 auto shader = SkGradientShader::MakeLinear(pts, &c[0], &p[0], p.size(), SkTileMode::kClamp);
384 return shader;
385 }
386 #else
MakeAlphaGradientShader(const Drawing::Rect & clipBounds,const std::shared_ptr<RSLinearGradientBlurPara> & para,uint8_t directionBias)387 std::shared_ptr<Drawing::ShaderEffect> RSLinearGradientBlurFilter::MakeAlphaGradientShader(
388 const Drawing::Rect& clipBounds, const std::shared_ptr<RSLinearGradientBlurPara>& para, uint8_t directionBias)
389 {
390 std::vector<Drawing::ColorQuad> c;
391 std::vector<Drawing::scalar> p;
392 Drawing::Point pts[2];
393
394 uint8_t direction = static_cast<uint8_t>(para->direction_);
395 if (directionBias != 0) {
396 TransformGradientBlurDirection(direction, directionBias);
397 }
398 bool result = GetGradientDirectionPoints(pts, clipBounds, static_cast<GradientDirection>(direction));
399 if (!result) {
400 return nullptr;
401 }
402 uint8_t ColorMax = 255;
403 uint8_t ColorMin = 0;
404 if (para->fractionStops_[0].second > 0.01) { // 0.01 represents the fraction bias
405 c.emplace_back(Drawing::Color::ColorQuadSetARGB(ColorMin, ColorMax, ColorMax, ColorMax));
406 p.emplace_back(para->fractionStops_[0].second - 0.01); // 0.01 represents the fraction bias
407 }
408 for (size_t i = 0; i < para->fractionStops_.size(); i++) {
409 c.emplace_back(Drawing::Color::ColorQuadSetARGB(
410 static_cast<uint8_t>(para->fractionStops_[i].first * ColorMax), ColorMax, ColorMax, ColorMax));
411 p.emplace_back(para->fractionStops_[i].second);
412 }
413 // 0.01 represents the fraction bias
414 if (para->fractionStops_[para->fractionStops_.size() - 1].second < (1 - 0.01)) {
415 c.emplace_back(Drawing::Color::ColorQuadSetARGB(ColorMin, ColorMax, ColorMax, ColorMax));
416 // 0.01 represents the fraction bias
417 p.emplace_back(para->fractionStops_[para->fractionStops_.size() - 1].second + 0.01);
418 }
419 return Drawing::ShaderEffect::CreateLinearGradient(pts[0], pts[1], c, p, Drawing::TileMode::CLAMP);
420 }
421 #endif
422
MakeHorizontalMeanBlurEffect()423 void RSLinearGradientBlurFilter::MakeHorizontalMeanBlurEffect()
424 {
425 #ifndef USE_ROSEN_DRAWING
426 static const SkString HorizontalBlurString(
427 #else
428 static const std::string HorizontalBlurString(
429 #endif
430 R"(
431 uniform half r;
432 uniform shader imageShader;
433 uniform shader gradientShader;
434 half4 meanFilter(float2 coord, half radius)
435 {
436 half4 sum = vec4(0.0);
437 half div = 0;
438 for (half x = -30.0; x < 30.0; x += 1.0) {
439 if (x > radius) {
440 break;
441 }
442 if (abs(x) < radius) {
443 div += 1;
444 sum += imageShader.eval(coord + float2(x, 0));
445 }
446 }
447 return half4(sum.xyz / div, 1.0);
448 }
449 half4 main(float2 coord)
450 {
451 if (abs(gradientShader.eval(coord).a - 0) < 0.001) {
452 return imageShader.eval(coord);
453 }
454 float val = clamp(r * gradientShader.eval(coord).a, 1.0, r);
455 return meanFilter(coord, val);
456 }
457 )");
458
459 #ifndef USE_ROSEN_DRAWING
460 if (horizontalMeanBlurShaderEffect_ == nullptr) {
461 auto [horizontalMeanBlurShaderEffect, error] = SkRuntimeEffect::MakeForShader(HorizontalBlurString);
462 if (!horizontalMeanBlurShaderEffect) {
463 ROSEN_LOGE("RSLinearGradientBlurFilter::RuntimeShader horizontalEffect error: %{public}s\n", error.c_str());
464 return;
465 }
466 horizontalMeanBlurShaderEffect_ = std::move(horizontalMeanBlurShaderEffect);
467 }
468 #else
469 if (horizontalMeanBlurShaderEffect_ == nullptr) {
470 horizontalMeanBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(HorizontalBlurString);
471 }
472 #endif
473 }
474
MakeVerticalMeanBlurEffect()475 void RSLinearGradientBlurFilter::MakeVerticalMeanBlurEffect()
476 {
477 #ifndef USE_ROSEN_DRAWING
478 static const SkString VerticalBlurString(
479 #else
480 static const std::string VerticalBlurString(
481 #endif
482 R"(
483 uniform half r;
484 uniform shader imageShader;
485 uniform shader gradientShader;
486 half4 meanFilter(float2 coord, half radius)
487 {
488 half4 sum = vec4(0.0);
489 half div = 0;
490 for (half y = -30.0; y < 30.0; y += 1.0) {
491 if (y > radius) {
492 break;
493 }
494 if (abs(y) < radius) {
495 div += 1;
496 sum += imageShader.eval(coord + float2(0, y));
497 }
498 }
499 return half4(sum.xyz / div, 1.0);
500 }
501 half4 main(float2 coord)
502 {
503 if (abs(gradientShader.eval(coord).a - 0) < 0.001) {
504 return imageShader.eval(coord);
505 }
506 float val = clamp(r * gradientShader.eval(coord).a, 1.0, r);
507 return meanFilter(coord, val);
508 }
509 )");
510
511 #ifndef USE_ROSEN_DRAWING
512 if (verticalMeanBlurShaderEffect_ == nullptr) {
513 auto [verticalMeanBlurShaderEffect, error2] = SkRuntimeEffect::MakeForShader(VerticalBlurString);
514 if (!verticalMeanBlurShaderEffect) {
515 ROSEN_LOGE("KawaseBlurFilter::RuntimeShader verticalEffect error: %s{public}\n", error2.c_str());
516 return;
517 }
518 verticalMeanBlurShaderEffect_ = std::move(verticalMeanBlurShaderEffect);
519 }
520 #else
521 if (verticalMeanBlurShaderEffect_ == nullptr) {
522 verticalMeanBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(VerticalBlurString);
523 }
524 #endif
525 }
526
527 #ifndef USE_ROSEN_DRAWING
DrawMeanLinearGradientBlur(const sk_sp<SkImage> & image,SkCanvas & canvas,float radius,sk_sp<SkShader> alphaGradientShader,const SkRect & dst)528 void RSLinearGradientBlurFilter::DrawMeanLinearGradientBlur(const sk_sp<SkImage>& image, SkCanvas& canvas,
529 float radius, sk_sp<SkShader> alphaGradientShader, const SkRect& dst)
530 {
531 if (!horizontalMeanBlurShaderEffect_ || !verticalMeanBlurShaderEffect_ || !image) {
532 ROSEN_LOGE("RSLinearGradientBlurFilter::shader error.");
533 return;
534 }
535
536 SkMatrix blurMatrix = SkMatrix::Scale(imageScale_, imageScale_);
537 blurMatrix.postConcat(SkMatrix::Translate(dst.fLeft, dst.fTop));
538 auto width = image->width();
539 auto height = image->height();
540 SkImageInfo scaledInfo = image->imageInfo().makeWH(std::ceil(width * imageScale_), std::ceil(height * imageScale_));
541
542 SkRuntimeShaderBuilder hBlurBuilder(horizontalMeanBlurShaderEffect_);
543 hBlurBuilder.uniform("r") = radius;
544 hBlurBuilder.child("imageShader") = image->makeShader(SkSamplingOptions(SkFilterMode::kLinear), blurMatrix);
545 hBlurBuilder.child("gradientShader") = alphaGradientShader;
546 sk_sp<SkImage> tmpBlur(hBlurBuilder.makeImage(canvas.recordingContext(), nullptr, scaledInfo, false));
547
548 SkRuntimeShaderBuilder vBlurBuilder(verticalMeanBlurShaderEffect_);
549 vBlurBuilder.uniform("r") = radius;
550 vBlurBuilder.child("imageShader") = tmpBlur->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
551 vBlurBuilder.child("gradientShader") = alphaGradientShader;
552 sk_sp<SkImage> tmpBlur2(vBlurBuilder.makeImage(canvas.recordingContext(), nullptr, scaledInfo, false));
553
554 hBlurBuilder.child("imageShader") = tmpBlur2->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
555 sk_sp<SkImage> tmpBlur3(hBlurBuilder.makeImage(canvas.recordingContext(), nullptr, scaledInfo, false));
556
557 vBlurBuilder.child("imageShader") = tmpBlur3->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
558 sk_sp<SkImage> tmpBlur4(vBlurBuilder.makeImage(canvas.recordingContext(), nullptr, scaledInfo, false));
559
560 float invBlurScale = 1.0f / imageScale_;
561 SkMatrix invBlurMatrix = SkMatrix::Scale(invBlurScale, invBlurScale);
562 auto blurShader = tmpBlur4->makeShader(SkSamplingOptions(SkFilterMode::kLinear), &invBlurMatrix);
563
564 SkPaint paint;
565 paint.setShader(blurShader);
566 canvas.drawRect(dst, paint);
567 }
568 #else
DrawMeanLinearGradientBlur(const std::shared_ptr<Drawing::Image> & image,Drawing::Canvas & canvas,float radius,std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,const Drawing::Rect & dst)569 void RSLinearGradientBlurFilter::DrawMeanLinearGradientBlur(const std::shared_ptr<Drawing::Image>& image,
570 Drawing::Canvas& canvas, float radius, std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,
571 const Drawing::Rect& dst)
572 {
573 if (!horizontalMeanBlurShaderEffect_ || !verticalMeanBlurShaderEffect_ ||!image) { return; }
574
575 Drawing::Matrix m;
576 Drawing::Matrix blurMatrix;
577 blurMatrix.PostScale(imageScale_, imageScale_);
578 blurMatrix.PostTranslate(dst.GetLeft(), dst.GetTop());
579
580 auto width = image->GetWidth();
581 auto height = image->GetHeight();
582 auto originImageInfo = image->GetImageInfo();
583 auto scaledInfo = Drawing::ImageInfo(std::ceil(width * imageScale_), std::ceil(height * imageScale_),
584 originImageInfo.GetColorType(), originImageInfo.GetAlphaType(), originImageInfo.GetColorSpace());
585 Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
586
587 Drawing::RuntimeShaderBuilder hBlurBuilder(horizontalMeanBlurShaderEffect_);
588 hBlurBuilder.SetUniform("r", radius);
589 hBlurBuilder.SetChild("imageShader", Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
590 Drawing::TileMode::CLAMP, linear, blurMatrix));
591 hBlurBuilder.SetChild("gradientShader", alphaGradientShader);
592 std::shared_ptr<Drawing::Image> tmpBlur(hBlurBuilder.MakeImage(
593 canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
594
595 Drawing::RuntimeShaderBuilder vBlurBuilder(verticalMeanBlurShaderEffect_);
596 vBlurBuilder.SetUniform("r", radius);
597 vBlurBuilder.SetChild("imageShader", Drawing::ShaderEffect::CreateImageShader(*tmpBlur, Drawing::TileMode::CLAMP,
598 Drawing::TileMode::CLAMP, linear, m));
599 vBlurBuilder.SetChild("gradientShader", alphaGradientShader);
600 std::shared_ptr<Drawing::Image> tmpBlur2(vBlurBuilder.MakeImage(
601 canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
602
603 hBlurBuilder.SetChild("imageShader", Drawing::ShaderEffect::CreateImageShader(*tmpBlur2, Drawing::TileMode::CLAMP,
604 Drawing::TileMode::CLAMP, linear, m));
605 std::shared_ptr<Drawing::Image> tmpBlur3(hBlurBuilder.MakeImage(
606 canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
607
608 vBlurBuilder.SetChild("imageShader", Drawing::ShaderEffect::CreateImageShader(*tmpBlur3, Drawing::TileMode::CLAMP,
609 Drawing::TileMode::CLAMP, linear, m));
610 std::shared_ptr<Drawing::Image> tmpBlur4(vBlurBuilder.MakeImage(
611 canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
612
613 float invBlurScale = 1.0f / imageScale_;
614 Drawing::Matrix invBlurMatrix;
615 invBlurMatrix.PostScale(invBlurScale, invBlurScale);
616 auto blurShader = Drawing::ShaderEffect::CreateImageShader(*tmpBlur4, Drawing::TileMode::CLAMP,
617 Drawing::TileMode::CLAMP, linear, invBlurMatrix);
618
619 Drawing::Brush brush;
620 brush.SetShaderEffect(blurShader);
621 canvas.AttachBrush(brush);
622 canvas.DrawRect(dst);
623 canvas.DetachBrush();
624 }
625 #endif
626
627 #ifndef USE_ROSEN_DRAWING
DrawMaskLinearGradientBlur(const sk_sp<SkImage> & image,SkCanvas & canvas,std::shared_ptr<RSSkiaFilter> & blurFilter,sk_sp<SkShader> alphaGradientShader,const SkRect & dst)628 void RSLinearGradientBlurFilter::DrawMaskLinearGradientBlur(const sk_sp<SkImage>& image, SkCanvas& canvas,
629 std::shared_ptr<RSSkiaFilter>& blurFilter, sk_sp<SkShader> alphaGradientShader, const SkRect& dst)
630 {
631 if (image == nullptr) {
632 ROSEN_LOGE("RSLinearGradientBlurFilter::DrawMaskLinearGradientBlur image is null");
633 return;
634 }
635
636 blurFilter->DrawImageRect(canvas, image, SkRect::Make(image->bounds()), dst);
637 auto offscreenSurface = canvas.GetSurface();
638 if (offscreenSurface == nullptr) {
639 return;
640 }
641 auto filteredSnapshot = offscreenSurface->makeImageSnapshot();
642 SkMatrix inputMatrix = SkMatrix::Translate(dst.fLeft, dst.fTop);
643 auto srcImageShader = image->makeShader(SkSamplingOptions(SkFilterMode::kLinear), inputMatrix);
644 auto blurImageShader = filteredSnapshot->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
645 auto shader = MakeMaskLinearGradientBlurShader(srcImageShader, blurImageShader, alphaGradientShader);
646
647 SkPaint paint;
648 paint.setShader(shader);
649 canvas.drawRect(dst, paint);
650 }
651 #else
DrawMaskLinearGradientBlur(const std::shared_ptr<Drawing::Image> & image,Drawing::Canvas & canvas,std::shared_ptr<RSDrawingFilter> & blurFilter,std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,const Drawing::Rect & dst)652 void RSLinearGradientBlurFilter::DrawMaskLinearGradientBlur(const std::shared_ptr<Drawing::Image>& image,
653 Drawing::Canvas& canvas, std::shared_ptr<RSDrawingFilter>& blurFilter,
654 std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader, const Drawing::Rect& dst)
655 {
656 if (image == nullptr) {
657 ROSEN_LOGE("RSLinearGradientBlurFilter::DrawMaskLinearGradientBlur image is null");
658 return;
659 }
660
661 auto imageInfo = image->GetImageInfo();
662 auto srcRect = Drawing::Rect(0, 0, imageInfo.GetWidth(), imageInfo.GetHeight());
663 blurFilter->DrawImageRect(canvas, image, srcRect, dst);
664 auto offscreenSurface = canvas.GetSurface();
665 if (offscreenSurface == nullptr) {
666 return;
667 }
668 std::shared_ptr<Drawing::Image> filteredSnapshot = offscreenSurface->GetImageSnapshot();
669 Drawing::Matrix matrix;
670 Drawing::Matrix inputMatrix;
671 inputMatrix.Translate(dst.GetLeft(), dst.GetTop());
672
673 auto srcImageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
674 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), inputMatrix);
675 auto blurImageShader = Drawing::ShaderEffect::CreateImageShader(*filteredSnapshot, Drawing::TileMode::CLAMP,
676 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
677 auto shader = MakeMaskLinearGradientBlurShader(srcImageShader, blurImageShader, alphaGradientShader);
678
679 Drawing::Brush brush;
680 brush.SetShaderEffect(shader);
681 canvas.AttachBrush(brush);
682 canvas.DrawRect(dst);
683 canvas.DetachBrush();
684 }
685 #endif
686
687 #ifndef USE_ROSEN_DRAWING
MakeMaskLinearGradientBlurShader(sk_sp<SkShader> srcImageShader,sk_sp<SkShader> blurImageShader,sk_sp<SkShader> gradientShader)688 sk_sp<SkShader> RSLinearGradientBlurFilter::MakeMaskLinearGradientBlurShader(
689 sk_sp<SkShader> srcImageShader, sk_sp<SkShader> blurImageShader, sk_sp<SkShader> gradientShader)
690 #else
691 std::shared_ptr<Drawing::ShaderEffect> RSLinearGradientBlurFilter::MakeMaskLinearGradientBlurShader(
692 std::shared_ptr<Drawing::ShaderEffect> srcImageShader, std::shared_ptr<Drawing::ShaderEffect> blurImageShader,
693 std::shared_ptr<Drawing::ShaderEffect> gradientShader)
694 #endif
695 {
696 static const char* prog = R"(
697 uniform shader srcImageShader;
698 uniform shader blurImageShader;
699 uniform shader gradientShader;
700 half4 meanFilter(float2 coord)
701 {
702 vec3 srcColor = vec3(srcImageShader.eval(coord).r,
703 srcImageShader.eval(coord).g, srcImageShader.eval(coord).b);
704 vec3 blurColor = vec3(blurImageShader.eval(coord).r,
705 blurImageShader.eval(coord).g, blurImageShader.eval(coord).b);
706 float gradient = gradientShader.eval(coord).a;
707
708 vec3 color = blurColor * gradient + srcColor * (1 - gradient);
709 return vec4(color, 1.0);
710 }
711 half4 main(float2 coord)
712 {
713 if (abs(gradientShader.eval(coord).a) < 0.001) {
714 return srcImageShader.eval(coord);
715 }
716
717 if (abs(gradientShader.eval(coord).a) > 0.999) {
718 return blurImageShader.eval(coord);
719 }
720
721 return meanFilter(coord);
722 }
723 )";
724
725 #ifndef USE_ROSEN_DRAWING
726 auto [effect, err] = SkRuntimeEffect::MakeForShader(SkString(prog));
727 if (!effect) {
728 return nullptr;
729 }
730
731 SkRuntimeShaderBuilder builder(effect);
732 builder.child("srcImageShader") = srcImageShader;
733 builder.child("blurImageShader") = blurImageShader;
734 builder.child("gradientShader") = gradientShader;
735 return builder.makeShader(nullptr, false);
736 #else
737 if (maskBlurShaderEffect_ == nullptr) {
738 maskBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
739 if (maskBlurShaderEffect_ == nullptr) {
740 return nullptr;
741 }
742 }
743
744 auto builder = std::make_shared<Drawing::RuntimeShaderBuilder>(maskBlurShaderEffect_);
745 builder->SetChild("srcImageShader", srcImageShader);
746 builder->SetChild("blurImageShader", blurImageShader);
747 builder->SetChild("gradientShader", gradientShader);
748 return builder->MakeShader(nullptr, false);
749 #endif
750 }
751
GetDescription()752 std::string RSLinearGradientBlurFilter::GetDescription()
753 {
754 return "RSLinearGradientBlurFilter";
755 }
756 } // namespace Rosen
757 } // namespace OHOS
758