• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "drawable/rs_property_drawable_foreground.h"
17 
18 #include "common/rs_obj_abs_geometry.h"
19 #include "drawable/rs_property_drawable_utils.h"
20 #include "effect/rs_render_filter_base.h"
21 #include "effect/rs_render_shader_base.h"
22 #include "ge_render.h"
23 #include "ge_visual_effect.h"
24 #include "ge_visual_effect_container.h"
25 #include "memory/rs_tag_tracker.h"
26 #include "pipeline/rs_recording_canvas.h"
27 #include "pipeline/rs_render_node.h"
28 #include "platform/common/rs_log.h"
29 #include "property/rs_point_light_manager.h"
30 
31 namespace OHOS::Rosen {
32 namespace DrawableV2 {
33 namespace {
34 constexpr int PARAM_TWO = 2;
35 } // namespace
36 
37 const bool FOREGROUND_FILTER_ENABLED = RSSystemProperties::GetForegroundFilterEnabled();
38 
39 // ====================================
40 // Binarization
OnGenerate(const RSRenderNode & node)41 RSDrawable::Ptr RSBinarizationDrawable::OnGenerate(const RSRenderNode& node)
42 {
43     if (auto ret = std::make_shared<RSBinarizationDrawable>(); ret->OnUpdate(node)) {
44         return std::move(ret);
45     }
46     return nullptr;
47 }
48 
OnUpdate(const RSRenderNode & node)49 bool RSBinarizationDrawable::OnUpdate(const RSRenderNode& node)
50 {
51     auto& aiInvert = node.GetRenderProperties().GetAiInvert();
52     if (!aiInvert.has_value()) {
53         return false;
54     }
55     needSync_ = true;
56     stagingAiInvert_ = aiInvert;
57     return true;
58 }
59 
OnSync()60 void RSBinarizationDrawable::OnSync()
61 {
62     if (!needSync_) {
63         return;
64     }
65     aiInvert_ = std::move(stagingAiInvert_);
66     needSync_ = false;
67 }
68 
CreateDrawFunc() const69 Drawing::RecordingCanvas::DrawFunc RSBinarizationDrawable::CreateDrawFunc() const
70 {
71     auto ptr = std::static_pointer_cast<const RSBinarizationDrawable>(shared_from_this());
72     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
73 #ifdef RS_ENABLE_GPU
74         RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
75             RSTagTracker::SOURCETYPE::SOURCE_RSBINARIZATIONDRAWABLE);
76 #endif
77         RSPropertyDrawableUtils::DrawBinarization(canvas, ptr->aiInvert_);
78     };
79 }
80 
OnGenerate(const RSRenderNode & node)81 RSDrawable::Ptr RSColorFilterDrawable::OnGenerate(const RSRenderNode& node)
82 {
83     if (auto ret = std::make_shared<RSColorFilterDrawable>(); ret->OnUpdate(node)) {
84         return std::move(ret);
85     }
86     return nullptr;
87 }
88 
OnUpdate(const RSRenderNode & node)89 bool RSColorFilterDrawable::OnUpdate(const RSRenderNode& node)
90 {
91     auto& colorFilter = node.GetRenderProperties().GetColorFilter();
92     if (colorFilter == nullptr) {
93         return false;
94     }
95     needSync_ = true;
96     stagingFilter_ = colorFilter;
97     return true;
98 }
99 
OnSync()100 void RSColorFilterDrawable::OnSync()
101 {
102     if (!needSync_) {
103         return;
104     }
105     filter_ = std::move(stagingFilter_);
106     needSync_ = false;
107 }
108 
CreateDrawFunc() const109 Drawing::RecordingCanvas::DrawFunc RSColorFilterDrawable::CreateDrawFunc() const
110 {
111     auto ptr = std::static_pointer_cast<const RSColorFilterDrawable>(shared_from_this());
112     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
113 #ifdef RS_ENABLE_GPU
114         RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
115             RSTagTracker::SOURCETYPE::SOURCE_RSCOLORFILTERDRAWABLE);
116 #endif
117         RSPropertyDrawableUtils::DrawColorFilter(canvas, ptr->filter_);
118     };
119 }
OnGenerate(const RSRenderNode & node)120 RSDrawable::Ptr RSLightUpEffectDrawable::OnGenerate(const RSRenderNode& node)
121 {
122     if (auto ret = std::make_shared<RSLightUpEffectDrawable>(); ret->OnUpdate(node)) {
123         return std::move(ret);
124     }
125     return nullptr;
126 }
127 
OnUpdate(const RSRenderNode & node)128 bool RSLightUpEffectDrawable::OnUpdate(const RSRenderNode& node)
129 {
130     if (!node.GetRenderProperties().IsLightUpEffectValid()) {
131         return false;
132     }
133     needSync_ = true;
134     stagingLightUpEffectDegree_ = node.GetRenderProperties().GetLightUpEffect();
135     return true;
136 }
137 
OnSync()138 void RSLightUpEffectDrawable::OnSync()
139 {
140     if (!needSync_) {
141         return;
142     }
143     lightUpEffectDegree_ = stagingLightUpEffectDegree_;
144     stagingLightUpEffectDegree_ = 1.0f;
145     needSync_ = false;
146 }
147 
CreateDrawFunc() const148 Drawing::RecordingCanvas::DrawFunc RSLightUpEffectDrawable::CreateDrawFunc() const
149 {
150     auto ptr = std::static_pointer_cast<const RSLightUpEffectDrawable>(shared_from_this());
151     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
152 #ifdef RS_ENABLE_GPU
153         RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
154             RSTagTracker::SOURCETYPE::SOURCE_RSLIGHTUPEFFECTDRAWABLE);
155 #endif
156         RSPropertyDrawableUtils::DrawLightUpEffect(canvas, ptr->lightUpEffectDegree_);
157     };
158 }
159 
OnGenerate(const RSRenderNode & node)160 RSDrawable::Ptr RSDynamicDimDrawable::OnGenerate(const RSRenderNode& node)
161 {
162     if (auto ret = std::make_shared<RSDynamicDimDrawable>(); ret->OnUpdate(node)) {
163         return std::move(ret);
164     }
165     return nullptr;
166 }
167 
OnUpdate(const RSRenderNode & node)168 bool RSDynamicDimDrawable::OnUpdate(const RSRenderNode& node)
169 {
170     if (!node.GetRenderProperties().IsDynamicDimValid()) {
171         return false;
172     }
173     needSync_ = true;
174     stagingDynamicDimDegree_ = node.GetRenderProperties().GetDynamicDimDegree().value();
175     return true;
176 }
177 
OnSync()178 void RSDynamicDimDrawable::OnSync()
179 {
180     if (!needSync_) {
181         return;
182     }
183     dynamicDimDegree_ = stagingDynamicDimDegree_;
184     needSync_ = false;
185 }
186 
CreateDrawFunc() const187 Drawing::RecordingCanvas::DrawFunc RSDynamicDimDrawable::CreateDrawFunc() const
188 {
189     auto ptr = std::static_pointer_cast<const RSDynamicDimDrawable>(shared_from_this());
190     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
191 #ifdef RS_ENABLE_GPU
192         RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
193             RSTagTracker::SOURCETYPE::SOURCE_RSDYNAMICDIMDRAWABLE);
194 #endif
195         RSPropertyDrawableUtils::DrawDynamicDim(canvas, ptr->dynamicDimDegree_);
196     };
197 }
198 
OnGenerate(const RSRenderNode & node)199 RSDrawable::Ptr RSForegroundColorDrawable::OnGenerate(const RSRenderNode& node)
200 {
201     if (auto ret = std::make_shared<RSForegroundColorDrawable>(); ret->OnUpdate(node)) {
202         return std::move(ret);
203     }
204     return nullptr;
205 };
206 
OnUpdate(const RSRenderNode & node)207 bool RSForegroundColorDrawable::OnUpdate(const RSRenderNode& node)
208 {
209     const RSProperties& properties = node.GetRenderProperties();
210     auto fgColor = properties.GetForegroundColor();
211     if (fgColor == RgbPalette::Transparent()) {
212         return false;
213     }
214 
215     RSPropertyDrawCmdListUpdater updater(0, 0, this);
216     Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
217     Drawing::Brush brush;
218     brush.SetColor(Drawing::Color(fgColor.AsArgbInt()));
219     brush.SetAntiAlias(true);
220     canvas.AttachBrush(brush);
221     canvas.DrawRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetRRect()));
222     canvas.DetachBrush();
223     return true;
224 }
225 
OnGenerate(const RSRenderNode & node)226 RSDrawable::Ptr RSForegroundShaderDrawable::OnGenerate(const RSRenderNode& node)
227 {
228     if (auto ret = std::make_shared<RSForegroundShaderDrawable>(); ret->OnUpdate(node)) {
229         return std::move(ret);
230     }
231     return nullptr;
232 };
233 
PostUpdate(const RSRenderNode & node)234 void RSForegroundShaderDrawable::PostUpdate(const RSRenderNode& node)
235 {
236     enableEDREffect_ = RSNGRenderShaderHelper::CheckEnableEDR(stagingShader_);
237     if (enableEDREffect_) {
238         screenNodeId_ = node.GetScreenNodeId();
239     }
240 }
241 
OnUpdate(const RSRenderNode & node)242 bool RSForegroundShaderDrawable::OnUpdate(const RSRenderNode& node)
243 {
244     const RSProperties& properties = node.GetRenderProperties();
245     const auto& shader = properties.GetForegroundShader();
246     if (!shader) {
247         return false;
248     }
249     needSync_ = true;
250     stagingShader_ = shader;
251     PostUpdate(node);
252     return true;
253 }
254 
OnSync()255 void RSForegroundShaderDrawable::OnSync()
256 {
257     if (needSync_ && stagingShader_) {
258         auto visualEffectContainer = std::make_shared<Drawing::GEVisualEffectContainer>();
259         stagingShader_->AppendToGEContainer(visualEffectContainer);
260         visualEffectContainer->UpdateCacheDataFrom(visualEffectContainer_);
261         visualEffectContainer_ = visualEffectContainer;
262         needSync_ = false;
263     }
264 }
265 
CreateDrawFunc() const266 Drawing::RecordingCanvas::DrawFunc RSForegroundShaderDrawable::CreateDrawFunc() const
267 {
268     auto ptr = std::static_pointer_cast<const RSForegroundShaderDrawable>(shared_from_this());
269     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
270         auto geRender = std::make_shared<GraphicsEffectEngine::GERender>();
271         if (canvas == nullptr || ptr->visualEffectContainer_ == nullptr || rect == nullptr) {
272             return;
273         }
274         geRender->DrawShaderEffect(*canvas, *(ptr->visualEffectContainer_), *rect);
275     };
276 }
277 
OnGenerate(const RSRenderNode & node)278 RSDrawable::Ptr RSCompositingFilterDrawable::OnGenerate(const RSRenderNode& node)
279 {
280     if (auto ret = std::make_shared<RSCompositingFilterDrawable>(); ret->OnUpdate(node)) {
281         return std::move(ret);
282     }
283     return nullptr;
284 }
285 
OnUpdate(const RSRenderNode & node)286 bool RSCompositingFilterDrawable::OnUpdate(const RSRenderNode& node)
287 {
288     stagingNodeId_ = node.GetId();
289     stagingNodeName_ = node.GetNodeName();
290     auto& rsFilter = node.GetRenderProperties().GetFilter();
291     if (rsFilter == nullptr) {
292         return false;
293     }
294     RecordFilterInfos(rsFilter);
295     needSync_ = true;
296     stagingFilter_ = rsFilter;
297     PostUpdate(node);
298     return true;
299 }
300 
301 // foregroundFilter
OnGenerate(const RSRenderNode & node)302 RSDrawable::Ptr RSForegroundFilterDrawable::OnGenerate(const RSRenderNode& node)
303 {
304     if (!FOREGROUND_FILTER_ENABLED) {
305         ROSEN_LOGD("RSForegroundFilterDrawable::OnGenerate close blur.");
306         return nullptr;
307     }
308     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
309     if (rsFilter == nullptr) {
310         return nullptr;
311     }
312 
313     if (auto ret = std::make_shared<RSForegroundFilterDrawable>(); ret->OnUpdate(node)) {
314         return std::move(ret);
315     }
316     return nullptr;
317 }
318 
OnUpdate(const RSRenderNode & node)319 bool RSForegroundFilterDrawable::OnUpdate(const RSRenderNode& node)
320 {
321     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
322     if (rsFilter == nullptr) {
323         return false;
324     }
325     needSync_ = true;
326     stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
327     return true;
328 }
329 
CreateDrawFunc() const330 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterDrawable::CreateDrawFunc() const
331 {
332     auto ptr = std::static_pointer_cast<const RSForegroundFilterDrawable>(shared_from_this());
333     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
334         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
335 #ifdef RS_ENABLE_GPU
336         RSTagTracker tagTracker(paintFilterCanvas ? paintFilterCanvas->GetGPUContext() : nullptr,
337             RSTagTracker::SOURCETYPE::SOURCE_RSFOREGROUNDFILTERDRAWABLE);
338 #endif
339         RSPropertyDrawableUtils::BeginForegroundFilter(*paintFilterCanvas, ptr->boundsRect_);
340     };
341 }
342 
OnSync()343 void RSForegroundFilterDrawable::OnSync()
344 {
345     if (needSync_ == false) {
346         return;
347     }
348     boundsRect_ = stagingBoundsRect_;
349     needSync_ = false;
350 }
351 
352 // Restore RSForegroundFilter
OnGenerate(const RSRenderNode & node)353 RSDrawable::Ptr RSForegroundFilterRestoreDrawable::OnGenerate(const RSRenderNode& node)
354 {
355     if (!FOREGROUND_FILTER_ENABLED) {
356         ROSEN_LOGD("RSForegroundFilterRestoreDrawable::OnGenerate close blur.");
357         return nullptr;
358     }
359     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
360     if (rsFilter == nullptr) {
361         return nullptr;
362     }
363 
364     if (auto ret = std::make_shared<RSForegroundFilterRestoreDrawable>(); ret->OnUpdate(node)) {
365         return std::move(ret);
366     }
367     return nullptr;
368 }
369 
OnUpdate(const RSRenderNode & node)370 bool RSForegroundFilterRestoreDrawable::OnUpdate(const RSRenderNode& node)
371 {
372     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
373     if (rsFilter == nullptr) {
374         return false;
375     }
376     needSync_ = true;
377     stagingForegroundFilter_ = rsFilter;
378     return true;
379 }
380 
CreateDrawFunc() const381 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterRestoreDrawable::CreateDrawFunc() const
382 {
383     auto ptr = std::static_pointer_cast<const RSForegroundFilterRestoreDrawable>(shared_from_this());
384     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
385         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
386 #ifdef RS_ENABLE_GPU
387         RSTagTracker tagTracker(paintFilterCanvas ? paintFilterCanvas->GetGPUContext() : nullptr,
388             RSTagTracker::SOURCETYPE::SOURCE_RSFOREGROUNDFILTERRESTOREDRAWABLE);
389 #endif
390         RSPropertyDrawableUtils::DrawForegroundFilter(*paintFilterCanvas, ptr->foregroundFilter_);
391     };
392 }
393 
OnSync()394 void RSForegroundFilterRestoreDrawable::OnSync()
395 {
396     if (needSync_ == false) {
397         return;
398     }
399     foregroundFilter_ = std::move(stagingForegroundFilter_);
400     if (foregroundFilter_) {
401         foregroundFilter_->OnSync();
402     }
403     needSync_ = false;
404 }
405 
OnGenerate(const RSRenderNode & node)406 RSDrawable::Ptr RSPixelStretchDrawable::OnGenerate(const RSRenderNode& node)
407 {
408     if (auto ret = std::make_shared<RSPixelStretchDrawable>(); ret->OnUpdate(node)) {
409         return std::move(ret);
410     }
411     return nullptr;
412 }
413 
OnUpdate(const RSRenderNode & node)414 bool RSPixelStretchDrawable::OnUpdate(const RSRenderNode& node)
415 {
416     auto& pixelStretch = node.GetRenderProperties().GetPixelStretch();
417     if (!pixelStretch.has_value()) {
418         return false;
419     }
420     needSync_ = true;
421     stagingNodeId_ = node.GetId();
422     stagingPixelStretch_ = pixelStretch;
423     stagePixelStretchTileMode_ = node.GetRenderProperties().GetPixelStretchTileMode();
424     const auto& boundsGeo = node.GetRenderProperties().GetBoundsGeometry();
425     stagingBoundsGeoValid_ = boundsGeo && !boundsGeo->IsEmpty();
426     stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
427     return true;
428 }
429 
SetPixelStretch(const std::optional<Vector4f> & pixelStretch)430 void RSPixelStretchDrawable::SetPixelStretch(const std::optional<Vector4f>& pixelStretch)
431 {
432     stagingPixelStretch_ = pixelStretch;
433 }
434 
OnSync()435 void RSPixelStretchDrawable::OnSync()
436 {
437     if (!needSync_) {
438         return;
439     }
440     renderNodeId_ = stagingNodeId_;
441     pixelStretch_ = std::move(stagingPixelStretch_);
442     pixelStretchTileMode_ = stagePixelStretchTileMode_;
443     boundsGeoValid_ = stagingBoundsGeoValid_;
444     stagingBoundsGeoValid_ = false;
445     boundsRect_ = stagingBoundsRect_;
446     stagingBoundsRect_.Clear();
447     needSync_ = false;
448 }
449 
CreateDrawFunc() const450 Drawing::RecordingCanvas::DrawFunc RSPixelStretchDrawable::CreateDrawFunc() const
451 {
452     auto ptr = std::static_pointer_cast<const RSPixelStretchDrawable>(shared_from_this());
453     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
454 #ifdef RS_ENABLE_GPU
455         RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
456             RSTagTracker::SOURCETYPE::SOURCE_RSPIXELSTRETCHDRAWABLE);
457 #endif
458         RSPropertyDrawableUtils::DrawPixelStretch(canvas, ptr->pixelStretch_, ptr->boundsRect_, ptr->boundsGeoValid_,
459             static_cast<Drawing::TileMode>(ptr->pixelStretchTileMode_));
460     };
461 }
462 
OnGenerate(const RSRenderNode & node)463 RSDrawable::Ptr RSBorderDrawable::OnGenerate(const RSRenderNode& node)
464 {
465     if (auto ret = std::make_shared<RSBorderDrawable>(); ret->OnUpdate(node)) {
466         return std::move(ret);
467     }
468     return nullptr;
469 };
470 
OnUpdate(const RSRenderNode & node)471 bool RSBorderDrawable::OnUpdate(const RSRenderNode& node)
472 {
473     const RSProperties& properties = node.GetRenderProperties();
474     auto& border = properties.GetBorder();
475     if (!border || !border->HasBorder()) {
476         return false;
477     }
478     // regenerate stagingDrawCmdList_
479     RSPropertyDrawCmdListUpdater updater(0, 0, this);
480     DrawBorder(properties, *updater.GetRecordingCanvas(), border, false);
481     return true;
482 }
483 
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool & isOutline)484 void RSBorderDrawable::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas,
485     const std::shared_ptr<RSBorder>& border, const bool& isOutline)
486 {
487     Drawing::Brush brush;
488     Drawing::Pen pen;
489     brush.SetAntiAlias(true);
490     pen.SetAntiAlias(true);
491     if (border->ApplyFillStyle(brush)) {
492         auto roundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
493             RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
494         auto innerRoundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
495             RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
496         canvas.AttachBrush(brush);
497         canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
498         canvas.DetachBrush();
499         return;
500     }
501     bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
502     if (isZero && border->ApplyFourLine(pen)) {
503         RectF rectf =
504             isOutline ? properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
505         border->PaintFourLine(canvas, pen, rectf);
506         return;
507     }
508     if (border->ApplyPathStyle(pen)) {
509         auto borderWidth = border->GetWidth();
510         RRect rrect = RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline);
511         rrect.rect_.width_ -= borderWidth;
512         rrect.rect_.height_ -= borderWidth;
513         rrect.rect_.Move(borderWidth / PARAM_TWO, borderWidth / PARAM_TWO);
514         Drawing::Path borderPath;
515         borderPath.AddRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(rrect));
516         canvas.AttachPen(pen);
517         canvas.DrawPath(borderPath);
518         canvas.DetachPen();
519         return;
520     }
521 
522     RSBorderGeo borderGeo;
523     borderGeo.rrect = RSPropertyDrawableUtils::RRect2DrawingRRect(
524         RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
525     borderGeo.innerRRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
526         RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
527     auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
528     auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
529     borderGeo.center = { centerX, centerY };
530     auto rect = borderGeo.rrect.GetRect();
531     Drawing::AutoCanvasRestore acr(canvas, false);
532     Drawing::SaveLayerOps slr(&rect, nullptr);
533     canvas.SaveLayer(slr);
534     border->DrawBorders(canvas, pen, borderGeo);
535 }
536 
OnGenerate(const RSRenderNode & node)537 RSDrawable::Ptr RSOutlineDrawable::OnGenerate(const RSRenderNode& node)
538 {
539     if (auto ret = std::make_shared<RSOutlineDrawable>(); ret->OnUpdate(node)) {
540         return std::move(ret);
541     }
542     return nullptr;
543 };
544 
OnUpdate(const RSRenderNode & node)545 bool RSOutlineDrawable::OnUpdate(const RSRenderNode& node)
546 {
547     const RSProperties& properties = node.GetRenderProperties();
548     auto& outline = properties.GetOutline();
549     if (!outline || !outline->HasBorder()) {
550         return false;
551     }
552     // regenerate stagingDrawCmdList_
553     RSPropertyDrawCmdListUpdater updater(0, 0, this);
554     RSBorderDrawable::DrawBorder(properties, *updater.GetRecordingCanvas(), outline, true);
555     return true;
556 }
557 
OnGenerate(const RSRenderNode & node)558 RSDrawable::Ptr RSPointLightDrawable::OnGenerate(const RSRenderNode& node)
559 {
560     if (auto ret = std::make_shared<RSPointLightDrawable>(node.GetRenderProperties()); ret->OnUpdate(node)) {
561         return std::move(ret);
562     }
563     return nullptr;
564 };
565 
CreateDrawFunc() const566 Drawing::RecordingCanvas::DrawFunc RSPointLightDrawable::CreateDrawFunc() const
567 {
568     auto ptr = std::static_pointer_cast<const RSPointLightDrawable>(shared_from_this());
569     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
570 #ifdef RS_ENABLE_GPU
571         RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
572             RSTagTracker::SOURCETYPE::SOURCE_RSPOINTLIGHTDRAWABLE);
573 #endif
574         ptr->DrawLight(canvas);
575     };
576 }
577 
OnUpdate(const RSRenderNode & node)578 bool RSPointLightDrawable::OnUpdate(const RSRenderNode& node)
579 {
580     const auto& illuminatedPtr = properties_.GetIlluminated();
581     if (!illuminatedPtr || !illuminatedPtr->IsIlluminatedValid()) {
582         return false;
583     }
584     return true;
585 }
586 
OnSync()587 void RSPointLightDrawable::OnSync()
588 {
589     lightSourcesAndPosVec_.clear();
590     const auto& lightSourcesAndPosMap  = properties_.GetIlluminated()->GetLightSourcesAndPosMap();
591     for (auto &pair : lightSourcesAndPosMap) {
592         lightSourcesAndPosVec_.push_back(pair);
593     }
594     properties_.GetIlluminated()->ClearLightSourcesAndPosMap();
595     if (lightSourcesAndPosVec_.empty()) {
596         return;
597     }
598     if (lightSourcesAndPosVec_.size() > MAX_LIGHT_SOURCES) {
599         std::sort(lightSourcesAndPosVec_.begin(), lightSourcesAndPosVec_.end(), [](const auto& x, const auto& y) {
600             return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
601                    y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
602         });
603     }
604     illuminatedType_ = properties_.GetIlluminated()->GetIlluminatedType();
605     borderWidth_ = std::ceil(properties_.GetIlluminatedBorderWidth());
606     auto& rrect = properties_.GetRRect();
607     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT ||
608         illuminatedType_ == IlluminatedType::BORDER ||
609         illuminatedType_ == IlluminatedType::BLEND_BORDER ||
610         illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT ||
611         illuminatedType_ == IlluminatedType::FEATHERING_BORDER) {
612         // half width and half height requires divide by 2.0f
613         Vector4f width = { borderWidth_ / 2.0f };
614         auto borderRRect = rrect.Inset(width);
615         borderRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(borderRRect);
616     }
617     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT ||
618         illuminatedType_ == IlluminatedType::CONTENT ||
619         illuminatedType_ == IlluminatedType::BLEND_CONTENT ||
620         illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT ||
621         illuminatedType_ == IlluminatedType::FEATHERING_BORDER) {
622         contentRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(rrect);
623     }
624     if (properties_.GetBoundsGeometry()) {
625         rect_ = properties_.GetBoundsGeometry()->GetAbsRect();
626     }
627 }
628 
DrawLight(Drawing::Canvas * canvas) const629 void RSPointLightDrawable::DrawLight(Drawing::Canvas* canvas) const
630 {
631     if (lightSourcesAndPosVec_.empty()) {
632         return;
633     }
634     auto phongShaderBuilder = GetPhongShaderBuilder();
635     if (!phongShaderBuilder) {
636         return;
637     }
638     if (illuminatedType_ == IlluminatedType::FEATHERING_BORDER) {
639         phongShaderBuilder = GetFeatheringBoardLightShaderBuilder();
640         float rectWidth = contentRRect_.GetRect().GetWidth();
641         float rectHeight = contentRRect_.GetRect().GetHeight();
642         phongShaderBuilder->SetUniform("iResolution", rectWidth, rectHeight);
643         phongShaderBuilder->SetUniform("contentBorderRadius",
644             contentRRect_.GetCornerRadius(Drawing::RoundRect::CornerPos::TOP_LEFT_POS).GetX());
645     }
646     constexpr int vectorLen = 4;
647     float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
648     float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
649     float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
650     std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
651 
652     auto iter = lightSourcesAndPosVec_.begin();
653     auto cnt = 0;
654     while (iter != lightSourcesAndPosVec_.end() && cnt < MAX_LIGHT_SOURCES) {
655         auto lightPos = iter->second;
656         auto lightIntensity = iter->first->GetLightIntensity();
657         auto lightColor = iter->first->GetLightColor();
658         Vector4f lightColorVec =
659             Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
660         for (int i = 0; i < vectorLen; i++) {
661             lightPosArray[cnt * vectorLen + i] = lightPos[i];
662             viewPosArray[cnt * vectorLen + i] = lightPos[i];
663             lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
664         }
665         lightIntensityArray[cnt] = lightIntensity;
666         iter++;
667         cnt++;
668     }
669     phongShaderBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
670     phongShaderBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
671     phongShaderBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
672     Drawing::Pen pen;
673     Drawing::Brush brush;
674     pen.SetAntiAlias(true);
675     brush.SetAntiAlias(true);
676     ROSEN_LOGD("RSPointLightDrawable::DrawLight illuminatedType:%{public}d", illuminatedType_);
677     if ((illuminatedType_ == IlluminatedType::BORDER_CONTENT) ||
678         (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
679         DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
680         DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
681     } else if ((illuminatedType_ == IlluminatedType::CONTENT) ||
682         (illuminatedType_ == IlluminatedType::BLEND_CONTENT)) {
683         DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
684     } else if ((illuminatedType_ == IlluminatedType::BORDER) ||
685         (illuminatedType_ == IlluminatedType::BLEND_BORDER) ||
686         (illuminatedType_ == IlluminatedType::FEATHERING_BORDER)) {
687         DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
688     }
689 }
690 
GetPhongShaderBuilder()691 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPointLightDrawable::GetPhongShaderBuilder()
692 {
693     thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder;
694     if (phongShaderBuilder) {
695         return phongShaderBuilder;
696     }
697     std::shared_ptr<Drawing::RuntimeEffect> lightEffect;
698     const static std::string lightString(R"(
699         uniform vec4 lightPos[12];
700         uniform vec4 viewPos[12];
701         uniform vec4 specularLightColor[12];
702         uniform float specularStrength[12];
703 
704         mediump vec4 main(vec2 drawing_coord) {
705             vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
706             float ambientStrength = 0.0;
707             vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
708             float diffuseStrength = 0.0;
709             float shininess = 8.0;
710             mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
711             vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
712             // ambient
713             vec4 ambient = lightColor * ambientStrength;
714             vec3 norm = normalize(NormalMap.rgb);
715 
716             for (int i = 0; i < 12; i++) {
717                 if (abs(specularStrength[i]) > 0.01) {
718                     vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
719                     float diff = max(dot(norm, lightDir), 0.0);
720                     vec4 diffuse = diff * lightColor;
721                     vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
722                     vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
723                     float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
724                     vec4 specular = lightColor * spec; // multiply color of incident light
725                     vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
726                     vec4 specularColor = specularLightColor[i];
727                     fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
728                 }
729             }
730             return fragColor;
731         }
732     )");
733     std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(lightString);
734     if (!effect) {
735         ROSEN_LOGE("light effect error");
736         return phongShaderBuilder;
737     }
738     lightEffect = std::move(effect);
739     phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect);
740     return phongShaderBuilder;
741 }
742 
GetFeatheringBoardLightShaderBuilder()743 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPointLightDrawable::GetFeatheringBoardLightShaderBuilder()
744 {
745     thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> featheringBoardLightShaderBuilder;
746     if (featheringBoardLightShaderBuilder) {
747         return featheringBoardLightShaderBuilder;
748     }
749     std::shared_ptr<Drawing::RuntimeEffect> lightEffect;
750     const static std::string lightString(R"(
751         uniform vec2 iResolution;
752         uniform float contentBorderRadius;
753         uniform vec4 lightPos[12];
754         uniform vec4 viewPos[12];
755         uniform vec4 specularLightColor[12];
756         uniform float specularStrength[12];
757         uniform float borderWidth;
758 
759         float sdRoundedBox(vec2 p, vec2 b, float r)
760         {
761             vec2 q = abs(p) - b + r;
762             return (min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r);
763         }
764 
765         vec2 sdRoundedBoxGradient(vec2 p, vec2 b, float r)
766         {
767             vec2 signs = vec2(p.x >= 0.0 ? 1.0 : -1.0, p.y >= 0.0 ? 1.0 : -1.0);
768             vec2 q = abs(p) - b + r;
769             vec2 nor = (q.y > q.x) ? vec2(0.0, 1.0) : vec2(1.0, 0.0);
770             nor = (q.x > 0.0 && q.y > 0.0) ? normalize(q) : nor;
771             return signs * nor;
772         }
773 
774         mediump vec4 main(vec2 drawing_coord)
775         {
776             float shininess = 8.0;
777             mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
778             vec2 halfResolution = iResolution.xy * 0.5;
779 
780             float gradRadius = min(max(contentBorderRadius, abs(borderWidth) * 3.0), iResolution.y * 0.5);
781             float drawRadius = min(max(contentBorderRadius, abs(borderWidth) * 1.1), iResolution.y * 0.5);
782             float realRoundedBoxSDF =
783                 sdRoundedBox(drawing_coord.xy - halfResolution, halfResolution, contentBorderRadius);
784             float virtualRoundedBoxSDF = sdRoundedBox(drawing_coord.xy - halfResolution, halfResolution, drawRadius);
785             vec2 grad = sdRoundedBoxGradient(drawing_coord.xy - halfResolution, halfResolution, gradRadius);
786             for (int i = 0; i < 12; i++) {
787                 if (abs(specularStrength[i]) > 0.01) {
788                     vec2 lightGrad = sdRoundedBoxGradient(lightPos[i].xy - halfResolution,
789                         halfResolution,
790                         contentBorderRadius); // lightGrad could be pre-computed
791                     float angleEfficient = dot(grad, lightGrad);
792                     if (angleEfficient > 0.0) {
793                         vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
794                         vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
795                         vec3 halfwayDir = normalize(lightDir + viewDir);                             // half vector
796                         // exponential relationship of angle
797                         float spec = pow(max(halfwayDir.z, 0.0), shininess); // norm is (0.0, 0.0, 1.0)
798                         spec *= specularStrength[i];
799                         spec *= smoothstep(-borderWidth, 0.0, virtualRoundedBoxSDF);
800                         spec *= (smoothstep(1.0, 0.0, spec) * 0.2 + 0.8);
801                         vec4 specularColor = specularLightColor[i];
802                         fragColor += specularColor * (spec * angleEfficient);
803                     }
804                 }
805             }
806             return vec4(fragColor.rgb, clamp(fragColor.a, 0.0, 1.0));
807         }
808     )");
809     std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(lightString);
810     if (!effect) {
811         ROSEN_LOGE("light effect error");
812         return featheringBoardLightShaderBuilder;
813     }
814     featheringBoardLightShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(effect);
815     return featheringBoardLightShaderBuilder;
816 }
817 
DrawContentLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const818 void RSPointLightDrawable::DrawContentLight(Drawing::Canvas& canvas,
819     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
820     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
821 {
822     constexpr float contentIntensityCoefficient = 0.3f;
823     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
824     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
825         specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
826     }
827     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
828     std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
829     brush.SetShaderEffect(shader);
830     if ((illuminatedType_ == IlluminatedType::BLEND_CONTENT) ||
831         (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
832         brush.SetAntiAlias(true);
833         brush.SetBlendMode(Drawing::BlendMode::OVERLAY);
834         Drawing::SaveLayerOps slo(&contentRRect_.GetRect(), &brush);
835         canvas.SaveLayer(slo);
836         canvas.AttachBrush(brush);
837         canvas.DrawRoundRect(contentRRect_);
838         canvas.DetachBrush();
839         canvas.Restore();
840     } else {
841         canvas.AttachBrush(brush);
842         canvas.DrawRoundRect(contentRRect_);
843         canvas.DetachBrush();
844     }
845 }
846 
DrawBorderLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const847 void RSPointLightDrawable::DrawBorderLight(Drawing::Canvas& canvas,
848     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
849     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
850 {
851     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
852     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
853         specularStrengthArr[i] = lightIntensityArray[i];
854     }
855     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
856     std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
857     pen.SetShaderEffect(shader);
858     float borderWidth = std::ceil(borderWidth_);
859     pen.SetWidth(borderWidth);
860     if ((illuminatedType_ == IlluminatedType::BLEND_BORDER) ||
861         (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
862         Drawing::Brush maskPaint;
863         pen.SetBlendMode(Drawing::BlendMode::OVERLAY);
864         Drawing::SaveLayerOps slo(&borderRRect_.GetRect(), &maskPaint);
865         canvas.SaveLayer(slo);
866         canvas.AttachPen(pen);
867         canvas.DrawRoundRect(borderRRect_);
868         canvas.DetachPen();
869         canvas.Restore();
870     } else {
871         canvas.AttachPen(pen);
872         canvas.DrawRoundRect(borderRRect_);
873         canvas.DetachPen();
874     }
875 }
876 
OnGenerate(const RSRenderNode & node)877 RSDrawable::Ptr RSParticleDrawable::OnGenerate(const RSRenderNode& node)
878 {
879     if (auto ret = std::make_shared<RSParticleDrawable>(); ret->OnUpdate(node)) {
880         return std::move(ret);
881     }
882     return nullptr;
883 };
884 
OnUpdate(const RSRenderNode & node)885 bool RSParticleDrawable::OnUpdate(const RSRenderNode& node)
886 {
887     const RSProperties& properties = node.GetRenderProperties();
888     const auto& particleVector = properties.GetParticles();
889     if (particleVector.GetParticleSize() == 0) {
890         return false;
891     }
892 
893     RSPropertyDrawCmdListUpdater updater(0, 0, this);
894     Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
895     const auto& particles = particleVector.GetParticleVector();
896     auto bounds = properties.GetDrawRegion();
897     auto imageCount = particleVector.GetParticleImageCount();
898     auto imageVector = particleVector.GetParticleImageVector();
899     auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
900     if (particleDrawable != nullptr) {
901         particleDrawable->Draw(canvas, bounds);
902     }
903     return true;
904 }
905 } // namespace DrawableV2
906 } // namespace OHOS::Rosen
907