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