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