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
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 RS_OPTIONAL_TRACE_NAME("DrawFilter " + RSFilter->GetDescription());
581 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawFilter, filterType: %d, %s, bounds: %s", filterType,
582 RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
583 g_blurCnt++;
584 Drawing::AutoCanvasRestore acr(canvas, true);
585
586 auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
587 auto surface = canvas.GetSurface();
588 if (surface == nullptr) {
589 ROSEN_LOGD("RSPropertiesPainter::DrawFilter surface null");
590 Drawing::Brush brush;
591 brush.SetAntiAlias(true);
592 Drawing::Filter filterForBrush;
593 auto imageFilter = filter->GetImageFilter();
594 std::shared_ptr<RSShaderFilter> kawaseShaderFilter =
595 filter->GetShaderFilterWithType(RSShaderFilter::KAWASE);
596 if (kawaseShaderFilter != nullptr) {
597 auto tmpFilter = std::static_pointer_cast<RSKawaseBlurShaderFilter>(kawaseShaderFilter);
598 auto radius = tmpFilter->GetRadius();
599 std::shared_ptr<Drawing::ImageFilter> blurFilter = Drawing::ImageFilter::CreateBlurImageFilter(
600 radius, radius, Drawing::TileMode::CLAMP, nullptr);
601 imageFilter = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter, blurFilter);
602 }
603 filterForBrush.SetImageFilter(imageFilter);
604 brush.SetFilter(filterForBrush);
605 Drawing::SaveLayerOps slr(nullptr, &brush, Drawing::SaveLayerOps::Flags::INIT_WITH_PREVIOUS);
606 canvas.SaveLayer(slr);
607 filter->PostProcess(canvas);
608 return;
609 }
610
611 // for foreground filter, when do online opacity, rendering result already applied opacity,
612 // so drawImage should not apply opacity again
613 RSAutoCanvasRestore autoCanvasRestore(&canvas,
614 filterType == FilterType::FOREGROUND_FILTER ? RSPaintFilterCanvas::kAlpha : RSPaintFilterCanvas::kNone);
615 if (filterType == FilterType::FOREGROUND_FILTER) {
616 canvas.SetAlpha(1.0);
617 }
618
619 auto clipIBounds = canvas.GetDeviceClipBounds();
620 auto imageClipIBounds = clipIBounds;
621 std::shared_ptr<RSShaderFilter> magnifierShaderFilter =
622 filter->GetShaderFilterWithType(RSShaderFilter::MAGNIFIER);
623 if (magnifierShaderFilter != nullptr) {
624 auto tmpFilter = std::static_pointer_cast<RSMagnifierShaderFilter>(magnifierShaderFilter);
625 auto canvasMatrix = canvas.GetTotalMatrix();
626 tmpFilter->SetMagnifierOffset(canvasMatrix);
627 imageClipIBounds.Offset(tmpFilter->GetMagnifierOffsetX(), tmpFilter->GetMagnifierOffsetY());
628 }
629
630 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
631 // Optional use cacheManager to draw filter
632 if (auto& cacheManager = properties.GetFilterCacheManager(filterType == FilterType::FOREGROUND_FILTER);
633 cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
634 std::shared_ptr<RSShaderFilter> rsShaderFilter =
635 filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
636 if (rsShaderFilter != nullptr) {
637 auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
638 tmpFilter->IsOffscreenCanvas(true);
639 tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
640 }
641 // RSFilterCacheManger has no more logic for evaluating filtered snapshot clearing
642 // Should be passed as secnod argument, if required (see RSPropertyDrawableUtils::DrewFiler())
643 cacheManager->DrawFilter(canvas, filter, {RSFilter->NeedSnapshotOutset(), false });
644 return;
645 }
646 #endif
647
648 std::shared_ptr<RSShaderFilter> rsShaderFilter =
649 filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
650 if (rsShaderFilter != nullptr) {
651 auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
652 tmpFilter->IsOffscreenCanvas(true);
653 tmpFilter->SetGeometry(canvas, properties.GetFrameWidth(), properties.GetFrameHeight());
654 }
655
656 auto imageSnapshot = surface->GetImageSnapshot(imageClipIBounds);
657 if (imageSnapshot == nullptr) {
658 ROSEN_LOGD("RSPropertiesPainter::DrawFilter image null");
659 return;
660 }
661 if (RSSystemProperties::GetImageGpuResourceCacheEnable(imageSnapshot->GetWidth(), imageSnapshot->GetHeight())) {
662 ROSEN_LOGD("DrawFilter cache image resource(width:%{public}d, height:%{public}d).",
663 imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
664 imageSnapshot->HintCacheGpuResource();
665 }
666
667 filter->PreProcess(imageSnapshot);
668 canvas.ResetMatrix();
669 auto visibleRect = canvas.GetVisibleRect();
670 visibleRect.Round();
671 auto visibleIRect = Drawing::RectI(
672 static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
673 static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
674 if (!visibleIRect.IsEmpty()) {
675 canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
676 }
677 Drawing::Rect srcRect = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
678 Drawing::Rect dstRect = clipIBounds;
679 filter->DrawImageRect(canvas, imageSnapshot, srcRect, dstRect);
680 filter->PostProcess(canvas);
681 }
682
DrawBackgroundImageAsEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)683 void RSPropertiesPainter::DrawBackgroundImageAsEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
684 {
685 RS_TRACE_FUNC();
686 auto boundsRect = properties.GetBoundsRect();
687
688 // Optional use cacheManager to draw filter, cache is valid, skip drawing background image
689 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
690 if (auto& cacheManager = properties.GetFilterCacheManager(false);
691 cacheManager != nullptr && !canvas.GetDisableFilterCache() && cacheManager->IsCacheValid()) {
692 // no need to validate parameters, the caller already do it
693 canvas.ClipRect(RSPropertiesPainter::Rect2DrawingRect(boundsRect));
694 auto filter = std::static_pointer_cast<RSDrawingFilter>(properties.GetBackgroundFilter());
695 // extract cache data from cacheManager
696 auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter);
697 canvas.SetEffectData(data);
698 return;
699 }
700 #endif
701
702 auto surface = canvas.GetSurface();
703 if (!surface) {
704 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect surface null");
705 return;
706 }
707 // create offscreen surface with same size as current surface (PLANNING: use bounds size instead)
708 auto offscreenSurface = surface->MakeSurface(canvas.GetWidth(), canvas.GetHeight());
709 auto offscreenCanvas = std::make_shared<RSPaintFilterCanvas>(offscreenSurface.get());
710 // copy matrix and other properties to offscreen canvas
711 offscreenCanvas->SetMatrix(canvas.GetTotalMatrix());
712 offscreenCanvas->CopyConfigurationToOffscreenCanvas(canvas);
713 // draw background onto offscreen canvas
714 RSPropertiesPainter::DrawBackground(properties, *offscreenCanvas);
715 // generate effect data
716 RSPropertiesPainter::DrawBackgroundEffect(properties, *offscreenCanvas);
717 // extract effect data from offscreen canvas and set to canvas
718 canvas.SetEffectData(offscreenCanvas->GetEffectData());
719 }
720
DrawBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)721 void RSPropertiesPainter::DrawBackgroundEffect(
722 const RSProperties& properties, RSPaintFilterCanvas& canvas)
723 {
724 auto& RSFilter = properties.GetBackgroundFilter();
725 if (RSFilter == nullptr) {
726 return;
727 }
728 g_blurCnt++;
729 RS_TRACE_NAME("DrawBackgroundEffect " + RSFilter->GetDescription());
730 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "EffectComponent, %s, bounds: %s",
731 RSFilter->GetDetailedDescription().c_str(), properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
732 auto surface = canvas.GetSurface();
733 if (surface == nullptr) {
734 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect surface null");
735 return;
736 }
737
738 canvas.Save();
739 canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()));
740 auto bounds = canvas.GetRoundInDeviceClipBounds();
741 canvas.Restore();
742 auto filter = std::static_pointer_cast<RSDrawingFilter>(RSFilter);
743
744 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
745 // Optional use cacheManager to draw filter
746 if (auto& cacheManager = properties.GetFilterCacheManager(false);
747 cacheManager != nullptr && !canvas.GetDisableFilterCache()) {
748 auto node = properties.backref_.lock();
749 if (node == nullptr) {
750 ROSEN_LOGE("DrawBackgroundEffect::node is null");
751 return;
752 }
753 auto effectNode = node->ReinterpretCastTo<RSEffectRenderNode>();
754 if (effectNode == nullptr) {
755 ROSEN_LOGE("DrawBackgroundEffect::node reinterpret cast failed.");
756 return;
757 }
758 auto&& data = cacheManager->GeneratedCachedEffectData(canvas, filter, bounds, bounds);
759 canvas.SetEffectData(data);
760 return;
761 }
762 #endif
763
764 auto imageRect = bounds;
765 auto imageSnapshot = surface->GetImageSnapshot(imageRect);
766 if (imageSnapshot == nullptr) {
767 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect image snapshot null");
768 return;
769 }
770
771 filter->PreProcess(imageSnapshot);
772 // create a offscreen skSurface
773 std::shared_ptr<Drawing::Surface> offscreenSurface =
774 surface->MakeSurface(imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
775 if (offscreenSurface == nullptr) {
776 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect offscreenSurface null");
777 return;
778 }
779 RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
780 auto clipBounds = Drawing::Rect(0, 0, imageRect.GetWidth(), imageRect.GetHeight());
781 auto imageSnapshotBounds = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
782 filter->DrawImageRect(offscreenCanvas, imageSnapshot, imageSnapshotBounds, clipBounds);
783 filter->PostProcess(offscreenCanvas);
784
785 auto imageCache = offscreenSurface->GetImageSnapshot();
786 if (imageCache == nullptr) {
787 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundEffect imageCache snapshot null");
788 return;
789 }
790 auto data = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(imageCache), std::move(imageRect));
791 canvas.SetEffectData(std::move(data));
792 }
793
ApplyBackgroundEffectFallback(const RSProperties & properties,RSPaintFilterCanvas & canvas)794 void RSPropertiesPainter::ApplyBackgroundEffectFallback(const RSProperties& properties, RSPaintFilterCanvas& canvas)
795 {
796 RS_TRACE_FUNC();
797 auto parentNode = properties.backref_.lock();
798 while (parentNode && !parentNode->IsInstanceOf<RSEffectRenderNode>()) {
799 parentNode = parentNode->GetParent().lock();
800 }
801 if (!parentNode) {
802 ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffectFallback: parentNode null, draw filter failed.");
803 return;
804 }
805 auto& filter = parentNode->GetRenderProperties().GetBackgroundFilter();
806 if (filter == nullptr || !filter->IsValid()) {
807 ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffectFallback: parent EffectRenderNode has no filter, "
808 "draw filter failed.");
809 return;
810 }
811 DrawFilter(properties, canvas, FilterType::BACKGROUND_FILTER, std::nullopt, filter);
812 }
813
ClipVisibleCanvas(const RSProperties & properties,RSPaintFilterCanvas & canvas)814 void RSPropertiesPainter::ClipVisibleCanvas(const RSProperties& properties, RSPaintFilterCanvas& canvas)
815 {
816 canvas.ResetMatrix();
817 auto visibleRect = canvas.GetVisibleRect();
818 visibleRect.Round();
819 auto visibleIRect = Drawing::RectI(
820 static_cast<int>(visibleRect.GetLeft()), static_cast<int>(visibleRect.GetTop()),
821 static_cast<int>(visibleRect.GetRight()), static_cast<int>(visibleRect.GetBottom()));
822 if (!visibleIRect.IsEmpty()) {
823 canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
824 }
825 }
826
ApplyBackgroundEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)827 void RSPropertiesPainter::ApplyBackgroundEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
828 {
829 const auto& effectData = canvas.GetEffectData();
830 if (effectData == nullptr || effectData->cachedImage_ == nullptr
831 || !RSSystemProperties::GetEffectMergeEnabled()) {
832 // no effectData available, draw background filter in fallback method
833 ROSEN_LOGD("RSPropertiesPainter::ApplyBackgroundEffect: effectData null, try fallback method.");
834 ApplyBackgroundEffectFallback(properties, canvas);
835 return;
836 }
837 RS_TRACE_FUNC();
838 Drawing::AutoCanvasRestore acr(canvas, true);
839 ClipVisibleCanvas(properties, canvas);
840 Drawing::Brush brush;
841 canvas.AttachBrush(brush);
842 // dstRect: canvas clip region
843 Drawing::Rect dstRect = canvas.GetDeviceClipBounds();
844 // srcRect: map dstRect onto cache coordinate
845 Drawing::Rect srcRect = dstRect;
846 srcRect.Offset(-effectData->cachedRect_.GetLeft(), -effectData->cachedRect_.GetTop());
847 canvas.DrawImageRect(*effectData->cachedImage_, srcRect, dstRect,
848 Drawing::SamplingOptions(), Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
849 canvas.DetachBrush();
850 }
851
GetPixelStretchDirtyRect(RectI & dirtyPixelStretch,const RSProperties & properties,const bool isAbsCoordinate)852 void RSPropertiesPainter::GetPixelStretchDirtyRect(RectI& dirtyPixelStretch,
853 const RSProperties& properties, const bool isAbsCoordinate)
854 {
855 auto& pixelStretch = properties.GetPixelStretch();
856 if (!pixelStretch.has_value()) {
857 return;
858 }
859 auto boundsRect = properties.GetBoundsRect();
860 auto scaledBounds = RectF(boundsRect.left_ - pixelStretch->x_, boundsRect.top_ - pixelStretch->y_,
861 boundsRect.width_ + pixelStretch->x_ + pixelStretch->z_,
862 boundsRect.height_ + pixelStretch->y_ + pixelStretch->w_);
863 auto& geoPtr = properties.GetBoundsGeometry();
864 Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
865 auto drawingRect = Rect2DrawingRect(scaledBounds);
866 matrix.MapRect(drawingRect, drawingRect);
867 dirtyPixelStretch.left_ = std::floor(drawingRect.GetLeft());
868 dirtyPixelStretch.top_ = std::floor(drawingRect.GetTop());
869 dirtyPixelStretch.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
870 dirtyPixelStretch.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
871 }
872
GetForegroundEffectDirtyRect(RectI & dirtyForegroundEffect,const RSProperties & properties,const bool isAbsCoordinate)873 void RSPropertiesPainter::GetForegroundEffectDirtyRect(RectI& dirtyForegroundEffect,
874 const RSProperties& properties, const bool isAbsCoordinate)
875 {
876 std::shared_ptr<RSFilter> foregroundFilter = nullptr;
877 if (RSProperties::IS_UNI_RENDER) {
878 foregroundFilter = properties.GetForegroundFilterCache();
879 } else {
880 foregroundFilter = properties.GetForegroundFilter();
881 }
882 if (!foregroundFilter || foregroundFilter->GetFilterType() != RSFilter::FOREGROUND_EFFECT) {
883 return;
884 }
885 float dirtyExtension =
886 std::static_pointer_cast<RSForegroundEffectFilter>(foregroundFilter)->GetDirtyExtension();
887 auto boundsRect = properties.GetBoundsRect();
888 auto scaledBounds = boundsRect.MakeOutset(dirtyExtension);
889 auto& geoPtr = properties.GetBoundsGeometry();
890 Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
891 auto drawingRect = Rect2DrawingRect(scaledBounds);
892 matrix.MapRect(drawingRect, drawingRect);
893 dirtyForegroundEffect.left_ = std::floor(drawingRect.GetLeft());
894 dirtyForegroundEffect.top_ = std::floor(drawingRect.GetTop());
895 dirtyForegroundEffect.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
896 dirtyForegroundEffect.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
897 }
898
899 // calculate the distortion effect's dirty area
GetDistortionEffectDirtyRect(RectI & dirtyDistortionEffect,const RSProperties & properties)900 void RSPropertiesPainter::GetDistortionEffectDirtyRect(RectI& dirtyDistortionEffect, const RSProperties& properties)
901 {
902 // if the distortionK > 0, set the dirty bounds to its maximum range value
903 auto distortionK = properties.GetDistortionK();
904 if (distortionK.has_value() && *distortionK > 0) {
905 int dirtyWidth = static_cast<int>(std::numeric_limits<int16_t>::max());
906 int dirtyBeginPoint = static_cast<int>(std::numeric_limits<int16_t>::min()) / PARAM_DOUBLE;
907 dirtyDistortionEffect.left_ = dirtyBeginPoint;
908 dirtyDistortionEffect.top_ = dirtyBeginPoint;
909 dirtyDistortionEffect.width_ = dirtyWidth;
910 dirtyDistortionEffect.height_ = dirtyWidth;
911 }
912 }
913
DrawPixelStretch(const RSProperties & properties,RSPaintFilterCanvas & canvas)914 void RSPropertiesPainter::DrawPixelStretch(const RSProperties& properties, RSPaintFilterCanvas& canvas)
915 {
916 auto& pixelStretch = properties.GetPixelStretch();
917 if (!pixelStretch.has_value()) {
918 return;
919 }
920 auto surface = canvas.GetSurface();
921 if (surface == nullptr) {
922 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch surface null");
923 return;
924 }
925
926 canvas.Save();
927 auto bounds = RSPropertiesPainter::Rect2DrawingRect(properties.GetBoundsRect());
928 canvas.ClipRect(bounds, Drawing::ClipOp::INTERSECT, false);
929 auto tmpBounds = canvas.GetDeviceClipBounds();
930 Drawing::Rect clipBounds(
931 tmpBounds.GetLeft(), tmpBounds.GetTop(), tmpBounds.GetRight() - 1, tmpBounds.GetBottom() - 1);
932 canvas.Restore();
933
934 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertiesPainter::DrawPixelStretch, right: %f, bottom: %f",
935 tmpBounds.GetRight(), tmpBounds.GetBottom());
936
937 /* Calculates the relative coordinates of the clipbounds
938 with respect to the origin of the current canvas coordinates */
939 Drawing::Matrix worldToLocalMat;
940 if (!canvas.GetTotalMatrix().Invert(worldToLocalMat)) {
941 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch get invert matrix failed.");
942 }
943 Drawing::Rect localClipBounds;
944 Drawing::Rect fClipBounds(clipBounds.GetLeft(), clipBounds.GetTop(), clipBounds.GetRight(),
945 clipBounds.GetBottom());
946 if (!worldToLocalMat.MapRect(localClipBounds, fClipBounds)) {
947 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch map rect failed.");
948 }
949
950 if (!bounds.Intersect(localClipBounds)) {
951 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch intersect clipbounds failed");
952 }
953
954 auto scaledBounds = Drawing::Rect(bounds.GetLeft() - pixelStretch->x_, bounds.GetTop() - pixelStretch->y_,
955 bounds.GetRight() + pixelStretch->z_, bounds.GetBottom() + pixelStretch->w_);
956 if (!scaledBounds.IsValid() || !bounds.IsValid() || !clipBounds.IsValid()) {
957 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch invalid scaled bounds");
958 return;
959 }
960
961 Drawing::RectI rectI(static_cast<int>(fClipBounds.GetLeft()), static_cast<int>(fClipBounds.GetTop()),
962 static_cast<int>(fClipBounds.GetRight()), static_cast<int>(fClipBounds.GetBottom()));
963 auto image = surface->GetImageSnapshot(rectI);
964 if (image == nullptr) {
965 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch image null");
966 return;
967 }
968
969 Drawing::Brush brush;
970 Drawing::Matrix inverseMat, rotateMat;
971 auto& boundsGeo = (properties.GetBoundsGeometry());
972 if (boundsGeo && !boundsGeo->IsEmpty()) {
973 auto transMat = canvas.GetTotalMatrix();
974 /* transMat.getSkewY() is the sin of the rotation angle(sin0 = 0,sin90 =1 sin180 = 0,sin270 = -1),
975 if transMat.getSkewY() is not 0 or -1 or 1,the rotation angle is not a multiple of 90,not Stretch*/
976 auto skewY = transMat.Get(Drawing::Matrix::SKEW_Y);
977 if (ROSEN_EQ(skewY, 0.f) || ROSEN_EQ(skewY, 1.f) ||
978 ROSEN_EQ(skewY, -1.f)) {
979 } else {
980 ROSEN_LOGD("rotate degree is not 0 or 90 or 180 or 270,return.");
981 return;
982 }
983 rotateMat.SetScale(transMat.Get(Drawing::Matrix::SCALE_X), transMat.Get(Drawing::Matrix::SCALE_Y));
984 rotateMat.Set(Drawing::Matrix::SKEW_X, transMat.Get(Drawing::Matrix::SKEW_X));
985 rotateMat.Set(Drawing::Matrix::SKEW_Y, transMat.Get(Drawing::Matrix::SKEW_Y));
986 rotateMat.PreTranslate(-bounds.GetLeft(), -bounds.GetTop());
987 rotateMat.PostTranslate(bounds.GetLeft(), bounds.GetTop());
988
989 Drawing::Rect transBounds;
990 rotateMat.MapRect(transBounds, bounds);
991 rotateMat.Set(Drawing::Matrix::TRANS_X, bounds.GetLeft() - transBounds.GetLeft());
992 rotateMat.Set(Drawing::Matrix::TRANS_Y, bounds.GetTop() - transBounds.GetTop());
993 if (!rotateMat.Invert(inverseMat)) {
994 ROSEN_LOGE("RSPropertiesPainter::DrawPixelStretch get invert matrix failed.");
995 }
996 }
997
998 canvas.Save();
999 canvas.Translate(bounds.GetLeft(), bounds.GetTop());
1000 Drawing::SamplingOptions samplingOptions;
1001 constexpr static float EPS = 1e-5f;
1002 auto pixelStretchTileMode = static_cast<Drawing::TileMode>(properties.GetPixelStretchTileMode());
1003 if (pixelStretch->x_ > EPS || pixelStretch->y_ > EPS || pixelStretch->z_ > EPS || pixelStretch->w_ > EPS) {
1004 brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1005 *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1006 canvas.AttachBrush(brush);
1007 canvas.DrawRect(Drawing::Rect(-pixelStretch->x_, -pixelStretch->y_,
1008 -pixelStretch->x_ + scaledBounds.GetWidth(), -pixelStretch->y_ + scaledBounds.GetHeight()));
1009 canvas.DetachBrush();
1010 } else {
1011 inverseMat.PostScale(scaledBounds.GetWidth() / bounds.GetWidth(),
1012 scaledBounds.GetHeight() / bounds.GetHeight());
1013 brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1014 *image, pixelStretchTileMode, pixelStretchTileMode, samplingOptions, inverseMat));
1015
1016 canvas.Translate(-pixelStretch->x_, -pixelStretch->y_);
1017 canvas.AttachBrush(brush);
1018 canvas.DrawRect(Drawing::Rect(pixelStretch->x_, pixelStretch->y_,
1019 pixelStretch->x_ + bounds.GetWidth(), pixelStretch->y_ + bounds.GetHeight()));
1020 canvas.DetachBrush();
1021 }
1022 canvas.Restore();
1023 }
1024
CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)1025 Drawing::ColorQuad RSPropertiesPainter::CalcAverageColor(std::shared_ptr<Drawing::Image> imageSnapshot)
1026 {
1027 // create a 1x1 SkPixmap
1028 uint32_t pixel[1] = { 0 };
1029 Drawing::ImageInfo single_pixel_info(1, 1, Drawing::ColorType::COLORTYPE_RGBA_8888,
1030 Drawing::AlphaType::ALPHATYPE_PREMUL);
1031 Drawing::Bitmap single_pixel;
1032 single_pixel.Build(single_pixel_info, single_pixel_info.GetBytesPerPixel());
1033 single_pixel.SetPixels(pixel);
1034
1035 // resize snapshot to 1x1 to calculate average color
1036 // kMedium_SkFilterQuality will do bilerp + mipmaps for down-scaling, we can easily get average color
1037 imageSnapshot->ScalePixels(single_pixel,
1038 Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR));
1039 // convert color format and return average color
1040 return SkColor4f::FromBytes_RGBA(pixel[0]).toSkColor();
1041 }
1042
GetAndResetBlurCnt()1043 int RSPropertiesPainter::GetAndResetBlurCnt()
1044 {
1045 auto blurCnt = g_blurCnt;
1046 g_blurCnt = 0;
1047 return blurCnt;
1048 }
1049
DrawBackground(const RSProperties & properties,RSPaintFilterCanvas & canvas,bool isAntiAlias,bool isSurfaceView)1050 void RSPropertiesPainter::DrawBackground(const RSProperties& properties, RSPaintFilterCanvas& canvas,
1051 bool isAntiAlias, bool isSurfaceView)
1052 {
1053 // only disable antialias when background is rect and g_forceBgAntiAlias is false
1054 bool antiAlias = g_forceBgAntiAlias || !properties.GetCornerRadius().IsZero();
1055 // clip
1056 if (properties.GetClipBounds() != nullptr) {
1057 auto& path = properties.GetClipBounds()->GetDrawingPath();
1058 canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, antiAlias);
1059 } else if (properties.GetClipToBounds()) {
1060 if (properties.GetCornerRadius().IsZero()) {
1061 canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, isAntiAlias);
1062 } else {
1063 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1064 }
1065 } else if (properties.GetClipToRRect()) {
1066 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1067 }
1068 // paint backgroundColor
1069 Drawing::Brush brush;
1070 brush.SetAntiAlias(antiAlias);
1071 auto bgColor = properties.GetBackgroundColor();
1072 if (bgColor != RgbPalette::Transparent() && !isSurfaceView) {
1073 brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
1074 canvas.AttachBrush(brush);
1075 canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1076 canvas.DetachBrush();
1077 }
1078 if (const auto& bgShader = properties.GetBackgroundShader()) {
1079 Drawing::AutoCanvasRestore acr(canvas, true);
1080 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1081 auto shaderEffect = bgShader->GetDrawingShader();
1082 brush.SetShaderEffect(shaderEffect);
1083 canvas.DrawBackground(brush);
1084 }
1085 if (const auto& bgImage = properties.GetBgImage()) {
1086 Drawing::AutoCanvasRestore acr(canvas, true);
1087 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, antiAlias);
1088 auto boundsRect = Rect2DrawingRect(properties.GetBoundsRect());
1089 bgImage->SetDstRect(properties.GetBgImageRect());
1090 canvas.AttachBrush(brush);
1091 bgImage->CanvasDrawImage(canvas, boundsRect, Drawing::SamplingOptions(), true);
1092 canvas.DetachBrush();
1093 }
1094 }
1095
SetBgAntiAlias(bool forceBgAntiAlias)1096 void RSPropertiesPainter::SetBgAntiAlias(bool forceBgAntiAlias)
1097 {
1098 g_forceBgAntiAlias = forceBgAntiAlias;
1099 }
1100
GetBgAntiAlias()1101 bool RSPropertiesPainter::GetBgAntiAlias()
1102 {
1103 return g_forceBgAntiAlias;
1104 }
1105
DrawFrame(const RSProperties & properties,RSPaintFilterCanvas & canvas,Drawing::DrawCmdListPtr & cmds)1106 void RSPropertiesPainter::DrawFrame(
1107 const RSProperties& properties, RSPaintFilterCanvas& canvas, Drawing::DrawCmdListPtr& cmds)
1108 {
1109 if (cmds == nullptr) {
1110 return;
1111 }
1112 Drawing::Matrix mat;
1113 if (GetGravityMatrix(
1114 properties.GetFrameGravity(), properties.GetFrameRect(), cmds->GetWidth(), cmds->GetHeight(), mat)) {
1115 canvas.ConcatMatrix(mat);
1116 }
1117 auto frameRect = Rect2DrawingRect(properties.GetFrameRect());
1118 cmds->Playback(canvas, &frameRect);
1119 }
1120
GetRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)1121 RRect RSPropertiesPainter::GetRRectForDrawingBorder(const RSProperties& properties,
1122 const std::shared_ptr<RSBorder>& border, const bool isOutline)
1123 {
1124 if (!border) {
1125 return RRect();
1126 }
1127
1128 return isOutline ?
1129 RRect(properties.GetRRect().rect_.MakeOutset(border->GetWidthFour()), border->GetRadiusFour()) :
1130 properties.GetRRect();
1131 }
1132
GetInnerRRectForDrawingBorder(const RSProperties & properties,const std::shared_ptr<RSBorder> & border,const bool isOutline)1133 RRect RSPropertiesPainter::GetInnerRRectForDrawingBorder(const RSProperties& properties,
1134 const std::shared_ptr<RSBorder>& border, const bool isOutline)
1135 {
1136 if (!border) {
1137 return RRect();
1138 }
1139 return isOutline ? properties.GetRRect() : properties.GetInnerRRect();
1140 }
1141
1142 static std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder = nullptr;
1143
GetPhongShaderBuilder()1144 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPropertiesPainter::GetPhongShaderBuilder()
1145 {
1146 if (phongShaderBuilder) {
1147 return phongShaderBuilder;
1148 }
1149 std::shared_ptr<Drawing::RuntimeEffect> lightEffect_;
1150 std::string lightString(R"(
1151 uniform vec4 lightPos[12];
1152 uniform vec4 viewPos[12];
1153 uniform vec4 specularLightColor[12];
1154 uniform float specularStrength[12];
1155
1156 mediump vec4 main(vec2 drawing_coord) {
1157 vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
1158 float ambientStrength = 0.0;
1159 vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
1160 float diffuseStrength = 0.0;
1161 float shininess = 8.0;
1162 mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
1163 vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
1164 // ambient
1165 vec4 ambient = lightColor * ambientStrength;
1166 vec3 norm = normalize(NormalMap.rgb);
1167
1168 for (int i = 0; i < 12; i++) {
1169 if (abs(specularStrength[i]) > 0.01) {
1170 vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
1171 float diff = max(dot(norm, lightDir), 0.0);
1172 vec4 diffuse = diff * lightColor;
1173 vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
1174 vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
1175 float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
1176 vec4 specular = lightColor * spec; // multiply color of incident light
1177 vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
1178 vec4 specularColor = specularLightColor[i];
1179 fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
1180 }
1181 }
1182 return fragColor;
1183 }
1184 )");
1185 std::shared_ptr<Drawing::RuntimeEffect> lightEffect = Drawing::RuntimeEffect::CreateForShader(lightString);
1186 if (!lightEffect) {
1187 ROSEN_LOGE("light effect error");
1188 return phongShaderBuilder;
1189 }
1190 lightEffect_ = std::move(lightEffect);
1191 phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect_);
1192 return phongShaderBuilder;
1193 }
1194
DrawLight(const RSProperties & properties,Drawing::Canvas & canvas)1195 void RSPropertiesPainter::DrawLight(const RSProperties& properties, Drawing::Canvas& canvas)
1196 {
1197 auto lightBuilder = GetPhongShaderBuilder();
1198 if (!lightBuilder) {
1199 return;
1200 }
1201 const auto& lightSourcesAndPosMap = properties.GetIlluminated()->GetLightSourcesAndPosMap();
1202 if (lightSourcesAndPosMap.empty()) {
1203 ROSEN_LOGD("RSPropertiesPainter::DrawLight lightSourceList is empty!");
1204 return;
1205 }
1206 std::vector<std::pair<std::shared_ptr<RSLightSource>, Vector4f>> lightSourcesAndPosVec(
1207 lightSourcesAndPosMap.begin(), lightSourcesAndPosMap.end());
1208 if (lightSourcesAndPosVec.size() > MAX_LIGHT_SOURCES) {
1209 std::sort(lightSourcesAndPosVec.begin(), lightSourcesAndPosVec.end(), [](const auto& x, const auto& y) {
1210 return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
1211 y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
1212 });
1213 }
1214 DrawLightInner(properties, canvas, lightBuilder, lightSourcesAndPosVec);
1215 }
1216
DrawLightInner(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,const std::vector<std::pair<std::shared_ptr<RSLightSource>,Vector4f>> & lightSourcesAndPosVec)1217 void RSPropertiesPainter::DrawLightInner(const RSProperties& properties, Drawing::Canvas& canvas,
1218 std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder,
1219 const std::vector<std::pair<std::shared_ptr<RSLightSource>, Vector4f>>& lightSourcesAndPosVec)
1220 {
1221 auto cnt = 0;
1222 constexpr int vectorLen = 4;
1223 float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1224 float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1225 float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
1226 std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
1227
1228 auto iter = lightSourcesAndPosVec.begin();
1229 while (iter != lightSourcesAndPosVec.end() && cnt < MAX_LIGHT_SOURCES) {
1230 auto lightPos = iter->second;
1231 auto lightIntensity = iter->first->GetLightIntensity();
1232 auto lightColor = iter->first->GetLightColor();
1233 Vector4f lightColorVec =
1234 Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
1235 for (int i = 0; i < vectorLen; i++) {
1236 lightPosArray[cnt * vectorLen + i] = lightPos[i];
1237 viewPosArray[cnt * vectorLen + i] = lightPos[i];
1238 lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
1239 }
1240 lightIntensityArray[cnt] = lightIntensity;
1241 iter++;
1242 cnt++;
1243 }
1244 lightBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
1245 lightBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
1246 lightBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
1247 Drawing::Pen pen;
1248 Drawing::Brush brush;
1249 pen.SetAntiAlias(true);
1250 brush.SetAntiAlias(true);
1251 auto illuminatedType = properties.GetIlluminated()->GetIlluminatedType();
1252 ROSEN_LOGD("RSPropertiesPainter::DrawLight illuminatedType:%{public}d", illuminatedType);
1253 if (illuminatedType == IlluminatedType::CONTENT) {
1254 DrawContentLight(properties, canvas, lightBuilder, brush, lightIntensityArray);
1255 } else if (illuminatedType == IlluminatedType::BORDER) {
1256 DrawBorderLight(properties, canvas, lightBuilder, pen, lightIntensityArray);
1257 } else if (illuminatedType == IlluminatedType::BORDER_CONTENT) {
1258 DrawContentLight(properties, canvas, lightBuilder, brush, lightIntensityArray);
1259 DrawBorderLight(properties, canvas, lightBuilder, pen, lightIntensityArray);
1260 }
1261 }
1262
DrawContentLight(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray)1263 void RSPropertiesPainter::DrawContentLight(const RSProperties& properties, Drawing::Canvas& canvas,
1264 std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
1265 const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray)
1266 {
1267 // content light
1268 std::shared_ptr<Drawing::ShaderEffect> shader;
1269 constexpr float contentIntensityCoefficient = 0.3f;
1270 float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
1271 for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
1272 specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
1273 }
1274 lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
1275 shader = lightBuilder->MakeShader(nullptr, false);
1276 brush.SetShaderEffect(shader);
1277 canvas.AttachBrush(brush);
1278 canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1279 canvas.DetachBrush();
1280 }
1281
DrawBorderLight(const RSProperties & properties,Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray)1282 void RSPropertiesPainter::DrawBorderLight(const RSProperties& properties, Drawing::Canvas& canvas,
1283 std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
1284 const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray)
1285 {
1286 // border light
1287 std::shared_ptr<Drawing::ShaderEffect> shader;
1288 float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
1289 for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
1290 specularStrengthArr[i] = lightIntensityArray[i];
1291 }
1292 lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
1293 shader = lightBuilder->MakeShader(nullptr, false);
1294 pen.SetShaderEffect(shader);
1295 float borderWidth = std::ceil(properties.GetIlluminatedBorderWidth());
1296 pen.SetWidth(borderWidth);
1297 auto borderRect = properties.GetRRect().rect_;
1298 float borderRadius = properties.GetRRect().radius_[0].x_;
1299 auto borderRRect = RRect(RectF(borderRect.left_ + borderWidth / 2.0f, borderRect.top_ + borderWidth / 2.0f,
1300 borderRect.width_ - borderWidth, borderRect.height_ - borderWidth),
1301 borderRadius - borderWidth / 2.0f, borderRadius - borderWidth / 2.0f);
1302 canvas.AttachPen(pen);
1303 canvas.DrawRoundRect(RRect2DrawingRRect(borderRRect));
1304 canvas.DetachPen();
1305 }
1306
DrawBorderBase(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool isOutline)1307 void RSPropertiesPainter::DrawBorderBase(const RSProperties& properties, Drawing::Canvas& canvas,
1308 const std::shared_ptr<RSBorder>& border, const bool isOutline)
1309 {
1310 if (!border || !border->HasBorder()) {
1311 return;
1312 }
1313
1314 Drawing::Brush brush;
1315 Drawing::Pen pen;
1316 brush.SetAntiAlias(true);
1317 pen.SetAntiAlias(true);
1318 if (border->ApplyFillStyle(brush)) {
1319 auto roundRect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
1320 auto innerRoundRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(
1321 properties, border, isOutline));
1322 canvas.AttachBrush(brush);
1323 canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
1324 canvas.DetachBrush();
1325 } else {
1326 bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
1327 if (isZero && border->ApplyFourLine(pen)) {
1328 RectF rectf = isOutline ?
1329 properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
1330 border->PaintFourLine(canvas, pen, rectf);
1331 } else if (border->ApplyPathStyle(pen)) {
1332 auto borderWidth = border->GetWidth();
1333 RRect rrect = GetRRectForDrawingBorder(properties, border, isOutline);
1334 rrect.rect_.width_ -= borderWidth;
1335 rrect.rect_.height_ -= borderWidth;
1336 rrect.rect_.Move(borderWidth / PARAM_DOUBLE, borderWidth / PARAM_DOUBLE);
1337 Drawing::Path borderPath;
1338 borderPath.AddRoundRect(RRect2DrawingRRect(rrect));
1339 canvas.AttachPen(pen);
1340 canvas.DrawPath(borderPath);
1341 canvas.DetachPen();
1342 } else {
1343 RSBorderGeo borderGeo;
1344 borderGeo.rrect = RRect2DrawingRRect(GetRRectForDrawingBorder(properties, border, isOutline));
1345 borderGeo.innerRRect = RRect2DrawingRRect(GetInnerRRectForDrawingBorder(properties, border, isOutline));
1346 auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
1347 auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
1348 borderGeo.center = { centerX, centerY };
1349 auto rect = borderGeo.rrect.GetRect();
1350 Drawing::AutoCanvasRestore acr(canvas, false);
1351 Drawing::SaveLayerOps slr(&rect, nullptr);
1352 canvas.SaveLayer(slr);
1353 border->DrawBorders(canvas, pen, borderGeo);
1354 }
1355 }
1356 }
1357
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas)1358 void RSPropertiesPainter::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas)
1359 {
1360 auto border = properties.GetBorder();
1361 if (border && border->HasBorder()) {
1362 DrawBorderBase(properties, canvas, border, false);
1363 }
1364 }
1365
GetOutlineDirtyRect(RectI & dirtyOutline,const RSProperties & properties,const bool isAbsCoordinate)1366 void RSPropertiesPainter::GetOutlineDirtyRect(RectI& dirtyOutline,
1367 const RSProperties& properties, const bool isAbsCoordinate)
1368 {
1369 auto outline = properties.GetOutline();
1370 if (!outline || !outline->HasBorder()) {
1371 return;
1372 }
1373
1374 auto& geoPtr = properties.GetBoundsGeometry();
1375 Drawing::Matrix matrix = (geoPtr && isAbsCoordinate) ? geoPtr->GetAbsMatrix() : Drawing::Matrix();
1376 auto drawingRect = Rect2DrawingRect(GetRRectForDrawingBorder(properties, outline, true).rect_);
1377 matrix.MapRect(drawingRect, drawingRect);
1378 dirtyOutline.left_ = std::floor(drawingRect.GetLeft());
1379 dirtyOutline.top_ = std::floor(drawingRect.GetTop());
1380 dirtyOutline.width_ = std::ceil(drawingRect.GetWidth()) + PARAM_DOUBLE;
1381 dirtyOutline.height_ = std::ceil(drawingRect.GetHeight()) + PARAM_DOUBLE;
1382 }
1383
DrawOutline(const RSProperties & properties,Drawing::Canvas & canvas)1384 void RSPropertiesPainter::DrawOutline(const RSProperties& properties, Drawing::Canvas& canvas)
1385 {
1386 auto outline = properties.GetOutline();
1387 if (outline && outline->HasBorder()) {
1388 DrawBorderBase(properties, canvas, outline, true);
1389 }
1390 }
1391
DrawForegroundColor(const RSProperties & properties,Drawing::Canvas & canvas)1392 void RSPropertiesPainter::DrawForegroundColor(const RSProperties& properties, Drawing::Canvas& canvas)
1393 {
1394 auto bgColor = properties.GetForegroundColor();
1395 if (bgColor == RgbPalette::Transparent()) {
1396 return;
1397 }
1398 // clip
1399 if (properties.GetClipBounds() != nullptr) {
1400 canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1401 } else if (properties.GetClipToBounds()) {
1402 canvas.ClipRect(Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, true);
1403 } else if (properties.GetClipToRRect()) {
1404 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, true);
1405 }
1406
1407 Drawing::Brush brush;
1408 brush.SetColor(Drawing::Color(bgColor.AsArgbInt()));
1409 brush.SetAntiAlias(true);
1410 canvas.AttachBrush(brush);
1411 canvas.DrawRoundRect(RRect2DrawingRRect(properties.GetRRect()));
1412 canvas.DetachBrush();
1413 }
1414
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas,Drawing::Rect maskBounds)1415 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas, Drawing::Rect maskBounds)
1416 {
1417 std::shared_ptr<RSMask> mask = properties.GetMask();
1418 if (mask == nullptr) {
1419 return;
1420 }
1421 if (mask->IsSvgMask() && !mask->GetSvgDom() && !mask->GetSvgPicture()) {
1422 ROSEN_LOGD("RSPropertiesPainter::DrawMask not has Svg Mask property");
1423 return;
1424 }
1425
1426 canvas.Save();
1427 Drawing::SaveLayerOps slr(&maskBounds, nullptr);
1428 canvas.SaveLayer(slr);
1429 uint32_t tmpLayer = canvas.GetSaveCount();
1430
1431 Drawing::Brush maskfilter;
1432 Drawing::Filter filter;
1433 filter.SetColorFilter(Drawing::ColorFilter::CreateComposeColorFilter(
1434 *(Drawing::ColorFilter::CreateLumaColorFilter()), *(Drawing::ColorFilter::CreateSrgbGammaToLinear())));
1435 maskfilter.SetFilter(filter);
1436 Drawing::SaveLayerOps slrMask(&maskBounds, &maskfilter);
1437 canvas.SaveLayer(slrMask);
1438 if (mask->IsSvgMask()) {
1439 Drawing::AutoCanvasRestore maskSave(canvas, true);
1440 canvas.Translate(maskBounds.GetLeft() + mask->GetSvgX(), maskBounds.GetTop() + mask->GetSvgY());
1441 canvas.Scale(mask->GetScaleX(), mask->GetScaleY());
1442 if (mask->GetSvgDom()) {
1443 canvas.DrawSVGDOM(mask->GetSvgDom());
1444 } else if (mask->GetSvgPicture()) {
1445 canvas.DrawPicture(*mask->GetSvgPicture());
1446 }
1447 } else if (mask->IsGradientMask()) {
1448 Drawing::AutoCanvasRestore maskSave(canvas, true);
1449 canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1450 Drawing::Rect rect = Drawing::Rect(
1451 0, 0, maskBounds.GetWidth(), maskBounds.GetHeight());
1452 canvas.AttachBrush(mask->GetMaskBrush());
1453 canvas.DrawRect(rect);
1454 canvas.DetachBrush();
1455 } else if (mask->IsPathMask()) {
1456 Drawing::AutoCanvasRestore maskSave(canvas, true);
1457 canvas.Translate(maskBounds.GetLeft(), maskBounds.GetTop());
1458 canvas.AttachBrush(mask->GetMaskBrush());
1459 canvas.AttachPen(mask->GetMaskPen());
1460 canvas.DrawPath(*mask->GetMaskPath());
1461 canvas.DetachBrush();
1462 canvas.DetachPen();
1463 } else if (mask->IsPixelMapMask()) {
1464 Drawing::AutoCanvasRestore arc(canvas, true);
1465 if (mask->GetImage()) {
1466 canvas.DrawImage(*mask->GetImage(), 0.f, 0.f, Drawing::SamplingOptions());
1467 }
1468 }
1469
1470 // back to mask layer
1471 canvas.RestoreToCount(tmpLayer);
1472 // create content layer
1473 Drawing::Brush maskPaint;
1474 maskPaint.SetBlendMode(Drawing::BlendMode::SRC_IN);
1475 Drawing::SaveLayerOps slrContent(&maskBounds, &maskPaint);
1476 canvas.SaveLayer(slrContent);
1477 canvas.ClipRect(maskBounds, Drawing::ClipOp::INTERSECT, true);
1478 }
1479
DrawMask(const RSProperties & properties,Drawing::Canvas & canvas)1480 void RSPropertiesPainter::DrawMask(const RSProperties& properties, Drawing::Canvas& canvas)
1481 {
1482 Drawing::Rect maskBounds = Rect2DrawingRect(properties.GetBoundsRect());
1483 DrawMask(properties, canvas, maskBounds);
1484 }
1485
DrawSpherize(const RSProperties & properties,RSPaintFilterCanvas & canvas,const std::shared_ptr<Drawing::Surface> & spherizeSurface)1486 void RSPropertiesPainter::DrawSpherize(const RSProperties& properties, RSPaintFilterCanvas& canvas,
1487 const std::shared_ptr<Drawing::Surface>& spherizeSurface)
1488 {
1489 if (spherizeSurface == nullptr) {
1490 return;
1491 }
1492 if (spherizeSurface->Width() == 0 || spherizeSurface->Height() == 0) {
1493 return;
1494 }
1495 Drawing::AutoCanvasRestore acr(canvas, true);
1496 float canvasWidth = properties.GetBoundsRect().GetWidth();
1497 float canvasHeight = properties.GetBoundsRect().GetHeight();
1498
1499 auto imageSnapshot = spherizeSurface->GetImageSnapshot();
1500 if (imageSnapshot == nullptr) {
1501 ROSEN_LOGE("RSPropertiesPainter::DrawCachedSpherizeSurface image is null");
1502 return;
1503 }
1504 int imageWidth = imageSnapshot->GetWidth();
1505 int imageHeight = imageSnapshot->GetHeight();
1506 if (imageWidth == 0 || imageHeight == 0) {
1507 return;
1508 }
1509 canvas.Scale(canvasWidth / imageWidth, canvasHeight / imageHeight);
1510
1511 float width = imageWidth;
1512 float height = imageHeight;
1513 float degree = properties.GetSpherize();
1514 bool isWidthGreater = width > height;
1515 ROSEN_LOGI("RSPropertiesPainter::DrawCachedSpherizeSurface spherize degree [%{public}f]", degree);
1516
1517 Drawing::Brush brush;
1518 brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
1519 Drawing::SamplingOptions samplingOptions;
1520 Drawing::Matrix scaleMat;
1521 brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
1522 *imageSnapshot, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat));
1523 canvas.AttachBrush(brush);
1524
1525 const Drawing::Point texCoords[4] = {
1526 {0.0f, 0.0f}, {width, 0.0f}, {width, height}, {0.0f, height}
1527 };
1528 float offsetSquare = 0.f;
1529 if (isWidthGreater) {
1530 offsetSquare = (width - height) * degree / 2.0; // half of the change distance
1531 width = width - (width - height) * degree;
1532 } else {
1533 offsetSquare = (height - width) * degree / 2.0; // half of the change distance
1534 height = height - (height - width) * degree;
1535 }
1536
1537 float segmentWidthOne = width / 3.0;
1538 float segmentWidthTwo = width / 3.0 * 2.0;
1539 float segmentHeightOne = height / 3.0;
1540 float segmentHeightTwo = height / 3.0 * 2.0;
1541 float offsetSphereWidth = width / 6 * degree;
1542 float offsetSphereHeight = height / 6 * degree;
1543
1544 const int PointNum = 12;
1545 Drawing::Point ctrlPoints[PointNum] = {
1546 // top edge control points
1547 {0.0f, 0.0f}, {segmentWidthOne, 0.0f}, {segmentWidthTwo, 0.0f}, {width, 0.0f},
1548 // right edge control points
1549 {width, segmentHeightOne}, {width, segmentHeightTwo},
1550 // bottom edge control points
1551 {width, height}, {segmentWidthTwo, height}, {segmentWidthOne, height}, {0.0f, height},
1552 // left edge control points
1553 {0.0f, segmentHeightTwo}, {0.0f, segmentHeightOne}
1554 };
1555 ctrlPoints[0].Offset(offsetSphereWidth, offsetSphereHeight); // top left control point
1556 ctrlPoints[3].Offset(-offsetSphereWidth, offsetSphereHeight); // top right control point
1557 ctrlPoints[6].Offset(-offsetSphereWidth, -offsetSphereHeight); // bottom right control point
1558 ctrlPoints[9].Offset(offsetSphereWidth, -offsetSphereHeight); // bottom left control point
1559 if (isWidthGreater) {
1560 for (int i = 0; i < PointNum; ++i) {
1561 ctrlPoints[i].Offset(offsetSquare, 0);
1562 }
1563 } else {
1564 for (int i = 0; i < PointNum; ++i) {
1565 ctrlPoints[i].Offset(0, offsetSquare);
1566 }
1567 }
1568 Drawing::Path path;
1569 path.MoveTo(ctrlPoints[0].GetX(), ctrlPoints[0].GetY());
1570 path.CubicTo(ctrlPoints[1], ctrlPoints[2], ctrlPoints[3]); // upper edge
1571 path.CubicTo(ctrlPoints[4], ctrlPoints[5], ctrlPoints[6]); // right edge
1572 path.CubicTo(ctrlPoints[7], ctrlPoints[8], ctrlPoints[9]); // bottom edge
1573 path.CubicTo(ctrlPoints[10], ctrlPoints[11], ctrlPoints[0]); // left edge
1574 canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, true);
1575 canvas.DrawPatch(ctrlPoints, nullptr, texCoords, Drawing::BlendMode::SRC_OVER);
1576 canvas.DetachBrush();
1577 }
1578
DrawColorFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas)1579 void RSPropertiesPainter::DrawColorFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1580 {
1581 // if useEffect defined, use color filter from parent EffectView.
1582 auto& colorFilter = properties.GetColorFilter();
1583 if (colorFilter == nullptr) {
1584 return;
1585 }
1586 Drawing::AutoCanvasRestore acr(canvas, true);
1587 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1588 Drawing::Brush brush;
1589 brush.SetAntiAlias(true);
1590 Drawing::Filter filter;
1591 filter.SetColorFilter(colorFilter);
1592 brush.SetFilter(filter);
1593 auto surface = canvas.GetSurface();
1594 if (surface == nullptr) {
1595 ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter surface is null");
1596 return;
1597 }
1598 auto clipBounds = canvas.GetDeviceClipBounds();
1599 auto imageSnapshot = surface->GetImageSnapshot(clipBounds);
1600 if (imageSnapshot == nullptr) {
1601 ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter image is null");
1602 return;
1603 }
1604 imageSnapshot->HintCacheGpuResource();
1605 canvas.ResetMatrix();
1606 Drawing::SamplingOptions options(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
1607 canvas.AttachBrush(brush);
1608 canvas.DrawImageRect(*imageSnapshot, clipBounds, options);
1609 canvas.DetachBrush();
1610 }
1611
DrawBinarizationShader(const RSProperties & properties,RSPaintFilterCanvas & canvas)1612 void RSPropertiesPainter::DrawBinarizationShader(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1613 {
1614 Drawing::AutoCanvasRestore acr(canvas, true);
1615 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1616 auto drSurface = canvas.GetSurface();
1617 if (drSurface == nullptr) {
1618 ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter drSurface is null");
1619 return;
1620 }
1621 auto clipBounds = canvas.GetDeviceClipBounds();
1622 auto imageSnapshot = drSurface->GetImageSnapshot(clipBounds);
1623 if (imageSnapshot == nullptr) {
1624 ROSEN_LOGE("RSPropertiesPainter::DrawColorFilter image is null");
1625 return;
1626 }
1627 auto& aiInvert = properties.GetAiInvert();
1628 Drawing::Matrix matrix;
1629 auto imageShader = Drawing::ShaderEffect::CreateImageShader(*imageSnapshot, Drawing::TileMode::CLAMP,
1630 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
1631 float thresholdLow = aiInvert->z_ - aiInvert->w_;
1632 float thresholdHigh = aiInvert->z_ + aiInvert->w_;
1633 auto shader = MakeBinarizationShader(
1634 aiInvert->x_, aiInvert->y_, thresholdLow, thresholdHigh, imageShader);
1635 Drawing::Brush brush;
1636 brush.SetShaderEffect(shader);
1637 brush.SetAntiAlias(true);
1638 canvas.ResetMatrix();
1639 canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1640 canvas.DrawBackground(brush);
1641 }
1642
MakeBinarizationShader(float low,float high,float thresholdLow,float thresholdHigh,std::shared_ptr<Drawing::ShaderEffect> imageShader)1643 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeBinarizationShader(float low, float high,
1644 float thresholdLow, float thresholdHigh,
1645 std::shared_ptr<Drawing::ShaderEffect> imageShader)
1646 {
1647 static constexpr char prog[] = R"(
1648 uniform mediump float ubo_low;
1649 uniform mediump float ubo_high;
1650 uniform mediump float ubo_thresholdLow;
1651 uniform mediump float ubo_thresholdHigh;
1652 uniform shader imageShader;
1653 mediump vec4 main(vec2 drawing_coord) {
1654 mediump vec3 c = imageShader(drawing_coord).rgb;
1655 float gray = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
1656 float lowRes = mix(ubo_high, -1.0, step(ubo_thresholdLow, gray));
1657 float highRes = mix(-1.0, ubo_low, step(ubo_thresholdHigh, gray));
1658 float midRes = (ubo_thresholdHigh - gray) * (ubo_high - ubo_low) /
1659 (ubo_thresholdHigh - ubo_thresholdLow) + ubo_low;
1660 float invertedGray = mix(midRes, max(lowRes, highRes), step(-0.5, max(lowRes, highRes)));
1661 mediump vec3 invert = vec3(invertedGray);
1662 mediump vec4 res = vec4(invert, 1.0);
1663 return res;
1664 }
1665 )";
1666 if (binarizationShaderEffect_ == nullptr) {
1667 binarizationShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
1668 if (binarizationShaderEffect_ == nullptr) {
1669 ROSEN_LOGE("MakeBinarizationShader::RuntimeShader effect error\n");
1670 return nullptr;
1671 }
1672 }
1673 std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
1674 std::make_shared<Drawing::RuntimeShaderBuilder>(binarizationShaderEffect_);
1675 // aviod zero-divide in shader
1676 thresholdHigh = thresholdHigh <= thresholdLow ? thresholdHigh + 1e-6 : thresholdHigh;
1677 builder->SetChild("imageShader", imageShader);
1678 builder->SetUniform("ubo_low", low);
1679 builder->SetUniform("ubo_high", high);
1680 builder->SetUniform("ubo_thresholdLow", thresholdLow);
1681 builder->SetUniform("ubo_thresholdHigh", thresholdHigh);
1682 return builder->MakeShader(nullptr, false);
1683 }
1684
DrawLightUpEffect(const RSProperties & properties,RSPaintFilterCanvas & canvas)1685 void RSPropertiesPainter::DrawLightUpEffect(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1686 {
1687 Drawing::Surface* surface = canvas.GetSurface();
1688 if (surface == nullptr) {
1689 ROSEN_LOGD("RSPropertiesPainter::DrawLightUpEffect surface is null");
1690 return;
1691 }
1692 Drawing::AutoCanvasRestore acr(canvas, true);
1693 if (properties.GetClipBounds() != nullptr) {
1694 canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1695 } else {
1696 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1697 }
1698
1699 auto clipBounds = canvas.GetDeviceClipBounds();
1700 auto image = surface->GetImageSnapshot(clipBounds);
1701 if (image == nullptr) {
1702 ROSEN_LOGE("RSPropertiesPainter::DrawLightUpEffect image is null");
1703 return;
1704 }
1705 Drawing::Matrix scaleMat;
1706 auto imageShader = Drawing::ShaderEffect::CreateImageShader(
1707 *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
1708 Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), scaleMat);
1709 auto shader = MakeLightUpEffectShader(properties.GetLightUpEffect(), imageShader);
1710 Drawing::Brush brush;
1711 brush.SetShaderEffect(shader);
1712 canvas.ResetMatrix();
1713 canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1714 canvas.DrawBackground(brush);
1715 }
1716
MakeLightUpEffectShader(float lightUpDeg,std::shared_ptr<Drawing::ShaderEffect> imageShader)1717 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeLightUpEffectShader(
1718 float lightUpDeg, std::shared_ptr<Drawing::ShaderEffect> imageShader)
1719 {
1720 // Realizations locate in SkiaShaderEffect::InitWithLightUp & DDGRShaderEffect::InitWithLightUp
1721 return Drawing::ShaderEffect::CreateLightUp(lightUpDeg, *imageShader);
1722 }
1723
1724
DrawDynamicLightUp(const RSProperties & properties,RSPaintFilterCanvas & canvas)1725 void RSPropertiesPainter::DrawDynamicLightUp(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1726 {
1727 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "DrawDynamicLightUp, rate: %f, degree: %f, bounds: %s",
1728 properties.GetDynamicLightUpRate().value(), properties.GetDynamicLightUpDegree().value(),
1729 properties.GetBoundsGeometry()->GetAbsRect().ToString().c_str());
1730 Drawing::Surface* surface = canvas.GetSurface();
1731 if (surface == nullptr) {
1732 ROSEN_LOGD("RSPropertiesPainter::DrawDynamicLightUp surface is null");
1733 return;
1734 }
1735
1736 auto blender = MakeDynamicLightUpBlender(properties.GetDynamicLightUpRate().value() * canvas.GetAlpha(),
1737 properties.GetDynamicLightUpDegree().value() * canvas.GetAlpha());
1738 Drawing::Brush brush;
1739 brush.SetBlender(blender);
1740 canvas.DrawBackground(brush);
1741 }
1742
MakeDynamicLightUpBlender(float dynamicLightUpRate,float dynamicLightUpDeg)1743 std::shared_ptr<Drawing::Blender> RSPropertiesPainter::MakeDynamicLightUpBlender(
1744 float dynamicLightUpRate, float dynamicLightUpDeg)
1745 {
1746 static constexpr char prog[] = R"(
1747 uniform float dynamicLightUpRate;
1748 uniform float dynamicLightUpDeg;
1749
1750 vec4 main(vec4 drawing_src, vec4 drawing_dst) {
1751 float x = 0.299 * drawing_dst.r + 0.587 * drawing_dst.g + 0.114 * drawing_dst.b;
1752 float y = (0 - dynamicLightUpRate) * x + dynamicLightUpDeg;
1753 float R = clamp((drawing_dst.r + y), 0.0, 1.0);
1754 float G = clamp((drawing_dst.g + y), 0.0, 1.0);
1755 float B = clamp((drawing_dst.b + y), 0.0, 1.0);
1756 return vec4(R, G, B, 1.0);
1757 }
1758 )";
1759 if (dynamicLightUpBlenderEffect_ == nullptr) {
1760 dynamicLightUpBlenderEffect_ = Drawing::RuntimeEffect::CreateForBlender(prog);
1761 if (dynamicLightUpBlenderEffect_ == nullptr) {
1762 ROSEN_LOGE("MakeDynamicLightUpBlender::MakeDynamicLightUpBlender effect error!\n");
1763 return nullptr;
1764 }
1765 }
1766 std::shared_ptr<Drawing::RuntimeBlenderBuilder> builder =
1767 std::make_shared<Drawing::RuntimeBlenderBuilder>(dynamicLightUpBlenderEffect_);
1768 builder->SetUniform("dynamicLightUpRate", dynamicLightUpRate);
1769 builder->SetUniform("dynamicLightUpDeg", dynamicLightUpDeg);
1770 return builder->MakeBlender();
1771 }
1772
DrawDynamicDim(const RSProperties & properties,RSPaintFilterCanvas & canvas)1773 void RSPropertiesPainter::DrawDynamicDim(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1774 {
1775 Drawing::Surface* surface = canvas.GetSurface();
1776 if (surface == nullptr) {
1777 ROSEN_LOGD("RSPropertiesPainter::DrawDynamicDim surface is null");
1778 return;
1779 }
1780 Drawing::AutoCanvasRestore acr(canvas, true);
1781 if (properties.GetClipBounds() != nullptr) {
1782 canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
1783 } else {
1784 canvas.ClipRoundRect(RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
1785 }
1786
1787 auto clipBounds = canvas.GetDeviceClipBounds();
1788 auto image = surface->GetImageSnapshot(clipBounds);
1789 if (image == nullptr) {
1790 ROSEN_LOGE("RSPropertiesPainter::DrawDynamicDim image is null");
1791 return;
1792 }
1793 Drawing::Matrix scaleMat;
1794 auto imageShader = Drawing::ShaderEffect::CreateImageShader(
1795 *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
1796 Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), scaleMat);
1797 auto shader = MakeDynamicDimShader(properties.GetDynamicDimDegree().value(), imageShader);
1798 if (shader == nullptr) {
1799 ROSEN_LOGE("RSPropertiesPainter::DrawDynamicDim shader is null");
1800 return;
1801 }
1802 Drawing::Brush brush;
1803 brush.SetShaderEffect(shader);
1804 canvas.ResetMatrix();
1805 canvas.Translate(clipBounds.GetLeft(), clipBounds.GetTop());
1806 canvas.DrawBackground(brush);
1807 }
1808
MakeDynamicDimShader(float dynamicDimDeg,std::shared_ptr<Drawing::ShaderEffect> imageShader)1809 std::shared_ptr<Drawing::ShaderEffect> RSPropertiesPainter::MakeDynamicDimShader(
1810 float dynamicDimDeg, std::shared_ptr<Drawing::ShaderEffect> imageShader)
1811 {
1812 static constexpr char prog[] = R"(
1813 uniform half dynamicDimDeg;
1814 uniform shader imageShader;
1815
1816 vec3 rgb2hsv(in vec3 c)
1817 {
1818 vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
1819 vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
1820 vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
1821 float d = q.x - min(q.w, q.y);
1822 float e = 1.0e-10;
1823 return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
1824 }
1825 vec3 hsv2rgb(in vec3 c)
1826 {
1827 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);
1828 return c.z * mix(vec3(1.0), rgb, c.y);
1829 }
1830 half4 main(float2 coord)
1831 {
1832 vec3 hsv = rgb2hsv(imageShader.eval(coord).rgb);
1833 float value = max(0.8, dynamicDimDeg); // 0.8 is min saturation ratio.
1834 hsv.y = hsv.y * (1.75 - value * 0.75); // saturation value [1.0 , 1.15].
1835 hsv.z = min(hsv.z * dynamicDimDeg, 1.0);
1836 return vec4(hsv2rgb(hsv), 1.0);
1837 }
1838 )";
1839 if (dynamicDimShaderEffect_ == nullptr) {
1840 dynamicDimShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
1841 if (dynamicDimShaderEffect_ == nullptr) {
1842 ROSEN_LOGE("MakeBinarizationShader::RuntimeShader effect error\n");
1843 return nullptr;
1844 }
1845 }
1846 std::shared_ptr<Drawing::ShaderEffect> children[] = {imageShader};
1847 size_t childCount = 1;
1848 auto data = std::make_shared<Drawing::Data>();
1849 data->BuildWithCopy(&dynamicDimDeg, sizeof(dynamicDimDeg));
1850 return dynamicDimShaderEffect_->MakeShader(data, children, childCount, nullptr, false);
1851 }
1852
DrawParticle(const RSProperties & properties,RSPaintFilterCanvas & canvas)1853 void RSPropertiesPainter::DrawParticle(const RSProperties& properties, RSPaintFilterCanvas& canvas)
1854 {
1855 const auto& particleVector = properties.GetParticles();
1856 if (particleVector.GetParticleSize() == 0) {
1857 return;
1858 }
1859 const auto& particles = particleVector.GetParticleVector();
1860 auto bounds = properties.GetDrawRegion();
1861 int imageCount = particleVector.GetParticleImageCount();
1862 auto imageVector = particleVector.GetParticleImageVector();
1863 auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
1864 if (particleDrawable != nullptr) {
1865 particleDrawable->Draw(canvas, bounds);
1866 }
1867 }
1868
IsDangerousBlendMode(int blendMode,int blendApplyType)1869 bool RSPropertiesPainter::IsDangerousBlendMode(int blendMode, int blendApplyType)
1870 {
1871 static const uint32_t fastDangerousBit =
1872 (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1873 (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1874 (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1875 (1 << static_cast<int>(Drawing::BlendMode::XOR));
1876 static const uint32_t offscreenDangerousBit =
1877 (1 << static_cast<int>(Drawing::BlendMode::CLEAR)) +
1878 (1 << static_cast<int>(Drawing::BlendMode::SRC)) +
1879 (1 << static_cast<int>(Drawing::BlendMode::SRC_IN)) +
1880 (1 << static_cast<int>(Drawing::BlendMode::DST_IN)) +
1881 (1 << static_cast<int>(Drawing::BlendMode::SRC_OUT)) +
1882 (1 << static_cast<int>(Drawing::BlendMode::DST_OUT)) +
1883 (1 << static_cast<int>(Drawing::BlendMode::DST_ATOP)) +
1884 (1 << static_cast<int>(Drawing::BlendMode::XOR)) +
1885 (1 << static_cast<int>(Drawing::BlendMode::MODULATE));
1886 uint32_t tmp = 1 << blendMode;
1887 if (blendApplyType == static_cast<int>(RSColorBlendApplyType::FAST)) {
1888 return tmp & fastDangerousBit;
1889 }
1890 return tmp & offscreenDangerousBit;
1891 }
1892 } // namespace Rosen
1893 } // namespace OHOS
1894