• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "property/rs_properties_painter.h"
17 #include "rs_trace.h"
18 
19 #include "common/rs_obj_abs_geometry.h"
20 #include "common/rs_optional_trace.h"
21 #include "pipeline/rs_effect_render_node.h"
22 #include "pipeline/rs_paint_filter_canvas.h"
23 #include "pipeline/rs_root_render_node.h"
24 #include "platform/common/rs_log.h"
25 #include "property/rs_point_light_manager.h"
26 #include "property/rs_properties_def.h"
27 #include "render/rs_blur_filter.h"
28 #include "render/rs_drawing_filter.h"
29 #include "render/rs_distortion_shader_filter.h"
30 #include "render/rs_foreground_effect_filter.h"
31 #include "render/rs_render_kawase_blur_filter.h"
32 #include "render/rs_render_linear_gradient_blur_filter.h"
33 #include "render/rs_skia_filter.h"
34 #include "render/rs_render_magnifier_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 
65 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::greyAdjustEffect_ = nullptr;
66 
Rect2DrawingRect(const RectF & r)67 Drawing::Rect RSPropertiesPainter::Rect2DrawingRect(const RectF& r)
68 {
69     return Drawing::Rect(r.left_, r.top_, r.left_ + r.width_, r.top_ + r.height_);
70 }
71 
RRect2DrawingRRect(const RRect & rr)72 Drawing::RoundRect RSPropertiesPainter::RRect2DrawingRRect(const RRect& rr)
73 {
74     Drawing::Rect rect = Drawing::Rect(
75         rr.rect_.left_, rr.rect_.top_, rr.rect_.left_ + rr.rect_.width_, rr.rect_.top_ + rr.rect_.height_);
76 
77     // set radius for all 4 corner of RRect
78     constexpr uint32_t NUM_OF_CORNERS_IN_RECT = 4;
79     std::vector<Drawing::Point> radii(NUM_OF_CORNERS_IN_RECT);
80     for (uint32_t i = 0; i < NUM_OF_CORNERS_IN_RECT; i++) {
81         radii.at(i).SetX(rr.radius_[i].x_);
82         radii.at(i).SetY(rr.radius_[i].y_);
83     }
84     return Drawing::RoundRect(rect, radii);
85 }
86 
GetGravityMatrix(Gravity gravity,RectF rect,float w,float h,Drawing::Matrix & mat)87 bool RSPropertiesPainter::GetGravityMatrix(Gravity gravity, RectF rect, float w, float h, Drawing::Matrix& mat)
88 {
89     if (w == rect.width_ && h == rect.height_) {
90         return false;
91     }
92     mat = Drawing::Matrix();
93 
94     switch (gravity) {
95         case Gravity::CENTER: {
96             mat.PreTranslate((rect.width_ - w) / PARAM_DOUBLE, (rect.height_ - h) / PARAM_DOUBLE);
97             return true;
98         }
99         case Gravity::TOP: {
100             mat.PreTranslate((rect.width_ - w) / PARAM_DOUBLE, 0);
101             return true;
102         }
103         case Gravity::BOTTOM: {
104             mat.PreTranslate((rect.width_ - w) / PARAM_DOUBLE, rect.height_ - h);
105             return true;
106         }
107         case Gravity::LEFT: {
108             mat.PreTranslate(0, (rect.height_ - h) / PARAM_DOUBLE);
109             return true;
110         }
111         case Gravity::RIGHT: {
112             mat.PreTranslate(rect.width_ - w, (rect.height_ - h) / PARAM_DOUBLE);
113             return true;
114         }
115         case Gravity::TOP_LEFT: {
116             return false;
117         }
118         case Gravity::TOP_RIGHT: {
119             mat.PreTranslate(rect.width_ - w, 0);
120             return true;
121         }
122         case Gravity::BOTTOM_LEFT: {
123             mat.PreTranslate(0, rect.height_ - h);
124             return true;
125         }
126         case Gravity::BOTTOM_RIGHT: {
127             mat.PreTranslate(rect.width_ - w, rect.height_ - h);
128             return true;
129         }
130         case Gravity::RESIZE: {
131             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
132                 return false;
133             }
134             mat.PreScale(rect.width_ / w, rect.height_ / h);
135             return true;
136         }
137         case Gravity::RESIZE_ASPECT: {
138             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
139                 return false;
140             }
141             float scale = std::min(rect.width_ / w, rect.height_ / h);
142             if (ROSEN_EQ(scale, 0.f)) {
143                 return false;
144             }
145             mat.PreScale(scale, scale);
146             mat.PreTranslate((rect.width_ / scale - w) / PARAM_DOUBLE, (rect.height_ / scale - h) / PARAM_DOUBLE);
147             return true;
148         }
149         case Gravity::RESIZE_ASPECT_TOP_LEFT: {
150             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
151                 return false;
152             }
153             float scale = std::min(rect.width_ / w, rect.height_ / h);
154             mat.PreScale(scale, scale);
155             return true;
156         }
157         case Gravity::RESIZE_ASPECT_BOTTOM_RIGHT: {
158             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
159                 return false;
160             }
161             float scale = std::min(rect.width_ / w, rect.height_ / h);
162             if (ROSEN_EQ(scale, 0.f)) {
163                 return false;
164             }
165             mat.PreScale(scale, scale);
166             mat.PreTranslate(rect.width_ / scale - w, rect.height_ / scale - h);
167             return true;
168         }
169         case Gravity::RESIZE_ASPECT_FILL: {
170             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
171                 return false;
172             }
173             float scale = std::max(rect.width_ / w, rect.height_ / h);
174             if (ROSEN_EQ(scale, 0.f)) {
175                 return false;
176             }
177             mat.PreScale(scale, scale);
178             mat.PreTranslate((rect.width_ / scale - w) / PARAM_DOUBLE, (rect.height_ / scale - h) / PARAM_DOUBLE);
179             return true;
180         }
181         case Gravity::RESIZE_ASPECT_FILL_TOP_LEFT: {
182             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
183                 return false;
184             }
185             float scale = std::max(rect.width_ / w, rect.height_ / h);
186             mat.PreScale(scale, scale);
187             return true;
188         }
189         case Gravity::RESIZE_ASPECT_FILL_BOTTOM_RIGHT: {
190             if (ROSEN_EQ(w, 0.f) || ROSEN_EQ(h, 0.f)) {
191                 return false;
192             }
193             float scale = std::max(rect.width_ / w, rect.height_ / h);
194             if (ROSEN_EQ(scale, 0.f)) {
195                 return false;
196             }
197             mat.PreScale(scale, scale);
198             mat.PreTranslate(rect.width_ / scale - w, rect.height_ / scale - h);
199             return true;
200         }
201         default: {
202             ROSEN_LOGE("GetGravityMatrix unknow gravity=[%{public}d]", gravity);
203             return false;
204         }
205     }
206 }
207 
GetScalingModeMatrix(ScalingMode scalingMode,RectF bounds,float bufferWidth,float bufferHeight,Drawing::Matrix & scalingModeMatrix)208 bool RSPropertiesPainter::GetScalingModeMatrix(ScalingMode scalingMode, RectF bounds,
209     float bufferWidth, float bufferHeight, Drawing::Matrix& scalingModeMatrix)
210 {
211     if (ROSEN_EQ(bufferWidth, bounds.width_) && ROSEN_EQ(bufferHeight, bounds.height_)) {
212         return false;
213     }
214     scalingModeMatrix = Drawing::Matrix();
215     switch (scalingMode) {
216         case ScalingMode::SCALING_MODE_SCALE_CROP: {
217             if (ROSEN_EQ(bufferWidth, 0.f) || ROSEN_EQ(bufferHeight, 0.f)) {
218                 return false;
219             }
220             float scale = std::max(bounds.width_ / bufferWidth, bounds.height_ / bufferHeight);
221             if (ROSEN_NE(scale, 0.f)) {
222                 scalingModeMatrix.PreScale(scale, scale);
223                 scalingModeMatrix.PreTranslate((bounds.width_ / scale - bufferWidth) / PARAM_DOUBLE,
224                     (bounds.height_ / scale - bufferHeight) / PARAM_DOUBLE);
225                 return true;
226             }
227             return false;
228         }
229         case ScalingMode::SCALING_MODE_SCALE_FIT: {
230             if (ROSEN_EQ(bufferWidth, 0.f) || ROSEN_EQ(bufferHeight, 0.f)) {
231                 return false;
232             }
233             float scale = std::min(bounds.width_ / bufferWidth, bounds.height_ / bufferHeight);
234             if (ROSEN_NE(scale, 0.f)) {
235                 scalingModeMatrix.PreScale(scale, scale);
236                 scalingModeMatrix.PreTranslate((bounds.width_ / scale - bufferWidth) / PARAM_DOUBLE,
237                     (bounds.height_ / scale - bufferHeight) / PARAM_DOUBLE);
238                 return true;
239             }
240             return false;
241         }
242         case ScalingMode::SCALING_MODE_NO_SCALE_CROP: {
243             if (ROSEN_EQ(bufferWidth, 0.f) || ROSEN_EQ(bufferHeight, 0.f)) {
244                 return false;
245             }
246             scalingModeMatrix.PreTranslate((bounds.width_ - bufferWidth) / PARAM_DOUBLE,
247                 (bounds.height_ - bufferHeight) / PARAM_DOUBLE);
248             return true;
249         }
250         case ScalingMode::SCALING_MODE_FREEZE: [[fallthrough]];
251         case ScalingMode::SCALING_MODE_SCALE_TO_WINDOW: {
252             return true;
253         }
254         default: {
255             ROSEN_LOGE("GetScalingModeMatrix: Unknown ScalingMode=[%{public}d]", static_cast<int>(scalingMode));
256             return false;
257         }
258     }
259 }
260 
Clip(Drawing::Canvas & canvas,RectF rect,bool isAntiAlias)261 void RSPropertiesPainter::Clip(Drawing::Canvas& canvas, RectF rect, bool isAntiAlias)
262 {
263     canvas.ClipRect(Rect2DrawingRect(rect), Drawing::ClipOp::INTERSECT, isAntiAlias);
264 }
265 
GetShadowDirtyRect(RectI & dirtyShadow,const RSProperties & properties,const RRect * rrect,bool isAbsCoordinate,bool radiusInclude)266 void RSPropertiesPainter::GetShadowDirtyRect(RectI& dirtyShadow, const RSProperties& properties,
267     const RRect* rrect, bool isAbsCoordinate, bool radiusInclude)
268 {
269     // [Planning]: After Skia being updated, we should directly call SkShadowUtils::GetLocalBounds here.
270     if (!properties.IsShadowValid()) {
271         return;
272     }
273     Drawing::Path path;
274     if (properties.GetShadowPath() && properties.GetShadowPath()->GetDrawingPath().IsValid()) {
275         path = properties.GetShadowPath()->GetDrawingPath();
276     } else if (properties.GetClipBounds()) {
277         path = properties.GetClipBounds()->GetDrawingPath();
278     } else {
279         if (rrect != nullptr) {
280             path.AddRoundRect(RRect2DrawingRRect(*rrect));
281         } else {
282             path.AddRoundRect(RRect2DrawingRRect(properties.GetRRect()));
283         }
284     }
285     path.Offset(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
286 
287     Drawing::Rect shadowRect = path.GetBounds();
288     if (properties.GetShadowElevation() > 0.f) {
289         float elevation = properties.GetShadowElevation() + DEFAULT_TRANSLATION_Z;
290 
291         float userTransRatio =
292             (elevation != DEFAULT_LIGHT_HEIGHT) ? elevation / (DEFAULT_LIGHT_HEIGHT - elevation) : MAX_TRANS_RATIO;
293         float transRatio = std::max(MIN_TRANS_RATIO, std::min(userTransRatio, MAX_TRANS_RATIO));
294 
295         float userSpotRatio = (elevation != DEFAULT_LIGHT_HEIGHT)
296                                   ? DEFAULT_LIGHT_HEIGHT / (DEFAULT_LIGHT_HEIGHT - elevation)
297                                   : MAX_SPOT_RATIO;
298         float spotRatio = std::max(MIN_SPOT_RATIO, std::min(userSpotRatio, MAX_SPOT_RATIO));
299 
300         Drawing::Rect ambientRect = path.GetBounds();
301         Drawing::Rect spotRect = Drawing::Rect(ambientRect.GetLeft() * spotRatio, ambientRect.GetTop() * spotRatio,
302             ambientRect.GetRight() * spotRatio, ambientRect.GetBottom() * spotRatio);
303         spotRect.Offset(-transRatio * DEFAULT_LIGHT_POSITION_X, -transRatio * DEFAULT_LIGHT_POSITION_Y);
304         spotRect.MakeOutset(transRatio * DEFAULT_LIGHT_RADIUS, transRatio * DEFAULT_LIGHT_RADIUS);
305 
306         shadowRect = ambientRect;
307         float ambientBlur = std::min(elevation * 0.5f, MAX_AMBIENT_RADIUS);
308         shadowRect.MakeOutset(ambientBlur, ambientBlur);
309 
310         shadowRect.Join(spotRect);
311     } else {
312         Drawing::Brush brush;
313         brush.SetAntiAlias(true);
314         Drawing::Filter filter;
315         filter.SetMaskFilter(
316             Drawing::MaskFilter::CreateBlurMaskFilter(Drawing::BlurType::NORMAL, properties.GetShadowRadius()));
317         brush.SetFilter(filter);
318         if (brush.CanComputeFastBounds() && radiusInclude) {
319             brush.ComputeFastBounds(shadowRect, &shadowRect);
320         }
321     }
322     // avoid 1 pixel reduction caused by converting float to int
323     shadowRect.MakeOutset(1, 1);
324 
325     auto& geoPtr = (properties.GetBoundsGeometry());
326     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
327     matrix.MapRect(shadowRect, shadowRect);
328 
329     dirtyShadow.left_ = shadowRect.GetLeft();
330     dirtyShadow.top_ = shadowRect.GetTop();
331     dirtyShadow.width_ = shadowRect.GetWidth();
332     dirtyShadow.height_ = shadowRect.GetHeight();
333 }
334 
DrawShadow(const RSProperties & properties,RSPaintFilterCanvas & canvas,const RRect * rrect)335 void RSPropertiesPainter::DrawShadow(const RSProperties& properties, RSPaintFilterCanvas& canvas, const RRect* rrect)
336 {
337     // skip shadow if not valid or cache is enabled
338     if (properties.IsSpherizeValid() || !properties.IsShadowValid() ||
339         canvas.GetCacheType() == RSPaintFilterCanvas::CacheType::ENABLED) {
340         return;
341     }
342     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO,
343         "RSPropertiesPainter::DrawShadow, ShadowElevation: %f, ShadowRadius: %f, ShadowOffsetX: "
344         "%f, ShadowOffsetY: %f, bounds: %s",
345         properties.GetShadowElevation(), properties.GetShadowRadius(), properties.GetShadowOffsetX(),
346         properties.GetShadowOffsetY(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
347     Drawing::AutoCanvasRestore acr(canvas, true);
348     Drawing::Path path;
349     if (properties.GetShadowPath() && properties.GetShadowPath()->GetDrawingPath().IsValid()) {
350         path = properties.GetShadowPath()->GetDrawingPath();
351         if (!properties.GetShadowIsFilled()) {
352             canvas.ClipPath(path, Drawing::ClipOp::DIFFERENCE, true);
353         }
354     } else if (properties.GetClipBounds()) {
355         path = properties.GetClipBounds()->GetDrawingPath();
356         if (!properties.GetShadowIsFilled()) {
357             canvas.ClipPath(path, Drawing::ClipOp::DIFFERENCE, true);
358         }
359     } else {
360         if (rrect != nullptr) {
361             path.AddRoundRect(RRect2DrawingRRect(*rrect));
362             if (!properties.GetShadowIsFilled()) {
363                 canvas.ClipRoundRect(RRect2DrawingRRect(*rrect), Drawing::ClipOp::DIFFERENCE, true);
364             }
365         } else {
366             path.AddRoundRect(RRect2DrawingRRect(properties.GetRRect()));
367             if (!properties.GetShadowIsFilled()) {
368                 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::DIFFERENCE, true);
369             }
370         }
371     }
372     if (properties.GetShadowMask()) {
373         DrawColorfulShadowInner(properties, canvas, path);
374     } else {
375         DrawShadowInner(properties, canvas, path);
376     }
377 }
378 
DrawColorfulShadowInner(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::Path & path)379 void RSPropertiesPainter::DrawColorfulShadowInner(
380     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::Path& path)
381 {
382     // blurRadius calculation is based on the formula in Canvas::DrawShadow, 0.25f and 128.0f are constants
383     const Drawing::scalar blurRadius =
384         properties.GetShadowElevation() > 0.f
385             ? 0.25f * properties.GetShadowElevation() * (1 + properties.GetShadowElevation() / 128.0f)
386             : properties.GetShadowRadius();
387 
388     // save layer, draw image with clipPath, blur and draw back
389     Drawing::Brush blurBrush;
390     Drawing::Filter filter;
391     filter.SetImageFilter(Drawing::ImageFilter::CreateBlurImageFilter(
392         blurRadius, blurRadius, Drawing::TileMode::DECAL, nullptr));
393     blurBrush.SetFilter(filter);
394 
395     canvas.SaveLayer({nullptr, &blurBrush});
396 
397     canvas.Translate(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
398 
399     canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, false);
400     // draw node content as shadow
401     // [PLANNING]: maybe we should also draw background color / image here, and we should cache the shadow image
402     if (auto node = RSBaseRenderNode::ReinterpretCast<RSCanvasRenderNode>(properties.backref_.lock())) {
403         node->InternalDrawContent(canvas, false);
404     }
405 }
406 
DrawShadowInner(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::Path & path)407 void RSPropertiesPainter::DrawShadowInner(
408     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::Path& path)
409 {
410     path.Offset(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
411     Color spotColor = properties.GetShadowColor();
412     auto deviceClipBounds = canvas.GetDeviceClipBounds();
413 
414     // The translation of the matrix is rounded to improve the hit ratio of skia blurfilter cache,
415     // the function <compute_key_and_clip_bounds> in <skia/src/gpu/GrBlurUtil.cpp> for more details.
416     RSAutoCanvasRestore rst(&canvas);
417     auto matrix = canvas.GetTotalMatrix();
418     matrix.Set(Drawing::Matrix::TRANS_X, std::ceil(matrix.Get(Drawing::Matrix::TRANS_X)));
419     matrix.Set(Drawing::Matrix::TRANS_Y, std::ceil(matrix.Get(Drawing::Matrix::TRANS_Y)));
420     canvas.SetMatrix(matrix);
421 
422     if (properties.GetShadowElevation() > 0.f) {
423         Drawing::Point3 planeParams = { 0.0f, 0.0f, properties.GetShadowElevation() };
424         std::vector<Drawing::Point> pt{{path.GetBounds().GetLeft() + path.GetBounds().GetWidth() / 2,
425             path.GetBounds().GetTop() + path.GetBounds().GetHeight() / 2}};
426         canvas.GetTotalMatrix().MapPoints(pt, pt, 1);
427         Drawing::Point3 lightPos = {pt[0].GetX(), pt[0].GetY(), DEFAULT_LIGHT_HEIGHT};
428         Color ambientColor = Color::FromArgbInt(DEFAULT_AMBIENT_COLOR);
429         ambientColor.MultiplyAlpha(canvas.GetAlpha());
430         spotColor.MultiplyAlpha(canvas.GetAlpha());
431         canvas.DrawShadowStyle(path, planeParams, lightPos, DEFAULT_LIGHT_RADIUS,
432             Drawing::Color(ambientColor.AsArgbInt()), Drawing::Color(spotColor.AsArgbInt()),
433             Drawing::ShadowFlags::TRANSPARENT_OCCLUDER, true);
434     } else {
435         Drawing::Brush brush;
436         brush.SetColor(Drawing::Color::ColorQuadSetARGB(
437             spotColor.GetAlpha(), spotColor.GetRed(), spotColor.GetGreen(), spotColor.GetBlue()));
438         brush.SetAntiAlias(true);
439         Drawing::Filter filter;
440         filter.SetMaskFilter(
441             Drawing::MaskFilter::CreateBlurMaskFilter(Drawing::BlurType::NORMAL, properties.GetShadowRadius()));
442         brush.SetFilter(filter);
443         canvas.AttachBrush(brush);
444         canvas.DrawPath(path);
445         canvas.DetachBrush();
446     }
447 }
448 
MakeGreyAdjustmentEffect()449 std::shared_ptr<Drawing::RuntimeEffect> RSPropertiesPainter::MakeGreyAdjustmentEffect()
450 {
451     static const std::string GreyGradationString(R"(
452         uniform shader imageShader;
453         uniform float coefficient1;
454         uniform float coefficient2;
455 
456         float poww(float x, float y) {
457             return (x < 0) ? -pow(-x, y) : pow(x, y);
458         }
459 
460         float calculateT_y(float rgb) {
461             if (rgb > 127.5) { rgb = 255 - rgb; }
462             float b = 38.0;
463             float c = 45.0;
464             float d = 127.5;
465             float A = 106.5;    // 3 * b - 3 * c + d;
466             float B = -93;      // 3 * (c - 2 * b);
467             float C = 114;      // 3 * b;
468             float p = 0.816240163988;                   // (3 * A * C - pow(B, 2)) / (3 * pow(A, 2));
469             float q = -rgb / 106.5 + 0.262253485943;    // -rgb/A - B*C/(3*pow(A,2)) + 2*pow(B,3)/(27*pow(A,3))
470             float s1 = -(q / 2.0);
471             float s2 = sqrt(pow(s1, 2) + pow(p / 3, 3));
472             return poww((s1 + s2), 1.0 / 3) + poww((s1 - s2), 1.0 / 3) - (B / (3 * A));
473         }
474 
475         float calculateGreyAdjustY(float rgb) {
476             float t_r = calculateT_y(rgb);
477             return (rgb < 127.5) ? (rgb + coefficient1 * pow((1 - t_r), 3)) : (rgb - coefficient2 * pow((1 - t_r), 3));
478         }
479 
480         vec4 main(vec2 drawing_coord) {
481             vec3 color = vec3(imageShader(drawing_coord).r, imageShader(drawing_coord).g, imageShader(drawing_coord).b);
482             float Y = (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) * 255;
483             float U = (-0.147 * color.r - 0.289 * color.g + 0.436 * color.b) * 255;
484             float V = (0.615 * color.r - 0.515 * color.g - 0.100 * color.b) * 255;
485             Y = calculateGreyAdjustY(Y);
486             color.r = (Y + 1.14 * V) / 255.0;
487             color.g = (Y - 0.39 * U - 0.58 * V) / 255.0;
488             color.b = (Y + 2.03 * U) / 255.0;
489 
490             return vec4(color, 1.0);
491         }
492     )");
493     if (!greyAdjustEffect_) {
494         std::shared_ptr<Drawing::RuntimeEffect> greyAdjustEffect =
495             Drawing::RuntimeEffect::CreateForShader(GreyGradationString);
496         if (!greyAdjustEffect) {
497             return nullptr;
498         }
499         greyAdjustEffect_ = std::move(greyAdjustEffect);
500     }
501 
502     return greyAdjustEffect_;
503 }
504 
DrawGreyAdjustment(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Vector2f & greyCoeff)505 std::shared_ptr<Drawing::Image> RSPropertiesPainter::DrawGreyAdjustment(Drawing::Canvas& canvas,
506     const std::shared_ptr<Drawing::Image>& image, const Vector2f& greyCoeff)
507 {
508 #ifdef RS_ENABLE_GPU
509     if (image == nullptr) {
510         ROSEN_LOGE("RSPropertiesPainter::DrawGreyAdjustment image is null");
511         return nullptr;
512     }
513     RS_TRACE_NAME_FMT("RSPropertiesPainter::DrawGreyAdjustment, greyCoef1 is: %f, greyCoef2 is: %f",
514         greyCoeff.x_, greyCoeff.y_);
515     auto greyAdjustEffect = MakeGreyAdjustmentEffect();
516     if (!greyAdjustEffect) {
517         ROSEN_LOGE("RSPropertiesPainter::DrawGreyAdjustment greyAdjustEffect is null");
518         return nullptr;
519     }
520     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
521         std::make_shared<Drawing::RuntimeShaderBuilder>(greyAdjustEffect);
522     Drawing::Matrix matrix;
523     auto imageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
524         Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
525     builder->SetChild("imageShader", imageShader);
526     builder->SetUniform("coefficient1", greyCoeff.x_);
527     builder->SetUniform("coefficient2", greyCoeff.y_);
528     return builder->MakeImage(canvas.GetGPUContext().get(), nullptr, image->GetImageInfo(), false);
529 #else
530     return nullptr;
531 #endif
532 }
533 
DrawFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas,FilterType filterType,const std::optional<Drawing::Rect> & rect,const std::shared_ptr<RSFilter> & externalFilter)534 void RSPropertiesPainter::DrawFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas,
535     FilterType filterType, const std::optional<Drawing::Rect>& rect, const std::shared_ptr<RSFilter>& externalFilter)
536 {
537     if (!BLUR_ENABLED) {
538         ROSEN_LOGD("RSPropertiesPainter::DrawFilter close blur.");
539         return;
540     }
541     // use provided filter if not null
542     auto& RSFilter = externalFilter ? externalFilter
543         : ((filterType == FilterType::BACKGROUND_FILTER) ? properties.GetBackgroundFilter() : properties.GetFilter());
544     if (RSFilter == nullptr) {
545         return;
546     }
547 
548     RS_OPTIONAL_TRACE_NAME("DrawFilter " + RSFilter->GetDescription());
549     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawFilter, filterType: %d, %s, bounds: %s", filterType,
550         RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
551     g_blurCnt++;
552     Drawing::AutoCanvasRestore acr(canvas, true);
553 
554     auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
555     auto surface = canvas.GetSurface();
556     if (surface == nullptr) {
557         ROSEN_LOGD("RSPropertiesPainter::DrawFilter surface null");
558         Drawing::Brush brush;
559         brush.SetAntiAlias(true);
560         Drawing::Filter filterForBrush;
561         auto imageFilter = filter->GetImageFilter();
562         // Since using Kawase blur (shader) in the screenshot scene would lead to failure,
563         // a Gaussian blur filter (imageFilter) is regenerated here instead.
564         auto kawaseShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::KAWASE);
565         if (kawaseShaderFilter != nullptr) {
566             auto tmpFilter = std::static_pointer_cast<RSKawaseBlurShaderFilter>(kawaseShaderFilter);
567             auto radius = tmpFilter->GetRadius();
568             std::shared_ptr<Drawing::ImageFilter> blurFilter = Drawing::ImageFilter::CreateBlurImageFilter(
569                 radius, radius, Drawing::TileMode::CLAMP, nullptr);
570             imageFilter = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter, blurFilter);
571         }
572         filterForBrush.SetImageFilter(imageFilter);
573         brush.SetFilter(filterForBrush);
574         Drawing::SaveLayerOps slr(nullptr, &brush, Drawing::SaveLayerOps::Flags::INIT_WITH_PREVIOUS);
575         canvas.SaveLayer(slr);
576         filter->PostProcess(canvas);
577         return;
578     }
579 
580     // for foreground filter, when do online opacity, rendering result already applied opacity,
581     // so drawImage should not apply opacity again
582     RSAutoCanvasRestore autoCanvasRestore(&canvas,
583         filterType == FilterType::FOREGROUND_FILTER ? RSPaintFilterCanvas::kAlpha : RSPaintFilterCanvas::kNone);
584     if (filterType == FilterType::FOREGROUND_FILTER) {
585         canvas.SetAlpha(1.0);
586     }
587 
588     auto clipIBounds = canvas.GetDeviceClipBounds();
589     auto imageClipIBounds = clipIBounds;
590     auto magnifierShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::MAGNIFIER);
591     if (magnifierShaderFilter != nullptr) {
592         auto tmpFilter = std::static_pointer_cast<RSMagnifierShaderFilter>(magnifierShaderFilter);
593         auto canvasMatrix = canvas.GetTotalMatrix();
594         tmpFilter->SetMagnifierOffset(canvasMatrix);
595         imageClipIBounds.Offset(tmpFilter->GetMagnifierOffsetX(), tmpFilter->GetMagnifierOffsetY());
596     }
597 
598 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
599     // Optional use cacheManager to draw filter
600     if (auto& cacheManager = properties.GetFilterCacheManager(filterType == FilterType::FOREGROUND_FILTER);
601         cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
602         auto rsShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::LINEAR_GRADIENT_BLUR);
603         if (rsShaderFilter != nullptr) {
604             auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
605             tmpFilter->IsOffscreenCanvas(true);
606             tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
607         }
608         // RSFilterCacheManger has no more logic for evaluating filtered snapshot clearing
609         // (see RSPropertyDrawableUtils::DrawFilter())
610         cacheManager->DrawFilter(canvas, filter, 0, true, false);
611         return;
612     }
613 #endif
614 
615     auto rsShaderFilter = filter->GetShaderFilterWithType(RSUIFilterType::LINEAR_GRADIENT_BLUR);
616     if (rsShaderFilter != nullptr) {
617         auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
618         tmpFilter->IsOffscreenCanvas(true);
619         tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
620     }
621 
622     auto imageSnapshot = surface->GetImageSnapshot(imageClipIBounds);
623     if (imageSnapshot == nullptr) {
624         ROSEN_LOGD("RSPropertiesPainter::DrawFilter image null");
625         return;
626     }
627     if (RSSystemProperties::GetImageGpuResourceCacheEnable(imageSnapshot->GetWidth(), imageSnapshot->GetHeight())) {
628         ROSEN_LOGD("DrawFilter cache image resource(width:%{public}d, height:%{public}d).",
629             imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
630         imageSnapshot->HintCacheGpuResource();
631     }
632 
633     filter->PreProcess(imageSnapshot);
634     canvas.ResetMatrix();
635     auto visibleRect = canvas.GetVisibleRect();
636     visibleRect.Round();
637     auto visibleIRect = Drawing::RectI(
638         static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
639         static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
640     if (!visibleIRect.IsEmpty()) {
641         canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
642     }
643     Drawing::Rect srcRect = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
644     Drawing::Rect dstRect = clipIBounds;
645     filter->DrawImageRect(canvas, imageSnapshot, srcRect, dstRect);
646     filter->PostProcess(canvas);
647 }
648 
DrawBackgroundImageAsEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)649 void RSPropertiesPainter::DrawBackgroundImageAsEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
650 {
651     RS_TRACE_FUNC();
652 
653     // Optional use cacheManager to draw filter, cache is valid, skip drawing background image
654 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
655     auto boundsRect = properties.GetBoundsRect();
656     if (auto& cacheManager = properties.GetFilterCacheManager(false);
657         cacheManager != nullptr && !canvas.GetDisableFilterCache() && cacheManager->IsCacheValid()) {
658         // no need to validate parameters, the caller already do it
659         canvas.ClipRect(RSPropertiesPainter::Rect2DrawingRect(boundsRect));
660         auto filter = std::static_pointer_cast<RSDrawingFilter>(properties.GetBackgroundFilter());
661         // extract cache data from cacheManager
662         auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter);
663         canvas.SetEffectData(data);
664         return;
665     }
666 #endif
667 
668     auto surface = canvas.GetSurface();
669     if (!surface) {
670         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect surface null");
671         return;
672     }
673     // create offscreen surface with same size as current surface (PLANNING: use bounds size instead)
674     auto offscreenSurface = surface->MakeSurface(canvas.GetWidth(), canvas.GetHeight());
675     auto offscreenCanvas = std::make_shared<RSPaintFilterCanvas>(offscreenSurface.get());
676     // copy matrix and other properties to offscreen canvas
677     offscreenCanvas->SetMatrix(canvas.GetTotalMatrix());
678     offscreenCanvas->CopyConfigurationToOffscreenCanvas(canvas);
679     // draw background onto offscreen canvas
680     RSPropertiesPainter::DrawBackground(properties, *offscreenCanvas);
681     // generate effect data
682     RSPropertiesPainter::DrawBackgroundEffect(properties, *offscreenCanvas);
683     // extract effect data from offscreen canvas and set to canvas
684     canvas.SetEffectData(offscreenCanvas->GetEffectData());
685 }
686 
DrawBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)687 void RSPropertiesPainter::DrawBackgroundEffect(
688     const RSProperties& properties, RSPaintFilterCanvas& canvas)
689 {
690     auto& RSFilter = properties.GetBackgroundFilter();
691     if (RSFilter == nullptr) {
692         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect RSFilter null");
693         return;
694     }
695     g_blurCnt++;
696     RS_TRACE_NAME("DrawBackgroundEffect " + RSFilter->GetDescription());
697     RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "EffectComponent, %s, bounds: %s",
698         RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
699     auto surface = canvas.GetSurface();
700     if (surface == nullptr) {
701         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect surface null");
702         return;
703     }
704 
705     canvas.Save();
706     canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()));
707     auto bounds = canvas.GetRoundInDeviceClipBounds();
708     canvas.Restore();
709     auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
710 
711 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
712     // Optional use cacheManager to draw filter
713     if (auto& cacheManager = properties.GetFilterCacheManager(false);
714         cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
715         auto node = properties.backref_.lock();
716         if (node == nullptr) {
717             ROSEN_LOGE("DrawBackgroundEffect::node is null");
718             return;
719         }
720         auto effectNode = node->ReinterpretCastTo<RSEffectRenderNode>();
721         if (effectNode == nullptr) {
722             ROSEN_LOGE("DrawBackgroundEffect::node reinterpret cast failed.");
723             return;
724         }
725         auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter, bounds, bounds);
726         canvas.SetEffectData(data);
727         return;
728     }
729 #endif
730 
731     auto imageRect = bounds;
732     auto imageSnapshot = surface->GetImageSnapshot(imageRect);
733     if (imageSnapshot == nullptr) {
734         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect image snapshot null");
735         return;
736     }
737 
738     filter->PreProcess(imageSnapshot);
739     // create a offscreen skSurface
740     std::shared_ptr<Drawing::Surface> offscreenSurface =
741         surface->MakeSurface(imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
742     if (offscreenSurface == nullptr) {
743         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect offscreenSurface null");
744         return;
745     }
746     RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
747     auto clipBounds = Drawing::Rect(0, 0, imageRect.GetWidth(), imageRect.GetHeight());
748     auto imageSnapshotBounds = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
749     filter->DrawImageRect(offscreenCanvas, imageSnapshot, imageSnapshotBounds, clipBounds);
750     filter->PostProcess(offscreenCanvas);
751 
752     auto imageCache = offscreenSurface->GetImageSnapshot();
753     if (imageCache == nullptr) {
754         ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect imageCache snapshot null");
755         return;
756     }
757     auto data = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(imageCache), std::move(imageRect));
758     canvas.SetEffectData(std::move(data));
759 }
760 
GetPixelStretchDirtyRect(RectI & dirtyPixelStretch,const RSProperties & properties,const bool isAbsCoordinate)761 void RSPropertiesPainter::GetPixelStretchDirtyRect(RectI& dirtyPixelStretch,
762     const RSProperties& properties, const bool isAbsCoordinate)
763 {
764     auto& pixelStretch = properties.GetPixelStretch();
765     if (!pixelStretch.has_value()) {
766         return;
767     }
768     auto boundsRect = properties.GetBoundsRect();
769     auto scaledBounds = RectF(boundsRect.left_ - pixelStretch->x_, boundsRect.top_ - pixelStretch->y_,
770         boundsRect.width_ + pixelStretch->x_ + pixelStretch->z_,
771         boundsRect.height_ + pixelStretch->y_ + pixelStretch->w_);
772     auto geoPtr = properties.GetBoundsGeometry();
773     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
774     auto drawingRect = Rect2DrawingRect(scaledBounds);
775     matrix.MapRect(drawingRect, drawingRect);
776     dirtyPixelStretch.left_ = std::floor(drawingRect.GetLeft());
777     dirtyPixelStretch.top_ = std::floor(drawingRect.GetTop());
778     dirtyPixelStretch.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
779     dirtyPixelStretch.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
780 }
781 
GetForegroundEffectDirtyRect(RectI & dirtyForegroundEffect,const RSProperties & properties,const bool isAbsCoordinate)782 void RSPropertiesPainter::GetForegroundEffectDirtyRect(RectI& dirtyForegroundEffect,
783     const RSProperties& properties, const bool isAbsCoordinate)
784 {
785     std::shared_ptr<RSFilter> foregroundFilter = nullptr;
786     if (RSProperties::IS_UNI_RENDER) {
787         foregroundFilter = properties.GetForegroundFilterCache();
788     } else {
789         foregroundFilter = properties.GetForegroundFilter();
790     }
791     if (!foregroundFilter) {
792         return;
793     }
794 
795     if (foregroundFilter->GetFilterType() == RSFilter::FOREGROUND_EFFECT) {
796         float dirtyExtension =
797             std::static_pointer_cast<RSForegroundEffectFilter>(foregroundFilter)->GetDirtyExtension();
798         auto boundsRect = properties.GetBoundsRect();
799         auto scaledBounds = boundsRect.MakeOutset(dirtyExtension);
800         auto& geoPtr = properties.GetBoundsGeometry();
801         Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
802         auto drawingRect = Rect2DrawingRect(scaledBounds);
803         matrix.MapRect(drawingRect, drawingRect);
804         dirtyForegroundEffect.left_ = std::floor(drawingRect.GetLeft());
805         dirtyForegroundEffect.top_ = std::floor(drawingRect.GetTop());
806         dirtyForegroundEffect.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
807         dirtyForegroundEffect.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
808     } else if (foregroundFilter->GetFilterType() == RSFilter::COLORFUL_SHADOW) {
809         if (properties.IsShadowValid()) {
810             GetShadowDirtyRect(dirtyForegroundEffect, properties, nullptr, false, true);
811         }
812     }
813 }
814 
815 // calculate the distortion effect's dirty area
GetDistortionEffectDirtyRect(RectI & dirtyDistortionEffect,const RSProperties & properties)816 void RSPropertiesPainter::GetDistortionEffectDirtyRect(RectI& dirtyDistortionEffect, const RSProperties& properties)
817 {
818     // if the distortionK > 0, set the dirty bounds to its maximum range value
819     auto distortionK = properties.GetDistortionK();
820     if (distortionK.has_value() && *distortionK > 0) {
821         int dirtyWidth = static_cast<int>(std::numeric_limits<int16_t>::max());
822         int dirtyBeginPoint = static_cast<int>(std::numeric_limits<int16_t>::min()) / PARAM_DOUBLE;
823         dirtyDistortionEffect.left_ = dirtyBeginPoint;
824         dirtyDistortionEffect.top_ = dirtyBeginPoint;
825         dirtyDistortionEffect.width_ = dirtyWidth;
826         dirtyDistortionEffect.height_ = dirtyWidth;
827     }
828 }
829 
CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)830 Drawing::ColorQuad RSPropertiesPainter::CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)
831 {
832     // create a 1x1 SkPixmap
833     uint32_t pixel[1] = { 0 };
834     Drawing::ImageInfo single_pixel_info(1, 1, Drawing::ColorType::COLORTYPE_RGBA_8888,
835         Drawing::AlphaType::ALPHATYPE_PREMUL);
836     Drawing::Bitmap single_pixel;
837     single_pixel.Build(single_pixel_info, single_pixel_info.GetBytesPerPixel());
838     single_pixel.SetPixels(pixel);
839 
840     // resize snapshot to 1x1 to calculate average color
841     // kMedium_SkFilterQuality will do bilerp + mipmaps for down-scaling, we can easily get average color
842     imageSnapshot->ScalePixels(single_pixel,
843         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR));
844     // convert color format and return average color
845     return SkColor4f::FromBytes_RGBA(pixel[0]).toSkColor();
846 }
847 
GetAndResetBlurCnt()848 int RSPropertiesPainter::GetAndResetBlurCnt()
849 {
850     auto blurCnt = g_blurCnt;
851     g_blurCnt = 0;
852     return blurCnt;
853 }
854 
DrawBackground(const RSProperties & properties,RSPaintFilterCanvas & canvas,bool isAntiAlias,bool isSurfaceView)855 void RSPropertiesPainter::DrawBackground(const RSProperties& properties, RSPaintFilterCanvas& canvas,
856     bool isAntiAlias, bool isSurfaceView)
857 {
858     // only disable antialias when background is rect and g_forceBgAntiAlias is false
859     bool antiAlias = g_forceBgAntiAlias || !properties.GetCornerRadius().IsZero();
860     // clip
861     if (properties.GetClipBounds() != nullptr) {
862         auto& path = properties.GetClipBounds()->GetDrawingPath();
863         canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, antiAlias);
864     } else if (properties.GetClipToBounds()) {
865         if (properties.GetCornerRadius().IsZero()) {
866             canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, isAntiAlias);
867         } else {
868             canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
869         }
870     } else if (properties.GetClipToRRect()) {
871         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
872     }
873     // paint backgroundColor
874     Drawing::Brush brush;
875     brush.SetAntiAlias(antiAlias);
876     auto bgColor = properties.GetBackgroundColor();
877     if (bgColor != RgbPalette::Transparent() && !isSurfaceView) {
878         brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
879         canvas.AttachBrush(brush);
880         canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
881         canvas.DetachBrush();
882     }
883     if (const auto& bgShader = properties.GetBackgroundShader()) {
884         Drawing::AutoCanvasRestore acr(canvas, true);
885         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
886         auto shaderEffect = bgShader->GetDrawingShader();
887         brush.SetShaderEffect(shaderEffect);
888         canvas.DrawBackground(brush);
889     }
890     if (const auto& bgImage = properties.GetBgImage()) {
891         Drawing::AutoCanvasRestore acr(canvas, true);
892         canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
893         auto boundsRect = Rect2DrawingRect(properties.GetBoundsRect());
894         bgImage->SetDstRect(properties.GetBgImageRect());
895         canvas.AttachBrush(brush);
896         bgImage->CanvasDrawImage(canvas, boundsRect, Drawing::SamplingOptions(), true);
897         canvas.DetachBrush();
898     }
899 }
900 
SetBgAntiAlias(bool forceBgAntiAlias)901 void RSPropertiesPainter::SetBgAntiAlias(bool forceBgAntiAlias)
902 {
903     g_forceBgAntiAlias = forceBgAntiAlias;
904 }
905 
GetBgAntiAlias()906 bool RSPropertiesPainter::GetBgAntiAlias()
907 {
908     return g_forceBgAntiAlias;
909 }
910 
DrawFrame(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::DrawCmdListPtr & cmds)911 void RSPropertiesPainter::DrawFrame(
912     const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::DrawCmdListPtr& cmds)
913 {
914     if (cmds == nullptr) {
915         ROSEN_LOGE("RSPropertiesPainter::DrawFrame cmds null");
916         return;
917     }
918     Drawing::Matrix mat;
919     if (GetGravityMatrix(
920             properties.GetFrameGravity(), properties.GetFrameRect(), cmds->GetWidth(), cmds->GetHeight(), mat)) {
921         canvas.ConcatMatrix(mat);
922     }
923     auto frameRect = Rect2DrawingRect(properties.GetFrameRect());
924     cmds->Playback(canvas, &frameRect);
925 }
926 
GetRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)927 RRect RSPropertiesPainter::GetRRectForDrawingBorder(const RSProperties& properties,
928     const std::shared_ptr<RSBorder>& border, const bool isOutline)
929 {
930     if (!border) {
931         return RRect();
932     }
933 
934     return isOutline ?
935         RRect(properties.GetRRect().rect_.MakeOutset(border->GetWidthFour()), border->GetRadiusFour()) :
936         properties.GetRRect();
937 }
938 
GetInnerRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)939 RRect RSPropertiesPainter::GetInnerRRectForDrawingBorder(const RSProperties& properties,
940     const std::shared_ptr<RSBorder>& border, const bool isOutline)
941 {
942     if (!border) {
943         return RRect();
944     }
945     return isOutline ? properties.GetRRect() : properties.GetInnerRRect();
946 }
947 
DrawBorderBase(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool isOutline)948 void RSPropertiesPainter::DrawBorderBase(const RSProperties& properties, Drawing::Canvas& canvas,
949     const std::shared_ptr<RSBorder>& border, const bool isOutline)
950 {
951     if (!border || !border->HasBorder()) {
952         return;
953     }
954 
955     Drawing::Brush brush;
956     Drawing::Pen pen;
957     brush.SetAntiAlias(true);
958     pen.SetAntiAlias(true);
959     if (border->ApplyFillStyle(brush)) {
960         auto roundRect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
961         auto innerRoundRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(
962             properties, border, isOutline));
963         canvas.AttachBrush(brush);
964         canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
965         canvas.DetachBrush();
966     } else {
967         bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
968         if (isZero && border->ApplyFourLine(pen)) {
969             RectF rectf = isOutline ?
970                 properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
971             border->PaintFourLine(canvas, pen, rectf);
972         } else if (border->ApplyPathStyle(pen)) {
973             auto borderWidth = border->GetWidth();
974             RRect rrect = GetRRectForDrawingBorder(properties, border, isOutline);
975             rrect.rect_.width_ -= borderWidth;
976             rrect.rect_.height_ -= borderWidth;
977             rrect.rect_.Move(borderWidth / PARAM_DOUBLE, borderWidth / PARAM_DOUBLE);
978             Drawing::Path borderPath;
979             borderPath.AddRoundRect(RRect2DrawingRRect(rrect));
980             canvas.AttachPen(pen);
981             canvas.DrawPath(borderPath);
982             canvas.DetachPen();
983         } else {
984             RSBorderGeo borderGeo;
985             borderGeo.rrect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
986             borderGeo.innerRRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(properties, border, isOutline));
987             auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
988             auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
989             borderGeo.center = { centerX, centerY };
990             auto rect = borderGeo.rrect.GetRect();
991             Drawing::AutoCanvasRestore acr(canvas, false);
992             Drawing::SaveLayerOps slr(&rect, nullptr);
993             canvas.SaveLayer(slr);
994             border->DrawBorders(canvas, pen, borderGeo);
995         }
996     }
997 }
998 
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas)999 void RSPropertiesPainter::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas)
1000 {
1001     auto border = properties.GetBorder();
1002     if (border && border->HasBorder()) {
1003         DrawBorderBase(properties, canvas, border, false);
1004     }
1005 }
1006 
GetOutlineDirtyRect(RectI & dirtyOutline,const RSProperties & properties,const bool isAbsCoordinate)1007 void RSPropertiesPainter::GetOutlineDirtyRect(RectI& dirtyOutline,
1008     const RSProperties& properties, const bool isAbsCoordinate)
1009 {
1010     auto outline = properties.GetOutline();
1011     if (!outline || !outline->HasBorder()) {
1012         return;
1013     }
1014 
1015     auto& geoPtr = properties.GetBoundsGeometry();
1016     Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
1017     auto drawingRect = Rect2DrawingRect(GetRRectForDrawingBorder(properties, outline, true).rect_);
1018     matrix.MapRect(drawingRect, drawingRect);
1019     dirtyOutline.left_ = std::floor(drawingRect.GetLeft());
1020     dirtyOutline.top_ = std::floor(drawingRect.GetTop());
1021     dirtyOutline.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
1022     dirtyOutline.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
1023 }
1024 
DrawOutline(const RSProperties & properties,Drawing::Canvas & canvas)1025 void RSPropertiesPainter::DrawOutline(const RSProperties& properties, Drawing::Canvas& canvas)
1026 {
1027     auto outline = properties.GetOutline();
1028     if (outline && outline->HasBorder()) {
1029         DrawBorderBase(properties, canvas, outline, true);
1030     }
1031 }
1032 
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas,Drawing::Rect maskBounds)1033 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas, Drawing::Rect maskBounds)
1034 {
1035     std::shared_ptr<RSMask> mask = properties.GetMask();
1036     if (mask == nullptr) {
1037         return;
1038     }
1039     if (mask->IsSvgMask() && !mask->GetSvgDom() && !mask->GetSvgPicture()) {
1040         ROSEN_LOGD("RSPropertiesPainter::DrawMask not has Svg Mask property");
1041         return;
1042     }
1043 
1044     canvas.Save();
1045     Drawing::SaveLayerOps slr(&maskBounds, nullptr);
1046     canvas.SaveLayer(slr);
1047     uint32_t tmpLayer = canvas.GetSaveCount();
1048 
1049     Drawing::Brush maskfilter;
1050     Drawing::Filter filter;
1051     filter.SetColorFilter(Drawing::ColorFilter::CreateComposeColorFilter(
1052         *(Drawing::ColorFilter::CreateLumaColorFilter()), *(Drawing::ColorFilter::CreateSrgbGammaToLinear())));
1053     maskfilter.SetFilter(filter);
1054     Drawing::SaveLayerOps slrMask(&maskBounds, &maskfilter);
1055     canvas.SaveLayer(slrMask);
1056     if (mask->IsSvgMask()) {
1057         Drawing::AutoCanvasRestore maskSave(canvas, true);
1058         canvas.Translate(maskBounds.GetLeft() + mask->GetSvgX(), maskBounds.GetTop() + mask->GetSvgY());
1059         canvas.Scale(mask->GetScaleX(), mask->GetScaleY());
1060         if (mask->GetSvgDom()) {
1061             canvas.DrawSVGDOM(mask->GetSvgDom());
1062         } else if (mask->GetSvgPicture()) {
1063             canvas.DrawPicture(*mask->GetSvgPicture());
1064         }
1065     } else if (mask->IsGradientMask()) {
1066         Drawing::AutoCanvasRestore maskSave(canvas, true);
1067         canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1068         Drawing::Rect rect = Drawing::Rect(
1069             0, 0, maskBounds.GetWidth(), maskBounds.GetHeight());
1070         canvas.AttachBrush(mask->GetMaskBrush());
1071         canvas.DrawRect(rect);
1072         canvas.DetachBrush();
1073     } else if (mask->IsPathMask()) {
1074         Drawing::AutoCanvasRestore maskSave(canvas, true);
1075         canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1076         canvas.AttachBrush(mask->GetMaskBrush());
1077         canvas.AttachPen(mask->GetMaskPen());
1078         canvas.DrawPath(*mask->GetMaskPath());
1079         canvas.DetachBrush();
1080         canvas.DetachPen();
1081     } else if (mask->IsPixelMapMask()) {
1082         Drawing::AutoCanvasRestore arc(canvas, true);
1083         if (mask->GetImage()) {
1084             canvas.DrawImage(*mask->GetImage(), 0.f, 0.f, Drawing::SamplingOptions());
1085         }
1086     }
1087 
1088     // back to mask layer
1089     canvas.RestoreToCount(tmpLayer);
1090     // create content layer
1091     Drawing::Brush maskPaint;
1092     maskPaint.SetBlendMode(Drawing::BlendMode::SRC_IN);
1093     Drawing::SaveLayerOps slrContent(&maskBounds, &maskPaint);
1094     canvas.SaveLayer(slrContent);
1095     canvas.ClipRect(maskBounds, Drawing::ClipOp::INTERSECT, true);
1096 }
1097 
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas)1098 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas)
1099 {
1100     Drawing::Rect maskBounds = Rect2DrawingRect(properties.GetBoundsRect());
1101     DrawMask(properties, canvas, maskBounds);
1102 }
1103 
IsDangerousBlendMode(int blendMode,int blendApplyType)1104 bool RSPropertiesPainter::IsDangerousBlendMode(int blendMode, int blendApplyType)
1105 {
1106     static const uint32_t fastDangerousBit =
1107         (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1108         (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1109         (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1110         (1 << static_cast<int>(Drawing::BlendMode::XOR));
1111     static const uint32_t offscreenDangerousBit =
1112         (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1113         (1 << static_cast<int>(Drawing::BlendMode::SRC)) +
1114         (1 << static_cast<int>(Drawing::BlendMode::SRC_IN)) +
1115         (1 << static_cast<int>(Drawing::BlendMode::DST_IN)) +
1116         (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1117         (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1118         (1 << static_cast<int>(Drawing::BlendMode::DST_ATOP)) +
1119         (1 << static_cast<int>(Drawing::BlendMode::XOR)) +
1120         (1 << static_cast<int>(Drawing::BlendMode::MODULATE));
1121     uint32_t tmp = 1 << blendMode;
1122     if (blendApplyType == static_cast<int>(RSColorBlendApplyType::FAST)) {
1123         return tmp & fastDangerousBit;
1124     }
1125     return tmp & offscreenDangerousBit;
1126 }
1127 } // namespace Rosen
1128 } // namespace OHOS
1129