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 "core/pipeline/base/render_node.h"
17
18 #ifdef ENABLE_ROSEN_BACKEND
19 #include "render_service_client/core/ui/rs_canvas_node.h"
20 #include "render_service_client/core/ui/rs_ui_director.h"
21
22 #include "core/animation/native_curve_helper.h"
23 #include "core/components/remote_window/rosen_render_remote_window.h"
24 #include "core/pipeline/base/rs_node_adapter.h"
25 #endif
26
27 #include "base/log/dump_log.h"
28 #include "core/components/common/rotation/rotation_node.h"
29 #include "core/components/container_modal/container_modal_constants.h"
30 #include "core/components/root/render_root.h"
31 #include "core/components/scroll/render_single_child_scroll.h"
32 #include "core/components/transform/render_transform.h"
33
34 namespace OHOS::Ace {
35 namespace {
36
37 constexpr float PRESS_KEYFRAME_START = 0.0f;
38 constexpr float PRESS_KEYFRAME_END = 1.0f;
39
40 struct ZIndexComparator {
operator ()OHOS::Ace::__anon2f3e62b60111::ZIndexComparator41 bool operator()(const RefPtr<RenderNode>& left, const RefPtr<RenderNode>& right) const
42 {
43 if (left && right) {
44 return (left->GetZIndex() < right->GetZIndex());
45 }
46 return false;
47 }
48 };
49
SortChildrenByZIndex(const std::list<RefPtr<RenderNode>> & children)50 inline std::multiset<RefPtr<RenderNode>, ZIndexComparator> SortChildrenByZIndex(
51 const std::list<RefPtr<RenderNode>>& children)
52 {
53 return std::multiset<RefPtr<RenderNode>, ZIndexComparator>(children.begin(), children.end());
54 }
55
56 } // namespace
57
58 constexpr Dimension FOCUS_BOUNDARY = 4.0_vp; // focus padding + effect boundary, VP
59
RenderNode(bool takeBoundary)60 RenderNode::RenderNode(bool takeBoundary) : takeBoundary_(takeBoundary) {}
61
MarkTreeRender(const RefPtr<RenderNode> & root,bool & meetHole,bool needFlush)62 void RenderNode::MarkTreeRender(const RefPtr<RenderNode>& root, bool& meetHole, bool needFlush)
63 {
64 if (root->GetHasSubWindow()) {
65 meetHole = true;
66 }
67
68 if (meetHole) {
69 root->SetNeedClip(false);
70 } else {
71 root->SetNeedClip(true);
72 }
73
74 if (needFlush) {
75 root->MarkNeedRender();
76 }
77
78 bool subMeetHole = meetHole;
79 for (auto child : root->GetChildren()) {
80 MarkTreeRender(child, subMeetHole, needFlush);
81 }
82 meetHole = subMeetHole;
83 }
84
MarkWholeRender(const WeakPtr<RenderNode> & nodeWeak,bool needFlush)85 void RenderNode::MarkWholeRender(const WeakPtr<RenderNode>& nodeWeak, bool needFlush)
86 {
87 auto node = nodeWeak.Upgrade();
88 if (!node) {
89 LOGE("Hole: MarkWholeRender node is null");
90 return;
91 }
92
93 auto parentWeak = node->GetParent();
94 auto parent = parentWeak.Upgrade();
95 while (parent) {
96 node = parent;
97 parentWeak = node->GetParent();
98 parent = parentWeak.Upgrade();
99 }
100
101 bool meetHole = false;
102 MarkTreeRender(node, meetHole, needFlush);
103 }
104
AddChild(const RefPtr<RenderNode> & child,int32_t slot)105 void RenderNode::AddChild(const RefPtr<RenderNode>& child, int32_t slot)
106 {
107 if (!child) {
108 LOGW("Child MUST NOT be nullptr");
109 return;
110 }
111
112 auto it = std::find(children_.begin(), children_.end(), child);
113 if (it != children_.end()) {
114 LOGW("RenderNode exist AddChild failed");
115 return;
116 }
117
118 auto pos = children_.begin();
119 std::advance(pos, slot);
120 children_.insert(pos, child);
121 child->SetParent(AceType::WeakClaim(this));
122 auto context = context_.Upgrade();
123 if (context && context->GetTransparentHole().IsValid()) {
124 MarkWholeRender(AceType::WeakClaim(this), true);
125 }
126 child->SetDepth(GetDepth() + 1);
127 OnChildAdded(child);
128 disappearingNodes_.remove(child);
129 if (SystemProperties::GetRosenBackendEnabled()) {
130 RSNodeAddChild(child);
131 // we don't know transition parameters until Update() is called, so we set pending flag here
132 child->SetPendingAppearingTransition();
133 } else {
134 child->NotifyTransition(TransitionType::APPEARING, child->GetNodeId());
135 }
136 }
137
RemoveChild(const RefPtr<RenderNode> & child)138 void RenderNode::RemoveChild(const RefPtr<RenderNode>& child)
139 {
140 if (!child) {
141 LOGW("Child MUST NOT be nullptr");
142 return;
143 }
144
145 // ClearChildren() before RemoveChild() also need to NotifyTransition().
146 if (!children_.empty()) {
147 auto it = std::find(children_.begin(), children_.end(), child);
148 if (it == children_.end()) {
149 LOGW("Child is not in this render node");
150 return;
151 } else {
152 children_.erase(it);
153 }
154 }
155
156 OnChildRemoved(child);
157 disappearingNodes_.remove(child);
158 // check whether child has config transition or will cause child memory leak.
159 auto context = context_.Upgrade();
160 if (context && context->GetExplicitAnimationOption().IsValid() &&
161 child->HasDisappearingTransition(child->GetNodeId())) {
162 disappearingNodes_.emplace_back(child);
163 child->SetParent(AceType::WeakClaim(this));
164 child->NotifyTransition(TransitionType::DISAPPEARING, child->GetNodeId());
165 }
166 #ifdef ENABLE_ROSEN_BACKEND
167 // To avoid redundant transition animation, only trigger transition when head render node is removed
168 else if (child->IsHeadRenderNode() && child->HasDisappearingTransition(child->GetNodeId())) {
169 // kick off a disappearing transition
170 child->NotifyTransition(TransitionType::DISAPPEARING, child->GetNodeId());
171 }
172 if (rsNode_ && rsNode_ == child->rsNode_) {
173 child->OnRemove();
174 }
175 #endif
176 }
177
MovePosition(int32_t slot)178 void RenderNode::MovePosition(int32_t slot)
179 {
180 auto parentNode = GetParent().Upgrade();
181 if (!parentNode) {
182 LOGW("Invalid parent");
183 return;
184 }
185
186 auto self = AceType::Claim(this);
187 auto& children = parentNode->children_;
188 auto it = children.end();
189 if (slot >= 0 && static_cast<size_t>(slot) < children.size()) {
190 it = children.begin();
191 std::advance(it, slot);
192 if (*it == this) {
193 // Already at the right place
194 return;
195 }
196
197 auto itSelf = std::find(it, children.end(), self);
198 if (itSelf != children.end()) {
199 children.erase(itSelf);
200 } else {
201 LOGW("Should NOT be here");
202 children.remove(self);
203 ++it;
204 }
205 } else {
206 children.remove(self);
207 }
208 children.insert(it, self);
209 }
210
ClearChildren()211 void RenderNode::ClearChildren()
212 {
213 children_.clear();
214 }
215
UpdateTouchRect()216 void RenderNode::UpdateTouchRect()
217 {
218 if (!isResponseRegion_) {
219 touchRect_ = GetPaintRect();
220 auto box = AceType::DynamicCast<RenderBox>(this);
221 if (box && box->GetTouchArea().GetOffset().IsPositiveOffset()) {
222 touchRect_.SetOffset(box->GetTouchArea().GetOffset() + touchRect_.GetOffset());
223 touchRect_.SetSize(box->GetTouchArea().GetSize());
224 }
225 touchRect_ = GetTransformRect(touchRect_);
226 touchRectList_.emplace_back(touchRect_);
227 SetTouchRectList(touchRectList_);
228 return;
229 }
230
231 responseRegionList_.clear();
232 touchRect_ = GetTransformRect(GetPaintRect());
233
234 for (auto& region : responseRegion_) {
235 double x = GetPxValue(touchRect_.Width(), region.GetOffset().GetX());
236 double y = GetPxValue(touchRect_.Height(), region.GetOffset().GetY());
237 double width = GetPxValue(touchRect_.Width(), region.GetWidth());
238 double height = GetPxValue(touchRect_.Height(), region.GetHeight());
239 Rect responseRegion(touchRect_.GetOffset().GetX() + x, touchRect_.GetOffset().GetY() + y, width, height);
240 responseRegionList_.emplace_back(responseRegion);
241 }
242
243 touchRectList_ = responseRegionList_;
244 SetTouchRectList(touchRectList_);
245 }
246
SetTouchRectList(std::vector<Rect> & touchRectList)247 void RenderNode::SetTouchRectList(std::vector<Rect>& touchRectList)
248 {
249 if (IsUseOnly()) {
250 return;
251 }
252 std::vector<Rect> parentTouchRectList = touchRectList;
253 const auto& children = GetChildren();
254 if (!children.empty()) {
255 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
256 auto& child = *iter;
257 auto childTouchRectList = child->GetTouchRectList();
258 CompareTouchRectList(touchRectList, childTouchRectList, parentTouchRectList);
259 }
260 }
261 }
262
CompareTouchRectList(std::vector<Rect> & touchRectList,const std::vector<Rect> & childTouchRectList,const std::vector<Rect> & parentTouchRectList)263 void RenderNode::CompareTouchRectList(std::vector<Rect>& touchRectList, const std::vector<Rect>& childTouchRectList,
264 const std::vector<Rect>& parentTouchRectList)
265 {
266 for (auto& childRect : childTouchRectList) {
267 bool isInRegion = false;
268 auto rect = childRect;
269 for (auto& parentRect : parentTouchRectList) {
270 // unified coordinate system
271 rect.SetOffset(childRect.GetOffset() + GetPaintRect().GetOffset());
272 if (CompareTouchRect(parentRect, rect)) {
273 isInRegion = true;
274 break;
275 }
276 }
277 if (!isInRegion && !IsResponseRegion()) {
278 touchRectList.emplace_back(rect);
279 }
280 }
281 }
282
GetPxValue(double standard,const Dimension & value)283 double RenderNode::GetPxValue(double standard, const Dimension& value)
284 {
285 auto context = context_.Upgrade();
286 if (!context) {
287 return value.Value();
288 }
289
290 double result = 0.0;
291 if (value.Unit() == DimensionUnit::PERCENT) {
292 result = standard * value.Value();
293 } else {
294 result = context->NormalizeToPx(value);
295 }
296 return result;
297 }
298
CompareTouchRect(const Rect & parentTouchRect,const Rect & childTouchRect)299 bool RenderNode::CompareTouchRect(const Rect& parentTouchRect, const Rect& childTouchRect)
300 {
301 if (childTouchRect.IsWrappedBy(parentTouchRect)) {
302 return true;
303 }
304 return false;
305 }
306
MoveWhenOutOfViewPort(bool hasEffect)307 void RenderNode::MoveWhenOutOfViewPort(bool hasEffect)
308 {
309 if (SystemProperties::GetDeviceType() != DeviceType::TV) {
310 return;
311 }
312
313 Offset effectOffset;
314 if (hasEffect) {
315 effectOffset = Offset(NormalizeToPx(FOCUS_BOUNDARY), NormalizeToPx(FOCUS_BOUNDARY));
316 }
317 auto parentNode = GetParent().Upgrade();
318 while (parentNode) {
319 auto scroll = AceType::DynamicCast<RenderSingleChildScroll>(parentNode);
320 if (scroll) {
321 // do move then break
322 scroll->MoveChildToViewPort(GetLayoutSize(), GetGlobalOffset(), effectOffset);
323 break;
324 } else {
325 parentNode = parentNode->GetParent().Upgrade();
326 }
327 }
328 }
329
DumpTree(int32_t depth)330 void RenderNode::DumpTree(int32_t depth)
331 {
332 auto accessibilityNode = GetAccessibilityNode().Upgrade();
333 int32_t nodeId = 0;
334 if (accessibilityNode) {
335 nodeId = accessibilityNode->GetNodeId();
336 }
337 const auto& children = GetChildren();
338 if (DumpLog::GetInstance().GetDumpFile()) {
339 auto dirtyRect = context_.Upgrade()->GetDirtyRect();
340 std::string touchRectList = "[";
341 for (auto& rect : touchRectList_) {
342 touchRectList.append("{").append(rect.ToString()).append("}");
343 }
344 touchRectList.append("]");
345
346 DumpLog::GetInstance().AddDesc(std::string("AccessibilityNodeID: ").append(std::to_string(nodeId)));
347 DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(depth)));
348 DumpLog::GetInstance().AddDesc(
349 std::string("DisappearingNodes: ").append(std::to_string(disappearingNodes_.size())));
350 DumpLog::GetInstance().AddDesc(std::string("GlobalOffset: ").append(GetGlobalOffset().ToString()));
351 DumpLog::GetInstance().AddDesc(std::string("PaintRect: ").append(paintRect_.ToString()));
352 DumpLog::GetInstance().AddDesc(std::string("TouchRect: ").append(touchRect_.ToString()));
353 DumpLog::GetInstance().AddDesc(std::string("TouchRectList: ").append(touchRectList));
354 DumpLog::GetInstance().AddDesc(std::string("DirtyRect: ").append(dirtyRect.ToString()));
355 DumpLog::GetInstance().AddDesc(std::string("LayoutParam: ").append(layoutParam_.ToString()));
356 #ifdef ENABLE_ROSEN_BACKEND
357 if (rsNode_) {
358 DumpLog::GetInstance().AddDesc(rsNode_->DumpNode(depth));
359 }
360 #endif
361 Dump();
362 DumpLog::GetInstance().Print(depth, AceType::TypeName(this), children.size());
363 }
364
365 for (const auto& item : children) {
366 item->DumpTree(depth + 1);
367 }
368 }
369
Dump()370 void RenderNode::Dump() {}
371
RenderWithContext(RenderContext & context,const Offset & offset)372 void RenderNode::RenderWithContext(RenderContext& context, const Offset& offset)
373 {
374 MarkNeedWindowBlur(false);
375 if (onLayoutReady_ && pendingDispatchLayoutReady_) {
376 onLayoutReady_(std::string("\"layoutReady\",null,null"));
377 }
378 pendingDispatchLayoutReady_ = false;
379 if (GetHasSubWindow() || !GetNeedClip()) {
380 if (context.GetNeedRestoreHole()) {
381 context.Restore();
382 context.SetNeedRestoreHole(false);
383 context.SetClipHole(Rect());
384 }
385 } else {
386 context.SetClipHole(context_.Upgrade()->GetTransparentHole());
387 }
388 Paint(context, offset);
389 for (const auto& item : SortChildrenByZIndex(disappearingNodes_)) {
390 PaintChild(item, context, offset);
391 }
392 auto hasOnAreaChangeCallback = eventExtensions_ ? eventExtensions_->HasOnAreaChangeExtension() : false;
393 if (needUpdateAccessibility_ || hasOnAreaChangeCallback) {
394 auto pipelineContext = context_.Upgrade();
395 if (pipelineContext != nullptr) {
396 pipelineContext->AddNeedRenderFinishNode(AceType::Claim(this));
397 }
398 }
399 CheckIfNeedUpdateTouchRect();
400 SetNeedRender(false);
401 }
402
NotifyPaintFinish()403 void RenderNode::NotifyPaintFinish()
404 {
405 bool hasObserver = false;
406 auto accessNode = accessibilityNode_.Upgrade();
407 if (accessNode) {
408 auto index = accessNode->GetNodeId();
409 auto pipeline = context_.Upgrade();
410 hasObserver = pipeline ? pipeline->IsVisibleChangeNodeExists(index) : false;
411 }
412 if (needUpdateAccessibility_ || hasObserver) {
413 for (auto& child : children_) {
414 child->NotifyPaintFinish();
415 }
416 auto pipelineContext = context_.Upgrade();
417 if (pipelineContext != nullptr) {
418 pipelineContext->AddNeedRenderFinishNode(AceType::Claim(this));
419 }
420 }
421 }
422
Paint(RenderContext & context,const Offset & offset)423 void RenderNode::Paint(RenderContext& context, const Offset& offset)
424 {
425 const auto& children = GetChildren();
426 for (const auto& item : SortChildrenByZIndex(children)) {
427 PaintChild(item, context, offset);
428 }
429 }
430
PaintChild(const RefPtr<RenderNode> & child,RenderContext & context,const Offset & offset)431 void RenderNode::PaintChild(const RefPtr<RenderNode>& child, RenderContext& context, const Offset& offset)
432 {
433 if (child && child->GetVisible()) {
434 context.PaintChild(child, offset);
435 }
436 }
437
PaintChildList(const std::list<RefPtr<RenderNode>> & childList,RenderContext & context,const Offset & offset)438 void RenderNode::PaintChildList(
439 const std::list<RefPtr<RenderNode>>& childList, RenderContext& context, const Offset& offset)
440 {
441 for (const auto& item : SortChildrenByZIndex(childList)) {
442 PaintChild(item, context, offset);
443 }
444 }
445
MarkNeedLayout(bool selfOnly,bool forceParent)446 void RenderNode::MarkNeedLayout(bool selfOnly, bool forceParent)
447 {
448 bool addSelf = false;
449 auto context = context_.Upgrade();
450 if (context != nullptr) {
451 context->ForceLayoutForImplicitAnimation();
452 }
453
454 bool forceSelf = forceParent && AceType::InstanceOf<RenderRoot>(this);
455 if (forceSelf) {
456 // This is root and child need force parent layout.
457 SetNeedLayout(true);
458 addSelf = true;
459 } else if (forceParent) {
460 // Force mark self and all ancestors need layout.
461 SetNeedLayout(true);
462 auto parent = parent_.Upgrade();
463 if (parent && (parent->CheckIfNeedLayoutAgain() || forceParent)) {
464 parent->MarkNeedLayout(false, forceParent);
465 } else {
466 addSelf = true;
467 }
468 } else if (!needLayout_) {
469 SetNeedLayout(true);
470 if ((IsTakenBoundary() || selfOnly) && !MarkNeedRenderSpecial()) {
471 addSelf = true;
472 } else {
473 auto parent = parent_.Upgrade();
474 if (parent && parent->CheckIfNeedLayoutAgain()) {
475 parent->MarkNeedLayout();
476 } else {
477 addSelf = true;
478 }
479 }
480 }
481 if (addSelf) {
482 auto pipelineContext = context_.Upgrade();
483 if (pipelineContext != nullptr) {
484 pipelineContext->AddDirtyLayoutNode(AceType::Claim(this));
485 }
486 }
487 }
488
MarkNeedPredictLayout()489 void RenderNode::MarkNeedPredictLayout()
490 {
491 auto pipelineContext = context_.Upgrade();
492 if (pipelineContext) {
493 pipelineContext->AddPredictLayoutNode(AceType::Claim(this));
494 }
495 }
496
OnLayout()497 void RenderNode::OnLayout()
498 {
499 auto parent = parent_.Upgrade();
500 if (parent) {
501 Size parentViewPort = parent->GetChildViewPort();
502 if (viewPort_ != parentViewPort) {
503 viewPort_ = parentViewPort;
504 needLayout_ = true;
505 }
506 }
507 if (NeedLayout()) {
508 PrepareLayout();
509 PerformLayout();
510 layoutParamChanged_ = false;
511 SetNeedLayout(false);
512 pendingDispatchLayoutReady_ = true;
513 MarkNeedRender();
514 }
515 }
516
PrepareLayout()517 void RenderNode::PrepareLayout() {}
518
SetPosition(const Offset & offset)519 void RenderNode::SetPosition(const Offset& offset)
520 {
521 Offset selfOffset;
522 if (positionParam_.left.second) {
523 selfOffset.SetX(NormalizePercentToPx(positionParam_.left.first, false));
524 } else if (positionParam_.right.second) {
525 selfOffset.SetX(-NormalizePercentToPx(positionParam_.right.first, false));
526 } else {
527 selfOffset.SetX(0);
528 }
529 selfOffset.SetX(selfOffset.GetX() - NormalizePercentToPx(positionParam_.anchor.first, false, true));
530 if (positionParam_.top.second) {
531 selfOffset.SetY(NormalizePercentToPx(positionParam_.top.first, true));
532 } else if (positionParam_.bottom.second) {
533 selfOffset.SetY(-NormalizePercentToPx(positionParam_.bottom.first, true));
534 } else {
535 selfOffset.SetY(0);
536 }
537 selfOffset.SetY(selfOffset.GetY() - NormalizePercentToPx(positionParam_.anchor.second, true, true));
538 selfOffset_ = selfOffset;
539 SetPositionInternal(selfOffset + offset);
540 }
541
Attach(const WeakPtr<PipelineContext> & context)542 void RenderNode::Attach(const WeakPtr<PipelineContext>& context)
543 {
544 context_ = context;
545 OnAttachContext();
546 paintX_.SetContextAndCallback(context_, [weak = WeakClaim(this)] {
547 auto render = weak.Upgrade();
548 if (!render) {
549 return;
550 }
551 auto parent = render->GetParent().Upgrade();
552 if (!parent) {
553 return;
554 }
555 parent->MarkNeedRender();
556 render->needUpdateTouchRect_ = true;
557 render->nonStrictPaintRect_.SetLeft(render->paintX_.Value());
558 render->OnGlobalPositionChanged();
559 });
560
561 paintY_.SetContextAndCallback(context_, [weak = WeakClaim(this)] {
562 auto render = weak.Upgrade();
563 if (!render) {
564 return;
565 }
566 auto parent = render->GetParent().Upgrade();
567 if (!parent) {
568 return;
569 }
570 parent->MarkNeedRender();
571 render->needUpdateTouchRect_ = true;
572 render->nonStrictPaintRect_.SetTop(render->paintY_.Value());
573 render->OnGlobalPositionChanged();
574 });
575
576 paintW_.SetContextAndCallback(context_, [weak = WeakClaim(this)] {
577 auto render = weak.Upgrade();
578 if (!render) {
579 return;
580 }
581 render->MarkNeedRender();
582 render->needUpdateTouchRect_ = true;
583 render->nonStrictPaintRect_.SetWidth(render->paintW_.Value());
584 render->transitionPaintRectSize_.SetWidth(render->paintW_.Value());
585 render->MarkNeedSyncGeometryProperties();
586 });
587
588 paintH_.SetContextAndCallback(context_, [weak = WeakClaim(this)] {
589 auto render = weak.Upgrade();
590 if (!render) {
591 return;
592 }
593 render->MarkNeedRender();
594 render->needUpdateTouchRect_ = true;
595 render->nonStrictPaintRect_.SetHeight(render->paintH_.Value());
596 render->transitionPaintRectSize_.SetHeight(render->paintH_.Value());
597 render->MarkNeedSyncGeometryProperties();
598 });
599 }
600
SetPositionInternal(const Offset & offset)601 void RenderNode::SetPositionInternal(const Offset& offset)
602 {
603 auto context = context_.Upgrade();
604 if (!context) {
605 LOGE("Set position internal failed. context is null.");
606 return;
607 }
608 if (paintRect_.GetOffset() != offset) {
609 isFirstPositionAssign_ = false;
610 nonStrictOption_ = context->GetExplicitAnimationOption();
611 context->AddLayoutTransitionNode(AceType::Claim(this));
612 paintRect_.SetOffset(offset);
613 needUpdateTouchRect_ = true;
614 OnPositionChanged();
615 OnGlobalPositionChanged();
616 MarkNeedSyncGeometryProperties();
617 }
618 if (isFirstPositionAssign_) {
619 isFirstPositionAssign_ = false;
620 nonStrictOption_ = context->GetExplicitAnimationOption();
621 context->AddLayoutTransitionNode(AceType::Claim(this));
622 }
623 }
624
CheckIfNeedUpdateTouchRect()625 void RenderNode::CheckIfNeedUpdateTouchRect()
626 {
627 auto parent = parent_.Upgrade();
628 if (!parent) {
629 return;
630 }
631 parent->MarkNeedUpdateTouchRect(true);
632 parent->CheckIfNeedUpdateTouchRect();
633 }
634
CreateMouseAnimation(RefPtr<KeyframeAnimation<Color>> & animation,const Color & from,const Color & to)635 void RenderNode::CreateMouseAnimation(RefPtr<KeyframeAnimation<Color>>& animation, const Color& from, const Color& to)
636 {
637 if (!animation) {
638 return;
639 }
640 auto colorFrameStart = AceType::MakeRefPtr<Keyframe<Color>>(PRESS_KEYFRAME_START, from);
641 auto colorFrameEnd = AceType::MakeRefPtr<Keyframe<Color>>(PRESS_KEYFRAME_END, to);
642 colorFrameEnd->SetCurve(Curves::SHARP);
643 animation->AddKeyframe(colorFrameStart);
644 animation->AddKeyframe(colorFrameEnd);
645 animation->AddListener([weakNode = AceType::WeakClaim(this)](const Color& value) {
646 auto node = weakNode.Upgrade();
647 if (node) {
648 node->eventEffectColor_ = value;
649 if (node->hoveAndPressCallback_) {
650 node->hoveAndPressCallback_(value);
651 }
652 node->MarkNeedRender();
653 }
654 });
655 }
656
MarkNeedRenderSpecial()657 bool RenderNode::MarkNeedRenderSpecial()
658 {
659 return false;
660 }
661
MarkNeedRender(bool overlay)662 void RenderNode::MarkNeedRender(bool overlay)
663 {
664 if (!needRender_) {
665 SetNeedRender(true);
666 if (IsRepaintBoundary()) {
667 auto pipelineContext = context_.Upgrade();
668 if (pipelineContext) {
669 pipelineContext->AddDirtyRenderNode(AceType::Claim(this), overlay);
670 }
671 } else {
672 auto parent = parent_.Upgrade();
673 if (parent) {
674 parent->MarkNeedRender();
675 }
676 }
677 }
678 }
679
SetVisible(bool visible,bool inRecursion)680 void RenderNode::SetVisible(bool visible, bool inRecursion)
681 {
682 if (visible_ != visible) {
683 visible_ = visible;
684 AddDirtyRenderBoundaryNode();
685 OnVisibleChanged();
686 CheckIfNeedUpdateTouchRect();
687 if (!inRecursion && SystemProperties::GetRosenBackendEnabled()) {
688 MarkParentNeedRender();
689 }
690 }
691 for (auto& child : children_) {
692 child->SetVisible(visible, true);
693 }
694 }
695
TouchTest(const Point & globalPoint,const Point & parentLocalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)696 bool RenderNode::TouchTest(const Point& globalPoint, const Point& parentLocalPoint, const TouchRestrict& touchRestrict,
697 TouchTestResult& result)
698 {
699 if (disableTouchEvent_ || disabled_) {
700 return false;
701 }
702
703 Point transformPoint = GetTransformPoint(parentLocalPoint);
704 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
705 return false;
706 }
707
708 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
709
710 bool dispatchSuccess = DispatchTouchTestToChildren(localPoint, globalPoint, touchRestrict, result);
711 auto beforeSize = result.size();
712 std::vector<Rect> vrect;
713 if (IsResponseRegion()) {
714 vrect = responseRegionList_;
715 }
716 vrect.emplace_back(paintRect_);
717 for (const auto& rect : vrect) {
718 if (touchable_ && rect.IsInRegion(transformPoint)) {
719 // Calculates the coordinate offset in this node.
720 globalPoint_ = globalPoint;
721 const auto coordinateOffset = globalPoint - localPoint;
722 coordinatePoint_ = Point(coordinateOffset.GetX(), coordinateOffset.GetY());
723 OnTouchTestHit(coordinateOffset, touchRestrict, result);
724 break;
725 }
726 }
727 auto endSize = result.size();
728 return dispatchSuccess || (beforeSize != endSize && IsNotSiblingAddRecognizerToResult());
729 }
730
DispatchTouchTestToChildren(const Point & localPoint,const Point & globalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)731 bool RenderNode::DispatchTouchTestToChildren(
732 const Point& localPoint, const Point& globalPoint, const TouchRestrict& touchRestrict, TouchTestResult& result)
733 {
734 bool dispatchSuccess = false;
735 if (!IsChildrenTouchEnable() || GetHitTestMode() == HitTestMode::HTMBLOCK) {
736 return dispatchSuccess;
737 }
738
739 const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
740 for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
741 const auto& child = *iter;
742 if (!child->GetVisible() || child->disabled_ || child->disableTouchEvent_) {
743 continue;
744 }
745 if (child->TouchTest(globalPoint, localPoint, touchRestrict, result)) {
746 dispatchSuccess = true;
747 if (child->GetHitTestMode() != HitTestMode::HTMTRANSPARENT) {
748 break;
749 }
750 }
751 auto interceptTouchEvent =
752 (child->IsTouchable() && (child->InterceptTouchEvent() || IsExclusiveEventForChild()) &&
753 child->GetHitTestMode() != HitTestMode::HTMTRANSPARENT);
754 if (child->GetHitTestMode() == HitTestMode::HTMBLOCK || interceptTouchEvent) {
755 auto localTransformPoint = child->GetTransformPoint(localPoint);
756 bool isInRegion = false;
757 for (const auto& rect : child->GetTouchRectList()) {
758 if (rect.IsInRegion(localTransformPoint)) {
759 dispatchSuccess = true;
760 isInRegion = true;
761 break;
762 }
763 }
764 if (isInRegion && child->GetHitTestMode() != HitTestMode::HTMDEFAULT) {
765 break;
766 }
767 }
768 }
769 return dispatchSuccess;
770 }
771
FindDropChild(const Point & globalPoint,const Point & parentLocalPoint)772 RefPtr<RenderNode> RenderNode::FindDropChild(const Point& globalPoint, const Point& parentLocalPoint)
773 {
774 Point transformPoint = GetTransformPoint(parentLocalPoint);
775 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
776 return nullptr;
777 }
778
779 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
780 const auto& children = GetChildren();
781 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
782 auto& child = *iter;
783 if (!child->GetVisible()) {
784 continue;
785 }
786 if (child->InterceptTouchEvent()) {
787 continue;
788 }
789
790 auto target = child->FindDropChild(globalPoint, localPoint);
791 if (target) {
792 return target;
793 }
794 }
795
796 for (auto& rect : GetTouchRectList()) {
797 if (touchable_ && rect.IsInRegion(transformPoint)) {
798 RefPtr<RenderNode> renderNode = AceType::Claim<RenderNode>(this);
799 auto targetDropNode = AceType::DynamicCast<DragDropEvent>(renderNode);
800 if (targetDropNode && targetDropNode->GetOnDrop()) {
801 return renderNode;
802 }
803 }
804 }
805
806 return nullptr;
807 }
808
MouseTest(const Point & globalPoint,const Point & parentLocalPoint,MouseRawResult & result)809 void RenderNode::MouseTest(const Point& globalPoint, const Point& parentLocalPoint, MouseRawResult& result)
810 {
811 if (!InTouchRectList(parentLocalPoint, GetTouchRectList())) {
812 return;
813 }
814
815 // Calculates the local point location in this node.
816 const auto localPoint = parentLocalPoint - paintRect_.GetOffset();
817 const auto& children = GetChildren();
818 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
819 auto& child = *iter;
820 child->MouseTest(globalPoint, localPoint, result);
821 }
822
823 // Calculates the coordinate offset in this node.
824 const auto coordinatePoint = globalPoint - localPoint;
825 globalPoint_ = globalPoint;
826 OnMouseTestHit(coordinatePoint, result);
827 }
828
MouseDetect(const Point & globalPoint,const Point & parentLocalPoint,MouseHoverTestList & hoverList,WeakPtr<RenderNode> & hoverNode)829 bool RenderNode::MouseDetect(const Point& globalPoint, const Point& parentLocalPoint, MouseHoverTestList& hoverList,
830 WeakPtr<RenderNode>& hoverNode)
831 {
832 if (disableTouchEvent_ || disabled_) {
833 return false;
834 }
835
836 Point transformPoint = GetTransformPoint(parentLocalPoint);
837 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
838 return false;
839 }
840
841 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
842 const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
843 for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
844 auto& child = *iter;
845 if (!child->GetVisible() || child->disabled_ || child->disableTouchEvent_) {
846 continue;
847 }
848 child->MouseDetect(globalPoint, localPoint, hoverList, hoverNode);
849 }
850
851 auto beforeSize = hoverList.size();
852 for (auto& rect : GetTouchRectList()) {
853 if (touchable_ && rect.IsInRegion(transformPoint)) {
854 if (!hoverNode.Upgrade()) {
855 if (hoverAnimationType_ != HoverAnimationType::UNKNOWN) {
856 hoverNode = AceType::WeakClaim<RenderNode>(this);
857 LOGI("Got hoverEffect node: %{public}s", AceType::TypeName(this));
858 }
859 }
860 hoverList.emplace_back(AceType::WeakClaim<RenderNode>(this));
861 // Calculates the coordinate offset in this node.
862 globalPoint_ = globalPoint;
863 auto offset = globalPoint - localPoint;
864 coordinatePoint_ = Point(offset.GetX(), offset.GetY());
865 break;
866 }
867 }
868 auto endSize = hoverList.size();
869 return beforeSize != endSize;
870 }
871
AxisDetect(const Point & globalPoint,const Point & parentLocalPoint,WeakPtr<RenderNode> & axisNode,const AxisDirection direction)872 bool RenderNode::AxisDetect(const Point& globalPoint, const Point& parentLocalPoint, WeakPtr<RenderNode>& axisNode,
873 const AxisDirection direction)
874 {
875 if (disabled_) {
876 return false;
877 }
878
879 Point transformPoint = GetTransformPoint(parentLocalPoint);
880 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
881 return false;
882 }
883
884 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
885 const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
886 for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
887 auto& child = *iter;
888 if (!child->GetVisible() || child->disabled_) {
889 continue;
890 }
891 child->AxisDetect(globalPoint, localPoint, axisNode, direction);
892 }
893
894 for (auto& rect : GetTouchRectList()) {
895 if (touchable_ && rect.IsInRegion(transformPoint)) {
896 if (!axisNode.Upgrade()) {
897 axisNode = CheckAxisNode();
898 if (axisNode.Upgrade() && !(axisNode.Upgrade()->IsAxisScrollable(direction))) {
899 axisNode = nullptr;
900 }
901 }
902 // Calculates the coordinate offset in this node.
903 globalPoint_ = globalPoint;
904 auto offset = globalPoint - localPoint;
905 coordinatePoint_ = Point(offset.GetX(), offset.GetY());
906 break;
907 }
908 }
909 return true;
910 }
911
MouseHoverTest(const Point & parentLocalPoint)912 bool RenderNode::MouseHoverTest(const Point& parentLocalPoint)
913 {
914 if (disabled_) {
915 return false;
916 }
917
918 Point transformPoint = GetTransformPoint(parentLocalPoint);
919 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
920
921 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
922 for (const auto& child : hoverChildren_) {
923 child->MouseHoverTest(localPoint);
924 }
925 // mouse state of the node is from HOVER to NONE, the callback of hover exit is triggered.
926 if (mouseState_ == MouseState::HOVER) {
927 if (hoverAnimationType_ == HoverAnimationType::AUTO) {
928 OnMouseHoverExitTest();
929 } else {
930 MouseHoverExitTest();
931 }
932 mouseState_ = MouseState::NONE;
933 }
934 return false;
935 }
936
937 // Since the paintRect is relative to parent, use parent local point to perform touch test.
938 auto context = context_.Upgrade();
939 if (!context) {
940 return false;
941 }
942 hoverChildren_.clear();
943 context->AddToHoverList(AceType::WeakClaim(this).Upgrade());
944 const auto& children = GetChildren();
945 for (auto iter = children.begin(); iter != children.end(); ++iter) {
946 auto& child = *iter;
947 if (child->MouseHoverTest(localPoint)) {
948 hoverChildren_.emplace_back(child);
949 }
950 }
951 // mouse state of the node is from NONE to HOVER, the callback of hover enter is triggered.
952 if (mouseState_ == MouseState::NONE) {
953 if (hoverAnimationType_ == HoverAnimationType::AUTO) {
954 OnMouseHoverEnterTest();
955 } else {
956 MouseHoverEnterTest();
957 }
958 mouseState_ = MouseState::HOVER;
959 }
960 return true;
961 }
962
963 #if defined(PREVIEW)
SetAccessibilityRect(const Rect & rect)964 void RenderNode::SetAccessibilityRect(const Rect& rect)
965 {
966 Rect parentRect = rect;
967 if (!selfOffset_.IsZero()) {
968 parentRect.SetOffset(parentRect.GetOffset() + selfOffset_);
969 }
970 auto node = accessibilityNode_.Upgrade();
971 auto content = context_.Upgrade();
972 Rect currentRect = Rect(GetGlobalOffset(), GetLayoutSize());
973 Rect clampRect = currentRect.Constrain(parentRect);
974 if (node && content) {
975 if (clampRect.IsValid()) {
976 auto size = Size(clampRect.Width(), clampRect.Height()) * content->GetViewScale();
977 node->SetGlobalRect(currentRect * content->GetViewScale());
978 if (size.Width() > node->GetWidth() || size.Height() > node->GetHeight()) {
979 // Same AccessibilityNode update the largest size.
980 node->SetWidth(size.Width());
981 node->SetHeight(size.Height());
982 node->SetLeft(clampRect.Left() * content->GetViewScale());
983 node->SetTop(clampRect.Top() * content->GetViewScale());
984 } else if (NearEqual(size.Width(), node->GetWidth()) && NearEqual(size.Height(), node->GetHeight())) {
985 // Update the offset when same size.
986 node->SetLeft(clampRect.Left() * content->GetViewScale());
987 node->SetTop(clampRect.Top() * content->GetViewScale());
988 }
989 if (node->GetTag() == "tab-bar") {
990 return;
991 }
992 } else {
993 SetAccessibilityVisible(false);
994 }
995 }
996 }
997 #else
SetAccessibilityRect(const Rect & rect)998 void RenderNode::SetAccessibilityRect(const Rect& rect)
999 {
1000 auto pipelineContext = context_.Upgrade();
1001 if (!pipelineContext) {
1002 return;
1003 }
1004 if (!pipelineContext->IsAccessibilityEnabled()) {
1005 return;
1006 }
1007 Rect parentRect = rect;
1008 if (!selfOffset_.IsZero()) {
1009 parentRect.SetOffset(parentRect.GetOffset() + selfOffset_);
1010 }
1011 auto node = accessibilityNode_.Upgrade();
1012 auto content = context_.Upgrade();
1013 Rect currentRect = Rect(GetGlobalOffset(), GetLayoutSize());
1014 Rect clampRect = currentRect.Constrain(parentRect);
1015 if (node && content) {
1016 node->SetGlobalRect(currentRect * content->GetViewScale());
1017 if (clampRect.IsValid()) {
1018 node->SetRect(clampRect * content->GetViewScale());
1019 } else {
1020 SetAccessibilityVisible(false);
1021 }
1022 }
1023 if (clampRect.IsValid()) {
1024 for (auto& child : children_) {
1025 // Fix case: child size is empty but access node is not empty.
1026 auto childAccessNode = child->GetAccessibilityNode().Upgrade();
1027 if (childAccessNode) {
1028 auto childAccessGlobalRect = childAccessNode->GetGlobalRect();
1029 if (childAccessGlobalRect.IsValid() && !child->GetPaintRect().IsValid()) {
1030 continue;
1031 }
1032 }
1033 child->SetAccessibilityRect(clampRect);
1034 }
1035 }
1036 }
1037 #endif
1038
RotationMatchTest(const RefPtr<RenderNode> & requestRenderNode)1039 bool RenderNode::RotationMatchTest(const RefPtr<RenderNode>& requestRenderNode)
1040 {
1041 RotationNode* rotationNode = AceType::DynamicCast<RotationNode>(this);
1042 if ((rotationNode != nullptr) && requestRenderNode == this) {
1043 return true;
1044 }
1045 const auto& children = GetChildren();
1046 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1047 const auto& child = *iter;
1048 if (child && child->RotationMatchTest(requestRenderNode)) {
1049 return true;
1050 }
1051 }
1052
1053 return false;
1054 }
1055
RotationTest(const RotationEvent & event)1056 bool RenderNode::RotationTest(const RotationEvent& event)
1057 {
1058 if (disabled_) {
1059 return false;
1060 }
1061
1062 const auto& children = GetChildren();
1063 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1064 const auto& child = *iter;
1065 if (child && child->RotationTest(event)) {
1066 return true;
1067 }
1068 }
1069
1070 RotationNode* rotationNode = AceType::DynamicCast<RotationNode>(this);
1071 if ((rotationNode != nullptr) && rotationNode->OnRotation(event)) {
1072 return true;
1073 }
1074
1075 return false;
1076 }
1077
RotationTestForward(const RotationEvent & event)1078 bool RenderNode::RotationTestForward(const RotationEvent& event)
1079 {
1080 RotationNode* rotationNode = AceType::DynamicCast<RotationNode>(this);
1081 if ((rotationNode != nullptr) && rotationNode->OnRotation(event)) {
1082 return true;
1083 }
1084 const auto& children = GetChildren();
1085 for (auto iter = children.begin(); iter != children.end(); ++iter) {
1086 const auto& child = *iter;
1087 if (child && child->RotationTestForward(event)) {
1088 return true;
1089 }
1090 }
1091
1092 return false;
1093 }
1094
GetBaselineDistance(TextBaseline textBaseline)1095 double RenderNode::GetBaselineDistance(TextBaseline textBaseline)
1096 {
1097 if (GetChildren().empty()) {
1098 return GetLayoutSize().Height();
1099 }
1100 return GetHighestChildBaseline(textBaseline);
1101 }
1102
GetContentSize()1103 Size RenderNode::GetContentSize()
1104 {
1105 if (GetChildren().empty()) {
1106 return Size();
1107 }
1108 return GetLargestChildContentSize();
1109 }
1110
ScrollPageByChild(Offset & delta,int32_t source)1111 bool RenderNode::ScrollPageByChild(Offset& delta, int32_t source)
1112 {
1113 RefPtr<RenderNode> parent = GetParent().Upgrade();
1114 if (parent) {
1115 return parent->ScrollPageByChild(delta, source);
1116 }
1117 return true;
1118 }
1119
GetHighestChildBaseline(TextBaseline baseline)1120 double RenderNode::GetHighestChildBaseline(TextBaseline baseline)
1121 {
1122 double distance = 0.0;
1123 for (const auto& child : children_) {
1124 double childBaseline = child->GetBaselineDistance(baseline);
1125 childBaseline += child->GetPosition().GetY();
1126 distance = NearZero(distance) ? childBaseline : std::min(distance, childBaseline);
1127 }
1128 return distance;
1129 }
1130
GetLargestChildContentSize()1131 Size RenderNode::GetLargestChildContentSize()
1132 {
1133 Size maxSize;
1134 for (const auto& child : children_) {
1135 Size childSize = child->GetContentSize();
1136 if (!childSize.IsValid()) {
1137 continue;
1138 }
1139 maxSize.SetWidth(maxSize.Width() > childSize.Width() ? maxSize.Width() : childSize.Width());
1140 maxSize.SetHeight(maxSize.Height() > childSize.Height() ? maxSize.Height() : childSize.Height());
1141 }
1142 return maxSize;
1143 }
1144
GetFirstChildBaseline(TextBaseline baseline)1145 double RenderNode::GetFirstChildBaseline(TextBaseline baseline)
1146 {
1147 double distance = GetLayoutSize().Height();
1148 if (!GetChildren().empty()) {
1149 auto firstChild = GetChildren().front();
1150 distance = firstChild->GetBaselineDistance(baseline);
1151 distance += firstChild->GetPosition().GetY();
1152 }
1153 return distance;
1154 }
1155
NormalizeToPx(Dimension dimension) const1156 double RenderNode::NormalizeToPx(Dimension dimension) const
1157 {
1158 if (dimension.Unit() == DimensionUnit::PX) {
1159 return dimension.Value();
1160 }
1161 auto context = context_.Upgrade();
1162 ACE_DCHECK(context);
1163 if (!context) {
1164 return dimension.Value();
1165 }
1166 return context->NormalizeToPx(dimension);
1167 }
1168
NormalizePercentToPx(const Dimension & dimension,bool isVertical,bool referSelf) const1169 double RenderNode::NormalizePercentToPx(const Dimension& dimension, bool isVertical, bool referSelf) const
1170 {
1171 if (dimension.Unit() != DimensionUnit::PERCENT) {
1172 return NormalizeToPx(dimension);
1173 }
1174 Size referSize;
1175 if (referSelf) {
1176 referSize = GetLayoutSize();
1177 } else {
1178 auto parent = parent_.Upgrade();
1179 if (!parent) {
1180 referSize = GetLayoutParam().GetMaxSize();
1181 } else {
1182 if (positionParam_.type == PositionType::PTOFFSET) {
1183 referSize = parent->GetLayoutSize();
1184 } else {
1185 referSize = parent->GetLayoutParam().GetMaxSize();
1186 }
1187 if (referSize > viewPort_) {
1188 referSize = viewPort_;
1189 }
1190 }
1191 }
1192 auto limit = isVertical ? referSize.Height() : referSize.Width();
1193 return limit * dimension.Value();
1194 }
1195
GetOffsetFromOrigin(const Offset & offset) const1196 Offset RenderNode::GetOffsetFromOrigin(const Offset& offset) const
1197 {
1198 auto parent = parent_.Upgrade();
1199 if (!parent) {
1200 return offset;
1201 }
1202 Offset nowOffset = GetPosition();
1203 return parent->GetOffsetFromOrigin(offset + nowOffset);
1204 }
1205
GetGlobalOffset() const1206 Offset RenderNode::GetGlobalOffset() const
1207 {
1208 Offset globalOffset = GetPosition();
1209 auto renderNode = parent_.Upgrade();
1210 while (renderNode) {
1211 globalOffset += renderNode->GetPosition();
1212 auto parentWeak = renderNode->GetParent();
1213 renderNode = parentWeak.Upgrade();
1214 }
1215 auto context = context_.Upgrade();
1216 if (!context) {
1217 return globalOffset;
1218 }
1219 auto isContainerModal = context->GetWindowModal() == WindowModal::CONTAINER_MODAL &&
1220 context->GetWindowManager()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
1221 if (isContainerModal) {
1222 globalOffset = globalOffset + Offset(-(CONTAINER_BORDER_WIDTH.ConvertToPx() + CONTENT_PADDING.ConvertToPx()),
1223 -CONTAINER_TITLE_HEIGHT.ConvertToPx());
1224 }
1225 return globalOffset;
1226 }
1227
GetPaintOffset() const1228 Offset RenderNode::GetPaintOffset() const
1229 {
1230 auto renderNode = parent_.Upgrade();
1231 bool isNotHead = !IsHeadRenderNode() || (renderNode ? (renderNode->rsNode_ == rsNode_) : false);
1232 return (renderNode && isNotHead) ? GetPosition() + renderNode->GetPaintOffset() : GetPosition();
1233 }
1234
GetGlobalOffsetExternal() const1235 Offset RenderNode::GetGlobalOffsetExternal() const
1236 {
1237 auto renderNode = parent_.Upgrade();
1238 return renderNode ? GetPosition() + renderNode->GetGlobalOffsetExternal() : GetPosition();
1239 }
1240
GetHeadRenderNode()1241 RefPtr<RenderNode> RenderNode::GetHeadRenderNode()
1242 {
1243 if (IsHeadRenderNode()) {
1244 return AceType::Claim(this);
1245 }
1246 auto renderNode = parent_.Upgrade();
1247 if (!renderNode) {
1248 return nullptr;
1249 }
1250 return renderNode->GetHeadRenderNode();
1251 }
1252
IsVisible(const Rect & rect,bool totally) const1253 bool RenderNode::IsVisible(const Rect& rect, bool totally) const
1254 {
1255 Rect intersectRect = Rect(Offset(), GetLayoutSize());
1256 bool visible = totally ? rect.IsWrappedBy(intersectRect) : rect.IsIntersectWith(intersectRect);
1257 if (!visible) {
1258 return false;
1259 }
1260 auto parent = parent_.Upgrade();
1261 if (!parent) {
1262 return true;
1263 }
1264 return parent->IsVisible(rect + GetPosition());
1265 }
1266
GetLastChild() const1267 RefPtr<RenderNode> RenderNode::GetLastChild() const
1268 {
1269 if (children_.empty()) {
1270 return nullptr;
1271 }
1272 return children_.back();
1273 }
1274
GetFirstChild() const1275 RefPtr<RenderNode> RenderNode::GetFirstChild() const
1276 {
1277 if (children_.empty()) {
1278 return nullptr;
1279 }
1280 return children_.front();
1281 }
1282
UpdateAccessibilityPosition()1283 void RenderNode::UpdateAccessibilityPosition()
1284 {
1285 const auto& context = context_.Upgrade();
1286 if (!context) {
1287 return;
1288 }
1289 auto viewScale = context->GetViewScale();
1290 if (NearZero(viewScale)) {
1291 return;
1292 }
1293
1294 auto accessibilityNode = GetAccessibilityNode().Upgrade();
1295 if (!accessibilityNode) {
1296 return;
1297 }
1298
1299 Size size = GetLayoutSize();
1300 Offset globalOffset = GetGlobalOffsetExternal();
1301 PositionInfo positionInfo = { (size.Width()) * viewScale, (size.Height()) * viewScale,
1302 (globalOffset.GetX()) * viewScale, (globalOffset.GetY()) * viewScale };
1303 accessibilityNode->SetPositionInfo(positionInfo);
1304 }
1305
UpdateAccessibilityEnable(bool isEnabled)1306 void RenderNode::UpdateAccessibilityEnable(bool isEnabled)
1307 {
1308 auto accessibilityNode = accessibilityNode_.Upgrade();
1309 if (accessibilityNode) {
1310 accessibilityNode->SetEnabledState(isEnabled);
1311 }
1312 }
1313
UpdateAll(const RefPtr<Component> & component)1314 void RenderNode::UpdateAll(const RefPtr<Component>& component)
1315 {
1316 if (!component) {
1317 LOGE("fail to update all due to component is null");
1318 return;
1319 }
1320 hitTestMode_ = component->GetHitTestMode();
1321 touchable_ = component->IsTouchable();
1322 disabled_ = component->IsDisabledStatus();
1323 UpdateAccessibilityEnable(!disabled_);
1324 isFirstNode_ = component->IsFirstNode();
1325 auto renderComponent = AceType::DynamicCast<RenderComponent>(component);
1326 CHECK_NULL_VOID(renderComponent);
1327 positionParam_ = renderComponent->GetPositionParam();
1328 motionPathOption_ = renderComponent->GetMotionPathOption();
1329 #ifdef ENABLE_ROSEN_BACKEND
1330 if (SystemProperties::GetRosenBackendEnabled() && motionPathOption_.IsValid()) {
1331 if (auto rsNode = GetRSNode()) {
1332 auto nativeMotionOption =
1333 std::make_shared<Rosen::RSMotionPathOption>(NativeCurveHelper::ToNativeMotionPathOption(
1334 motionPathOption_, positionParam_.type == PositionType::PTOFFSET));
1335 rsNode->SetMotionPathOption(nativeMotionOption);
1336 }
1337 }
1338 #endif
1339
1340 if (!NearEqual(flexWeight_, renderComponent->GetFlexWeight())) {
1341 auto parentFlex = GetParent().Upgrade();
1342 if (parentFlex) {
1343 parentFlex->MarkNeedLayout();
1344 }
1345 }
1346 flexWeight_ = renderComponent->GetFlexWeight();
1347 displayIndex_ = renderComponent->GetDisplayIndex();
1348 displayIndexSetted_ = renderComponent->GetDisplayIndexSetted();
1349 isIgnored_ = renderComponent->IsIgnored();
1350 interceptTouchEvent_ = renderComponent->InterceptEvent();
1351 if (renderComponent->IsCustomComponent()) {
1352 onLayoutReady_ =
1353 AceAsyncEvent<void(const std::string&)>::Create(renderComponent->GetOnLayoutReadyMarker(), context_);
1354 }
1355 auto context = context_.Upgrade();
1356 if (context != nullptr) {
1357 minPlatformVersion_ = context->GetMinPlatformVersion();
1358 }
1359 SetZIndex(renderComponent->GetZIndex());
1360 isPercentSize_ = renderComponent->GetIsPercentSize();
1361 responseRegion_ = renderComponent->GetResponseRegion();
1362 isResponseRegion_ = renderComponent->IsResponseRegion();
1363 if (component->HasEventExtensions()) {
1364 eventExtensions_ = component->GetEventExtensions();
1365 }
1366 UpdatePropAnimation(component->GetAnimatables());
1367 Update(component);
1368 MarkNeedLayout();
1369 }
1370
UpdateOpacity(uint8_t opacity)1371 void RenderNode::UpdateOpacity(uint8_t opacity)
1372 {
1373 if (!SupportOpacity()) {
1374 return;
1375 }
1376 if (opacity_ != opacity) {
1377 opacity_ = opacity;
1378 if (auto rsNode = GetRSNode()) {
1379 #ifdef ENABLE_ROSEN_BACKEND
1380 rsNode->SetAlpha(opacity_ / 255.0);
1381 #endif
1382 } else {
1383 MarkNeedRender();
1384 }
1385 }
1386 }
1387
GetOpacityCallback(int32_t domId)1388 RenderNode::OpacityCallback RenderNode::GetOpacityCallback(int32_t domId)
1389 {
1390 if (domId != GetNodeId()) {
1391 return nullptr;
1392 }
1393 if (!SupportOpacity()) {
1394 return nullptr;
1395 }
1396 return [weak = AceType::WeakClaim(this)](uint8_t opacity) {
1397 auto render = weak.Upgrade();
1398 if (render) {
1399 render->UpdateOpacity(opacity);
1400 }
1401 };
1402 }
1403
GetDomOpacityCallbacks(int32_t domId,std::list<OpacityCallback> & result)1404 void RenderNode::GetDomOpacityCallbacks(int32_t domId, std::list<OpacityCallback>& result)
1405 {
1406 if (domId != GetNodeId()) {
1407 return;
1408 }
1409 auto callback = GetOpacityCallback(domId);
1410 if (callback) {
1411 result.emplace_back(callback);
1412 }
1413 for (auto& child : children_) {
1414 child->GetDomOpacityCallbacks(domId, result);
1415 }
1416 }
1417
GetNodeId() const1418 int32_t RenderNode::GetNodeId() const
1419 {
1420 return GetAccessibilityNodeId();
1421 }
1422
GetOpacity() const1423 uint8_t RenderNode::GetOpacity() const
1424 {
1425 return opacity_;
1426 }
1427
SupportOpacity()1428 bool RenderNode::SupportOpacity()
1429 {
1430 return false;
1431 }
1432
GetOffsetToPage() const1433 Offset RenderNode::GetOffsetToPage() const
1434 {
1435 auto offset = GetGlobalOffset();
1436 auto context = GetContext().Upgrade();
1437 if (context) {
1438 offset = offset - context->GetPageRect().GetOffset();
1439 }
1440 return offset;
1441 }
1442
ClearRenderObject()1443 void RenderNode::ClearRenderObject()
1444 {
1445 context_ = nullptr;
1446 viewPort_ = Size();
1447 globalPoint_ = Point();
1448 touchRect_ = Rect();
1449 accessibilityNode_ = nullptr;
1450 needUpdateAccessibility_ = true;
1451 disabled_ = false;
1452 positionParam_ = PositionParam();
1453 opacity_ = 255;
1454 interceptTouchEvent_ = false;
1455 mouseState_ = MouseState::NONE;
1456
1457 ClearChildren();
1458 rsNode_ = nullptr;
1459 isHeadRenderNode_ = false;
1460 isTailRenderNode_ = false;
1461 isFirstNode_ = false;
1462 accessibilityText_ = "";
1463 layoutParam_ = LayoutParam();
1464 paintRect_ = Rect();
1465 paintX_ = Dimension();
1466 paintY_ = Dimension();
1467 paintW_ = Dimension();
1468 paintH_ = Dimension();
1469 nonStrictPaintRect_ = Rect();
1470 transitionPaintRectSize_ = Size();
1471 isFirstSizeAssign_ = true;
1472 isFirstPositionAssign_ = true;
1473 disappearingNodes_.clear();
1474 parent_ = nullptr;
1475 depth_ = 0;
1476 needRender_ = false;
1477 needLayout_ = false;
1478 visible_ = true;
1479 hidden_ = false;
1480 takeBoundary_ = false;
1481 layoutParamChanged_ = false;
1482 disableTouchEvent_ = false;
1483 needUpdateTouchRect_ = false;
1484 flexWeight_ = 0.0;
1485 displayIndex_ = 1;
1486 textDirection_ = TextDirection::LTR;
1487 onChangeCallback_ = nullptr;
1488 isPaintGeometryTransition_ = false;
1489 displayIndexSetted_ = false;
1490 }
1491
GetGlobalWindowBlurRRect(std::vector<RRect> & coords) const1492 RRect RenderNode::GetGlobalWindowBlurRRect(std::vector<RRect>& coords) const
1493 {
1494 RRect windowBlurRRect = GetWindowBlurRRect();
1495 Rect innerRect = windowBlurRRect.GetRect();
1496 if (!innerRect.IsValid()) {
1497 return RRect {};
1498 } else {
1499 innerRect += GetPosition();
1500 windowBlurRRect += GetPosition();
1501 coords.push_back(windowBlurRRect);
1502 auto parent = GetParent().Upgrade();
1503 while (parent) {
1504 auto parentBlurRRect = parent->GetWindowBlurRRect();
1505 const Corner& corner = parentBlurRRect.GetCorner();
1506 // intersect with parent or set border radius should clip by java
1507 if (!innerRect.IsWrappedBy(parentBlurRRect.GetRect()) ||
1508 (corner.topLeftRadius.GetX().IsValid() && corner.topLeftRadius.GetY().IsValid())) {
1509 coords.push_back(parentBlurRRect);
1510 }
1511 innerRect = innerRect.Constrain(parentBlurRRect.GetRect());
1512 auto offset = parent->GetPosition();
1513 innerRect += offset;
1514 // out of view port
1515 if (!innerRect.IsValid()) {
1516 coords.clear();
1517 return RRect {};
1518 }
1519 for (auto& coord : coords) {
1520 coord += offset;
1521 }
1522 parent = parent->GetParent().Upgrade();
1523 }
1524 return RRect::MakeRRect(innerRect, windowBlurRRect.GetCorner().topLeftRadius);
1525 }
1526 }
1527
GetRectWithShadow() const1528 Rect RenderNode::GetRectWithShadow() const
1529 {
1530 Rect paintRect(paintRect_);
1531 if (InLayoutTransition()) {
1532 paintRect = nonStrictPaintRect_;
1533 }
1534 if (!hasShadow_ || !shadow_.IsValid()) {
1535 return Rect(Offset::Zero(), paintRect.GetSize());
1536 }
1537 auto blurRadius = shadow_.GetBlurRadius();
1538 auto elevation = shadow_.GetElevation();
1539 if (elevation > 0.0f && elevation < shadow_.GetLightHeight()) {
1540 // Conversion between blurRadius and elevation.
1541 blurRadius = elevation / (shadow_.GetLightHeight() - elevation) * shadow_.GetLightRadius();
1542 }
1543 auto radius = 2.0 * blurRadius + shadow_.GetSpreadRadius();
1544
1545 Rect shadowRect = paintRect + (shadow_.GetOffset() - Offset(radius, radius));
1546 shadowRect += Size(2.0 * radius, 2.0 * radius);
1547 shadowRect = shadowRect.CombineRect(paintRect);
1548
1549 Offset paintOffset = paintRect.GetOffset();
1550 Offset shadowOffset = shadowRect.GetOffset();
1551 Offset offset = Offset(std::min(0.0, shadowOffset.GetX() - paintOffset.GetX()),
1552 std::min(0.0, shadowOffset.GetY() - paintOffset.GetY()));
1553 return Rect(offset, shadowRect.GetSize());
1554 }
1555
UpdateWindowBlurRRect(bool clear)1556 void RenderNode::UpdateWindowBlurRRect(bool clear)
1557 {
1558 auto pipelineContext = context_.Upgrade();
1559 if (!pipelineContext) {
1560 LOGE("pipelineContext is null");
1561 return;
1562 }
1563 if (clear) {
1564 pipelineContext->ClearWindowBlurRegion(GetNodeId());
1565 } else {
1566 std::vector<RRect> coords;
1567 auto blurRect = GetGlobalWindowBlurRRect(coords);
1568 pipelineContext->UpdateWindowBlurRegion(
1569 GetNodeId(), blurRect, GetWindowBlurProgress(), GetWindowBlurStyle(), coords);
1570 }
1571 }
1572
WindowBlurTest()1573 void RenderNode::WindowBlurTest()
1574 {
1575 if (GetHidden() || !GetVisible()) {
1576 return;
1577 }
1578
1579 if (NeedWindowBlur()) {
1580 UpdateWindowBlurRRect();
1581 }
1582 const auto& children = GetChildren();
1583 for (const auto& child : children) {
1584 child->WindowBlurTest();
1585 }
1586 }
1587
HasEffectiveTransform() const1588 bool RenderNode::HasEffectiveTransform() const
1589 {
1590 return false;
1591 }
1592
IsDisappearing()1593 bool RenderNode::IsDisappearing()
1594 {
1595 auto parentNode = parent_.Upgrade();
1596 if (!parentNode) {
1597 return false;
1598 }
1599 const auto& disappearingList = parentNode->disappearingNodes_;
1600 auto iter = std::find(disappearingList.begin(), disappearingList.end(), AceType::Claim(this));
1601 if (iter != disappearingList.end()) {
1602 return true;
1603 } else {
1604 return false;
1605 }
1606 }
HasDisappearingTransition(int32_t nodeId)1607 bool RenderNode::HasDisappearingTransition(int32_t nodeId)
1608 {
1609 #ifdef ENABLE_ROSEN_BACKEND
1610 if (SystemProperties::GetRosenBackendEnabled()) {
1611 if (isTailRenderNode_) {
1612 return false;
1613 }
1614 for (auto& child : children_) {
1615 if (child->HasDisappearingTransition(nodeId)) {
1616 return true;
1617 }
1618 }
1619 return false;
1620 }
1621 #endif
1622 for (auto& child : children_) {
1623 if (child->GetNodeId() == nodeId) {
1624 if (child->HasDisappearingTransition(nodeId)) {
1625 return true;
1626 }
1627 }
1628 }
1629 return false;
1630 }
1631
NotifyTransition(TransitionType type,int32_t nodeId)1632 void RenderNode::NotifyTransition(TransitionType type, int32_t nodeId)
1633 {
1634 #ifdef ENABLE_ROSEN_BACKEND
1635 if (SystemProperties::GetRosenBackendEnabled()) {
1636 if (GetRSNode() == nullptr) {
1637 return;
1638 }
1639 // call OnRSTransition for all render_nodes sharing this RSNode
1640 OnRSTransition(type);
1641 if (isTailRenderNode_) {
1642 return;
1643 }
1644 for (auto& child : children_) {
1645 child->NotifyTransition(type, nodeId);
1646 }
1647 return;
1648 }
1649 #endif
1650 OnTransition(type, nodeId);
1651 for (auto& child : children_) {
1652 if (child->GetNodeId() == nodeId) {
1653 child->NotifyTransition(type, nodeId);
1654 }
1655 }
1656 }
1657
NotifySizeTransition(const AnimationOption & option,Size fromSize,Size toSize,int32_t nodeId)1658 void RenderNode::NotifySizeTransition(const AnimationOption& option, Size fromSize, Size toSize, int32_t nodeId)
1659 {
1660 paintW_.MoveTo(fromSize.Width());
1661 paintH_.MoveTo(fromSize.Height());
1662 paintW_ = AnimatableDimension(toSize.Width());
1663 paintH_ = AnimatableDimension(toSize.Height());
1664 for (auto& child : children_) {
1665 if (child->GetNodeId() == nodeId) {
1666 child->NotifySizeTransition(option, fromSize, toSize, nodeId);
1667 }
1668 }
1669 }
1670
GetDirtyRect() const1671 Rect RenderNode::GetDirtyRect() const
1672 {
1673 Rect dirty = Rect(GetGlobalOffset(), GetLayoutSize());
1674 auto context = context_.Upgrade();
1675 if (!context) {
1676 LOGE("Get dirty rect failed. context is null.");
1677 return dirty;
1678 }
1679 // check self has transform effect.
1680 if (HasEffectiveTransform()) {
1681 return context->GetRootRect();
1682 }
1683 // check parent has transform effect.
1684 auto pageRoot = context->GetLastPageRender();
1685 auto parent = GetParent().Upgrade();
1686 while (parent && parent != pageRoot) {
1687 if (parent->HasEffectiveTransform()) {
1688 return context->GetRootRect();
1689 }
1690 parent = parent->GetParent().Upgrade();
1691 }
1692 // No transform takes effect, return layoutSize.
1693 return dirty;
1694 }
1695
IsPointInBox(const TouchEvent & point)1696 bool RenderNode::IsPointInBox(const TouchEvent& point)
1697 {
1698 double offsetX = GetGlobalOffset().GetX();
1699 double offsetY = GetGlobalOffset().GetY();
1700 double maxX = GetPaintRect().Width() + offsetX;
1701 double maxY = GetPaintRect().Height() + offsetY;
1702 if (InRegion(offsetX, maxX, point.x) && InRegion(offsetY, maxY, point.y)) {
1703 return true;
1704 }
1705 return false;
1706 }
1707
GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr,Offset & offset) const1708 bool RenderNode::GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr, Offset& offset) const
1709 {
1710 offset = offset - GetPosition();
1711 auto renderNode = parent_.Upgrade();
1712 return renderNode ? renderNode->GetAlignDeclarationOffset(alignDeclarationPtr, offset) : false;
1713 }
1714
SaveExplicitAnimationOption(const AnimationOption & option)1715 void RenderNode::SaveExplicitAnimationOption(const AnimationOption& option)
1716 {
1717 nonStrictOption_ = option;
1718 }
1719
GetExplicitAnimationOption() const1720 const AnimationOption& RenderNode::GetExplicitAnimationOption() const
1721 {
1722 return nonStrictOption_;
1723 }
1724
ClearExplicitAnimationOption()1725 void RenderNode::ClearExplicitAnimationOption()
1726 {
1727 nonStrictOption_ = AnimationOption();
1728 }
1729
ClearDisappearingNode(RefPtr<RenderNode> child)1730 void RenderNode::ClearDisappearingNode(RefPtr<RenderNode> child)
1731 {
1732 disappearingNodes_.remove(child);
1733 }
1734
CreateLayoutTransition()1735 void RenderNode::CreateLayoutTransition()
1736 {
1737 auto context = context_.Upgrade();
1738 if (!context) {
1739 return;
1740 }
1741 if (nonStrictOption_.IsValid()) {
1742 auto option = context->GetExplicitAnimationOption();
1743 context->SaveExplicitAnimationOption(nonStrictOption_);
1744 CreatePathAnimation();
1745 paintX_ = AnimatableDimension(paintRect_.GetOffset().GetX());
1746 paintY_ = AnimatableDimension(paintRect_.GetOffset().GetY());
1747 paintW_ = AnimatableDimension(paintRect_.GetSize().Width());
1748 paintH_ = AnimatableDimension(paintRect_.GetSize().Height());
1749 context->SaveExplicitAnimationOption(option);
1750 nonStrictOption_ = AnimationOption();
1751 } else {
1752 if (paintX_.GetAnimationStatus() != AnimatorStatus::RUNNING) {
1753 paintX_.MoveTo(paintRect_.GetOffset().GetX());
1754 }
1755 if (paintY_.GetAnimationStatus() != AnimatorStatus::RUNNING) {
1756 paintY_.MoveTo(paintRect_.GetOffset().GetY());
1757 }
1758 if (paintW_.GetAnimationStatus() != AnimatorStatus::RUNNING) {
1759 paintW_.MoveTo(paintRect_.GetSize().Width());
1760 }
1761 if (paintH_.GetAnimationStatus() != AnimatorStatus::RUNNING) {
1762 paintH_.MoveTo(paintRect_.GetSize().Height());
1763 }
1764 }
1765
1766 nonStrictPaintRect_.SetOffset(Offset(paintX_.Value(), paintY_.Value()));
1767 nonStrictPaintRect_.SetSize(Size(paintW_.Value(), paintH_.Value()));
1768 }
1769
CreatePathAnimation()1770 void RenderNode::CreatePathAnimation()
1771 {
1772 if (!motionPathOption_.IsValid()) {
1773 paintX_.SetEvaluator(nullptr);
1774 paintY_.SetEvaluator(nullptr);
1775 return;
1776 }
1777 if (paintX_.Value() == paintRect_.GetOffset().GetX() && paintY_.Value() == paintRect_.GetOffset().GetY()) {
1778 LOGE("CreatePathAnimation failed, target equal source");
1779 return;
1780 }
1781
1782 auto evaluator = AceType::MakeRefPtr<MotionPathEvaluator>(
1783 motionPathOption_, Offset(paintX_.Value(), paintY_.Value()), paintRect_.GetOffset(), positionParam_.type);
1784 paintX_.SetEvaluator(evaluator->CreateXEvaluator());
1785 paintY_.SetEvaluator(evaluator->CreateYEvaluator());
1786 // find transform to create rotate Animation
1787 if (motionPathOption_.GetRotate()) {
1788 auto child = GetFirstChild();
1789 while (child) {
1790 auto transform = AceType::DynamicCast<RenderTransform>(child);
1791 if (transform) {
1792 transform->SetMotionPathEvaluator(evaluator);
1793 break;
1794 }
1795 child = child->GetFirstChild();
1796 }
1797 }
1798 }
1799
CreateGeometryTransitionFrom(const RefPtr<RenderNode> & targetNode,AnimationOption & sharedOption)1800 void RenderNode::CreateGeometryTransitionFrom(const RefPtr<RenderNode>& targetNode, AnimationOption& sharedOption)
1801 {
1802 auto context = context_.Upgrade();
1803 if (!context) {
1804 return;
1805 }
1806 auto weak = AceType::WeakClaim(this);
1807 auto render = weak.Upgrade();
1808 if (!render) {
1809 return;
1810 }
1811 const Rect targetPaintRect_ = targetNode->GetPaintRect();
1812 const Offset targetOffset = targetNode->GetTransitionGlobalOffset();
1813 const Offset currentOffset = render->GetGlobalOffset();
1814 if (sharedOption.IsValid()) {
1815 auto option = context->GetExplicitAnimationOption();
1816 context->SaveExplicitAnimationOption(sharedOption);
1817 Size toSize = paintRect_.GetSize();
1818 Size fromSize = targetPaintRect_.GetSize();
1819 isPaintGeometryTransition_ = true;
1820 for (auto& child : children_) {
1821 child->SetIsPaintGeometryTransition(isPaintGeometryTransition_);
1822 }
1823 paintX_.MoveTo(targetOffset.GetX());
1824 paintY_.MoveTo(targetOffset.GetY());
1825 paintX_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1826 auto render = weak.Upgrade();
1827 if (!render) {
1828 return;
1829 }
1830 auto children = render->GetChildren();
1831 render->isPaintGeometryTransition_ = false;
1832 for (auto& child : children) {
1833 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1834 }
1835 auto parent = render->GetParent().Upgrade();
1836 if (!parent) {
1837 return;
1838 }
1839 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1840 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1841 });
1842 paintY_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1843 auto render = weak.Upgrade();
1844 if (!render) {
1845 return;
1846 }
1847 auto children = render->GetChildren();
1848 render->isPaintGeometryTransition_ = false;
1849 for (auto& child : children) {
1850 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1851 }
1852 auto parent = render->GetParent().Upgrade();
1853 if (!parent) {
1854 return;
1855 }
1856 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1857 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1858 });
1859 paintX_ = AnimatableDimension(currentOffset.GetX());
1860 paintY_ = AnimatableDimension(currentOffset.GetY());
1861 render->NotifySizeTransition(sharedOption, fromSize, toSize, render->GetNodeId());
1862 context->SaveExplicitAnimationOption(option);
1863 }
1864 }
1865
CreateGeometryTransitionTo(const RefPtr<RenderNode> & targetNode,AnimationOption & sharedOption)1866 void RenderNode::CreateGeometryTransitionTo(const RefPtr<RenderNode>& targetNode, AnimationOption& sharedOption)
1867 {
1868 auto context = context_.Upgrade();
1869 if (!context) {
1870 return;
1871 }
1872 auto weak = AceType::WeakClaim(this);
1873 auto render = weak.Upgrade();
1874 if (!render) {
1875 return;
1876 }
1877 const Rect targetPaintRect_ = targetNode->GetPaintRect();
1878 const Offset targetOffset = targetNode->GetGlobalOffset();
1879 const Offset currentOffset = render->GetTransitionGlobalOffset();
1880 if (sharedOption.IsValid()) {
1881 auto option = context->GetExplicitAnimationOption();
1882 context->SaveExplicitAnimationOption(sharedOption);
1883 Size fromSize = paintRect_.GetSize();
1884 Size toSize = targetPaintRect_.GetSize();
1885 isPaintGeometryTransition_ = true;
1886 for (auto& child : children_) {
1887 child->SetIsPaintGeometryTransition(isPaintGeometryTransition_);
1888 }
1889 paintX_.MoveTo(currentOffset.GetX());
1890 paintY_.MoveTo(currentOffset.GetY());
1891 paintX_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1892 auto render = weak.Upgrade();
1893 if (!render) {
1894 return;
1895 }
1896 auto children = render->GetChildren();
1897 render->isPaintGeometryTransition_ = false;
1898 for (auto& child : children) {
1899 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1900 }
1901 auto parent = render->GetParent().Upgrade();
1902 if (!parent) {
1903 return;
1904 }
1905 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1906 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1907 });
1908 paintY_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1909 auto render = weak.Upgrade();
1910 if (!render) {
1911 return;
1912 }
1913 auto children = render->GetChildren();
1914 render->isPaintGeometryTransition_ = false;
1915 for (auto& child : children) {
1916 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1917 }
1918 auto parent = render->GetParent().Upgrade();
1919 if (!parent) {
1920 return;
1921 }
1922 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1923 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1924 });
1925 paintX_ = AnimatableDimension(targetOffset.GetX());
1926 paintY_ = AnimatableDimension(targetOffset.GetY());
1927 render->NotifySizeTransition(sharedOption, fromSize, toSize, render->GetNodeId());
1928 context->SaveExplicitAnimationOption(option);
1929 }
1930 }
1931
GetPaintRect() const1932 const Rect& RenderNode::GetPaintRect() const
1933 {
1934 if (InLayoutTransition()) {
1935 return nonStrictPaintRect_;
1936 } else {
1937 return paintRect_;
1938 }
1939 }
1940
GetTransitionGlobalOffset() const1941 Offset RenderNode::GetTransitionGlobalOffset() const
1942 {
1943 auto renderNode = parent_.Upgrade();
1944 return renderNode ? GetTransitionPaintRect().GetOffset() + renderNode->GetTransitionGlobalOffset()
1945 : GetTransitionPaintRect().GetOffset();
1946 }
1947
GetTransitionPaintRect() const1948 Rect RenderNode::GetTransitionPaintRect() const
1949 {
1950 if (InLayoutTransition()) {
1951 return Rect(nonStrictPaintRect_.GetOffset(), transitionPaintRectSize_);
1952 } else {
1953 return paintRect_;
1954 }
1955 }
1956
SetLayoutSize(const Size & size)1957 void RenderNode::SetLayoutSize(const Size& size)
1958 {
1959 auto context = context_.Upgrade();
1960 if (!context) {
1961 LOGE("Set layout size failed. context is null.");
1962 return;
1963 }
1964 if (paintRect_.GetSize() != size) {
1965 isFirstSizeAssign_ = false;
1966 nonStrictOption_ = context->GetExplicitAnimationOption();
1967 context->AddLayoutTransitionNode(AceType::Claim(this));
1968 // get bigger canvas size duration transition.
1969 transitionPaintRectSize_ = Rect(Offset(), paintRect_.GetSize()).CombineRect(Rect(Offset(), size)).GetSize();
1970 paintRect_.SetSize(size);
1971 needUpdateTouchRect_ = true;
1972 OnSizeChanged();
1973 MarkNeedSyncGeometryProperties();
1974 }
1975 if (isFirstSizeAssign_) {
1976 isFirstSizeAssign_ = false;
1977 nonStrictOption_ = context->GetExplicitAnimationOption();
1978 context->AddLayoutTransitionNode(AceType::Claim(this));
1979 }
1980 }
1981
InLayoutTransition() const1982 bool RenderNode::InLayoutTransition() const
1983 {
1984 return paintX_.GetAnimationStatus() == AnimatorStatus::RUNNING ||
1985 paintY_.GetAnimationStatus() == AnimatorStatus::RUNNING ||
1986 paintW_.GetAnimationStatus() == AnimatorStatus::RUNNING ||
1987 paintH_.GetAnimationStatus() == AnimatorStatus::RUNNING;
1988 }
1989
MarkUpdateType(const RefPtr<Component> & component)1990 void RenderNode::MarkUpdateType(const RefPtr<Component>& component)
1991 {
1992 updateType_ = component->Compare(GetComponent());
1993 if (updateType_ & static_cast<uint32_t>(UpdateRenderType::LAYOUT)) {
1994 MarkNeedLayout();
1995 return;
1996 }
1997 if (updateType_ & static_cast<uint32_t>(UpdateRenderType::PAINT)) {
1998 MarkNeedRender();
1999 return;
2000 }
2001 }
2002
SetIsPaintGeometryTransition(bool isPaintGeometryTransition)2003 void RenderNode::SetIsPaintGeometryTransition(bool isPaintGeometryTransition)
2004 {
2005 isPaintGeometryTransition_ = isPaintGeometryTransition;
2006 }
2007
SetPaintOutOfParent(bool isPaintOutOfParent)2008 void RenderNode::SetPaintOutOfParent(bool isPaintOutOfParent)
2009 {
2010 isPaintOutOfParent_ = isPaintOutOfParent;
2011 }
2012
IsPaintOutOfParent()2013 bool RenderNode::IsPaintOutOfParent()
2014 {
2015 return isPaintGeometryTransition_ || isPaintOutOfParent_;
2016 }
2017
UpdatePosition()2018 void RenderNode::UpdatePosition()
2019 {
2020 if (isPaintGeometryTransition_) {
2021 nonStrictPaintRect_.SetLeft(paintX_.Value() - GetParent().Upgrade()->GetTransitionGlobalOffset().GetX());
2022 nonStrictPaintRect_.SetTop(paintY_.Value() - GetParent().Upgrade()->GetTransitionGlobalOffset().GetY());
2023 }
2024 }
2025
SetDepth(int32_t depth)2026 void RenderNode::SetDepth(int32_t depth)
2027 {
2028 if (depth_ != depth) {
2029 depth_ = depth;
2030 const auto& children = GetChildren();
2031 for (const auto& item : children) {
2032 item->SetDepth(depth_ + 1);
2033 }
2034 }
2035 }
2036
SyncRSNodeBoundary(bool isHead,bool isTail,const RefPtr<Component> & component)2037 void RenderNode::SyncRSNodeBoundary(bool isHead, bool isTail, const RefPtr<Component>& component)
2038 {
2039 isHeadRenderNode_ = isHead;
2040 #ifdef ENABLE_ROSEN_BACKEND
2041 isTailRenderNode_ = isTail;
2042
2043 // if "UseExternalRSNode" is true, we should find tail component and extract RSNode from it.
2044 if (ProcessExternalRSNode(component)) {
2045 return;
2046 }
2047
2048 if (isHead && !rsNode_) {
2049 // create RSNode in first node of JSview
2050 rsNode_ = CreateRSNode();
2051 } else if (!isHead && rsNode_) {
2052 // destroy unneeded RSNode
2053 rsNode_ = nullptr;
2054 }
2055 #endif
2056 }
2057
ProcessExternalRSNode(const RefPtr<Component> & component)2058 bool RenderNode::ProcessExternalRSNode(const RefPtr<Component>& component)
2059 {
2060 #ifdef ENABLE_ROSEN_BACKEND
2061 if (!isHeadRenderNode_ || component == nullptr || !component->UseExternalRSNode()) {
2062 return false;
2063 }
2064
2065 auto tailComponent = component;
2066 // recursively locate tail component.
2067 while (tailComponent != nullptr && !tailComponent->IsTailComponent()) {
2068 if (auto singleChild = AceType::DynamicCast<SingleChild>(tailComponent)) {
2069 tailComponent = singleChild->GetChild();
2070 } else {
2071 return false;
2072 }
2073 }
2074 #ifdef OHOS_PLATFORM
2075 // extract RSNode from tail component.
2076 auto rsNode = RosenRenderRemoteWindow::ExtractRSNode(tailComponent);
2077 SyncRSNode(rsNode);
2078 // avoid redundant function call.
2079 component->MarkUseExternalRSNode(false);
2080 return rsNode != nullptr;
2081 #endif
2082 #endif
2083 return false;
2084 }
2085
SyncRSNode(const std::shared_ptr<RSNode> & rsNode)2086 void RenderNode::SyncRSNode(const std::shared_ptr<RSNode>& rsNode)
2087 {
2088 #ifdef ENABLE_ROSEN_BACKEND
2089 if (rsNode_ == rsNode) {
2090 return;
2091 }
2092 rsNode_ = rsNode;
2093 if (isTailRenderNode_) {
2094 return;
2095 }
2096 for (const auto& child : GetChildren()) {
2097 child->SyncRSNode(rsNode);
2098 }
2099 #endif
2100 }
2101
MarkNeedSyncGeometryProperties()2102 void RenderNode::MarkNeedSyncGeometryProperties()
2103 {
2104 if (!HasGeometryProperties()) {
2105 return;
2106 }
2107 if (auto pipelineContext = context_.Upgrade()) {
2108 pipelineContext->AddGeometryChangedNode(AceType::Claim(this));
2109 }
2110 }
2111
SyncGeometryProperties()2112 void RenderNode::SyncGeometryProperties()
2113 {
2114 #ifdef ENABLE_ROSEN_BACKEND
2115 if (!IsTailRenderNode()) {
2116 return;
2117 }
2118 auto rsNode = GetRSNode();
2119 if (!rsNode) {
2120 return;
2121 }
2122 Offset paintOffset = GetPaintOffset();
2123 Size paintSize = GetLayoutSize();
2124 rsNode->SetFrame(paintOffset.GetX(), paintOffset.GetY(), paintSize.Width(), paintSize.Height());
2125 #endif
2126 }
2127
SetPaintRect(const Rect & rect)2128 void RenderNode::SetPaintRect(const Rect& rect)
2129 {
2130 if (paintRect_ == rect) {
2131 return;
2132 }
2133 paintRect_ = rect;
2134 needUpdateTouchRect_ = true;
2135
2136 MarkNeedSyncGeometryProperties();
2137 }
2138
RSNodeAddChild(const RefPtr<RenderNode> & child)2139 void RenderNode::RSNodeAddChild(const RefPtr<RenderNode>& child)
2140 {
2141 #ifdef ENABLE_ROSEN_BACKEND
2142 if (!rsNode_) {
2143 // workaround if parent have no RSNode while it should
2144 SyncRSNodeBoundary(true, true);
2145 }
2146 if (IsTailRenderNode()) {
2147 if (!child->GetRSNode()) {
2148 // workaround if child have no RSNode while it should
2149 child->SyncRSNodeBoundary(true, true);
2150 }
2151 } else {
2152 if (child->rsNode_ && rsNode_ != child->rsNode_) {
2153 LOGE("Overwriting existing RSNode in child, this SHOULD NOT HAPPEN.");
2154 }
2155 // copy parent RSNode to child if they belong to the same JSView
2156 child->rsNode_ = rsNode_;
2157 }
2158 #endif
2159 }
2160
MarkParentNeedRender() const2161 void RenderNode::MarkParentNeedRender() const
2162 {
2163 auto renderNode = parent_.Upgrade();
2164 if (!renderNode) {
2165 return;
2166 }
2167 if (IsHeadRenderNode()) {
2168 renderNode->MarkNeedRender();
2169 } else {
2170 renderNode->MarkParentNeedRender();
2171 }
2172 }
2173
CreateRSNode() const2174 std::shared_ptr<RSNode> RenderNode::CreateRSNode() const
2175 {
2176 #ifdef ENABLE_ROSEN_BACKEND
2177 if (!SystemProperties::GetMultiInstanceEnabled()) {
2178 return Rosen::RSCanvasNode::Create();
2179 }
2180 return RsNodeAdapter::CreateCanvasNode();
2181 #else
2182 return nullptr;
2183 #endif
2184 }
2185
OnStatusStyleChanged(VisualState state)2186 void RenderNode::OnStatusStyleChanged(VisualState state)
2187 {
2188 if (isHeadRenderNode_) {
2189 return;
2190 }
2191 RefPtr<RenderNode> parent = parent_.Upgrade();
2192 if (parent) {
2193 parent->OnStatusStyleChanged(state);
2194 }
2195 }
2196
ComputeSelectedZone(const Offset & startOffset,const Offset & endOffset)2197 Rect RenderNode::ComputeSelectedZone(const Offset& startOffset, const Offset& endOffset)
2198 {
2199 Rect selectedZone;
2200 if (startOffset.GetX() <= endOffset.GetX()) {
2201 if (startOffset.GetY() <= endOffset.GetY()) {
2202 // bottom right
2203 selectedZone = Rect(startOffset.GetX(), startOffset.GetY(), endOffset.GetX() - startOffset.GetX(),
2204 endOffset.GetY() - startOffset.GetY());
2205 return selectedZone;
2206 } else {
2207 // top right
2208 selectedZone = Rect(startOffset.GetX(), endOffset.GetY(), endOffset.GetX() - startOffset.GetX(),
2209 startOffset.GetY() - endOffset.GetY());
2210 return selectedZone;
2211 }
2212 } else {
2213 if (startOffset.GetY() <= endOffset.GetY()) {
2214 // bottom left
2215 selectedZone = Rect(endOffset.GetX(), startOffset.GetY(), startOffset.GetX() - endOffset.GetX(),
2216 endOffset.GetY() - startOffset.GetY());
2217 return selectedZone;
2218 } else {
2219 // top left
2220 selectedZone = Rect(endOffset.GetX(), endOffset.GetY(), startOffset.GetX() - endOffset.GetX(),
2221 startOffset.GetY() - endOffset.GetY());
2222 return selectedZone;
2223 }
2224 }
2225 }
2226
SendAccessibilityEvent(const std::string & eventType)2227 void RenderNode::SendAccessibilityEvent(const std::string& eventType)
2228 {
2229 auto accessibilityNode = GetAccessibilityNode().Upgrade();
2230 if (!accessibilityNode) {
2231 return;
2232 }
2233 auto context = context_.Upgrade();
2234 if (context) {
2235 AccessibilityEvent event;
2236 event.nodeId = accessibilityNode->GetNodeId();
2237 event.eventType = eventType;
2238 context->SendEventToAccessibility(event);
2239 }
2240 }
2241
SetAccessibilityClick(RefPtr<ClickRecognizer> clickRecognizer)2242 void RenderNode::SetAccessibilityClick(RefPtr<ClickRecognizer> clickRecognizer)
2243 {
2244 auto accessibilityNode = accessibilityNode_.Upgrade();
2245 if (!accessibilityNode) {
2246 return;
2247 }
2248 if (clickRecognizer) {
2249 accessibilityNode->SetClickableState(true);
2250 auto weakPtr = AceType::WeakClaim(AceType::RawPtr(clickRecognizer));
2251 accessibilityNode->SetActionClickImpl([weakPtr]() {
2252 auto click = weakPtr.Upgrade();
2253 if (click) {
2254 click->OnAccepted();
2255 }
2256 });
2257 } else {
2258 accessibilityNode->SetClickableState(false);
2259 accessibilityNode->SetActionClickImpl(nullptr);
2260 }
2261 }
2262
2263 } // namespace OHOS::Ace
2264