• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/components_ng/pattern/stage/page_pattern.h"
17 
18 #include "base/log/jank_frame_report.h"
19 #include "base/perfmonitor/perf_monitor.h"
20 #include "base/utils/utils.h"
21 #include "core/animation/animator.h"
22 #include "core/common/container.h"
23 #include "core/components/common/properties/alignment.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25 
26 namespace OHOS::Ace::NG {
27 
28 namespace {
IterativeAddToSharedMap(const RefPtr<UINode> & node,SharedTransitionMap & map)29 void IterativeAddToSharedMap(const RefPtr<UINode>& node, SharedTransitionMap& map)
30 {
31     const auto& children = node->GetChildren();
32     for (const auto& child : children) {
33         auto frameChild = AceType::DynamicCast<FrameNode>(child);
34         if (!frameChild) {
35             IterativeAddToSharedMap(child, map);
36             continue;
37         }
38         auto id = frameChild->GetRenderContext()->GetShareId();
39         if (!id.empty()) {
40             LOGD("add id:%{public}s", id.c_str());
41             map[id] = frameChild;
42         }
43         IterativeAddToSharedMap(frameChild, map);
44     }
45 }
46 } // namespace
47 
OnAttachToFrameNode()48 void PagePattern::OnAttachToFrameNode()
49 {
50     auto host = GetHost();
51     CHECK_NULL_VOID(host);
52     host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
53     host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
54 }
55 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> &,const DirtySwapConfig &)56 bool PagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& /*wrapper*/, const DirtySwapConfig& /*config*/)
57 {
58     if (isFirstLoad_) {
59         isFirstLoad_ = false;
60         if (firstBuildCallback_) {
61             firstBuildCallback_();
62             firstBuildCallback_ = nullptr;
63         }
64     }
65     return false;
66 }
67 
TriggerPageTransition(PageTransitionType type,const std::function<void ()> & onFinish)68 bool PagePattern::TriggerPageTransition(PageTransitionType type, const std::function<void()>& onFinish)
69 {
70     auto host = GetHost();
71     CHECK_NULL_RETURN(host, false);
72     auto renderContext = host->GetRenderContext();
73     CHECK_NULL_RETURN(renderContext, false);
74     if (pageTransitionFunc_) {
75         pageTransitionFunc_();
76     }
77     auto effect = FindPageTransitionEffect(type);
78     pageTransitionFinish_ = std::make_shared<std::function<void()>>(onFinish);
79     auto wrappedOnFinish = [weak = WeakClaim(this), sharedFinish = pageTransitionFinish_]() {
80         auto pattern = weak.Upgrade();
81         CHECK_NULL_VOID_NOLOG(pattern);
82         if (sharedFinish == pattern->pageTransitionFinish_) {
83             // ensure this is exactly the finish callback saved in pagePattern,
84             // otherwise means new pageTransition started
85             pattern->FirePageTransitionFinish();
86         }
87     };
88     if (effect && effect->GetUserCallback()) {
89         if (!controller_) {
90             controller_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
91         }
92         if (!controller_->IsStopped()) {
93             controller_->Finish();
94         }
95         controller_->ClearInterpolators();
96         RouteType routeType = (type == PageTransitionType::ENTER_POP || type == PageTransitionType::EXIT_POP)
97                                   ? RouteType::POP
98                                   : RouteType::PUSH;
99         auto floatAnimation = AceType::MakeRefPtr<CurveAnimation<float>>(0.0f, 1.0f, effect->GetCurve());
100         floatAnimation->AddListener(
101             [routeType, handler = effect->GetUserCallback(), weak = WeakClaim(this)](const float& progress) {
102                 auto pattern = weak.Upgrade();
103                 CHECK_NULL_VOID(pattern);
104                 handler(routeType, progress);
105             });
106         if (effect->GetDelay() >= 0) {
107             controller_->SetStartDelay(effect->GetDelay());
108         }
109         controller_->SetDuration(effect->GetDuration());
110         controller_->AddInterpolator(floatAnimation);
111         controller_->AddStopListener(wrappedOnFinish);
112         controller_->Forward();
113         return renderContext->TriggerPageTransition(type, nullptr);
114     }
115     return renderContext->TriggerPageTransition(type, wrappedOnFinish);
116 }
117 
ProcessHideState()118 void PagePattern::ProcessHideState()
119 {
120     auto host = GetHost();
121     CHECK_NULL_VOID(host);
122     host->SetActive(false);
123     host->OnVisibleChange(false);
124     host->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
125     auto parent = host->GetAncestorNodeOfFrame();
126     CHECK_NULL_VOID(parent);
127     parent->MarkNeedSyncRenderTree();
128     parent->RebuildRenderContextTree();
129 }
130 
ProcessShowState()131 void PagePattern::ProcessShowState()
132 {
133     auto host = GetHost();
134     CHECK_NULL_VOID(host);
135     host->SetActive(true);
136     host->OnVisibleChange(true);
137     host->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
138     auto parent = host->GetAncestorNodeOfFrame();
139     CHECK_NULL_VOID(parent);
140     parent->MarkNeedSyncRenderTree();
141     parent->RebuildRenderContextTree();
142 }
143 
OnShow()144 void PagePattern::OnShow()
145 {
146     // Do not invoke onPageShow unless the initialRender function has been executed.
147     CHECK_NULL_VOID_NOLOG(isRenderDone_);
148     CHECK_NULL_VOID_NOLOG(!isOnShow_);
149     auto container = Container::Current();
150     if (!container || !container->WindowIsShow()) {
151         LOGW("no need to trigger onPageShow callback when not in the foreground");
152         return;
153     }
154     auto host = GetHost();
155     CHECK_NULL_VOID(host);
156     host->SetJSViewActive(true);
157     isOnShow_ = true;
158     JankFrameReport::StartRecord(pageInfo_->GetPageUrl());
159     PerfMonitor::GetPerfMonitor()->SetPageUrl(pageInfo_->GetPageUrl());
160     if (onPageShow_) {
161         onPageShow_();
162     }
163 }
164 
OnHide()165 void PagePattern::OnHide()
166 {
167     CHECK_NULL_VOID_NOLOG(isOnShow_);
168     JankFrameReport::FlushRecord();
169     auto host = GetHost();
170     CHECK_NULL_VOID(host);
171     host->SetJSViewActive(false);
172     isOnShow_ = false;
173     if (onPageHide_) {
174         onPageHide_();
175     }
176 }
177 
BuildSharedTransitionMap()178 void PagePattern::BuildSharedTransitionMap()
179 {
180     auto host = GetHost();
181     CHECK_NULL_VOID(host);
182     sharedTransitionMap_.clear();
183     IterativeAddToSharedMap(host, sharedTransitionMap_);
184 }
185 
ReloadPage()186 void PagePattern::ReloadPage()
187 {
188     auto host = GetHost();
189     CHECK_NULL_VOID(host);
190     auto customNode = DynamicCast<CustomNodeBase>(host->GetFirstChild());
191     CHECK_NULL_VOID(customNode);
192     customNode->FireReloadFunction(true);
193 }
194 
FindPageTransitionEffect(PageTransitionType type)195 RefPtr<PageTransitionEffect> PagePattern::FindPageTransitionEffect(PageTransitionType type)
196 {
197     RefPtr<PageTransitionEffect> result;
198     for (auto iter = pageTransitionEffects_.rbegin(); iter != pageTransitionEffects_.rend(); ++iter) {
199         auto effect = *iter;
200         if (effect->CanFit(type)) {
201             result = effect;
202             break;
203         }
204     }
205     return result;
206 }
207 
ClearPageTransitionEffect()208 void PagePattern::ClearPageTransitionEffect()
209 {
210     pageTransitionEffects_.clear();
211 }
212 
GetTopTransition() const213 RefPtr<PageTransitionEffect> PagePattern::GetTopTransition() const
214 {
215     return pageTransitionEffects_.empty() ? nullptr : pageTransitionEffects_.back();
216 }
217 
AddPageTransition(const RefPtr<PageTransitionEffect> & effect)218 void PagePattern::AddPageTransition(const RefPtr<PageTransitionEffect>& effect)
219 {
220     pageTransitionEffects_.emplace_back(effect);
221 }
222 
AddJsAnimator(const std::string & animatorId,const RefPtr<Framework::AnimatorInfo> & animatorInfo)223 void PagePattern::AddJsAnimator(const std::string& animatorId, const RefPtr<Framework::AnimatorInfo>& animatorInfo)
224 {
225     CHECK_NULL_VOID(animatorInfo);
226     auto animator = animatorInfo->GetAnimator();
227     CHECK_NULL_VOID(animator);
228     animator->AttachScheduler(PipelineContext::GetCurrentContext());
229     jsAnimatorMap_[animatorId] = animatorInfo;
230 }
231 
GetJsAnimator(const std::string & animatorId)232 RefPtr<Framework::AnimatorInfo> PagePattern::GetJsAnimator(const std::string& animatorId)
233 {
234     auto iter = jsAnimatorMap_.find(animatorId);
235     if (iter != jsAnimatorMap_.end()) {
236         return iter->second;
237     }
238     return nullptr;
239 }
240 
SetFirstBuildCallback(std::function<void ()> && buildCallback)241 void PagePattern::SetFirstBuildCallback(std::function<void()>&& buildCallback)
242 {
243     if (isFirstLoad_) {
244         firstBuildCallback_ = std::move(buildCallback);
245     } else if (buildCallback) {
246         buildCallback();
247     }
248 }
249 
FirePageTransitionFinish()250 void PagePattern::FirePageTransitionFinish()
251 {
252     if (pageTransitionFinish_) {
253         auto onFinish = *pageTransitionFinish_;
254         pageTransitionFinish_ = nullptr;
255         if (onFinish) {
256             onFinish();
257         }
258     }
259 }
260 
StopPageTransition()261 void PagePattern::StopPageTransition()
262 {
263     if (controller_ && !controller_->IsStopped()) {
264         controller_->Finish();
265         return;
266     }
267     FirePageTransitionFinish();
268 }
269 
BeforeCreateLayoutWrapper()270 void PagePattern::BeforeCreateLayoutWrapper()
271 {
272     auto pipeline = PipelineContext::GetCurrentContext();
273     CHECK_NULL_VOID(pipeline);
274     // SafeArea already applied to AppBar
275     if (pipeline->GetInstallationFree()) {
276         return;
277     }
278     auto host = GetHost();
279     CHECK_NULL_VOID(host);
280     auto safeArea = pipeline->GetSafeArea();
281     auto props = host->GetLayoutProperty();
282     if (safeArea.IsValid() || props->GetSafeAreaInsets()) {
283         props->UpdateSafeAreaInsets(safeArea);
284     }
285 }
286 } // namespace OHOS::Ace::NG
287