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