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 "ge_linear_gradient_blur_shader_filter.h"
16
17 #include "ge_log.h"
18 #include "ge_system_properties.h"
19
20 namespace OHOS {
21 namespace Rosen {
22
23 namespace {
24 constexpr static float FLOAT_ZERO_THRESHOLD = 0.001f;
25 constexpr static uint8_t DIRECTION_NUM = 4;
26
GetMaskLinearBlurEnabled()27 static bool GetMaskLinearBlurEnabled()
28 {
29 #ifdef GE_OHOS
30 // Determine whether the mask LinearBlur render should be enabled. The default value is 0,
31 // which means that it is unenabled.
32 static bool enabled =
33 std::atoi((system::GetParameter("persist.sys.graphic.maskLinearBlurEnabled", "1")).c_str()) != 0;
34 return enabled;
35 #else
36 return false;
37 #endif
38 }
39 } // namespace
40
41 std::shared_ptr<Drawing::RuntimeEffect> GELinearGradientBlurShaderFilter::horizontalMeanBlurShaderEffect_ = nullptr;
42 std::shared_ptr<Drawing::RuntimeEffect> GELinearGradientBlurShaderFilter::verticalMeanBlurShaderEffect_ = nullptr;
43 std::shared_ptr<Drawing::RuntimeEffect> GELinearGradientBlurShaderFilter::maskBlurShaderEffect_ = nullptr;
44
GELinearGradientBlurShaderFilter(const Drawing::GELinearGradientBlurShaderFilterParams & params)45 GELinearGradientBlurShaderFilter::GELinearGradientBlurShaderFilter(
46 const Drawing::GELinearGradientBlurShaderFilterParams& params)
47 {
48 geoWidth_ = params.geoWidth;
49 geoHeight_ = params.geoHeight;
50 auto maskLinearBlur = GetMaskLinearBlurEnabled();
51 linearGradientBlurPara_ = std::make_shared<GELinearGradientBlurPara>(
52 params.blurRadius, params.fractionStops, static_cast<GEGradientDirection>(params.direction), maskLinearBlur);
53 mat_ = params.mat;
54 tranX_ = params.tranX;
55 tranY_ = params.tranY;
56 isOffscreenCanvas_ = params.isOffscreenCanvas;
57 }
58
ProcessImageDDGR(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> image,uint8_t directionBias)59 std::shared_ptr<Drawing::Image> GELinearGradientBlurShaderFilter::ProcessImageDDGR(
60 Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image> image, uint8_t directionBias)
61 {
62 auto& para = linearGradientBlurPara_;
63 auto clipIPadding = Drawing::Rect(0, 0, geoWidth_ * imageScale_, geoHeight_ * imageScale_);
64 uint8_t direction = static_cast<uint8_t>(para->direction_);
65 TransformGradientBlurDirection(direction, directionBias);
66 float radius = para->blurRadius_;
67
68 Drawing::Brush brush;
69 Drawing::Filter imageFilter;
70 Drawing::GradientBlurType blurType;
71 if (GetMaskLinearBlurEnabled() && para->useMaskAlgorithm_) {
72 blurType = Drawing::GradientBlurType::ALPHA_BLEND;
73 radius /= 2; // 2: half radius.
74 } else {
75 radius -= GELinearGradientBlurPara::ORIGINAL_BASE;
76 radius = std::clamp(radius, 0.0f, 60.0f); // 60.0 represents largest blur radius
77 blurType = Drawing::GradientBlurType::RADIUS_GRADIENT;
78 }
79 imageFilter.SetImageFilter(Drawing::ImageFilter::CreateGradientBlurImageFilter(
80 radius, para->fractionStops_, static_cast<Drawing::GradientDir>(direction), blurType, nullptr));
81 brush.SetFilter(imageFilter);
82
83 canvas.AttachBrush(brush);
84 Drawing::Rect rect = clipIPadding;
85 rect.Offset(-clipIPadding.GetLeft(), -clipIPadding.GetTop());
86 canvas.DrawImageRect(
87 *image, rect, clipIPadding, Drawing::SamplingOptions(), Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
88 canvas.DetachBrush();
89 return image;
90 }
91
ProcessImage(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> image,const Drawing::Rect & src,const Drawing::Rect & dst)92 std::shared_ptr<Drawing::Image> GELinearGradientBlurShaderFilter::ProcessImage(Drawing::Canvas& canvas,
93 const std::shared_ptr<Drawing::Image> image, const Drawing::Rect& src, const Drawing::Rect& dst)
94 {
95 auto& para = linearGradientBlurPara_;
96 if (!image || para == nullptr || para->blurRadius_ <= 0) {
97 return image;
98 }
99 LOGD("GELinearGradientBlurShaderFilter::DrawImageRect%{public}f, %{public}f, %{public}f, %{public}f, %{public}f "
100 "%{public}d", para->blurRadius_, geoWidth_, geoHeight_, tranX_, tranY_, (int)isOffscreenCanvas_);
101
102 ComputeScale(dst.GetWidth(), dst.GetHeight(), para->useMaskAlgorithm_);
103 auto clipIPadding = Drawing::Rect(0, 0, geoWidth_ * imageScale_, geoHeight_ * imageScale_);
104 uint8_t directionBias = 0;
105 auto alphaGradientShader = MakeAlphaGradientShader(clipIPadding, para, directionBias);
106 if (alphaGradientShader == nullptr) {
107 LOGE("GELinearGradientBlurShaderFilter::DrawImageRect alphaGradientShader null");
108 return image;
109 }
110
111 if (GetMaskLinearBlurEnabled() && para->useMaskAlgorithm_) {
112 // use faster LinearGradientBlur if valid
113 if (para->linearGradientBlurFilter_ == nullptr) {
114 LOGE("RSPropertiesPainter::DrawLinearGradientBlur blurFilter null");
115 return image;
116 }
117
118 const auto& RSFilter = para->linearGradientBlurFilter_;
119 auto filter = RSFilter;
120 return DrawMaskLinearGradientBlur(image, canvas, filter, alphaGradientShader, dst);
121 } else {
122 // use original LinearGradientBlur
123 float radius = para->blurRadius_ - GELinearGradientBlurPara::ORIGINAL_BASE;
124 radius = std::clamp(radius, 0.0f, 60.0f); // 60.0 represents largest blur radius
125 radius = radius / 2 * imageScale_; // 2 half blur radius
126 MakeHorizontalMeanBlurEffect();
127 MakeVerticalMeanBlurEffect();
128 DrawMeanLinearGradientBlur(image, canvas, radius, alphaGradientShader, dst);
129 return image;
130 }
131 }
132
ComputeScale(float width,float height,bool useMaskAlgorithm)133 void GELinearGradientBlurShaderFilter::ComputeScale(float width, float height, bool useMaskAlgorithm)
134 {
135 if (GetMaskLinearBlurEnabled() && useMaskAlgorithm) {
136 imageScale_ = 1.0f;
137 } else {
138 if (width * height < 10000) { // 10000 for 100 * 100 resolution
139 imageScale_ = 0.7f; // 0.7 for scale
140 } else {
141 imageScale_ = 0.5f; // 0.5 for scale
142 }
143 }
144 }
145
CalcDirectionBias(const Drawing::Matrix & mat)146 uint8_t GELinearGradientBlurShaderFilter::CalcDirectionBias(const Drawing::Matrix& mat)
147 {
148 uint8_t directionBias = 0;
149 // 1 and 3 represents rotate matrix's index
150 if ((mat.Get(1) > FLOAT_ZERO_THRESHOLD) && (mat.Get(3) < (0 - FLOAT_ZERO_THRESHOLD))) {
151 directionBias = 1; // 1 represents rotate 90 degree
152 // 0 and 4 represents rotate matrix's index
153 } else if ((mat.Get(0) < (0 - FLOAT_ZERO_THRESHOLD)) && (mat.Get(4) < (0 - FLOAT_ZERO_THRESHOLD))) {
154 directionBias = 2; // 2 represents rotate 180 degree
155 // 1 and 3 represents rotate matrix's index
156 } else if ((mat.Get(1) < (0 - FLOAT_ZERO_THRESHOLD)) && (mat.Get(3) > FLOAT_ZERO_THRESHOLD)) {
157 directionBias = 3; // 3 represents rotate 270 degree
158 }
159 return directionBias;
160 }
161
TransformGradientBlurDirection(uint8_t & direction,const uint8_t directionBias)162 void GELinearGradientBlurShaderFilter::TransformGradientBlurDirection(uint8_t& direction, const uint8_t directionBias)
163 {
164 if (direction == static_cast<uint8_t>(GEGradientDirection::LEFT_BOTTOM)) {
165 direction += 2; // 2 is used to transtorm diagnal direction.
166 } else if (direction == static_cast<uint8_t>(GEGradientDirection::RIGHT_TOP) ||
167 direction == static_cast<uint8_t>(GEGradientDirection::RIGHT_BOTTOM)) {
168 direction -= 1; // 1 is used to transtorm diagnal direction.
169 }
170 if (direction <= static_cast<uint8_t>(GEGradientDirection::BOTTOM)) {
171 if (direction < directionBias) {
172 direction += DIRECTION_NUM;
173 }
174 direction -= directionBias;
175 } else {
176 direction -= DIRECTION_NUM;
177 if (direction < directionBias) {
178 direction += DIRECTION_NUM;
179 }
180 direction -= directionBias;
181 direction += DIRECTION_NUM;
182 }
183 if (direction == static_cast<uint8_t>(GEGradientDirection::RIGHT_BOTTOM)) {
184 direction -= 2; // 2 is used to restore diagnal direction.
185 } else if (direction == static_cast<uint8_t>(GEGradientDirection::LEFT_BOTTOM) ||
186 direction == static_cast<uint8_t>(GEGradientDirection::RIGHT_TOP)) {
187 direction += 1; // 1 is used to restore diagnal direction.
188 }
189 }
190
GetGEGradientDirectionPoints(Drawing::Point (& pts)[2],const Drawing::Rect & clipBounds,GEGradientDirection direction)191 bool GELinearGradientBlurShaderFilter::GetGEGradientDirectionPoints(
192 Drawing::Point (&pts)[2], const Drawing::Rect& clipBounds, GEGradientDirection direction) // 2 size of points
193 {
194 switch (direction) {
195 case GEGradientDirection::BOTTOM: {
196 pts[0].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetTop()); // 2 middle of width;
197 pts[1].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetBottom()); // 2 middle of width;
198 break;
199 }
200 case GEGradientDirection::TOP: {
201 pts[0].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetBottom()); // 2 middle of width;
202 pts[1].Set(clipBounds.GetWidth() / 2 + clipBounds.GetLeft(), clipBounds.GetTop()); // 2 middle of width;
203 break;
204 }
205 case GEGradientDirection::RIGHT: {
206 pts[0].Set(clipBounds.GetLeft(), clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
207 pts[1].Set(clipBounds.GetRight(),
208 clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
209 break;
210 }
211 case GEGradientDirection::LEFT: {
212 pts[0].Set(clipBounds.GetRight(),
213 clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
214 pts[1].Set(clipBounds.GetLeft(), clipBounds.GetHeight() / 2 + clipBounds.GetTop()); // 2 middle of height;
215 break;
216 }
217 default: {
218 }
219 }
220 return ProcessGradientDirectionPoints(pts, clipBounds, direction);
221 }
222
ProcessGradientDirectionPoints(Drawing::Point (& pts)[2],const Drawing::Rect & clipBounds,GEGradientDirection direction)223 bool GELinearGradientBlurShaderFilter::ProcessGradientDirectionPoints(
224 Drawing::Point (&pts)[2], const Drawing::Rect& clipBounds, GEGradientDirection direction) // 2 size of points
225 {
226 switch (direction) {
227 case GEGradientDirection::RIGHT_BOTTOM: {
228 pts[0].Set(clipBounds.GetLeft(), clipBounds.GetTop());
229 pts[1].Set(clipBounds.GetRight(), clipBounds.GetBottom());
230 break;
231 }
232 case GEGradientDirection::LEFT_TOP: {
233 pts[0].Set(clipBounds.GetRight(), clipBounds.GetBottom());
234 pts[1].Set(clipBounds.GetLeft(), clipBounds.GetTop());
235 break;
236 }
237 case GEGradientDirection::LEFT_BOTTOM: {
238 pts[0].Set(clipBounds.GetRight(), clipBounds.GetTop());
239 pts[1].Set(clipBounds.GetLeft(), clipBounds.GetBottom());
240 break;
241 }
242 case GEGradientDirection::RIGHT_TOP: {
243 pts[0].Set(clipBounds.GetLeft(), clipBounds.GetBottom());
244 pts[1].Set(clipBounds.GetRight(), clipBounds.GetTop());
245 break;
246 }
247 default: {
248 }
249 }
250 Drawing::Matrix pointsMat = mat_;
251 if (isOffscreenCanvas_) {
252 pointsMat.PostTranslate(-tranX_, -tranY_);
253 }
254 std::vector<Drawing::Point> points(pts, pts + 2); // 2 size of pts
255 pointsMat.MapPoints(points, points, points.size());
256 pts[0].Set(points[0].GetX(), points[0].GetY());
257 pts[1].Set(points[1].GetX(), points[1].GetY());
258 return true;
259 }
260
MakeAlphaGradientShader(const Drawing::Rect & clipBounds,const std::shared_ptr<GELinearGradientBlurPara> & para,uint8_t directionBias)261 std::shared_ptr<Drawing::ShaderEffect> GELinearGradientBlurShaderFilter::MakeAlphaGradientShader(
262 const Drawing::Rect& clipBounds, const std::shared_ptr<GELinearGradientBlurPara>& para, uint8_t directionBias)
263 {
264 std::vector<Drawing::ColorQuad> c;
265 std::vector<Drawing::scalar> p;
266 Drawing::Point pts[2]; // 2 size of points
267
268 uint8_t direction = static_cast<uint8_t>(para->direction_);
269 if (directionBias != 0) {
270 TransformGradientBlurDirection(direction, directionBias);
271 }
272 bool result = GetGEGradientDirectionPoints(pts, clipBounds, static_cast<GEGradientDirection>(direction));
273 if (!result) {
274 return nullptr;
275 }
276 uint8_t ColorMax = 255; // 255 max number of color
277 uint8_t ColorMin = 0;
278 if (para->fractionStops_[0].second > 0.01) { // 0.01 represents the fraction bias
279 c.emplace_back(Drawing::Color::ColorQuadSetARGB(ColorMin, ColorMax, ColorMax, ColorMax));
280 p.emplace_back(para->fractionStops_[0].second - 0.01); // 0.01 represents the fraction bias
281 }
282 for (size_t i = 0; i < para->fractionStops_.size(); i++) {
283 c.emplace_back(Drawing::Color::ColorQuadSetARGB(
284 static_cast<uint8_t>(para->fractionStops_[i].first * ColorMax), ColorMax, ColorMax, ColorMax));
285 p.emplace_back(para->fractionStops_[i].second);
286 }
287 // 0.01 represents the fraction bias
288 if (para->fractionStops_[para->fractionStops_.size() - 1].second < (1 - 0.01)) {
289 c.emplace_back(Drawing::Color::ColorQuadSetARGB(ColorMin, ColorMax, ColorMax, ColorMax));
290 // 0.01 represents the fraction bias
291 p.emplace_back(para->fractionStops_[para->fractionStops_.size() - 1].second + 0.01);
292 }
293 return Drawing::ShaderEffect::CreateLinearGradient(pts[0], pts[1], c, p, Drawing::TileMode::CLAMP);
294 }
295
MakeHorizontalMeanBlurEffect()296 void GELinearGradientBlurShaderFilter::MakeHorizontalMeanBlurEffect()
297 {
298 static const std::string HorizontalBlurString(
299 R"(
300 uniform half r;
301 uniform shader imageShader;
302 uniform shader gradientShader;
303 half4 meanFilter(float2 coord, half radius)
304 {
305 half4 sum = vec4(0.0);
306 half div = 0;
307 for (half x = -30.0; x < 30.0; x += 1.0) {
308 if (x > radius) {
309 break;
310 }
311 if (abs(x) < radius) {
312 div += 1;
313 sum += imageShader.eval(coord + float2(x, 0));
314 }
315 }
316 return half4(sum.xyz / div, 1.0);
317 }
318 half4 main(float2 coord)
319 {
320 if (abs(gradientShader.eval(coord).a - 0) < 0.001) {
321 return imageShader.eval(coord);
322 }
323 float val = clamp(r * gradientShader.eval(coord).a, 1.0, r);
324 return meanFilter(coord, val);
325 }
326 )");
327
328 if (horizontalMeanBlurShaderEffect_ == nullptr) {
329 horizontalMeanBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(HorizontalBlurString);
330 }
331 }
332
MakeVerticalMeanBlurEffect()333 void GELinearGradientBlurShaderFilter::MakeVerticalMeanBlurEffect()
334 {
335 static const std::string VerticalBlurString(
336 R"(
337 uniform half r;
338 uniform shader imageShader;
339 uniform shader gradientShader;
340 half4 meanFilter(float2 coord, half radius)
341 {
342 half4 sum = vec4(0.0);
343 half div = 0;
344 for (half y = -30.0; y < 30.0; y += 1.0) {
345 if (y > radius) {
346 break;
347 }
348 if (abs(y) < radius) {
349 div += 1;
350 sum += imageShader.eval(coord + float2(0, y));
351 }
352 }
353 return half4(sum.xyz / div, 1.0);
354 }
355 half4 main(float2 coord)
356 {
357 if (abs(gradientShader.eval(coord).a - 0) < 0.001) {
358 return imageShader.eval(coord);
359 }
360 float val = clamp(r * gradientShader.eval(coord).a, 1.0, r);
361 return meanFilter(coord, val);
362 }
363 )");
364
365 if (verticalMeanBlurShaderEffect_ == nullptr) {
366 verticalMeanBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(VerticalBlurString);
367 }
368 }
369
DrawMeanLinearGradientBlur(const std::shared_ptr<Drawing::Image> & image,Drawing::Canvas & canvas,float radius,std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,const Drawing::Rect & dst)370 void GELinearGradientBlurShaderFilter::DrawMeanLinearGradientBlur(const std::shared_ptr<Drawing::Image>& image,
371 Drawing::Canvas& canvas, float radius, std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,
372 const Drawing::Rect& dst)
373 {
374 if (!horizontalMeanBlurShaderEffect_ || !verticalMeanBlurShaderEffect_ || !image) {
375 return;
376 }
377
378 if (imageScale_ < 1e-6) {
379 return;
380 }
381
382 Drawing::Matrix m;
383 Drawing::Matrix blurMatrix;
384 blurMatrix.PostScale(imageScale_, imageScale_);
385 blurMatrix.PostTranslate(dst.GetLeft(), dst.GetTop());
386
387 Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
388
389 auto tmpBlur4 = BuildMeanLinearGradientBlur(image, canvas, radius, alphaGradientShader, blurMatrix);
390
391 float invBlurScale = 1.0f / imageScale_;
392 Drawing::Matrix invBlurMatrix;
393 invBlurMatrix.PostScale(invBlurScale, invBlurScale);
394 auto blurShader = Drawing::ShaderEffect::CreateImageShader(
395 *tmpBlur4, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, linear, invBlurMatrix);
396
397 Drawing::Brush brush;
398 brush.SetShaderEffect(blurShader);
399 canvas.AttachBrush(brush);
400 canvas.DrawRect(dst);
401 canvas.DetachBrush();
402 }
403
BuildMeanLinearGradientBlur(const std::shared_ptr<Drawing::Image> & image,Drawing::Canvas & canvas,float radius,std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,Drawing::Matrix blurMatrix)404 std::shared_ptr<Drawing::Image> GELinearGradientBlurShaderFilter::BuildMeanLinearGradientBlur(
405 const std::shared_ptr<Drawing::Image>& image, Drawing::Canvas& canvas, float radius,
406 std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader, Drawing::Matrix blurMatrix)
407 {
408 auto width = image->GetWidth();
409 auto height = image->GetHeight();
410 auto originImageInfo = image->GetImageInfo();
411 auto scaledInfo = Drawing::ImageInfo(std::ceil(width * imageScale_), std::ceil(height * imageScale_),
412 originImageInfo.GetColorType(), originImageInfo.GetAlphaType(), originImageInfo.GetColorSpace());
413 Drawing::Matrix m;
414 Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
415 Drawing::RuntimeShaderBuilder hBlurBuilder(horizontalMeanBlurShaderEffect_);
416 hBlurBuilder.SetUniform("r", radius);
417 auto shader1 = Drawing::ShaderEffect::CreateImageShader(
418 *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, linear, blurMatrix);
419 hBlurBuilder.SetChild("imageShader", shader1);
420 hBlurBuilder.SetChild("gradientShader", alphaGradientShader);
421 std::shared_ptr<Drawing::Image> tmpBlur(
422 hBlurBuilder.MakeImage(canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
423
424 Drawing::RuntimeShaderBuilder vBlurBuilder(verticalMeanBlurShaderEffect_);
425 vBlurBuilder.SetUniform("r", radius);
426 auto tmpBlurShader = Drawing::ShaderEffect::CreateImageShader(
427 *tmpBlur, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, linear, m);
428 vBlurBuilder.SetChild("imageShader", tmpBlurShader);
429 vBlurBuilder.SetChild("gradientShader", alphaGradientShader);
430 std::shared_ptr<Drawing::Image> tmpBlur2(
431 vBlurBuilder.MakeImage(canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
432
433 auto tmpBlur2Shader = Drawing::ShaderEffect::CreateImageShader(
434 *tmpBlur2, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, linear, m);
435 hBlurBuilder.SetChild("imageShader", tmpBlur2Shader);
436 std::shared_ptr<Drawing::Image> tmpBlur3(
437 hBlurBuilder.MakeImage(canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
438
439 auto tmpBlur3Shader = Drawing::ShaderEffect::CreateImageShader(
440 *tmpBlur3, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, linear, m);
441 vBlurBuilder.SetChild("imageShader", tmpBlur3Shader);
442 std::shared_ptr<Drawing::Image> tmpBlur4(
443 vBlurBuilder.MakeImage(canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
444 return tmpBlur4;
445 }
446
DrawMaskLinearGradientBlur(const std::shared_ptr<Drawing::Image> & image,Drawing::Canvas & canvas,std::shared_ptr<GEShaderFilter> & blurFilter,std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader,const Drawing::Rect & dst)447 std::shared_ptr<Drawing::Image> GELinearGradientBlurShaderFilter::DrawMaskLinearGradientBlur(
448 const std::shared_ptr<Drawing::Image>& image, Drawing::Canvas& canvas, std::shared_ptr<GEShaderFilter>& blurFilter,
449 std::shared_ptr<Drawing::ShaderEffect> alphaGradientShader, const Drawing::Rect& dst)
450 {
451 if (image == nullptr) {
452 LOGE("GELinearGradientBlurShaderFilter::DrawMaskLinearGradientBlur image is null");
453 return image;
454 }
455
456 auto imageInfo = image->GetImageInfo();
457 if (imageInfo.GetWidth() < 1e-6 || imageInfo.GetHeight() < 1e-6) {
458 return image;
459 }
460 auto srcRect = Drawing::Rect(0, 0, imageInfo.GetWidth(), imageInfo.GetHeight());
461 auto blurImage = blurFilter->ProcessImage(canvas, image, srcRect, dst);
462
463 Drawing::Matrix matrix;
464 Drawing::Matrix inputMatrix;
465 inputMatrix.Translate(dst.GetLeft(), dst.GetTop());
466 inputMatrix.PostScale(dst.GetWidth() / imageInfo.GetWidth(), dst.GetHeight() / imageInfo.GetHeight());
467
468 auto srcImageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
469 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), inputMatrix);
470 auto blurImageShader = Drawing::ShaderEffect::CreateImageShader(*blurImage, Drawing::TileMode::CLAMP,
471 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
472 auto builder = MakeMaskLinearGradientBlurShader(srcImageShader, blurImageShader, alphaGradientShader);
473 auto outImageInfo = Drawing::ImageInfo(dst.GetWidth(), dst.GetHeight(), blurImage->GetImageInfo().GetColorType(),
474 blurImage->GetImageInfo().GetAlphaType(), blurImage->GetImageInfo().GetColorSpace());
475 auto outImage = builder->MakeImage(canvas.GetGPUContext().get(), nullptr, outImageInfo, false);
476
477 return outImage;
478 }
479
MakeMaskLinearGradientBlurShader(std::shared_ptr<Drawing::ShaderEffect> srcImageShader,std::shared_ptr<Drawing::ShaderEffect> blurImageShader,std::shared_ptr<Drawing::ShaderEffect> gradientShader)480 std::shared_ptr<Drawing::RuntimeShaderBuilder> GELinearGradientBlurShaderFilter::MakeMaskLinearGradientBlurShader(
481 std::shared_ptr<Drawing::ShaderEffect> srcImageShader, std::shared_ptr<Drawing::ShaderEffect> blurImageShader,
482 std::shared_ptr<Drawing::ShaderEffect> gradientShader)
483 {
484 if (maskBlurShaderEffect_ == nullptr) {
485 static const char* prog = R"(
486 uniform shader srcImageShader;
487 uniform shader blurImageShader;
488 uniform shader gradientShader;
489 half4 meanFilter(float2 coord)
490 {
491 vec3 srcColor = vec3(srcImageShader.eval(coord).r,
492 srcImageShader.eval(coord).g, srcImageShader.eval(coord).b);
493 vec3 blurColor = vec3(blurImageShader.eval(coord).r,
494 blurImageShader.eval(coord).g, blurImageShader.eval(coord).b);
495 float gradient = gradientShader.eval(coord).a;
496
497 vec3 color = blurColor * gradient + srcColor * (1 - gradient);
498 return vec4(color, 1.0);
499 }
500 half4 main(float2 coord)
501 {
502 if (abs(gradientShader.eval(coord).a) < 0.001) {
503 return srcImageShader.eval(coord);
504 }
505
506 if (abs(gradientShader.eval(coord).a) > 0.999) {
507 return blurImageShader.eval(coord);
508 }
509
510 return meanFilter(coord);
511 }
512 )";
513 maskBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
514 if (maskBlurShaderEffect_ == nullptr) {
515 return nullptr;
516 }
517 }
518
519 auto builder = std::make_shared<Drawing::RuntimeShaderBuilder>(maskBlurShaderEffect_);
520 builder->SetChild("srcImageShader", srcImageShader);
521 builder->SetChild("blurImageShader", blurImageShader);
522 builder->SetChild("gradientShader", gradientShader);
523 return builder;
524 }
525
GetDescription()526 std::string GELinearGradientBlurShaderFilter::GetDescription()
527 {
528 return "GELinearGradientBlurShaderFilter";
529 }
530
GetDetailedDescription()531 std::string GELinearGradientBlurShaderFilter::GetDetailedDescription()
532 {
533 if (!linearGradientBlurPara_) {
534 return "GELinearGradientBlurShaderFilterBlur, radius: unavailable";
535 }
536 return "GELinearGradientBlurShaderFilterBlur, radius: " + std::to_string(linearGradientBlurPara_->blurRadius_);
537 }
538 } // namespace Rosen
539 } // namespace OHOS
540