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