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