• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "property/rs_properties_painter.h"
17 #include "rs_trace.h"
18 
19 #include "common/rs_obj_abs_geometry.h"
20 #include "common/rs_optional_trace.h"
21 #include "pipeline/rs_effect_render_node.h"
22 #include "pipeline/rs_paint_filter_canvas.h"
23 #include "pipeline/rs_root_render_node.h"
24 #include "platform/common/rs_log.h"
25 #include "property/rs_point_light_manager.h"
26 #include "property/rs_properties_def.h"
27 #include "render/rs_blur_filter.h"
28 #include "render/rs_drawing_filter.h"
29 #include "render/rs_distortion_shader_filter.h"
30 #include "render/rs_foreground_effect_filter.h"
31 #include "render/rs_kawase_blur_shader_filter.h"
32 #include "render/rs_linear_gradient_blur_shader_filter.h"
33 #include "render/rs_skia_filter.h"
34 #include "render/rs_magnifier_shader_filter.h"
35 #include "render/rs_material_filter.h"
36 #include "platform/common/rs_system_properties.h"
37 
38 #include <cstdint>
39 #include <algorithm>
40 
41 #include "draw/canvas.h"
42 #include "draw/clip.h"
43 #include "drawing/draw/core_canvas.h"
44 #include "effect/runtime_blender_builder.h"
45 #include "effect/runtime_effect.h"
46 #include "effect/runtime_shader_builder.h"
47 #include "utils/rect.h"
48 #include "src/image/SkImage_Base.h"
49 
50 namespace OHOS {
51 namespace Rosen {
52 namespace {
53 bool g_forceBgAntiAlias = true;
54 constexpr int PARAM_DOUBLE = 2;
55 constexpr int TRACE_LEVEL_TWO = 2;
56 constexpr float MIN_TRANS_RATIO = 0.0f;
57 constexpr float MAX_TRANS_RATIO = 0.95f;
58 constexpr float MIN_SPOT_RATIO = 1.0f;
59 constexpr float MAX_SPOT_RATIO = 1.95f;
60 constexpr float MAX_AMBIENT_RADIUS = 150.0f;
61 } // namespace
62 
63 const bool RSPropertiesPainter::BLUR_ENABLED = RSSystemProperties::GetBlurEnabled();
64 const bool RSPropertiesPainter::FOREGROUND_FILTER_ENABLED = RSSystemProperties::GetForegroundFilterEnabled();
65 
66 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::greyAdjustEffect_ = nullptr;
67 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::binarizationShaderEffect_ = nullptr;
68 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::lightUpEffectBlender_ = nullptr;
69 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::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 
581     RS_OPTIONAL_TRACE_NAME("DrawFilter " + RSFilter->GetDescription());
582     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawFilter, filterType: %d, %s, bounds: %s", filterType,
583         RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
584     g_blurCnt++;
585     Drawing::AutoCanvasRestore acr(canvas, true);
586 
587     auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
588     auto surface = canvas.GetSurface();
589     if (surface == nullptr) {
590         ROSEN_LOGD("RSPropertiesPainter::DrawFilter surface null");
591         Drawing::Brush brush;
592         brush.SetAntiAlias(true);
593         Drawing::Filter filterForBrush;
594         auto imageFilter = filter->GetImageFilter();
595         // Since using Kawase blur (shader) in the screenshot scene would lead to failure,
596         // a Gaussian blur filter (imageFilter) is regenerated here instead.
597         std::shared_ptr<RSShaderFilter> kawaseShaderFilter =
598             filter->GetShaderFilterWithType(RSShaderFilter::KAWASE);
599         if (kawaseShaderFilter != nullptr) {
600             auto tmpFilter = std::static_pointer_cast<RSKawaseBlurShaderFilter>(kawaseShaderFilter);
601             auto radius = tmpFilter->GetRadius();
602             std::shared_ptr<Drawing::ImageFilter> blurFilter = Drawing::ImageFilter::CreateBlurImageFilter(
603                 radius, radius, Drawing::TileMode::CLAMP, nullptr);
604             imageFilter = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter, blurFilter);
605         }
606         filterForBrush.SetImageFilter(imageFilter);
607         brush.SetFilter(filterForBrush);
608         Drawing::SaveLayerOps slr(nullptr, &brush, Drawing::SaveLayerOps::Flags::INIT_WITH_PREVIOUS);
609         canvas.SaveLayer(slr);
610         filter->PostProcess(canvas);
611         return;
612     }
613 
614     // for foreground filter, when do online opacity, rendering result already applied opacity,
615     // so drawImage should not apply opacity again
616     RSAutoCanvasRestore autoCanvasRestore(&canvas,
617         filterType == FilterType::FOREGROUND_FILTER ? RSPaintFilterCanvas::kAlpha : RSPaintFilterCanvas::kNone);
618     if (filterType == FilterType::FOREGROUND_FILTER) {
619         canvas.SetAlpha(1.0);
620     }
621 
622     auto clipIBounds = canvas.GetDeviceClipBounds();
623     auto imageClipIBounds = clipIBounds;
624     std::shared_ptr<RSShaderFilter> magnifierShaderFilter =
625         filter->GetShaderFilterWithType(RSShaderFilter::MAGNIFIER);
626     if (magnifierShaderFilter != nullptr) {
627         auto tmpFilter = std::static_pointer_cast<RSMagnifierShaderFilter>(magnifierShaderFilter);
628         auto canvasMatrix = canvas.GetTotalMatrix();
629         tmpFilter->SetMagnifierOffset(canvasMatrix);
630         imageClipIBounds.Offset(tmpFilter->GetMagnifierOffsetX(), tmpFilter->GetMagnifierOffsetY());
631     }
632 
633 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
634     // Optional use cacheManager to draw filter
635     if (auto& cacheManager = properties.GetFilterCacheManager(filterType == FilterType::FOREGROUND_FILTER);
636         cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
637         std::shared_ptr<RSShaderFilter> rsShaderFilter =
638             filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
639         if (rsShaderFilter != nullptr) {
640             auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
641             tmpFilter->IsOffscreenCanvas(true);
642             tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
643         }
644         // RSFilterCacheManger has no more logic for evaluating filtered snapshot clearing
645         // Should be passed as secnod argument, if required (see RSPropertyDrawableUtils::DrewFiler())
646         cacheManager->DrawFilter(canvas, filter, { false, false });
647         return;
648     }
649 #endif
650 
651     std::shared_ptr<RSShaderFilter> rsShaderFilter =
652         filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
653     if (rsShaderFilter != nullptr) {
654         auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
655         tmpFilter->IsOffscreenCanvas(true);
656         tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
657     }
658 
659     auto imageSnapshot = surface->GetImageSnapshot(imageClipIBounds);
660     if (imageSnapshot == nullptr) {
661         ROSEN_LOGD("RSPropertiesPainter::DrawFilter image null");
662         return;
663     }
664     if (RSSystemProperties::GetImageGpuResourceCacheEnable(imageSnapshot->GetWidth(), imageSnapshot->GetHeight())) {
665         ROSEN_LOGD("DrawFilter cache image resource(width:%{public}d, height:%{public}d).",
666             imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
667         imageSnapshot->HintCacheGpuResource();
668     }
669 
670     filter->PreProcess(imageSnapshot);
671     canvas.ResetMatrix();
672     auto visibleRect = canvas.GetVisibleRect();
673     visibleRect.Round();
674     auto visibleIRect = Drawing::RectI(
675         static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
676         static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
677     if (!visibleIRect.IsEmpty()) {
678         canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
679     }
680     Drawing::Rect srcRect = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
681     Drawing::Rect dstRect = clipIBounds;
682     filter->DrawImageRect(canvas, imageSnapshot, srcRect, dstRect);
683     filter->PostProcess(canvas);
684 }
685 
DrawBackgroundImageAsEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)686 void RSPropertiesPainter::DrawBackgroundImageAsEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
687 {
688     RS_TRACE_FUNC();
689     auto boundsRect = properties.GetBoundsRect();
690 
691     // Optional use cacheManager to draw filter, cache is valid, skip drawing background image
692 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
693     if (auto& cacheManager = properties.GetFilterCacheManager(false);
694         cacheManager != nullptr && !canvas.GetDisableFilterCache() && cacheManager->IsCacheValid()) {
695         // no need to validate parameters, the caller already do it
696         canvas.ClipRect(RSPropertiesPainter::Rect2DrawingRect(boundsRect));
697         auto filter = std::static_pointer_cast<RSDrawingFilter>(properties.GetBackgroundFilter());
698         // extract cache data from cacheManager
699         auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter);
700         canvas.SetEffectData(data);
701         return;
702     }
703 #endif
704 
705     auto surface = canvas.GetSurface();
706     if (!surface) {
707         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect surface null");
708         return;
709     }
710     // create offscreen surface with same size as current surface (PLANNING: use bounds size instead)
711     auto offscreenSurface = surface->MakeSurface(canvas.GetWidth(), canvas.GetHeight());
712     auto offscreenCanvas = std::make_shared<RSPaintFilterCanvas>(offscreenSurface.get());
713     // copy matrix and other properties to offscreen canvas
714     offscreenCanvas->SetMatrix(canvas.GetTotalMatrix());
715     offscreenCanvas->CopyConfigurationToOffscreenCanvas(canvas);
716     // draw background onto offscreen canvas
717     RSPropertiesPainter::DrawBackground(properties, *offscreenCanvas);
718     // generate effect data
719     RSPropertiesPainter::DrawBackgroundEffect(properties, *offscreenCanvas);
720     // extract effect data from offscreen canvas and set to canvas
721     canvas.SetEffectData(offscreenCanvas->GetEffectData());
722 }
723 
DrawBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)724 void RSPropertiesPainter::DrawBackgroundEffect(
725     const RSProperties& properties, RSPaintFilterCanvas& canvas)
726 {
727     auto& RSFilter = properties.GetBackgroundFilter();
728     if (RSFilter == nullptr) {
729         return;
730     }
731     g_blurCnt++;
732     RS_TRACE_NAME("DrawBackgroundEffect " + RSFilter->GetDescription());
733     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "EffectComponent, %s, bounds: %s",
734         RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
735     auto surface = canvas.GetSurface();
736     if (surface == nullptr) {
737         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect surface null");
738         return;
739     }
740 
741     canvas.Save();
742     canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()));
743     auto bounds = canvas.GetRoundInDeviceClipBounds();
744     canvas.Restore();
745     auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
746 
747 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
748     // Optional use cacheManager to draw filter
749     if (auto& cacheManager = properties.GetFilterCacheManager(false);
750         cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
751         auto node = properties.backref_.lock();
752         if (node == nullptr) {
753             ROSEN_LOGE("DrawBackgroundEffect::node is null");
754             return;
755         }
756         auto effectNode = node->ReinterpretCastTo<RSEffectRenderNode>();
757         if (effectNode == nullptr) {
758             ROSEN_LOGE("DrawBackgroundEffect::node reinterpret cast failed.");
759             return;
760         }
761         auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter, bounds, bounds);
762         canvas.SetEffectData(data);
763         return;
764     }
765 #endif
766 
767     auto imageRect = bounds;
768     auto imageSnapshot = surface->GetImageSnapshot(imageRect);
769     if (imageSnapshot == nullptr) {
770         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect image snapshot null");
771         return;
772     }
773 
774     filter->PreProcess(imageSnapshot);
775     // create a offscreen skSurface
776     std::shared_ptr<Drawing::Surface> offscreenSurface =
777         surface->MakeSurface(imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
778     if (offscreenSurface == nullptr) {
779         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect offscreenSurface null");
780         return;
781     }
782     RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
783     auto clipBounds = Drawing::Rect(0, 0, imageRect.GetWidth(), imageRect.GetHeight());
784     auto imageSnapshotBounds = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
785     filter->DrawImageRect(offscreenCanvas, imageSnapshot, imageSnapshotBounds, clipBounds);
786     filter->PostProcess(offscreenCanvas);
787 
788     auto imageCache = offscreenSurface->GetImageSnapshot();
789     if (imageCache == nullptr) {
790         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect imageCache snapshot null");
791         return;
792     }
793     auto data = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(imageCache), std::move(imageRect));
794     canvas.SetEffectData(std::move(data));
795 }
796 
ApplyBackgroundEffectFallback(const RSProperties & properties,RSPaintFilterCanvas & canvas)797 void RSPropertiesPainter::ApplyBackgroundEffectFallback(const RSProperties& properties, RSPaintFilterCanvas& canvas)
798 {
799     RS_TRACE_FUNC();
800     auto parentNode = properties.backref_.lock();
801     while (parentNode && !parentNode->IsInstanceOf<RSEffectRenderNode>()) {
802         parentNode = parentNode->GetParent().lock();
803     }
804     if (!parentNode) {
805         ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffectFallback: parentNode null, draw filter failed.");
806         return;
807     }
808     auto& filter = parentNode->GetRenderProperties().GetBackgroundFilter();
809     if (filter == nullptr || !filter->IsValid()) {
810         ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffectFallback: parent EffectRenderNode has no filter, "
811                    "draw filter failed.");
812         return;
813     }
814     DrawFilter(properties, canvas, FilterType::BACKGROUND_FILTER, std::nullopt, filter);
815 }
816 
ClipVisibleCanvas(const RSProperties & properties,RSPaintFilterCanvas & canvas)817 void RSPropertiesPainter::ClipVisibleCanvas(const RSProperties& properties, RSPaintFilterCanvas& canvas)
818 {
819     canvas.ResetMatrix();
820     auto visibleRect = canvas.GetVisibleRect();
821     visibleRect.Round();
822     auto visibleIRect = Drawing::RectI(
823         static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
824         static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
825     if (!visibleIRect.IsEmpty()) {
826         canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
827     }
828 }
829 
ApplyBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)830 void RSPropertiesPainter::ApplyBackgroundEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
831 {
832     const auto& effectData = canvas.GetEffectData();
833     if (effectData == nullptr || effectData->cachedImage_ == nullptr
834         || !RSSystemProperties::GetEffectMergeEnabled()) {
835         // no effectData available, draw background filter in fallback method
836         ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffect: effectData null, try fallback method.");
837         ApplyBackgroundEffectFallback(properties, canvas);
838         return;
839     }
840     RS_TRACE_FUNC();
841     Drawing::AutoCanvasRestore acr(canvas, true);
842     ClipVisibleCanvas(properties, canvas);
843     Drawing::Brush brush;
844     canvas.AttachBrush(brush);
845     // dstRect: canvas clip region
846     Drawing::Rect dstRect = canvas.GetDeviceClipBounds();
847     // srcRect: map dstRect onto cache coordinate
848     Drawing::Rect srcRect = dstRect;
849     srcRect.Offset(-effectData->cachedRect_.GetLeft(), -effectData->cachedRect_.GetTop());
850     canvas.DrawImageRect(*effectData->cachedImage_, srcRect, dstRect,
851                          Drawing::SamplingOptions(), Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
852     canvas.DetachBrush();
853 }
854 
GetPixelStretchDirtyRect(RectI & dirtyPixelStretch,const RSProperties & properties,const bool isAbsCoordinate)855 void RSPropertiesPainter::GetPixelStretchDirtyRect(RectI& dirtyPixelStretch,
856     const RSProperties& properties, const bool isAbsCoordinate)
857 {
858     auto& pixelStretch = properties.GetPixelStretch();
859     if (!pixelStretch.has_value()) {
860         return;
861     }
862     auto boundsRect = properties.GetBoundsRect();
863     auto scaledBounds = RectF(boundsRect.left_ - pixelStretch->x_, boundsRect.top_ - pixelStretch->y_,
864         boundsRect.width_ + pixelStretch->x_ + pixelStretch->z_,
865         boundsRect.height_ + pixelStretch->y_ + pixelStretch->w_);
866     auto geoPtr = properties.GetBoundsGeometry();
867     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
868     auto drawingRect = Rect2DrawingRect(scaledBounds);
869     matrix.MapRect(drawingRect, drawingRect);
870     dirtyPixelStretch.left_ = std::floor(drawingRect.GetLeft());
871     dirtyPixelStretch.top_ = std::floor(drawingRect.GetTop());
872     dirtyPixelStretch.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
873     dirtyPixelStretch.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
874 }
875 
GetForegroundEffectDirtyRect(RectI & dirtyForegroundEffect,const RSProperties & properties,const bool isAbsCoordinate)876 void RSPropertiesPainter::GetForegroundEffectDirtyRect(RectI& dirtyForegroundEffect,
877     const RSProperties& properties, const bool isAbsCoordinate)
878 {
879     std::shared_ptr<RSFilter> foregroundFilter = nullptr;
880     if (RSProperties::IS_UNI_RENDER) {
881         foregroundFilter = properties.GetForegroundFilterCache();
882     } else {
883         foregroundFilter = properties.GetForegroundFilter();
884     }
885     if (!foregroundFilter || foregroundFilter->GetFilterType() != RSFilter::FOREGROUND_EFFECT) {
886         return;
887     }
888     float dirtyExtension =
889                 std::static_pointer_cast<RSForegroundEffectFilter>(foregroundFilter)->GetDirtyExtension();
890     auto boundsRect = properties.GetBoundsRect();
891     auto scaledBounds = boundsRect.MakeOutset(dirtyExtension);
892     auto& geoPtr = properties.GetBoundsGeometry();
893     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
894     auto drawingRect = Rect2DrawingRect(scaledBounds);
895     matrix.MapRect(drawingRect, drawingRect);
896     dirtyForegroundEffect.left_ = std::floor(drawingRect.GetLeft());
897     dirtyForegroundEffect.top_ = std::floor(drawingRect.GetTop());
898     dirtyForegroundEffect.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
899     dirtyForegroundEffect.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
900 }
901 
902 // calculate the distortion effect's dirty area
GetDistortionEffectDirtyRect(RectI & dirtyDistortionEffect,const RSProperties & properties)903 void RSPropertiesPainter::GetDistortionEffectDirtyRect(RectI& dirtyDistortionEffect, const RSProperties& properties)
904 {
905     // if the distortionK > 0, set the dirty bounds to its maximum range value
906     auto distortionK = properties.GetDistortionK();
907     if (distortionK.has_value() && *distortionK > 0) {
908         int dirtyWidth = static_cast<int>(std::numeric_limits<int16_t>::max());
909         int dirtyBeginPoint = static_cast<int>(std::numeric_limits<int16_t>::min()) / PARAM_DOUBLE;
910         dirtyDistortionEffect.left_ = dirtyBeginPoint;
911         dirtyDistortionEffect.top_ = dirtyBeginPoint;
912         dirtyDistortionEffect.width_ = dirtyWidth;
913         dirtyDistortionEffect.height_ = dirtyWidth;
914     }
915 }
916 
DrawPixelStretch(const RSProperties & properties,RSPaintFilterCanvas & canvas)917 void RSPropertiesPainter::DrawPixelStretch(const RSProperties& properties, RSPaintFilterCanvas& canvas)
918 {
919     auto& pixelStretch = properties.GetPixelStretch();
920     if (!pixelStretch.has_value()) {
921         return;
922     }
923     auto surface = canvas.GetSurface();
924     if (surface == nullptr) {
925         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch surface null");
926         return;
927     }
928 
929     canvas.Save();
930     auto bounds = RSPropertiesPainter::Rect2DrawingRect(properties.GetBoundsRect());
931     canvas.ClipRect(bounds, Drawing::ClipOp::INTERSECT, false);
932     auto tmpBounds = canvas.GetDeviceClipBounds();
933     Drawing::Rect clipBounds(
934         tmpBounds.GetLeft(), tmpBounds.GetTop(), tmpBounds.GetRight() - 1, tmpBounds.GetBottom() - 1);
935     canvas.Restore();
936 
937     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertiesPainter::DrawPixelStretch, right: %f, bottom: %f",
938         tmpBounds.GetRight(), tmpBounds.GetBottom());
939 
940     /*  Calculates the relative coordinates of the clipbounds
941         with respect to the origin of the current canvas coordinates */
942     Drawing::Matrix worldToLocalMat;
943     if (!canvas.GetTotalMatrix().Invert(worldToLocalMat)) {
944         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch get invert matrix failed.");
945     }
946     Drawing::Rect localClipBounds;
947     Drawing::Rect fClipBounds(clipBounds.GetLeft(), clipBounds.GetTop(), clipBounds.GetRight(),
948         clipBounds.GetBottom());
949     if (!worldToLocalMat.MapRect(localClipBounds, fClipBounds)) {
950         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch map rect failed.");
951     }
952 
953     if (!bounds.Intersect(localClipBounds)) {
954         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch intersect clipbounds failed");
955     }
956 
957     auto scaledBounds = Drawing::Rect(bounds.GetLeft() - pixelStretch->x_, bounds.GetTop() - pixelStretch->y_,
958         bounds.GetRight() + pixelStretch->z_, bounds.GetBottom() + pixelStretch->w_);
959     if (!scaledBounds.IsValid() || !bounds.IsValid() || !clipBounds.IsValid()) {
960         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch invalid scaled bounds");
961         return;
962     }
963 
964     Drawing::RectI rectI(static_cast<int>(fClipBounds.GetLeft()), static_cast<int>(fClipBounds.GetTop()),
965         static_cast<int>(fClipBounds.GetRight()), static_cast<int>(fClipBounds.GetBottom()));
966     auto image = surface->GetImageSnapshot(rectI);
967     if (image == nullptr) {
968         ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch image null");
969         return;
970     }
971 
972     Drawing::Brush brush;
973     Drawing::Matrix inverseMat, rotateMat;
974     auto& boundsGeo = (properties.GetBoundsGeometry());
975     if (boundsGeo && !boundsGeo->IsEmpty()) {
976         auto transMat = canvas.GetTotalMatrix();
977         /* transMat.getSkewY() is the sin of the rotation angle(sin0 = 0,sin90 =1 sin180 = 0,sin270 = -1),
978             if transMat.getSkewY() is not 0 or -1 or 1,the rotation angle is not a multiple of 90,not Stretch*/
979         auto skewY = transMat.Get(Drawing::Matrix::SKEW_Y);
980         if (ROSEN_EQ(skewY, 0.f) || ROSEN_EQ(skewY, 1.f) ||
981             ROSEN_EQ(skewY, -1.f)) {
982         } else {
983             ROSEN_LOGD("rotate degree is not 0 or 90 or 180 or 270,return.");
984             return;
985         }
986         rotateMat.SetScale(transMat.Get(Drawing::Matrix::SCALE_X), transMat.Get(Drawing::Matrix::SCALE_Y));
987         rotateMat.Set(Drawing::Matrix::SKEW_X, transMat.Get(Drawing::Matrix::SKEW_X));
988         rotateMat.Set(Drawing::Matrix::SKEW_Y, transMat.Get(Drawing::Matrix::SKEW_Y));
989         rotateMat.PreTranslate(-bounds.GetLeft(), -bounds.GetTop());
990         rotateMat.PostTranslate(bounds.GetLeft(), bounds.GetTop());
991 
992         Drawing::Rect transBounds;
993         rotateMat.MapRect(transBounds, bounds);
994         rotateMat.Set(Drawing::Matrix::TRANS_X, bounds.GetLeft() - transBounds.GetLeft());
995         rotateMat.Set(Drawing::Matrix::TRANS_Y, bounds.GetTop() - transBounds.GetTop());
996         if (!rotateMat.Invert(inverseMat)) {
997             ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch get invert matrix failed.");
998         }
999     }
1000 
1001     canvas.Save();
1002     canvas.Translate(bounds.GetLeft(), bounds.GetTop());
1003     Drawing::SamplingOptions samplingOptions;
1004     constexpr static float EPS = 1e-5f;
1005     auto pixelStretchTileMode = static_cast<Drawing::TileMode>(properties.GetPixelStretchTileMode());
1006     if (pixelStretch->x_ > EPS || pixelStretch->y_ > EPS || pixelStretch->z_ > EPS || pixelStretch->w_ > EPS) {
1007         brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1008             *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1009         canvas.AttachBrush(brush);
1010         canvas.DrawRect(Drawing::Rect(-pixelStretch->x_, -pixelStretch->y_,
1011             -pixelStretch->x_ + scaledBounds.GetWidth(), -pixelStretch->y_ + scaledBounds.GetHeight()));
1012         canvas.DetachBrush();
1013     } else {
1014         inverseMat.PostScale(scaledBounds.GetWidth() / bounds.GetWidth(),
1015             scaledBounds.GetHeight() / bounds.GetHeight());
1016         brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1017             *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1018 
1019         canvas.Translate(-pixelStretch->x_, -pixelStretch->y_);
1020         canvas.AttachBrush(brush);
1021         canvas.DrawRect(Drawing::Rect(pixelStretch->x_, pixelStretch->y_,
1022             pixelStretch->x_ + bounds.GetWidth(), pixelStretch->y_ + bounds.GetHeight()));
1023         canvas.DetachBrush();
1024     }
1025     canvas.Restore();
1026 }
1027 
CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)1028 Drawing::ColorQuad RSPropertiesPainter::CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)
1029 {
1030     // create a 1x1 SkPixmap
1031     uint32_t pixel[1] = { 0 };
1032     Drawing::ImageInfo single_pixel_info(1, 1, Drawing::ColorType::COLORTYPE_RGBA_8888,
1033         Drawing::AlphaType::ALPHATYPE_PREMUL);
1034     Drawing::Bitmap single_pixel;
1035     single_pixel.Build(single_pixel_info, single_pixel_info.GetBytesPerPixel());
1036     single_pixel.SetPixels(pixel);
1037 
1038     // resize snapshot to 1x1 to calculate average color
1039     // kMedium_SkFilterQuality will do bilerp + mipmaps for down-scaling, we can easily get average color
1040     imageSnapshot->ScalePixels(single_pixel,
1041         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR));
1042     // convert color format and return average color
1043     return SkColor4f::FromBytes_RGBA(pixel[0]).toSkColor();
1044 }
1045 
GetAndResetBlurCnt()1046 int RSPropertiesPainter::GetAndResetBlurCnt()
1047 {
1048     auto blurCnt = g_blurCnt;
1049     g_blurCnt = 0;
1050     return blurCnt;
1051 }
1052 
DrawBackground(const RSProperties & properties,RSPaintFilterCanvas & canvas,bool isAntiAlias,bool isSurfaceView)1053 void RSPropertiesPainter::DrawBackground(const RSProperties& properties, RSPaintFilterCanvas& canvas,
1054     bool isAntiAlias, bool isSurfaceView)
1055 {
1056     // only disable antialias when background is rect and g_forceBgAntiAlias is false
1057     bool antiAlias = g_forceBgAntiAlias || !properties.GetCornerRadius().IsZero();
1058     // clip
1059     if (properties.GetClipBounds() != nullptr) {
1060         auto& path = properties.GetClipBounds()->GetDrawingPath();
1061         canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, antiAlias);
1062     } else if (properties.GetClipToBounds()) {
1063         if (properties.GetCornerRadius().IsZero()) {
1064             canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, isAntiAlias);
1065         } else {
1066             canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1067         }
1068     } else if (properties.GetClipToRRect()) {
1069         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1070     }
1071     // paint backgroundColor
1072     Drawing::Brush brush;
1073     brush.SetAntiAlias(antiAlias);
1074     auto bgColor = properties.GetBackgroundColor();
1075     if (bgColor != RgbPalette::Transparent() && !isSurfaceView) {
1076         brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
1077         canvas.AttachBrush(brush);
1078         canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1079         canvas.DetachBrush();
1080     }
1081     if (const auto& bgShader = properties.GetBackgroundShader()) {
1082         Drawing::AutoCanvasRestore acr(canvas, true);
1083         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1084         auto shaderEffect = bgShader->GetDrawingShader();
1085         brush.SetShaderEffect(shaderEffect);
1086         canvas.DrawBackground(brush);
1087     }
1088     if (const auto& bgImage = properties.GetBgImage()) {
1089         Drawing::AutoCanvasRestore acr(canvas, true);
1090         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1091         auto boundsRect = Rect2DrawingRect(properties.GetBoundsRect());
1092         bgImage->SetDstRect(properties.GetBgImageRect());
1093         canvas.AttachBrush(brush);
1094         bgImage->CanvasDrawImage(canvas, boundsRect, Drawing::SamplingOptions(), true);
1095         canvas.DetachBrush();
1096     }
1097 }
1098 
SetBgAntiAlias(bool forceBgAntiAlias)1099 void RSPropertiesPainter::SetBgAntiAlias(bool forceBgAntiAlias)
1100 {
1101     g_forceBgAntiAlias = forceBgAntiAlias;
1102 }
1103 
GetBgAntiAlias()1104 bool RSPropertiesPainter::GetBgAntiAlias()
1105 {
1106     return g_forceBgAntiAlias;
1107 }
1108 
DrawFrame(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::DrawCmdListPtr & cmds)1109 void RSPropertiesPainter::DrawFrame(
1110     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::DrawCmdListPtr& cmds)
1111 {
1112     if (cmds == nullptr) {
1113         return;
1114     }
1115     Drawing::Matrix mat;
1116     if (GetGravityMatrix(
1117             properties.GetFrameGravity(), properties.GetFrameRect(), cmds->GetWidth(), cmds->GetHeight(), mat)) {
1118         canvas.ConcatMatrix(mat);
1119     }
1120     auto frameRect = Rect2DrawingRect(properties.GetFrameRect());
1121     cmds->Playback(canvas, &frameRect);
1122 }
1123 
GetRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)1124 RRect RSPropertiesPainter::GetRRectForDrawingBorder(const RSProperties& properties,
1125     const std::shared_ptr<RSBorder>& border, const bool isOutline)
1126 {
1127     if (!border) {
1128         return RRect();
1129     }
1130 
1131     return isOutline ?
1132         RRect(properties.GetRRect().rect_.MakeOutset(border->GetWidthFour()), border->GetRadiusFour()) :
1133         properties.GetRRect();
1134 }
1135 
GetInnerRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)1136 RRect RSPropertiesPainter::GetInnerRRectForDrawingBorder(const RSProperties& properties,
1137     const std::shared_ptr<RSBorder>& border, const bool isOutline)
1138 {
1139     if (!border) {
1140         return RRect();
1141     }
1142     return isOutline ? properties.GetRRect() : properties.GetInnerRRect();
1143 }
1144 
1145 static std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder = nullptr;
1146 
GetPhongShaderBuilder()1147 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPropertiesPainter::GetPhongShaderBuilder()
1148 {
1149     if (phongShaderBuilder) {
1150         return phongShaderBuilder;
1151     }
1152     std::shared_ptr<Drawing::RuntimeEffect> lightEffect_;
1153     const static std::string lightString(R"(
1154         uniform vec4 lightPos[12];
1155         uniform vec4 viewPos[12];
1156         uniform vec4 specularLightColor[12];
1157         uniform float specularStrength[12];
1158 
1159         mediump vec4 main(vec2 drawing_coord) {
1160             vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
1161             float ambientStrength = 0.0;
1162             vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
1163             float diffuseStrength = 0.0;
1164             float shininess = 8.0;
1165             mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
1166             vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
1167             // ambient
1168             vec4 ambient = lightColor * ambientStrength;
1169             vec3 norm = normalize(NormalMap.rgb);
1170 
1171             for (int i = 0; i < 12; i++) {
1172                 if (abs(specularStrength[i]) > 0.01) {
1173                     vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
1174                     float diff = max(dot(norm, lightDir), 0.0);
1175                     vec4 diffuse = diff * lightColor;
1176                     vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
1177                     vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
1178                     float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
1179                     vec4 specular = lightColor * spec; // multiply color of incident light
1180                     vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
1181                     vec4 specularColor = specularLightColor[i];
1182                     fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
1183                 }
1184             }
1185             return fragColor;
1186         }
1187     )");
1188     std::shared_ptr<Drawing::RuntimeEffect> lightEffect = Drawing::RuntimeEffect::CreateForShader(lightString);
1189     if (!lightEffect) {
1190         ROSEN_LOGE("light effect error");
1191         return phongShaderBuilder;
1192     }
1193     lightEffect_ = std::move(lightEffect);
1194     phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect_);
1195     return phongShaderBuilder;
1196 }
1197 
DrawLight(const RSProperties & properties,Drawing::Canvas & canvas)1198 void RSPropertiesPainter::DrawLight(const RSProperties& properties, Drawing::Canvas& canvas)
1199 {
1200     auto lightBuilder = GetPhongShaderBuilder();
1201     if (!lightBuilder) {
1202         return;
1203     }
1204     const auto& lightSourcesAndPosMap = properties.GetIlluminated()->GetLightSourcesAndPosMap();
1205     if (lightSourcesAndPosMap.empty()) {
1206         ROSEN_LOGD("RSPropertiesPainter::DrawLight lightSourceList is empty!");
1207         return;
1208     }
1209     std::vector<std::pair<std::shared_ptr<RSLightSource>, Vector4f>> lightSourcesAndPosVec(
1210         lightSourcesAndPosMap.begin(), lightSourcesAndPosMap.end());
1211     if (lightSourcesAndPosVec.size() > MAX_LIGHT_SOURCES) {
1212         std::sort(lightSourcesAndPosVec.begin(), lightSourcesAndPosVec.end(), [](const auto& x, const auto& y) {
1213             return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
1214                    y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
1215         });
1216     }
1217     DrawLightInner(properties, canvas, lightBuilder, lightSourcesAndPosVec);
1218 }
1219 
DrawLightInner(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,const std::vector<std::pair<std::shared_ptr<RSLightSource>,Vector4f>> & lightSourcesAndPosVec)1220 void RSPropertiesPainter::DrawLightInner(const RSProperties& properties, Drawing::Canvas& canvas,
1221     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder,
1222     const std::vector<std::pair<std::shared_ptr<RSLightSource>, Vector4f>>& lightSourcesAndPosVec)
1223 {
1224     auto cnt = 0;
1225     constexpr int vectorLen = 4;
1226     float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1227     float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1228     float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1229     std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
1230 
1231     auto iter = lightSourcesAndPosVec.begin();
1232     while (iter != lightSourcesAndPosVec.end() && cnt < MAX_LIGHT_SOURCES) {
1233         auto lightPos = iter->second;
1234         auto lightIntensity = iter->first->GetLightIntensity();
1235         auto lightColor = iter->first->GetLightColor();
1236         Vector4f lightColorVec =
1237             Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
1238         for (int i = 0; i < vectorLen; i++) {
1239             lightPosArray[cnt * vectorLen + i] = lightPos[i];
1240             viewPosArray[cnt * vectorLen + i] = lightPos[i];
1241             lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
1242         }
1243         lightIntensityArray[cnt] = lightIntensity;
1244         iter++;
1245         cnt++;
1246     }
1247     lightBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
1248     lightBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
1249     lightBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
1250     Drawing::Pen pen;
1251     Drawing::Brush brush;
1252     pen.SetAntiAlias(true);
1253     brush.SetAntiAlias(true);
1254     auto illuminatedType = properties.GetIlluminated()->GetIlluminatedType();
1255     ROSEN_LOGD("RSPropertiesPainter::DrawLight illuminatedType:%{public}d", illuminatedType);
1256     if (illuminatedType == IlluminatedType::CONTENT) {
1257         DrawContentLight(properties, canvas, lightBuilder, brush, lightIntensityArray);
1258     } else if (illuminatedType == IlluminatedType::BORDER) {
1259         DrawBorderLight(properties, canvas, lightBuilder, pen, lightIntensityArray);
1260     } else if (illuminatedType == IlluminatedType::BORDER_CONTENT) {
1261         DrawContentLight(properties, canvas, lightBuilder, brush, lightIntensityArray);
1262         DrawBorderLight(properties, canvas, lightBuilder, pen, lightIntensityArray);
1263     }
1264 }
1265 
DrawContentLight(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray)1266 void RSPropertiesPainter::DrawContentLight(const RSProperties& properties, Drawing::Canvas& canvas,
1267     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
1268     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray)
1269 {
1270     // content light
1271     std::shared_ptr<Drawing::ShaderEffect> shader;
1272     constexpr float contentIntensityCoefficient = 0.3f;
1273     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
1274     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
1275         specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
1276     }
1277     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
1278     shader = lightBuilder->MakeShader(nullptr, false);
1279     brush.SetShaderEffect(shader);
1280     canvas.AttachBrush(brush);
1281     canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1282     canvas.DetachBrush();
1283 }
1284 
DrawBorderLight(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray)1285 void RSPropertiesPainter::DrawBorderLight(const RSProperties& properties, Drawing::Canvas& canvas,
1286     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
1287     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray)
1288 {
1289     // border light
1290     std::shared_ptr<Drawing::ShaderEffect> shader;
1291     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
1292     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
1293         specularStrengthArr[i] = lightIntensityArray[i];
1294     }
1295     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
1296     shader = lightBuilder->MakeShader(nullptr, false);
1297     pen.SetShaderEffect(shader);
1298     float borderWidth = std::ceil(properties.GetIlluminatedBorderWidth());
1299     pen.SetWidth(borderWidth);
1300     auto borderRect = properties.GetRRect().rect_;
1301     float borderRadius = properties.GetRRect().radius_[0].x_;
1302     auto borderRRect = RRect(RectF(borderRect.left_ + borderWidth / 2.0f, borderRect.top_ + borderWidth / 2.0f,
1303         borderRect.width_ - borderWidth, borderRect.height_ - borderWidth),
1304         borderRadius - borderWidth / 2.0f, borderRadius - borderWidth / 2.0f);
1305     canvas.AttachPen(pen);
1306     canvas.DrawRoundRect(RRect2DrawingRRect(borderRRect));
1307     canvas.DetachPen();
1308 }
1309 
DrawBorderBase(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool isOutline)1310 void RSPropertiesPainter::DrawBorderBase(const RSProperties& properties, Drawing::Canvas& canvas,
1311     const std::shared_ptr<RSBorder>& border, const bool isOutline)
1312 {
1313     if (!border || !border->HasBorder()) {
1314         return;
1315     }
1316 
1317     Drawing::Brush brush;
1318     Drawing::Pen pen;
1319     brush.SetAntiAlias(true);
1320     pen.SetAntiAlias(true);
1321     if (border->ApplyFillStyle(brush)) {
1322         auto roundRect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
1323         auto innerRoundRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(
1324             properties, border, isOutline));
1325         canvas.AttachBrush(brush);
1326         canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
1327         canvas.DetachBrush();
1328     } else {
1329         bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
1330         if (isZero && border->ApplyFourLine(pen)) {
1331             RectF rectf = isOutline ?
1332                 properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
1333             border->PaintFourLine(canvas, pen, rectf);
1334         } else if (border->ApplyPathStyle(pen)) {
1335             auto borderWidth = border->GetWidth();
1336             RRect rrect = GetRRectForDrawingBorder(properties, border, isOutline);
1337             rrect.rect_.width_ -= borderWidth;
1338             rrect.rect_.height_ -= borderWidth;
1339             rrect.rect_.Move(borderWidth / PARAM_DOUBLE, borderWidth / PARAM_DOUBLE);
1340             Drawing::Path borderPath;
1341             borderPath.AddRoundRect(RRect2DrawingRRect(rrect));
1342             canvas.AttachPen(pen);
1343             canvas.DrawPath(borderPath);
1344             canvas.DetachPen();
1345         } else {
1346             RSBorderGeo borderGeo;
1347             borderGeo.rrect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
1348             borderGeo.innerRRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(properties, border, isOutline));
1349             auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
1350             auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
1351             borderGeo.center = { centerX, centerY };
1352             auto rect = borderGeo.rrect.GetRect();
1353             Drawing::AutoCanvasRestore acr(canvas, false);
1354             Drawing::SaveLayerOps slr(&rect, nullptr);
1355             canvas.SaveLayer(slr);
1356             border->DrawBorders(canvas, pen, borderGeo);
1357         }
1358     }
1359 }
1360 
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas)1361 void RSPropertiesPainter::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas)
1362 {
1363     auto border = properties.GetBorder();
1364     if (border && border->HasBorder()) {
1365         DrawBorderBase(properties, canvas, border, false);
1366     }
1367 }
1368 
GetOutlineDirtyRect(RectI & dirtyOutline,const RSProperties & properties,const bool isAbsCoordinate)1369 void RSPropertiesPainter::GetOutlineDirtyRect(RectI& dirtyOutline,
1370     const RSProperties& properties, const bool isAbsCoordinate)
1371 {
1372     auto outline = properties.GetOutline();
1373     if (!outline || !outline->HasBorder()) {
1374         return;
1375     }
1376 
1377     auto& geoPtr = properties.GetBoundsGeometry();
1378     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
1379     auto drawingRect = Rect2DrawingRect(GetRRectForDrawingBorder(properties, outline, true).rect_);
1380     matrix.MapRect(drawingRect, drawingRect);
1381     dirtyOutline.left_ = std::floor(drawingRect.GetLeft());
1382     dirtyOutline.top_ = std::floor(drawingRect.GetTop());
1383     dirtyOutline.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
1384     dirtyOutline.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
1385 }
1386 
DrawOutline(const RSProperties & properties,Drawing::Canvas & canvas)1387 void RSPropertiesPainter::DrawOutline(const RSProperties& properties, Drawing::Canvas& canvas)
1388 {
1389     auto outline = properties.GetOutline();
1390     if (outline && outline->HasBorder()) {
1391         DrawBorderBase(properties, canvas, outline, true);
1392     }
1393 }
1394 
DrawForegroundColor(const RSProperties & properties,Drawing::Canvas & canvas)1395 void RSPropertiesPainter::DrawForegroundColor(const RSProperties& properties, Drawing::Canvas& canvas)
1396 {
1397     auto bgColor = properties.GetForegroundColor();
1398     if (bgColor == RgbPalette::Transparent()) {
1399         return;
1400     }
1401     // clip
1402     if (properties.GetClipBounds() != nullptr) {
1403         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1404     } else if (properties.GetClipToBounds()) {
1405         canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, true);
1406     } else if (properties.GetClipToRRect()) {
1407         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, true);
1408     }
1409 
1410     Drawing::Brush brush;
1411     brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
1412     brush.SetAntiAlias(true);
1413     canvas.AttachBrush(brush);
1414     canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1415     canvas.DetachBrush();
1416 }
1417 
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas,Drawing::Rect maskBounds)1418 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas, Drawing::Rect maskBounds)
1419 {
1420     std::shared_ptr<RSMask> mask = properties.GetMask();
1421     if (mask == nullptr) {
1422         return;
1423     }
1424     if (mask->IsSvgMask() && !mask->GetSvgDom() && !mask->GetSvgPicture()) {
1425         ROSEN_LOGD("RSPropertiesPainter::DrawMask not has Svg Mask property");
1426         return;
1427     }
1428 
1429     canvas.Save();
1430     Drawing::SaveLayerOps slr(&maskBounds, nullptr);
1431     canvas.SaveLayer(slr);
1432     uint32_t tmpLayer = canvas.GetSaveCount();
1433 
1434     Drawing::Brush maskfilter;
1435     Drawing::Filter filter;
1436     filter.SetColorFilter(Drawing::ColorFilter::CreateComposeColorFilter(
1437         *(Drawing::ColorFilter::CreateLumaColorFilter()), *(Drawing::ColorFilter::CreateSrgbGammaToLinear())));
1438     maskfilter.SetFilter(filter);
1439     Drawing::SaveLayerOps slrMask(&maskBounds, &maskfilter);
1440     canvas.SaveLayer(slrMask);
1441     if (mask->IsSvgMask()) {
1442         Drawing::AutoCanvasRestore maskSave(canvas, true);
1443         canvas.Translate(maskBounds.GetLeft() + mask->GetSvgX(), maskBounds.GetTop() + mask->GetSvgY());
1444         canvas.Scale(mask->GetScaleX(), mask->GetScaleY());
1445         if (mask->GetSvgDom()) {
1446             canvas.DrawSVGDOM(mask->GetSvgDom());
1447         } else if (mask->GetSvgPicture()) {
1448             canvas.DrawPicture(*mask->GetSvgPicture());
1449         }
1450     } else if (mask->IsGradientMask()) {
1451         Drawing::AutoCanvasRestore maskSave(canvas, true);
1452         canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1453         Drawing::Rect rect = Drawing::Rect(
1454             0, 0, maskBounds.GetWidth(), maskBounds.GetHeight());
1455         canvas.AttachBrush(mask->GetMaskBrush());
1456         canvas.DrawRect(rect);
1457         canvas.DetachBrush();
1458     } else if (mask->IsPathMask()) {
1459         Drawing::AutoCanvasRestore maskSave(canvas, true);
1460         canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1461         canvas.AttachBrush(mask->GetMaskBrush());
1462         canvas.AttachPen(mask->GetMaskPen());
1463         canvas.DrawPath(*mask->GetMaskPath());
1464         canvas.DetachBrush();
1465         canvas.DetachPen();
1466     } else if (mask->IsPixelMapMask()) {
1467         Drawing::AutoCanvasRestore arc(canvas, true);
1468         if (mask->GetImage()) {
1469             canvas.DrawImage(*mask->GetImage(), 0.f, 0.f, Drawing::SamplingOptions());
1470         }
1471     }
1472 
1473     // back to mask layer
1474     canvas.RestoreToCount(tmpLayer);
1475     // create content layer
1476     Drawing::Brush maskPaint;
1477     maskPaint.SetBlendMode(Drawing::BlendMode::SRC_IN);
1478     Drawing::SaveLayerOps slrContent(&maskBounds, &maskPaint);
1479     canvas.SaveLayer(slrContent);
1480     canvas.ClipRect(maskBounds, Drawing::ClipOp::INTERSECT, true);
1481 }
1482 
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas)1483 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas)
1484 {
1485     Drawing::Rect maskBounds = Rect2DrawingRect(properties.GetBoundsRect());
1486     DrawMask(properties, canvas, maskBounds);
1487 }
1488 
DrawSpherize(const RSProperties & properties,RSPaintFilterCanvas & canvas,const std::shared_ptr<Drawing::Surface> & spherizeSurface)1489 void RSPropertiesPainter::DrawSpherize(const RSProperties& properties, RSPaintFilterCanvas& canvas,
1490     const std::shared_ptr<Drawing::Surface>& spherizeSurface)
1491 {
1492     if (spherizeSurface == nullptr) {
1493         return;
1494     }
1495     if (spherizeSurface->Width() == 0 || spherizeSurface->Height() == 0) {
1496         return;
1497     }
1498     Drawing::AutoCanvasRestore acr(canvas, true);
1499     float canvasWidth = properties.GetBoundsRect().GetWidth();
1500     float canvasHeight = properties.GetBoundsRect().GetHeight();
1501 
1502     auto imageSnapshot = spherizeSurface->GetImageSnapshot();
1503     if (imageSnapshot == nullptr) {
1504         ROSEN_LOGE("RSPropertiesPainter::DrawCachedSpherizeSurface image is null");
1505         return;
1506     }
1507     int imageWidth = imageSnapshot->GetWidth();
1508     int imageHeight = imageSnapshot->GetHeight();
1509     if (imageWidth == 0 || imageHeight == 0) {
1510         return;
1511     }
1512     canvas.Scale(canvasWidth / imageWidth, canvasHeight / imageHeight);
1513 
1514     float width = imageWidth;
1515     float height = imageHeight;
1516     float degree = properties.GetSpherize();
1517     bool isWidthGreater = width > height;
1518     ROSEN_LOGI("RSPropertiesPainter::DrawCachedSpherizeSurface spherize degree [%{public}f]", degree);
1519 
1520     Drawing::Brush brush;
1521     brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
1522     Drawing::SamplingOptions samplingOptions;
1523     Drawing::Matrix scaleMat;
1524     brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1525         *imageSnapshot, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat));
1526     canvas.AttachBrush(brush);
1527 
1528     const Drawing::Point texCoords[4] = {
1529         {0.0f, 0.0f}, {width, 0.0f}, {width, height}, {0.0f, height}
1530     };
1531     float offsetSquare = 0.f;
1532     if (isWidthGreater) {
1533         offsetSquare = (width - height) * degree / 2.0; // half of the change distance
1534         width = width - (width - height) * degree;
1535     } else {
1536         offsetSquare = (height - width) * degree / 2.0; // half of the change distance
1537         height = height - (height - width) * degree;
1538     }
1539 
1540     float segmentWidthOne = width / 3.0;
1541     float segmentWidthTwo = width / 3.0 * 2.0;
1542     float segmentHeightOne = height / 3.0;
1543     float segmentHeightTwo = height / 3.0 * 2.0;
1544     float offsetSphereWidth = width / 6 * degree;
1545     float offsetSphereHeight = height / 6  * degree;
1546 
1547     const int PointNum = 12;
1548     Drawing::Point ctrlPoints[PointNum] = {
1549         // top edge control points
1550         {0.0f, 0.0f}, {segmentWidthOne, 0.0f}, {segmentWidthTwo, 0.0f}, {width, 0.0f},
1551         // right edge control points
1552         {width, segmentHeightOne}, {width, segmentHeightTwo},
1553         // bottom edge control points
1554         {width, height}, {segmentWidthTwo, height}, {segmentWidthOne, height}, {0.0f, height},
1555         // left edge control points
1556         {0.0f, segmentHeightTwo}, {0.0f, segmentHeightOne}
1557     };
1558     ctrlPoints[0].Offset(offsetSphereWidth, offsetSphereHeight); // top left control point
1559     ctrlPoints[3].Offset(-offsetSphereWidth, offsetSphereHeight); // top right control point
1560     ctrlPoints[6].Offset(-offsetSphereWidth, -offsetSphereHeight); // bottom right control point
1561     ctrlPoints[9].Offset(offsetSphereWidth, -offsetSphereHeight); // bottom left control point
1562     if (isWidthGreater) {
1563         for (int i = 0; i < PointNum; ++i) {
1564             ctrlPoints[i].Offset(offsetSquare, 0);
1565         }
1566     } else {
1567         for (int i = 0; i < PointNum; ++i) {
1568             ctrlPoints[i].Offset(0, offsetSquare);
1569         }
1570     }
1571     Drawing::Path path;
1572     path.MoveTo(ctrlPoints[0].GetX(), ctrlPoints[0].GetY());
1573     path.CubicTo(ctrlPoints[1], ctrlPoints[2], ctrlPoints[3]); // upper edge
1574     path.CubicTo(ctrlPoints[4], ctrlPoints[5], ctrlPoints[6]); // right edge
1575     path.CubicTo(ctrlPoints[7], ctrlPoints[8], ctrlPoints[9]); // bottom edge
1576     path.CubicTo(ctrlPoints[10], ctrlPoints[11], ctrlPoints[0]); // left edge
1577     canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, true);
1578     canvas.DrawPatch(ctrlPoints, nullptr, texCoords, Drawing::BlendMode::SRC_OVER);
1579     canvas.DetachBrush();
1580 }
1581 
DrawColorFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas)1582 void RSPropertiesPainter::DrawColorFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1583 {
1584     // if useEffect defined, use color filter from parent EffectView.
1585     auto& colorFilter = properties.GetColorFilter();
1586     if (colorFilter == nullptr) {
1587         return;
1588     }
1589     Drawing::AutoCanvasRestore acr(canvas, true);
1590     canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1591     Drawing::Brush brush;
1592     brush.SetAntiAlias(true);
1593     Drawing::Filter filter;
1594     filter.SetColorFilter(colorFilter);
1595     brush.SetFilter(filter);
1596     auto surface = canvas.GetSurface();
1597     if (surface == nullptr) {
1598         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter surface is null");
1599         return;
1600     }
1601     auto clipBounds = canvas.GetDeviceClipBounds();
1602     auto imageSnapshot = surface->GetImageSnapshot(clipBounds);
1603     if (imageSnapshot == nullptr) {
1604         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter image is null");
1605         return;
1606     }
1607     imageSnapshot->HintCacheGpuResource();
1608     canvas.ResetMatrix();
1609     Drawing::SamplingOptions options(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
1610     canvas.AttachBrush(brush);
1611     canvas.DrawImageRect(*imageSnapshot, clipBounds, options);
1612     canvas.DetachBrush();
1613 }
1614 
DrawBinarizationShader(const RSProperties & properties,RSPaintFilterCanvas & canvas)1615 void RSPropertiesPainter::DrawBinarizationShader(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1616 {
1617     Drawing::AutoCanvasRestore acr(canvas, true);
1618     canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1619     auto drSurface = canvas.GetSurface();
1620     if (drSurface == nullptr) {
1621         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter drSurface is null");
1622         return;
1623     }
1624     auto clipBounds = canvas.GetDeviceClipBounds();
1625     auto imageSnapshot = drSurface->GetImageSnapshot(clipBounds);
1626     if (imageSnapshot == nullptr) {
1627         ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter image is null");
1628         return;
1629     }
1630     auto& aiInvert = properties.GetAiInvert();
1631     Drawing::Matrix matrix;
1632     auto imageShader = Drawing::ShaderEffect::CreateImageShader(*imageSnapshot, Drawing::TileMode::CLAMP,
1633         Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
1634     float thresholdLow = aiInvert->z_ - aiInvert->w_;
1635     float thresholdHigh = aiInvert->z_ + aiInvert->w_;
1636     auto shader = MakeBinarizationShader(
1637         aiInvert->x_, aiInvert->y_, thresholdLow, thresholdHigh, imageShader);
1638     Drawing::Brush brush;
1639     brush.SetShaderEffect(shader);
1640     brush.SetAntiAlias(true);
1641     canvas.ResetMatrix();
1642     canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1643     canvas.DrawBackground(brush);
1644 }
1645 
MakeBinarizationShader(float low,float high,float thresholdLow,float thresholdHigh,std::shared_ptr<Drawing::ShaderEffect> imageShader)1646 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeBinarizationShader(float low, float high,
1647     float thresholdLow, float thresholdHigh,
1648     std::shared_ptr<Drawing::ShaderEffect> imageShader)
1649 {
1650     static constexpr char prog[] = R"(
1651         uniform mediump float ubo_low;
1652         uniform mediump float ubo_high;
1653         uniform mediump float ubo_thresholdLow;
1654         uniform mediump float ubo_thresholdHigh;
1655         uniform shader imageShader;
1656         mediump vec4 main(vec2 drawing_coord) {
1657             mediump vec3 c = imageShader(drawing_coord).rgb;
1658             float gray = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
1659             float lowRes = mix(ubo_high, -1.0, step(ubo_thresholdLow, gray));
1660             float highRes = mix(-1.0, ubo_low, step(ubo_thresholdHigh, gray));
1661             float midRes = (ubo_thresholdHigh - gray) * (ubo_high - ubo_low) /
1662             (ubo_thresholdHigh - ubo_thresholdLow) + ubo_low;
1663             float invertedGray = mix(midRes, max(lowRes, highRes), step(-0.5, max(lowRes, highRes)));
1664             mediump vec3 invert = vec3(invertedGray);
1665             mediump vec4 res = vec4(invert, 1.0);
1666             return res;
1667         }
1668     )";
1669     if (binarizationShaderEffect_ == nullptr) {
1670         binarizationShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
1671         if (binarizationShaderEffect_ == nullptr) {
1672             ROSEN_LOGE("MakeBinarizationShader::RuntimeShader effect error\n");
1673             return nullptr;
1674         }
1675     }
1676     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
1677         std::make_shared<Drawing::RuntimeShaderBuilder>(binarizationShaderEffect_);
1678     // aviod zero-divide in shader
1679     thresholdHigh = thresholdHigh <= thresholdLow ? thresholdHigh + 1e-6 : thresholdHigh;
1680     builder->SetChild("imageShader", imageShader);
1681     builder->SetUniform("ubo_low", low);
1682     builder->SetUniform("ubo_high", high);
1683     builder->SetUniform("ubo_thresholdLow", thresholdLow);
1684     builder->SetUniform("ubo_thresholdHigh", thresholdHigh);
1685     return builder->MakeShader(nullptr, false);
1686 }
1687 
DrawLightUpEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)1688 void RSPropertiesPainter::DrawLightUpEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1689 {
1690     Drawing::Surface* surface = canvas.GetSurface();
1691     if (surface == nullptr) {
1692         ROSEN_LOGD("RSPropertiesPainter::DrawLightUpEffect surface is null");
1693         return;
1694     }
1695     Drawing::AutoCanvasRestore acr(canvas, true);
1696     if (properties.GetClipBounds() != nullptr) {
1697         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1698     } else {
1699         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1700     }
1701 
1702     auto blender = MakeLightUpEffectBlender(properties.GetLightUpEffect());
1703     Drawing::Brush brush;
1704     brush.SetBlender(blender);
1705     canvas.DrawBackground(brush);
1706 }
1707 
MakeLightUpEffectBlender(const float lightUpDeg)1708 std::shared_ptr<Drawing::Blender> RSPropertiesPainter::MakeLightUpEffectBlender(const float lightUpDeg)
1709 {
1710     static constexpr char prog[] = R"(
1711         uniform half lightUpDeg;
1712 
1713         vec3 rgb2hsv(in vec3 c)
1714         {
1715             vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
1716             vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
1717             vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
1718             float d = q.x - min(q.w, q.y);
1719             float e = 1.0e-10;
1720             return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
1721         }
1722         vec3 hsv2rgb(in vec3 c)
1723         {
1724             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);
1725             return c.z * mix(vec3(1.0), rgb, c.y);
1726         }
1727         vec4 main(vec4 drawing_src, vec4 drawing_dst) {
1728             drawing_dst = max(drawing_dst, 0.0);
1729             vec3 c = vec3(drawing_dst.r, drawing_dst.g, drawing_dst.b);
1730             vec3 hsv = rgb2hsv(c);
1731             float satUpper = clamp(hsv.y * 1.2, 0.0, 1.0);
1732             hsv.y = mix(satUpper, hsv.y, lightUpDeg);
1733             hsv.z += lightUpDeg - 1.0;
1734             hsv.z = max(hsv.z, 0.0);
1735             return vec4(hsv2rgb(hsv), drawing_dst.a);
1736         }
1737     )";
1738     if (lightUpEffectBlender_ == nullptr) {
1739         lightUpEffectBlender_ = Drawing::RuntimeEffect::CreateForBlender(prog);
1740         if (lightUpEffectBlender_ == nullptr) {
1741             return nullptr;
1742         }
1743     }
1744     auto builder = std::make_shared<Drawing::RuntimeBlenderBuilder>(lightUpEffectBlender_);
1745     builder->SetUniform("lightUpDeg", lightUpDeg);
1746     return builder->MakeBlender();
1747 }
1748 
DrawDynamicLightUp(const RSProperties & properties,RSPaintFilterCanvas & canvas)1749 void RSPropertiesPainter::DrawDynamicLightUp(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1750 {
1751     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawDynamicLightUp, rate: %f, degree: %f, bounds: %s",
1752         properties.GetDynamicLightUpRate().value(), properties.GetDynamicLightUpDegree().value(),
1753         properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
1754     Drawing::Surface* surface = canvas.GetSurface();
1755     if (surface == nullptr) {
1756         ROSEN_LOGD("RSPropertiesPainter::DrawDynamicLightUp surface is null");
1757         return;
1758     }
1759 
1760     auto blender = MakeDynamicLightUpBlender(properties.GetDynamicLightUpRate().value() * canvas.GetAlpha(),
1761         properties.GetDynamicLightUpDegree().value() * canvas.GetAlpha());
1762     Drawing::Brush brush;
1763     brush.SetBlender(blender);
1764     canvas.DrawBackground(brush);
1765 }
1766 
MakeDynamicLightUpBlender(float dynamicLightUpRate,float dynamicLightUpDeg)1767 std::shared_ptr<Drawing::Blender> RSPropertiesPainter::MakeDynamicLightUpBlender(
1768     float dynamicLightUpRate, float dynamicLightUpDeg)
1769 {
1770     static constexpr char prog[] = R"(
1771         uniform float dynamicLightUpRate;
1772         uniform float dynamicLightUpDeg;
1773 
1774         vec4 main(vec4 drawing_src, vec4 drawing_dst) {
1775             float x = 0.299 * drawing_dst.r + 0.587 * drawing_dst.g + 0.114 * drawing_dst.b;
1776             float y = (0 - dynamicLightUpRate) * x + dynamicLightUpDeg;
1777             float R = clamp((drawing_dst.r + y), 0.0, 1.0);
1778             float G = clamp((drawing_dst.g + y), 0.0, 1.0);
1779             float B = clamp((drawing_dst.b + y), 0.0, 1.0);
1780             return vec4(R, G, B, 1.0);
1781         }
1782     )";
1783     if (dynamicLightUpBlenderEffect_ == nullptr) {
1784         dynamicLightUpBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
1785         if (dynamicLightUpBlenderEffect_ == nullptr) {
1786             return nullptr;
1787         }
1788     }
1789     auto builder = std::make_shared<Drawing::RuntimeBlenderBuilder>(dynamicLightUpBlenderEffect_);
1790     builder->SetUniform("dynamicLightUpRate", dynamicLightUpRate);
1791     builder->SetUniform("dynamicLightUpDeg", dynamicLightUpDeg);
1792     return builder->MakeBlender();
1793 }
1794 
DrawDynamicDim(const RSProperties & properties,RSPaintFilterCanvas & canvas)1795 void RSPropertiesPainter::DrawDynamicDim(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1796 {
1797     Drawing::Surface* surface = canvas.GetSurface();
1798     if (surface == nullptr) {
1799         ROSEN_LOGD("RSPropertiesPainter::DrawDynamicDim surface is null");
1800         return;
1801     }
1802     Drawing::AutoCanvasRestore acr(canvas, true);
1803     if (properties.GetClipBounds() != nullptr) {
1804         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1805     } else {
1806         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1807     }
1808 
1809     auto clipBounds = canvas.GetDeviceClipBounds();
1810     auto image = surface->GetImageSnapshot(clipBounds);
1811     if (image == nullptr) {
1812         ROSEN_LOGE("RSPropertiesPainter::DrawDynamicDim image is null");
1813         return;
1814     }
1815     Drawing::Matrix scaleMat;
1816     auto imageShader = Drawing::ShaderEffect::CreateImageShader(
1817         *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
1818         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), scaleMat);
1819     auto shader = MakeDynamicDimShader(properties.GetDynamicDimDegree().value(), imageShader);
1820     if (shader == nullptr) {
1821         ROSEN_LOGE("RSPropertiesPainter::DrawDynamicDim shader is null");
1822         return;
1823     }
1824     Drawing::Brush brush;
1825     brush.SetShaderEffect(shader);
1826     canvas.ResetMatrix();
1827     canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1828     canvas.DrawBackground(brush);
1829 }
1830 
MakeDynamicDimShader(float dynamicDimDeg,std::shared_ptr<Drawing::ShaderEffect> imageShader)1831 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeDynamicDimShader(
1832     float dynamicDimDeg, std::shared_ptr<Drawing::ShaderEffect> imageShader)
1833 {
1834     static constexpr char prog[] = R"(
1835         uniform half dynamicDimDeg;
1836         uniform shader imageShader;
1837 
1838         vec3 rgb2hsv(in vec3 c)
1839         {
1840             vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
1841             vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
1842             vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
1843             float d = q.x - min(q.w, q.y);
1844             float e = 1.0e-10;
1845             return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
1846         }
1847         vec3 hsv2rgb(in vec3 c)
1848         {
1849             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);
1850             return c.z * mix(vec3(1.0), rgb, c.y);
1851         }
1852         half4 main(float2 coord)
1853         {
1854             vec3 hsv = rgb2hsv(imageShader.eval(coord).rgb);
1855             float value = max(0.8, dynamicDimDeg); // 0.8 is min saturation ratio.
1856             hsv.y = hsv.y * (1.75 - value * 0.75); // saturation value [1.0 , 1.15].
1857             hsv.z = min(hsv.z * dynamicDimDeg, 1.0);
1858             return vec4(hsv2rgb(hsv), 1.0);
1859         }
1860     )";
1861     if (dynamicDimShaderEffect_ == nullptr) {
1862         dynamicDimShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
1863         if (dynamicDimShaderEffect_ == nullptr) {
1864             ROSEN_LOGE("MakeBinarizationShader::RuntimeShader effect error\n");
1865             return nullptr;
1866         }
1867     }
1868     std::shared_ptr<Drawing::ShaderEffect> children[] = {imageShader};
1869     size_t childCount = 1;
1870     auto data = std::make_shared<Drawing::Data>();
1871     data->BuildWithCopy(&dynamicDimDeg, sizeof(dynamicDimDeg));
1872     return dynamicDimShaderEffect_->MakeShader(data, children, childCount, nullptr, false);
1873 }
1874 
DrawParticle(const RSProperties & properties,RSPaintFilterCanvas & canvas)1875 void RSPropertiesPainter::DrawParticle(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1876 {
1877     const auto& particleVector = properties.GetParticles();
1878     if (particleVector.GetParticleSize() == 0) {
1879         return;
1880     }
1881     const auto& particles = particleVector.GetParticleVector();
1882     auto bounds = properties.GetDrawRegion();
1883     auto imageCount = particleVector.GetParticleImageCount();
1884     auto imageVector = particleVector.GetParticleImageVector();
1885     auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
1886     if (particleDrawable != nullptr) {
1887         particleDrawable->Draw(canvas, bounds);
1888     }
1889 }
1890 
IsDangerousBlendMode(int blendMode,int blendApplyType)1891 bool RSPropertiesPainter::IsDangerousBlendMode(int blendMode, int blendApplyType)
1892 {
1893     static const uint32_t fastDangerousBit =
1894         (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1895         (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1896         (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1897         (1 << static_cast<int>(Drawing::BlendMode::XOR));
1898     static const uint32_t offscreenDangerousBit =
1899         (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1900         (1 << static_cast<int>(Drawing::BlendMode::SRC)) +
1901         (1 << static_cast<int>(Drawing::BlendMode::SRC_IN)) +
1902         (1 << static_cast<int>(Drawing::BlendMode::DST_IN)) +
1903         (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1904         (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1905         (1 << static_cast<int>(Drawing::BlendMode::DST_ATOP)) +
1906         (1 << static_cast<int>(Drawing::BlendMode::XOR)) +
1907         (1 << static_cast<int>(Drawing::BlendMode::MODULATE));
1908     uint32_t tmp = 1 << blendMode;
1909     if (blendApplyType == static_cast<int>(RSColorBlendApplyType::FAST)) {
1910         return tmp & fastDangerousBit;
1911     }
1912     return tmp & offscreenDangerousBit;
1913 }
1914 } // namespace Rosen
1915 } // namespace OHOS
1916