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
16 #include "drawable/rs_property_drawable_utils.h"
17
18 #include "common/rs_obj_abs_geometry.h"
19 #include "common/rs_optional_trace.h"
20 #include "platform/common/rs_log.h"
21 #include "property/rs_properties_painter.h"
22 #include "render/rs_blur_filter.h"
23 #include "render/rs_color_picker.h"
24 #include "render/rs_drawing_filter.h"
25 #include "render/rs_effect_luminance_manager.h"
26 #include "render/rs_foreground_effect_filter.h"
27 #include "render/rs_material_filter.h"
28 #include "render/rs_motion_blur_filter.h"
29 #include "render/rs_render_kawase_blur_filter.h"
30 #include "render/rs_render_linear_gradient_blur_filter.h"
31 #include "render/rs_render_magnifier_filter.h"
32 #include "render/rs_render_maskcolor_filter.h"
33 #include "render/rs_render_mesa_blur_filter.h"
34 #ifdef USE_M133_SKIA
35 #include "src/core/SkChecksum.h"
36 #else
37 #include "src/core/SkOpts.h"
38 #endif
39
40 namespace OHOS {
41 namespace Rosen {
42 namespace {
43 constexpr int TRACE_LEVEL_TWO = 2;
44 constexpr int PARAM_DOUBLE = 2;
45 }
46
47 std::shared_ptr<Drawing::RuntimeEffect> RSPropertyDrawableUtils::binarizationShaderEffect_ = nullptr;
48 std::shared_ptr<Drawing::RuntimeEffect> RSPropertyDrawableUtils::dynamicDimShaderEffect_ = nullptr;
49 std::shared_ptr<Drawing::RuntimeEffect> RSPropertyDrawableUtils::dynamicBrightnessBlenderEffect_ = nullptr;
50 std::shared_ptr<Drawing::RuntimeEffect> RSPropertyDrawableUtils::dynamicBrightnessLinearBlenderEffect_ = nullptr;
51 std::shared_ptr<Drawing::RuntimeEffect> RSPropertyDrawableUtils::lightUpShaderEffect_ = nullptr;
52 std::shared_ptr<Drawing::RuntimeEffect> RSPropertyDrawableUtils::shadowBlenderEffect_ = nullptr;
53
RRect2DrawingRRect(const RRect & rr)54 Drawing::RoundRect RSPropertyDrawableUtils::RRect2DrawingRRect(const RRect& rr)
55 {
56 Drawing::Rect rect = Drawing::Rect(
57 rr.rect_.left_, rr.rect_.top_, rr.rect_.left_ + rr.rect_.width_, rr.rect_.top_ + rr.rect_.height_);
58
59 // set radius for all 4 corner of RRect
60 constexpr uint32_t NUM_OF_CORNERS_IN_RECT = 4;
61 std::vector<Drawing::Point> radii(NUM_OF_CORNERS_IN_RECT);
62 for (uint32_t i = 0; i < NUM_OF_CORNERS_IN_RECT; i++) {
63 radii.at(i).SetX(rr.radius_[i].x_);
64 radii.at(i).SetY(rr.radius_[i].y_);
65 }
66 return { rect, radii };
67 }
68
Rect2DrawingRect(const RectF & r)69 Drawing::Rect RSPropertyDrawableUtils::Rect2DrawingRect(const RectF& r)
70 {
71 return { r.left_, r.top_, r.left_ + r.width_, r.top_ + r.height_ };
72 }
73
GetRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool & isOutline)74 RRect RSPropertyDrawableUtils::GetRRectForDrawingBorder(
75 const RSProperties& properties, const std::shared_ptr<RSBorder>& border, const bool& isOutline)
76 {
77 if (!border) {
78 return {};
79 }
80
81 return isOutline ? RRect(properties.GetRRect().rect_.MakeOutset(border->GetWidthFour()), border->GetRadiusFour())
82 : properties.GetRRect();
83 }
84
GetInnerRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool & isOutline)85 RRect RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(
86 const RSProperties& properties, const std::shared_ptr<RSBorder>& border, const bool& isOutline)
87 {
88 if (!border) {
89 return {};
90 }
91 return isOutline ? properties.GetRRect() : properties.GetInnerRRect();
92 }
93
GetColorForShadowSyn(Drawing::Canvas * canvas,Drawing::Path & path,const Color & color,const int & colorStrategy)94 Color RSPropertyDrawableUtils::GetColorForShadowSyn(Drawing::Canvas* canvas, Drawing::Path& path, const Color& color,
95 const int& colorStrategy)
96 {
97 RSColor colorPicked;
98 auto shadowAlpha = color.GetAlpha();
99 auto matrix = canvas->GetTotalMatrix();
100 if (PickColorSyn(canvas, path, matrix, colorPicked, colorStrategy)) {
101 GetDarkColor(colorPicked);
102 } else {
103 shadowAlpha = 0;
104 }
105 return Color(colorPicked.GetRed(), colorPicked.GetGreen(), colorPicked.GetBlue(), shadowAlpha);
106 }
107
GetShadowRegionImage(Drawing::Canvas * canvas,Drawing::Path & drPath,Drawing::Matrix & matrix)108 std::shared_ptr<Drawing::Image> RSPropertyDrawableUtils::GetShadowRegionImage(Drawing::Canvas* canvas,
109 Drawing::Path& drPath, Drawing::Matrix& matrix)
110 {
111 Drawing::Rect clipBounds = drPath.GetBounds();
112 Drawing::RectI clipIBounds = { static_cast<int>(clipBounds.GetLeft()), static_cast<int>(clipBounds.GetTop()),
113 static_cast<int>(clipBounds.GetRight()), static_cast<int>(clipBounds.GetBottom()) };
114 Drawing::Surface* drSurface = canvas->GetSurface();
115 if (drSurface == nullptr) {
116 ROSEN_LOGE("RSPropertyDrawableUtils::GetShadowRegionImage drSurface is null");
117 return nullptr;
118 }
119 const int deviceWidth = drSurface->Width();
120 const int deviceHeight = drSurface->Height();
121 Drawing::Rect regionRect = {0, 0, clipIBounds.GetWidth(), clipIBounds.GetHeight()};
122 Drawing::Rect regionRectDev;
123 matrix.MapRect(regionRectDev, regionRect);
124 int32_t fLeft = std::clamp(int(regionRectDev.GetLeft()), 0, deviceWidth - 1);
125 int32_t fTop = std::clamp(int(regionRectDev.GetTop()), 0, deviceHeight - 1);
126 int32_t fRight = std::clamp(int(regionRectDev.GetRight()), 0, deviceWidth - 1);
127 int32_t fBottom = std::clamp(int(regionRectDev.GetBottom()), 0, deviceHeight - 1);
128 if (fLeft == fRight || fTop == fBottom) {
129 ROSEN_LOGE("RSPropertyDrawableUtils::GetShadowRegionImage Shadow Rect Invalid");
130 return nullptr;
131 }
132 Drawing::RectI regionBounds = { fLeft, fTop, fRight, fBottom };
133 std::shared_ptr<Drawing::Image> shadowRegionImage = drSurface->GetImageSnapshot(regionBounds);
134 return shadowRegionImage;
135 }
136
PickColorSyn(Drawing::Canvas * canvas,Drawing::Path & drPath,Drawing::Matrix & matrix,RSColor & colorPicked,const int & colorStrategy)137 bool RSPropertyDrawableUtils::PickColorSyn(Drawing::Canvas* canvas, Drawing::Path& drPath, Drawing::Matrix& matrix,
138 RSColor& colorPicked, const int& colorStrategy)
139 {
140 std::shared_ptr<Drawing::Image> shadowRegionImage = GetShadowRegionImage(canvas, drPath, matrix);
141 if (shadowRegionImage == nullptr) {
142 ROSEN_LOGE("RSPropertyDrawableUtils::PickColorSyn GetImageSnapshot Failed");
143 return false;
144 }
145 auto scaledImage = GpuScaleImage(canvas, shadowRegionImage);
146 if (scaledImage == nullptr) {
147 ROSEN_LOGE("RSPropertyDrawableUtils::PickColorSyn GpuScaleImageids null");
148 return false;
149 }
150 std::shared_ptr<Drawing::Pixmap> dst;
151 const int buffLen = scaledImage->GetWidth() * scaledImage->GetHeight();
152 auto pixelPtr = std::make_unique<uint32_t[]>(buffLen);
153 auto info = scaledImage->GetImageInfo();
154 dst = std::make_shared<Drawing::Pixmap>(info, pixelPtr.get(), info.GetWidth() * info.GetBytesPerPixel());
155 bool flag = scaledImage->ReadPixels(*dst, 0, 0);
156 if (!flag) {
157 ROSEN_LOGE("RSPropertyDrawableUtils::PickColorSyn ReadPixel Failed");
158 return false;
159 }
160 uint32_t errorCode = 0;
161 std::shared_ptr<RSColorPicker> colorPicker = RSColorPicker::CreateColorPicker(dst, errorCode);
162 if (colorPicker == nullptr) {
163 ROSEN_LOGE("RSPropertyDrawableUtils::PickColorSyn colorPicker is null");
164 return false;
165 }
166 if (errorCode != 0) {
167 return false;
168 }
169 Drawing::ColorQuad color;
170 if (colorStrategy == SHADOW_COLOR_STRATEGY::COLOR_STRATEGY_MAIN) {
171 colorPicker->GetLargestProportionColor(color);
172 } else {
173 colorPicker->GetAverageColor(color);
174 }
175 colorPicked = RSColor(Drawing::Color::ColorQuadGetR(color), Drawing::Color::ColorQuadGetG(color),
176 Drawing::Color::ColorQuadGetB(color), Drawing::Color::ColorQuadGetA(color));
177 return true;
178 }
179
GpuScaleImage(Drawing::Canvas * canvas,const std::shared_ptr<Drawing::Image> image)180 std::shared_ptr<Drawing::Image> RSPropertyDrawableUtils::GpuScaleImage(Drawing::Canvas* canvas,
181 const std::shared_ptr<Drawing::Image> image)
182 {
183 std::string shaderString(R"(
184 uniform shader imageInput;
185
186 half4 main(float2 xy) {
187 half4 c = imageInput.eval(xy);
188 return half4(c.rgb, 1.0);
189 }
190 )");
191
192 std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(shaderString);
193 if (!effect) {
194 ROSEN_LOGE("RSPropertyDrawableUtils::GpuScaleImage effect is null");
195 return nullptr;
196 }
197
198 Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
199 std::shared_ptr<Drawing::RuntimeShaderBuilder> effectBulider =
200 std::make_shared<Drawing::RuntimeShaderBuilder>(effect);
201 Drawing::ImageInfo pcInfo;
202 Drawing::Matrix matrix;
203 matrix.SetScale(1.0, 1.0);
204 if (image->GetWidth() * image->GetHeight() < 10000) { // 10000 = 100 * 100 pixels
205 pcInfo = Drawing::ImageInfo::MakeN32Premul(10, 10); // 10 * 10 pixels
206 matrix.SetScale(10.0 / image->GetWidth(), 10.0 / image->GetHeight()); // 10.0 pixels
207 } else {
208 pcInfo = Drawing::ImageInfo::MakeN32Premul(100, 100); // 100 * 100 pixels
209 matrix.SetScale(100.0 / image->GetWidth(), 100.0 / image->GetHeight()); // 100.0 pixels
210 }
211 effectBulider->SetChild("imageInput", Drawing::ShaderEffect::CreateImageShader(
212 *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, linear, matrix));
213 std::shared_ptr<Drawing::Image> tmpColorImg = effectBulider->MakeImage(
214 canvas->GetGPUContext().get(), nullptr, pcInfo, false);
215
216 return tmpColorImg;
217 }
218
GetDarkColor(RSColor & color)219 void RSPropertyDrawableUtils::GetDarkColor(RSColor& color)
220 {
221 // convert to lab
222 float minColorRange = 0;
223 float maxColorRange = 255;
224 float R = float(color.GetRed()) / maxColorRange;
225 float G = float(color.GetGreen()) / maxColorRange;
226 float B = float(color.GetBlue()) / maxColorRange;
227
228 float X = 0.4124 * R + 0.3576 * G + 0.1805 * B;
229 float Y = 0.2126 * R + 0.7152 * G + 0.0722 * B;
230 float Z = 0.0193 * R + 0.1192 * G + 0.9505 * B;
231
232 float Xn = 0.9505;
233 float Yn = 1.0000;
234 float Zn = 1.0889999;
235 float Fx = (X / Xn) > 0.008856 ? pow((X / Xn), 1.0 / 3) : (7.787 * (X / Xn) + 16.0 / 116);
236 float Fy = (Y / Yn) > 0.008856 ? pow((Y / Yn), 1.0 / 3) : (7.787 * (Y / Yn) + 16.0 / 116);
237 float Fz = (Z / Zn) > 0.008856 ? pow((Z / Zn), 1.0 / 3) : (7.787 * (Z / Zn) + 16.0 / 116);
238 float L = 116 * Fy - 16;
239 float a = 500 * (Fx - Fy);
240 float b = 200 * (Fy - Fz);
241
242 float standardLightness = 75.0;
243 if (L > standardLightness) {
244 float L1 = standardLightness;
245 float xw = 0.9505;
246 float yw = 1.0000;
247 float zw = 1.0889999;
248
249 float fy = (L1 + 16) / 116;
250 float fx = fy + (a / 500);
251 float fz = fy - (b / 200);
252
253 float X1 = xw * ((pow(fx, 3) > 0.008856) ? pow(fx, 3) : ((fx - 16.0 / 116) / 7.787));
254 float Y1 = yw * ((pow(fy, 3) > 0.008856) ? pow(fy, 3) : ((fy - 16.0 / 116) / 7.787));
255 float Z1 = zw * ((pow(fz, 3) > 0.008856) ? pow(fz, 3) : ((fz - 16.0 / 116) / 7.787));
256
257 float DarkR = 3.2406 * X1 - 1.5372 * Y1 - 0.4986 * Z1;
258 float DarkG = -0.9689 * X1 + 1.8758 * Y1 + 0.0415 * Z1;
259 float DarkB = 0.0557 * X1 - 0.2040 * Y1 + 1.0570 * Z1;
260
261 DarkR = std::clamp(maxColorRange * DarkR, minColorRange, maxColorRange);
262 DarkG = std::clamp(maxColorRange * DarkG, minColorRange, maxColorRange);
263 DarkB = std::clamp(maxColorRange * DarkB, minColorRange, maxColorRange);
264
265 color = RSColor(DarkR, DarkG, DarkB, color.GetAlpha());
266 }
267 }
268
DrawFilter(Drawing::Canvas * canvas,const std::shared_ptr<RSFilter> & rsFilter,const std::unique_ptr<RSFilterCacheManager> & cacheManager,NodeId nodeId,const bool isForegroundFilter)269 void RSPropertyDrawableUtils::DrawFilter(Drawing::Canvas* canvas,
270 const std::shared_ptr<RSFilter>& rsFilter, const std::unique_ptr<RSFilterCacheManager>& cacheManager,
271 NodeId nodeId, const bool isForegroundFilter)
272 {
273 if (!RSSystemProperties::GetBlurEnabled()) {
274 ROSEN_LOGD("RSPropertyDrawableUtils::DrawFilter close blur.");
275 return;
276 }
277 if (rsFilter == nullptr) {
278 ROSEN_LOGE("RSPropertyDrawableUtils::DrawFilter null filter.");
279 return;
280 }
281 if (canvas == nullptr) {
282 ROSEN_LOGE("RSPropertyDrawableUtils::DrawFilter null canvas.");
283 return;
284 }
285
286 auto filter = std::static_pointer_cast<RSDrawingFilter>(rsFilter);
287 auto clipIBounds = canvas->GetRoundInDeviceClipBounds();
288 RS_OPTIONAL_TRACE_NAME("DrawFilter " + rsFilter->GetDescription());
289 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawFilter, filterType: %d, %s, bounds: %s",
290 isForegroundFilter, rsFilter->GetDetailedDescription().c_str(), clipIBounds.ToString().c_str());
291 ROSEN_LOGD("RSPropertyDrawableUtils::DrawFilter filterType: %{public}d, %{public}s, bounds: %{public}s",
292 isForegroundFilter, rsFilter->GetDetailedDescription().c_str(), clipIBounds.ToString().c_str());
293 g_blurCnt++;
294
295 auto surface = canvas->GetSurface();
296 if (surface == nullptr) {
297 ROSEN_LOGE("RSPropertyDrawableUtils::DrawFilter surface null");
298 Drawing::Brush brush = filter->GetBrush();
299 Drawing::SaveLayerOps slr(nullptr, &brush, Drawing::SaveLayerOps::Flags::INIT_WITH_PREVIOUS);
300 canvas->SaveLayer(slr);
301 filter->PostProcess(*canvas);
302 return;
303 }
304
305 auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
306 if (paintFilterCanvas == nullptr) {
307 return;
308 }
309 RSAutoCanvasRestore autoCanvasStore(paintFilterCanvas, isForegroundFilter ?
310 RSPaintFilterCanvas::SaveType::kAlpha : RSPaintFilterCanvas::SaveType::kNone);
311 if (isForegroundFilter) {
312 paintFilterCanvas->SetAlpha(1.0);
313 }
314 auto imageClipIBounds = clipIBounds;
315 auto magnifierShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::MAGNIFIER);
316 if (magnifierShaderFilter != nullptr) {
317 auto tmpFilter = std::static_pointer_cast<RSMagnifierShaderFilter>(magnifierShaderFilter);
318 auto canvasMatrix = canvas->GetTotalMatrix();
319 tmpFilter->SetMagnifierOffset(canvasMatrix);
320 imageClipIBounds.Offset(tmpFilter->GetMagnifierOffsetX(), tmpFilter->GetMagnifierOffsetY());
321 }
322
323 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
324 // Optional use cacheManager to draw filter
325 auto enableCache = (!paintFilterCanvas->GetDisableFilterCache() && cacheManager != nullptr &&
326 RSProperties::filterCacheEnabled_);
327 if (enableCache) {
328 if (cacheManager->GetCachedType() == FilterCacheType::FILTERED_SNAPSHOT) {
329 g_blurCnt--;
330 }
331
332 auto rsShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::LINEAR_GRADIENT_BLUR);
333 if (rsShaderFilter != nullptr) {
334 auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
335 tmpFilter->IsOffscreenCanvas(true);
336 }
337 cacheManager->DrawFilter(*paintFilterCanvas, filter, nodeId);
338 cacheManager->CompactFilterCache(); // flag for clear witch cache after drawing
339 return;
340 }
341 #endif
342
343 auto rsShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::LINEAR_GRADIENT_BLUR);
344 if (rsShaderFilter != nullptr) {
345 auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
346 tmpFilter->IsOffscreenCanvas(true);
347 }
348
349 if (imageClipIBounds.IsEmpty()) {
350 return;
351 }
352 auto imageSnapshot = surface->GetImageSnapshot(imageClipIBounds, false);
353 if (imageSnapshot == nullptr) {
354 ROSEN_LOGE("RSPropertyDrawableUtils::DrawFilter image null");
355 return;
356 }
357 if (RSSystemProperties::GetImageGpuResourceCacheEnable(imageSnapshot->GetWidth(), imageSnapshot->GetHeight())) {
358 ROSEN_LOGD("RSPropertyDrawableUtils::DrawFilter cache image resource(w:%{public}d, h:%{public}d).",
359 imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
360 imageSnapshot->HintCacheGpuResource();
361 }
362
363 filter->PreProcess(imageSnapshot);
364 Drawing::AutoCanvasRestore acr(*canvas, true);
365 canvas->ResetMatrix();
366 Drawing::Rect srcRect = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
367 Drawing::Rect dstRect = clipIBounds;
368 filter->DrawImageRect(*canvas, imageSnapshot, srcRect, dstRect);
369 filter->PostProcess(*canvas);
370 }
371
BeginForegroundFilter(RSPaintFilterCanvas & canvas,const RectF & bounds)372 void RSPropertyDrawableUtils::BeginForegroundFilter(RSPaintFilterCanvas& canvas, const RectF& bounds)
373 {
374 RS_OPTIONAL_TRACE_NAME("RSPropertyDrawableUtils::BeginForegroundFilter");
375 auto surface = canvas.GetSurface();
376 if (!surface) {
377 return;
378 }
379 std::shared_ptr<Drawing::Surface> offscreenSurface = surface->MakeSurface(bounds.width_, bounds.height_);
380 if (!offscreenSurface) {
381 return;
382 }
383 auto offscreenCanvas = std::make_shared<RSPaintFilterCanvas>(offscreenSurface.get());
384 canvas.StoreCanvas();
385 canvas.ReplaceMainScreenData(offscreenSurface, offscreenCanvas);
386 offscreenCanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
387 canvas.SavePCanvasList();
388 canvas.RemoveAll();
389 canvas.AddCanvas(offscreenCanvas.get());
390 }
391
DrawForegroundFilter(RSPaintFilterCanvas & canvas,const std::shared_ptr<RSFilter> & rsFilter)392 void RSPropertyDrawableUtils::DrawForegroundFilter(RSPaintFilterCanvas& canvas,
393 const std::shared_ptr<RSFilter>& rsFilter)
394 {
395 RS_OPTIONAL_TRACE_NAME("DrawForegroundFilter restore");
396 auto surface = canvas.GetSurface();
397 std::shared_ptr<Drawing::Image> imageSnapshot = nullptr;
398 if (surface) {
399 imageSnapshot = surface->GetImageSnapshot();
400 } else {
401 ROSEN_LOGD("RSPropertyDrawableUtils::DrawForegroundFilter Surface null");
402 }
403
404 canvas.RestorePCanvasList();
405 canvas.SwapBackMainScreenData();
406
407 if (rsFilter == nullptr) {
408 return;
409 }
410
411 if (imageSnapshot == nullptr) {
412 ROSEN_LOGD("RSPropertyDrawableUtils::DrawForegroundFilter image null");
413 return;
414 }
415
416 if (rsFilter->IsDrawingFilter()) {
417 auto rsDrawingFilter = std::static_pointer_cast<RSDrawingFilter>(rsFilter);
418 rsDrawingFilter->DrawImageRect(canvas, imageSnapshot, Drawing::Rect(0, 0, imageSnapshot->GetWidth(),
419 imageSnapshot->GetHeight()), Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight()));
420 return;
421 }
422
423 auto foregroundFilter = std::static_pointer_cast<RSDrawingFilterOriginal>(rsFilter);
424 if (foregroundFilter->GetFilterType() == RSFilter::MOTION_BLUR) {
425 if (canvas.GetDisableFilterCache()) {
426 foregroundFilter->DisableMotionBlur(true);
427 } else {
428 foregroundFilter->DisableMotionBlur(false);
429 }
430 }
431
432 foregroundFilter->DrawImageRect(canvas, imageSnapshot, Drawing::Rect(0, 0, imageSnapshot->GetWidth(),
433 imageSnapshot->GetHeight()), Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight()));
434 }
435
GetAndResetBlurCnt()436 int RSPropertyDrawableUtils::GetAndResetBlurCnt()
437 {
438 auto blurCnt = g_blurCnt.load();
439 g_blurCnt = 0;
440 return blurCnt;
441 }
442
DrawBackgroundEffect(RSPaintFilterCanvas * canvas,const std::shared_ptr<RSFilter> & rsFilter,const std::unique_ptr<RSFilterCacheManager> & cacheManager,Drawing::RectI & bounds,bool behindWindow)443 void RSPropertyDrawableUtils::DrawBackgroundEffect(
444 RSPaintFilterCanvas* canvas, const std::shared_ptr<RSFilter>& rsFilter,
445 const std::unique_ptr<RSFilterCacheManager>& cacheManager,
446 Drawing::RectI& bounds, bool behindWindow)
447 {
448 if (rsFilter == nullptr) {
449 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBackgroundEffect null filter");
450 return;
451 }
452 if (canvas == nullptr) {
453 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBackgroundEffect null canvas");
454 return;
455 }
456 auto surface = canvas->GetSurface();
457 if (surface == nullptr) {
458 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBackgroundEffect surface null");
459 return;
460 }
461 g_blurCnt++;
462 auto clipIBounds = bounds;
463 auto filter = std::static_pointer_cast<RSDrawingFilter>(rsFilter);
464 RS_OPTIONAL_TRACE_NAME("RSPropertyDrawableUtils::DrawBackgroundEffect " + rsFilter->GetDescription());
465 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "EffectComponent, %s, bounds: %s",
466 rsFilter->GetDetailedDescription().c_str(), clipIBounds.ToString().c_str());
467 ROSEN_LOGD("RSPropertyDrawableUtils::DrawBackgroundEffect EffectComponent, %{public}s, bounds: %{public}s",
468 rsFilter->GetDetailedDescription().c_str(), clipIBounds.ToString().c_str());
469 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
470 // Optional use cacheManager to draw filter
471 if (RSProperties::filterCacheEnabled_ && cacheManager != nullptr && !canvas->GetDisableFilterCache()) {
472 if (cacheManager->GetCachedType() == FilterCacheType::FILTERED_SNAPSHOT) {
473 g_blurCnt--;
474 }
475 auto&& data = cacheManager->GeneratedCachedEffectData(*canvas, filter, clipIBounds, clipIBounds);
476 cacheManager->CompactFilterCache(); // flag for clear witch cache after drawing
477 behindWindow ? canvas->SetBehindWindowData(data) : canvas->SetEffectData(data);
478 cacheManager->ClearEffectCacheWithDrawnRegion(*canvas, clipIBounds);
479 return;
480 }
481 #endif
482 auto imageRect = clipIBounds;
483 auto imageSnapshot = surface->GetImageSnapshot(imageRect);
484 if (imageSnapshot == nullptr) {
485 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBackgroundEffect image snapshot null");
486 return;
487 }
488 filter->PreProcess(imageSnapshot);
489 // create a offscreen skSurface
490 std::shared_ptr<Drawing::Surface> offscreenSurface =
491 surface->MakeSurface(imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
492 if (offscreenSurface == nullptr) {
493 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBackgroundEffect offscreenSurface null");
494 return;
495 }
496 RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
497 auto clipBounds = Drawing::Rect(0, 0, imageRect.GetWidth(), imageRect.GetHeight());
498 auto imageSnapshotBounds = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
499 filter->DrawImageRect(offscreenCanvas, imageSnapshot, imageSnapshotBounds, clipBounds);
500 filter->PostProcess(offscreenCanvas);
501
502 auto imageCache = offscreenSurface->GetImageSnapshot();
503 if (imageCache == nullptr) {
504 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBackgroundEffect imageCache snapshot null");
505 return;
506 }
507 auto data = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(imageCache), std::move(imageRect));
508 behindWindow ? canvas->SetBehindWindowData(std::move(data)) : canvas->SetEffectData(std::move(data));
509 }
510
DrawColorFilter(Drawing::Canvas * canvas,const std::shared_ptr<Drawing::ColorFilter> & colorFilter)511 void RSPropertyDrawableUtils::DrawColorFilter(
512 Drawing::Canvas* canvas, const std::shared_ptr<Drawing::ColorFilter>& colorFilter)
513 {
514 if (colorFilter == nullptr) {
515 ROSEN_LOGE("RSPropertyDrawableUtils::DrawColorFilter null colorFilter.");
516 return;
517 }
518
519 Drawing::Brush brush;
520 brush.SetAntiAlias(true);
521 Drawing::Filter filter;
522 filter.SetColorFilter(colorFilter);
523 brush.SetFilter(filter);
524 auto surface = canvas->GetSurface();
525 if (surface == nullptr) {
526 ROSEN_LOGE("RSPropertyDrawableUtils::DrawColorFilter surface is null");
527 return;
528 }
529 auto clipBounds = canvas->GetLocalClipBounds();
530 Drawing::AutoCanvasRestore acr(*canvas, false);
531 Drawing::SaveLayerOps slo(&clipBounds, &brush, Drawing::SaveLayerOps::Flags::INIT_WITH_PREVIOUS);
532 canvas->SaveLayer(slo);
533 }
534
DrawLightUpEffect(Drawing::Canvas * canvas,const float lightUpEffectDegree)535 void RSPropertyDrawableUtils::DrawLightUpEffect(Drawing::Canvas* canvas, const float lightUpEffectDegree)
536 {
537 if (!ROSEN_GE(lightUpEffectDegree, 0.0) || !ROSEN_LNE(lightUpEffectDegree, 1.0)) {
538 ROSEN_LOGE(
539 "RSPropertyDrawableUtils::DrawLightUpEffect Invalid lightUpEffectDegree %{public}f", lightUpEffectDegree);
540 return;
541 }
542
543 Drawing::Surface* surface = canvas->GetSurface();
544 if (surface == nullptr) {
545 ROSEN_LOGE("RSPropertyDrawableUtils::DrawLightUpEffect surface is null");
546 return;
547 }
548
549 auto clipBounds = canvas->GetDeviceClipBounds();
550 auto image = surface->GetImageSnapshot(clipBounds, false);
551 if (image == nullptr) {
552 ROSEN_LOGE("RSPropertyDrawableUtils::DrawLightUpEffect image is null");
553 return;
554 }
555 Drawing::Matrix scaleMat;
556 auto imageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
557 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), scaleMat);
558 auto shader = MakeLightUpShader(lightUpEffectDegree, imageShader);
559 if (shader == nullptr) {
560 ROSEN_LOGE("RSPropertyDrawableUtils::MakeLightUpShader shader is null");
561 return;
562 }
563 Drawing::Brush brush;
564 brush.SetShaderEffect(shader);
565 Drawing::AutoCanvasRestore acr(*canvas, true);
566 canvas->ResetMatrix();
567 canvas->Translate(clipBounds.GetLeft(), clipBounds.GetTop());
568 canvas->DrawBackground(brush);
569 }
570
MakeLightUpShader(float lightUpDeg,std::shared_ptr<Drawing::ShaderEffect> imageShader)571 std::shared_ptr<Drawing::ShaderEffect> RSPropertyDrawableUtils::MakeLightUpShader(
572 float lightUpDeg, std::shared_ptr<Drawing::ShaderEffect> imageShader)
573 {
574 static constexpr char prog[] = R"(
575 uniform float lightUpDeg;
576 uniform shader imageShader;
577 vec3 rgb2hsv(in vec3 c)
578 {
579 vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
580 vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
581 vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
582 float d = q.x - min(q.w, q.y);
583 float e = 1.0e-10;
584 return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
585 }
586 vec3 hsv2rgb(in vec3 c)
587 {
588 vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
589 return c.z * mix(vec3(1.0), rgb, c.y);
590 }
591 half4 main(float2 coord)
592 {
593 vec4 color = imageShader.eval(coord);
594 float a = color.a;
595 vec3 rgb = max(color.rgb, 0.0);
596 vec3 hsv = rgb2hsv(rgb);
597 float satUpper = clamp(hsv.y * 1.2, 0.0, 1.0);
598 hsv.y = mix(satUpper, hsv.y, lightUpDeg);
599 hsv.z += lightUpDeg - 1.0;
600 hsv.z = max(hsv.z, 0.0);
601 return vec4(hsv2rgb(hsv), a);
602 }
603 )";
604 if (lightUpShaderEffect_ == nullptr) {
605 lightUpShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
606 if (lightUpShaderEffect_ == nullptr) {
607 ROSEN_LOGE("MakeLightUpShader::RuntimeShader effect error\n");
608 return nullptr;
609 }
610 }
611 std::shared_ptr<Drawing::ShaderEffect> children[] = {imageShader};
612 size_t childCount = 1;
613 auto data = std::make_shared<Drawing::Data>();
614 data->BuildWithCopy(&lightUpDeg, sizeof(lightUpDeg));
615 return lightUpShaderEffect_->MakeShader(data, children, childCount, nullptr, false);
616 }
617
DrawDynamicDim(Drawing::Canvas * canvas,const float dynamicDimDegree)618 void RSPropertyDrawableUtils::DrawDynamicDim(Drawing::Canvas* canvas, const float dynamicDimDegree)
619 {
620 if (!ROSEN_GE(dynamicDimDegree, 0.0) || !ROSEN_LNE(dynamicDimDegree, 1.0)) {
621 ROSEN_LOGE(
622 "RSPropertyDrawableUtils::DrawDynamicDim Invalid dynamicDimDegree %{public}f", dynamicDimDegree);
623 return;
624 }
625
626 Drawing::Surface* surface = canvas->GetSurface();
627 if (surface == nullptr) {
628 ROSEN_LOGE("RSPropertyDrawableUtils::DrawDynamicDim surface is null");
629 return;
630 }
631
632 auto clipBounds = canvas->GetDeviceClipBounds();
633 auto image = surface->GetImageSnapshot(clipBounds, false);
634 if (image == nullptr) {
635 ROSEN_LOGE("RSPropertyDrawableUtils::DrawDynamicDim image is null");
636 return;
637 }
638
639 Drawing::Matrix scaleMat;
640 auto imageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
641 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), scaleMat);
642 auto shader = MakeDynamicDimShader(dynamicDimDegree, imageShader);
643 if (shader == nullptr) {
644 ROSEN_LOGE("RSPropertyDrawableUtils::DrawDynamicDim shader is null");
645 return;
646 }
647 Drawing::Brush brush;
648 brush.SetShaderEffect(shader);
649 Drawing::AutoCanvasRestore acr(*canvas, true);
650 canvas->ResetMatrix();
651 canvas->Translate(clipBounds.GetLeft(), clipBounds.GetTop());
652 canvas->DrawBackground(brush);
653 }
654
MakeDynamicDimShader(float dynamicDimDeg,std::shared_ptr<Drawing::ShaderEffect> imageShader)655 std::shared_ptr<Drawing::ShaderEffect> RSPropertyDrawableUtils::MakeDynamicDimShader(
656 float dynamicDimDeg, std::shared_ptr<Drawing::ShaderEffect> imageShader)
657 {
658 static constexpr char prog[] = R"(
659 uniform half dynamicDimDeg;
660 uniform shader imageShader;
661
662 vec3 rgb2hsv(in vec3 c)
663 {
664 vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
665 vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
666 vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
667 float d = q.x - min(q.w, q.y);
668 float e = 1.0e-10;
669 return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
670 }
671 vec3 hsv2rgb(in vec3 c)
672 {
673 vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
674 return c.z * mix(vec3(1.0), rgb, c.y);
675 }
676 half4 main(float2 coord)
677 {
678 vec3 hsv = rgb2hsv(imageShader.eval(coord).rgb);
679 float value = max(0.8, dynamicDimDeg); // 0.8 is min saturation ratio.
680 hsv.y = hsv.y * (1.75 - value * 0.75); // saturation value [1.0 , 1.15].
681 hsv.z = min(hsv.z * dynamicDimDeg, 1.0);
682 return vec4(hsv2rgb(hsv), 1.0);
683 }
684 )";
685 if (dynamicDimShaderEffect_ == nullptr) {
686 dynamicDimShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
687 if (dynamicDimShaderEffect_ == nullptr) {
688 ROSEN_LOGE("MakeDynamicDimShader::RuntimeShader effect error\n");
689 return nullptr;
690 }
691 }
692 std::shared_ptr<Drawing::ShaderEffect> children[] = {imageShader};
693 size_t childCount = 1;
694 auto data = std::make_shared<Drawing::Data>();
695 data->BuildWithCopy(&dynamicDimDeg, sizeof(dynamicDimDeg));
696 return dynamicDimShaderEffect_->MakeShader(data, children, childCount, nullptr, false);
697 }
698
MakeBinarizationShader(float low,float high,float thresholdLow,float thresholdHigh,std::shared_ptr<Drawing::ShaderEffect> imageShader)699 std::shared_ptr<Drawing::ShaderEffect> RSPropertyDrawableUtils::MakeBinarizationShader(
700 float low, float high, float thresholdLow, float thresholdHigh, std::shared_ptr<Drawing::ShaderEffect> imageShader)
701 {
702 static constexpr char prog[] = R"(
703 uniform mediump float ubo_low;
704 uniform mediump float ubo_high;
705 uniform mediump float ubo_thresholdLow;
706 uniform mediump float ubo_thresholdHigh;
707 uniform shader imageShader;
708 mediump vec4 main(vec2 drawing_coord) {
709 mediump vec3 c = imageShader(drawing_coord).rgb;
710 float gray = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
711 float lowRes = mix(ubo_high, -1.0, step(ubo_thresholdLow, gray));
712 float highRes = mix(-1.0, ubo_low, step(ubo_thresholdHigh, gray));
713 float midRes = (ubo_thresholdHigh - gray) * (ubo_high - ubo_low) /
714 (ubo_thresholdHigh - ubo_thresholdLow) + ubo_low;
715 float invertedGray = mix(midRes, max(lowRes, highRes), step(-0.5, max(lowRes, highRes)));
716 mediump vec3 invert = vec3(invertedGray);
717 mediump vec4 res = vec4(invert, 1.0);
718 return res;
719 }
720 )";
721 if (binarizationShaderEffect_ == nullptr) {
722 binarizationShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
723 if (binarizationShaderEffect_ == nullptr) {
724 ROSEN_LOGE("RSPropertyDrawableUtils::MakeBinarizationShader effect error\n");
725 return nullptr;
726 }
727 }
728 std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
729 std::make_shared<Drawing::RuntimeShaderBuilder>(binarizationShaderEffect_);
730 thresholdHigh = thresholdHigh <= thresholdLow ? thresholdHigh + 1e-6 : thresholdHigh;
731 builder->SetChild("imageShader", imageShader);
732 builder->SetUniform("ubo_low", low);
733 builder->SetUniform("ubo_high", high);
734 builder->SetUniform("ubo_thresholdLow", thresholdLow);
735 builder->SetUniform("ubo_thresholdHigh", thresholdHigh);
736 return builder->MakeShader(nullptr, false);
737 }
738
MakeDynamicBrightnessBlender(const RSDynamicBrightnessPara & params)739 std::shared_ptr<Drawing::Blender> RSPropertyDrawableUtils::MakeDynamicBrightnessBlender(
740 const RSDynamicBrightnessPara& params)
741 {
742 if (!RSSystemProperties::GetDynamicBrightnessEnabled()) {
743 return nullptr;
744 }
745
746 std::shared_ptr<Drawing::RuntimeBlenderBuilder> builder;
747 if (ROSEN_EQ(params.rates_.x_, 0.f) && ROSEN_EQ(params.rates_.y_, 0.f) && ROSEN_EQ(params.fraction_, 0.f)) {
748 builder = MakeDynamicBrightnessLinearBuilder();
749 ROSEN_LOGD("RSPropertyDrawableUtils::MakeDynamicBrightnessBlender equivalent blender in the linear case");
750 if (!builder) {
751 ROSEN_LOGE("RSPropertyDrawableUtils::MakeDynamicBrightnessBlender make linear builder fail");
752 return nullptr;
753 }
754 // pre-process for pos and neg params
755 float minusSat = 1.f - params.saturation_;
756 bool swap = ROSEN_LE(minusSat, 0.f);
757 const auto& posCoeffTmp = swap ? params.negCoeff_ : params.posCoeff_;
758 const auto& negCoeffTmp = swap ? params.posCoeff_ : params.negCoeff_;
759 builder->SetUniform("ubo_posr", posCoeffTmp.x_ * minusSat);
760 builder->SetUniform("ubo_posg", posCoeffTmp.y_ * minusSat);
761 builder->SetUniform("ubo_posb", posCoeffTmp.z_ * minusSat);
762 builder->SetUniform("ubo_negr", negCoeffTmp.x_ * minusSat);
763 builder->SetUniform("ubo_negg", negCoeffTmp.y_ * minusSat);
764 builder->SetUniform("ubo_negb", negCoeffTmp.z_ * minusSat);
765 } else {
766 builder = MakeDynamicBrightnessBuilder();
767 if (!builder) {
768 ROSEN_LOGE("RSPropertyDrawableUtils::MakeDynamicBrightnessBlender make builder fail");
769 return nullptr;
770 }
771 builder->SetUniform("ubo_fract", std::clamp(params.fraction_, 0.0f, 1.0f));
772 builder->SetUniform("ubo_cubic", params.rates_.x_);
773 builder->SetUniform("ubo_quad", params.rates_.y_);
774 builder->SetUniform("ubo_baseSat", params.saturation_);
775 builder->SetUniform("ubo_posr", params.posCoeff_.x_);
776 builder->SetUniform("ubo_posg", params.posCoeff_.y_);
777 builder->SetUniform("ubo_posb", params.posCoeff_.z_);
778 builder->SetUniform("ubo_negr", params.negCoeff_.x_);
779 builder->SetUniform("ubo_negg", params.negCoeff_.y_);
780 builder->SetUniform("ubo_negb", params.negCoeff_.z_);
781 }
782
783 RS_OPTIONAL_TRACE_NAME("RSPropertyDrawableUtils::MakeDynamicBrightnessBlender");
784 builder->SetUniform("ubo_rate", params.rates_.z_);
785 builder->SetUniform("ubo_degree", params.rates_.w_);
786 builder->SetUniform("ubo_headroom", params.enableHdr_ ? EFFECT_MAX_LUMINANCE : 1.0f);
787 return builder->MakeBlender();
788 }
789
MakeDynamicBrightnessLinearBuilder()790 std::shared_ptr<Drawing::RuntimeBlenderBuilder> RSPropertyDrawableUtils::MakeDynamicBrightnessLinearBuilder()
791 {
792 RS_OPTIONAL_TRACE_NAME("RSPropertyDrawableUtils::MakeDynamicBrightnessLinearBuilder");
793 static constexpr char prog[] = R"(
794 uniform half ubo_rate;
795 uniform half ubo_degree;
796 uniform half ubo_posr;
797 uniform half ubo_posg;
798 uniform half ubo_posb;
799 uniform half ubo_negr;
800 uniform half ubo_negg;
801 uniform half ubo_negb;
802 uniform half ubo_headroom;
803
804 const half3 baseVec = half3(0.2412016, 0.6922296, 0.0665688);
805 half3 sat(half3 inColor, half3 pos, half3 neg) {
806 half3 delta = dot(inColor, baseVec) - inColor;
807 half3 v = mix(neg, pos, step(0, delta));
808 return clamp(inColor + delta * v, half3(0.0), half3(ubo_headroom));
809 }
810
811 half4 main(half4 src, half4 dst) {
812 half2 coeff = half2(ubo_rate, ubo_degree);
813 half3 color = coeff.x * dst.rgb + coeff.y * dst.a;
814 half3 pos = half3(ubo_posr, ubo_posg, ubo_posb);
815 half3 neg = half3(ubo_negr, ubo_negg, ubo_negb);
816 color = sat(color, pos, neg);
817 return half4(mix(dst.rgb, color, src.a), dst.a);
818 }
819 )";
820 if (dynamicBrightnessLinearBlenderEffect_ == nullptr) {
821 dynamicBrightnessLinearBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
822 if (dynamicBrightnessLinearBlenderEffect_ == nullptr) { return nullptr; }
823 }
824 return std::make_shared<Drawing::RuntimeBlenderBuilder>(dynamicBrightnessLinearBlenderEffect_);
825 }
826
MakeDynamicBrightnessBuilder()827 std::shared_ptr<Drawing::RuntimeBlenderBuilder> RSPropertyDrawableUtils::MakeDynamicBrightnessBuilder()
828 {
829 RS_OPTIONAL_TRACE_NAME("RSPropertyDrawableUtils::MakeDynamicBrightnessBuilder");
830 static constexpr char prog[] = R"(
831 uniform half ubo_fract;
832 uniform half ubo_rate;
833 uniform half ubo_degree;
834 uniform half ubo_cubic;
835 uniform half ubo_quad;
836 uniform half ubo_baseSat;
837 uniform half ubo_posr;
838 uniform half ubo_posg;
839 uniform half ubo_posb;
840 uniform half ubo_negr;
841 uniform half ubo_negg;
842 uniform half ubo_negb;
843 uniform half ubo_headroom;
844
845 const vec3 baseVec = vec3(0.2412016, 0.6922296, 0.0665688);
846 const half eps = 1e-5;
847 half3 getUnpremulRGB(half4 color) {
848 half factor = 1.0 / (max(color.a, eps));
849 return saturate(color.rgb * factor);
850 }
851 half3 gray(half3 x, half4 coeff) {
852 return coeff.x * x * x * x + coeff.y * x * x + coeff.z * x + coeff.w;
853 }
854 half3 sat(half3 inColor, half n, half3 pos, half3 neg) {
855 half3 r = (1.0 - n) * inColor;
856 half base = dot(r, baseVec);
857 half3 delta = base - r;
858 half3 v = mix(neg, pos, step(0, delta));
859 return clamp(inColor + delta * v, half3(0.0), half3(ubo_headroom));
860 }
861
862 half4 main(half4 src, half4 dst) {
863 half4 coeff = half4(ubo_cubic, ubo_quad, ubo_rate, ubo_degree);
864 half3 color = gray(getUnpremulRGB(dst), coeff);
865 half3 pos = half3(ubo_posr, ubo_posg, ubo_posb);
866 half3 neg = half3(ubo_negr, ubo_negg, ubo_negb);
867 color = sat(color, ubo_baseSat, pos, neg);
868 color = mix(color, getUnpremulRGB(src), ubo_fract);
869 return half4(mix(dst.rgb, color * dst.a, src.a), dst.a);
870 }
871 )";
872 if (dynamicBrightnessBlenderEffect_ == nullptr) {
873 dynamicBrightnessBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
874 if (dynamicBrightnessBlenderEffect_ == nullptr) { return nullptr; }
875 }
876 return std::make_shared<Drawing::RuntimeBlenderBuilder>(dynamicBrightnessBlenderEffect_);
877 }
878
MakeShadowBlender(const RSShadowBlenderPara & params)879 std::shared_ptr<Drawing::Blender> RSPropertyDrawableUtils::MakeShadowBlender(const RSShadowBlenderPara& params)
880 {
881 static constexpr char prog[] = R"(
882 uniform half ubo_cubic;
883 uniform half ubo_quadratic;
884 uniform half ubo_linear;
885 uniform half ubo_constant;
886
887 float4 main(float4 src, float4 dst) {
888 float lum = dot(unpremul(dst).rgb, float3(0.2126, 0.7152, 0.0722));
889 float opacity = saturate(ubo_cubic * lum * lum * lum +
890 ubo_quadratic * lum * lum + ubo_linear * lum + ubo_constant);
891 half4 srcNew = src * opacity;
892 return mix(dst, vec4(srcNew.rgb, 1.0), src.a);
893 }
894 )";
895 if (shadowBlenderEffect_ == nullptr) {
896 shadowBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
897 }
898 std::shared_ptr<Drawing::RuntimeBlenderBuilder> builder =
899 std::make_shared<Drawing::RuntimeBlenderBuilder>(shadowBlenderEffect_);
900 if (!builder) {
901 ROSEN_LOGE("RSPropertyDrawableUtils::MakeShadowBlender make builder fail");
902 return nullptr;
903 }
904 builder->SetUniform("ubo_cubic", params.cubic_);
905 builder->SetUniform("ubo_quadratic", params.quadratic_);
906 builder->SetUniform("ubo_linear", params.linear_);
907 builder->SetUniform("ubo_constant", params.constant_);
908 RS_OPTIONAL_TRACE_FMT("RSPropertyDrawableUtils::MakeShadowBlender params[%f,%f,%f,%f]",
909 params.cubic_, params.quadratic_, params.linear_, params.constant_);
910 return builder->MakeBlender();
911 }
912
DrawBinarization(Drawing::Canvas * canvas,const std::optional<Vector4f> & aiInvert)913 void RSPropertyDrawableUtils::DrawBinarization(Drawing::Canvas* canvas, const std::optional<Vector4f>& aiInvert)
914 {
915 if (!aiInvert.has_value()) {
916 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBinarization aiInvert has no value");
917 return;
918 }
919 auto drSurface = canvas->GetSurface();
920 if (drSurface == nullptr) {
921 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBinarization drSurface is null");
922 return;
923 }
924 auto clipBounds = canvas->GetDeviceClipBounds();
925 auto imageSnapshot = drSurface->GetImageSnapshot(clipBounds);
926 if (imageSnapshot == nullptr) {
927 ROSEN_LOGE("RSPropertyDrawableUtils::DrawBinarization image is null");
928 return;
929 }
930 Drawing::Matrix matrix;
931 auto imageShader = Drawing::ShaderEffect::CreateImageShader(*imageSnapshot, Drawing::TileMode::CLAMP,
932 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
933 float thresholdLow = aiInvert->z_ - aiInvert->w_;
934 float thresholdHigh = aiInvert->z_ + aiInvert->w_;
935 auto shader = MakeBinarizationShader(aiInvert->x_, aiInvert->y_, thresholdLow, thresholdHigh, imageShader);
936 Drawing::Brush brush;
937 brush.SetShaderEffect(shader);
938 brush.SetAntiAlias(true);
939 Drawing::AutoCanvasRestore acr(*canvas, true);
940 canvas->ResetMatrix();
941 canvas->Translate(clipBounds.GetLeft(), clipBounds.GetTop());
942 canvas->DrawBackground(brush);
943 }
944
DrawPixelStretch(Drawing::Canvas * canvas,const std::optional<Vector4f> & pixelStretch,const RectF & boundsRect,const bool boundsGeoValid,const Drawing::TileMode pixelStretchTileMode)945 void RSPropertyDrawableUtils::DrawPixelStretch(Drawing::Canvas* canvas,
946 const std::optional<Vector4f>& pixelStretch, const RectF& boundsRect,
947 const bool boundsGeoValid, const Drawing::TileMode pixelStretchTileMode)
948 {
949 if (!pixelStretch.has_value()) {
950 ROSEN_LOGD("RSPropertyDrawableUtils::DrawPixelStretch pixelStretch has no value");
951 return;
952 }
953 if (std::isinf(pixelStretch->x_) || std::isinf(pixelStretch->y_) ||
954 std::isinf(pixelStretch->z_) || std::isinf(pixelStretch->w_)) {
955 ROSEN_LOGD("RSPropertyDrawableUtils::DrawPixelStretch skip original pixelStretch");
956 return;
957 }
958 auto surface = canvas->GetSurface();
959 if (surface == nullptr) {
960 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch surface null");
961 return;
962 }
963
964 /* Calculates the relative coordinates of the clipbounds
965 with respect to the origin of the current canvas coordinates */
966 Drawing::Matrix worldToLocalMat;
967 if (!canvas->GetTotalMatrix().Invert(worldToLocalMat)) {
968 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch get invert matrix failed.");
969 return;
970 }
971 Drawing::Rect localClipBounds;
972 canvas->Save();
973 canvas->ClipRect(Rect2DrawingRect(boundsRect), Drawing::ClipOp::INTERSECT, false);
974 auto tmpBounds = canvas->GetDeviceClipBounds();
975 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO,
976 "RSPropertyDrawableUtils::DrawPixelStretch, tmpBounds: %s", tmpBounds.ToString().c_str());
977 canvas->Restore();
978 Drawing::Rect clipBounds(
979 tmpBounds.GetLeft(), tmpBounds.GetTop(), tmpBounds.GetRight() - 1, tmpBounds.GetBottom() - 1);
980 Drawing::Rect fClipBounds(clipBounds.GetLeft(), clipBounds.GetTop(), clipBounds.GetRight(), clipBounds.GetBottom());
981
982 if (!worldToLocalMat.MapRect(localClipBounds, fClipBounds)) {
983 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch map rect failed.");
984 return;
985 }
986 auto bounds = Rect2DrawingRect(boundsRect);
987 if (!bounds.Intersect(localClipBounds)) {
988 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch intersect clipbounds failed");
989 return;
990 }
991
992 auto scaledBounds = Drawing::Rect(bounds.GetLeft() - pixelStretch->x_, bounds.GetTop() - pixelStretch->y_,
993 bounds.GetRight() + pixelStretch->z_, bounds.GetBottom() + pixelStretch->w_);
994 if (!scaledBounds.IsValid() || !bounds.IsValid() || !clipBounds.IsValid()) {
995 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch invalid scaled bounds");
996 return;
997 }
998
999 Drawing::RectI rectI(static_cast<int>(fClipBounds.GetLeft()), static_cast<int>(fClipBounds.GetTop()),
1000 static_cast<int>(fClipBounds.GetRight()), static_cast<int>(fClipBounds.GetBottom()));
1001 auto image = surface->GetImageSnapshot(rectI);
1002 if (image == nullptr) {
1003 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch image null");
1004 return;
1005 }
1006
1007 Drawing::Brush brush;
1008 Drawing::Matrix inverseMat;
1009 Drawing::Matrix rotateMat;
1010 if (boundsGeoValid) {
1011 auto transMat = canvas->GetTotalMatrix();
1012 /* transMat.getSkewY() is the sin of the rotation angle(sin0 = 0,sin90 =1 sin180 = 0,sin270 = -1),
1013 if transMat.getSkewY() is not 0 or -1 or 1,the rotation angle is not a multiple of 90,not Stretch*/
1014 auto skewY = transMat.Get(Drawing::Matrix::SKEW_Y);
1015 if (ROSEN_EQ(skewY, 0.f) || ROSEN_EQ(skewY, 1.f) || ROSEN_EQ(skewY, -1.f)) {
1016 } else {
1017 ROSEN_LOGD("rotate degree is not 0 or 90 or 180 or 270,return.");
1018 return;
1019 }
1020 rotateMat.SetScale(transMat.Get(Drawing::Matrix::SCALE_X), transMat.Get(Drawing::Matrix::SCALE_Y));
1021 rotateMat.Set(Drawing::Matrix::SKEW_X, transMat.Get(Drawing::Matrix::SKEW_X));
1022 rotateMat.Set(Drawing::Matrix::SKEW_Y, transMat.Get(Drawing::Matrix::SKEW_Y));
1023 rotateMat.PreTranslate(-bounds.GetLeft(), -bounds.GetTop());
1024 rotateMat.PostTranslate(bounds.GetLeft(), bounds.GetTop());
1025
1026 Drawing::Rect transBounds;
1027 rotateMat.MapRect(transBounds, bounds);
1028 rotateMat.Set(Drawing::Matrix::TRANS_X, bounds.GetLeft() - transBounds.GetLeft());
1029 rotateMat.Set(Drawing::Matrix::TRANS_Y, bounds.GetTop() - transBounds.GetTop());
1030 if (!rotateMat.Invert(inverseMat)) {
1031 ROSEN_LOGE("RSPropertyDrawableUtils::DrawPixelStretch get invert matrix failed.");
1032 }
1033 }
1034
1035 Drawing::AutoCanvasRestore acr(*canvas, true);
1036 canvas->Translate(bounds.GetLeft(), bounds.GetTop());
1037 Drawing::SamplingOptions samplingOptions;
1038 constexpr static float EPS = 1e-5f;
1039 if (pixelStretch->x_ > EPS || pixelStretch->y_ > EPS || pixelStretch->z_ > EPS || pixelStretch->w_ > EPS) {
1040 brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1041 *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1042 canvas->AttachBrush(brush);
1043 canvas->DrawRect(Drawing::Rect(-pixelStretch->x_, -pixelStretch->y_,
1044 -pixelStretch->x_ + scaledBounds.GetWidth(), -pixelStretch->y_ + scaledBounds.GetHeight()));
1045 canvas->DetachBrush();
1046 } else {
1047 inverseMat.PostScale(
1048 scaledBounds.GetWidth() / bounds.GetWidth(), scaledBounds.GetHeight() / bounds.GetHeight());
1049 brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1050 *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1051
1052 canvas->Translate(-pixelStretch->x_, -pixelStretch->y_);
1053 canvas->AttachBrush(brush);
1054 canvas->DrawRect(Drawing::Rect(pixelStretch->x_, pixelStretch->y_, pixelStretch->x_ + bounds.GetWidth(),
1055 pixelStretch->y_ + bounds.GetHeight()));
1056 canvas->DetachBrush();
1057 }
1058 }
1059
CreateShadowPath(const std::shared_ptr<RSPath> rsPath,const std::shared_ptr<RSPath> & clipBounds,const RRect & rrect)1060 Drawing::Path RSPropertyDrawableUtils::CreateShadowPath(const std::shared_ptr<RSPath> rsPath,
1061 const std::shared_ptr<RSPath>& clipBounds, const RRect& rrect)
1062 {
1063 Drawing::Path path;
1064 if (rsPath && rsPath->GetDrawingPath().IsValid()) {
1065 path = rsPath->GetDrawingPath();
1066 } else if (clipBounds) {
1067 path = clipBounds->GetDrawingPath();
1068 } else {
1069 path.AddRoundRect(RRect2DrawingRRect(rrect));
1070 }
1071 return path;
1072 }
1073
DrawShadow(Drawing::Canvas * canvas,Drawing::Path & path,const float & offsetX,const float & offsetY,const float & elevation,const bool & isFilled,Color spotColor)1074 void RSPropertyDrawableUtils::DrawShadow(Drawing::Canvas* canvas, Drawing::Path& path, const float& offsetX,
1075 const float& offsetY, const float& elevation, const bool& isFilled, Color spotColor)
1076 {
1077 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO,
1078 "RSPropertyDrawableUtils::DrawShadow, ShadowElevation: %f, ShadowOffsetX: "
1079 "%f, ShadowOffsetY: %f, bounds: %s",
1080 elevation, offsetX, offsetY, path.GetBounds().ToString().c_str());
1081 Drawing::AutoCanvasRestore acr(*canvas, true);
1082 if (!isFilled) {
1083 canvas->ClipPath(path, Drawing::ClipOp::DIFFERENCE, true);
1084 }
1085 path.Offset(offsetX, offsetY);
1086 Drawing::Point3 planeParams = {0.0f, 0.0f, elevation};
1087 std::vector<Drawing::Point> pt{{path.GetBounds().GetLeft() + path.GetBounds().GetWidth() / 2,
1088 path.GetBounds().GetTop() + path.GetBounds().GetHeight() / 2}};
1089 canvas->GetTotalMatrix().MapPoints(pt, pt, 1);
1090 Drawing::Point3 lightPos = {pt[0].GetX(), pt[0].GetY(), DEFAULT_LIGHT_HEIGHT};
1091 Color ambientColor = Color::FromArgbInt(DEFAULT_AMBIENT_COLOR);
1092 ambientColor.MultiplyAlpha(canvas->GetAlpha());
1093 spotColor.MultiplyAlpha(canvas->GetAlpha());
1094 canvas->DrawShadowStyle(path, planeParams, lightPos, DEFAULT_LIGHT_RADIUS, Drawing::Color(ambientColor.AsArgbInt()),
1095 Drawing::Color(spotColor.AsArgbInt()), Drawing::ShadowFlags::TRANSPARENT_OCCLUDER, true);
1096 }
1097
DrawShadowMaskFilter(Drawing::Canvas * canvas,Drawing::Path & path,const float & offsetX,const float & offsetY,const float & radius,const bool & isFilled,Color spotColor)1098 void RSPropertyDrawableUtils::DrawShadowMaskFilter(Drawing::Canvas* canvas, Drawing::Path& path, const float& offsetX,
1099 const float& offsetY, const float& radius, const bool& isFilled, Color spotColor)
1100 {
1101 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO,
1102 "RSPropertyDrawableUtils::DrawShadowMaskFilter, Radius: %f, ShadowOffsetX: "
1103 "%f, ShadowOffsetY: %f, bounds: %s",
1104 radius, offsetX, offsetY, path.GetBounds().ToString().c_str());
1105 Drawing::AutoCanvasRestore acr(*canvas, true);
1106 if (!isFilled) {
1107 canvas->ClipPath(path, Drawing::ClipOp::DIFFERENCE, true);
1108 }
1109 path.Offset(offsetX, offsetY);
1110 Drawing::Brush brush;
1111 brush.SetColor(Drawing::Color::ColorQuadSetARGB(
1112 spotColor.GetAlpha(), spotColor.GetRed(), spotColor.GetGreen(), spotColor.GetBlue()));
1113 brush.SetAntiAlias(true);
1114 Drawing::Filter filter;
1115 filter.SetMaskFilter(
1116 Drawing::MaskFilter::CreateBlurMaskFilter(Drawing::BlurType::NORMAL, radius));
1117 brush.SetFilter(filter);
1118 canvas->AttachBrush(brush);
1119 auto stencilVal = canvas->GetStencilVal();
1120 if (stencilVal > 0) {
1121 --stencilVal; // shadow positioned under app window
1122 }
1123 if (stencilVal > Drawing::Canvas::INVALID_STENCIL_VAL && stencilVal < canvas->GetMaxStencilVal()) {
1124 RS_OPTIONAL_TRACE_NAME_FMT("DrawPathWithStencil, stencilVal: %" PRId64 "", stencilVal);
1125 canvas->DrawPathWithStencil(path, static_cast<uint32_t>(stencilVal));
1126 } else {
1127 canvas->DrawPath(path);
1128 }
1129 canvas->DetachBrush();
1130 }
1131
DrawUseEffect(RSPaintFilterCanvas * canvas,UseEffectType useEffectType)1132 void RSPropertyDrawableUtils::DrawUseEffect(RSPaintFilterCanvas* canvas, UseEffectType useEffectType)
1133 {
1134 const auto& effectData = useEffectType == UseEffectType::EFFECT_COMPONENT ?
1135 canvas->GetEffectData() : canvas->GetBehindWindowData();
1136 if (effectData == nullptr || effectData->cachedImage_ == nullptr ||
1137 !(RSSystemProperties::GetEffectMergeEnabled() && RSFilterCacheManager::isCCMEffectMergeEnable_)) {
1138 return;
1139 }
1140 RS_TRACE_FUNC();
1141 Drawing::AutoCanvasRestore acr(*canvas, true);
1142 // Align the current coordinate system with the one that the effect data was generated from. In most cases,
1143 // the two coordinate systems are the same, so the cachedMatrix_ should be set to identity.
1144 canvas->SetMatrix(effectData->cachedMatrix_);
1145 auto visibleRect = canvas->GetVisibleRect();
1146 visibleRect.Round();
1147 auto visibleIRect = Drawing::RectI(
1148 static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
1149 static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
1150 if (!visibleIRect.IsEmpty()) {
1151 canvas->ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
1152 }
1153 Drawing::Brush brush;
1154 canvas->AttachBrush(brush);
1155 // Draw the cached image in the coordinate system where the effect data is generated. The image content
1156 // outside the device clip bounds will be automatically clipped.
1157 canvas->DrawImage(*effectData->cachedImage_, static_cast<float>(effectData->cachedRect_.GetLeft()),
1158 static_cast<float>(effectData->cachedRect_.GetTop()), Drawing::SamplingOptions());
1159 RS_OPTIONAL_TRACE_NAME_FMT("RSPropertyDrawableUtils::DrawUseEffect cachedRect_:%s, DeviceClipBounds:%s, "
1160 "IdentityMatrix: %d", effectData->cachedRect_.ToString().c_str(),
1161 canvas->GetDeviceClipBounds().ToString().c_str(), effectData->cachedMatrix_.IsIdentity());
1162 ROSEN_LOGD("RSPropertyDrawableUtils::DrawUseEffect cachedRect_:%{public}s, DeviceClipBounds:%{public}s, "
1163 "IdentityMatrix: %{public}d", effectData->cachedRect_.ToString().c_str(),
1164 canvas->GetDeviceClipBounds().ToString().c_str(), effectData->cachedMatrix_.IsIdentity());
1165 canvas->DetachBrush();
1166 }
1167
IsDangerousBlendMode(int blendMode,int blendApplyType)1168 bool RSPropertyDrawableUtils::IsDangerousBlendMode(int blendMode, int blendApplyType)
1169 {
1170 static const uint32_t fastDangerousBit =
1171 (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1172 (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1173 (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1174 (1 << static_cast<int>(Drawing::BlendMode::XOR));
1175 static const uint32_t offscreenDangerousBit =
1176 (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1177 (1 << static_cast<int>(Drawing::BlendMode::SRC)) +
1178 (1 << static_cast<int>(Drawing::BlendMode::SRC_IN)) +
1179 (1 << static_cast<int>(Drawing::BlendMode::DST_IN)) +
1180 (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1181 (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1182 (1 << static_cast<int>(Drawing::BlendMode::DST_ATOP)) +
1183 (1 << static_cast<int>(Drawing::BlendMode::XOR)) +
1184 (1 << static_cast<int>(Drawing::BlendMode::MODULATE));
1185 uint32_t tmp = 1 << blendMode;
1186 if (blendApplyType == static_cast<int>(RSColorBlendApplyType::FAST)) {
1187 return tmp & fastDangerousBit;
1188 }
1189 return tmp & offscreenDangerousBit;
1190 }
1191
BeginBlender(RSPaintFilterCanvas & canvas,std::shared_ptr<Drawing::Blender> blender,int blendModeApplyType,bool isDangerous)1192 void RSPropertyDrawableUtils::BeginBlender(RSPaintFilterCanvas& canvas, std::shared_ptr<Drawing::Blender> blender,
1193 int blendModeApplyType, bool isDangerous)
1194 {
1195 if (isDangerous && !canvas.HasOffscreenLayer()) {
1196 Drawing::SaveLayerOps maskLayerRec(nullptr, nullptr, 0);
1197 canvas.SaveLayer(maskLayerRec);
1198 ROSEN_LOGD("Dangerous offscreen blendmode may produce transparent pixels, add extra offscreen here.");
1199 }
1200
1201 // fast blender
1202 if (blendModeApplyType == static_cast<int>(RSColorBlendApplyType::FAST)) {
1203 canvas.SetBlender(blender);
1204 return;
1205 }
1206
1207 // save layer mode
1208 Drawing::Brush blendBrush_;
1209
1210 // The savelayer in the RSPaintFilterCanvas will automatically apply alpha to the brush.
1211 // If the alpha of the canvas is set to the brush here, the final transparency will be
1212 // alpha * alpha, not alpha.
1213 if (blendModeApplyType == static_cast<int>(RSColorBlendApplyType::SAVE_LAYER_ALPHA)) {
1214 blendBrush_.SetAlphaF(canvas.GetAlpha());
1215 }
1216 blendBrush_.SetBlender(blender);
1217 uint32_t saveLayerFlag = 0;
1218 if (blendModeApplyType == static_cast<int>(RSColorBlendApplyType::SAVE_LAYER_INIT_WITH_PREVIOUS_CONTENT)) {
1219 // currently we only support DDGR backend, we thus use 1 << 1 as indicated in their code.
1220 saveLayerFlag = 1 << 1;
1221 }
1222 Drawing::SaveLayerOps maskLayerRec(nullptr, &blendBrush_, saveLayerFlag);
1223 canvas.SaveLayer(maskLayerRec);
1224 canvas.SetBlender(nullptr);
1225 canvas.SaveAlpha();
1226 canvas.SetAlpha(1.0f);
1227 }
1228
DrawFilterWithDRM(Drawing::Canvas * canvas,bool isDark)1229 void RSPropertyDrawableUtils::DrawFilterWithDRM(Drawing::Canvas* canvas, bool isDark)
1230 {
1231 Drawing::Brush brush;
1232 int16_t alpha = 245; // give a nearly opaque mask to replace blur effect
1233 RSColor demoColor;
1234 if (isDark) {
1235 int16_t rgb_dark = 80;
1236 demoColor = RSColor(rgb_dark, rgb_dark, rgb_dark, alpha);
1237 } else {
1238 int16_t rgb_light = 235;
1239 demoColor = RSColor(rgb_light, rgb_light, rgb_light, alpha);
1240 }
1241
1242 float sat = 1.0f;
1243 float brightness = 0.9f;
1244 float normalizedDegree = brightness - sat;
1245 const float brightnessMat[] = {
1246 1.0f,
1247 0.0f,
1248 0.0f,
1249 0.0f,
1250 normalizedDegree,
1251 0.0f,
1252 1.0f,
1253 0.0f,
1254 0.0f,
1255 normalizedDegree,
1256 0.0f,
1257 0.0f,
1258 1.0f,
1259 0.0f,
1260 normalizedDegree,
1261 0.0f,
1262 0.0f,
1263 0.0f,
1264 1.0f,
1265 0.0f,
1266 };
1267 Drawing::ColorMatrix cm;
1268 cm.SetSaturation(sat);
1269 float cmArray[Drawing::ColorMatrix::MATRIX_SIZE];
1270 cm.GetArray(cmArray);
1271 std::shared_ptr<Drawing::ColorFilter> filterCompose =
1272 Drawing::ColorFilter::CreateComposeColorFilter(cmArray, brightnessMat);
1273 auto colorImageFilter = Drawing::ImageFilter::CreateColorFilterImageFilter(*filterCompose, nullptr);
1274 Drawing::Filter filter;
1275 filter.SetImageFilter(colorImageFilter);
1276 brush.SetFilter(filter);
1277 brush.SetColor(demoColor.AsArgbInt());
1278 canvas->DrawBackground(brush);
1279 }
1280
EndBlender(RSPaintFilterCanvas & canvas,int blendModeApplyType)1281 void RSPropertyDrawableUtils::EndBlender(RSPaintFilterCanvas& canvas, int blendModeApplyType)
1282 {
1283 // RSRenderNodeDrawable will do other necessary work (restore canvas & env), we only need to restore alpha
1284 if (blendModeApplyType != static_cast<int>(RSColorBlendApplyType::FAST)) {
1285 canvas.RestoreAlpha();
1286 }
1287 }
1288
CalculateInvertColor(const Color & backgroundColor)1289 Color RSPropertyDrawableUtils::CalculateInvertColor(const Color& backgroundColor)
1290 {
1291 uint32_t a = backgroundColor.GetAlpha();
1292 uint32_t r = 255 - backgroundColor.GetRed(); // 255 max red channel value
1293 uint32_t g = 255 - backgroundColor.GetGreen(); // 255 max green channel value
1294 uint32_t b = 255 - backgroundColor.GetBlue(); // 255 max blue channel value
1295 return Color(r, g, b, a);
1296 }
1297
GetInvertBackgroundColor(RSPaintFilterCanvas & canvas,bool needClipToBounds,const Vector4f & boundsRect,const Color & backgroundColor)1298 Color RSPropertyDrawableUtils::GetInvertBackgroundColor(RSPaintFilterCanvas& canvas, bool needClipToBounds,
1299 const Vector4f& boundsRect, const Color& backgroundColor)
1300 {
1301 Drawing::AutoCanvasRestore acr(canvas, true);
1302 if (!needClipToBounds) {
1303 RS_LOGI("RSPropertyDrawableUtils::GetInvertBackgroundColor not GetClipToBounds");
1304 Drawing::Rect rect = Drawing::Rect(0, 0, boundsRect.z_, boundsRect.w_);
1305 canvas.ClipRect(rect, Drawing::ClipOp::INTERSECT, false);
1306 }
1307 if (backgroundColor.GetAlpha() == 0xff) { // 0xff = 255, max alpha value
1308 RS_LOGI("RSPropertyDrawableUtils::GetInvertBackgroundColor not alpha");
1309 return RSPropertyDrawableUtils::CalculateInvertColor(backgroundColor);
1310 }
1311 auto surface = canvas.GetSurface();
1312 std::shared_ptr<Drawing::Image> imageSnapshot = surface == nullptr ?
1313 nullptr :
1314 surface->GetImageSnapshot(canvas.GetDeviceClipBounds());
1315 if (imageSnapshot == nullptr) {
1316 RS_LOGI("RSPropertyDrawableUtils::GetInvertBackgroundColor imageSnapshot null");
1317 return Color(0);
1318 }
1319 auto colorPicker = RSPropertiesPainter::CalcAverageColor(imageSnapshot);
1320 return RSPropertyDrawableUtils::CalculateInvertColor(Color(
1321 Drawing::Color::ColorQuadGetR(colorPicker), Drawing::Color::ColorQuadGetG(colorPicker),
1322 Drawing::Color::ColorQuadGetB(colorPicker), Drawing::Color::ColorQuadGetA(colorPicker)));
1323 }
1324
GetGravityMatrix(const Gravity & gravity,const Drawing::Rect & rect,const float & w,const float & h,Drawing::Matrix & mat)1325 bool RSPropertyDrawableUtils::GetGravityMatrix(const Gravity& gravity, const Drawing::Rect& rect, const float& w,
1326 const float& h, Drawing::Matrix& mat)
1327 {
1328 if (w == rect.GetWidth() && h == rect.GetHeight()) {
1329 return false;
1330 }
1331 mat = Drawing::Matrix();
1332
1333 switch (gravity) {
1334 case Gravity::CENTER: {
1335 mat.PreTranslate((rect.GetWidth() - w) / PARAM_DOUBLE, (rect.GetHeight() - h) / PARAM_DOUBLE);
1336 return true;
1337 }
1338 case Gravity::TOP: {
1339 mat.PreTranslate((rect.GetWidth() - w) / PARAM_DOUBLE, 0);
1340 return true;
1341 }
1342 case Gravity::BOTTOM: {
1343 mat.PreTranslate((rect.GetWidth() - w) / PARAM_DOUBLE, rect.GetHeight() - h);
1344 return true;
1345 }
1346 case Gravity::LEFT: {
1347 mat.PreTranslate(0, (rect.GetHeight() - h) / PARAM_DOUBLE);
1348 return true;
1349 }
1350 case Gravity::RIGHT: {
1351 mat.PreTranslate(rect.GetWidth() - w, (rect.GetHeight() - h) / PARAM_DOUBLE);
1352 return true;
1353 }
1354 case Gravity::TOP_LEFT: {
1355 return false;
1356 }
1357 case Gravity::TOP_RIGHT: {
1358 mat.PreTranslate(rect.GetWidth() - w, 0);
1359 return true;
1360 }
1361 case Gravity::BOTTOM_LEFT: {
1362 mat.PreTranslate(0, rect.GetHeight() - h);
1363 return true;
1364 }
1365 case Gravity::BOTTOM_RIGHT: {
1366 mat.PreTranslate(rect.GetWidth() - w, rect.GetHeight() - h);
1367 return true;
1368 }
1369 case Gravity::RESIZE: {
1370 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1371 return false;
1372 }
1373 mat.PreScale(rect.GetWidth() / w, rect.GetHeight() / h);
1374 return true;
1375 }
1376 case Gravity::RESIZE_ASPECT: {
1377 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1378 return false;
1379 }
1380 float scale = std::min(rect.GetWidth() / w, rect.GetHeight() / h);
1381 if (ROSEN_EQ(scale, 0.f)) {
1382 return false;
1383 }
1384 mat.PreScale(scale, scale);
1385 mat.PreTranslate((rect.GetWidth() / scale - w) / PARAM_DOUBLE,
1386 (rect.GetHeight() / scale - h) / PARAM_DOUBLE);
1387 return true;
1388 }
1389 case Gravity::RESIZE_ASPECT_TOP_LEFT: {
1390 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1391 return false;
1392 }
1393 float scale = std::min(rect.GetWidth() / w, rect.GetHeight() / h);
1394 mat.PreScale(scale, scale);
1395 return true;
1396 }
1397 case Gravity::RESIZE_ASPECT_BOTTOM_RIGHT: {
1398 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1399 return false;
1400 }
1401 float scale = std::min(rect.GetWidth() / w, rect.GetHeight() / h);
1402 if (ROSEN_EQ(scale, 0.f)) {
1403 return false;
1404 }
1405 mat.PreScale(scale, scale);
1406 mat.PreTranslate(rect.GetWidth() / scale - w, rect.GetHeight() / scale - h);
1407 return true;
1408 }
1409 case Gravity::RESIZE_ASPECT_FILL: {
1410 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1411 return false;
1412 }
1413 float scale = std::max(rect.GetWidth() / w, rect.GetHeight() / h);
1414 if (ROSEN_EQ(scale, 0.f)) {
1415 return false;
1416 }
1417 mat.PreScale(scale, scale);
1418 mat.PreTranslate((rect.GetWidth() / scale - w) / PARAM_DOUBLE,
1419 (rect.GetHeight() / scale - h) / PARAM_DOUBLE);
1420 return true;
1421 }
1422 case Gravity::RESIZE_ASPECT_FILL_TOP_LEFT: {
1423 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1424 return false;
1425 }
1426 float scale = std::max(rect.GetWidth() / w, rect.GetHeight() / h);
1427 mat.PreScale(scale, scale);
1428 return true;
1429 }
1430 case Gravity::RESIZE_ASPECT_FILL_BOTTOM_RIGHT: {
1431 if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
1432 return false;
1433 }
1434 float scale = std::max(rect.GetWidth() / w, rect.GetHeight() / h);
1435 if (ROSEN_EQ(scale, 0.f)) {
1436 return false;
1437 }
1438 mat.PreScale(scale, scale);
1439 mat.PreTranslate(rect.GetWidth() / scale - w, rect.GetHeight() / scale - h);
1440 return true;
1441 }
1442 default: {
1443 ROSEN_LOGE("GetGravityMatrix unknow gravity=[%{public}d]", gravity);
1444 return false;
1445 }
1446 }
1447 }
1448
RSFilterSetPixelStretch(const RSProperties & property,const std::shared_ptr<RSFilter> & filter)1449 bool RSPropertyDrawableUtils::RSFilterSetPixelStretch(const RSProperties& property,
1450 const std::shared_ptr<RSFilter>& filter)
1451 {
1452 if (!filter || !RSSystemProperties::GetMESABlurFuzedEnabled()) {
1453 return false;
1454 }
1455 auto drawingFilter = std::static_pointer_cast<RSDrawingFilter>(filter);
1456 auto mesaShaderFilter = drawingFilter->GetShaderFilterWithType(RSUIFilterType::MESA);
1457 if (!mesaShaderFilter) {
1458 return false;
1459 }
1460
1461 auto& pixelStretch = property.GetPixelStretch();
1462 if (!pixelStretch.has_value()) {
1463 return false;
1464 }
1465
1466 constexpr static float EPS = 1e-5f;
1467 // The pixel stretch is fuzed only when the stretch factors are negative
1468 if (pixelStretch->x_ > EPS || pixelStretch->y_ > EPS || pixelStretch->z_ > EPS || pixelStretch->w_ > EPS) {
1469 return false;
1470 }
1471
1472 ROSEN_LOGD("RSPropertyDrawableUtils::DrawPixelStretch fuzed with MESABlur.");
1473 const auto& boundsRect = property.GetBoundsRect();
1474 auto tileMode = property.GetPixelStretchTileMode();
1475 auto pixelStretchParams = std::make_shared<RSPixelStretchParams>(std::abs(pixelStretch->x_),
1476 std::abs(pixelStretch->y_),
1477 std::abs(pixelStretch->z_),
1478 std::abs(pixelStretch->w_),
1479 tileMode,
1480 boundsRect.width_, boundsRect.height_);
1481 auto mesaBlurFilter = std::static_pointer_cast<RSMESABlurShaderFilter>(mesaShaderFilter);
1482 mesaBlurFilter->SetPixelStretchParams(pixelStretchParams);
1483 return true;
1484 }
1485
RSFilterRemovePixelStretch(const std::shared_ptr<RSFilter> & filter)1486 void RSPropertyDrawableUtils::RSFilterRemovePixelStretch(const std::shared_ptr<RSFilter>& filter)
1487 {
1488 if (!filter) {
1489 return;
1490 }
1491 auto drawingFilter = std::static_pointer_cast<RSDrawingFilter>(filter);
1492 auto mesaShaderFilter = drawingFilter->GetShaderFilterWithType(RSUIFilterType::MESA);
1493 if (!mesaShaderFilter) {
1494 return;
1495 }
1496
1497 ROSEN_LOGD("RSPropertyDrawableUtils::remove pixel stretch from the fuzed blur");
1498 auto mesaBlurFilter = std::static_pointer_cast<RSMESABlurShaderFilter>(mesaShaderFilter);
1499 std::shared_ptr<RSPixelStretchParams> pixelStretchParams = nullptr;
1500 mesaBlurFilter->SetPixelStretchParams(pixelStretchParams);
1501 return;
1502 }
1503
GenerateBehindWindowFilter(float radius,float saturation,float brightness,RSColor maskColor)1504 std::shared_ptr<RSFilter> RSPropertyDrawableUtils::GenerateBehindWindowFilter(float radius,
1505 float saturation, float brightness, RSColor maskColor)
1506 {
1507 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO,
1508 "RSPropertyDrawableUtils::GenerateBehindWindowFilter, Radius: %f, Saturation: %f, "
1509 "Brightness: %f, MaskColor: %08X", radius, saturation, brightness, maskColor.AsArgbInt());
1510 #ifdef USE_M133_SKIA
1511 const auto hashFunc = SkChecksum::Hash32;
1512 #else
1513 const auto hashFunc = SkOpts::hash;
1514 #endif
1515 uint32_t hash = hashFunc(&radius, sizeof(radius), 0);
1516 std::shared_ptr<Drawing::ColorFilter> colorFilter = GenerateMaterialColorFilter(saturation, brightness);
1517 std::shared_ptr<Drawing::ImageFilter> blurColorFilter =
1518 Drawing::ImageFilter::CreateColorBlurImageFilter(*colorFilter, radius, radius);
1519 std::shared_ptr<RSDrawingFilter> filter = nullptr;
1520 if (RSSystemProperties::GetKawaseEnabled()) {
1521 std::shared_ptr<RSKawaseBlurShaderFilter> kawaseBlurFilter = std::make_shared<RSKawaseBlurShaderFilter>(radius);
1522 auto colorImageFilter = Drawing::ImageFilter::CreateColorFilterImageFilter(*colorFilter, nullptr);
1523 filter = filter?
1524 filter->Compose(colorImageFilter, hash) : std::make_shared<RSDrawingFilter>(colorImageFilter, hash);
1525 filter = filter->Compose(std::static_pointer_cast<RSRenderFilterParaBase>(kawaseBlurFilter));
1526 } else {
1527 hash = hashFunc(&saturation, sizeof(saturation), hash);
1528 hash = hashFunc(&brightness, sizeof(brightness), hash);
1529 filter = filter?
1530 filter->Compose(blurColorFilter, hash) : std::make_shared<RSDrawingFilter>(blurColorFilter, hash);
1531 }
1532 std::shared_ptr<RSMaskColorShaderFilter> maskColorShaderFilter = std::make_shared<RSMaskColorShaderFilter>(
1533 BLUR_COLOR_MODE::DEFAULT, maskColor);
1534 filter = filter->Compose(std::static_pointer_cast<RSRenderFilterParaBase>(maskColorShaderFilter));
1535 filter->SetSkipFrame(RSDrawingFilter::CanSkipFrame(radius));
1536 filter->SetSaturationForHPS(saturation);
1537 filter->SetBrightnessForHPS(brightness);
1538 filter->SetFilterType(RSFilter::MATERIAL);
1539 return filter;
1540 }
1541
GenerateMaterialColorFilter(float sat,float brt)1542 std::shared_ptr<Drawing::ColorFilter> RSPropertyDrawableUtils::GenerateMaterialColorFilter(float sat, float brt)
1543 {
1544 float normalizedDegree = brt - 1.0;
1545 const float brightnessMat[] = {
1546 1.000000f, 0.000000f, 0.000000f, 0.000000f, normalizedDegree,
1547 0.000000f, 1.000000f, 0.000000f, 0.000000f, normalizedDegree,
1548 0.000000f, 0.000000f, 1.000000f, 0.000000f, normalizedDegree,
1549 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
1550 };
1551 Drawing::ColorMatrix cm;
1552 cm.SetSaturation(sat);
1553 float cmArray[Drawing::ColorMatrix::MATRIX_SIZE];
1554 cm.GetArray(cmArray);
1555 return Drawing::ColorFilter::CreateComposeColorFilter(cmArray, brightnessMat, Drawing::Clamp::NO_CLAMP);
1556 }
1557
IsBlurFilterType(const RSFilter::FilterType & filterType)1558 bool RSPropertyDrawableUtils::IsBlurFilterType(const RSFilter::FilterType& filterType)
1559 {
1560 switch (filterType) {
1561 case RSFilter::BLUR :
1562 case RSFilter::MATERIAL :
1563 case RSFilter::LINEAR_GRADIENT_BLUR :
1564 case RSFilter::FOREGROUND_EFFECT :
1565 case RSFilter::MOTION_BLUR :
1566 return true;
1567 default:
1568 return false;
1569 }
1570 }
1571
GetBlurFilterRadius(const std::shared_ptr<RSFilter> & rsFilter)1572 float RSPropertyDrawableUtils::GetBlurFilterRadius(const std::shared_ptr<RSFilter>& rsFilter)
1573 {
1574 if (!rsFilter) {
1575 return 0;
1576 }
1577 switch (rsFilter->GetFilterType()) {
1578 case RSFilter::BLUR :
1579 return std::static_pointer_cast<RSBlurFilter>(rsFilter)->GetBlurRadiusX();
1580 case RSFilter::MATERIAL :
1581 return std::static_pointer_cast<RSMaterialFilter>(rsFilter)->GetRadius();
1582 case RSFilter::LINEAR_GRADIENT_BLUR :
1583 {
1584 auto filter = std::static_pointer_cast<RSDrawingFilter>(rsFilter);
1585 auto rsShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::LINEAR_GRADIENT_BLUR);
1586 if (rsShaderFilter != nullptr) {
1587 auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
1588 return tmpFilter->GetLinearGradientBlurRadius();
1589 }
1590 return 0;
1591 }
1592 case RSFilter::FOREGROUND_EFFECT :
1593 return std::static_pointer_cast<RSForegroundEffectFilter>(rsFilter)->GetRadius();
1594 case RSFilter::MOTION_BLUR :
1595 return std::static_pointer_cast<RSMotionBlurFilter>(rsFilter)->GetRadius();
1596 default:
1597 return 0;
1598 }
1599 }
1600
GetRectByStrategy(const Drawing::Rect & rect,RoundingStrategyType roundingStrategy)1601 Drawing::RectI RSPropertyDrawableUtils::GetRectByStrategy(
1602 const Drawing::Rect& rect, RoundingStrategyType roundingStrategy)
1603 {
1604 switch (roundingStrategy) {
1605 case RoundingStrategyType::ROUND_IN:
1606 return Drawing::RectI(std::ceil(rect.GetLeft()), std::ceil(rect.GetTop()), std::floor(rect.GetRight()),
1607 std::floor(rect.GetBottom()));
1608 case RoundingStrategyType::ROUND_OUT:
1609 return Drawing::RectI(std::floor(rect.GetLeft()), std::floor(rect.GetTop()), std::ceil(rect.GetRight()),
1610 std::ceil(rect.GetBottom()));
1611 case RoundingStrategyType::ROUND_OFF:
1612 return Drawing::RectI(std::round(rect.GetLeft()), std::round(rect.GetTop()), std::round(rect.GetRight()),
1613 std::round(rect.GetBottom()));
1614 case RoundingStrategyType::ROUND_STATIC_CAST_INT:
1615 return Drawing::RectI(static_cast<int>(rect.GetLeft()), static_cast<int>(rect.GetTop()),
1616 static_cast<int>(rect.GetRight()), static_cast<int>(rect.GetBottom()));
1617 default:
1618 return Drawing::RectI(std::floor(rect.GetLeft()), std::floor(rect.GetTop()), std::ceil(rect.GetRight()),
1619 std::ceil(rect.GetBottom()));
1620 }
1621 }
1622
GetAbsRectByStrategy(const Drawing::Surface * surface,const Drawing::Matrix & totalMatrix,const Drawing::Rect & relativeRect,RoundingStrategyType roundingStrategy)1623 Drawing::RectI RSPropertyDrawableUtils::GetAbsRectByStrategy(const Drawing::Surface* surface,
1624 const Drawing::Matrix& totalMatrix, const Drawing::Rect& relativeRect, RoundingStrategyType roundingStrategy)
1625 {
1626 Drawing::Rect absRect;
1627 totalMatrix.MapRect(absRect, relativeRect);
1628 Drawing::RectI absRectI = GetRectByStrategy(absRect, roundingStrategy);
1629 Drawing::RectI deviceRect(0, 0, surface->Width(), surface->Height());
1630 absRectI.Intersect(deviceRect);
1631 return absRectI;
1632 }
1633
GetAbsRectByStrategyForImage(const Drawing::Surface * surface,const Drawing::Matrix & totalMatrix,const Drawing::Rect & relativeRect)1634 std::tuple<Drawing::RectI, Drawing::RectI> RSPropertyDrawableUtils::GetAbsRectByStrategyForImage(
1635 const Drawing::Surface* surface, const Drawing::Matrix& totalMatrix, const Drawing::Rect& relativeRect)
1636 {
1637 Drawing::Rect absRect;
1638 totalMatrix.MapRect(absRect, relativeRect);
1639 Drawing::RectI deviceRect(0, 0, surface->Width(), surface->Height());
1640
1641 Drawing::RectI absImageRect = GetRectByStrategy(absRect, RoundingStrategyType::ROUND_IN);
1642 absImageRect.Intersect(deviceRect);
1643
1644 Drawing::RectI absDrawRect = GetRectByStrategy(absRect, RoundingStrategyType::ROUND_OUT);
1645 absDrawRect.Intersect(deviceRect);
1646
1647 return {absImageRect, absDrawRect};
1648 }
1649
1650 } // namespace Rosen
1651 } // namespace OHOS
1652