• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "property/rs_properties_painter.h"
17 #include "rs_trace.h"
18 
19 #include "common/rs_obj_abs_geometry.h"
20 #include "common/rs_optional_trace.h"
21 #include "pipeline/rs_effect_render_node.h"
22 #include "pipeline/rs_paint_filter_canvas.h"
23 #include "pipeline/rs_root_render_node.h"
24 #include "platform/common/rs_log.h"
25 #include "property/rs_point_light_manager.h"
26 #include "property/rs_properties_def.h"
27 #include "render/rs_blur_filter.h"
28 #include "render/rs_drawing_filter.h"
29 #include "render/rs_distortion_shader_filter.h"
30 #include "render/rs_foreground_effect_filter.h"
31 #include "render/rs_kawase_blur_shader_filter.h"
32 #include "render/rs_linear_gradient_blur_shader_filter.h"
33 #include "render/rs_skia_filter.h"
34 #include "render/rs_magnifier_shader_filter.h"
35 #include "render/rs_material_filter.h"
36 #include "platform/common/rs_system_properties.h"
37 
38 #include <cstdint>
39 #include <algorithm>
40 
41 #include "draw/canvas.h"
42 #include "draw/clip.h"
43 #include "drawing/draw/core_canvas.h"
44 #include "effect/runtime_blender_builder.h"
45 #include "effect/runtime_effect.h"
46 #include "effect/runtime_shader_builder.h"
47 #include "utils/rect.h"
48 #include "src/image/SkImage_Base.h"
49 
50 namespace OHOS {
51 namespace Rosen {
52 namespace {
53 bool g_forceBgAntiAlias = true;
54 constexpr int PARAM_DOUBLE = 2;
55 constexpr int TRACE_LEVEL_TWO = 2;
56 constexpr float MIN_TRANS_RATIO = 0.0f;
57 constexpr float MAX_TRANS_RATIO = 0.95f;
58 constexpr float MIN_SPOT_RATIO = 1.0f;
59 constexpr float MAX_SPOT_RATIO = 1.95f;
60 constexpr float MAX_AMBIENT_RADIUS = 150.0f;
61 } // namespace
62 
63 const bool RSPropertiesPainter::BLUR_ENABLED = RSSystemProperties::GetBlurEnabled();
64 const bool RSPropertiesPainter::FOREGROUND_FILTER_ENABLED = RSSystemProperties::GetForegroundFilterEnabled();
65 
66 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::greyAdjustEffect_ = nullptr;
67 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::binarizationShaderEffect_ = nullptr;
68 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::lightUpEffectBlender_ = nullptr;
69 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::dynamicBrightnessBlenderEffect_ = nullptr;
70 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::dynamicLightUpBlenderEffect_ = nullptr;
71 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::dynamicDimShaderEffect_ = nullptr;
72 
Rect2DrawingRect(const RectF & r)73 Drawing::Rect RSPropertiesPainter::Rect2DrawingRect(const RectF& r)
74 {
75     return Drawing::Rect(r.left_, r.top_, r.left_ + r.width_, r.top_ + r.height_);
76 }
77 
RRect2DrawingRRect(const RRect & rr)78 Drawing::RoundRect RSPropertiesPainter::RRect2DrawingRRect(const RRect& rr)
79 {
80     Drawing::Rect rect = Drawing::Rect(
81         rr.rect_.left_, rr.rect_.top_, rr.rect_.left_ + rr.rect_.width_, rr.rect_.top_ + rr.rect_.height_);
82 
83     // set radius for all 4 corner of RRect
84     constexpr uint32_t NUM_OF_CORNERS_IN_RECT = 4;
85     std::vector<Drawing::Point> radii(NUM_OF_CORNERS_IN_RECT);
86     for (uint32_t i = 0; i < NUM_OF_CORNERS_IN_RECT; i++) {
87         radii.at(i).SetX(rr.radius_[i].x_);
88         radii.at(i).SetY(rr.radius_[i].y_);
89     }
90     return Drawing::RoundRect(rect, radii);
91 }
92 
GetGravityMatrix(Gravity gravity,RectF rect,float w,float h,Drawing::Matrix & mat)93 bool RSPropertiesPainter::GetGravityMatrix(Gravity gravity, RectF rect, float w, float h, Drawing::Matrix& mat)
94 {
95     if (w == rect.width_ && h == rect.height_) {
96         return false;
97     }
98     mat = Drawing::Matrix();
99 
100     switch (gravity) {
101         case Gravity::CENTER: {
102             mat.PreTranslate((rect.width_ - w) / PARAM_DOUBLE, (rect.height_ - h) / PARAM_DOUBLE);
103             return true;
104         }
105         case Gravity::TOP: {
106             mat.PreTranslate((rect.width_ - w) / PARAM_DOUBLE, 0);
107             return true;
108         }
109         case Gravity::BOTTOM: {
110             mat.PreTranslate((rect.width_ - w) / PARAM_DOUBLE, rect.height_ - h);
111             return true;
112         }
113         case Gravity::LEFT: {
114             mat.PreTranslate(0, (rect.height_ - h) / PARAM_DOUBLE);
115             return true;
116         }
117         case Gravity::RIGHT: {
118             mat.PreTranslate(rect.width_ - w, (rect.height_ - h) / PARAM_DOUBLE);
119             return true;
120         }
121         case Gravity::TOP_LEFT: {
122             return false;
123         }
124         case Gravity::TOP_RIGHT: {
125             mat.PreTranslate(rect.width_ - w, 0);
126             return true;
127         }
128         case Gravity::BOTTOM_LEFT: {
129             mat.PreTranslate(0, rect.height_ - h);
130             return true;
131         }
132         case Gravity::BOTTOM_RIGHT: {
133             mat.PreTranslate(rect.width_ - w, rect.height_ - h);
134             return true;
135         }
136         case Gravity::RESIZE: {
137             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
138                 return false;
139             }
140             mat.PreScale(rect.width_ / w, rect.height_ / h);
141             return true;
142         }
143         case Gravity::RESIZE_ASPECT: {
144             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
145                 return false;
146             }
147             float scale = std::min(rect.width_ / w, rect.height_ / h);
148             if (ROSEN_EQ(scale, 0.f)) {
149                 return false;
150             }
151             mat.PreScale(scale, scale);
152             mat.PreTranslate((rect.width_ / scale - w) / PARAM_DOUBLE, (rect.height_ / scale - h) / PARAM_DOUBLE);
153             return true;
154         }
155         case Gravity::RESIZE_ASPECT_TOP_LEFT: {
156             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
157                 return false;
158             }
159             float scale = std::min(rect.width_ / w, rect.height_ / h);
160             mat.PreScale(scale, scale);
161             return true;
162         }
163         case Gravity::RESIZE_ASPECT_BOTTOM_RIGHT: {
164             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
165                 return false;
166             }
167             float scale = std::min(rect.width_ / w, rect.height_ / h);
168             if (ROSEN_EQ(scale, 0.f)) {
169                 return false;
170             }
171             mat.PreScale(scale, scale);
172             mat.PreTranslate(rect.width_ / scale - w, rect.height_ / scale - h);
173             return true;
174         }
175         case Gravity::RESIZE_ASPECT_FILL: {
176             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
177                 return false;
178             }
179             float scale = std::max(rect.width_ / w, rect.height_ / h);
180             if (ROSEN_EQ(scale, 0.f)) {
181                 return false;
182             }
183             mat.PreScale(scale, scale);
184             mat.PreTranslate((rect.width_ / scale - w) / PARAM_DOUBLE, (rect.height_ / scale - h) / PARAM_DOUBLE);
185             return true;
186         }
187         case Gravity::RESIZE_ASPECT_FILL_TOP_LEFT: {
188             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
189                 return false;
190             }
191             float scale = std::max(rect.width_ / w, rect.height_ / h);
192             mat.PreScale(scale, scale);
193             return true;
194         }
195         case Gravity::RESIZE_ASPECT_FILL_BOTTOM_RIGHT: {
196             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
197                 return false;
198             }
199             float scale = std::max(rect.width_ / w, rect.height_ / h);
200             if (ROSEN_EQ(scale, 0.f)) {
201                 return false;
202             }
203             mat.PreScale(scale, scale);
204             mat.PreTranslate(rect.width_ / scale - w, rect.height_ / scale - h);
205             return true;
206         }
207         default: {
208             ROSEN_LOGE("GetGravityMatrix unknow gravity=[%{public}d]", gravity);
209             return false;
210         }
211     }
212 }
213 
GetScalingModeMatrix(ScalingMode scalingMode,RectF bounds,float bufferWidth,float bufferHeight,Drawing::Matrix & scalingModeMatrix)214 bool RSPropertiesPainter::GetScalingModeMatrix(ScalingMode scalingMode, RectF bounds,
215     float bufferWidth, float bufferHeight, Drawing::Matrix& scalingModeMatrix)
216 {
217     if (ROSEN_EQ(bufferWidth, bounds.width_) && ROSEN_EQ(bufferHeight, bounds.height_)) {
218         return false;
219     }
220     scalingModeMatrix = Drawing::Matrix();
221     switch (scalingMode) {
222         case ScalingMode::SCALING_MODE_SCALE_CROP: {
223             if (ROSEN_EQ(bufferWidth, 0.f) || ROSEN_EQ(bufferHeight, 0.f)) {
224                 return false;
225             }
226             float scale = std::max(bounds.width_ / bufferWidth, bounds.height_ / bufferHeight);
227             if (ROSEN_NE(scale, 0.f)) {
228                 scalingModeMatrix.PreScale(scale, scale);
229                 scalingModeMatrix.PreTranslate((bounds.width_ / scale - bufferWidth) / PARAM_DOUBLE,
230                     (bounds.height_ / scale - bufferHeight) / PARAM_DOUBLE);
231                 return true;
232             }
233             return false;
234         }
235         case ScalingMode::SCALING_MODE_SCALE_FIT: {
236             if (ROSEN_EQ(bufferWidth, 0.f) || ROSEN_EQ(bufferHeight, 0.f)) {
237                 return false;
238             }
239             float scale = std::min(bounds.width_ / bufferWidth, bounds.height_ / bufferHeight);
240             if (ROSEN_NE(scale, 0.f)) {
241                 scalingModeMatrix.PreScale(scale, scale);
242                 scalingModeMatrix.PreTranslate((bounds.width_ / scale - bufferWidth) / PARAM_DOUBLE,
243                     (bounds.height_ / scale - bufferHeight) / PARAM_DOUBLE);
244                 return true;
245             }
246             return false;
247         }
248         case ScalingMode::SCALING_MODE_NO_SCALE_CROP: {
249             if (ROSEN_EQ(bufferWidth, 0.f) || ROSEN_EQ(bufferHeight, 0.f)) {
250                 return false;
251             }
252             scalingModeMatrix.PreTranslate((bounds.width_ - bufferWidth) / PARAM_DOUBLE,
253                 (bounds.height_ - bufferHeight) / PARAM_DOUBLE);
254             return true;
255         }
256         case ScalingMode::SCALING_MODE_FREEZE: [[fallthrough]];
257         case ScalingMode::SCALING_MODE_SCALE_TO_WINDOW: {
258             return true;
259         }
260         default: {
261             ROSEN_LOGE("GetScalingModeMatrix: Unknown ScalingMode=[%{public}d]", static_cast<int>(scalingMode));
262             return false;
263         }
264     }
265 }
266 
Clip(Drawing::Canvas & canvas,RectF rect,bool isAntiAlias)267 void RSPropertiesPainter::Clip(Drawing::Canvas& canvas, RectF rect, bool isAntiAlias)
268 {
269     canvas.ClipRect(Rect2DrawingRect(rect), Drawing::ClipOp::INTERSECT, isAntiAlias);
270 }
271 
GetShadowDirtyRect(RectI & dirtyShadow,const RSProperties & properties,const RRect * rrect,bool isAbsCoordinate,bool radiusInclude)272 void RSPropertiesPainter::GetShadowDirtyRect(RectI& dirtyShadow, const RSProperties& properties,
273     const RRect* rrect, bool isAbsCoordinate, bool radiusInclude)
274 {
275     // [Planning]: After Skia being updated, we should directly call SkShadowUtils::GetLocalBounds here.
276     if (!properties.IsShadowValid()) {
277         return;
278     }
279     Drawing::Path path;
280     if (properties.GetShadowPath() && properties.GetShadowPath()->GetDrawingPath().IsValid()) {
281         path = properties.GetShadowPath()->GetDrawingPath();
282     } else if (properties.GetClipBounds()) {
283         path = properties.GetClipBounds()->GetDrawingPath();
284     } else {
285         if (rrect != nullptr) {
286             path.AddRoundRect(RRect2DrawingRRect(*rrect));
287         } else {
288             path.AddRoundRect(RRect2DrawingRRect(properties.GetRRect()));
289         }
290     }
291     path.Offset(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
292 
293     Drawing::Rect shadowRect = path.GetBounds();
294     if (properties.GetShadowElevation() > 0.f) {
295         float elevation = properties.GetShadowElevation() + DEFAULT_TRANSLATION_Z;
296 
297         float userTransRatio =
298             (elevation != DEFAULT_LIGHT_HEIGHT) ? elevation / (DEFAULT_LIGHT_HEIGHT - elevation) : MAX_TRANS_RATIO;
299         float transRatio = std::max(MIN_TRANS_RATIO, std::min(userTransRatio, MAX_TRANS_RATIO));
300 
301         float userSpotRatio = (elevation != DEFAULT_LIGHT_HEIGHT)
302                                   ? DEFAULT_LIGHT_HEIGHT / (DEFAULT_LIGHT_HEIGHT - elevation)
303                                   : MAX_SPOT_RATIO;
304         float spotRatio = std::max(MIN_SPOT_RATIO, std::min(userSpotRatio, MAX_SPOT_RATIO));
305 
306         Drawing::Rect ambientRect = path.GetBounds();
307         Drawing::Rect spotRect = Drawing::Rect(ambientRect.GetLeft() * spotRatio, ambientRect.GetTop() * spotRatio,
308             ambientRect.GetRight() * spotRatio, ambientRect.GetBottom() * spotRatio);
309         spotRect.Offset(-transRatio * DEFAULT_LIGHT_POSITION_X, -transRatio * DEFAULT_LIGHT_POSITION_Y);
310         spotRect.MakeOutset(transRatio * DEFAULT_LIGHT_RADIUS, transRatio * DEFAULT_LIGHT_RADIUS);
311 
312         shadowRect = ambientRect;
313         float ambientBlur = std::min(elevation * 0.5f, MAX_AMBIENT_RADIUS);
314         shadowRect.MakeOutset(ambientBlur, ambientBlur);
315 
316         shadowRect.Join(spotRect);
317     } else {
318         Drawing::Brush brush;
319         brush.SetAntiAlias(true);
320         Drawing::Filter filter;
321         filter.SetMaskFilter(
322             Drawing::MaskFilter::CreateBlurMaskFilter(Drawing::BlurType::NORMAL, properties.GetShadowRadius()));
323         brush.SetFilter(filter);
324         if (brush.CanComputeFastBounds() && radiusInclude) {
325             brush.ComputeFastBounds(shadowRect, &shadowRect);
326         }
327     }
328     // avoid 1 pixel reduction caused by converting float to int
329     shadowRect.MakeOutset(1, 1);
330 
331     auto& geoPtr = (properties.GetBoundsGeometry());
332     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
333     matrix.MapRect(shadowRect, shadowRect);
334 
335     dirtyShadow.left_ = shadowRect.GetLeft();
336     dirtyShadow.top_ = shadowRect.GetTop();
337     dirtyShadow.width_ = shadowRect.GetWidth();
338     dirtyShadow.height_ = shadowRect.GetHeight();
339 }
340 
DrawShadow(const RSProperties & properties,RSPaintFilterCanvas & canvas,const RRect * rrect)341 void RSPropertiesPainter::DrawShadow(const RSProperties& properties, RSPaintFilterCanvas& canvas, const RRect* rrect)
342 {
343     // skip shadow if not valid or cache is enabled
344     if (properties.IsSpherizeValid() || !properties.IsShadowValid() ||
345         canvas.GetCacheType() == RSPaintFilterCanvas::CacheType::ENABLED) {
346         return;
347     }
348     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO,
349         "RSPropertiesPainter::DrawShadow, ShadowElevation: %f, ShadowRadius: %f, ShadowOffsetX: "
350         "%f, ShadowOffsetY: %f, bounds: %s",
351         properties.GetShadowElevation(), properties.GetShadowRadius(), properties.GetShadowOffsetX(),
352         properties.GetShadowOffsetY(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
353     Drawing::AutoCanvasRestore acr(canvas, true);
354     Drawing::Path path;
355     if (properties.GetShadowPath() && properties.GetShadowPath()->GetDrawingPath().IsValid()) {
356         path = properties.GetShadowPath()->GetDrawingPath();
357         if (!properties.GetShadowIsFilled()) {
358             canvas.ClipPath(path, Drawing::ClipOp::DIFFERENCE, true);
359         }
360     } else if (properties.GetClipBounds()) {
361         path = properties.GetClipBounds()->GetDrawingPath();
362         if (!properties.GetShadowIsFilled()) {
363             canvas.ClipPath(path, Drawing::ClipOp::DIFFERENCE, true);
364         }
365     } else {
366         if (rrect != nullptr) {
367             path.AddRoundRect(RRect2DrawingRRect(*rrect));
368             if (!properties.GetShadowIsFilled()) {
369                 canvas.ClipRoundRect(RRect2DrawingRRect(*rrect), Drawing::ClipOp::DIFFERENCE, true);
370             }
371         } else {
372             path.AddRoundRect(RRect2DrawingRRect(properties.GetRRect()));
373             if (!properties.GetShadowIsFilled()) {
374                 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::DIFFERENCE, true);
375             }
376         }
377     }
378     if (properties.GetShadowMask()) {
379         DrawColorfulShadowInner(properties, canvas, path);
380     } else {
381         DrawShadowInner(properties, canvas, path);
382     }
383 }
384 
DrawColorfulShadowInner(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::Path & path)385 void RSPropertiesPainter::DrawColorfulShadowInner(
386     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::Path& path)
387 {
388     // blurRadius calculation is based on the formula in Canvas::DrawShadow, 0.25f and 128.0f are constants
389     const Drawing::scalar blurRadius =
390         properties.GetShadowElevation() > 0.f
391             ? 0.25f * properties.GetShadowElevation() * (1 + properties.GetShadowElevation() / 128.0f)
392             : properties.GetShadowRadius();
393 
394     // save layer, draw image with clipPath, blur and draw back
395     Drawing::Brush blurBrush;
396     Drawing::Filter filter;
397     filter.SetImageFilter(Drawing::ImageFilter::CreateBlurImageFilter(
398         blurRadius, blurRadius, Drawing::TileMode::DECAL, nullptr));
399     blurBrush.SetFilter(filter);
400 
401     canvas.SaveLayer({nullptr, &blurBrush});
402 
403     canvas.Translate(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
404 
405     canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, false);
406     // draw node content as shadow
407     // [PLANNING]: maybe we should also draw background color / image here, and we should cache the shadow image
408     if (auto node = RSBaseRenderNode::ReinterpretCast<RSCanvasRenderNode>(properties.backref_.lock())) {
409         node->InternalDrawContent(canvas, false);
410     }
411 }
412 
GetDarkColor(RSColor & color)413 void RSPropertiesPainter::GetDarkColor(RSColor& color)
414 {
415     // convert to lab
416     float minColorRange = 0;
417     float maxColorRange = 255;
418     float R = float(color.GetRed()) / maxColorRange;
419     float G = float(color.GetGreen()) / maxColorRange;
420     float B = float(color.GetBlue()) / maxColorRange;
421 
422     float X = 0.4124 * R + 0.3576 * G + 0.1805 * B;
423     float Y = 0.2126 * R + 0.7152 * G + 0.0722 * B;
424     float Z = 0.0193 * R + 0.1192 * G + 0.9505 * B;
425 
426     float Xn = 0.9505;
427     float Yn = 1.0000;
428     float Zn = 1.0889999;
429     float Fx = (X / Xn) > 0.008856 ? pow((X / Xn), 1.0 / 3) : (7.787 * (X / Xn) + 16.0 / 116);
430     float Fy = (Y / Yn) > 0.008856 ? pow((Y / Yn), 1.0 / 3) : (7.787 * (Y / Yn) + 16.0 / 116);
431     float Fz = (Z / Zn) > 0.008856 ? pow((Z / Zn), 1.0 / 3) : (7.787 * (Z / Zn) + 16.0 / 116);
432     float L = 116 * Fy - 16;
433     float a = 500 * (Fx - Fy);
434     float b = 200 * (Fy - Fz);
435 
436     float standardLightness = 75.0;
437     if (L > standardLightness) {
438         float L1 = standardLightness;
439         float xw = 0.9505;
440         float yw = 1.0000;
441         float zw = 1.0889999;
442 
443         float fy = (L1 + 16) / 116;
444         float fx = fy + (a / 500);
445         float fz = fy - (b / 200);
446 
447         float X1 = xw * ((pow(fx, 3) > 0.008856) ? pow(fx, 3) : ((fx - 16.0 / 116) / 7.787));
448         float Y1 = yw * ((pow(fy, 3) > 0.008856) ? pow(fy, 3) : ((fy - 16.0 / 116) / 7.787));
449         float Z1 = zw * ((pow(fz, 3) > 0.008856) ? pow(fz, 3) : ((fz - 16.0 / 116) / 7.787));
450 
451         float DarkR = 3.2406 * X1 - 1.5372 * Y1 - 0.4986 * Z1;
452         float DarkG = -0.9689 * X1 + 1.8758 * Y1 + 0.0415 * Z1;
453         float DarkB = 0.0557 * X1 - 0.2040 * Y1 + 1.0570 * Z1;
454 
455         DarkR = std::clamp(maxColorRange * DarkR, minColorRange, maxColorRange);
456         DarkG = std::clamp(maxColorRange * DarkG, minColorRange, maxColorRange);
457         DarkB = std::clamp(maxColorRange * DarkB, minColorRange, maxColorRange);
458 
459         color = RSColor(DarkR, DarkG, DarkB, color.GetAlpha());
460     }
461 }
462 
DrawShadowInner(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::Path & path)463 void RSPropertiesPainter::DrawShadowInner(
464     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::Path& path)
465 {
466     path.Offset(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
467     Color spotColor = properties.GetShadowColor();
468     auto deviceClipBounds = canvas.GetDeviceClipBounds();
469 
470     // The translation of the matrix is rounded to improve the hit ratio of skia blurfilter cache,
471     // the function <compute_key_and_clip_bounds> in <skia/src/gpu/GrBlurUtil.cpp> for more details.
472     RSAutoCanvasRestore rst(&canvas);
473     auto matrix = canvas.GetTotalMatrix();
474     matrix.Set(Drawing::Matrix::TRANS_X, std::ceil(matrix.Get(Drawing::Matrix::TRANS_X)));
475     matrix.Set(Drawing::Matrix::TRANS_Y, std::ceil(matrix.Get(Drawing::Matrix::TRANS_Y)));
476     canvas.SetMatrix(matrix);
477 
478     if (properties.GetShadowElevation() > 0.f) {
479         Drawing::Point3 planeParams = { 0.0f, 0.0f, properties.GetShadowElevation() };
480         std::vector<Drawing::Point> pt{{path.GetBounds().GetLeft() + path.GetBounds().GetWidth() / 2,
481             path.GetBounds().GetTop() + path.GetBounds().GetHeight() / 2}};
482         canvas.GetTotalMatrix().MapPoints(pt, pt, 1);
483         Drawing::Point3 lightPos = {pt[0].GetX(), pt[0].GetY(), DEFAULT_LIGHT_HEIGHT};
484         Color ambientColor = Color::FromArgbInt(DEFAULT_AMBIENT_COLOR);
485         ambientColor.MultiplyAlpha(canvas.GetAlpha());
486         spotColor.MultiplyAlpha(canvas.GetAlpha());
487         canvas.DrawShadowStyle(path, planeParams, lightPos, DEFAULT_LIGHT_RADIUS,
488             Drawing::Color(ambientColor.AsArgbInt()), Drawing::Color(spotColor.AsArgbInt()),
489             Drawing::ShadowFlags::TRANSPARENT_OCCLUDER, true);
490     } else {
491         Drawing::Brush brush;
492         brush.SetColor(Drawing::Color::ColorQuadSetARGB(
493             spotColor.GetAlpha(), spotColor.GetRed(), spotColor.GetGreen(), spotColor.GetBlue()));
494         brush.SetAntiAlias(true);
495         Drawing::Filter filter;
496         filter.SetMaskFilter(
497             Drawing::MaskFilter::CreateBlurMaskFilter(Drawing::BlurType::NORMAL, properties.GetShadowRadius()));
498         brush.SetFilter(filter);
499         canvas.AttachBrush(brush);
500         canvas.DrawPath(path);
501         canvas.DetachBrush();
502     }
503 }
504 
MakeGreyAdjustmentEffect()505 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::MakeGreyAdjustmentEffect()
506 {
507     static const std::string GreyGradationString(R"(
508         uniform shader imageShader;
509         uniform float coefficient1;
510         uniform float coefficient2;
511 
512         float poww(float x, float y) {
513             return (x < 0) ? -pow(-x, y) : pow(x, y);
514         }
515 
516         float calculateT_y(float rgb) {
517             if (rgb > 127.5) { rgb = 255 - rgb; }
518             float b = 38.0;
519             float c = 45.0;
520             float d = 127.5;
521             float A = 106.5;    // 3 * b - 3 * c + d;
522             float B = -93;      // 3 * (c - 2 * b);
523             float C = 114;      // 3 * b;
524             float p = 0.816240163988;                   // (3 * A * C - pow(B, 2)) / (3 * pow(A, 2));
525             float q = -rgb / 106.5 + 0.262253485943;    // -rgb/A - B*C/(3*pow(A,2)) + 2*pow(B,3)/(27*pow(A,3))
526             float s1 = -(q / 2.0);
527             float s2 = sqrt(pow(s1, 2) + pow(p / 3, 3));
528             return poww((s1 + s2), 1.0 / 3) + poww((s1 - s2), 1.0 / 3) - (B / (3 * A));
529         }
530 
531         float calculateGreyAdjustY(float rgb) {
532             float t_r = calculateT_y(rgb);
533             return (rgb < 127.5) ? (rgb + coefficient1 * pow((1 - t_r), 3)) : (rgb - coefficient2 * pow((1 - t_r), 3));
534         }
535 
536         vec4 main(vec2 drawing_coord) {
537             vec3 color = vec3(imageShader(drawing_coord).r, imageShader(drawing_coord).g, imageShader(drawing_coord).b);
538             float Y = (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) * 255;
539             float U = (-0.147 * color.r - 0.289 * color.g + 0.436 * color.b) * 255;
540             float V = (0.615 * color.r - 0.515 * color.g - 0.100 * color.b) * 255;
541             Y = calculateGreyAdjustY(Y);
542             color.r = (Y + 1.14 * V) / 255.0;
543             color.g = (Y - 0.39 * U - 0.58 * V) / 255.0;
544             color.b = (Y + 2.03 * U) / 255.0;
545 
546             return vec4(color, 1.0);
547         }
548     )");
549     if (!greyAdjustEffect_) {
550         std::shared_ptr<Drawing::RuntimeEffect> greyAdjustEffect =
551             Drawing::RuntimeEffect::CreateForShader(GreyGradationString);
552         if (!greyAdjustEffect) {
553             return nullptr;
554         }
555         greyAdjustEffect_ = std::move(greyAdjustEffect);
556     }
557 
558     return greyAdjustEffect_;
559 }
560 
DrawGreyAdjustment(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Vector2f & greyCoeff)561 std::shared_ptr<Drawing::Image> RSPropertiesPainter::DrawGreyAdjustment(Drawing::Canvas& canvas,
562     const std::shared_ptr<Drawing::Image>& image, const Vector2f& greyCoeff)
563 {
564 #ifdef RS_ENABLE_GPU
565     if (image == nullptr) {
566         ROSEN_LOGE("RSPropertiesPainter::DrawGreyAdjustment image is null");
567         return nullptr;
568     }
569     RS_TRACE_NAME_FMT("RSPropertiesPainter::DrawGreyAdjustment, greyCoef1 is: %f, greyCoef2 is: %f",
570         greyCoeff.x_, greyCoeff.y_);
571     auto greyAdjustEffect = MakeGreyAdjustmentEffect();
572     if (!greyAdjustEffect) {
573         ROSEN_LOGE("RSPropertiesPainter::DrawGreyAdjustment greyAdjustEffect is null");
574         return nullptr;
575     }
576     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
577         std::make_shared<Drawing::RuntimeShaderBuilder>(greyAdjustEffect);
578     Drawing::Matrix matrix;
579     auto imageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
580         Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
581     builder->SetChild("imageShader", imageShader);
582     builder->SetUniform("coefficient1", greyCoeff.x_);
583     builder->SetUniform("coefficient2", greyCoeff.y_);
584     return builder->MakeImage(canvas.GetGPUContext().get(), nullptr, image->GetImageInfo(), false);
585 #else
586     return nullptr;
587 #endif
588 }
589 
DrawForegroundFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas)590 void RSPropertiesPainter::DrawForegroundFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas)
591 {
592     RS_OPTIONAL_TRACE_NAME("DrawForegroundFilter restore");
593     auto surface = canvas.GetSurface();
594     std::shared_ptr<Drawing::Image> imageSnapshot = nullptr;
595     if (surface) {
596         imageSnapshot = surface->GetImageSnapshot();
597     } else {
598         ROSEN_LOGD("RSPropertiesPainter::DrawForegroundFilter Surface null");
599     }
600 
601     canvas.RestorePCanvasList();
602     canvas.SwapBackMainScreenData();
603 
604     auto& RSFilter = properties.GetForegroundFilter();
605     if (RSFilter == nullptr) {
606         return;
607     }
608 
609     if (imageSnapshot == nullptr) {
610         ROSEN_LOGD("RSPropertiesPainter::DrawForegroundFilter image null");
611         return;
612     }
613     auto foregroundFilter = std::static_pointer_cast<RSDrawingFilterOriginal>(RSFilter);
614     if (foregroundFilter->GetFilterType() == RSFilter::MOTION_BLUR) {
615         if (canvas.GetDisableFilterCache()) {
616             foregroundFilter->DisableMotionBlur(true);
617         } else {
618             foregroundFilter->DisableMotionBlur(false);
619         }
620     }
621 
622     foregroundFilter->DrawImageRect(canvas, imageSnapshot, Drawing::Rect(0, 0, imageSnapshot->GetWidth(),
623         imageSnapshot->GetHeight()), Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight()));
624 }
625 
DrawFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas,FilterType filterType,const std::optional<Drawing::Rect> & rect,const std::shared_ptr<RSFilter> & externalFilter)626 void RSPropertiesPainter::DrawFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas,
627     FilterType filterType, const std::optional<Drawing::Rect>& rect, const std::shared_ptr<RSFilter>& externalFilter)
628 {
629     if (!BLUR_ENABLED) {
630         ROSEN_LOGD("RSPropertiesPainter::DrawFilter close blur.");
631         return;
632     }
633     // use provided filter if not null
634     auto& RSFilter = externalFilter ? externalFilter
635         : ((filterType == FilterType::BACKGROUND_FILTER) ? properties.GetBackgroundFilter() : properties.GetFilter());
636     if (RSFilter == nullptr) {
637         return;
638     }
639 
640     RS_OPTIONAL_TRACE_NAME("DrawFilter " + RSFilter->GetDescription());
641     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawFilter, filterType: %d, %s, bounds: %s", filterType,
642         RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
643     g_blurCnt++;
644     Drawing::AutoCanvasRestore acr(canvas, true);
645 
646     auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
647     auto surface = canvas.GetSurface();
648     if (surface == nullptr) {
649         ROSEN_LOGD("RSPropertiesPainter::DrawFilter surface null");
650         Drawing::Brush brush;
651         brush.SetAntiAlias(true);
652         Drawing::Filter filterForBrush;
653         auto imageFilter = filter->GetImageFilter();
654         // Since using Kawase blur (shader) in the screenshot scene would lead to failure,
655         // a Gaussian blur filter (imageFilter) is regenerated here instead.
656         std::shared_ptr<RSShaderFilter> kawaseShaderFilter =
657             filter->GetShaderFilterWithType(RSShaderFilter::KAWASE);
658         if (kawaseShaderFilter != nullptr) {
659             auto tmpFilter = std::static_pointer_cast<RSKawaseBlurShaderFilter>(kawaseShaderFilter);
660             auto radius = tmpFilter->GetRadius();
661             std::shared_ptr<Drawing::ImageFilter> blurFilter = Drawing::ImageFilter::CreateBlurImageFilter(
662                 radius, radius, Drawing::TileMode::CLAMP, nullptr);
663             imageFilter = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter, blurFilter);
664         }
665         filterForBrush.SetImageFilter(imageFilter);
666         brush.SetFilter(filterForBrush);
667         Drawing::SaveLayerOps slr(nullptr, &brush, Drawing::SaveLayerOps::Flags::INIT_WITH_PREVIOUS);
668         canvas.SaveLayer(slr);
669         filter->PostProcess(canvas);
670         return;
671     }
672 
673     // for foreground filter, when do online opacity, rendering result already applied opacity,
674     // so drawImage should not apply opacity again
675     RSAutoCanvasRestore autoCanvasRestore(&canvas,
676         filterType == FilterType::FOREGROUND_FILTER ? RSPaintFilterCanvas::kAlpha : RSPaintFilterCanvas::kNone);
677     if (filterType == FilterType::FOREGROUND_FILTER) {
678         canvas.SetAlpha(1.0);
679     }
680 
681     auto clipIBounds = canvas.GetDeviceClipBounds();
682     auto imageClipIBounds = clipIBounds;
683     std::shared_ptr<RSShaderFilter> magnifierShaderFilter =
684         filter->GetShaderFilterWithType(RSShaderFilter::MAGNIFIER);
685     if (magnifierShaderFilter != nullptr) {
686         auto tmpFilter = std::static_pointer_cast<RSMagnifierShaderFilter>(magnifierShaderFilter);
687         auto canvasMatrix = canvas.GetTotalMatrix();
688         tmpFilter->SetMagnifierOffset(canvasMatrix);
689         imageClipIBounds.Offset(tmpFilter->GetMagnifierOffsetX(), tmpFilter->GetMagnifierOffsetY());
690     }
691 
692 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
693     // Optional use cacheManager to draw filter
694     if (auto& cacheManager = properties.GetFilterCacheManager(filterType == FilterType::FOREGROUND_FILTER);
695         cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
696         std::shared_ptr<RSShaderFilter> rsShaderFilter =
697             filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
698         if (rsShaderFilter != nullptr) {
699             auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
700             tmpFilter->IsOffscreenCanvas(true);
701             tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
702         }
703         // RSFilterCacheManger has no more logic for evaluating filtered snapshot clearing
704         // (see RSPropertyDrawableUtils::DrawFilter())
705         cacheManager->DrawFilter(canvas, filter, true, false);
706         return;
707     }
708 #endif
709 
710     std::shared_ptr<RSShaderFilter> rsShaderFilter =
711         filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
712     if (rsShaderFilter != nullptr) {
713         auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
714         tmpFilter->IsOffscreenCanvas(true);
715         tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
716     }
717 
718     auto imageSnapshot = surface->GetImageSnapshot(imageClipIBounds);
719     if (imageSnapshot == nullptr) {
720         ROSEN_LOGD("RSPropertiesPainter::DrawFilter image null");
721         return;
722     }
723     if (RSSystemProperties::GetImageGpuResourceCacheEnable(imageSnapshot->GetWidth(), imageSnapshot->GetHeight())) {
724         ROSEN_LOGD("DrawFilter cache image resource(width:%{public}d, height:%{public}d).",
725             imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
726         imageSnapshot->HintCacheGpuResource();
727     }
728 
729     filter->PreProcess(imageSnapshot);
730     canvas.ResetMatrix();
731     auto visibleRect = canvas.GetVisibleRect();
732     visibleRect.Round();
733     auto visibleIRect = Drawing::RectI(
734         static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
735         static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
736     if (!visibleIRect.IsEmpty()) {
737         canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
738     }
739     Drawing::Rect srcRect = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
740     Drawing::Rect dstRect = clipIBounds;
741     filter->DrawImageRect(canvas, imageSnapshot, srcRect, dstRect);
742     filter->PostProcess(canvas);
743 }
744 
DrawBackgroundImageAsEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)745 void RSPropertiesPainter::DrawBackgroundImageAsEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
746 {
747     RS_TRACE_FUNC();
748 
749     // Optional use cacheManager to draw filter, cache is valid, skip drawing background image
750 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
751     auto boundsRect = properties.GetBoundsRect();
752     if (auto& cacheManager = properties.GetFilterCacheManager(false);
753         cacheManager != nullptr && !canvas.GetDisableFilterCache() && cacheManager->IsCacheValid()) {
754         // no need to validate parameters, the caller already do it
755         canvas.ClipRect(RSPropertiesPainter::Rect2DrawingRect(boundsRect));
756         auto filter = std::static_pointer_cast<RSDrawingFilter>(properties.GetBackgroundFilter());
757         // extract cache data from cacheManager
758         auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter);
759         canvas.SetEffectData(data);
760         return;
761     }
762 #endif
763 
764     auto surface = canvas.GetSurface();
765     if (!surface) {
766         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect surface null");
767         return;
768     }
769     // create offscreen surface with same size as current surface (PLANNING: use bounds size instead)
770     auto offscreenSurface = surface->MakeSurface(canvas.GetWidth(), canvas.GetHeight());
771     auto offscreenCanvas = std::make_shared<RSPaintFilterCanvas>(offscreenSurface.get());
772     // copy matrix and other properties to offscreen canvas
773     offscreenCanvas->SetMatrix(canvas.GetTotalMatrix());
774     offscreenCanvas->CopyConfigurationToOffscreenCanvas(canvas);
775     // draw background onto offscreen canvas
776     RSPropertiesPainter::DrawBackground(properties, *offscreenCanvas);
777     // generate effect data
778     RSPropertiesPainter::DrawBackgroundEffect(properties, *offscreenCanvas);
779     // extract effect data from offscreen canvas and set to canvas
780     canvas.SetEffectData(offscreenCanvas->GetEffectData());
781 }
782 
DrawBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)783 void RSPropertiesPainter::DrawBackgroundEffect(
784     const RSProperties& properties, RSPaintFilterCanvas& canvas)
785 {
786     auto& RSFilter = properties.GetBackgroundFilter();
787     if (RSFilter == nullptr) {
788         return;
789     }
790     g_blurCnt++;
791     RS_TRACE_NAME("DrawBackgroundEffect " + RSFilter->GetDescription());
792     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "EffectComponent, %s, bounds: %s",
793         RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
794     auto surface = canvas.GetSurface();
795     if (surface == nullptr) {
796         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect surface null");
797         return;
798     }
799 
800     canvas.Save();
801     canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()));
802     auto bounds = canvas.GetRoundInDeviceClipBounds();
803     canvas.Restore();
804     auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
805 
806 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
807     // Optional use cacheManager to draw filter
808     if (auto& cacheManager = properties.GetFilterCacheManager(false);
809         cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
810         auto node = properties.backref_.lock();
811         if (node == nullptr) {
812             ROSEN_LOGE("DrawBackgroundEffect::node is null");
813             return;
814         }
815         auto effectNode = node->ReinterpretCastTo<RSEffectRenderNode>();
816         if (effectNode == nullptr) {
817             ROSEN_LOGE("DrawBackgroundEffect::node reinterpret cast failed.");
818             return;
819         }
820         auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter, bounds, bounds);
821         canvas.SetEffectData(data);
822         return;
823     }
824 #endif
825 
826     auto imageRect = bounds;
827     auto imageSnapshot = surface->GetImageSnapshot(imageRect);
828     if (imageSnapshot == nullptr) {
829         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect image snapshot null");
830         return;
831     }
832 
833     filter->PreProcess(imageSnapshot);
834     // create a offscreen skSurface
835     std::shared_ptr<Drawing::Surface> offscreenSurface =
836         surface->MakeSurface(imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
837     if (offscreenSurface == nullptr) {
838         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect offscreenSurface null");
839         return;
840     }
841     RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
842     auto clipBounds = Drawing::Rect(0, 0, imageRect.GetWidth(), imageRect.GetHeight());
843     auto imageSnapshotBounds = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
844     filter->DrawImageRect(offscreenCanvas, imageSnapshot, imageSnapshotBounds, clipBounds);
845     filter->PostProcess(offscreenCanvas);
846 
847     auto imageCache = offscreenSurface->GetImageSnapshot();
848     if (imageCache == nullptr) {
849         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect imageCache snapshot null");
850         return;
851     }
852     auto data = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(imageCache), std::move(imageRect));
853     canvas.SetEffectData(std::move(data));
854 }
855 
ApplyBackgroundEffectFallback(const RSProperties & properties,RSPaintFilterCanvas & canvas)856 void RSPropertiesPainter::ApplyBackgroundEffectFallback(const RSProperties& properties, RSPaintFilterCanvas& canvas)
857 {
858     RS_TRACE_FUNC();
859     auto parentNode = properties.backref_.lock();
860     while (parentNode && !parentNode->IsInstanceOf<RSEffectRenderNode>()) {
861         parentNode = parentNode->GetParent().lock();
862     }
863     if (!parentNode) {
864         ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffectFallback: parentNode null, draw filter failed.");
865         return;
866     }
867     auto& filter = parentNode->GetRenderProperties().GetBackgroundFilter();
868     if (filter == nullptr || !filter->IsValid()) {
869         ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffectFallback: parent EffectRenderNode has no filter, "
870                    "draw filter failed.");
871         return;
872     }
873     DrawFilter(properties, canvas, FilterType::BACKGROUND_FILTER, std::nullopt, filter);
874 }
875 
ClipVisibleCanvas(const RSProperties & properties,RSPaintFilterCanvas & canvas)876 void RSPropertiesPainter::ClipVisibleCanvas(const RSProperties& properties, RSPaintFilterCanvas& canvas)
877 {
878     canvas.ResetMatrix();
879     auto visibleRect = canvas.GetVisibleRect();
880     visibleRect.Round();
881     auto visibleIRect = Drawing::RectI(
882         static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
883         static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
884     if (!visibleIRect.IsEmpty()) {
885         canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
886     }
887 }
888 
ApplyBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)889 void RSPropertiesPainter::ApplyBackgroundEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
890 {
891     const auto& effectData = canvas.GetEffectData();
892     if (effectData == nullptr || effectData->cachedImage_ == nullptr
893         || !(RSSystemProperties::GetEffectMergeEnabled() && RSFilterCacheManager::isCCMEffectMergeEnable_)) {
894         // no effectData available, draw background filter in fallback method
895         ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffect: effectData null, try fallback method.");
896         ApplyBackgroundEffectFallback(properties, canvas);
897         return;
898     }
899     RS_TRACE_FUNC();
900     Drawing::AutoCanvasRestore acr(canvas, true);
901     ClipVisibleCanvas(properties, canvas);
902     Drawing::Brush brush;
903     canvas.AttachBrush(brush);
904     // dstRect: canvas clip region
905     Drawing::Rect dstRect = canvas.GetDeviceClipBounds();
906     // srcRect: map dstRect onto cache coordinate
907     Drawing::Rect srcRect = dstRect;
908     srcRect.Offset(-effectData->cachedRect_.GetLeft(), -effectData->cachedRect_.GetTop());
909     canvas.DrawImageRect(*effectData->cachedImage_, srcRect, dstRect,
910                          Drawing::SamplingOptions(), Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
911     canvas.DetachBrush();
912 }
913 
GetPixelStretchDirtyRect(RectI & dirtyPixelStretch,const RSProperties & properties,const bool isAbsCoordinate)914 void RSPropertiesPainter::GetPixelStretchDirtyRect(RectI& dirtyPixelStretch,
915     const RSProperties& properties, const bool isAbsCoordinate)
916 {
917     auto& pixelStretch = properties.GetPixelStretch();
918     if (!pixelStretch.has_value()) {
919         return;
920     }
921     auto boundsRect = properties.GetBoundsRect();
922     auto scaledBounds = RectF(boundsRect.left_ - pixelStretch->x_, boundsRect.top_ - pixelStretch->y_,
923         boundsRect.width_ + pixelStretch->x_ + pixelStretch->z_,
924         boundsRect.height_ + pixelStretch->y_ + pixelStretch->w_);
925     auto geoPtr = properties.GetBoundsGeometry();
926     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
927     auto drawingRect = Rect2DrawingRect(scaledBounds);
928     matrix.MapRect(drawingRect, drawingRect);
929     dirtyPixelStretch.left_ = std::floor(drawingRect.GetLeft());
930     dirtyPixelStretch.top_ = std::floor(drawingRect.GetTop());
931     dirtyPixelStretch.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
932     dirtyPixelStretch.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
933 }
934 
GetForegroundEffectDirtyRect(RectI & dirtyForegroundEffect,const RSProperties & properties,const bool isAbsCoordinate)935 void RSPropertiesPainter::GetForegroundEffectDirtyRect(RectI& dirtyForegroundEffect,
936     const RSProperties& properties, const bool isAbsCoordinate)
937 {
938     std::shared_ptr<RSFilter> foregroundFilter = nullptr;
939     if (RSProperties::IS_UNI_RENDER) {
940         foregroundFilter = properties.GetForegroundFilterCache();
941     } else {
942         foregroundFilter = properties.GetForegroundFilter();
943     }
944     if (!foregroundFilter) {
945         return;
946     }
947 
948     if (foregroundFilter->GetFilterType() == RSFilter::FOREGROUND_EFFECT) {
949         float dirtyExtension =
950             std::static_pointer_cast<RSForegroundEffectFilter>(foregroundFilter)->GetDirtyExtension();
951         auto boundsRect = properties.GetBoundsRect();
952         auto scaledBounds = boundsRect.MakeOutset(dirtyExtension);
953         auto& geoPtr = properties.GetBoundsGeometry();
954         Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
955         auto drawingRect = Rect2DrawingRect(scaledBounds);
956         matrix.MapRect(drawingRect, drawingRect);
957         dirtyForegroundEffect.left_ = std::floor(drawingRect.GetLeft());
958         dirtyForegroundEffect.top_ = std::floor(drawingRect.GetTop());
959         dirtyForegroundEffect.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
960         dirtyForegroundEffect.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
961     } else if (foregroundFilter->GetFilterType() == RSFilter::COLORFUL_SHADOW) {
962         if (properties.IsShadowValid()) {
963             GetShadowDirtyRect(dirtyForegroundEffect, properties, nullptr, false, true);
964         }
965     }
966 }
967 
968 // calculate the distortion effect's dirty area
GetDistortionEffectDirtyRect(RectI & dirtyDistortionEffect,const RSProperties & properties)969 void RSPropertiesPainter::GetDistortionEffectDirtyRect(RectI& dirtyDistortionEffect, const RSProperties& properties)
970 {
971     // if the distortionK > 0, set the dirty bounds to its maximum range value
972     auto distortionK = properties.GetDistortionK();
973     if (distortionK.has_value() && *distortionK > 0) {
974         int dirtyWidth = static_cast<int>(std::numeric_limits<int16_t>::max());
975         int dirtyBeginPoint = static_cast<int>(std::numeric_limits<int16_t>::min()) / PARAM_DOUBLE;
976         dirtyDistortionEffect.left_ = dirtyBeginPoint;
977         dirtyDistortionEffect.top_ = dirtyBeginPoint;
978         dirtyDistortionEffect.width_ = dirtyWidth;
979         dirtyDistortionEffect.height_ = dirtyWidth;
980     }
981 }
982 
DrawPixelStretch(const RSProperties & properties,RSPaintFilterCanvas & canvas)983 void RSPropertiesPainter::DrawPixelStretch(const RSProperties& properties, RSPaintFilterCanvas& canvas)
984 {
985     auto& pixelStretch = properties.GetPixelStretch();
986     if (!pixelStretch.has_value()) {
987         return;
988     }
989     auto surface = canvas.GetSurface();
990     if (surface == nullptr) {
991         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch surface null");
992         return;
993     }
994 
995     canvas.Save();
996     auto bounds = RSPropertiesPainter::Rect2DrawingRect(properties.GetBoundsRect());
997     canvas.ClipRect(bounds, Drawing::ClipOp::INTERSECT, false);
998     auto tmpBounds = canvas.GetDeviceClipBounds();
999     Drawing::Rect clipBounds(
1000         tmpBounds.GetLeft(), tmpBounds.GetTop(), tmpBounds.GetRight() - 1, tmpBounds.GetBottom() - 1);
1001     canvas.Restore();
1002 
1003     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertiesPainter::DrawPixelStretch, right: %f, bottom: %f",
1004         tmpBounds.GetRight(), tmpBounds.GetBottom());
1005 
1006     /*  Calculates the relative coordinates of the clipbounds
1007         with respect to the origin of the current canvas coordinates */
1008     Drawing::Matrix worldToLocalMat;
1009     if (!canvas.GetTotalMatrix().Invert(worldToLocalMat)) {
1010         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch get invert matrix failed.");
1011     }
1012     Drawing::Rect localClipBounds;
1013     Drawing::Rect fClipBounds(clipBounds.GetLeft(), clipBounds.GetTop(), clipBounds.GetRight(),
1014         clipBounds.GetBottom());
1015     if (!worldToLocalMat.MapRect(localClipBounds, fClipBounds)) {
1016         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch map rect failed.");
1017         return;
1018     }
1019 
1020     if (!bounds.Intersect(localClipBounds)) {
1021         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch intersect clipbounds failed");
1022         return;
1023     }
1024 
1025     auto scaledBounds = Drawing::Rect(bounds.GetLeft() - pixelStretch->x_, bounds.GetTop() - pixelStretch->y_,
1026         bounds.GetRight() + pixelStretch->z_, bounds.GetBottom() + pixelStretch->w_);
1027     if (!scaledBounds.IsValid() || !bounds.IsValid() || !clipBounds.IsValid()) {
1028         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch invalid scaled bounds");
1029         return;
1030     }
1031 
1032     Drawing::RectI rectI(static_cast<int>(fClipBounds.GetLeft()), static_cast<int>(fClipBounds.GetTop()),
1033         static_cast<int>(fClipBounds.GetRight()), static_cast<int>(fClipBounds.GetBottom()));
1034     auto image = surface->GetImageSnapshot(rectI);
1035     if (image == nullptr) {
1036         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch image null");
1037         return;
1038     }
1039 
1040     Drawing::Brush brush;
1041     Drawing::Matrix inverseMat, rotateMat;
1042     auto& boundsGeo = (properties.GetBoundsGeometry());
1043     if (boundsGeo && !boundsGeo->IsEmpty()) {
1044         auto transMat = canvas.GetTotalMatrix();
1045         /* transMat.getSkewY() is the sin of the rotation angle(sin0 = 0,sin90 =1 sin180 = 0,sin270 = -1),
1046             if transMat.getSkewY() is not 0 or -1 or 1,the rotation angle is not a multiple of 90,not Stretch*/
1047         auto skewY = transMat.Get(Drawing::Matrix::SKEW_Y);
1048         if (ROSEN_EQ(skewY, 0.f) || ROSEN_EQ(skewY, 1.f) ||
1049             ROSEN_EQ(skewY, -1.f)) {
1050         } else {
1051             ROSEN_LOGD("rotate degree is not 0 or 90 or 180 or 270,return.");
1052             return;
1053         }
1054         rotateMat.SetScale(transMat.Get(Drawing::Matrix::SCALE_X), transMat.Get(Drawing::Matrix::SCALE_Y));
1055         rotateMat.Set(Drawing::Matrix::SKEW_X, transMat.Get(Drawing::Matrix::SKEW_X));
1056         rotateMat.Set(Drawing::Matrix::SKEW_Y, transMat.Get(Drawing::Matrix::SKEW_Y));
1057         rotateMat.PreTranslate(-bounds.GetLeft(), -bounds.GetTop());
1058         rotateMat.PostTranslate(bounds.GetLeft(), bounds.GetTop());
1059 
1060         Drawing::Rect transBounds;
1061         rotateMat.MapRect(transBounds, bounds);
1062         rotateMat.Set(Drawing::Matrix::TRANS_X, bounds.GetLeft() - transBounds.GetLeft());
1063         rotateMat.Set(Drawing::Matrix::TRANS_Y, bounds.GetTop() - transBounds.GetTop());
1064         if (!rotateMat.Invert(inverseMat)) {
1065             ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch get invert matrix failed.");
1066         }
1067     }
1068 
1069     canvas.Save();
1070     canvas.Translate(bounds.GetLeft(), bounds.GetTop());
1071     Drawing::SamplingOptions samplingOptions;
1072     constexpr static float EPS = 1e-5f;
1073     auto pixelStretchTileMode = static_cast<Drawing::TileMode>(properties.GetPixelStretchTileMode());
1074     if (pixelStretch->x_ > EPS || pixelStretch->y_ > EPS || pixelStretch->z_ > EPS || pixelStretch->w_ > EPS) {
1075         brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1076             *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1077         canvas.AttachBrush(brush);
1078         canvas.DrawRect(Drawing::Rect(-pixelStretch->x_, -pixelStretch->y_,
1079             -pixelStretch->x_ + scaledBounds.GetWidth(), -pixelStretch->y_ + scaledBounds.GetHeight()));
1080         canvas.DetachBrush();
1081     } else {
1082         inverseMat.PostScale(scaledBounds.GetWidth() / bounds.GetWidth(),
1083             scaledBounds.GetHeight() / bounds.GetHeight());
1084         brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1085             *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1086 
1087         canvas.Translate(-pixelStretch->x_, -pixelStretch->y_);
1088         canvas.AttachBrush(brush);
1089         canvas.DrawRect(Drawing::Rect(pixelStretch->x_, pixelStretch->y_,
1090             pixelStretch->x_ + bounds.GetWidth(), pixelStretch->y_ + bounds.GetHeight()));
1091         canvas.DetachBrush();
1092     }
1093     canvas.Restore();
1094 }
1095 
CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)1096 Drawing::ColorQuad RSPropertiesPainter::CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)
1097 {
1098     // create a 1x1 SkPixmap
1099     uint32_t pixel[1] = { 0 };
1100     Drawing::ImageInfo single_pixel_info(1, 1, Drawing::ColorType::COLORTYPE_RGBA_8888,
1101         Drawing::AlphaType::ALPHATYPE_PREMUL);
1102     Drawing::Bitmap single_pixel;
1103     single_pixel.Build(single_pixel_info, single_pixel_info.GetBytesPerPixel());
1104     single_pixel.SetPixels(pixel);
1105 
1106     // resize snapshot to 1x1 to calculate average color
1107     // kMedium_SkFilterQuality will do bilerp + mipmaps for down-scaling, we can easily get average color
1108     imageSnapshot->ScalePixels(single_pixel,
1109         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR));
1110     // convert color format and return average color
1111     return SkColor4f::FromBytes_RGBA(pixel[0]).toSkColor();
1112 }
1113 
GetAndResetBlurCnt()1114 int RSPropertiesPainter::GetAndResetBlurCnt()
1115 {
1116     auto blurCnt = g_blurCnt;
1117     g_blurCnt = 0;
1118     return blurCnt;
1119 }
1120 
DrawBackground(const RSProperties & properties,RSPaintFilterCanvas & canvas,bool isAntiAlias,bool isSurfaceView)1121 void RSPropertiesPainter::DrawBackground(const RSProperties& properties, RSPaintFilterCanvas& canvas,
1122     bool isAntiAlias, bool isSurfaceView)
1123 {
1124     // only disable antialias when background is rect and g_forceBgAntiAlias is false
1125     bool antiAlias = g_forceBgAntiAlias || !properties.GetCornerRadius().IsZero();
1126     // clip
1127     if (properties.GetClipBounds() != nullptr) {
1128         auto& path = properties.GetClipBounds()->GetDrawingPath();
1129         canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, antiAlias);
1130     } else if (properties.GetClipToBounds()) {
1131         if (properties.GetCornerRadius().IsZero()) {
1132             canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, isAntiAlias);
1133         } else {
1134             canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1135         }
1136     } else if (properties.GetClipToRRect()) {
1137         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1138     }
1139     // paint backgroundColor
1140     Drawing::Brush brush;
1141     brush.SetAntiAlias(antiAlias);
1142     auto bgColor = properties.GetBackgroundColor();
1143     if (bgColor != RgbPalette::Transparent() && !isSurfaceView) {
1144         brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
1145         canvas.AttachBrush(brush);
1146         canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1147         canvas.DetachBrush();
1148     }
1149     if (const auto& bgShader = properties.GetBackgroundShader()) {
1150         Drawing::AutoCanvasRestore acr(canvas, true);
1151         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1152         auto shaderEffect = bgShader->GetDrawingShader();
1153         brush.SetShaderEffect(shaderEffect);
1154         canvas.DrawBackground(brush);
1155     }
1156     if (const auto& bgImage = properties.GetBgImage()) {
1157         Drawing::AutoCanvasRestore acr(canvas, true);
1158         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1159         auto boundsRect = Rect2DrawingRect(properties.GetBoundsRect());
1160         bgImage->SetDstRect(properties.GetBgImageRect());
1161         canvas.AttachBrush(brush);
1162         bgImage->CanvasDrawImage(canvas, boundsRect, Drawing::SamplingOptions(), true);
1163         canvas.DetachBrush();
1164     }
1165 }
1166 
SetBgAntiAlias(bool forceBgAntiAlias)1167 void RSPropertiesPainter::SetBgAntiAlias(bool forceBgAntiAlias)
1168 {
1169     g_forceBgAntiAlias = forceBgAntiAlias;
1170 }
1171 
GetBgAntiAlias()1172 bool RSPropertiesPainter::GetBgAntiAlias()
1173 {
1174     return g_forceBgAntiAlias;
1175 }
1176 
DrawFrame(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::DrawCmdListPtr & cmds)1177 void RSPropertiesPainter::DrawFrame(
1178     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::DrawCmdListPtr& cmds)
1179 {
1180     if (cmds == nullptr) {
1181         return;
1182     }
1183     Drawing::Matrix mat;
1184     if (GetGravityMatrix(
1185             properties.GetFrameGravity(), properties.GetFrameRect(), cmds->GetWidth(), cmds->GetHeight(), mat)) {
1186         canvas.ConcatMatrix(mat);
1187     }
1188     auto frameRect = Rect2DrawingRect(properties.GetFrameRect());
1189     cmds->Playback(canvas, &frameRect);
1190 }
1191 
GetRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)1192 RRect RSPropertiesPainter::GetRRectForDrawingBorder(const RSProperties& properties,
1193     const std::shared_ptr<RSBorder>& border, const bool isOutline)
1194 {
1195     if (!border) {
1196         return RRect();
1197     }
1198 
1199     return isOutline ?
1200         RRect(properties.GetRRect().rect_.MakeOutset(border->GetWidthFour()), border->GetRadiusFour()) :
1201         properties.GetRRect();
1202 }
1203 
GetInnerRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)1204 RRect RSPropertiesPainter::GetInnerRRectForDrawingBorder(const RSProperties& properties,
1205     const std::shared_ptr<RSBorder>& border, const bool isOutline)
1206 {
1207     if (!border) {
1208         return RRect();
1209     }
1210     return isOutline ? properties.GetRRect() : properties.GetInnerRRect();
1211 }
1212 
1213 static std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder = nullptr;
1214 
GetPhongShaderBuilder()1215 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPropertiesPainter::GetPhongShaderBuilder()
1216 {
1217     if (phongShaderBuilder) {
1218         return phongShaderBuilder;
1219     }
1220     std::shared_ptr<Drawing::RuntimeEffect> lightEffect_;
1221     const static std::string lightString(R"(
1222         uniform vec4 lightPos[12];
1223         uniform vec4 viewPos[12];
1224         uniform vec4 specularLightColor[12];
1225         uniform float specularStrength[12];
1226 
1227         mediump vec4 main(vec2 drawing_coord) {
1228             vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
1229             float ambientStrength = 0.0;
1230             vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
1231             float diffuseStrength = 0.0;
1232             float shininess = 8.0;
1233             mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
1234             vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
1235             // ambient
1236             vec4 ambient = lightColor * ambientStrength;
1237             vec3 norm = normalize(NormalMap.rgb);
1238 
1239             for (int i = 0; i < 12; i++) {
1240                 if (abs(specularStrength[i]) > 0.01) {
1241                     vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
1242                     float diff = max(dot(norm, lightDir), 0.0);
1243                     vec4 diffuse = diff * lightColor;
1244                     vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
1245                     vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
1246                     float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
1247                     vec4 specular = lightColor * spec; // multiply color of incident light
1248                     vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
1249                     vec4 specularColor = specularLightColor[i];
1250                     fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
1251                 }
1252             }
1253             return fragColor;
1254         }
1255     )");
1256     std::shared_ptr<Drawing::RuntimeEffect> lightEffect = Drawing::RuntimeEffect::CreateForShader(lightString);
1257     if (!lightEffect) {
1258         ROSEN_LOGE("light effect error");
1259         return phongShaderBuilder;
1260     }
1261     lightEffect_ = std::move(lightEffect);
1262     phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect_);
1263     return phongShaderBuilder;
1264 }
1265 
DrawLight(const RSProperties & properties,Drawing::Canvas & canvas)1266 void RSPropertiesPainter::DrawLight(const RSProperties& properties, Drawing::Canvas& canvas)
1267 {
1268     auto lightBuilder = GetPhongShaderBuilder();
1269     if (!lightBuilder) {
1270         return;
1271     }
1272     const auto& lightSourcesAndPosMap = properties.GetIlluminated()->GetLightSourcesAndPosMap();
1273     if (lightSourcesAndPosMap.empty()) {
1274         ROSEN_LOGD("RSPropertiesPainter::DrawLight lightSourceList is empty!");
1275         return;
1276     }
1277     std::vector<std::pair<std::shared_ptr<RSLightSource>, Vector4f>> lightSourcesAndPosVec(
1278         lightSourcesAndPosMap.begin(), lightSourcesAndPosMap.end());
1279     if (lightSourcesAndPosVec.size() > MAX_LIGHT_SOURCES) {
1280         std::sort(lightSourcesAndPosVec.begin(), lightSourcesAndPosVec.end(), [](const auto& x, const auto& y) {
1281             return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
1282                    y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
1283         });
1284     }
1285     DrawLightInner(properties, canvas, lightBuilder, lightSourcesAndPosVec);
1286 }
1287 
DrawLightInner(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,const std::vector<std::pair<std::shared_ptr<RSLightSource>,Vector4f>> & lightSourcesAndPosVec)1288 void RSPropertiesPainter::DrawLightInner(const RSProperties& properties, Drawing::Canvas& canvas,
1289     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder,
1290     const std::vector<std::pair<std::shared_ptr<RSLightSource>, Vector4f>>& lightSourcesAndPosVec)
1291 {
1292     auto cnt = 0;
1293     constexpr int vectorLen = 4;
1294     float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1295     float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1296     float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1297     std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
1298 
1299     auto iter = lightSourcesAndPosVec.begin();
1300     while (iter != lightSourcesAndPosVec.end() && cnt < MAX_LIGHT_SOURCES) {
1301         auto lightPos = iter->second;
1302         auto lightIntensity = iter->first->GetLightIntensity();
1303         auto lightColor = iter->first->GetLightColor();
1304         Vector4f lightColorVec =
1305             Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
1306         for (int i = 0; i < vectorLen; i++) {
1307             lightPosArray[cnt * vectorLen + i] = lightPos[i];
1308             viewPosArray[cnt * vectorLen + i] = lightPos[i];
1309             lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
1310         }
1311         lightIntensityArray[cnt] = lightIntensity;
1312         iter++;
1313         cnt++;
1314     }
1315     lightBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
1316     lightBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
1317     lightBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
1318     Drawing::Pen pen;
1319     Drawing::Brush brush;
1320     pen.SetAntiAlias(true);
1321     brush.SetAntiAlias(true);
1322     auto illuminatedType = properties.GetIlluminated()->GetIlluminatedType();
1323     ROSEN_LOGD("RSPropertiesPainter::DrawLight illuminatedType:%{public}d", illuminatedType);
1324     if (illuminatedType == IlluminatedType::CONTENT) {
1325         DrawContentLight(properties, canvas, lightBuilder, brush, lightIntensityArray);
1326     } else if (illuminatedType == IlluminatedType::BORDER) {
1327         DrawBorderLight(properties, canvas, lightBuilder, pen, lightIntensityArray);
1328     } else if (illuminatedType == IlluminatedType::BORDER_CONTENT) {
1329         DrawContentLight(properties, canvas, lightBuilder, brush, lightIntensityArray);
1330         DrawBorderLight(properties, canvas, lightBuilder, pen, lightIntensityArray);
1331     }
1332 }
1333 
DrawContentLight(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray)1334 void RSPropertiesPainter::DrawContentLight(const RSProperties& properties, Drawing::Canvas& canvas,
1335     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
1336     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray)
1337 {
1338     // content light
1339     std::shared_ptr<Drawing::ShaderEffect> shader;
1340     constexpr float contentIntensityCoefficient = 0.3f;
1341     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
1342     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
1343         specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
1344     }
1345     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
1346     shader = lightBuilder->MakeShader(nullptr, false);
1347     brush.SetShaderEffect(shader);
1348     canvas.AttachBrush(brush);
1349     canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1350     canvas.DetachBrush();
1351 }
1352 
DrawBorderLight(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray)1353 void RSPropertiesPainter::DrawBorderLight(const RSProperties& properties, Drawing::Canvas& canvas,
1354     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
1355     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray)
1356 {
1357     // border light
1358     std::shared_ptr<Drawing::ShaderEffect> shader;
1359     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
1360     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
1361         specularStrengthArr[i] = lightIntensityArray[i];
1362     }
1363     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
1364     shader = lightBuilder->MakeShader(nullptr, false);
1365     pen.SetShaderEffect(shader);
1366     float borderWidth = std::ceil(properties.GetIlluminatedBorderWidth());
1367     pen.SetWidth(borderWidth);
1368     auto borderRect = properties.GetRRect().rect_;
1369     float borderRadius = properties.GetRRect().radius_[0].x_;
1370     auto borderRRect = RRect(RectF(borderRect.left_ + borderWidth / 2.0f, borderRect.top_ + borderWidth / 2.0f,
1371         borderRect.width_ - borderWidth, borderRect.height_ - borderWidth),
1372         borderRadius - borderWidth / 2.0f, borderRadius - borderWidth / 2.0f);
1373     canvas.AttachPen(pen);
1374     canvas.DrawRoundRect(RRect2DrawingRRect(borderRRect));
1375     canvas.DetachPen();
1376 }
1377 
DrawBorderBase(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool isOutline)1378 void RSPropertiesPainter::DrawBorderBase(const RSProperties& properties, Drawing::Canvas& canvas,
1379     const std::shared_ptr<RSBorder>& border, const bool isOutline)
1380 {
1381     if (!border || !border->HasBorder()) {
1382         return;
1383     }
1384 
1385     Drawing::Brush brush;
1386     Drawing::Pen pen;
1387     brush.SetAntiAlias(true);
1388     pen.SetAntiAlias(true);
1389     if (border->ApplyFillStyle(brush)) {
1390         auto roundRect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
1391         auto innerRoundRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(
1392             properties, border, isOutline));
1393         canvas.AttachBrush(brush);
1394         canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
1395         canvas.DetachBrush();
1396     } else {
1397         bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
1398         if (isZero && border->ApplyFourLine(pen)) {
1399             RectF rectf = isOutline ?
1400                 properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
1401             border->PaintFourLine(canvas, pen, rectf);
1402         } else if (border->ApplyPathStyle(pen)) {
1403             auto borderWidth = border->GetWidth();
1404             RRect rrect = GetRRectForDrawingBorder(properties, border, isOutline);
1405             rrect.rect_.width_ -= borderWidth;
1406             rrect.rect_.height_ -= borderWidth;
1407             rrect.rect_.Move(borderWidth / PARAM_DOUBLE, borderWidth / PARAM_DOUBLE);
1408             Drawing::Path borderPath;
1409             borderPath.AddRoundRect(RRect2DrawingRRect(rrect));
1410             canvas.AttachPen(pen);
1411             canvas.DrawPath(borderPath);
1412             canvas.DetachPen();
1413         } else {
1414             RSBorderGeo borderGeo;
1415             borderGeo.rrect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
1416             borderGeo.innerRRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(properties, border, isOutline));
1417             auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
1418             auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
1419             borderGeo.center = { centerX, centerY };
1420             auto rect = borderGeo.rrect.GetRect();
1421             Drawing::AutoCanvasRestore acr(canvas, false);
1422             Drawing::SaveLayerOps slr(&rect, nullptr);
1423             canvas.SaveLayer(slr);
1424             border->DrawBorders(canvas, pen, borderGeo);
1425         }
1426     }
1427 }
1428 
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas)1429 void RSPropertiesPainter::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas)
1430 {
1431     auto border = properties.GetBorder();
1432     if (border && border->HasBorder()) {
1433         DrawBorderBase(properties, canvas, border, false);
1434     }
1435 }
1436 
GetOutlineDirtyRect(RectI & dirtyOutline,const RSProperties & properties,const bool isAbsCoordinate)1437 void RSPropertiesPainter::GetOutlineDirtyRect(RectI& dirtyOutline,
1438     const RSProperties& properties, const bool isAbsCoordinate)
1439 {
1440     auto outline = properties.GetOutline();
1441     if (!outline || !outline->HasBorder()) {
1442         return;
1443     }
1444 
1445     auto& geoPtr = properties.GetBoundsGeometry();
1446     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
1447     auto drawingRect = Rect2DrawingRect(GetRRectForDrawingBorder(properties, outline, true).rect_);
1448     matrix.MapRect(drawingRect, drawingRect);
1449     dirtyOutline.left_ = std::floor(drawingRect.GetLeft());
1450     dirtyOutline.top_ = std::floor(drawingRect.GetTop());
1451     dirtyOutline.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
1452     dirtyOutline.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
1453 }
1454 
DrawOutline(const RSProperties & properties,Drawing::Canvas & canvas)1455 void RSPropertiesPainter::DrawOutline(const RSProperties& properties, Drawing::Canvas& canvas)
1456 {
1457     auto outline = properties.GetOutline();
1458     if (outline && outline->HasBorder()) {
1459         DrawBorderBase(properties, canvas, outline, true);
1460     }
1461 }
1462 
DrawForegroundColor(const RSProperties & properties,Drawing::Canvas & canvas)1463 void RSPropertiesPainter::DrawForegroundColor(const RSProperties& properties, Drawing::Canvas& canvas)
1464 {
1465     auto bgColor = properties.GetForegroundColor();
1466     if (bgColor == RgbPalette::Transparent()) {
1467         return;
1468     }
1469     // clip
1470     if (properties.GetClipBounds() != nullptr) {
1471         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1472     } else if (properties.GetClipToBounds()) {
1473         canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, true);
1474     } else if (properties.GetClipToRRect()) {
1475         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, true);
1476     }
1477 
1478     Drawing::Brush brush;
1479     brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
1480     brush.SetAntiAlias(true);
1481     canvas.AttachBrush(brush);
1482     canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1483     canvas.DetachBrush();
1484 }
1485 
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas,Drawing::Rect maskBounds)1486 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas, Drawing::Rect maskBounds)
1487 {
1488     std::shared_ptr<RSMask> mask = properties.GetMask();
1489     if (mask == nullptr) {
1490         return;
1491     }
1492     if (mask->IsSvgMask() && !mask->GetSvgDom() && !mask->GetSvgPicture()) {
1493         ROSEN_LOGD("RSPropertiesPainter::DrawMask not has Svg Mask property");
1494         return;
1495     }
1496 
1497     canvas.Save();
1498     Drawing::SaveLayerOps slr(&maskBounds, nullptr);
1499     canvas.SaveLayer(slr);
1500     uint32_t tmpLayer = canvas.GetSaveCount();
1501 
1502     Drawing::Brush maskfilter;
1503     Drawing::Filter filter;
1504     filter.SetColorFilter(Drawing::ColorFilter::CreateComposeColorFilter(
1505         *(Drawing::ColorFilter::CreateLumaColorFilter()), *(Drawing::ColorFilter::CreateSrgbGammaToLinear())));
1506     maskfilter.SetFilter(filter);
1507     Drawing::SaveLayerOps slrMask(&maskBounds, &maskfilter);
1508     canvas.SaveLayer(slrMask);
1509     if (mask->IsSvgMask()) {
1510         Drawing::AutoCanvasRestore maskSave(canvas, true);
1511         canvas.Translate(maskBounds.GetLeft() + mask->GetSvgX(), maskBounds.GetTop() + mask->GetSvgY());
1512         canvas.Scale(mask->GetScaleX(), mask->GetScaleY());
1513         if (mask->GetSvgDom()) {
1514             canvas.DrawSVGDOM(mask->GetSvgDom());
1515         } else if (mask->GetSvgPicture()) {
1516             canvas.DrawPicture(*mask->GetSvgPicture());
1517         }
1518     } else if (mask->IsGradientMask()) {
1519         Drawing::AutoCanvasRestore maskSave(canvas, true);
1520         canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1521         Drawing::Rect rect = Drawing::Rect(
1522             0, 0, maskBounds.GetWidth(), maskBounds.GetHeight());
1523         canvas.AttachBrush(mask->GetMaskBrush());
1524         canvas.DrawRect(rect);
1525         canvas.DetachBrush();
1526     } else if (mask->IsPathMask()) {
1527         Drawing::AutoCanvasRestore maskSave(canvas, true);
1528         canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1529         canvas.AttachBrush(mask->GetMaskBrush());
1530         canvas.AttachPen(mask->GetMaskPen());
1531         canvas.DrawPath(*mask->GetMaskPath());
1532         canvas.DetachBrush();
1533         canvas.DetachPen();
1534     } else if (mask->IsPixelMapMask()) {
1535         Drawing::AutoCanvasRestore arc(canvas, true);
1536         if (mask->GetImage()) {
1537             canvas.DrawImage(*mask->GetImage(), 0.f, 0.f, Drawing::SamplingOptions());
1538         }
1539     }
1540 
1541     // back to mask layer
1542     canvas.RestoreToCount(tmpLayer);
1543     // create content layer
1544     Drawing::Brush maskPaint;
1545     maskPaint.SetBlendMode(Drawing::BlendMode::SRC_IN);
1546     Drawing::SaveLayerOps slrContent(&maskBounds, &maskPaint);
1547     canvas.SaveLayer(slrContent);
1548     canvas.ClipRect(maskBounds, Drawing::ClipOp::INTERSECT, true);
1549 }
1550 
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas)1551 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas)
1552 {
1553     Drawing::Rect maskBounds = Rect2DrawingRect(properties.GetBoundsRect());
1554     DrawMask(properties, canvas, maskBounds);
1555 }
1556 
DrawSpherize(const RSProperties & properties,RSPaintFilterCanvas & canvas,const std::shared_ptr<Drawing::Surface> & spherizeSurface)1557 void RSPropertiesPainter::DrawSpherize(const RSProperties& properties, RSPaintFilterCanvas& canvas,
1558     const std::shared_ptr<Drawing::Surface>& spherizeSurface)
1559 {
1560     if (spherizeSurface == nullptr) {
1561         return;
1562     }
1563     if (spherizeSurface->Width() == 0 || spherizeSurface->Height() == 0) {
1564         return;
1565     }
1566     Drawing::AutoCanvasRestore acr(canvas, true);
1567     float canvasWidth = properties.GetBoundsRect().GetWidth();
1568     float canvasHeight = properties.GetBoundsRect().GetHeight();
1569 
1570     auto imageSnapshot = spherizeSurface->GetImageSnapshot();
1571     if (imageSnapshot == nullptr) {
1572         ROSEN_LOGE("RSPropertiesPainter::DrawCachedSpherizeSurface image is null");
1573         return;
1574     }
1575     int imageWidth = imageSnapshot->GetWidth();
1576     int imageHeight = imageSnapshot->GetHeight();
1577     if (imageWidth == 0 || imageHeight == 0) {
1578         return;
1579     }
1580     canvas.Scale(canvasWidth / imageWidth, canvasHeight / imageHeight);
1581 
1582     float width = imageWidth;
1583     float height = imageHeight;
1584     float degree = properties.GetSpherize();
1585     bool isWidthGreater = width > height;
1586     ROSEN_LOGI("RSPropertiesPainter::DrawCachedSpherizeSurface spherize degree [%{public}f]", degree);
1587 
1588     Drawing::Brush brush;
1589     brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
1590     Drawing::SamplingOptions samplingOptions;
1591     Drawing::Matrix scaleMat;
1592     brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1593         *imageSnapshot, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat));
1594     canvas.AttachBrush(brush);
1595 
1596     const Drawing::Point texCoords[4] = {
1597         {0.0f, 0.0f}, {width, 0.0f}, {width, height}, {0.0f, height}
1598     };
1599     float offsetSquare = 0.f;
1600     if (isWidthGreater) {
1601         offsetSquare = (width - height) * degree / 2.0; // half of the change distance
1602         width = width - (width - height) * degree;
1603     } else {
1604         offsetSquare = (height - width) * degree / 2.0; // half of the change distance
1605         height = height - (height - width) * degree;
1606     }
1607 
1608     float segmentWidthOne = width / 3.0;
1609     float segmentWidthTwo = width / 3.0 * 2.0;
1610     float segmentHeightOne = height / 3.0;
1611     float segmentHeightTwo = height / 3.0 * 2.0;
1612     float offsetSphereWidth = width / 6 * degree;
1613     float offsetSphereHeight = height / 6  * degree;
1614 
1615     const int PointNum = 12;
1616     Drawing::Point ctrlPoints[PointNum] = {
1617         // top edge control points
1618         {0.0f, 0.0f}, {segmentWidthOne, 0.0f}, {segmentWidthTwo, 0.0f}, {width, 0.0f},
1619         // right edge control points
1620         {width, segmentHeightOne}, {width, segmentHeightTwo},
1621         // bottom edge control points
1622         {width, height}, {segmentWidthTwo, height}, {segmentWidthOne, height}, {0.0f, height},
1623         // left edge control points
1624         {0.0f, segmentHeightTwo}, {0.0f, segmentHeightOne}
1625     };
1626     ctrlPoints[0].Offset(offsetSphereWidth, offsetSphereHeight); // top left control point
1627     ctrlPoints[3].Offset(-offsetSphereWidth, offsetSphereHeight); // top right control point
1628     ctrlPoints[6].Offset(-offsetSphereWidth, -offsetSphereHeight); // bottom right control point
1629     ctrlPoints[9].Offset(offsetSphereWidth, -offsetSphereHeight); // bottom left control point
1630     if (isWidthGreater) {
1631         for (int i = 0; i < PointNum; ++i) {
1632             ctrlPoints[i].Offset(offsetSquare, 0);
1633         }
1634     } else {
1635         for (int i = 0; i < PointNum; ++i) {
1636             ctrlPoints[i].Offset(0, offsetSquare);
1637         }
1638     }
1639     Drawing::Path path;
1640     path.MoveTo(ctrlPoints[0].GetX(), ctrlPoints[0].GetY());
1641     path.CubicTo(ctrlPoints[1], ctrlPoints[2], ctrlPoints[3]); // upper edge
1642     path.CubicTo(ctrlPoints[4], ctrlPoints[5], ctrlPoints[6]); // right edge
1643     path.CubicTo(ctrlPoints[7], ctrlPoints[8], ctrlPoints[9]); // bottom edge
1644     path.CubicTo(ctrlPoints[10], ctrlPoints[11], ctrlPoints[0]); // left edge
1645     canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, true);
1646     canvas.DrawPatch(ctrlPoints, nullptr, texCoords, Drawing::BlendMode::SRC_OVER);
1647     canvas.DetachBrush();
1648 }
1649 
DrawColorFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas)1650 void RSPropertiesPainter::DrawColorFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1651 {
1652     // if useEffect defined, use color filter from parent EffectView.
1653     auto& colorFilter = properties.GetColorFilter();
1654     if (colorFilter == nullptr) {
1655         return;
1656     }
1657     Drawing::AutoCanvasRestore acr(canvas, true);
1658     canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1659     Drawing::Brush brush;
1660     brush.SetAntiAlias(true);
1661     Drawing::Filter filter;
1662     filter.SetColorFilter(colorFilter);
1663     brush.SetFilter(filter);
1664     auto surface = canvas.GetSurface();
1665     if (surface == nullptr) {
1666         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter surface is null");
1667         return;
1668     }
1669     auto clipBounds = canvas.GetDeviceClipBounds();
1670     auto imageSnapshot = surface->GetImageSnapshot(clipBounds);
1671     if (imageSnapshot == nullptr) {
1672         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter image is null");
1673         return;
1674     }
1675     imageSnapshot->HintCacheGpuResource();
1676     canvas.ResetMatrix();
1677     Drawing::SamplingOptions options(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
1678     canvas.AttachBrush(brush);
1679     canvas.DrawImageRect(*imageSnapshot, clipBounds, options);
1680     canvas.DetachBrush();
1681 }
1682 
DrawBinarizationShader(const RSProperties & properties,RSPaintFilterCanvas & canvas)1683 void RSPropertiesPainter::DrawBinarizationShader(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1684 {
1685     Drawing::AutoCanvasRestore acr(canvas, true);
1686     canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1687     auto drSurface = canvas.GetSurface();
1688     if (drSurface == nullptr) {
1689         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter drSurface is null");
1690         return;
1691     }
1692     auto clipBounds = canvas.GetDeviceClipBounds();
1693     auto imageSnapshot = drSurface->GetImageSnapshot(clipBounds);
1694     if (imageSnapshot == nullptr) {
1695         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter image is null");
1696         return;
1697     }
1698     auto& aiInvert = properties.GetAiInvert();
1699     Drawing::Matrix matrix;
1700     auto imageShader = Drawing::ShaderEffect::CreateImageShader(*imageSnapshot, Drawing::TileMode::CLAMP,
1701         Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
1702     float thresholdLow = aiInvert->z_ - aiInvert->w_;
1703     float thresholdHigh = aiInvert->z_ + aiInvert->w_;
1704     auto shader = MakeBinarizationShader(
1705         aiInvert->x_, aiInvert->y_, thresholdLow, thresholdHigh, imageShader);
1706     Drawing::Brush brush;
1707     brush.SetShaderEffect(shader);
1708     brush.SetAntiAlias(true);
1709     canvas.ResetMatrix();
1710     canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1711     canvas.DrawBackground(brush);
1712 }
1713 
MakeBinarizationShader(float low,float high,float thresholdLow,float thresholdHigh,std::shared_ptr<Drawing::ShaderEffect> imageShader)1714 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeBinarizationShader(float low, float high,
1715     float thresholdLow, float thresholdHigh,
1716     std::shared_ptr<Drawing::ShaderEffect> imageShader)
1717 {
1718     static constexpr char prog[] = R"(
1719         uniform mediump float ubo_low;
1720         uniform mediump float ubo_high;
1721         uniform mediump float ubo_thresholdLow;
1722         uniform mediump float ubo_thresholdHigh;
1723         uniform shader imageShader;
1724         mediump vec4 main(vec2 drawing_coord) {
1725             mediump vec3 c = imageShader(drawing_coord).rgb;
1726             float gray = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
1727             float lowRes = mix(ubo_high, -1.0, step(ubo_thresholdLow, gray));
1728             float highRes = mix(-1.0, ubo_low, step(ubo_thresholdHigh, gray));
1729             float midRes = (ubo_thresholdHigh - gray) * (ubo_high - ubo_low) /
1730             (ubo_thresholdHigh - ubo_thresholdLow) + ubo_low;
1731             float invertedGray = mix(midRes, max(lowRes, highRes), step(-0.5, max(lowRes, highRes)));
1732             mediump vec3 invert = vec3(invertedGray);
1733             mediump vec4 res = vec4(invert, 1.0);
1734             return res;
1735         }
1736     )";
1737     if (binarizationShaderEffect_ == nullptr) {
1738         binarizationShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
1739         if (binarizationShaderEffect_ == nullptr) {
1740             ROSEN_LOGE("MakeBinarizationShader::RuntimeShader effect error\n");
1741             return nullptr;
1742         }
1743     }
1744     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
1745         std::make_shared<Drawing::RuntimeShaderBuilder>(binarizationShaderEffect_);
1746     // aviod zero-divide in shader
1747     thresholdHigh = thresholdHigh <= thresholdLow ? thresholdHigh + 1e-6 : thresholdHigh;
1748     builder->SetChild("imageShader", imageShader);
1749     builder->SetUniform("ubo_low", low);
1750     builder->SetUniform("ubo_high", high);
1751     builder->SetUniform("ubo_thresholdLow", thresholdLow);
1752     builder->SetUniform("ubo_thresholdHigh", thresholdHigh);
1753     return builder->MakeShader(nullptr, false);
1754 }
1755 
DrawLightUpEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)1756 void RSPropertiesPainter::DrawLightUpEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1757 {
1758     Drawing::Surface* surface = canvas.GetSurface();
1759     if (surface == nullptr) {
1760         ROSEN_LOGD("RSPropertiesPainter::DrawLightUpEffect surface is null");
1761         return;
1762     }
1763     Drawing::AutoCanvasRestore acr(canvas, true);
1764     if (properties.GetClipBounds() != nullptr) {
1765         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1766     } else {
1767         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1768     }
1769 
1770     auto blender = MakeLightUpEffectBlender(properties.GetLightUpEffect());
1771     Drawing::Brush brush;
1772     brush.SetBlender(blender);
1773     canvas.DrawBackground(brush);
1774 }
1775 
MakeLightUpEffectBlender(const float lightUpDeg)1776 std::shared_ptr<Drawing::Blender> RSPropertiesPainter::MakeLightUpEffectBlender(const float lightUpDeg)
1777 {
1778     static constexpr char prog[] = R"(
1779         uniform half lightUpDeg;
1780 
1781         vec3 rgb2hsv(in vec3 c)
1782         {
1783             vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
1784             vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
1785             vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
1786             float d = q.x - min(q.w, q.y);
1787             float e = 1.0e-10;
1788             return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
1789         }
1790         vec3 hsv2rgb(in vec3 c)
1791         {
1792             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);
1793             return c.z * mix(vec3(1.0), rgb, c.y);
1794         }
1795         vec4 main(vec4 drawing_src, vec4 drawing_dst) {
1796             drawing_dst = max(drawing_dst, 0.0);
1797             vec3 c = vec3(drawing_dst.r, drawing_dst.g, drawing_dst.b);
1798             vec3 hsv = rgb2hsv(c);
1799             float satUpper = clamp(hsv.y * 1.2, 0.0, 1.0);
1800             hsv.y = mix(satUpper, hsv.y, lightUpDeg);
1801             hsv.z += lightUpDeg - 1.0;
1802             hsv.z = max(hsv.z, 0.0);
1803             return vec4(hsv2rgb(hsv), drawing_dst.a);
1804         }
1805     )";
1806     if (lightUpEffectBlender_ == nullptr) {
1807         lightUpEffectBlender_ = Drawing::RuntimeEffect::CreateForBlender(prog);
1808         if (lightUpEffectBlender_ == nullptr) {
1809             return nullptr;
1810         }
1811     }
1812     auto builder = std::make_shared<Drawing::RuntimeBlenderBuilder>(lightUpEffectBlender_);
1813     builder->SetUniform("lightUpDeg", lightUpDeg);
1814     return builder->MakeBlender();
1815 }
1816 
DrawDynamicLightUp(const RSProperties & properties,RSPaintFilterCanvas & canvas)1817 void RSPropertiesPainter::DrawDynamicLightUp(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1818 {
1819     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawDynamicLightUp, rate: %f, degree: %f, bounds: %s",
1820         properties.GetDynamicLightUpRate().value(), properties.GetDynamicLightUpDegree().value(),
1821         properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
1822     Drawing::Surface* surface = canvas.GetSurface();
1823     if (surface == nullptr) {
1824         ROSEN_LOGD("RSPropertiesPainter::DrawDynamicLightUp surface is null");
1825         return;
1826     }
1827 
1828     auto blender = MakeDynamicLightUpBlender(properties.GetDynamicLightUpRate().value() * canvas.GetAlpha(),
1829         properties.GetDynamicLightUpDegree().value() * canvas.GetAlpha());
1830     Drawing::Brush brush;
1831     brush.SetBlender(blender);
1832     canvas.DrawBackground(brush);
1833 }
1834 
MakeDynamicBrightnessBlender(const RSDynamicBrightnessPara & params)1835 std::shared_ptr<Drawing::Blender> RSPropertiesPainter::MakeDynamicBrightnessBlender(
1836     const RSDynamicBrightnessPara& params)
1837 {
1838     if (!RSSystemProperties::GetDynamicBrightnessEnabled()) {
1839         return nullptr;
1840     }
1841 
1842     auto builder = MakeDynamicBrightnessBuilder();
1843     if (!builder) {
1844         ROSEN_LOGE("RSPropertiesPainter::MakeDynamicBrightnessBlender make builder fail");
1845         return nullptr;
1846     }
1847 
1848     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertiesPainter::MakeDynamicBrightnessBlender");
1849     builder->SetUniform("ubo_fract", std::clamp(params.fraction_, 0.0f, 1.0f));
1850     builder->SetUniform("ubo_cubic", params.rates_.x_);
1851     builder->SetUniform("ubo_quad", params.rates_.y_);
1852     builder->SetUniform("ubo_rate", params.rates_.z_);
1853     builder->SetUniform("ubo_degree", params.rates_.w_);
1854     builder->SetUniform("ubo_baseSat", params.saturation_);
1855     builder->SetUniform("ubo_posr", params.posCoeff_.x_);
1856     builder->SetUniform("ubo_posg", params.posCoeff_.y_);
1857     builder->SetUniform("ubo_posb", params.posCoeff_.z_);
1858     builder->SetUniform("ubo_negr", params.negCoeff_.x_);
1859     builder->SetUniform("ubo_negg", params.negCoeff_.y_);
1860     builder->SetUniform("ubo_negb", params.negCoeff_.z_);
1861     return builder->MakeBlender();
1862 }
1863 
MakeDynamicBrightnessBuilder()1864 std::shared_ptr<Drawing::RuntimeBlenderBuilder> RSPropertiesPainter::MakeDynamicBrightnessBuilder()
1865 {
1866     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertiesPainter::MakeDynamicBrightnessBuilder");
1867     static constexpr char prog[] = R"(
1868         uniform half ubo_fract;
1869         uniform half ubo_rate;
1870         uniform half ubo_degree;
1871         uniform half ubo_cubic;
1872         uniform half ubo_quad;
1873         uniform half ubo_baseSat;
1874         uniform half ubo_posr;
1875         uniform half ubo_posg;
1876         uniform half ubo_posb;
1877         uniform half ubo_negr;
1878         uniform half ubo_negg;
1879         uniform half ubo_negb;
1880 
1881         const vec3 baseVec = vec3(0.2412016, 0.6922296, 0.0665688);
1882 
1883         half3 gray(half3 x, half4 coeff) {
1884             return coeff.x * x * x * x + coeff.y * x * x + coeff.z * x + coeff.w;
1885         }
1886         half3 sat(half3 inColor, half n, half3 pos, half3 neg) {
1887             half base = dot(inColor, baseVec) * (1.0 - n);
1888             half3 delta = base + inColor * n - inColor;
1889             half3 posDelta = inColor + delta * pos;
1890             half3 negDelta = inColor + delta * neg;
1891             half3 test = mix(negDelta, posDelta, step(0, delta));
1892             return test;
1893         }
1894 
1895         half4 main(half4 src, half4 dst) {
1896             half4 coeff = half4(ubo_cubic, ubo_quad, ubo_rate, ubo_degree);
1897             half3 color = gray(dst.rgb / (dst.a + 0.000001), coeff); // restore alpha-premul first
1898             half3 pos = half3(ubo_posr, ubo_posg, ubo_posb);
1899             half3 neg = half3(ubo_negr, ubo_negg, ubo_negb);
1900             color = sat(color, ubo_baseSat, pos, neg);
1901             color = clamp(color, 0.0, 1.0);
1902             color = mix(color, src.rgb, ubo_fract);
1903             half4 res = half4(mix(dst.rgb, color, src.a), 1.0);
1904             return dst.a * res; // alpha-premul
1905         }
1906     )";
1907     if (dynamicBrightnessBlenderEffect_ == nullptr) {
1908         dynamicBrightnessBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
1909         if (dynamicBrightnessBlenderEffect_ == nullptr) { return nullptr; }
1910     }
1911     return std::make_shared<Drawing::RuntimeBlenderBuilder>(dynamicBrightnessBlenderEffect_);
1912 }
1913 
MakeDynamicLightUpBlender(float dynamicLightUpRate,float dynamicLightUpDeg)1914 std::shared_ptr<Drawing::Blender> RSPropertiesPainter::MakeDynamicLightUpBlender(
1915     float dynamicLightUpRate, float dynamicLightUpDeg)
1916 {
1917     static constexpr char prog[] = R"(
1918         uniform float dynamicLightUpRate;
1919         uniform float dynamicLightUpDeg;
1920 
1921         vec4 main(vec4 drawing_src, vec4 drawing_dst) {
1922             float x = 0.299 * drawing_dst.r + 0.587 * drawing_dst.g + 0.114 * drawing_dst.b;
1923             float y = (0 - dynamicLightUpRate) * x + dynamicLightUpDeg;
1924             float R = clamp((drawing_dst.r + y), 0.0, 1.0);
1925             float G = clamp((drawing_dst.g + y), 0.0, 1.0);
1926             float B = clamp((drawing_dst.b + y), 0.0, 1.0);
1927             return vec4(R, G, B, 1.0);
1928         }
1929     )";
1930     if (dynamicLightUpBlenderEffect_ == nullptr) {
1931         dynamicLightUpBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
1932         if (dynamicLightUpBlenderEffect_ == nullptr) {
1933             return nullptr;
1934         }
1935     }
1936     auto builder = std::make_shared<Drawing::RuntimeBlenderBuilder>(dynamicLightUpBlenderEffect_);
1937     builder->SetUniform("dynamicLightUpRate", dynamicLightUpRate);
1938     builder->SetUniform("dynamicLightUpDeg", dynamicLightUpDeg);
1939     return builder->MakeBlender();
1940 }
1941 
DrawDynamicDim(const RSProperties & properties,RSPaintFilterCanvas & canvas)1942 void RSPropertiesPainter::DrawDynamicDim(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1943 {
1944     Drawing::Surface* surface = canvas.GetSurface();
1945     if (surface == nullptr) {
1946         ROSEN_LOGD("RSPropertiesPainter::DrawDynamicDim surface is null");
1947         return;
1948     }
1949     Drawing::AutoCanvasRestore acr(canvas, true);
1950     if (properties.GetClipBounds() != nullptr) {
1951         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1952     } else {
1953         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1954     }
1955 
1956     auto clipBounds = canvas.GetDeviceClipBounds();
1957     auto image = surface->GetImageSnapshot(clipBounds);
1958     if (image == nullptr) {
1959         ROSEN_LOGE("RSPropertiesPainter::DrawDynamicDim image is null");
1960         return;
1961     }
1962     Drawing::Matrix scaleMat;
1963     auto imageShader = Drawing::ShaderEffect::CreateImageShader(
1964         *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
1965         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), scaleMat);
1966     auto shader = MakeDynamicDimShader(properties.GetDynamicDimDegree().value(), imageShader);
1967     if (shader == nullptr) {
1968         ROSEN_LOGE("RSPropertiesPainter::DrawDynamicDim shader is null");
1969         return;
1970     }
1971     Drawing::Brush brush;
1972     brush.SetShaderEffect(shader);
1973     canvas.ResetMatrix();
1974     canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1975     canvas.DrawBackground(brush);
1976 }
1977 
MakeDynamicDimShader(float dynamicDimDeg,std::shared_ptr<Drawing::ShaderEffect> imageShader)1978 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeDynamicDimShader(
1979     float dynamicDimDeg, std::shared_ptr<Drawing::ShaderEffect> imageShader)
1980 {
1981     static constexpr char prog[] = R"(
1982         uniform half dynamicDimDeg;
1983         uniform shader imageShader;
1984 
1985         vec3 rgb2hsv(in vec3 c)
1986         {
1987             vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
1988             vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
1989             vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
1990             float d = q.x - min(q.w, q.y);
1991             float e = 1.0e-10;
1992             return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
1993         }
1994         vec3 hsv2rgb(in vec3 c)
1995         {
1996             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);
1997             return c.z * mix(vec3(1.0), rgb, c.y);
1998         }
1999         half4 main(float2 coord)
2000         {
2001             vec3 hsv = rgb2hsv(imageShader.eval(coord).rgb);
2002             float value = max(0.8, dynamicDimDeg); // 0.8 is min saturation ratio.
2003             hsv.y = hsv.y * (1.75 - value * 0.75); // saturation value [1.0 , 1.15].
2004             hsv.z = min(hsv.z * dynamicDimDeg, 1.0);
2005             return vec4(hsv2rgb(hsv), 1.0);
2006         }
2007     )";
2008     if (dynamicDimShaderEffect_ == nullptr) {
2009         dynamicDimShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
2010         if (dynamicDimShaderEffect_ == nullptr) {
2011             ROSEN_LOGE("MakeBinarizationShader::RuntimeShader effect error\n");
2012             return nullptr;
2013         }
2014     }
2015     std::shared_ptr<Drawing::ShaderEffect> children[] = {imageShader};
2016     size_t childCount = 1;
2017     auto data = std::make_shared<Drawing::Data>();
2018     data->BuildWithCopy(&dynamicDimDeg, sizeof(dynamicDimDeg));
2019     return dynamicDimShaderEffect_->MakeShader(data, children, childCount, nullptr, false);
2020 }
2021 
DrawParticle(const RSProperties & properties,RSPaintFilterCanvas & canvas)2022 void RSPropertiesPainter::DrawParticle(const RSProperties& properties, RSPaintFilterCanvas& canvas)
2023 {
2024     const auto& particleVector = properties.GetParticles();
2025     if (particleVector.GetParticleSize() == 0) {
2026         return;
2027     }
2028     const auto& particles = particleVector.GetParticleVector();
2029     auto bounds = properties.GetDrawRegion();
2030     auto imageCount = particleVector.GetParticleImageCount();
2031     auto imageVector = particleVector.GetParticleImageVector();
2032     auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
2033     if (particleDrawable != nullptr) {
2034         particleDrawable->Draw(canvas, bounds);
2035     }
2036 }
2037 
IsDangerousBlendMode(int blendMode,int blendApplyType)2038 bool RSPropertiesPainter::IsDangerousBlendMode(int blendMode, int blendApplyType)
2039 {
2040     static const uint32_t fastDangerousBit =
2041         (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
2042         (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
2043         (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
2044         (1 << static_cast<int>(Drawing::BlendMode::XOR));
2045     static const uint32_t offscreenDangerousBit =
2046         (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
2047         (1 << static_cast<int>(Drawing::BlendMode::SRC)) +
2048         (1 << static_cast<int>(Drawing::BlendMode::SRC_IN)) +
2049         (1 << static_cast<int>(Drawing::BlendMode::DST_IN)) +
2050         (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
2051         (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
2052         (1 << static_cast<int>(Drawing::BlendMode::DST_ATOP)) +
2053         (1 << static_cast<int>(Drawing::BlendMode::XOR)) +
2054         (1 << static_cast<int>(Drawing::BlendMode::MODULATE));
2055     uint32_t tmp = 1 << blendMode;
2056     if (blendApplyType == static_cast<int>(RSColorBlendApplyType::FAST)) {
2057         return tmp & fastDangerousBit;
2058     }
2059     return tmp & offscreenDangerousBit;
2060 }
2061 } // namespace Rosen
2062 } // namespace OHOS
2063