• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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