• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 "base/utils/utf_helper.h"
17 #include "core/components_ng/pattern/navigation/title_bar_layout_algorithm.h"
18 
19 #include "core/components_ng/base/frame_node.h"
20 #include "core/components_ng/pattern/app_bar/app_bar_theme.h"
21 #include "core/components_ng/pattern/image/image_layout_property.h"
22 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
23 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
24 #include "core/components_ng/pattern/navigation/navdestination_node_base.h"
25 #include "core/components_ng/pattern/navigation/navdestination_pattern_base.h"
26 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
27 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
28 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
29 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
30 #include "core/components_ng/pattern/navigation/title_bar_node.h"
31 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
32 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
33 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
34 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
35 #include "core/components_ng/pattern/text/text_layout_property.h"
36 #include "core/components_ng/property/layout_constraint.h"
37 #include "core/components_ng/property/measure_property.h"
38 #include "core/components_ng/property/measure_utils.h"
39 #include "base/utils/measure_util.h"
40 #ifdef ENABLE_ROSEN_BACKEND
41 #include "core/components/custom_paint/rosen_render_custom_paint.h"
42 #endif
43 
44 namespace OHOS::Ace::NG {
45 
46 namespace {
47 constexpr int32_t MENU_OFFSET_RATIO = 9;
48 // maximum radio of the subtitle height to the titlebar height
49 constexpr double SUBTITLE_MAX_HEIGHT_RADIO = 0.35;
50 constexpr float OVERDRAG_DIVIDE_NUM = 6.0f;
51 
NeedAvoidMenuBar(PipelineContext * pipeline)52 bool NeedAvoidMenuBar(PipelineContext* pipeline)
53 {
54     return pipeline && pipeline->GetInstallationFree();
55 }
56 
NeedAvoidContainerModal(PipelineContext * pipeline,const RefPtr<TitleBarNode> & titleBarNode)57 bool NeedAvoidContainerModal(
58     PipelineContext* pipeline, const RefPtr<TitleBarNode>& titleBarNode)
59 {
60     CHECK_NULL_RETURN(pipeline, false);
61     auto avoidInfoMgr = pipeline->GetAvoidInfoManager();
62     CHECK_NULL_RETURN(avoidInfoMgr, false);
63     return avoidInfoMgr->NeedAvoidContainerModal() && titleBarNode && titleBarNode->NeedAvoidContainerModal();
64 }
65 } // namespace
66 
BackButtonLayout(LayoutWrapper * layoutWrapper)67 void TitleBarLayoutAlgorithm::BackButtonLayout(LayoutWrapper* layoutWrapper)
68 {
69     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
70     CHECK_NULL_VOID(titleBarNode);
71     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
72     CHECK_NULL_VOID(backButtonNode);
73     auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty();
74     CHECK_NULL_VOID(backButtonLayoutProperty);
75     PaddingProperty padding;
76     padding.SetEdges(CalcLength(MENU_BUTTON_PADDING));
77     backButtonLayoutProperty->UpdatePadding(padding);
78 }
79 
UpdateIconSize(const RefPtr<FrameNode> & backButtonNode)80 void TitleBarLayoutAlgorithm::UpdateIconSize(const RefPtr<FrameNode>& backButtonNode)
81 {
82     auto backButtonImageNode = AceType::DynamicCast<FrameNode>(backButtonNode->GetChildren().front());
83     CHECK_NULL_VOID(backButtonImageNode);
84     auto backButtonImageLayoutProperty = backButtonImageNode->GetLayoutProperty<LayoutProperty>();
85     CHECK_NULL_VOID(backButtonImageLayoutProperty);
86     backButtonImageLayoutProperty->UpdateUserDefinedIdealSize(
87         CalcSize(CalcLength(backIconWidth_), CalcLength(backIconHeight_)));
88 }
89 
MeasureBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)90 void TitleBarLayoutAlgorithm::MeasureBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
91     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
92 {
93     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
94     CHECK_NULL_VOID(backButtonNode);
95     auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
96     auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
97     CHECK_NULL_VOID(backButtonWrapper);
98     auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty();
99 
100     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
101     // navDestination title bar
102     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
103         TitleBarParentType::NAV_DESTINATION) {
104         if (!showBackButton_) {
105             backButtonLayoutProperty->UpdateVisibility(VisibleType::GONE);
106             return;
107         }
108         backButtonLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
109         PaddingProperty padding;
110         padding.SetEdges(CalcLength(BUTTON_PADDING));
111         backButtonLayoutProperty->UpdatePadding(padding);
112         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
113             constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()),
114                 static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()));
115             backButtonWrapper->Measure(constraint);
116             return;
117         }
118         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
119             UpdateIconSize(backButtonNode);
120             constraint.selfIdealSize = OptionalSizeF(static_cast<float>(backButtonWidth_.ConvertToPx()),
121                 static_cast<float>(backButtonWidth_.ConvertToPx()));
122             backButtonWrapper->Measure(constraint);
123             return;
124         }
125         constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()),
126             static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
127         backButtonWrapper->Measure(constraint);
128         return;
129     }
130 
131     backButtonLayoutProperty->UpdateVisibility(VisibleType::GONE);
132     // navBar title bar
133     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
134         return;
135     }
136 
137     if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
138         return;
139     }
140 
141     backButtonLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
142     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
143         UpdateIconSize(backButtonNode);
144         constraint.selfIdealSize = OptionalSizeF(static_cast<float>(backButtonWidth_.ConvertToPx()),
145             static_cast<float>(backButtonWidth_.ConvertToPx()));
146         backButtonWrapper->Measure(constraint);
147         return;
148     }
149 
150     constraint.selfIdealSize = OptionalSizeF(
151         static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()), static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
152     backButtonWrapper->Measure(constraint);
153 }
154 
GetTitleWidth(const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize)155 float TitleBarLayoutAlgorithm::GetTitleWidth(const RefPtr<TitleBarNode>& titleBarNode,
156     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize)
157 {
158     double paddingLeft = maxPaddingStart_.ConvertToPx();
159     double paddingLeftForBackButton = paddingLeft;
160     double paddingRight = maxPaddingEnd_.ConvertToPx();
161     double paddingRightForMenu = paddingRight;
162     double horizontalMargin = NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
163     auto backButtonWidth = BACK_BUTTON_ICON_SIZE.ConvertToPx();
164     auto customBackButtonRightPadding = BUTTON_PADDING.ConvertToPx();
165     auto defaultPaddingStart = defaultPaddingStart_.ConvertToPx();
166     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
167         paddingLeft = paddingLeft_;
168         paddingLeftForBackButton = paddingLeftForBackButton_;
169         paddingRight = paddingRight_;
170         paddingRightForMenu = paddingRightForMenu_;
171         horizontalMargin = menuCompPadding_.ConvertToPx();
172         backButtonWidth = backButtonWidth_.ConvertToPx();
173         customBackButtonRightPadding = 0.0f;
174         defaultPaddingStart = paddingRight;
175     }
176     // navDestination title bar
177     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
178         TitleBarParentType::NAV_DESTINATION) {
179         // nav destination custom title
180         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
181         CHECK_NULL_RETURN(navDestination, 0.0f);
182         auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
183         float occupiedWidth = 0.0f;
184         // left padding
185         if (showBackButton_) {
186             if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
187                 occupiedWidth += backButtonWidth_.ConvertToPx();
188             } else {
189                 occupiedWidth += (BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx();
190             }
191             occupiedWidth += paddingLeftForBackButton;
192             occupiedWidth += isCustom ? 0.0f : horizontalMargin;
193         } else {
194             occupiedWidth += isCustom ? 0.0f : paddingLeft;
195         }
196         // compute right padding
197         if (NearZero(menuOccupiedWidth_)) {
198             occupiedWidth += isCustom ? 0.0f : paddingRight;
199         } else {
200             occupiedWidth += menuOccupiedWidth_;
201             if (!navDestination->GetPrevMenuIsCustomValue(false)) {
202                 occupiedWidth += paddingRightForMenu;
203                 occupiedWidth += isCustom ? 0.0f : horizontalMargin;
204             }
205         }
206         return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
207     }
208     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
209     CHECK_NULL_RETURN(navBarNode, 0.0f);
210     float occupiedWidth = 0.0f;
211     auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
212     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
213         // mini mode
214         if (titleBarLayoutProperty->GetHideBackButtonValue(false)) {
215             occupiedWidth += isCustom ? 0.0f : paddingLeft;
216         } else {
217             occupiedWidth += paddingLeft + backButtonWidth;
218             // custom right padding is the back button hot zone
219             occupiedWidth += isCustom ? customBackButtonRightPadding : horizontalMargin;
220         }
221         // compute right padding
222         if (NearZero(menuOccupiedWidth_)) {
223             occupiedWidth += isCustom ? 0.0f : paddingRight;
224         } else {
225             occupiedWidth += menuOccupiedWidth_;
226             if (!navBarNode->GetPrevMenuIsCustomValue(false)) {
227                 occupiedWidth += defaultPaddingStart;
228                 occupiedWidth += isCustom ? 0.0f : horizontalMargin;
229             }
230         }
231         return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
232     }
233     // left padding of full and free mode
234     occupiedWidth = isCustom ? 0.0f : paddingLeft;
235     // right padding of full mode
236     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FULL
237         || isCustom) {
238         occupiedWidth += isCustom ? 0.0f : paddingRight;
239         return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
240     }
241     // right padding of free mode
242     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
243     if (titleBarPattern && titleBarPattern->IsFreeTitleUpdated() &&
244         titleBarPattern->GetTempTitleOffsetY() < menuOccupiedHeight_) {
245         if (NearZero(menuOccupiedWidth_)) {
246             occupiedWidth += isCustom ? 0.0f : paddingRight;
247         } else {
248             occupiedWidth += menuOccupiedWidth_;
249             if (!navBarNode->GetPrevMenuIsCustomValue(false)) {
250                 occupiedWidth += paddingLeft;
251                 occupiedWidth += isCustom ? 0.0f : horizontalMargin;
252             }
253         }
254     } else {
255         occupiedWidth += isCustom ? 0.0f : paddingRight;
256     }
257     return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
258 }
259 
WidthAfterAvoidMenuBarAndContainerModal(const RefPtr<TitleBarNode> & titleBarNode,float width)260 float TitleBarLayoutAlgorithm::WidthAfterAvoidMenuBarAndContainerModal(
261     const RefPtr<TitleBarNode>& titleBarNode, float width)
262 {
263     float afterAvoidWidth = width;
264     CHECK_NULL_RETURN(titleBarNode, afterAvoidWidth);
265     auto titleBarGeo = titleBarNode->GetGeometryNode();
266     CHECK_NULL_RETURN(titleBarGeo, afterAvoidWidth);
267     auto pipeline = titleBarNode->GetContext();
268     CHECK_NULL_RETURN(pipeline, afterAvoidWidth);
269     auto titleBarOffset = titleBarNode->GetParentGlobalOffsetDuringLayout();
270     RectF avoidArea;
271     if (NeedAvoidMenuBar(pipeline)) {
272         auto container = Container::Current();
273         CHECK_NULL_RETURN(container, afterAvoidWidth);
274         auto appBar = container->GetAppBar();
275         CHECK_NULL_RETURN(appBar, afterAvoidWidth);
276         auto appBarRect = appBar->GetAppBarRect();
277         CHECK_NULL_RETURN(appBarRect, afterAvoidWidth);
278         avoidArea = appBarRect.value();
279     }
280     if (NeedAvoidContainerModal(pipeline, titleBarNode)) {
281         RectF containerModal;
282         RectF buttonsRect;
283         auto avoidInfoMgr = pipeline->GetAvoidInfoManager();
284         CHECK_NULL_RETURN(avoidInfoMgr, afterAvoidWidth);
285         if (avoidInfoMgr->GetContainerModalButtonsRect(containerModal, buttonsRect)) {
286             if (NearZero(avoidArea.Width())) {
287                 avoidArea = buttonsRect;
288             } else {
289                 avoidArea.CombineRectT(buttonsRect);
290             }
291         }
292         titleBarOffset += titleBarGeo->GetFrameOffset();
293     }
294     if (NearZero(avoidArea.Width())) {
295         return afterAvoidWidth;
296     }
297 
298     auto avoidAreaOffset = avoidArea.GetOffset();
299     auto avoidAreaSize = avoidArea.GetSize();
300     auto avoidWidth = titleBarOffset.GetX() + titleBarGeo->GetFrameSize().Width() - avoidAreaOffset.GetX();
301     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
302         avoidWidth = avoidAreaOffset.GetX() + avoidAreaSize.Width() - titleBarOffset.GetX();
303     }
304     auto avoidAreaBottom = avoidAreaOffset.GetY() + avoidAreaSize.Height();
305     if (LessOrEqual(titleBarOffset.GetY(), avoidAreaBottom) && GreatOrEqual(avoidWidth, 0.0f)) {
306         afterAvoidWidth = afterAvoidWidth - avoidWidth;
307     }
308 
309     return LessOrEqual(afterAvoidWidth, 0.0f) ? 0.0f : afterAvoidWidth;
310 }
311 
MeasureSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)312 void TitleBarLayoutAlgorithm::MeasureSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
313     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
314 {
315     auto subtitleNode = titleBarNode->GetSubtitle();
316     CHECK_NULL_VOID(subtitleNode);
317     auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
318     auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
319     CHECK_NULL_VOID(subtitleWrapper);
320     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
321     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
322         // limit the maxHeight of the subtitle to adapt to the scenarios where the text is too high
323         constraint.maxSize.SetHeight(SUBTITLE_MAX_HEIGHT_RADIO * titleBarSize.Height());
324     } else {
325         constraint.maxSize.SetHeight(titleBarSize.Height());
326     }
327     constraint.maxSize.SetWidth(maxWidth);
328     subtitleWrapper->Measure(constraint);
329 }
330 
MeasureTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)331 void TitleBarLayoutAlgorithm::MeasureTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
332     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
333 {
334     auto titleNode = titleBarNode->GetTitle();
335     CHECK_NULL_VOID(titleNode);
336     auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
337     auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
338     CHECK_NULL_VOID(titleWrapper);
339     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
340     constraint.maxSize.SetHeight(titleBarSize.Height());
341 
342     // navDestination title bar
343     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
344         TitleBarParentType::NAV_DESTINATION) {
345         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
346         CHECK_NULL_VOID(navDestination);
347         auto isCustomTitle = navDestination->GetPrevTitleIsCustomValue(false);
348         if (isCustomTitle) {
349             constraint.parentIdealSize.SetWidth(maxWidth);
350             constraint.maxSize.SetWidth(maxWidth);
351             // custom title must be single line title
352 
353             constraint.parentIdealSize.SetHeight(titleBarSize.Height());
354             constraint.maxSize.SetHeight(titleBarSize.Height());
355             titleWrapper->Measure(constraint);
356             return;
357         }
358         constraint.maxSize.SetWidth(maxWidth);
359         if (!titleBarNode->GetSubtitle()) {
360             constraint.maxSize.SetHeight(titleBarSize.Height());
361             titleWrapper->Measure(constraint);
362             return;
363         }
364         auto subtitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
365         auto subtitleHeight = subtitle->GetGeometryNode()->GetFrameSize().Height();
366         constraint.maxSize.SetHeight(titleBarSize.Height() - subtitleHeight);
367         titleWrapper->Measure(constraint);
368         return;
369     }
370     // NavigationCustomTitle: Custom title + height
371     if (titleBarLayoutProperty->HasTitleHeight()) {
372         constraint.parentIdealSize.SetWidth(maxWidth);
373         constraint.maxSize.SetWidth(maxWidth);
374         constraint.parentIdealSize.SetHeight(titleBarSize.Height());
375         constraint.maxSize.SetHeight(titleBarSize.Height());
376         titleWrapper->Measure(constraint);
377         return;
378     }
379     // subTitle
380     auto titleMode = titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE);
381     auto subTitle = titleBarNode->GetSubtitle();
382     float titleSpaceVertical = 0.0f;
383     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
384         titleSpaceVertical = static_cast<float>(titleSpaceVertical_.ConvertToPx());
385     }
386     if (subTitle) {
387         // common title
388         auto index = titleBarNode->GetChildIndexById(subTitle->GetId());
389         auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
390         CHECK_NULL_VOID(subtitleWrapper);
391         auto subtitleHeight = subtitleWrapper->GetGeometryNode()->GetFrameSize().Height();
392         // mini mode double title height is 56vp, free/full mode is 82vp
393         auto maxTitleHeight = titleMode == NavigationTitleMode::MINI ? SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() :
394             DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
395         constraint.maxSize.SetWidth(maxWidth);
396         constraint.maxSize.SetHeight(maxTitleHeight - subtitleHeight - titleSpaceVertical);
397         titleWrapper->Measure(constraint);
398         return;
399     }
400     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
401     CHECK_NULL_VOID(navBarNode);
402     auto isCustomTitle = navBarNode->GetPrevTitleIsCustomValue(false);
403     // single line title and mini mode
404     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
405         if (isCustomTitle) {
406             constraint.parentIdealSize.SetWidth(maxWidth);
407             constraint.maxSize.SetWidth(maxWidth);
408             constraint.parentIdealSize.SetHeight(titleBarSize.Height());
409             constraint.maxSize.SetHeight(titleBarSize.Height());
410         } else {
411             constraint.maxSize.SetWidth(maxWidth);
412             constraint.maxSize.SetHeight(titleBarSize.Height());
413         }
414         titleWrapper->Measure(constraint);
415         return;
416     }
417     // custom builder
418     if (isCustomTitle) {
419         constraint.parentIdealSize.SetWidth(maxWidth);
420         constraint.maxSize.SetWidth(maxWidth);
421         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
422             constraint.parentIdealSize.SetHeight(titleBarSize.Height());
423         } else {
424             auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
425             // if has menu and menu is not custom, max height is single line height
426             auto maxHeight = NearZero(menuOccupiedWidth_) ? titleBarSize.Height()
427                              : isCustomMenu       ? titleBarSize.Height() - menuOccupiedHeight_
428                                                   : SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
429             constraint.parentIdealSize.SetHeight(maxHeight);
430             constraint.maxSize.SetHeight(maxHeight);
431         }
432         titleWrapper->Measure(constraint);
433         return;
434     }
435     // resourceStr title
436     constraint.maxSize.SetWidth(maxWidth);
437     constraint.maxSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
438     titleWrapper->Measure(constraint);
439 }
440 
MeasureMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)441 void TitleBarLayoutAlgorithm::MeasureMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
442     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
443 {
444     auto menuNode = titleBarNode->GetMenu();
445     CHECK_NULL_VOID(menuNode);
446     auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
447     auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
448     CHECK_NULL_VOID(menuWrapper);
449     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
450 
451     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(titleBarNode->GetParent());
452     CHECK_NULL_VOID(nodeBase);
453     bool isCustomMenu = nodeBase->GetPrevMenuIsCustomValue(false);
454     auto patternBase = nodeBase->GetPattern<NavDestinationPatternBase>();
455     CHECK_NULL_VOID(patternBase);
456     int32_t maxMenu = patternBase->GetMaxMenuNum();
457 
458     if (isCustomMenu) {
459         // custom title can't be higher than 56vp
460         constraint.parentIdealSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
461         if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI &&
462             !titleBarLayoutProperty->HasTitleHeight()) {
463             auto maxWidth = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * maxMenu +
464                             defaultPaddingStart_.ConvertToPx();
465             constraint.parentIdealSize.SetWidth(maxWidth);
466         }
467         menuWrapper->Measure(constraint);
468         menuOccupiedWidth_ = menuWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
469         menuOccupiedHeight_ = menuWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
470         return;
471     }
472     auto menuItemNum = static_cast<int32_t>(menuNode->GetChildren().size());
473     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
474         if (menuItemNum >= maxMenu) {
475             menuOccupiedWidth_ = static_cast<float>(iconBackgroundWidth_.ConvertToPx()) * maxMenu +
476                 static_cast<float>(menuCompPadding_.ConvertToPx()) * (maxMenu - 1);
477         } else {
478             // the number of the padding between menuItem.
479             int32_t paddingAmount = std::max(menuItemNum - 1, 0);
480             menuOccupiedWidth_ = static_cast<float>(iconBackgroundWidth_.ConvertToPx()) * menuItemNum +
481                 static_cast<float>(menuCompPadding_.ConvertToPx()) * paddingAmount;
482         }
483     } else {
484         if (menuItemNum >= maxMenu) {
485             menuOccupiedWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * maxMenu;
486         } else {
487             menuOccupiedWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * menuItemNum;
488         }
489     }
490     constraint.selfIdealSize = OptionalSizeF(menuOccupiedWidth_, menuOccupiedHeight_);
491     menuWrapper->Measure(constraint);
492 }
493 
ShowBackButtonLayout(LayoutWrapper * layoutWrapper,RefPtr<GeometryNode> & geometryNode,const RefPtr<LayoutWrapper> & backButtonWrapper,float titleBarHeight)494 void TitleBarLayoutAlgorithm::ShowBackButtonLayout(LayoutWrapper* layoutWrapper,
495     RefPtr<GeometryNode>& geometryNode, const RefPtr<LayoutWrapper>& backButtonWrapper, float titleBarHeight)
496 {
497     Dimension backButtonHeight = BACK_BUTTON_SIZE;
498     float paddingLeft = (maxPaddingStart_ - BUTTON_PADDING).ConvertToPx();
499     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
500         backButtonHeight = backButtonHeight_;
501         paddingLeft = paddingLeftForBackButton_;
502         BackButtonLayout(layoutWrapper);
503     }
504     auto offsetY = (titleBarHeight - backButtonHeight.ConvertToPx()) / 2.0f;
505     auto offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, paddingLeft);
506     OffsetF backButtonOffset = OffsetF(offsetX, offsetY);
507     geometryNode->SetMarginFrameOffset(backButtonOffset);
508     backButtonWrapper->Layout();
509 }
510 
LayoutBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)511 void TitleBarLayoutAlgorithm::LayoutBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
512     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
513 {
514     CHECK_NULL_VOID(titleBarNode);
515     auto titleBarGeometryNode = titleBarNode->GetGeometryNode();
516     CHECK_NULL_VOID(titleBarGeometryNode);
517     auto titleBarHeight = titleBarGeometryNode->GetFrameSize().Height();
518     auto backButtonNode = titleBarNode->GetBackButton();
519     CHECK_NULL_VOID(backButtonNode);
520     auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
521     auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
522     CHECK_NULL_VOID(backButtonWrapper);
523     auto geometryNode = backButtonWrapper->GetGeometryNode();
524 
525     // navDestination title bar
526     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
527         TitleBarParentType::NAV_DESTINATION) {
528         OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
529         if (!showBackButton_) {
530             SizeF size = SizeF(0.0f, 0.0f);
531             geometryNode->SetFrameSize(size);
532             backButtonWrapper->Layout();
533             return;
534         }
535         bool useContainerModalTitleHeight = titleBarNode->UseContainerModalTitleHeight();
536         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
537             auto fullHeight = useContainerModalTitleHeight ? titleBarHeight : menuOccupiedHeight_;
538             auto offsetY = (fullHeight - BACK_BUTTON_ICON_SIZE.ConvertToPx()) / 2.0f;
539             auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
540                 static_cast<float>(maxPaddingStart_.ConvertToPx()));
541             backButtonOffset = OffsetF(offsetXResult, offsetY);
542             geometryNode->SetMarginFrameOffset(backButtonOffset);
543             backButtonWrapper->Layout();
544             return;
545         }
546 
547         float height = useContainerModalTitleHeight ?
548             titleBarHeight : titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT).ConvertToPx();
549         ShowBackButtonLayout(layoutWrapper, geometryNode, backButtonWrapper, height);
550         return;
551     }
552 
553     // navBar title bar
554     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
555         OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
556         geometryNode->SetMarginFrameOffset(backButtonOffset);
557         backButtonWrapper->Layout();
558         return;
559     }
560 
561     if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
562         OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
563         geometryNode->SetMarginFrameOffset(backButtonOffset);
564         backButtonWrapper->Layout();
565         return;
566     }
567 
568     ShowBackButtonLayout(layoutWrapper, geometryNode, backButtonWrapper,
569         titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT).ConvertToPx());
570 }
571 
GetFullModeTitleOffsetY(float titleHeight,float subtitleHeight,RefPtr<GeometryNode> titleBarGeometryNode)572 float TitleBarLayoutAlgorithm::GetFullModeTitleOffsetY(float titleHeight, float subtitleHeight,
573     RefPtr<GeometryNode> titleBarGeometryNode)
574 {
575     auto titleBarHeight = titleBarGeometryNode->GetFrameSize().Height();
576     // fixed white space menuHeight
577     OffsetF titleOffset = OffsetF(0.0f, 0.0f);
578     float offsetY = 0.0f;
579     auto titleSpace = titleBarHeight - menuOccupiedHeight_ - static_cast<float>(paddingTopTwolines_.ConvertToPx());
580     auto titleRealHeight = titleHeight + subtitleHeight + navTitleSpaceVertical_;
581     float dividerOffset = 2.0f;
582     if (NearZero(subtitleHeight) && titleHeight < titleBarHeight - menuOccupiedHeight_) {
583         offsetY = (titleBarHeight - menuOccupiedHeight_ - titleRealHeight) / dividerOffset;
584         return offsetY;
585     }
586     if (titleRealHeight <= titleSpace) {
587         offsetY = (titleSpace - titleRealHeight +
588             static_cast<float>(paddingTopTwolines_.ConvertToPx())) / dividerOffset;
589     } else {
590         offsetY = titleSpace - titleRealHeight;
591     }
592 
593     return offsetY;
594 }
595 
LayoutTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)596 void TitleBarLayoutAlgorithm::LayoutTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
597     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
598 {
599     auto titleNode = titleBarNode->GetTitle();
600     CHECK_NULL_VOID(titleNode);
601     auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
602     auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
603     CHECK_NULL_VOID(titleWrapper);
604     auto geometryNode = titleWrapper->GetGeometryNode();
605     auto titleBarGeometryNode = titleBarNode->GetGeometryNode();
606     CHECK_NULL_VOID(titleBarGeometryNode);
607     auto titleBarHeight = titleBarGeometryNode->GetFrameSize().Height();
608     CHECK_NULL_VOID(geometryNode);
609 
610     auto titleHeight = geometryNode->GetFrameSize().Height();
611     float offsetY = 0.0f;
612     float dividerOffset = 2.0f;
613     bool isNavDestination = titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
614         TitleBarParentType::NAV_DESTINATION;
615     bool useContainerModalTitleHeight = titleBarNode->UseContainerModalTitleHeight();
616     if (!NearZero(subtitleHeight)) {
617         auto fullHeight = doubleLineTitleBarHeight_;
618         if (isNavDestination && useContainerModalTitleHeight) {
619             fullHeight = titleBarHeight;
620         }
621         offsetY = (fullHeight - titleHeight - subtitleHeight - navTitleSpaceVertical_) / dividerOffset;
622     } else {
623         navTitleSpaceVertical_ = 0.0f;
624         auto fullHeight = singleLineTitleHeight_;
625         if (isNavDestination && useContainerModalTitleHeight) {
626             fullHeight = titleBarHeight;
627         }
628         offsetY = (fullHeight - titleHeight) / dividerOffset;
629     }
630     // navDestination title bar
631     if (isNavDestination) {
632         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
633         CHECK_NULL_VOID(navDestination);
634         auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
635         OffsetF titleOffset = OffsetF(0.0f, 0.0f);
636         // add sdk 9 compatible
637         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
638             if (showBackButton_) {
639                 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
640                     static_cast<float>(
641                         (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M).ConvertToPx()));
642                 titleOffset = OffsetF(offsetXResult, offsetY);
643                 geometryNode->SetMarginFrameOffset(titleOffset);
644                 titleWrapper->Layout();
645                 return;
646             }
647             auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
648                 static_cast<float>(maxPaddingStart_.ConvertToPx()));
649             titleOffset = OffsetF(offsetXResult, offsetY);
650             geometryNode->SetMarginFrameOffset(titleOffset);
651             titleWrapper->Layout();
652             return;
653         }
654         if (showBackButton_) {
655             float offsetX = 0.0f;
656             if (isCustom) {
657                 offsetX = paddingLeft_ + navBackIconWidth_ + navButtonPadding_;
658             } else {
659                 offsetX = paddingLeftForBackButton_ + navBackIconWidth_ + navHorizontalMargin_;
660             }
661             offsetY = isCustom ? 0.0f : offsetY;
662             auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
663             titleOffset = OffsetF(offsetXResult, offsetY);
664             geometryNode->SetMarginFrameOffset(titleOffset);
665             titleWrapper->Layout();
666             return;
667         }
668         auto offsetX = isCustom ? 0.0f : paddingLeft_;
669         offsetY = isCustom ? 0.0f : offsetY;
670         auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
671         titleOffset = OffsetF(offsetXResult, offsetY);
672         geometryNode->SetMarginFrameOffset(titleOffset);
673         titleWrapper->Layout();
674         return;
675     }
676 
677     // navBar title bar
678     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
679     CHECK_NULL_VOID(navBarNode);
680     auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
681     // full mode
682     if (!isCustom) {
683         if (!NearZero(subtitleHeight)) {
684             offsetY = (doubleLineTitleBarHeight_ - titleHeight -
685                 subtitleHeight - navTitleSpaceVertical_) / dividerOffset;
686         } else {
687             navTitleSpaceVertical_ = 0.0f;
688             offsetY = (singleLineTitleHeight_ - titleHeight) / dividerOffset;
689         }
690     }
691     // only control layout when titleMode is free
692     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
693         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
694             if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
695                 auto offsetX = maxPaddingStart_.ConvertToPx();
696                 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
697                 geometryNode->SetMarginFrameOffset(OffsetF { offsetX, offsetY });
698                 titleWrapper->Layout();
699                 return;
700             }
701             auto offsetX =  (defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
702             offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
703             geometryNode->SetMarginFrameOffset(OffsetF {offsetX, offsetY});
704             titleWrapper->Layout();
705             return;
706         }
707         // NavigationCustomTitle and Custom builder layout margin is (0, 0);
708         offsetY = isCustom ? 0 : offsetY;
709         if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
710             auto offsetX = isCustom ? 0.0f : paddingLeft_;
711             offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
712             OffsetF titleOffset = OffsetF(offsetX, offsetY);
713             geometryNode->SetMarginFrameOffset(titleOffset);
714             titleWrapper->Layout();
715             return;
716         }
717 
718         auto offsetX = isCustom ? (paddingLeft_ + navBackIconWidth_ + navButtonPadding_) :
719                 (paddingLeft_ + navBackIconWidth_ + navHorizontalMargin_);
720         offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
721         OffsetF offset = OffsetF(offsetX, offsetY);
722         geometryNode->SetMarginFrameOffset(offset);
723         titleWrapper->Layout();
724         return;
725     }
726 
727     float offsetX = paddingLeft_;
728     offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
729     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
730         offsetY = GetFullModeTitleOffsetY(titleHeight, subtitleHeight, titleBarGeometryNode);
731     }
732     // full mode
733     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
734         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
735             offsetX = maxPaddingStart_.ConvertToPx();
736             offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
737             geometryNode->SetMarginFrameOffset(OffsetF { offsetX, menuOccupiedHeight_ + offsetY });
738             titleWrapper->Layout();
739             return;
740         }
741         // full mode
742         if (isCustom) {
743             // custom title margin is (0.0f, menuOccupiedHeight_)
744             float customOffsetX = 0.0f;
745             customOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, customOffsetX);
746             geometryNode->SetMarginFrameOffset(OffsetF { customOffsetX, menuOccupiedHeight_});
747             titleWrapper->Layout();
748             return;
749         }
750         // fixed white space menuHeight
751         OffsetF titleOffset = OffsetF(0.0f, 0.0f);
752         titleOffset = OffsetF(offsetX, menuOccupiedHeight_ + offsetY);
753         geometryNode->SetMarginFrameOffset(titleOffset);
754         titleWrapper->Layout();
755         return;
756     }
757 
758     // free mode
759     auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
760     CHECK_NULL_VOID(titlePattern);
761     if (isCustom) {
762         isInitialTitle_ = false;
763         // customBuilder and NavigationCustomTitle offset is (0.0f, menuOccupiedHeight_)
764         auto customOffsetX = 0.0f;
765         customOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, customOffsetX);
766         geometryNode->SetMarginFrameOffset(OffsetF { customOffsetX, menuOccupiedHeight_});
767         titleWrapper->Layout();
768         return;
769     }
770     auto title = AceType::DynamicCast<FrameNode>(titleNode);
771     CHECK_NULL_VOID(title);
772     if (isInitialTitle_) {
773         auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
774         if (!textLayoutProperty) {
775             // current title mode is Navigation common title
776             OffsetF titleOffset = OffsetF(offsetX, menuOccupiedHeight_+ offsetY);
777             geometryNode->SetMarginFrameOffset(titleOffset);
778             titleWrapper->Layout();
779             return;
780         }
781         MeasureContext context;
782         context.textContent = UtfUtils::Str16ToStr8(textLayoutProperty->GetContentValue());
783         context.fontSize = titleFontSize_;
784 #ifdef ENABLE_ROSEN_BACKEND
785         minTitleHeight_ = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(context).Height());
786 #else
787         minTitleHeight_ = 0.0;
788 #endif
789         initialTitleOffsetY_ = menuOccupiedHeight_ + offsetY;
790         isInitialTitle_ = false;
791         auto titleOffset = OffsetF(offsetX, initialTitleOffsetY_);
792         titlePattern->SetCurrentTitleOffsetY(initialTitleOffsetY_);
793         geometryNode->SetMarginFrameOffset(titleOffset);
794         titleWrapper->Layout();
795         return;
796     }
797 
798     if (NearZero(titlePattern->GetTempTitleOffsetY())) {
799         initialTitleOffsetY_ = menuOccupiedHeight_ + offsetY;
800         titlePattern->SetCurrentTitleOffsetY(initialTitleOffsetY_);
801         auto titleOffset = OffsetF(offsetX, initialTitleOffsetY_);
802         geometryNode->SetMarginFrameOffset(titleOffset);
803         titleWrapper->Layout();
804         return;
805     }
806     auto overDragOffset = titlePattern->GetOverDragOffset();
807     auto titleOffset = OffsetF(offsetX, titlePattern->GetTempTitleOffsetY() + overDragOffset / OVERDRAG_DIVIDE_NUM);
808     titlePattern->SetCurrentTitleOffsetY(titleOffset.GetY());
809     geometryNode->SetMarginFrameOffset(titleOffset);
810     titleWrapper->Layout();
811 }
812 
LayoutSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float titleHeight)813 void TitleBarLayoutAlgorithm::LayoutSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
814     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float titleHeight)
815 {
816     auto subtitleNode = titleBarNode->GetSubtitle();
817     CHECK_NULL_VOID(subtitleNode);
818     auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
819     auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
820     CHECK_NULL_VOID(subtitleWrapper);
821     auto geometryNode = subtitleWrapper->GetGeometryNode();
822     auto titleBarGeometryNode = titleBarNode->GetGeometryNode();
823     CHECK_NULL_VOID(titleBarGeometryNode);
824     auto titleBarHeight = titleBarGeometryNode->GetFrameSize().Height();
825     CHECK_NULL_VOID(geometryNode);
826 
827     auto subtitleHeight = geometryNode->GetFrameSize().Height();
828     float offsetY = 0.0f;
829     float dividerOffset = 2.0f;
830     bool isNavDestination = titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
831         TitleBarParentType::NAV_DESTINATION;
832     bool useContainerModalTitleHeight = titleBarNode->UseContainerModalTitleHeight();
833     if (!NearZero(titleHeight)) {
834         auto fullHeight = doubleLineTitleBarHeight_;
835         if (isNavDestination && useContainerModalTitleHeight) {
836             fullHeight = titleBarHeight;
837         }
838         offsetY = (fullHeight - titleHeight -
839                   subtitleHeight - navTitleSpaceVertical_) / dividerOffset + titleHeight + navTitleSpaceVertical_;
840     } else {
841         navTitleSpaceVertical_ = 0.0f;
842         auto fullHeight = singleLineTitleHeight_;
843         if (isNavDestination && useContainerModalTitleHeight) {
844             fullHeight = titleBarHeight;
845         }
846         offsetY = (fullHeight - subtitleHeight) / dividerOffset;
847     }
848     // navDestination title bar
849     if (isNavDestination) {
850         OffsetF subTitleOffset = OffsetF(0.0f, 0.0f);
851         // subtitle doesn't support custom title
852         if (showBackButton_) {
853             float offsetX = 0.0f;
854             if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
855                 offsetX = (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M).ConvertToPx();
856             } else {
857                 offsetX = paddingLeftForBackButton_ + navBackIconWidth_ + navHorizontalMargin_;
858             }
859             offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
860             subTitleOffset = OffsetF(offsetX, offsetY);
861             geometryNode->SetMarginFrameOffset(subTitleOffset);
862             subtitleWrapper->Layout();
863             return;
864         }
865 
866         auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode, paddingLeft_);
867         subTitleOffset = OffsetF(offsetXResult, offsetY);
868         geometryNode->SetMarginFrameOffset(subTitleOffset);
869         subtitleWrapper->Layout();
870         return;
871     }
872 
873     // navBar title bar
874     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
875         float offsetX = paddingLeft_;
876         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
877             auto titleOffsetY = GetFullModeTitleOffsetY(titleHeight, subtitleHeight, titleBarGeometryNode);
878             offsetY = titleOffsetY + titleHeight + navTitleSpaceVertical_;
879         }
880         offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
881         initialSubtitleOffsetY_ = menuOccupiedHeight_ + offsetY;
882         if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
883             if (isInitialSubtitle_) {
884                 isInitialSubtitle_ = false;
885                 OffsetF titleOffset = OffsetF(offsetX, initialSubtitleOffsetY_);
886                 geometryNode->SetMarginFrameOffset(titleOffset);
887                 subtitleWrapper->Layout();
888                 return;
889             }
890 
891             auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
892             CHECK_NULL_VOID(titlePattern);
893             if (NearZero(titlePattern->GetTempTitleOffsetY())) {
894                 OffsetF titleOffset = OffsetF(offsetX, initialSubtitleOffsetY_);
895                 geometryNode->SetMarginFrameOffset(titleOffset);
896                 subtitleWrapper->Layout();
897                 return;
898             }
899             auto overDragOffset = titlePattern->GetOverDragOffset();
900             OffsetF titleOffset = OffsetF(
901                 offsetX, titlePattern->GetTempSubTitleOffsetY() + overDragOffset / OVERDRAG_DIVIDE_NUM);
902             geometryNode->SetMarginFrameOffset(titleOffset);
903             subtitleWrapper->Layout();
904             return;
905         }
906         // full mode
907         OffsetF titleOffset = OffsetF(offsetX, initialSubtitleOffsetY_);
908         geometryNode->SetMarginFrameOffset(titleOffset);
909         subtitleWrapper->Layout();
910         return;
911     }
912     // mini mode + hideBackButton true
913     if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
914         auto offsetX = paddingLeft_;
915         offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
916         OffsetF titleOffset = OffsetF(offsetX, offsetY);
917         geometryNode->SetMarginFrameOffset(titleOffset);
918         subtitleWrapper->Layout();
919         return;
920     }
921     float occupiedWidth = 0.0f;
922     // mini mode + back button
923     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
924         occupiedWidth = static_cast<float>((maxPaddingStart_ + BACK_BUTTON_ICON_SIZE +
925             NAV_HORIZONTAL_MARGIN_M).ConvertToPx());
926     } else {
927         occupiedWidth = paddingLeft_ + navBackIconWidth_ + navHorizontalMargin_;
928     }
929     auto miniOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, occupiedWidth);
930     OffsetF offset = OffsetF(miniOffsetX, offsetY);
931     geometryNode->SetMarginFrameOffset(offset);
932     subtitleWrapper->Layout();
933 }
934 
LayoutMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)935 void TitleBarLayoutAlgorithm::LayoutMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
936     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
937 {
938     CHECK_NULL_VOID(titleBarNode);
939     auto titleBarGeometryNode = titleBarNode->GetGeometryNode();
940     CHECK_NULL_VOID(titleBarGeometryNode);
941     auto titleBarHeight = titleBarGeometryNode->GetFrameSize().Height();
942     bool useContainerModalTitleHeight = titleBarNode->UseContainerModalTitleHeight();
943     auto menuNode = titleBarNode->GetMenu();
944     CHECK_NULL_VOID(menuNode);
945     auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
946     auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
947     CHECK_NULL_VOID(menuWrapper);
948     auto geometryNode = menuWrapper->GetGeometryNode();
949     CHECK_NULL_VOID(geometryNode);
950     auto menuWidth = geometryNode->GetMarginFrameSize().Width();
951     auto maxWidth = geometryNode->GetParentLayoutConstraint()->maxSize.Width();
952     maxWidth = WidthAfterAvoidMenuBarAndContainerModal(titleBarNode, maxWidth);
953     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(titleBarNode->GetParent());
954     CHECK_NULL_VOID(nodeBase);
955     bool isCustomMenu = nodeBase->GetPrevMenuIsCustomValue(false);
956     auto currentOffsetX = maxWidth - menuWidth - defaultPaddingStart_.ConvertToPx();
957     auto isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
958     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
959         auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
960         auto overDragOffset = titlePattern->GetOverDragOffset();
961         float menuOffsetY = 0.0f;
962         if (!isCustomMenu) {
963             float totalHeight = useContainerModalTitleHeight ?
964                 titleBarHeight : SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
965             menuOffsetY = (totalHeight - menuOccupiedHeight_) / 2.0f;
966         }
967         // custom menu width has no right padding
968         float offsetX = 0.0f;
969         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
970             offsetX = isCustomMenu ? maxWidth - menuWidth
971                                    : (maxWidth - menuWidth - paddingRightForMenu_);
972         } else {
973             offsetX = isCustomMenu ? maxWidth - menuWidth
974                                    : (maxWidth - menuWidth - static_cast<float>(maxPaddingEnd_.ConvertToPx()) +
975                                          BUTTON_PADDING.ConvertToPx());
976         }
977         currentOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, currentOffsetX);
978         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
979             geometryNode->SetMarginFrameOffset(OffsetF { currentOffsetX,
980                 menuOffsetY + overDragOffset / MENU_OFFSET_RATIO });
981             menuWrapper->Layout();
982             return;
983         }
984         offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
985         // Fixed the issue of repeatedly adding margin in SetMarginFrameOffset for RTL
986         if (isRightToLeft && geometryNode->GetMargin()) {
987             offsetX = offsetX - geometryNode->GetMargin()->left.value_or(.0f) -
988                       geometryNode->GetMargin()->right.value_or(.0f);
989         }
990         OffsetF menuOffset(offsetX, menuOffsetY + overDragOffset / MENU_OFFSET_RATIO);
991         geometryNode->SetMarginFrameOffset(menuOffset);
992         menuWrapper->Layout();
993         return;
994     }
995     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
996         float totalHeight = titleBarHeight;
997         if (!useContainerModalTitleHeight) {
998             auto totalHeightDimension = NearZero(subtitleHeight) ?
999                 SINGLE_LINE_TITLEBAR_HEIGHT : DOUBLE_LINE_TITLEBAR_HEIGHT;
1000             totalHeight = totalHeightDimension.ConvertToPx();
1001         }
1002         geometryNode->SetMarginFrameOffset(OffsetF { currentOffsetX, (totalHeight - menuOccupiedHeight_) / 2.0f });
1003         menuWrapper->Layout();
1004         return;
1005     }
1006     // custom menu doesn't have top padding. if menu isn't custom, menu items has top padding
1007     auto menuOffsetY =  0.0f;
1008     if (!isCustomMenu) {
1009         float totalHeight = useContainerModalTitleHeight ?
1010             titleBarHeight : SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
1011         menuOffsetY = (totalHeight - menuOccupiedHeight_) / 2.0f;
1012     }
1013     auto menuOffsetX = maxWidth - menuWidth;
1014     // custom menu doesn't have right padding. if menu isn't custom, menu items has right padding
1015     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1016         menuOffsetX =
1017             isCustomMenu ? menuOffsetX : (menuOffsetX - paddingRight_);
1018     } else {
1019         menuOffsetX =
1020             isCustomMenu ? menuOffsetX : (menuOffsetX - maxPaddingEnd_.ConvertToPx() + BUTTON_PADDING.ConvertToPx());
1021     }
1022     menuOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, menuOffsetX);
1023     // Fixed the issue of repeatedly adding margin in SetMarginFrameOffset for RTL
1024     if (isRightToLeft && geometryNode->GetMargin()) {
1025         menuOffsetX = menuOffsetX - geometryNode->GetMargin()->left.value_or(.0f) -
1026                       geometryNode->GetMargin()->right.value_or(.0f);
1027     }
1028     OffsetF menuOffset(menuOffsetX, menuOffsetY);
1029     geometryNode->SetMarginFrameOffset(menuOffset);
1030     menuWrapper->Layout();
1031 }
1032 
1033 // set variables from theme
InitializeTheme(const RefPtr<TitleBarNode> & titleBarNode,const SizeF & titleBarSize)1034 void TitleBarLayoutAlgorithm::InitializeTheme(const RefPtr<TitleBarNode>& titleBarNode, const SizeF& titleBarSize)
1035 {
1036     auto theme = NavigationGetTheme();
1037     CHECK_NULL_VOID(theme);
1038     maxPaddingStart_ = theme->GetMaxPaddingStart();
1039     maxPaddingEnd_ = theme->GetMaxPaddingEnd();
1040     menuOccupiedHeight_ = theme->GetHeight().ConvertToPx();
1041     defaultPaddingStart_ = theme->GetDefaultPaddingStart();
1042     iconSize_ = theme->GetMenuIconSize();
1043     titleFontSize_ = theme->GetTitleFontSize();
1044     menuCompPadding_ = theme->GetCompPadding();
1045     iconBackgroundWidth_ = theme->GetIconBackgroundWidth();
1046     backButtonWidth_ = theme->GetBackButtonWidth();
1047     backButtonHeight_ = theme->GetBackButtonHeight();
1048     paddingTopTwolines_ = theme->GetPaddingTopTwolines();
1049     titleSpaceVertical_ = theme->GetTitleSpaceVertical();
1050     backIconWidth_ = theme->GetIconWidth();
1051     backIconHeight_ = theme->GetIconHeight();
1052     singleLineTitleHeight_ = static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
1053     doubleLineTitleBarHeight_ = static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
1054     navTitleSpaceVertical_ = 0.0f;
1055     paddingLeft_ = maxPaddingStart_.ConvertToPx();
1056     navBackIconWidth_ = BACK_BUTTON_ICON_SIZE.ConvertToPx();
1057     navButtonPadding_ = BUTTON_PADDING.ConvertToPx();
1058     navHorizontalMargin_ = NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
1059     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1060         doubleLineTitleBarHeight_ = static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
1061         navTitleSpaceVertical_ = static_cast<float>(titleSpaceVertical_.ConvertToPx());
1062         CHECK_NULL_VOID(titleBarNode);
1063         auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
1064         CHECK_NULL_VOID(titlePattern);
1065         auto options = titlePattern->GetTitleBarOptions();
1066         auto paddingStart = options.brOptions.paddingStart;
1067         if (paddingStart.has_value()) {
1068             paddingLeft_ = NavigationTitleUtil::ParseCalcDimensionToPx(paddingStart, titleBarSize.Width());
1069             paddingLeftForBackButton_ = paddingLeft_;
1070         } else {
1071             paddingLeft_ = theme->GetMarginLeft().ConvertToPx();
1072             paddingLeftForBackButton_ = theme->GetMarginLeftForBackButton().ConvertToPx();
1073         }
1074         auto paddingEnd = options.brOptions.paddingEnd;
1075         if (paddingEnd.has_value()) {
1076             paddingRight_ = NavigationTitleUtil::ParseCalcDimensionToPx(paddingEnd, titleBarSize.Width());
1077             paddingRightForMenu_ = paddingRight_;
1078         } else {
1079             paddingRight_ = theme->GetMarginRight().ConvertToPx();
1080             paddingRightForMenu_ = theme->GetMarginRightForMenu().ConvertToPx();
1081         }
1082         navBackIconWidth_ = backIconWidth_.ConvertToPx();
1083         navButtonPadding_ = (MENU_BUTTON_PADDING + MENU_BUTTON_PADDING).ConvertToPx();
1084         navHorizontalMargin_ = navButtonPadding_ + menuCompPadding_.ConvertToPx();
1085     }
1086 }
1087 
Measure(LayoutWrapper * layoutWrapper)1088 void TitleBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
1089 {
1090     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
1091     CHECK_NULL_VOID(titleBarNode);
1092     auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
1093     CHECK_NULL_VOID(layoutProperty);
1094     const auto& constraint = layoutProperty->GetLayoutConstraint();
1095     CHECK_NULL_VOID(constraint);
1096     auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
1097     auto size = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT, true);
1098     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1099     MinusPaddingToSize(padding, size);
1100     InitializeTheme(titleBarNode, size);
1101     do {
1102         if (layoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) !=
1103             TitleBarParentType::NAV_DESTINATION) {
1104             break;
1105         }
1106         auto navDestinationNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetParent());
1107         CHECK_NULL_BREAK(navDestinationNode);
1108         auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestinationNode->GetPattern());
1109         CHECK_NULL_BREAK(navDestinationPattern);
1110         showBackButton_ = navDestinationPattern->GetBackButtonState();
1111     } while (false);
1112     MeasureBackButton(layoutWrapper, titleBarNode, layoutProperty);
1113     MeasureMenu(layoutWrapper, titleBarNode, layoutProperty);
1114     auto titleMaxWidth = GetTitleWidth(titleBarNode, layoutProperty, size);
1115     titleMaxWidth = WidthAfterAvoidMenuBarAndContainerModal(titleBarNode, titleMaxWidth);
1116     MeasureSubtitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
1117     MeasureTitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
1118     titlePattern->SetCurrentTitleBarHeight(size.Height());
1119     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
1120 }
1121 
Layout(LayoutWrapper * layoutWrapper)1122 void TitleBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1123 {
1124     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
1125     CHECK_NULL_VOID(titleBarNode);
1126     auto pipeline = titleBarNode->GetContext();
1127     if (NeedAvoidMenuBar(pipeline) ||
1128         NeedAvoidContainerModal(pipeline, titleBarNode)) {
1129         // TitleBar need run measure again during Layout
1130         // when avoiding menuBar in atomic service, or avoiding containerModal.
1131         Measure(layoutWrapper);
1132     }
1133     auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
1134     CHECK_NULL_VOID(layoutProperty);
1135     LayoutBackButton(layoutWrapper, titleBarNode, layoutProperty);
1136 
1137     float subtitleHeight = 0.0f;
1138     auto subtitleNode = titleBarNode->GetSubtitle();
1139     if (subtitleNode) {
1140         auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
1141         auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1142         CHECK_NULL_VOID(subtitleWrapper);
1143         auto geometryNode = subtitleWrapper->GetGeometryNode();
1144         subtitleHeight = geometryNode->GetFrameSize().Height();
1145     }
1146     LayoutTitle(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
1147 
1148     float titleHeight = 0.0f;
1149     auto titleNode = titleBarNode->GetTitle();
1150     if (titleNode) {
1151         auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
1152         auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1153         CHECK_NULL_VOID(titleWrapper);
1154         auto geometryNode = titleWrapper->GetGeometryNode();
1155         titleHeight = geometryNode->GetFrameSize().Height();
1156     }
1157     LayoutSubtitle(layoutWrapper, titleBarNode, layoutProperty, titleHeight);
1158 
1159     LayoutMenu(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
1160 }
1161 
ChangeOffsetByDirection(LayoutWrapper * layoutWrapper,const RefPtr<NG::GeometryNode> & childGeometryNode,float offsetX) const1162 float TitleBarLayoutAlgorithm::ChangeOffsetByDirection(LayoutWrapper* layoutWrapper,
1163     const RefPtr<NG::GeometryNode>& childGeometryNode, float offsetX) const
1164 {
1165     CHECK_NULL_RETURN(layoutWrapper, offsetX);
1166     CHECK_NULL_RETURN(childGeometryNode, offsetX);
1167     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
1168         auto geometryNode = layoutWrapper->GetGeometryNode();
1169         CHECK_NULL_RETURN(geometryNode, offsetX);
1170         auto parentWidth = geometryNode->GetFrameSize().Width();
1171         offsetX = parentWidth - offsetX - childGeometryNode->GetFrameSize().Width();
1172     }
1173     return offsetX;
1174 }
1175 } // namespace OHOS::Ace::NG
1176