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::__anon7a8b98930111::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, const std::vector<Rect>& childTouchRectList,
286 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
736 bool dispatchSuccess = DispatchTouchTestToChildren(localPoint, globalPoint, touchRestrict, result);
737 auto beforeSize = result.size();
738 std::vector<Rect> vrect;
739 if (IsResponseRegion()) {
740 vrect = responseRegionList_;
741 }
742 vrect.emplace_back(paintRect_);
743 for (const auto& rect : vrect) {
744 if (touchable_ && rect.IsInRegion(transformPoint)) {
745 // Calculates the coordinate offset in this node.
746 globalPoint_ = globalPoint;
747 const auto coordinateOffset = globalPoint - localPoint;
748 coordinatePoint_ = Point(coordinateOffset.GetX(), coordinateOffset.GetY());
749 OnTouchTestHit(coordinateOffset, touchRestrict, result);
750 break;
751 }
752 }
753 auto endSize = result.size();
754 return dispatchSuccess || (beforeSize != endSize && IsNotSiblingAddRecognizerToResult());
755 }
756
DispatchTouchTestToChildren(const Point & localPoint,const Point & globalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)757 bool RenderNode::DispatchTouchTestToChildren(
758 const Point& localPoint, const Point& globalPoint, const TouchRestrict& touchRestrict, TouchTestResult& result)
759 {
760 bool dispatchSuccess = false;
761 if (!IsChildrenTouchEnable() || GetHitTestMode() == HitTestMode::HTMBLOCK) {
762 return dispatchSuccess;
763 }
764
765 const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
766 for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
767 const auto& child = *iter;
768 if (!child->GetVisible() || child->disabled_ || child->disableTouchEvent_) {
769 continue;
770 }
771 if (child->TouchTest(globalPoint, localPoint, touchRestrict, result)) {
772 dispatchSuccess = true;
773 if (child->GetHitTestMode() != HitTestMode::HTMTRANSPARENT) {
774 break;
775 }
776 }
777 auto interceptTouchEvent =
778 (child->IsTouchable() && (child->InterceptTouchEvent() || IsExclusiveEventForChild()) &&
779 child->GetHitTestMode() != HitTestMode::HTMTRANSPARENT);
780 if (child->GetHitTestMode() == HitTestMode::HTMBLOCK || interceptTouchEvent) {
781 auto localTransformPoint = child->GetTransformPoint(localPoint);
782 bool isInRegion = false;
783 for (const auto& rect : child->GetTouchRectList()) {
784 if (rect.IsInRegion(localTransformPoint)) {
785 dispatchSuccess = true;
786 isInRegion = true;
787 break;
788 }
789 }
790 if (isInRegion && child->GetHitTestMode() != HitTestMode::HTMDEFAULT) {
791 break;
792 }
793 }
794 }
795 return dispatchSuccess;
796 }
797
FindDropChild(const Point & globalPoint,const Point & parentLocalPoint)798 RefPtr<RenderNode> RenderNode::FindDropChild(const Point& globalPoint, const Point& parentLocalPoint)
799 {
800 Point transformPoint = GetTransformPoint(parentLocalPoint);
801 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
802 return nullptr;
803 }
804
805 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
806 const auto& children = GetChildren();
807 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
808 auto& child = *iter;
809 if (!child->GetVisible()) {
810 continue;
811 }
812 if (child->InterceptTouchEvent()) {
813 continue;
814 }
815
816 auto target = child->FindDropChild(globalPoint, localPoint);
817 if (target) {
818 return target;
819 }
820 }
821
822 for (auto& rect : GetTouchRectList()) {
823 if (touchable_ && rect.IsInRegion(transformPoint)) {
824 RefPtr<RenderNode> renderNode = AceType::Claim<RenderNode>(this);
825 auto targetDropNode = AceType::DynamicCast<DragDropEvent>(renderNode);
826 if (targetDropNode && targetDropNode->GetOnDrop()) {
827 return renderNode;
828 }
829 }
830 }
831
832 return nullptr;
833 }
834
MouseTest(const Point & globalPoint,const Point & parentLocalPoint,MouseRawResult & result)835 void RenderNode::MouseTest(const Point& globalPoint, const Point& parentLocalPoint, MouseRawResult& result)
836 {
837 LOGD("MouseTest: type is %{public}s, the region is %{public}lf, %{public}lf, %{public}lf, %{public}lf",
838 GetTypeName(), GetTouchRect().Left(), GetTouchRect().Top(), GetTouchRect().Width(), GetTouchRect().Height());
839 LOGD("MouseTest: the local point refer to parent is %{public}lf, %{public}lf, ", parentLocalPoint.GetX(),
840 parentLocalPoint.GetY());
841
842 if (!InTouchRectList(parentLocalPoint, GetTouchRectList())) {
843 return;
844 }
845
846 // Calculates the local point location in this node.
847 const auto localPoint = parentLocalPoint - paintRect_.GetOffset();
848 const auto& children = GetChildren();
849 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
850 auto& child = *iter;
851 child->MouseTest(globalPoint, localPoint, result);
852 }
853
854 // Calculates the coordinate offset in this node.
855 const auto coordinatePoint = globalPoint - localPoint;
856 globalPoint_ = globalPoint;
857 OnMouseTestHit(coordinatePoint, result);
858 }
859
MouseDetect(const Point & globalPoint,const Point & parentLocalPoint,MouseHoverTestList & hoverList,WeakPtr<RenderNode> & hoverNode)860 bool RenderNode::MouseDetect(const Point& globalPoint, const Point& parentLocalPoint, MouseHoverTestList& hoverList,
861 WeakPtr<RenderNode>& hoverNode)
862 {
863 LOGD("MouseDetect: type is %{public}s, the region is %{public}lf, %{public}lf, %{public}lf, %{public}lf",
864 GetTypeName(), GetTouchRect().Left(), GetTouchRect().Top(), GetTouchRect().Width(), GetTouchRect().Height());
865 if (disableTouchEvent_ || disabled_) {
866 return false;
867 }
868
869 Point transformPoint = GetTransformPoint(parentLocalPoint);
870 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
871 return false;
872 }
873
874 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
875 const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
876 for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
877 auto& child = *iter;
878 if (!child->GetVisible() || child->disabled_ || child->disableTouchEvent_) {
879 continue;
880 }
881 child->MouseDetect(globalPoint, localPoint, hoverList, hoverNode);
882 }
883
884 auto beforeSize = hoverList.size();
885 for (auto& rect : GetTouchRectList()) {
886 if (touchable_ && rect.IsInRegion(transformPoint)) {
887 if (!hoverNode.Upgrade()) {
888 if (hoverAnimationType_ != HoverAnimationType::UNKNOWN) {
889 hoverNode = AceType::WeakClaim<RenderNode>(this);
890 LOGI("Got hoverEffect node: %{public}s", AceType::TypeName(this));
891 }
892 }
893 hoverList.emplace_back(AceType::WeakClaim<RenderNode>(this));
894 // Calculates the coordinate offset in this node.
895 globalPoint_ = globalPoint;
896 auto offset = globalPoint - localPoint;
897 coordinatePoint_ = Point(offset.GetX(), offset.GetY());
898 break;
899 }
900 }
901 auto endSize = hoverList.size();
902 return beforeSize != endSize;
903 }
904
AxisDetect(const Point & globalPoint,const Point & parentLocalPoint,WeakPtr<RenderNode> & axisNode,const AxisDirection direction)905 bool RenderNode::AxisDetect(const Point& globalPoint, const Point& parentLocalPoint, WeakPtr<RenderNode>& axisNode,
906 const AxisDirection direction)
907 {
908 LOGD("AxisDetect: type is %{public}s, the region is %{public}lf, %{public}lf, %{public}lf, %{public}lf",
909 GetTypeName(), GetTouchRect().Left(), GetTouchRect().Top(), GetTouchRect().Width(), GetTouchRect().Height());
910 if (disabled_) {
911 return false;
912 }
913
914 Point transformPoint = GetTransformPoint(parentLocalPoint);
915 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
916 return false;
917 }
918
919 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
920 const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
921 for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
922 auto& child = *iter;
923 if (!child->GetVisible() || child->disabled_) {
924 continue;
925 }
926 child->AxisDetect(globalPoint, localPoint, axisNode, direction);
927 }
928
929 for (auto& rect : GetTouchRectList()) {
930 if (touchable_ && rect.IsInRegion(transformPoint)) {
931 if (!axisNode.Upgrade()) {
932 axisNode = CheckAxisNode();
933 if (axisNode.Upgrade() && !(axisNode.Upgrade()->IsAxisScrollable(direction))) {
934 axisNode = nullptr;
935 }
936 }
937 // Calculates the coordinate offset in this node.
938 globalPoint_ = globalPoint;
939 auto offset = globalPoint - localPoint;
940 coordinatePoint_ = Point(offset.GetX(), offset.GetY());
941 break;
942 }
943 }
944 return true;
945 }
946
MouseHoverTest(const Point & parentLocalPoint)947 bool RenderNode::MouseHoverTest(const Point& parentLocalPoint)
948 {
949 LOGD("OnMouseHoverTest: type is %{public}s, the region is %{public}lf, %{public}lf, %{public}lf, %{public}lf",
950 GetTypeName(), GetTouchRect().Left(), GetTouchRect().Top(), GetTouchRect().Width(), GetTouchRect().Height());
951 LOGD("OnMouseHoverTest: the local point refer to parent is %{public}lf, %{public}lf, ", parentLocalPoint.GetX(),
952 parentLocalPoint.GetY());
953 if (disabled_) {
954 return false;
955 }
956
957 Point transformPoint = GetTransformPoint(parentLocalPoint);
958 const auto localPoint = transformPoint - GetPaintRect().GetOffset();
959
960 if (!InTouchRectList(transformPoint, GetTouchRectList())) {
961 for (const auto& child : hoverChildren_) {
962 child->MouseHoverTest(localPoint);
963 }
964 // mouse state of the node is from HOVER to NONE, the callback of hover exit is triggered.
965 if (mouseState_ == MouseState::HOVER) {
966 if (hoverAnimationType_ == HoverAnimationType::AUTO) {
967 OnMouseHoverExitTest();
968 } else {
969 MouseHoverExitTest();
970 }
971 mouseState_ = MouseState::NONE;
972 }
973 return false;
974 }
975
976 // Since the paintRect is relative to parent, use parent local point to perform touch test.
977 auto context = context_.Upgrade();
978 if (!context) {
979 return false;
980 }
981 hoverChildren_.clear();
982 context->AddToHoverList(AceType::WeakClaim(this).Upgrade());
983 const auto& children = GetChildren();
984 for (auto iter = children.begin(); iter != children.end(); ++iter) {
985 auto& child = *iter;
986 if (child->MouseHoverTest(localPoint)) {
987 hoverChildren_.emplace_back(child);
988 }
989 }
990 // mouse state of the node is from NONE to HOVER, the callback of hover enter is triggered.
991 if (mouseState_ == MouseState::NONE) {
992 if (hoverAnimationType_ == HoverAnimationType::AUTO) {
993 OnMouseHoverEnterTest();
994 } else {
995 MouseHoverEnterTest();
996 }
997 mouseState_ = MouseState::HOVER;
998 }
999 return true;
1000 }
1001
1002 #if defined(PREVIEW)
SetAccessibilityRect(const Rect & rect)1003 void RenderNode::SetAccessibilityRect(const Rect& rect)
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 if (clampRect.IsValid()) {
1015 auto size = Size(clampRect.Width(), clampRect.Height()) * content->GetViewScale();
1016 node->SetGlobalRect(currentRect * content->GetViewScale());
1017 if (size.Width() > node->GetWidth() || size.Height() > node->GetHeight()) {
1018 // Same AccessibilityNode update the largest size.
1019 node->SetWidth(size.Width());
1020 node->SetHeight(size.Height());
1021 node->SetLeft(clampRect.Left() * content->GetViewScale());
1022 node->SetTop(clampRect.Top() * content->GetViewScale());
1023 } else if (NearEqual(size.Width(), node->GetWidth()) && NearEqual(size.Height(), node->GetHeight())) {
1024 // Update the offset when same size.
1025 node->SetLeft(clampRect.Left() * content->GetViewScale());
1026 node->SetTop(clampRect.Top() * content->GetViewScale());
1027 }
1028 if (node->GetTag() == "tab-bar") {
1029 return;
1030 }
1031 } else {
1032 SetAccessibilityVisible(false);
1033 }
1034 }
1035 }
1036 #else
SetAccessibilityRect(const Rect & rect)1037 void RenderNode::SetAccessibilityRect(const Rect& rect)
1038 {
1039 auto pipelineContext = context_.Upgrade();
1040 if (!pipelineContext) {
1041 return;
1042 }
1043 if (!pipelineContext->IsAccessibilityEnabled()) {
1044 return;
1045 }
1046 Rect parentRect = rect;
1047 if (!selfOffset_.IsZero()) {
1048 parentRect.SetOffset(parentRect.GetOffset() + selfOffset_);
1049 }
1050 auto node = accessibilityNode_.Upgrade();
1051 auto content = context_.Upgrade();
1052 Rect currentRect = Rect(GetGlobalOffset(), GetLayoutSize());
1053 Rect clampRect = currentRect.Constrain(parentRect);
1054 if (node && content) {
1055 node->SetGlobalRect(currentRect * content->GetViewScale());
1056 if (clampRect.IsValid()) {
1057 node->SetRect(clampRect * content->GetViewScale());
1058 } else {
1059 SetAccessibilityVisible(false);
1060 }
1061 }
1062 if (clampRect.IsValid()) {
1063 for (auto& child : children_) {
1064 // Fix case: child size is empty but access node is not empty.
1065 auto childAccessNode = child->GetAccessibilityNode().Upgrade();
1066 if (childAccessNode) {
1067 auto childAccessGlobalRect = childAccessNode->GetGlobalRect();
1068 if (childAccessGlobalRect.IsValid() && !child->GetPaintRect().IsValid()) {
1069 continue;
1070 }
1071 }
1072 child->SetAccessibilityRect(clampRect);
1073 }
1074 }
1075 }
1076 #endif
1077
RotationMatchTest(const RefPtr<RenderNode> & requestRenderNode)1078 bool RenderNode::RotationMatchTest(const RefPtr<RenderNode>& requestRenderNode)
1079 {
1080 RotationNode* rotationNode = AceType::DynamicCast<RotationNode>(this);
1081 if ((rotationNode != nullptr) && requestRenderNode == this) {
1082 LOGD("RotationMatchTest: match rotation focus node %{public}s.", GetTypeName());
1083 return true;
1084 }
1085 const auto& children = GetChildren();
1086 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1087 const auto& child = *iter;
1088 if (child && child->RotationMatchTest(requestRenderNode)) {
1089 return true;
1090 }
1091 }
1092
1093 return false;
1094 }
1095
RotationTest(const RotationEvent & event)1096 bool RenderNode::RotationTest(const RotationEvent& event)
1097 {
1098 if (disabled_) {
1099 return false;
1100 }
1101
1102 const auto& children = GetChildren();
1103 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1104 const auto& child = *iter;
1105 if (child && child->RotationTest(event)) {
1106 return true;
1107 }
1108 }
1109
1110 RotationNode* rotationNode = AceType::DynamicCast<RotationNode>(this);
1111 if ((rotationNode != nullptr) && rotationNode->OnRotation(event)) {
1112 LOGD("RotationTest: type is %{public}s accept", GetTypeName());
1113 return true;
1114 }
1115
1116 return false;
1117 }
1118
RotationTestForward(const RotationEvent & event)1119 bool RenderNode::RotationTestForward(const RotationEvent& event)
1120 {
1121 RotationNode* rotationNode = AceType::DynamicCast<RotationNode>(this);
1122 if ((rotationNode != nullptr) && rotationNode->OnRotation(event)) {
1123 LOGD("RotationTestForward: type is %{public}s accept", GetTypeName());
1124 return true;
1125 }
1126 const auto& children = GetChildren();
1127 for (auto iter = children.begin(); iter != children.end(); ++iter) {
1128 const auto& child = *iter;
1129 if (child && child->RotationTestForward(event)) {
1130 return true;
1131 }
1132 }
1133
1134 return false;
1135 }
1136
GetBaselineDistance(TextBaseline textBaseline)1137 double RenderNode::GetBaselineDistance(TextBaseline textBaseline)
1138 {
1139 if (GetChildren().empty()) {
1140 return GetLayoutSize().Height();
1141 }
1142 return GetHighestChildBaseline(textBaseline);
1143 }
1144
GetContentSize()1145 Size RenderNode::GetContentSize()
1146 {
1147 if (GetChildren().empty()) {
1148 return Size();
1149 }
1150 return GetLargestChildContentSize();
1151 }
1152
ScrollPageByChild(Offset & delta,int32_t source)1153 bool RenderNode::ScrollPageByChild(Offset& delta, int32_t source)
1154 {
1155 RefPtr<RenderNode> parent = GetParent().Upgrade();
1156 if (parent) {
1157 return parent->ScrollPageByChild(delta, source);
1158 }
1159 return true;
1160 }
1161
GetHighestChildBaseline(TextBaseline baseline)1162 double RenderNode::GetHighestChildBaseline(TextBaseline baseline)
1163 {
1164 double distance = 0.0;
1165 for (const auto& child : children_) {
1166 double childBaseline = child->GetBaselineDistance(baseline);
1167 childBaseline += child->GetPosition().GetY();
1168 distance = NearZero(distance) ? childBaseline : std::min(distance, childBaseline);
1169 }
1170 return distance;
1171 }
1172
GetLargestChildContentSize()1173 Size RenderNode::GetLargestChildContentSize()
1174 {
1175 Size maxSize;
1176 for (const auto& child : children_) {
1177 Size childSize = child->GetContentSize();
1178 if (!childSize.IsValid()) {
1179 continue;
1180 }
1181 maxSize.SetWidth(maxSize.Width() > childSize.Width() ? maxSize.Width() : childSize.Width());
1182 maxSize.SetHeight(maxSize.Height() > childSize.Height() ? maxSize.Height() : childSize.Height());
1183 }
1184 return maxSize;
1185 }
1186
GetFirstChildBaseline(TextBaseline baseline)1187 double RenderNode::GetFirstChildBaseline(TextBaseline baseline)
1188 {
1189 double distance = GetLayoutSize().Height();
1190 if (!GetChildren().empty()) {
1191 auto firstChild = GetChildren().front();
1192 distance = firstChild->GetBaselineDistance(baseline);
1193 distance += firstChild->GetPosition().GetY();
1194 }
1195 return distance;
1196 }
1197
NormalizeToPx(Dimension dimension) const1198 double RenderNode::NormalizeToPx(Dimension dimension) const
1199 {
1200 if (dimension.Unit() == DimensionUnit::PX) {
1201 return dimension.Value();
1202 }
1203 auto context = context_.Upgrade();
1204 ACE_DCHECK(context);
1205 if (!context) {
1206 return dimension.Value();
1207 }
1208 return context->NormalizeToPx(dimension);
1209 }
1210
NormalizePercentToPx(const Dimension & dimension,bool isVertical,bool referSelf) const1211 double RenderNode::NormalizePercentToPx(const Dimension& dimension, bool isVertical, bool referSelf) const
1212 {
1213 if (dimension.Unit() != DimensionUnit::PERCENT) {
1214 return NormalizeToPx(dimension);
1215 }
1216 Size referSize;
1217 if (referSelf) {
1218 referSize = GetLayoutSize();
1219 } else {
1220 auto parent = parent_.Upgrade();
1221 if (!parent) {
1222 referSize = GetLayoutParam().GetMaxSize();
1223 } else {
1224 if (positionParam_.type == PositionType::PTOFFSET) {
1225 referSize = parent->GetLayoutSize();
1226 } else {
1227 referSize = parent->GetLayoutParam().GetMaxSize();
1228 }
1229 if (referSize > viewPort_) {
1230 referSize = viewPort_;
1231 }
1232 }
1233 }
1234 auto limit = isVertical ? referSize.Height() : referSize.Width();
1235 return limit * dimension.Value();
1236 }
1237
GetOffsetFromOrigin(const Offset & offset) const1238 Offset RenderNode::GetOffsetFromOrigin(const Offset& offset) const
1239 {
1240 auto parent = parent_.Upgrade();
1241 if (!parent) {
1242 return offset;
1243 }
1244 Offset nowOffset = GetPosition();
1245 return parent->GetOffsetFromOrigin(offset + nowOffset);
1246 }
1247
GetGlobalOffset() const1248 Offset RenderNode::GetGlobalOffset() const
1249 {
1250 Offset globalOffset = GetPosition();
1251 auto renderNode = parent_.Upgrade();
1252 while (renderNode) {
1253 globalOffset += renderNode->GetPosition();
1254 auto parentWeak = renderNode->GetParent();
1255 renderNode = parentWeak.Upgrade();
1256 }
1257 auto context = context_.Upgrade();
1258 if (!context) {
1259 return globalOffset;
1260 }
1261 auto isContainerModal = context->GetWindowModal() == WindowModal::CONTAINER_MODAL &&
1262 context->GetWindowManager()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
1263 if (isContainerModal) {
1264 globalOffset = globalOffset + Offset(-(CONTAINER_BORDER_WIDTH.ConvertToPx() + CONTENT_PADDING.ConvertToPx()),
1265 -CONTAINER_TITLE_HEIGHT.ConvertToPx());
1266 }
1267 return globalOffset;
1268 }
1269
GetPaintOffset() const1270 Offset RenderNode::GetPaintOffset() const
1271 {
1272 auto renderNode = parent_.Upgrade();
1273 bool isNotHead = !IsHeadRenderNode() || (renderNode ? (renderNode->rsNode_ == rsNode_) : false);
1274 return (renderNode && isNotHead) ? GetPosition() + renderNode->GetPaintOffset() : GetPosition();
1275 }
1276
GetGlobalOffsetExternal() const1277 Offset RenderNode::GetGlobalOffsetExternal() const
1278 {
1279 auto renderNode = parent_.Upgrade();
1280 return renderNode ? GetPosition() + renderNode->GetGlobalOffsetExternal() : GetPosition();
1281 }
1282
GetHeadRenderNode()1283 RefPtr<RenderNode> RenderNode::GetHeadRenderNode()
1284 {
1285 if (IsHeadRenderNode()) {
1286 return AceType::Claim(this);
1287 }
1288 auto renderNode = parent_.Upgrade();
1289 if (!renderNode) {
1290 return nullptr;
1291 }
1292 return renderNode->GetHeadRenderNode();
1293 }
1294
IsVisible(const Rect & rect,bool totally) const1295 bool RenderNode::IsVisible(const Rect& rect, bool totally) const
1296 {
1297 Rect intersectRect = Rect(Offset(), GetLayoutSize());
1298 bool visible = totally ? rect.IsWrappedBy(intersectRect) : rect.IsIntersectWith(intersectRect);
1299 if (!visible) {
1300 return false;
1301 }
1302 auto parent = parent_.Upgrade();
1303 if (!parent) {
1304 return true;
1305 }
1306 return parent->IsVisible(rect + GetPosition());
1307 }
1308
GetLastChild() const1309 RefPtr<RenderNode> RenderNode::GetLastChild() const
1310 {
1311 if (children_.empty()) {
1312 return nullptr;
1313 }
1314 return children_.back();
1315 }
1316
GetFirstChild() const1317 RefPtr<RenderNode> RenderNode::GetFirstChild() const
1318 {
1319 if (children_.empty()) {
1320 return nullptr;
1321 }
1322 return children_.front();
1323 }
1324
UpdateAccessibilityPosition()1325 void RenderNode::UpdateAccessibilityPosition()
1326 {
1327 const auto& context = context_.Upgrade();
1328 if (!context) {
1329 return;
1330 }
1331 auto viewScale = context->GetViewScale();
1332 if (NearZero(viewScale)) {
1333 return;
1334 }
1335
1336 auto accessibilityNode = GetAccessibilityNode().Upgrade();
1337 if (!accessibilityNode) {
1338 return;
1339 }
1340
1341 Size size = GetLayoutSize();
1342 Offset globalOffset = GetGlobalOffsetExternal();
1343 PositionInfo positionInfo = { (size.Width()) * viewScale, (size.Height()) * viewScale,
1344 (globalOffset.GetX()) * viewScale, (globalOffset.GetY()) * viewScale };
1345 accessibilityNode->SetPositionInfo(positionInfo);
1346 }
1347
UpdateAccessibilityEnable(bool isEnabled)1348 void RenderNode::UpdateAccessibilityEnable(bool isEnabled)
1349 {
1350 auto accessibilityNode = accessibilityNode_.Upgrade();
1351 if (accessibilityNode) {
1352 accessibilityNode->SetEnabledState(isEnabled);
1353 }
1354 }
1355
UpdateAll(const RefPtr<Component> & component)1356 void RenderNode::UpdateAll(const RefPtr<Component>& component)
1357 {
1358 if (!component) {
1359 LOGE("fail to update all due to component is null");
1360 return;
1361 }
1362 hitTestMode_ = component->GetHitTestMode();
1363 touchable_ = component->IsTouchable();
1364 disabled_ = component->IsDisabledStatus();
1365 UpdateAccessibilityEnable(!disabled_);
1366 isFirstNode_ = component->IsFirstNode();
1367 auto renderComponent = AceType::DynamicCast<RenderComponent>(component);
1368 CHECK_NULL_VOID(renderComponent);
1369 positionParam_ = renderComponent->GetPositionParam();
1370 motionPathOption_ = renderComponent->GetMotionPathOption();
1371 #ifdef ENABLE_ROSEN_BACKEND
1372 if (SystemProperties::GetRosenBackendEnabled() && motionPathOption_.IsValid()) {
1373 if (auto rsNode = GetRSNode()) {
1374 auto nativeMotionOption =
1375 std::make_shared<Rosen::RSMotionPathOption>(NativeCurveHelper::ToNativeMotionPathOption(
1376 motionPathOption_, positionParam_.type == PositionType::PTOFFSET));
1377 rsNode->SetMotionPathOption(nativeMotionOption);
1378 }
1379 }
1380 #endif
1381
1382 if (!NearEqual(flexWeight_, renderComponent->GetFlexWeight())) {
1383 auto parentFlex = GetParent().Upgrade();
1384 if (parentFlex) {
1385 parentFlex->MarkNeedLayout();
1386 }
1387 }
1388 flexWeight_ = renderComponent->GetFlexWeight();
1389 displayIndex_ = renderComponent->GetDisplayIndex();
1390 displayIndexSetted_ = renderComponent->GetDisplayIndexSetted();
1391 isIgnored_ = renderComponent->IsIgnored();
1392 interceptTouchEvent_ = renderComponent->InterceptEvent();
1393 if (renderComponent->IsCustomComponent()) {
1394 onLayoutReady_ =
1395 AceAsyncEvent<void(const std::string&)>::Create(renderComponent->GetOnLayoutReadyMarker(), context_);
1396 }
1397 auto context = context_.Upgrade();
1398 if (context != nullptr) {
1399 minPlatformVersion_ = context->GetMinPlatformVersion();
1400 }
1401 SetZIndex(renderComponent->GetZIndex());
1402 isPercentSize_ = renderComponent->GetIsPercentSize();
1403 responseRegion_ = renderComponent->GetResponseRegion();
1404 isResponseRegion_ = renderComponent->IsResponseRegion();
1405 if (component->HasEventExtensions()) {
1406 eventExtensions_ = component->GetEventExtensions();
1407 }
1408 UpdatePropAnimation(component->GetAnimatables());
1409 Update(component);
1410 MarkNeedLayout();
1411 }
1412
UpdateOpacity(uint8_t opacity)1413 void RenderNode::UpdateOpacity(uint8_t opacity)
1414 {
1415 if (!SupportOpacity()) {
1416 return;
1417 }
1418 if (opacity_ != opacity) {
1419 opacity_ = opacity;
1420 if (auto rsNode = GetRSNode()) {
1421 #ifdef ENABLE_ROSEN_BACKEND
1422 rsNode->SetAlpha(opacity_ / 255.0);
1423 #endif
1424 } else {
1425 MarkNeedRender();
1426 }
1427 }
1428 }
1429
GetOpacityCallback(int32_t domId)1430 RenderNode::OpacityCallback RenderNode::GetOpacityCallback(int32_t domId)
1431 {
1432 if (domId != GetNodeId()) {
1433 return nullptr;
1434 }
1435 if (!SupportOpacity()) {
1436 return nullptr;
1437 }
1438 return [weak = AceType::WeakClaim(this)](uint8_t opacity) {
1439 auto render = weak.Upgrade();
1440 if (render) {
1441 render->UpdateOpacity(opacity);
1442 }
1443 };
1444 }
1445
GetDomOpacityCallbacks(int32_t domId,std::list<OpacityCallback> & result)1446 void RenderNode::GetDomOpacityCallbacks(int32_t domId, std::list<OpacityCallback>& result)
1447 {
1448 if (domId != GetNodeId()) {
1449 return;
1450 }
1451 auto callback = GetOpacityCallback(domId);
1452 if (callback) {
1453 result.emplace_back(callback);
1454 }
1455 for (auto& child : children_) {
1456 child->GetDomOpacityCallbacks(domId, result);
1457 }
1458 }
1459
GetNodeId() const1460 int32_t RenderNode::GetNodeId() const
1461 {
1462 return GetAccessibilityNodeId();
1463 }
1464
GetOpacity() const1465 uint8_t RenderNode::GetOpacity() const
1466 {
1467 return opacity_;
1468 }
1469
SupportOpacity()1470 bool RenderNode::SupportOpacity()
1471 {
1472 return false;
1473 }
1474
GetOffsetToPage() const1475 Offset RenderNode::GetOffsetToPage() const
1476 {
1477 auto offset = GetGlobalOffset();
1478 auto context = GetContext().Upgrade();
1479 if (context) {
1480 offset = offset - context->GetPageRect().GetOffset();
1481 }
1482 return offset;
1483 }
1484
ClearRenderObject()1485 void RenderNode::ClearRenderObject()
1486 {
1487 context_ = nullptr;
1488 viewPort_ = Size();
1489 globalPoint_ = Point();
1490 touchRect_ = Rect();
1491 accessibilityNode_ = nullptr;
1492 needUpdateAccessibility_ = true;
1493 disabled_ = false;
1494 positionParam_ = PositionParam();
1495 opacity_ = 255;
1496 interceptTouchEvent_ = false;
1497 mouseState_ = MouseState::NONE;
1498
1499 ClearChildren();
1500 rsNode_ = nullptr;
1501 isHeadRenderNode_ = false;
1502 isTailRenderNode_ = false;
1503 isFirstNode_ = false;
1504 accessibilityText_ = "";
1505 layoutParam_ = LayoutParam();
1506 paintRect_ = Rect();
1507 paintX_ = Dimension();
1508 paintY_ = Dimension();
1509 paintW_ = Dimension();
1510 paintH_ = Dimension();
1511 nonStrictPaintRect_ = Rect();
1512 transitionPaintRectSize_ = Size();
1513 isFirstSizeAssign_ = true;
1514 isFirstPositionAssign_ = true;
1515 disappearingNodes_.clear();
1516 parent_ = nullptr;
1517 depth_ = 0;
1518 needRender_ = false;
1519 needLayout_ = false;
1520 visible_ = true;
1521 hidden_ = false;
1522 takeBoundary_ = false;
1523 layoutParamChanged_ = false;
1524 disableTouchEvent_ = false;
1525 needUpdateTouchRect_ = false;
1526 flexWeight_ = 0.0;
1527 displayIndex_ = 1;
1528 textDirection_ = TextDirection::LTR;
1529 onChangeCallback_ = nullptr;
1530 isPaintGeometryTransition_ = false;
1531 displayIndexSetted_ = false;
1532 }
1533
GetGlobalWindowBlurRRect(std::vector<RRect> & coords) const1534 RRect RenderNode::GetGlobalWindowBlurRRect(std::vector<RRect>& coords) const
1535 {
1536 RRect windowBlurRRect = GetWindowBlurRRect();
1537 Rect innerRect = windowBlurRRect.GetRect();
1538 if (!innerRect.IsValid()) {
1539 return RRect {};
1540 } else {
1541 innerRect += GetPosition();
1542 windowBlurRRect += GetPosition();
1543 coords.push_back(windowBlurRRect);
1544 auto parent = GetParent().Upgrade();
1545 while (parent) {
1546 auto parentBlurRRect = parent->GetWindowBlurRRect();
1547 const Corner& corner = parentBlurRRect.GetCorner();
1548 // intersect with parent or set border radius should clip by java
1549 if (!innerRect.IsWrappedBy(parentBlurRRect.GetRect()) ||
1550 (corner.topLeftRadius.GetX().IsValid() && corner.topLeftRadius.GetY().IsValid())) {
1551 coords.push_back(parentBlurRRect);
1552 }
1553 innerRect = innerRect.Constrain(parentBlurRRect.GetRect());
1554 auto offset = parent->GetPosition();
1555 innerRect += offset;
1556 // out of view port
1557 if (!innerRect.IsValid()) {
1558 coords.clear();
1559 return RRect {};
1560 }
1561 for (auto& coord : coords) {
1562 coord += offset;
1563 }
1564 parent = parent->GetParent().Upgrade();
1565 }
1566 return RRect::MakeRRect(innerRect, windowBlurRRect.GetCorner().topLeftRadius);
1567 }
1568 }
1569
GetRectWithShadow() const1570 Rect RenderNode::GetRectWithShadow() const
1571 {
1572 Rect paintRect(paintRect_);
1573 if (InLayoutTransition()) {
1574 paintRect = nonStrictPaintRect_;
1575 }
1576 if (!hasShadow_ || !shadow_.IsValid()) {
1577 return Rect(Offset::Zero(), paintRect.GetSize());
1578 }
1579 auto blurRadius = shadow_.GetBlurRadius();
1580 auto elevation = shadow_.GetElevation();
1581 if (elevation > 0.0f && elevation < shadow_.GetLightHeight()) {
1582 // Conversion between blurRadius and elevation.
1583 blurRadius = elevation / (shadow_.GetLightHeight() - elevation) * shadow_.GetLightRadius();
1584 }
1585 auto radius = 2.0 * blurRadius + shadow_.GetSpreadRadius();
1586
1587 Rect shadowRect = paintRect + (shadow_.GetOffset() - Offset(radius, radius));
1588 shadowRect += Size(2.0 * radius, 2.0 * radius);
1589 shadowRect = shadowRect.CombineRect(paintRect);
1590
1591 Offset paintOffset = paintRect.GetOffset();
1592 Offset shadowOffset = shadowRect.GetOffset();
1593 Offset offset = Offset(std::min(0.0, shadowOffset.GetX() - paintOffset.GetX()),
1594 std::min(0.0, shadowOffset.GetY() - paintOffset.GetY()));
1595 return Rect(offset, shadowRect.GetSize());
1596 }
1597
UpdateWindowBlurRRect(bool clear)1598 void RenderNode::UpdateWindowBlurRRect(bool clear)
1599 {
1600 auto pipelineContext = context_.Upgrade();
1601 if (!pipelineContext) {
1602 LOGE("pipelineContext is null");
1603 return;
1604 }
1605 if (clear) {
1606 pipelineContext->ClearWindowBlurRegion(GetNodeId());
1607 } else {
1608 std::vector<RRect> coords;
1609 auto blurRect = GetGlobalWindowBlurRRect(coords);
1610 pipelineContext->UpdateWindowBlurRegion(
1611 GetNodeId(), blurRect, GetWindowBlurProgress(), GetWindowBlurStyle(), coords);
1612 }
1613 }
1614
WindowBlurTest()1615 void RenderNode::WindowBlurTest()
1616 {
1617 if (GetHidden() || !GetVisible()) {
1618 return;
1619 }
1620
1621 if (NeedWindowBlur()) {
1622 UpdateWindowBlurRRect();
1623 }
1624 const auto& children = GetChildren();
1625 for (const auto& child : children) {
1626 child->WindowBlurTest();
1627 }
1628 }
1629
HasEffectiveTransform() const1630 bool RenderNode::HasEffectiveTransform() const
1631 {
1632 return false;
1633 }
1634
IsDisappearing()1635 bool RenderNode::IsDisappearing()
1636 {
1637 auto parentNode = parent_.Upgrade();
1638 if (!parentNode) {
1639 return false;
1640 }
1641 const auto& disappearingList = parentNode->disappearingNodes_;
1642 auto iter = std::find(disappearingList.begin(), disappearingList.end(), AceType::Claim(this));
1643 if (iter != disappearingList.end()) {
1644 return true;
1645 } else {
1646 return false;
1647 }
1648 }
HasDisappearingTransition(int32_t nodeId)1649 bool RenderNode::HasDisappearingTransition(int32_t nodeId)
1650 {
1651 #ifdef ENABLE_ROSEN_BACKEND
1652 if (SystemProperties::GetRosenBackendEnabled()) {
1653 if (isTailRenderNode_) {
1654 return false;
1655 }
1656 for (auto& child : children_) {
1657 if (child->HasDisappearingTransition(nodeId)) {
1658 return true;
1659 }
1660 }
1661 return false;
1662 }
1663 #endif
1664 for (auto& child : children_) {
1665 if (child->GetNodeId() == nodeId) {
1666 if (child->HasDisappearingTransition(nodeId)) {
1667 return true;
1668 }
1669 }
1670 }
1671 return false;
1672 }
1673
NotifyTransition(TransitionType type,int32_t nodeId)1674 void RenderNode::NotifyTransition(TransitionType type, int32_t nodeId)
1675 {
1676 #ifdef ENABLE_ROSEN_BACKEND
1677 if (SystemProperties::GetRosenBackendEnabled()) {
1678 if (GetRSNode() == nullptr) {
1679 return;
1680 }
1681 // call OnRSTransition for all render_nodes sharing this RSNode
1682 OnRSTransition(type);
1683 if (isTailRenderNode_) {
1684 return;
1685 }
1686 for (auto& child : children_) {
1687 child->NotifyTransition(type, nodeId);
1688 }
1689 return;
1690 }
1691 #endif
1692 OnTransition(type, nodeId);
1693 for (auto& child : children_) {
1694 if (child->GetNodeId() == nodeId) {
1695 child->NotifyTransition(type, nodeId);
1696 }
1697 }
1698 }
1699
NotifySizeTransition(const AnimationOption & option,Size fromSize,Size toSize,int32_t nodeId)1700 void RenderNode::NotifySizeTransition(const AnimationOption& option, Size fromSize, Size toSize, int32_t nodeId)
1701 {
1702 paintW_.MoveTo(fromSize.Width());
1703 paintH_.MoveTo(fromSize.Height());
1704 paintW_ = AnimatableDimension(toSize.Width());
1705 paintH_ = AnimatableDimension(toSize.Height());
1706 for (auto& child : children_) {
1707 if (child->GetNodeId() == nodeId) {
1708 child->NotifySizeTransition(option, fromSize, toSize, nodeId);
1709 }
1710 }
1711 }
1712
GetDirtyRect() const1713 Rect RenderNode::GetDirtyRect() const
1714 {
1715 Rect dirty = Rect(GetGlobalOffset(), GetLayoutSize());
1716 auto context = context_.Upgrade();
1717 if (!context) {
1718 LOGE("Get dirty rect failed. context is null.");
1719 return dirty;
1720 }
1721 // check self has transform effect.
1722 if (HasEffectiveTransform()) {
1723 return context->GetRootRect();
1724 }
1725 // check parent has transform effect.
1726 auto pageRoot = context->GetLastPageRender();
1727 auto parent = GetParent().Upgrade();
1728 while (parent && parent != pageRoot) {
1729 if (parent->HasEffectiveTransform()) {
1730 return context->GetRootRect();
1731 }
1732 parent = parent->GetParent().Upgrade();
1733 }
1734 // No transform takes effect, return layoutSize.
1735 return dirty;
1736 }
1737
IsPointInBox(const TouchEvent & point)1738 bool RenderNode::IsPointInBox(const TouchEvent& point)
1739 {
1740 double offsetX = GetGlobalOffset().GetX();
1741 double offsetY = GetGlobalOffset().GetY();
1742 double maxX = GetPaintRect().Width() + offsetX;
1743 double maxY = GetPaintRect().Height() + offsetY;
1744 if (InRegion(offsetX, maxX, point.x) && InRegion(offsetY, maxY, point.y)) {
1745 return true;
1746 }
1747 return false;
1748 }
1749
GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr,Offset & offset) const1750 bool RenderNode::GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr, Offset& offset) const
1751 {
1752 offset = offset - GetPosition();
1753 auto renderNode = parent_.Upgrade();
1754 return renderNode ? renderNode->GetAlignDeclarationOffset(alignDeclarationPtr, offset) : false;
1755 }
1756
SaveExplicitAnimationOption(const AnimationOption & option)1757 void RenderNode::SaveExplicitAnimationOption(const AnimationOption& option)
1758 {
1759 nonStrictOption_ = option;
1760 }
1761
GetExplicitAnimationOption() const1762 const AnimationOption& RenderNode::GetExplicitAnimationOption() const
1763 {
1764 return nonStrictOption_;
1765 }
1766
ClearExplicitAnimationOption()1767 void RenderNode::ClearExplicitAnimationOption()
1768 {
1769 nonStrictOption_ = AnimationOption();
1770 }
1771
ClearDisappearingNode(RefPtr<RenderNode> child)1772 void RenderNode::ClearDisappearingNode(RefPtr<RenderNode> child)
1773 {
1774 disappearingNodes_.remove(child);
1775 }
1776
CreateLayoutTransition()1777 void RenderNode::CreateLayoutTransition()
1778 {
1779 auto context = context_.Upgrade();
1780 if (!context) {
1781 return;
1782 }
1783 if (nonStrictOption_.IsValid()) {
1784 auto option = context->GetExplicitAnimationOption();
1785 context->SaveExplicitAnimationOption(nonStrictOption_);
1786 CreatePathAnimation();
1787 paintX_ = AnimatableDimension(paintRect_.GetOffset().GetX());
1788 paintY_ = AnimatableDimension(paintRect_.GetOffset().GetY());
1789 paintW_ = AnimatableDimension(paintRect_.GetSize().Width());
1790 paintH_ = AnimatableDimension(paintRect_.GetSize().Height());
1791 context->SaveExplicitAnimationOption(option);
1792 nonStrictOption_ = AnimationOption();
1793 } else {
1794 if (paintX_.GetAnimationStatus() != Animator::Status::RUNNING) {
1795 paintX_.MoveTo(paintRect_.GetOffset().GetX());
1796 }
1797 if (paintY_.GetAnimationStatus() != Animator::Status::RUNNING) {
1798 paintY_.MoveTo(paintRect_.GetOffset().GetY());
1799 }
1800 if (paintW_.GetAnimationStatus() != Animator::Status::RUNNING) {
1801 paintW_.MoveTo(paintRect_.GetSize().Width());
1802 }
1803 if (paintH_.GetAnimationStatus() != Animator::Status::RUNNING) {
1804 paintH_.MoveTo(paintRect_.GetSize().Height());
1805 }
1806 }
1807
1808 nonStrictPaintRect_.SetOffset(Offset(paintX_.Value(), paintY_.Value()));
1809 nonStrictPaintRect_.SetSize(Size(paintW_.Value(), paintH_.Value()));
1810 }
1811
CreatePathAnimation()1812 void RenderNode::CreatePathAnimation()
1813 {
1814 if (!motionPathOption_.IsValid()) {
1815 paintX_.SetEvaluator(nullptr);
1816 paintY_.SetEvaluator(nullptr);
1817 return;
1818 }
1819 if (paintX_.Value() == paintRect_.GetOffset().GetX() && paintY_.Value() == paintRect_.GetOffset().GetY()) {
1820 LOGE("CreatePathAnimation failed, target equal source");
1821 return;
1822 }
1823
1824 auto evaluator = AceType::MakeRefPtr<MotionPathEvaluator>(
1825 motionPathOption_, Offset(paintX_.Value(), paintY_.Value()), paintRect_.GetOffset(), positionParam_.type);
1826 paintX_.SetEvaluator(evaluator->CreateXEvaluator());
1827 paintY_.SetEvaluator(evaluator->CreateYEvaluator());
1828 // find transform to create rotate Animation
1829 if (motionPathOption_.GetRotate()) {
1830 auto child = GetFirstChild();
1831 while (child) {
1832 auto transform = AceType::DynamicCast<RenderTransform>(child);
1833 if (transform) {
1834 transform->SetMotionPathEvaluator(evaluator);
1835 break;
1836 }
1837 child = child->GetFirstChild();
1838 }
1839 }
1840 }
1841
CreateGeometryTransitionFrom(const RefPtr<RenderNode> & targetNode,AnimationOption & sharedOption)1842 void RenderNode::CreateGeometryTransitionFrom(const RefPtr<RenderNode>& targetNode, AnimationOption& sharedOption)
1843 {
1844 auto context = context_.Upgrade();
1845 if (!context) {
1846 return;
1847 }
1848 auto weak = AceType::WeakClaim(this);
1849 auto render = weak.Upgrade();
1850 if (!render) {
1851 return;
1852 }
1853 const Rect targetPaintRect_ = targetNode->GetPaintRect();
1854 const Offset targetOffset = targetNode->GetTransitionGlobalOffset();
1855 const Offset currentOffset = render->GetGlobalOffset();
1856 if (sharedOption.IsValid()) {
1857 auto option = context->GetExplicitAnimationOption();
1858 context->SaveExplicitAnimationOption(sharedOption);
1859 Size toSize = paintRect_.GetSize();
1860 Size fromSize = targetPaintRect_.GetSize();
1861 isPaintGeometryTransition_ = true;
1862 for (auto& child : children_) {
1863 child->SetIsPaintGeometryTransition(isPaintGeometryTransition_);
1864 }
1865 paintX_.MoveTo(targetOffset.GetX());
1866 paintY_.MoveTo(targetOffset.GetY());
1867 paintX_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1868 auto render = weak.Upgrade();
1869 if (!render) {
1870 return;
1871 }
1872 auto children = render->GetChildren();
1873 render->isPaintGeometryTransition_ = false;
1874 for (auto& child : children) {
1875 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1876 }
1877 auto parent = render->GetParent().Upgrade();
1878 if (!parent) {
1879 return;
1880 }
1881 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1882 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1883 });
1884 paintY_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1885 auto render = weak.Upgrade();
1886 if (!render) {
1887 return;
1888 }
1889 auto children = render->GetChildren();
1890 render->isPaintGeometryTransition_ = false;
1891 for (auto& child : children) {
1892 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1893 }
1894 auto parent = render->GetParent().Upgrade();
1895 if (!parent) {
1896 return;
1897 }
1898 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1899 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1900 });
1901 paintX_ = AnimatableDimension(currentOffset.GetX());
1902 paintY_ = AnimatableDimension(currentOffset.GetY());
1903 render->NotifySizeTransition(sharedOption, fromSize, toSize, render->GetNodeId());
1904 context->SaveExplicitAnimationOption(option);
1905 }
1906 }
1907
CreateGeometryTransitionTo(const RefPtr<RenderNode> & targetNode,AnimationOption & sharedOption)1908 void RenderNode::CreateGeometryTransitionTo(const RefPtr<RenderNode>& targetNode, AnimationOption& sharedOption)
1909 {
1910 auto context = context_.Upgrade();
1911 if (!context) {
1912 return;
1913 }
1914 auto weak = AceType::WeakClaim(this);
1915 auto render = weak.Upgrade();
1916 if (!render) {
1917 return;
1918 }
1919 const Rect targetPaintRect_ = targetNode->GetPaintRect();
1920 const Offset targetOffset = targetNode->GetGlobalOffset();
1921 const Offset currentOffset = render->GetTransitionGlobalOffset();
1922 if (sharedOption.IsValid()) {
1923 auto option = context->GetExplicitAnimationOption();
1924 context->SaveExplicitAnimationOption(sharedOption);
1925 Size fromSize = paintRect_.GetSize();
1926 Size toSize = targetPaintRect_.GetSize();
1927 isPaintGeometryTransition_ = true;
1928 for (auto& child : children_) {
1929 child->SetIsPaintGeometryTransition(isPaintGeometryTransition_);
1930 }
1931 paintX_.MoveTo(currentOffset.GetX());
1932 paintY_.MoveTo(currentOffset.GetY());
1933 paintX_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1934 auto render = weak.Upgrade();
1935 if (!render) {
1936 return;
1937 }
1938 auto children = render->GetChildren();
1939 render->isPaintGeometryTransition_ = false;
1940 for (auto& child : children) {
1941 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1942 }
1943 auto parent = render->GetParent().Upgrade();
1944 if (!parent) {
1945 return;
1946 }
1947 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1948 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1949 });
1950 paintY_.SetAnimationStopCallback([weak = AceType::WeakClaim(this)] {
1951 auto render = weak.Upgrade();
1952 if (!render) {
1953 return;
1954 }
1955 auto children = render->GetChildren();
1956 render->isPaintGeometryTransition_ = false;
1957 for (auto& child : children) {
1958 child->SetIsPaintGeometryTransition(render->isPaintGeometryTransition_);
1959 }
1960 auto parent = render->GetParent().Upgrade();
1961 if (!parent) {
1962 return;
1963 }
1964 render->paintX_.MoveTo(render->GetGlobalOffset().GetX() - parent->GetGlobalOffset().GetX());
1965 render->paintY_.MoveTo(render->GetGlobalOffset().GetY() - parent->GetGlobalOffset().GetY());
1966 });
1967 paintX_ = AnimatableDimension(targetOffset.GetX());
1968 paintY_ = AnimatableDimension(targetOffset.GetY());
1969 render->NotifySizeTransition(sharedOption, fromSize, toSize, render->GetNodeId());
1970 context->SaveExplicitAnimationOption(option);
1971 }
1972 }
1973
GetPaintRect() const1974 const Rect& RenderNode::GetPaintRect() const
1975 {
1976 if (InLayoutTransition()) {
1977 return nonStrictPaintRect_;
1978 } else {
1979 return paintRect_;
1980 }
1981 }
1982
GetTransitionGlobalOffset() const1983 Offset RenderNode::GetTransitionGlobalOffset() const
1984 {
1985 auto renderNode = parent_.Upgrade();
1986 return renderNode ? GetTransitionPaintRect().GetOffset() + renderNode->GetTransitionGlobalOffset()
1987 : GetTransitionPaintRect().GetOffset();
1988 }
1989
GetTransitionPaintRect() const1990 Rect RenderNode::GetTransitionPaintRect() const
1991 {
1992 if (InLayoutTransition()) {
1993 return Rect(nonStrictPaintRect_.GetOffset(), transitionPaintRectSize_);
1994 } else {
1995 return paintRect_;
1996 }
1997 }
1998
SetLayoutSize(const Size & size)1999 void RenderNode::SetLayoutSize(const Size& size)
2000 {
2001 auto context = context_.Upgrade();
2002 if (!context) {
2003 LOGE("Set layout size failed. context is null.");
2004 return;
2005 }
2006 if (paintRect_.GetSize() != size) {
2007 isFirstSizeAssign_ = false;
2008 nonStrictOption_ = context->GetExplicitAnimationOption();
2009 context->AddLayoutTransitionNode(AceType::Claim(this));
2010 // get bigger canvas size duration transition.
2011 transitionPaintRectSize_ = Rect(Offset(), paintRect_.GetSize()).CombineRect(Rect(Offset(), size)).GetSize();
2012 paintRect_.SetSize(size);
2013 needUpdateTouchRect_ = true;
2014 OnSizeChanged();
2015 MarkNeedSyncGeometryProperties();
2016 }
2017 if (isFirstSizeAssign_) {
2018 isFirstSizeAssign_ = false;
2019 nonStrictOption_ = context->GetExplicitAnimationOption();
2020 context->AddLayoutTransitionNode(AceType::Claim(this));
2021 }
2022 }
2023
InLayoutTransition() const2024 bool RenderNode::InLayoutTransition() const
2025 {
2026 return paintX_.GetAnimationStatus() == Animator::Status::RUNNING ||
2027 paintY_.GetAnimationStatus() == Animator::Status::RUNNING ||
2028 paintW_.GetAnimationStatus() == Animator::Status::RUNNING ||
2029 paintH_.GetAnimationStatus() == Animator::Status::RUNNING;
2030 }
2031
MarkUpdateType(const RefPtr<Component> & component)2032 void RenderNode::MarkUpdateType(const RefPtr<Component>& component)
2033 {
2034 updateType_ = component->Compare(GetComponent());
2035 if (updateType_ & static_cast<uint32_t>(UpdateRenderType::LAYOUT)) {
2036 MarkNeedLayout();
2037 return;
2038 }
2039 if (updateType_ & static_cast<uint32_t>(UpdateRenderType::PAINT)) {
2040 MarkNeedRender();
2041 return;
2042 }
2043 }
2044
SetIsPaintGeometryTransition(bool isPaintGeometryTransition)2045 void RenderNode::SetIsPaintGeometryTransition(bool isPaintGeometryTransition)
2046 {
2047 isPaintGeometryTransition_ = isPaintGeometryTransition;
2048 }
2049
SetPaintOutOfParent(bool isPaintOutOfParent)2050 void RenderNode::SetPaintOutOfParent(bool isPaintOutOfParent)
2051 {
2052 isPaintOutOfParent_ = isPaintOutOfParent;
2053 }
2054
IsPaintOutOfParent()2055 bool RenderNode::IsPaintOutOfParent()
2056 {
2057 return isPaintGeometryTransition_ || isPaintOutOfParent_;
2058 }
2059
UpdatePosition()2060 void RenderNode::UpdatePosition()
2061 {
2062 if (isPaintGeometryTransition_) {
2063 nonStrictPaintRect_.SetLeft(paintX_.Value() - GetParent().Upgrade()->GetTransitionGlobalOffset().GetX());
2064 nonStrictPaintRect_.SetTop(paintY_.Value() - GetParent().Upgrade()->GetTransitionGlobalOffset().GetY());
2065 }
2066 }
2067
SetDepth(int32_t depth)2068 void RenderNode::SetDepth(int32_t depth)
2069 {
2070 if (depth_ != depth) {
2071 depth_ = depth;
2072 const auto& children = GetChildren();
2073 for (const auto& item : children) {
2074 item->SetDepth(depth_ + 1);
2075 }
2076 }
2077 }
2078
SyncRSNodeBoundary(bool isHead,bool isTail,const RefPtr<Component> & component)2079 void RenderNode::SyncRSNodeBoundary(bool isHead, bool isTail, const RefPtr<Component>& component)
2080 {
2081 isHeadRenderNode_ = isHead;
2082 #ifdef ENABLE_ROSEN_BACKEND
2083 isTailRenderNode_ = isTail;
2084
2085 // if "UseExternalRSNode" is true, we should find tail component and extract RSNode from it.
2086 if (ProcessExternalRSNode(component)) {
2087 return;
2088 }
2089
2090 if (isHead && !rsNode_) {
2091 // create RSNode in first node of JSview
2092 rsNode_ = CreateRSNode();
2093 } else if (!isHead && rsNode_) {
2094 // destroy unneeded RSNode
2095 rsNode_ = nullptr;
2096 }
2097 #endif
2098 }
2099
ProcessExternalRSNode(const RefPtr<Component> & component)2100 bool RenderNode::ProcessExternalRSNode(const RefPtr<Component>& component)
2101 {
2102 #ifdef ENABLE_ROSEN_BACKEND
2103 if (!isHeadRenderNode_ || component == nullptr || !component->UseExternalRSNode()) {
2104 return false;
2105 }
2106
2107 auto tailComponent = component;
2108 // recursively locate tail component.
2109 while (tailComponent != nullptr && !tailComponent->IsTailComponent()) {
2110 if (auto singleChild = AceType::DynamicCast<SingleChild>(tailComponent)) {
2111 tailComponent = singleChild->GetChild();
2112 } else {
2113 return false;
2114 }
2115 }
2116 #ifdef OHOS_PLATFORM
2117 // extract RSNode from tail component.
2118 auto rsNode = RosenRenderRemoteWindow::ExtractRSNode(tailComponent);
2119 SyncRSNode(rsNode);
2120 // avoid redundant function call.
2121 component->MarkUseExternalRSNode(false);
2122 return rsNode != nullptr;
2123 #endif
2124 #endif
2125 return false;
2126 }
2127
SyncRSNode(const std::shared_ptr<RSNode> & rsNode)2128 void RenderNode::SyncRSNode(const std::shared_ptr<RSNode>& rsNode)
2129 {
2130 #ifdef ENABLE_ROSEN_BACKEND
2131 if (rsNode_ == rsNode) {
2132 return;
2133 }
2134 rsNode_ = rsNode;
2135 if (isTailRenderNode_) {
2136 return;
2137 }
2138 for (const auto& child : GetChildren()) {
2139 child->SyncRSNode(rsNode);
2140 }
2141 #endif
2142 }
2143
MarkNeedSyncGeometryProperties()2144 void RenderNode::MarkNeedSyncGeometryProperties()
2145 {
2146 if (!HasGeometryProperties()) {
2147 return;
2148 }
2149 if (auto pipelineContext = context_.Upgrade()) {
2150 pipelineContext->AddGeometryChangedNode(AceType::Claim(this));
2151 }
2152 }
2153
SyncGeometryProperties()2154 void RenderNode::SyncGeometryProperties()
2155 {
2156 #ifdef ENABLE_ROSEN_BACKEND
2157 if (!IsTailRenderNode()) {
2158 return;
2159 }
2160 auto rsNode = GetRSNode();
2161 if (!rsNode) {
2162 return;
2163 }
2164 Offset paintOffset = GetPaintOffset();
2165 Size paintSize = GetLayoutSize();
2166 rsNode->SetFrame(paintOffset.GetX(), paintOffset.GetY(), paintSize.Width(), paintSize.Height());
2167 #endif
2168 }
2169
SetPaintRect(const Rect & rect)2170 void RenderNode::SetPaintRect(const Rect& rect)
2171 {
2172 if (paintRect_ == rect) {
2173 return;
2174 }
2175 paintRect_ = rect;
2176 needUpdateTouchRect_ = true;
2177
2178 MarkNeedSyncGeometryProperties();
2179 }
2180
RSNodeAddChild(const RefPtr<RenderNode> & child)2181 void RenderNode::RSNodeAddChild(const RefPtr<RenderNode>& child)
2182 {
2183 #ifdef ENABLE_ROSEN_BACKEND
2184 if (!rsNode_) {
2185 // workaround if parent have no RSNode while it should
2186 LOGD("Parent render_node has no RSNode, creating now.");
2187 SyncRSNodeBoundary(true, true);
2188 }
2189 if (IsTailRenderNode()) {
2190 if (!child->GetRSNode()) {
2191 // workaround if child have no RSNode while it should
2192 LOGD("Child render_node has no RSNode, creating now.");
2193 child->SyncRSNodeBoundary(true, true);
2194 }
2195 } else {
2196 if (child->rsNode_ && rsNode_ != child->rsNode_) {
2197 LOGE("Overwriting existing RSNode in child, this SHOULD NOT HAPPEN.");
2198 }
2199 // copy parent RSNode to child if they belong to the same JSView
2200 child->rsNode_ = rsNode_;
2201 }
2202 #endif
2203 }
2204
MarkParentNeedRender() const2205 void RenderNode::MarkParentNeedRender() const
2206 {
2207 auto renderNode = parent_.Upgrade();
2208 if (!renderNode) {
2209 return;
2210 }
2211 if (IsHeadRenderNode()) {
2212 renderNode->MarkNeedRender();
2213 } else {
2214 renderNode->MarkParentNeedRender();
2215 }
2216 }
2217
CreateRSNode() const2218 std::shared_ptr<RSNode> RenderNode::CreateRSNode() const
2219 {
2220 #ifdef ENABLE_ROSEN_BACKEND
2221 return Rosen::RSCanvasNode::Create();
2222 #else
2223 return nullptr;
2224 #endif
2225 }
2226
OnStatusStyleChanged(VisualState state)2227 void RenderNode::OnStatusStyleChanged(VisualState state)
2228 {
2229 LOGD("start %{public}s", AceType::TypeName(this));
2230 if (isHeadRenderNode_) {
2231 return;
2232 }
2233 RefPtr<RenderNode> parent = parent_.Upgrade();
2234 if (parent) {
2235 parent->OnStatusStyleChanged(state);
2236 }
2237 }
2238
ComputeSelectedZone(const Offset & startOffset,const Offset & endOffset)2239 Rect RenderNode::ComputeSelectedZone(const Offset& startOffset, const Offset& endOffset)
2240 {
2241 Rect selectedZone;
2242 if (startOffset.GetX() <= endOffset.GetX()) {
2243 if (startOffset.GetY() <= endOffset.GetY()) {
2244 // bottom right
2245 selectedZone = Rect(startOffset.GetX(), startOffset.GetY(), endOffset.GetX() - startOffset.GetX(),
2246 endOffset.GetY() - startOffset.GetY());
2247 return selectedZone;
2248 } else {
2249 // top right
2250 selectedZone = Rect(startOffset.GetX(), endOffset.GetY(), endOffset.GetX() - startOffset.GetX(),
2251 startOffset.GetY() - endOffset.GetY());
2252 return selectedZone;
2253 }
2254 } else {
2255 if (startOffset.GetY() <= endOffset.GetY()) {
2256 // bottom left
2257 selectedZone = Rect(endOffset.GetX(), startOffset.GetY(), startOffset.GetX() - endOffset.GetX(),
2258 endOffset.GetY() - startOffset.GetY());
2259 return selectedZone;
2260 } else {
2261 // top left
2262 selectedZone = Rect(endOffset.GetX(), endOffset.GetY(), startOffset.GetX() - endOffset.GetX(),
2263 startOffset.GetY() - endOffset.GetY());
2264 return selectedZone;
2265 }
2266 }
2267 }
2268
SendAccessibilityEvent(const std::string & eventType)2269 void RenderNode::SendAccessibilityEvent(const std::string& eventType)
2270 {
2271 auto accessibilityNode = GetAccessibilityNode().Upgrade();
2272 if (!accessibilityNode) {
2273 return;
2274 }
2275 auto context = context_.Upgrade();
2276 if (context) {
2277 AccessibilityEvent event;
2278 event.nodeId = accessibilityNode->GetNodeId();
2279 event.eventType = eventType;
2280 context->SendEventToAccessibility(event);
2281 }
2282 }
2283
SetAccessibilityClick(RefPtr<ClickRecognizer> clickRecognizer)2284 void RenderNode::SetAccessibilityClick(RefPtr<ClickRecognizer> clickRecognizer)
2285 {
2286 auto accessibilityNode = accessibilityNode_.Upgrade();
2287 if (!accessibilityNode) {
2288 return;
2289 }
2290 if (clickRecognizer) {
2291 accessibilityNode->SetClickableState(true);
2292 auto weakPtr = AceType::WeakClaim(AceType::RawPtr(clickRecognizer));
2293 accessibilityNode->SetActionClickImpl([weakPtr]() {
2294 auto click = weakPtr.Upgrade();
2295 if (click) {
2296 click->OnAccepted();
2297 }
2298 });
2299 } else {
2300 accessibilityNode->SetClickableState(false);
2301 accessibilityNode->SetActionClickImpl(nullptr);
2302 }
2303 }
2304
2305 } // namespace OHOS::Ace
2306