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