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