1 /*
2  * Copyright (c) 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/common/container.h"
17 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
18 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
19 #include "core/components_ng/pattern/navigation/navigation_transition_proxy.h"
20 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
21 #include "core/components_ng/pattern/navrouter/navdestination_context.h"
22 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
23 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
24 #include "core/components_ng/pattern/text/text_layout_property.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26 #include "core/components_ng/pattern/text/text_pattern.h"
27 
28 namespace OHOS::Ace::NG {
29 constexpr double HALF = 0.5;
30 constexpr float CONTENT_OFFSET_PERCENT = 0.2f;
31 constexpr float TITLE_OFFSET_PERCENT = 0.02f;
32 constexpr float REMOVE_CLIP_SIZE = 10000.0f;
33 constexpr int32_t MAX_RENDER_GROUP_TEXT_NODE_COUNT = 50;
34 constexpr int32_t OPACITY_TITLE_OUT_DELAY = 17;
35 constexpr int32_t OPACITY_TITLE_IN_DELAY = 33;
36 constexpr int32_t OPACITY_TITLE_DURATION = 150;
37 constexpr int32_t OPACITY_BACKBUTTON_IN_DELAY = 150;
38 constexpr int32_t OPACITY_BACKBUTTON_IN_DURATION = 200;
39 constexpr int32_t OPACITY_BACKBUTTON_OUT_DURATION = 67;
40 constexpr float MAX_RENDER_GROUP_TEXT_NODE_HEIGHT = 150.0f;
41 
~NavDestinationGroupNode()42 NavDestinationGroupNode::~NavDestinationGroupNode()
43 {
44     if (contentNode_) {
45         contentNode_->Clean();
46     }
47     ReleaseTextNodeList();
48 }
49 
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)50 RefPtr<NavDestinationGroupNode> NavDestinationGroupNode::GetOrCreateGroupNode(
51     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
52 {
53     auto frameNode = GetFrameNode(tag, nodeId);
54     CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavDestinationGroupNode>(frameNode));
55     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
56     auto navDestinationNode = AceType::MakeRefPtr<NavDestinationGroupNode>(tag, nodeId, pattern);
57     navDestinationNode->InitializePatternAndContext();
58     ElementRegister::GetInstance()->AddUINode(navDestinationNode);
59     return navDestinationNode;
60 }
61 
IsNeedContentTransition()62 bool NavDestinationGroupNode::IsNeedContentTransition()
63 {
64     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
65         return true;
66     }
67     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
68 }
69 
TransitionContentInValid()70 bool NavDestinationGroupNode::TransitionContentInValid()
71 {
72     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) == NavigationSystemTransitionType::NONE
73         && mode_ == NavDestinationMode::STANDARD;
74 }
75 
IsNeedTitleTransition()76 bool NavDestinationGroupNode::IsNeedTitleTransition()
77 {
78     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
79         return true;
80     }
81     if (mode_ == NavDestinationMode::STANDARD) {
82         return (systemTransitionType_ & NavigationSystemTransitionType::TITLE) != NavigationSystemTransitionType::NONE;
83     }
84     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
85 }
86 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)87 void NavDestinationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
88 {
89     auto pattern = AceType::DynamicCast<Pattern>(GetPattern());
90     CHECK_NULL_VOID(pattern);
91     auto contentNode = GetContentNode();
92     if (!contentNode) {
93         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
94         ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId);
95         contentNode = FrameNode::GetOrCreateFrameNode(V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId,
96             []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
97         SetContentNode(contentNode);
98         AddChild(contentNode);
99 
100         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
101             auto navdestinationContentNode = AceType::DynamicCast<FrameNode>(contentNode);
102             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
103                 .edges = SAFE_AREA_EDGE_ALL };
104             navdestinationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
105         }
106     }
107     contentNode->AddChild(child, slot);
108 }
109 
DeleteChildFromGroup(int32_t slot)110 void NavDestinationGroupNode::DeleteChildFromGroup(int32_t slot)
111 {
112     auto navDestination = GetContentNode();
113     CHECK_NULL_VOID(navDestination);
114     navDestination->RemoveChildAtIndex(slot);
115 }
116 
OnAttachToMainTree(bool recursive)117 void NavDestinationGroupNode::OnAttachToMainTree(bool recursive)
118 {
119     if (!UseOffscreenProcess()) {
120         ProcessShallowBuilder();
121     }
122     FrameNode::OnAttachToMainTree(recursive);
123 }
124 
OnOffscreenProcess(bool recursive)125 void NavDestinationGroupNode::OnOffscreenProcess(bool recursive)
126 {
127     ProcessShallowBuilder();
128     FrameNode::OnOffscreenProcess(recursive);
129 }
130 
ProcessShallowBuilder()131 void NavDestinationGroupNode::ProcessShallowBuilder()
132 {
133     if (isCacheNode_) {
134         return;
135     }
136 
137     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "render navDestination content");
138     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
139     CHECK_NULL_VOID(navDestinationPattern);
140     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
141     if (shallowBuilder && !shallowBuilder->IsExecuteDeepRenderDone()) {
142         auto eventHub = GetEventHub<NavDestinationEventHub>();
143         if (eventHub) {
144             auto ctx = navDestinationPattern->GetNavDestinationContext();
145             eventHub->FireOnReady(ctx);
146         }
147         shallowBuilder->ExecuteDeepRender();
148         GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
149         AceType::DynamicCast<FrameNode>(contentNode_)
150             ->GetLayoutProperty()
151             ->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
152     }
153 }
154 
GetNavDestinationCustomNode()155 RefPtr<CustomNodeBase> NavDestinationGroupNode::GetNavDestinationCustomNode()
156 {
157     return customNode_.Upgrade();
158 }
159 
SetNavDestinationMode(NavDestinationMode mode)160 void NavDestinationGroupNode::SetNavDestinationMode(NavDestinationMode mode)
161 {
162     mode_ = mode;
163     auto pattern = GetPattern<NavDestinationPattern>();
164     CHECK_NULL_VOID(pattern);
165     auto context = pattern->GetNavDestinationContext();
166     CHECK_NULL_VOID(context);
167     context->SetMode(mode);
168 }
169 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const170 void NavDestinationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
171 {
172     FrameNode::ToJsonValue(json, filter);
173     /* no fixed attr below, just return */
174     if (filter.IsFastFilter()) {
175         return;
176     }
177     auto titleBarNode = DynamicCast<TitleBarNode>(titleBarNode_);
178     if (titleBarNode) {
179         std::string title = NavigationTitleUtil::GetTitleString(titleBarNode, GetPrevTitleIsCustomValue(false));
180         std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
181         json->PutExtAttr("title", title.c_str(), filter);
182         json->PutExtAttr("subtitle", subtitle.c_str(), filter);
183     }
184     json->PutExtAttr("mode", mode_ == NavDestinationMode::DIALOG
185         ? "NavDestinationMode::DIALOG"
186         : "NavDestinationMode::STANDARD", filter);
187 }
188 
InitSystemTransitionPush(bool transitionIn)189 void NavDestinationGroupNode::InitSystemTransitionPush(bool transitionIn)
190 {
191     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
192     float isRTL = GetLanguageDirection();
193     bool needContentAnimation = IsNeedContentTransition();
194     bool needTitleAnimation = IsNeedTitleTransition();
195     if (transitionIn) {
196         SetIsOnAnimation(true);
197         SetTransitionType(PageTransitionType::ENTER_PUSH);
198         auto frameSize = GetGeometryNode()->GetFrameSize();
199         if (needContentAnimation) {
200             if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
201                 GetRenderContext()->ClipWithRRect(
202                     RectF(0.0f, 0.0f, frameSize.Width() * HALF, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
203             } else {
204                 GetRenderContext()->ClipWithRRect(
205                     RectF(frameSize.Width() * HALF, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
206                     RadiusF(EdgeF(0.0f, 0.0f)));
207             }
208             GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
209         }
210         if (titleBarNode && needTitleAnimation) {
211             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
212         }
213         return;
214     }
215     SetTransitionType(PageTransitionType::EXIT_PUSH);
216     SetIsOnAnimation(true);
217     GetRenderContext()->RemoveClipWithRRect();
218     if (needContentAnimation) {
219         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
220     }
221     if (NeedRemoveInPush()) {
222         GetEventHub<EventHub>()->SetEnabledInternal(false);
223     }
224     if (titleBarNode && needTitleAnimation) {
225         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
226     }
227 }
228 
StartSystemTransitionPush(bool transitionIn)229 void NavDestinationGroupNode::StartSystemTransitionPush(bool transitionIn)
230 {
231     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
232     auto frameSize = GetGeometryNode()->GetFrameSize();
233     float isRTL = GetLanguageDirection();
234     bool needContentAnimation = IsNeedContentTransition();
235     bool needTitleAnimation = IsNeedTitleTransition();
236     if (transitionIn) {
237         if (needContentAnimation) {
238             GetRenderContext()->ClipWithRRect(
239                 RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
240             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
241         }
242         if (titleBarNode && needTitleAnimation) {
243             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
244         }
245         return;
246     }
247     if (needContentAnimation) {
248         GetRenderContext()->UpdateTranslateInXY(
249             { -frameSize.Width() * CONTENT_OFFSET_PERCENT * isRTL, 0.0f });
250     }
251     if (titleBarNode && needTitleAnimation) {
252         titleBarNode->GetRenderContext()->UpdateTranslateInXY(
253             { frameSize.Width() * TITLE_OFFSET_PERCENT  * isRTL, 0.0f });
254     }
255 }
256 
SystemTransitionPushCallback(bool transitionIn)257 void NavDestinationGroupNode::SystemTransitionPushCallback(bool transitionIn)
258 {
259     if (transitionIn) {
260         if (GetTransitionType() != PageTransitionType::ENTER_PUSH) {
261             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "curNode has another transition");
262             return;
263         }
264         GetRenderContext()->RemoveClipWithRRect();
265         SetIsOnAnimation(false);
266         return;
267     }
268     SetIsOnAnimation(false);
269     if (IsNeedContentTransition()) {
270         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
271     }
272     GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
273     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
274     auto navigation = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
275     CHECK_NULL_VOID(navigation);
276     bool isInvisible = IsNodeInvisible(navigation);
277     if (GetTransitionType() == PageTransitionType::EXIT_PUSH && isInvisible) {
278         GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
279         SetJSViewActive(false);
280     }
281     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
282     if (titleBarNode && IsNeedTitleTransition()) {
283         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
284     }
285 }
286 
InitSystemTransitionPop(bool isTransitionIn)287 void NavDestinationGroupNode::InitSystemTransitionPop(bool isTransitionIn)
288 {
289     auto frameSize = GetGeometryNode()->GetFrameSize();
290     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
291     float isRTL = GetLanguageDirection();
292     bool needContentAnimation = IsNeedContentTransition();
293     bool needTitleAnimation = IsNeedTitleTransition();
294     if (isTransitionIn) {
295         SetTransitionType(PageTransitionType::ENTER_POP);
296         GetRenderContext()->RemoveClipWithRRect();
297         if (needContentAnimation) {
298             GetRenderContext()->UpdateTranslateInXY({ -frameSize.Width() * CONTENT_OFFSET_PERCENT * isRTL, 0.0f });
299         }
300         if (titleBarNode && needTitleAnimation) {
301             titleBarNode->GetRenderContext()->UpdateTranslateInXY(
302                 { frameSize.Width() * TITLE_OFFSET_PERCENT * isRTL, 0.0f });
303         }
304         return;
305     }
306     SetIsOnAnimation(true);
307     SetTransitionType(PageTransitionType::EXIT_POP);
308     GetEventHub<EventHub>()->SetEnabledInternal(false);
309     if (needContentAnimation) {
310         GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
311             RadiusF(EdgeF(0.0f, 0.0f)));
312         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
313     }
314     if (titleBarNode && needTitleAnimation) {
315         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
316     }
317 }
318 
StartSystemTransitionPop(bool transitionIn)319 void NavDestinationGroupNode::StartSystemTransitionPop(bool transitionIn)
320 {
321     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
322     bool needContentAnimation = IsNeedContentTransition();
323     bool needTitleAnimation = IsNeedTitleTransition();
324     if (transitionIn) {
325         if (needContentAnimation) {
326             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
327         }
328         if (titleBarNode && needTitleAnimation) {
329             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
330         }
331         return;
332     }
333     auto frameSize = GetGeometryNode()->GetFrameSize();
334     float isRTL = GetLanguageDirection();
335     if (needContentAnimation) {
336         if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
337             GetRenderContext()->ClipWithRRect(
338                 RectF(0.0f, 0.0f, frameSize.Width() * HALF, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
339         } else {
340             GetRenderContext()->ClipWithRRect(
341                 RectF(frameSize.Width() * HALF, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
342                 RadiusF(EdgeF(0.0f, 0.0f)));
343         }
344         GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
345     }
346     if (titleBarNode && needTitleAnimation) {
347         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
348     }
349 }
350 
SystemTransitionPopCallback()351 bool NavDestinationGroupNode::SystemTransitionPopCallback()
352 {
353     if (GetTransitionType() != PageTransitionType::EXIT_POP) {
354         // has another transition, just return
355         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "preNavDesNode has another transition");
356         return false;
357     }
358     auto preNavDesPattern = GetPattern<NavDestinationPattern>();
359     CHECK_NULL_RETURN(preNavDesPattern, false);
360 
361     // NavRouter will restore the preNavDesNode and needs to set the initial state after the animation ends.
362     auto shallowBuilder = preNavDesPattern->GetShallowBuilder();
363     if (shallowBuilder && !IsCacheNode()) {
364         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
365     }
366     if (!IsCacheNode() && GetContentNode()) {
367         GetContentNode()->Clean();
368     }
369     SetIsOnAnimation(false);
370     GetEventHub<EventHub>()->SetEnabledInternal(true);
371     GetRenderContext()->RemoveClipWithRRect();
372     if (IsNeedContentTransition()) {
373         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
374     }
375     auto preTitleNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
376     if (preTitleNode && IsNeedTitleTransition()) {
377         preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
378         preTitleNode->GetRenderContext()->SetOpacity(1.0);
379         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(preTitleNode);
380         CHECK_NULL_RETURN(titleBarNode, true);
381         auto preBackIcon = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
382         if (preBackIcon)  {
383             preBackIcon->GetRenderContext()->SetOpacity(1.0);
384         }
385     }
386     return true;
387 }
388 
InitDialogTransition(bool isZeroY)389 void NavDestinationGroupNode::InitDialogTransition(bool isZeroY)
390 {
391     if (systemTransitionType_ == NavigationSystemTransitionType::NONE
392         || systemTransitionType_ == NavigationSystemTransitionType::TITLE) {
393         return;
394     }
395     auto contentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
396     CHECK_NULL_VOID(contentNode);
397     auto context = contentNode->GetRenderContext();
398     CHECK_NULL_VOID(context);
399     if (isZeroY) {
400         context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
401         return;
402     }
403     context->UpdateTransformTranslate({ 0.0f,
404         contentNode->GetGeometryNode()->GetFrameSize().Height(), 0.0f });
405 }
406 
UpdateTextNodeListAsRenderGroup(bool isPopPage,const RefPtr<NavigationTransitionProxy> & proxy)407 void NavDestinationGroupNode::UpdateTextNodeListAsRenderGroup(
408     bool isPopPage, const RefPtr<NavigationTransitionProxy>& proxy)
409 {
410     if (isPopPage) {
411         CollectTextNodeAsRenderGroup(isPopPage);
412     } else {
413         CHECK_NULL_VOID(proxy);
414         auto pipeline = PipelineContext::GetCurrentContext();
415         CHECK_NULL_VOID(pipeline);
416         pipeline->AddAfterLayoutTask([weakNavDestiniation = WeakClaim(this),
417             weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] () {
418             auto navDestination = weakNavDestiniation.Upgrade();
419             CHECK_NULL_VOID(navDestination);
420             auto proxy = weakProxy.Upgrade();
421             if (proxy && proxy->GetIsFinished()) {
422                 return;
423             }
424             navDestination->CollectTextNodeAsRenderGroup(false);
425         });
426         pipeline->RequestFrame();
427     }
428 }
429 
CollectTextNodeAsRenderGroup(bool isPopPage)430 void NavDestinationGroupNode::CollectTextNodeAsRenderGroup(bool isPopPage)
431 {
432     ReleaseTextNodeList();
433     std::queue<RefPtr<UINode>> childrenLoopQueue;
434     childrenLoopQueue.push(contentNode_);
435 
436     // only the first 50 text nodes will be marked, avoid too much time for traversal
437     // and off-screen drawing at first few frames
438     int32_t remainTextNodeNeedRenderGroup = MAX_RENDER_GROUP_TEXT_NODE_COUNT;
439     while (!childrenLoopQueue.empty() && remainTextNodeNeedRenderGroup > 0) {
440         auto currentNode = childrenLoopQueue.front();
441         childrenLoopQueue.pop();
442         CHECK_NULL_CONTINUE(currentNode);
443         for (auto& child : currentNode->GetChildren()) {
444             if (remainTextNodeNeedRenderGroup <= 0) {
445                 break;
446             }
447             CHECK_NULL_CONTINUE(child);
448             childrenLoopQueue.push(child);
449             auto frameNode = AceType::DynamicCast<FrameNode>(child);
450             if (!frameNode || (frameNode->GetTag() != V2::TEXT_ETS_TAG)) {
451                 continue;
452             }
453             auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
454             if (!layoutProperty ||
455                 (layoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE)) {
456                 continue;
457             }
458             auto& renderContext = frameNode->GetRenderContext();
459             if (!renderContext || renderContext->GetRenderGroupValue(false)) {
460                 continue;
461             }
462             renderContext->SetMarkNodeGroup(isPopPage ||
463                 (renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT));
464             textNodeList_.emplace_back(WeakPtr<UINode>(child));
465             --remainTextNodeNeedRenderGroup;
466             auto pattern = AceType::DynamicCast<TextPattern>(frameNode->GetPattern());
467             CHECK_NULL_CONTINUE(pattern);
468             pattern->RegisterAfterLayoutCallback([weakRenderContext = WeakPtr<RenderContext>(renderContext)]() {
469                 auto renderContext = weakRenderContext.Upgrade();
470                 if (renderContext && !(renderContext->GetRenderGroupValue(false))) {
471                     renderContext->SetMarkNodeGroup(
472                         renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT);
473                 }
474             });
475         }
476     }
477 }
478 
ReleaseTextNodeList()479 void NavDestinationGroupNode::ReleaseTextNodeList()
480 {
481     for (auto& child : textNodeList_) {
482         auto textNode = AceType::DynamicCast<FrameNode>(child.Upgrade());
483         if (!textNode) {
484             continue;
485         }
486         auto pattern = AceType::DynamicCast<TextPattern>(textNode->GetPattern());
487         if (pattern) {
488             pattern->UnRegisterAfterLayoutCallback();
489         }
490         auto renderContext = textNode->GetRenderContext();
491         if (renderContext) {
492             renderContext->SetMarkNodeGroup(renderContext->GetRenderGroupValue(false));
493         }
494     }
495     textNodeList_.clear();
496 }
497 
CleanContent()498 void NavDestinationGroupNode::CleanContent()
499 {
500     // cacheNode is cached for pip info, and is no need to clean when clean content node
501     if (IsCacheNode()) {
502         return;
503     }
504     auto pattern = GetPattern<NavDestinationPattern>();
505     CHECK_NULL_VOID(pattern);
506     auto shallowBuilder = pattern->GetShallowBuilder();
507     if (shallowBuilder) {
508         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
509     }
510     if (GetContentNode()) {
511         GetContentNode()->Clean(false, true);
512     }
513 }
514 
IsNodeInvisible(const RefPtr<FrameNode> & node)515 bool NavDestinationGroupNode::IsNodeInvisible(const RefPtr<FrameNode>& node)
516 {
517     auto navigaiton = DynamicCast<NavigationGroupNode>(node);
518     CHECK_NULL_RETURN(navigaiton, false);
519     int32_t lastStandardIndex = navigaiton->GetLastStandardIndex();
520     bool isInvisible = index_ < lastStandardIndex;
521     return isInvisible;
522 }
523 
TitleOpacityAnimation(bool isTransitionIn)524 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::TitleOpacityAnimation(bool isTransitionIn)
525 {
526     if (!IsNeedTitleTransition()) {
527         return nullptr;
528     }
529     CHECK_NULL_RETURN(GetTitleBarNode(), nullptr);
530     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
531     CHECK_NULL_RETURN(titleNode, nullptr);
532     auto titleRenderContext = titleNode->GetRenderContext();
533     CHECK_NULL_RETURN(titleRenderContext, nullptr);
534     AnimationOption opacityOption;
535     opacityOption.SetCurve(Curves::SHARP);
536     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
537     if (isTransitionIn) {
538         opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
539         titleRenderContext->SetOpacity(0.0f);
540         return AnimationUtils::StartAnimation(opacityOption,
541             [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
542             auto renderContext = weakRender.Upgrade();
543             CHECK_NULL_VOID(renderContext);
544             renderContext->SetOpacity(1.0f);
545         });
546     }
547     // recover after transition animation.
548     opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
549     titleRenderContext->SetOpacity(1.0f);
550     return AnimationUtils::StartAnimation(opacityOption,
551         [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
552         auto renderContext = weakRender.Upgrade();
553         CHECK_NULL_VOID(renderContext);
554         renderContext->SetOpacity(0.0f);
555     });
556 }
557 
BackButtonAnimation(bool isTransitionIn)558 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::BackButtonAnimation(bool isTransitionIn)
559 {
560     if (!IsNeedTitleTransition()) {
561         return nullptr;
562     }
563     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
564     CHECK_NULL_RETURN(titleNode, nullptr);
565     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
566     CHECK_NULL_RETURN(backButtonNode, nullptr);
567     AnimationOption transitionOption;
568     transitionOption.SetCurve(Curves::SHARP);
569     auto backButtonNodeContext = backButtonNode->GetRenderContext();
570     CHECK_NULL_RETURN(backButtonNodeContext, nullptr);
571     if (isTransitionIn) {
572         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
573         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
574         backButtonNodeContext->SetOpacity(0.0f);
575         return AnimationUtils::StartAnimation(transitionOption,
576             [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
577             auto renderContext = weakRender.Upgrade();
578             CHECK_NULL_VOID(renderContext);
579             renderContext->SetOpacity(1.0f);
580         });
581     }
582     transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
583     backButtonNodeContext->SetOpacity(1.0f);
584     return AnimationUtils::StartAnimation(transitionOption,
585         [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
586         auto renderContext = weakRender.Upgrade();
587         CHECK_NULL_VOID(renderContext);
588         renderContext->SetOpacity(0.0f);
589     });
590 }
591 } // namespace OHOS::Ace::NG
592