• 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/components/common/layout/constants.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/layout/layout_algorithm.h"
29 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
30 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
31 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
32 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
33 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
34 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
35 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
36 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
37 #include "core/components_ng/property/calc_length.h"
38 #include "core/components_ng/property/layout_constraint.h"
39 #include "core/components_ng/property/measure_property.h"
40 #include "core/components_ng/property/measure_utils.h"
41 #include "core/pipeline_ng/pipeline_context.h"
42 
43 namespace OHOS::Ace::NG {
44 
45 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
46 constexpr Dimension WINDOW_WIDTH = 520.0_vp;
47 
48 namespace {
49 
MeasureDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)50 void MeasureDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
51     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
52 {
53     auto dividerNode = hostNode->GetDividerNode();
54     CHECK_NULL_VOID(dividerNode);
55     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
56     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
57     CHECK_NULL_VOID(dividerWrapper);
58     auto constraint = navigationLayoutProperty->CreateChildConstraint();
59     constraint.selfIdealSize = OptionalSizeF(dividerSize.Width(), dividerSize.Height());
60     dividerWrapper->Measure(constraint);
61 }
62 
LayoutNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const NavBarPosition & position,OffsetF & returnNavBarOffset)63 float LayoutNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
64     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const NavBarPosition& position,
65     OffsetF& returnNavBarOffset)
66 {
67     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
68     if (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
69         navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
70         return 0.0f;
71     }
72     auto contentNode = hostNode->GetContentNode();
73     CHECK_NULL_RETURN(contentNode, 0.0f);
74     auto navBarNode = hostNode->GetNavBarNode();
75     CHECK_NULL_RETURN(navBarNode, 0.0f);
76     auto index = hostNode->GetChildIndexById(navBarNode->GetId());
77     auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
78     CHECK_NULL_RETURN(navBarWrapper, 0.0f);
79     auto geometryNode = navBarWrapper->GetGeometryNode();
80     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
81     if (position == NavBarPosition::END) {
82         auto navBarOffset =
83             OffsetT<float>(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width(),
84                 geometryNode->GetFrameOffset().GetY());
85         const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
86         navBarOffset.AddX(padding.left.value_or(0));
87         navBarOffset.AddY(padding.top.value_or(0));
88         geometryNode->SetMarginFrameOffset(navBarOffset);
89         navBarWrapper->Layout();
90         returnNavBarOffset = navBarOffset;
91         return geometryNode->GetFrameSize().Width();
92     }
93     auto navBarOffset = OffsetT<float>(0.0f, 0.0f);
94     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
95     navBarOffset.AddX(padding.left.value_or(0));
96     navBarOffset.AddY(padding.top.value_or(0));
97     geometryNode->SetMarginFrameOffset(navBarOffset);
98     navBarWrapper->Layout();
99     returnNavBarOffset = navBarOffset;
100     return geometryNode->GetFrameSize().Width();
101 }
102 
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)103 float LayoutDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
104     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
105 {
106     auto dividerNode = hostNode->GetDividerNode();
107     CHECK_NULL_RETURN(dividerNode, 0.0f);
108     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
109     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
110     CHECK_NULL_RETURN(dividerWrapper, 0.0f);
111     auto geometryNode = dividerWrapper->GetGeometryNode();
112     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
113     OffsetT<float> dividerOffset;
114     if (position == NavBarPosition::END) {
115         dividerOffset = OffsetT<float>(
116             navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - navBarWidth, 0.0f);
117     } else {
118         dividerOffset = OffsetT<float>(navBarWidth, 0.0f);
119     }
120     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
121     dividerOffset.AddX(padding.left.value_or(0));
122     dividerOffset.AddY(padding.top.value_or(0));
123     geometryNode->SetMarginFrameOffset(dividerOffset);
124     dividerWrapper->Layout();
125     return geometryNode->GetFrameSize().Width();
126 }
127 
LayoutContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth,const NavBarPosition & position)128 void LayoutContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
129     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth,
130     const NavBarPosition& position)
131 {
132     auto contentNode = hostNode->GetContentNode();
133     CHECK_NULL_VOID(contentNode);
134     auto index = hostNode->GetChildIndexById(contentNode->GetId());
135     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
136     CHECK_NULL_VOID(contentWrapper);
137     auto geometryNode = contentWrapper->GetGeometryNode();
138     CHECK_NULL_VOID(geometryNode);
139 
140     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
141     auto contentChildSize = contentNode->GetChildren().size();
142 
143     // cases that content layouts from start
144     // 1. displaying content pages in STACK mode
145     // 2. placing navBar at the end
146     // 3. hiding navBar in SPLIT mode
147     auto contentOffset = OffsetT<float>(0.0f, 0.0f);
148     if ((contentChildSize != 0 && navigationPattern->GetNavigationMode() == NavigationMode::STACK) ||
149         position == NavBarPosition::END ||
150         (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
151             navigationPattern->GetNavigationMode() == NavigationMode::SPLIT)) {
152         const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
153         contentOffset.AddX(padding.left.value_or(0));
154         contentOffset.AddY(padding.top.value_or(0));
155         geometryNode->SetMarginFrameOffset(contentOffset);
156         contentWrapper->Layout();
157         return;
158     }
159     contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
160     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
161     contentOffset.AddX(padding.left.value_or(0));
162     contentOffset.AddY(padding.top.value_or(0));
163     geometryNode->SetMarginFrameOffset(contentOffset);
164     contentWrapper->Layout();
165 }
166 
FitScrollFullWindow(SizeF & frameSize)167 void FitScrollFullWindow(SizeF& frameSize)
168 {
169     auto pipeline = PipelineContext::GetCurrentContext();
170     CHECK_NULL_VOID(pipeline);
171     if (frameSize.Width() == Infinity<float>()) {
172         frameSize.SetWidth(pipeline->GetRootWidth());
173     }
174     if (frameSize.Height() == Infinity<float>()) {
175         frameSize.SetHeight(pipeline->GetRootHeight());
176     }
177 }
178 
179 } // namespace
180 
IsAutoHeight(const RefPtr<LayoutProperty> & layoutProperty)181 bool NavigationLayoutAlgorithm::IsAutoHeight(const RefPtr<LayoutProperty>& layoutProperty)
182 {
183     CHECK_NULL_RETURN(layoutProperty, false);
184     auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
185     if (!calcLayoutConstraint || !calcLayoutConstraint->selfIdealSize.has_value() ||
186         !calcLayoutConstraint->selfIdealSize->Height().has_value() ||
187         (calcLayoutConstraint->selfIdealSize->Height().value().ToString().find("auto") == std::string::npos)) {
188         return false;
189     }
190     return true;
191 }
192 
RangeCalculation(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)193 void NavigationLayoutAlgorithm::RangeCalculation(
194     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
195 {
196     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
197     CHECK_NULL_VOID(constraint);
198     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
199     auto frameSize = parentSize.ConvertToSizeT();
200     float frameSizeWidth = frameSize.Width();
201     Dimension defaultValue = Dimension(-1.0);
202     auto pipeline = PipelineContext::GetCurrentContext();
203     CHECK_NULL_VOID(pipeline);
204 
205     minContentWidthValue_ = navigationLayoutProperty->GetMinContentWidthValue(defaultValue);
206     if (minContentWidthValue_ == defaultValue) {
207         userSetMinContentFlag_ = false;
208         minContentWidthValue_ = DEFAULT_MIN_CONTENT_WIDTH;
209     } else {
210         userSetMinContentFlag_ = true;
211     }
212     minNavBarWidthValue_ = navigationLayoutProperty->GetMinNavBarWidthValue(DEFAULT_MIN_NAV_BAR_WIDTH);
213     auto userSetMaxNavBarWidthValue = navigationLayoutProperty->GetMaxNavBarWidthValue(defaultValue);
214 
215     float minNavBarWidth =
216         std::min(static_cast<float>(minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f))),
217             frameSizeWidth);
218     float maxNavBarWidth = 0.0f;
219     if (userSetMaxNavBarWidthValue == defaultValue) {
220         userSetNavBarRangeFlag_ = false;
221         maxNavBarWidth = std::min(
222             static_cast<float>(DEFAULT_MAX_NAV_BAR_WIDTH.ConvertToPx()), frameSizeWidth * MAX_NAV_BAR_WIDTH_SCALE);
223     } else {
224         userSetNavBarRangeFlag_ = true;
225         maxNavBarWidth =
226             static_cast<float>(userSetMaxNavBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f)));
227     }
228     maxNavBarWidthValue_ = Dimension(Dimension(std::max(maxNavBarWidth, minNavBarWidth)).ConvertToVp(),
229         DimensionUnit::VP);
230     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
231     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
232         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
233         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
234         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
235         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
236     }
237     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
238     CHECK_NULL_VOID(navigationPattern);
239     navigationPattern->SetMinNavBarWidthValue(minNavBarWidthValue_);
240     navigationPattern->SetMaxNavBarWidthValue(maxNavBarWidthValue_);
241     navigationPattern->SetMinContentWidthValue(minContentWidthValue_);
242     navigationPattern->SetUserSetNavBarRangeFlag(userSetNavBarRangeFlag_);
243     navigationPattern->SetUserSetMinContentFlag(userSetMinContentFlag_);
244 }
245 
GetRange(const RefPtr<NavigationGroupNode> & hostNode)246 void NavigationLayoutAlgorithm::GetRange(const RefPtr<NavigationGroupNode>& hostNode)
247 {
248     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
249     CHECK_NULL_VOID(navigationPattern);
250     minNavBarWidthValue_ = navigationPattern->GetMinNavBarWidthValue();
251     maxNavBarWidthValue_ = navigationPattern->GetMaxNavBarWidthValue();
252     minContentWidthValue_ = navigationPattern->GetMinContentWidthValue();
253     userSetNavBarRangeFlag_ = navigationPattern->GetUserSetNavBarRangeFlag();
254     userSetMinContentFlag_ = navigationPattern->GetUserSetMinContentFlag();
255     userSetNavBarWidthFlag_ = navigationPattern->GetUserSetNavBarWidthFlag();
256 }
257 
UpdateNavigationMode(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize,const RefPtr<NavigationGroupNode> & hostNode)258 void NavigationLayoutAlgorithm::UpdateNavigationMode(const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
259     const SizeF& frameSize, const RefPtr<NavigationGroupNode>& hostNode)
260 {
261     auto usrNavigationMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
262     auto pipeline = PipelineContext::GetCurrentContext();
263     CHECK_NULL_VOID(pipeline);
264     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
265 
266     auto navigationWidth = 0.0f;
267     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
268         const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
269         CHECK_NULL_VOID(constraint);
270         auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
271         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
272         navigationWidth = static_cast<float>(minNavBarWidth + minContentWidthValue_.ConvertToPx());
273     } else {
274         navigationWidth = static_cast<float>(WINDOW_WIDTH.ConvertToPx());
275     }
276     if (usrNavigationMode == NavigationMode::AUTO) {
277         if (frameSize.Width() >= navigationWidth) {
278             usrNavigationMode = NavigationMode::SPLIT;
279             auto navBarNode = hostNode->GetNavBarNode();
280             if (navBarNode) {
281                 navBarNode->SetJSViewActive(true);
282             }
283         } else {
284             usrNavigationMode = NavigationMode::STACK;
285         }
286     }
287     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
288     bool modeChange = navigationPattern->GetNavigationMode() != usrNavigationMode;
289     navigationPattern->SetNavigationMode(usrNavigationMode);
290 
291     navigationPattern->SetNavigationModeChange(modeChange);
292     navigationPattern->OnNavBarStateChange(modeChange);
293     navigationPattern->OnNavigationModeChange(modeChange);
294 }
295 
SizeCalculation(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)296 void NavigationLayoutAlgorithm::SizeCalculation(LayoutWrapper* layoutWrapper,
297     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
298     const SizeF& frameSize)
299 {
300     auto pipeline = PipelineContext::GetCurrentContext();
301     CHECK_NULL_VOID(pipeline);
302     auto constraint = navigationLayoutProperty->GetLayoutConstraint();
303     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
304     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
305     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
306     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
307         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
308         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
309         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
310         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
311     } else {
312         auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
313         auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
314         realNavBarWidth_ = navBarWidth;
315     }
316     navBarSize_ = frameSize;
317     contentSize_ = frameSize;
318     dividerSize_ = SizeF(0.0f, frameSize.Height());
319     if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
320         SizeCalculationSplit(navigationLayoutProperty, frameSize);
321     } else {
322         SizeCalculationStack(hostNode, navigationLayoutProperty, frameSize);
323     }
324 }
325 
SizeCalculationSplit(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)326 void NavigationLayoutAlgorithm::SizeCalculationSplit(
327     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
328 {
329     float frameWidth = frameSize.Width();
330     auto parentSize = CreateIdealSizeByPercentRef(
331         navigationLayoutProperty->GetLayoutConstraint().value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
332     auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
333     auto userSetNavBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
334     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
335     auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
336     auto minContentWidth = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
337     realContentWidth_ = minContentWidth;
338 
339     if (navigationLayoutProperty->GetHideNavBar().value_or(false)) {
340         navBarSize_ = SizeF(0.0f, 0.0f);
341         dividerSize_ = SizeF(0.0f, 0.0f);
342         realNavBarWidth_ = 0.0f;
343         realContentWidth_ = frameWidth;
344     } else {
345         CheckSizeInSplit(frameWidth, userSetNavBarWidth, minNavBarWidth, minContentWidth);
346     }
347 
348     realDividerWidth_ = std::max(realDividerWidth_, 0.0f);
349     realContentWidth_ = std::max(realContentWidth_, 0.0f);
350     realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
351     realContentWidth_ = std::min(realContentWidth_, frameWidth);
352     if (realNavBarWidth_ == 0.0f || realContentWidth_ == 0.0f) {
353         realDividerWidth_ = 0.0f;
354     } else {
355         realDividerWidth_ = dividerWidth;
356     }
357     navBarSize_.SetWidth(realNavBarWidth_);
358     dividerSize_.SetWidth(realDividerWidth_);
359     contentSize_.SetWidth(realContentWidth_);
360 }
361 
CheckSizeInSplit(const float frameWidth,const float userSetNavBarWidth,const float minNavBarWidth,const float minContentWidth)362 void NavigationLayoutAlgorithm::CheckSizeInSplit(
363     const float frameWidth, const float userSetNavBarWidth, const float minNavBarWidth, const float minContentWidth)
364 {
365     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
366 
367     if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
368         if (minContentWidth >= frameWidth) {
369             realContentWidth_ = frameWidth;
370             realNavBarWidth_ = 0.0f;
371         } else if (realNavBarWidth_ + dividerWidth + minContentWidth <= frameWidth) {
372             realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
373         } else {
374             realContentWidth_ = minContentWidth;
375             realNavBarWidth_ = frameWidth - realContentWidth_ - dividerWidth;
376         }
377     } else if (!userSetNavBarRangeFlag_ && !userSetMinContentFlag_ && userSetNavBarWidthFlag_) {
378         realNavBarWidth_ = userSetNavBarWidth;
379         realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
380     } else {
381         float remainingSpace = frameWidth - realNavBarWidth_ - dividerWidth;
382         float remainingMaxSpace = frameWidth - minNavBarWidth - dividerWidth;
383         if (remainingSpace >= minContentWidth) {
384             realContentWidth_ = remainingSpace;
385         } else if (remainingSpace < minContentWidth && remainingMaxSpace > minContentWidth &&
386                    realNavBarWidth_ > minNavBarWidth) {
387             realContentWidth_ = minContentWidth;
388             realNavBarWidth_ = frameWidth - minContentWidth - dividerWidth;
389         } else {
390             realNavBarWidth_ = minNavBarWidth;
391             realContentWidth_ = frameWidth - minNavBarWidth - dividerWidth;
392         }
393     }
394 }
395 
SizeCalculationStack(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)396 void NavigationLayoutAlgorithm::SizeCalculationStack(const RefPtr<NavigationGroupNode>& hostNode,
397     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
398 {
399     auto contentNode = hostNode->GetContentNode();
400     CHECK_NULL_VOID(contentNode);
401     realDividerWidth_ = 0.0f;
402     float frameWidth = frameSize.Width();
403     navBarSize_.SetWidth(frameWidth);
404     dividerSize_.SetWidth(realDividerWidth_);
405     contentSize_.SetWidth(frameWidth);
406     realContentWidth_ = frameWidth;
407 }
408 
MeasureNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & navBarSize)409 void NavigationLayoutAlgorithm::MeasureNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
410     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& navBarSize)
411 {
412     auto navBarNode = hostNode->GetNavBarNode();
413     CHECK_NULL_VOID(navBarNode);
414     auto index = hostNode->GetChildIndexById(navBarNode->GetId());
415     auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
416     CHECK_NULL_VOID(navBarWrapper);
417     auto constraint = navigationLayoutProperty->CreateChildConstraint();
418     if (IsAutoHeight(navigationLayoutProperty)) {
419         navBarWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
420             navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
421         constraint.selfIdealSize.SetWidth(navBarSize.Width());
422     } else {
423         constraint.selfIdealSize = OptionalSizeF(navBarSize.Width(), navBarSize.Height());
424     }
425     navBarWrapper->Measure(constraint);
426     realNavBarHeight_ = navBarWrapper->GetGeometryNode()->GetFrameSize().Height();
427 }
428 
MeasureContentChild(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & contentSize)429 void NavigationLayoutAlgorithm::MeasureContentChild(LayoutWrapper* layoutWrapper,
430     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
431     const SizeF& contentSize)
432 {
433     auto contentNode = hostNode->GetContentNode();
434     CHECK_NULL_VOID(contentNode);
435     auto index = hostNode->GetChildIndexById(contentNode->GetId());
436     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
437     CHECK_NULL_VOID(contentWrapper);
438     auto constraint = navigationLayoutProperty->CreateChildConstraint();
439     if (contentNode->GetChildren().empty()) {
440         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
441     } else {
442         if (IsAutoHeight(navigationLayoutProperty)) {
443             constraint.selfIdealSize.SetWidth(contentSize.Width());
444         } else {
445             constraint.selfIdealSize = OptionalSizeF(contentSize.Width(), contentSize.Height());
446         }
447     }
448     contentWrapper->Measure(constraint);
449     realContentHeight_ = contentWrapper->GetGeometryNode()->GetFrameSize().Height();
450 }
451 
Measure(LayoutWrapper * layoutWrapper)452 void NavigationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
453 {
454     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
455     CHECK_NULL_VOID(hostNode);
456     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
457     CHECK_NULL_VOID(navigationLayoutProperty);
458     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
459     CHECK_NULL_VOID(constraint);
460     auto geometryNode = layoutWrapper->GetGeometryNode();
461     auto size =
462         CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT).ConvertToSizeT();
463     FitScrollFullWindow(size);
464 
465     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
466     MinusPaddingToSize(padding, size);
467 
468     if (ifNeedInit_) {
469         RangeCalculation(hostNode, navigationLayoutProperty);
470     }
471     if (size.Width() == 0.0f) {
472         return;
473     }
474     GetRange(hostNode);
475     UpdateNavigationMode(navigationLayoutProperty, size, hostNode);
476     SizeCalculation(layoutWrapper, hostNode, navigationLayoutProperty, size);
477 
478     MeasureNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
479     MeasureContentChild(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
480     MeasureDivider(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
481 
482     if (IsAutoHeight(navigationLayoutProperty)) {
483         SetNavigationHeight(layoutWrapper, size);
484     }
485     size.AddWidth(padding.left.value_or(0.0f) + padding.right.value_or(0.0f));
486     size.AddHeight(padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f));
487     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
488 }
489 
Layout(LayoutWrapper * layoutWrapper)490 void NavigationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
491 {
492     auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
493     if (layoutAlgorithm && layoutAlgorithm->SkipLayout()) {
494         return;
495     }
496     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
497     CHECK_NULL_VOID(hostNode);
498     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
499     CHECK_NULL_VOID(navigationLayoutProperty);
500     auto navBarPosition = navigationLayoutProperty->GetNavBarPositionValue(NavBarPosition::START);
501     OffsetF navBarOffset(0.0, 0.0);
502     float navBarWidth = LayoutNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
503     float dividerWidth = LayoutDivider(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, navBarPosition);
504     LayoutContent(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, dividerWidth, navBarPosition);
505 }
506 
SetNavigationHeight(LayoutWrapper * layoutWrapper,SizeF & size)507 void NavigationLayoutAlgorithm::SetNavigationHeight(LayoutWrapper* layoutWrapper, SizeF& size)
508 {
509     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
510     CHECK_NULL_VOID(hostNode);
511     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
512     CHECK_NULL_VOID(navigationPattern);
513     auto navigationStack = navigationPattern->GetNavigationStack();
514     CHECK_NULL_VOID(navigationStack);
515     if (navigationStack->Empty()) {
516         size.SetHeight(realNavBarHeight_);
517     } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
518         size.SetHeight(realContentHeight_);
519     } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
520         float navHeight = std::max(realContentHeight_, realNavBarHeight_);
521         size.SetHeight(navHeight);
522     }
523 }
524 
525 } // namespace OHOS::Ace::NG
526