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