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