• 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/navigation/navigation_layout_algorithm.h"
17 
18 #include <cmath>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/log/ace_trace.h"
24 #include "base/memory/ace_type.h"
25 #include "base/utils/utils.h"
26 #include "core/common/container.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components_ng/base/frame_node.h"
29 #include "core/components_ng/layout/layout_algorithm.h"
30 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
31 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
32 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
33 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
34 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
35 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
36 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
37 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
38 #include "core/components_ng/property/calc_length.h"
39 #include "core/components_ng/property/layout_constraint.h"
40 #include "core/components_ng/property/measure_property.h"
41 #include "core/components_ng/property/measure_utils.h"
42 #include "core/pipeline_ng/pipeline_context.h"
43 
44 namespace OHOS::Ace::NG {
45 
46 constexpr static float HALF = 0.5f;
47 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
48 constexpr Dimension WINDOW_WIDTH = 520.0_vp;
49 
50 namespace {
51 constexpr NavigationMode INITIAL_MODE = NavigationMode::AUTO;
52 constexpr int32_t MODE_SWITCH_ANIMATION_DURATION = 500; // ms
53 const RefPtr<CubicCurve> MODE_SWITCH_CURVE = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.2f, 0.1f, 1.0f);
54 constexpr Dimension DIVIDER_DRAG_BAR_WIDTH = 12.0_vp;
55 constexpr Dimension DIVIDER_DRAG_BAR_HEIGHT = 48.0_vp;
56 constexpr Dimension DRAG_BAR_ITEM_WIDTH = 2.0_vp;
57 constexpr Dimension DRAG_BAR_ITEM_HEIGHT = 24.0_vp;
58 
MeasureDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)59 void MeasureDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
60     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
61 {
62     auto dividerNode = hostNode->GetDividerNode();
63     CHECK_NULL_VOID(dividerNode);
64     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
65     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
66     CHECK_NULL_VOID(dividerWrapper);
67     auto constraint = navigationLayoutProperty->CreateChildConstraint();
68     constraint.selfIdealSize = OptionalSizeF(dividerSize.Width(), dividerSize.Height());
69     dividerWrapper->Measure(constraint);
70 }
71 
MeasureDragBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)72 void MeasureDragBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
73     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
74 {
75     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
76     CHECK_NULL_VOID(navigationPattern);
77     auto dragNode = hostNode->GetDragBarNode();
78     CHECK_NULL_VOID(dragNode);
79     auto index = hostNode->GetChildIndexById(dragNode->GetId());
80     auto dargWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
81     CHECK_NULL_VOID(dargWrapper);
82     auto dragBarItem = AceType::DynamicCast<FrameNode>(dragNode->GetChildAtIndex(0));
83     CHECK_NULL_VOID(dragBarItem);
84     auto dragBarItemLayoutProperty = dragBarItem->GetLayoutProperty();
85     CHECK_NULL_VOID(dragBarItemLayoutProperty);
86     auto constraint = navigationLayoutProperty->CreateChildConstraint();
87     if (NearZero(dividerSize.Width()) || !navigationPattern->GetEnableDragBar()) {
88         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
89         dragBarItemLayoutProperty->UpdateUserDefinedIdealSize(
90             CalcSize(CalcLength(0.0f), CalcLength(0.0f)));
91     } else {
92         constraint.selfIdealSize = OptionalSizeF(static_cast<float>(DIVIDER_DRAG_BAR_WIDTH.ConvertToPx()),
93             static_cast<float>(DIVIDER_DRAG_BAR_HEIGHT.ConvertToPx()));
94         dragBarItemLayoutProperty->UpdateUserDefinedIdealSize(
95             CalcSize(CalcLength(DRAG_BAR_ITEM_WIDTH), CalcLength(DRAG_BAR_ITEM_HEIGHT)));
96     }
97     dargWrapper->Measure(constraint);
98 }
99 
LayoutDragBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)100 void LayoutDragBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
101     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
102 {
103     auto dargNode = hostNode->GetDragBarNode();
104     CHECK_NULL_VOID(dargNode);
105     auto index = hostNode->GetChildIndexById(dargNode->GetId());
106     auto dargWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
107     CHECK_NULL_VOID(dargWrapper);
108     auto geometryNode = dargWrapper->GetGeometryNode();
109     CHECK_NULL_VOID(geometryNode);
110     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
111     CHECK_NULL_VOID(navigationGeometryNode);
112     auto navigationWidth = navigationGeometryNode->GetFrameSize().Width();
113     auto navigationHeight = navigationGeometryNode->GetFrameSize().Height();
114     auto offsetX = navBarWidth - geometryNode->GetFrameSize().Width() * HALF;
115     auto offsetY = navigationHeight * HALF - geometryNode->GetFrameSize().Height() * HALF;
116     OffsetT<float> dragOffset = OffsetT<float>(offsetX, offsetY);
117     bool isNavBarInRight = (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
118         (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
119     if (isNavBarInRight) {
120         dragOffset.SetX(navigationWidth - navBarWidth - geometryNode->GetFrameSize().Width() * HALF);
121     }
122     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
123     dragOffset.AddX(padding.left.value_or(0.0f));
124     dragOffset.AddY(padding.top.value_or(0.0f));
125     geometryNode->SetMarginFrameOffset(dragOffset);
126     dargWrapper->Layout();
127 }
128 
LayoutNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const NavBarPosition & position,OffsetF & returnNavBarOffset)129 float LayoutNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
130     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const NavBarPosition& position,
131     OffsetF& returnNavBarOffset)
132 {
133     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
134     bool isZeroNavbarWidth = false;
135     if (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
136         navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
137         isZeroNavbarWidth = true;
138     }
139     auto contentNode = hostNode->GetContentNode();
140     CHECK_NULL_RETURN(contentNode, 0.0f);
141     auto navBarNode = hostNode->GetNavBarNode();
142     CHECK_NULL_RETURN(navBarNode, 0.0f);
143     auto index = hostNode->GetChildIndexById(navBarNode->GetId());
144     auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
145     CHECK_NULL_RETURN(navBarWrapper, 0.0f);
146     auto geometryNode = navBarWrapper->GetGeometryNode();
147     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
148     auto navBarOffset = OffsetT<float>(0.0f, 0.0f);
149     bool isNavBarInRight = (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
150         (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
151     if (isNavBarInRight) {
152         navBarOffset.SetX(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width());
153     }
154     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
155     navBarOffset.AddX(padding.left.value_or(0.0f));
156     navBarOffset.AddY(padding.top.value_or(0.0f));
157     geometryNode->SetMarginFrameOffset(navBarOffset);
158     navBarWrapper->Layout();
159     returnNavBarOffset = navBarOffset;
160     return isZeroNavbarWidth ? 0.0f : geometryNode->GetFrameSize().Width();
161 }
162 
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)163 float LayoutDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
164     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
165 {
166     auto dividerNode = hostNode->GetDividerNode();
167     CHECK_NULL_RETURN(dividerNode, 0.0f);
168     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
169     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
170     CHECK_NULL_RETURN(dividerWrapper, 0.0f);
171     auto geometryNode = dividerWrapper->GetGeometryNode();
172     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
173     auto dividerOffsetX = navBarWidth;
174     if (position == NavBarPosition::END) {
175         dividerOffsetX =
176             navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - dividerOffsetX;
177     }
178     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
179         dividerOffsetX =
180             navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - dividerOffsetX;
181     }
182     OffsetT<float> dividerOffset = OffsetT<float>(dividerOffsetX, 0.0f);
183     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
184     dividerOffset.AddX(padding.left.value_or(0));
185     dividerOffset.AddY(padding.top.value_or(0));
186     geometryNode->SetMarginFrameOffset(dividerOffset);
187     dividerWrapper->Layout();
188     return geometryNode->GetFrameSize().Width();
189 }
190 
LayoutContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth,const NavBarPosition & position)191 void LayoutContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
192     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth,
193     const NavBarPosition& position)
194 {
195     auto contentNode = hostNode->GetContentNode();
196     CHECK_NULL_VOID(contentNode);
197     auto index = hostNode->GetChildIndexById(contentNode->GetId());
198     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
199     CHECK_NULL_VOID(contentWrapper);
200     auto geometryNode = contentWrapper->GetGeometryNode();
201     CHECK_NULL_VOID(geometryNode);
202 
203     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
204     auto contentChildSize = contentNode->GetChildren().size();
205 
206     // cases that content layouts from start
207     // 1. displaying content pages in STACK mode
208     // 2. placing navBar at the end
209     // 3. hiding navBar in SPLIT mode
210     auto contentOffset = OffsetT<float>(0.0f, 0.0f);
211     if ((contentChildSize != 0 && navigationPattern->GetNavigationMode() == NavigationMode::STACK) ||
212         position == NavBarPosition::END ||
213         (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
214             navigationPattern->GetNavigationMode() == NavigationMode::SPLIT)) {
215         if (AceApplicationInfo::GetInstance().IsRightToLeft() &&
216             navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
217             contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
218         }
219         const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
220         contentOffset.AddX(padding.left.value_or(0));
221         contentOffset.AddY(padding.top.value_or(0));
222         geometryNode->SetMarginFrameOffset(contentOffset);
223         contentWrapper->Layout();
224         return;
225     }
226     if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
227         contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
228     }
229     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
230     contentOffset.AddX(padding.left.value_or(0));
231     contentOffset.AddY(padding.top.value_or(0));
232     geometryNode->SetMarginFrameOffset(contentOffset);
233     contentWrapper->Layout();
234 }
235 
FitScrollFullWindow(SizeF & frameSize)236 void FitScrollFullWindow(SizeF& frameSize)
237 {
238     auto pipeline = PipelineContext::GetCurrentContext();
239     CHECK_NULL_VOID(pipeline);
240     if (frameSize.Width() == Infinity<float>()) {
241         frameSize.SetWidth(pipeline->GetRootWidth());
242     }
243     if (frameSize.Height() == Infinity<float>()) {
244         frameSize.SetHeight(pipeline->GetRootHeight());
245     }
246 }
247 
SwitchModeWithAnimation(const RefPtr<NavigationGroupNode> & hostNode)248 void SwitchModeWithAnimation(const RefPtr<NavigationGroupNode>& hostNode)
249 {
250     CHECK_NULL_VOID(hostNode);
251     hostNode->SetDoingModeSwitchAnimationFlag(true);
252     hostNode->SetNeedSetInvisible(false);
253     AnimationOption option;
254     option.SetCurve(MODE_SWITCH_CURVE);
255     option.SetFillMode(FillMode::FORWARDS);
256     option.SetDuration(MODE_SWITCH_ANIMATION_DURATION);
257     option.SetOnFinishEvent([weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
258         auto hostNode = weakHost.Upgrade();
259         CHECK_NULL_VOID(hostNode);
260         hostNode->ReduceModeSwitchAnimationCnt();
261         if (hostNode->GetModeSwitchAnimationCnt() == 0) {
262             auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
263             CHECK_NULL_VOID(dividerNode);
264             auto layoutProperty = dividerNode->GetLayoutProperty();
265             CHECK_NULL_VOID(layoutProperty);
266             layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
267             auto pattern = hostNode->GetPattern<NavigationPattern>();
268             CHECK_NULL_VOID(pattern);
269             auto lastStandardIndex = hostNode->GetLastStandardIndex();
270             auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
271             CHECK_NULL_VOID(navigationLayoutProperty);
272             bool navbarIsHidden = (pattern->GetNavigationMode() == NavigationMode::STACK && lastStandardIndex >= 0) ||
273                                   navigationLayoutProperty->GetHideNavBar().value_or(false);
274             if (navbarIsHidden) {
275                 hostNode->SetNeedSetInvisible(true);
276             } else {
277                 hostNode->SetNeedSetInvisible(false);
278             }
279             hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
280         }
281     });
282     AnimationUtils::Animate(option, [weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
283         auto hostNode = weakHost.Upgrade();
284         CHECK_NULL_VOID(hostNode);
285         auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
286         CHECK_NULL_VOID(dividerNode);
287         auto layoutProperty = dividerNode->GetLayoutProperty();
288         CHECK_NULL_VOID(layoutProperty);
289         layoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
290         hostNode->IncreaseModeSwitchAnimationCnt();
291         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
292         hostNode->GetContext()->FlushUITasks();
293         hostNode->SetDoingModeSwitchAnimationFlag(false);
294     }, option.GetOnFinishEvent());
295 }
296 
297 } // namespace
298 
IsAutoHeight(const RefPtr<LayoutProperty> & layoutProperty)299 bool NavigationLayoutAlgorithm::IsAutoHeight(const RefPtr<LayoutProperty>& layoutProperty)
300 {
301     CHECK_NULL_RETURN(layoutProperty, false);
302     auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
303     if (!calcLayoutConstraint || !calcLayoutConstraint->selfIdealSize.has_value() ||
304         !calcLayoutConstraint->selfIdealSize->Height().has_value() ||
305         (calcLayoutConstraint->selfIdealSize->Height().value().ToString().find("auto") == std::string::npos)) {
306         return false;
307     }
308     return true;
309 }
310 
RangeCalculation(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)311 void NavigationLayoutAlgorithm::RangeCalculation(
312     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
313 {
314     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
315     CHECK_NULL_VOID(constraint);
316     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
317     auto frameSize = parentSize.ConvertToSizeT();
318     float frameSizeWidth = frameSize.Width();
319     Dimension defaultValue = Dimension(-1.0);
320     auto pipeline = PipelineContext::GetCurrentContext();
321     CHECK_NULL_VOID(pipeline);
322 
323     minContentWidthValue_ = navigationLayoutProperty->GetMinContentWidthValue(defaultValue);
324     if (minContentWidthValue_ == defaultValue) {
325         userSetMinContentFlag_ = false;
326         minContentWidthValue_ = DEFAULT_MIN_CONTENT_WIDTH;
327     } else {
328         userSetMinContentFlag_ = true;
329     }
330     minNavBarWidthValue_ = navigationLayoutProperty->GetMinNavBarWidthValue(DEFAULT_MIN_NAV_BAR_WIDTH);
331     auto userSetMaxNavBarWidthValue = navigationLayoutProperty->GetMaxNavBarWidthValue(defaultValue);
332 
333     float minNavBarWidth =
334         std::min(static_cast<float>(minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f))),
335             frameSizeWidth);
336     float maxNavBarWidth = 0.0f;
337     if (userSetMaxNavBarWidthValue == defaultValue) {
338         userSetNavBarRangeFlag_ = false;
339         maxNavBarWidth = std::min(
340             static_cast<float>(DEFAULT_MAX_NAV_BAR_WIDTH.ConvertToPx()), frameSizeWidth * MAX_NAV_BAR_WIDTH_SCALE);
341     } else {
342         userSetNavBarRangeFlag_ = true;
343         maxNavBarWidth =
344             static_cast<float>(userSetMaxNavBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f)));
345     }
346     maxNavBarWidthValue_ = Dimension(Dimension(std::max(maxNavBarWidth, minNavBarWidth)).ConvertToVp(),
347         DimensionUnit::VP);
348     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
349     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
350         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
351         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
352         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
353         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
354     }
355     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
356     CHECK_NULL_VOID(navigationPattern);
357     navigationPattern->SetMinNavBarWidthValue(minNavBarWidthValue_);
358     navigationPattern->SetMaxNavBarWidthValue(maxNavBarWidthValue_);
359     navigationPattern->SetMinContentWidthValue(minContentWidthValue_);
360     navigationPattern->SetUserSetNavBarRangeFlag(userSetNavBarRangeFlag_);
361     navigationPattern->SetUserSetMinContentFlag(userSetMinContentFlag_);
362 }
363 
GetRange(const RefPtr<NavigationGroupNode> & hostNode)364 void NavigationLayoutAlgorithm::GetRange(const RefPtr<NavigationGroupNode>& hostNode)
365 {
366     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
367     CHECK_NULL_VOID(navigationPattern);
368     minNavBarWidthValue_ = navigationPattern->GetMinNavBarWidthValue();
369     maxNavBarWidthValue_ = navigationPattern->GetMaxNavBarWidthValue();
370     minContentWidthValue_ = navigationPattern->GetMinContentWidthValue();
371     userSetNavBarRangeFlag_ = navigationPattern->GetUserSetNavBarRangeFlag();
372     userSetMinContentFlag_ = navigationPattern->GetUserSetMinContentFlag();
373     userSetNavBarWidthFlag_ = navigationPattern->GetUserSetNavBarWidthFlag();
374 }
375 
CalculateNavigationWidth(const RefPtr<NavigationGroupNode> & hostNode)376 float NavigationLayoutAlgorithm::CalculateNavigationWidth(const RefPtr<NavigationGroupNode>& hostNode)
377 {
378     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
379     auto pipeline = hostNode->GetContext();
380     CHECK_NULL_RETURN(pipeline, 0.0f);
381     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
382     auto navigationWidth = 0.0f;
383     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
384         CHECK_NULL_RETURN(navigationLayoutProperty, navigationWidth);
385         const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
386         auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
387         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
388         navigationWidth = static_cast<float>(minNavBarWidth + minContentWidthValue_.ConvertToPx());
389     } else {
390         navigationWidth = static_cast<float>(WINDOW_WIDTH.ConvertToPx());
391     }
392     return navigationWidth;
393 }
394 
UpdateNavigationMode(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize,const RefPtr<NavigationGroupNode> & hostNode)395 void NavigationLayoutAlgorithm::UpdateNavigationMode(const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
396     const SizeF& frameSize, const RefPtr<NavigationGroupNode>& hostNode)
397 {
398     CHECK_NULL_VOID(hostNode);
399     CHECK_NULL_VOID(navigationLayoutProperty);
400     auto usrNavigationMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
401     if (usrNavigationMode == NavigationMode::AUTO) {
402         if (frameSize.Width() >= CalculateNavigationWidth(hostNode)) {
403             usrNavigationMode = NavigationMode::SPLIT;
404             auto navBarNode = hostNode->GetNavBarNode();
405             if (navBarNode) {
406                 navBarNode->SetJSViewActive(true);
407             }
408         } else {
409             usrNavigationMode = NavigationMode::STACK;
410         }
411     }
412     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
413     bool modeChange = navigationPattern->GetNavigationMode() != usrNavigationMode;
414     bool isFirstTimeLayout = (navigationPattern->GetNavigationMode() == INITIAL_MODE);
415     bool enableModeChangeAnimation = navigationLayoutProperty->GetEnableModeChangeAnimation().value_or(true);
416     bool doModeSwitchAnimationInAnotherTask =
417         enableModeChangeAnimation && modeChange && !isFirstTimeLayout && !hostNode->IsOnModeSwitchAnimation();
418     if (doModeSwitchAnimationInAnotherTask) {
419         auto container = Container::Current();
420         CHECK_NULL_VOID(container);
421         if (container->IsFoldable()) {
422             // If screen-fold-state changed, no need to do mode switch animation.
423             // Only when navigation-mode changed, it is necessary to update the current screen-fold-state.
424             doModeSwitchAnimationInAnotherTask =
425                 !navigationPattern->JudgeFoldStateChangeAndUpdateState() && doModeSwitchAnimationInAnotherTask;
426         }
427     }
428     if (!doModeSwitchAnimationInAnotherTask) {
429         navigationPattern->SetNavigationMode(usrNavigationMode);
430         navigationPattern->SetNavigationModeChange(modeChange);
431     }
432 
433     auto pipeline = hostNode->GetContext();
434     CHECK_NULL_VOID(pipeline);
435     pipeline->AddAfterLayoutTask([weakNavigationPattern = WeakPtr<NavigationPattern>(navigationPattern),
436         modeChange, doModeSwitchAnimationInAnotherTask]() {
437         auto navigationPattern = weakNavigationPattern.Upgrade();
438         CHECK_NULL_VOID(navigationPattern);
439         if (doModeSwitchAnimationInAnotherTask) {
440             navigationPattern->OnNavBarStateChange(false);
441             SwitchModeWithAnimation(AceType::DynamicCast<NavigationGroupNode>(navigationPattern->GetHost()));
442         } else {
443             navigationPattern->OnNavBarStateChange(modeChange);
444             navigationPattern->OnNavigationModeChange(modeChange);
445         }
446     });
447 }
448 
SizeCalculation(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)449 void NavigationLayoutAlgorithm::SizeCalculation(LayoutWrapper* layoutWrapper,
450     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
451     const SizeF& frameSize)
452 {
453     auto pipeline = PipelineContext::GetCurrentContext();
454     CHECK_NULL_VOID(pipeline);
455     auto constraint = navigationLayoutProperty->GetLayoutConstraint();
456     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
457     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
458     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
459     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
460         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
461         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
462         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
463         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
464     } else {
465         auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
466         auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
467         realNavBarWidth_ = navBarWidth;
468     }
469     navBarSize_ = frameSize;
470     contentSize_ = frameSize;
471     dividerSize_ = SizeF(0.0f, frameSize.Height());
472     if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
473         SizeCalculationSplit(hostNode, navigationLayoutProperty, frameSize);
474     } else {
475         SizeCalculationStack(hostNode, navigationLayoutProperty, frameSize);
476     }
477 }
478 
SizeCalculationSplit(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)479 void NavigationLayoutAlgorithm::SizeCalculationSplit(const RefPtr<NavigationGroupNode>& hostNode,
480     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
481 {
482     float frameWidth = frameSize.Width();
483     auto parentSize = CreateIdealSizeByPercentRef(
484         navigationLayoutProperty->GetLayoutConstraint().value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
485     auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
486     auto userSetNavBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
487     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
488     auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
489     auto minContentWidth = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
490     realContentWidth_ = minContentWidth;
491 
492     bool isHideNavbar = navigationLayoutProperty->GetHideNavBar().value_or(false);
493     if (isHideNavbar) {
494         CHECK_NULL_VOID(hostNode);
495         auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
496         CHECK_NULL_VOID(navBarNode);
497         auto geometryNode = navBarNode->GetGeometryNode();
498         CHECK_NULL_VOID(geometryNode);
499         navBarSize_.SetWidth(geometryNode->GetFrameSize().Width());
500         dividerSize_.SetWidth(0.0f);
501         realNavBarWidth_ = 0.0f;
502         realContentWidth_ = frameWidth;
503     } else {
504         CheckSizeInSplit(frameWidth, userSetNavBarWidth, minNavBarWidth, minContentWidth);
505     }
506 
507     realDividerWidth_ = std::max(realDividerWidth_, 0.0f);
508     realContentWidth_ = std::max(realContentWidth_, 0.0f);
509     realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
510     realContentWidth_ = std::min(realContentWidth_, frameWidth);
511     if (realNavBarWidth_ == 0.0f || realContentWidth_ == 0.0f) {
512         realDividerWidth_ = 0.0f;
513     } else {
514         realDividerWidth_ = dividerWidth;
515     }
516     if (!isHideNavbar) {
517         navBarSize_.SetWidth(realNavBarWidth_);
518         dividerSize_.SetWidth(realDividerWidth_);
519     }
520     contentSize_.SetWidth(realContentWidth_);
521 }
522 
CheckSizeInSplit(const float frameWidth,const float userSetNavBarWidth,const float minNavBarWidth,const float minContentWidth)523 void NavigationLayoutAlgorithm::CheckSizeInSplit(
524     const float frameWidth, const float userSetNavBarWidth, const float minNavBarWidth, const float minContentWidth)
525 {
526     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
527 
528     if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
529         if (minContentWidth >= frameWidth) {
530             realContentWidth_ = frameWidth;
531             realNavBarWidth_ = 0.0f;
532         } else if (realNavBarWidth_ + dividerWidth + minContentWidth <= frameWidth) {
533             realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
534         } else {
535             realContentWidth_ = minContentWidth;
536             realNavBarWidth_ = frameWidth - realContentWidth_ - dividerWidth;
537         }
538     } else if (!userSetNavBarRangeFlag_ && !userSetMinContentFlag_ && userSetNavBarWidthFlag_) {
539         realNavBarWidth_ = userSetNavBarWidth;
540         realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
541     } else {
542         float remainingSpace = frameWidth - realNavBarWidth_ - dividerWidth;
543         float remainingMaxSpace = frameWidth - minNavBarWidth - dividerWidth;
544         if (remainingSpace >= minContentWidth) {
545             realContentWidth_ = remainingSpace;
546         } else if (remainingSpace < minContentWidth && remainingMaxSpace > minContentWidth &&
547                    realNavBarWidth_ > minNavBarWidth) {
548             realContentWidth_ = minContentWidth;
549             realNavBarWidth_ = frameWidth - minContentWidth - dividerWidth;
550         } else {
551             realNavBarWidth_ = minNavBarWidth;
552             realContentWidth_ = frameWidth - minNavBarWidth - dividerWidth;
553         }
554     }
555 }
556 
SizeCalculationStack(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)557 void NavigationLayoutAlgorithm::SizeCalculationStack(const RefPtr<NavigationGroupNode>& hostNode,
558     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
559 {
560     auto contentNode = hostNode->GetContentNode();
561     CHECK_NULL_VOID(contentNode);
562     realDividerWidth_ = 0.0f;
563     float frameWidth = frameSize.Width();
564     navBarSize_.SetWidth(frameWidth);
565     dividerSize_.SetWidth(realDividerWidth_);
566     contentSize_.SetWidth(frameWidth);
567     realContentWidth_ = frameWidth;
568 }
569 
MeasureNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & navBarSize)570 void NavigationLayoutAlgorithm::MeasureNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
571     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& navBarSize)
572 {
573     auto navBarNode = hostNode->GetNavBarNode();
574     CHECK_NULL_VOID(navBarNode);
575     auto index = hostNode->GetChildIndexById(navBarNode->GetId());
576     auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
577     CHECK_NULL_VOID(navBarWrapper);
578     auto constraint = navigationLayoutProperty->CreateChildConstraint();
579     if (IsAutoHeight(navigationLayoutProperty)) {
580         navBarWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
581             navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
582         constraint.selfIdealSize.SetWidth(navBarSize.Width());
583     } else {
584         constraint.selfIdealSize = OptionalSizeF(navBarSize.Width(), navBarSize.Height());
585     }
586     navBarWrapper->Measure(constraint);
587     realNavBarHeight_ = navBarWrapper->GetGeometryNode()->GetFrameSize().Height();
588 }
589 
MeasureContentChild(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & contentSize)590 void NavigationLayoutAlgorithm::MeasureContentChild(LayoutWrapper* layoutWrapper,
591     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
592     const SizeF& contentSize)
593 {
594     auto contentNode = hostNode->GetContentNode();
595     CHECK_NULL_VOID(contentNode);
596     auto index = hostNode->GetChildIndexById(contentNode->GetId());
597     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
598     CHECK_NULL_VOID(contentWrapper);
599     auto constraint = navigationLayoutProperty->CreateChildConstraint();
600     if (contentNode->GetChildren().empty()) {
601         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
602     } else {
603         if (IsAutoHeight(navigationLayoutProperty)) {
604             constraint.selfIdealSize.SetWidth(contentSize.Width());
605         } else {
606             constraint.selfIdealSize = OptionalSizeF(contentSize.Width(), contentSize.Height());
607         }
608     }
609     contentWrapper->Measure(constraint);
610     realContentHeight_ = contentWrapper->GetGeometryNode()->GetFrameSize().Height();
611 }
612 
Measure(LayoutWrapper * layoutWrapper)613 void NavigationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
614 {
615     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
616     CHECK_NULL_VOID(hostNode);
617     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
618     CHECK_NULL_VOID(navigationLayoutProperty);
619     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
620     CHECK_NULL_VOID(constraint);
621     auto geometryNode = layoutWrapper->GetGeometryNode();
622     auto size =
623         CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT).ConvertToSizeT();
624     FitScrollFullWindow(size);
625 
626     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
627     MinusPaddingToSize(padding, size);
628 
629     if (ifNeedInit_) {
630         RangeCalculation(hostNode, navigationLayoutProperty);
631     }
632     if (size.Width() == 0.0f) {
633         auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
634         if (layoutAlgorithm) {
635             layoutAlgorithm->SetSkipLayout();
636         }
637         return;
638     }
639     GetRange(hostNode);
640     UpdateNavigationMode(navigationLayoutProperty, size, hostNode);
641     SizeCalculation(layoutWrapper, hostNode, navigationLayoutProperty, size);
642 
643     MeasureNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
644     MeasureContentChild(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
645     MeasureDivider(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
646     MeasureDragBar(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
647 
648     if (IsAutoHeight(navigationLayoutProperty)) {
649         SetNavigationHeight(layoutWrapper, size);
650     }
651     size.AddWidth(padding.left.value_or(0.0f) + padding.right.value_or(0.0f));
652     size.AddHeight(padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f));
653     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
654 }
655 
Layout(LayoutWrapper * layoutWrapper)656 void NavigationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
657 {
658     auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
659     if (layoutAlgorithm && layoutAlgorithm->SkipLayout()) {
660         return;
661     }
662     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
663     CHECK_NULL_VOID(hostNode);
664     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
665     CHECK_NULL_VOID(navigationLayoutProperty);
666     auto navBarPosition = navigationLayoutProperty->GetNavBarPositionValue(NavBarPosition::START);
667     OffsetF navBarOffset(0.0, 0.0);
668     float navBarWidth = LayoutNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
669     float dividerWidth = LayoutDivider(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, navBarPosition);
670     LayoutContent(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, dividerWidth, navBarPosition);
671     LayoutDragBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, navBarPosition);
672 
673     auto&& opts = navigationLayoutProperty->GetSafeAreaExpandOpts();
674     if (opts) {
675         auto geometryNode = hostNode->GetGeometryNode();
676         CHECK_NULL_VOID(geometryNode);
677         TAG_LOGD(AceLogTag::ACE_NAVIGATION,
678             "Navigation id is %{public}d, frameRect is %{public}s",
679             hostNode->GetId(), geometryNode->GetFrameRect().ToString().c_str());
680     }
681 }
682 
SetNavigationHeight(LayoutWrapper * layoutWrapper,SizeF & size)683 void NavigationLayoutAlgorithm::SetNavigationHeight(LayoutWrapper* layoutWrapper, SizeF& size)
684 {
685     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
686     CHECK_NULL_VOID(hostNode);
687     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
688     CHECK_NULL_VOID(navigationPattern);
689     auto navigationStack = navigationPattern->GetNavigationStack();
690     CHECK_NULL_VOID(navigationStack);
691     if (navigationStack->Empty()) {
692         size.SetHeight(realNavBarHeight_);
693     } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
694         size.SetHeight(realContentHeight_);
695     } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
696         float navHeight = std::max(realContentHeight_, realNavBarHeight_);
697         size.SetHeight(navHeight);
698     }
699 }
700 
701 } // namespace OHOS::Ace::NG
702