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