• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/navigation/title_bar_layout_algorithm.h"
17 
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/geometry/ng/size_t.h"
20 #include "base/memory/ace_type.h"
21 #include "base/utils/measure_util.h"
22 #include "base/utils/utils.h"
23 #include "core/components/custom_paint/rosen_render_custom_paint.h"
24 #include "core/components_ng/base/frame_node.h"
25 #include "core/components_ng/pattern/navigation/nav_bar_node.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/title_bar_layout_property.h"
29 #include "core/components_ng/pattern/navigation/title_bar_node.h"
30 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
31 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
32 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
33 #include "core/components_ng/pattern/text/text_layout_property.h"
34 #include "core/components_ng/property/layout_constraint.h"
35 #include "core/components_ng/property/measure_property.h"
36 #include "core/components_ng/property/measure_utils.h"
37 
38 namespace OHOS::Ace::NG {
39 
40 namespace {
41 constexpr int32_t MAX_MENU_ITEMS_NUM = 3;
42 constexpr int32_t MENU_OFFSET_RATIO = 9;
43 }
44 
MeasureBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)45 void TitleBarLayoutAlgorithm::MeasureBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
46     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
47 {
48     auto backButtonNode = titleBarNode->GetBackButton();
49     CHECK_NULL_VOID(backButtonNode);
50     auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
51     auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
52     CHECK_NULL_VOID(backButtonWrapper);
53     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
54     // navDestination title bar
55     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
56         TitleBarParentType::NAV_DESTINATION) {
57         if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
58             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
59             constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()),
60             static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()));
61             backButtonWrapper->Measure(constraint);
62             return;
63         }
64         constraint.parentIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()),
65             static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
66         backButtonWrapper->Measure(constraint);
67         return;
68     }
69 
70     // navBar title bar
71     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
72         constraint.parentIdealSize = OptionalSizeF(0.0f, 0.0f);
73         backButtonWrapper->Measure(constraint);
74         return;
75     }
76 
77     if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
78         constraint.parentIdealSize = OptionalSizeF(0.0f, 0.0f);
79         backButtonWrapper->Measure(constraint);
80         return;
81     }
82 
83     constraint.parentIdealSize = OptionalSizeF(
84         static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()), static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
85     backButtonWrapper->Measure(constraint);
86 }
87 
GetTitleWidth(const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize)88 float TitleBarLayoutAlgorithm::GetTitleWidth(const RefPtr<TitleBarNode>& titleBarNode,
89     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize)
90 {
91     // navDestination title bar
92     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
93         TitleBarParentType::NAV_DESTINATION) {
94 
95         // nav destination custom title
96         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
97         CHECK_NULL_RETURN(navDestination, 0.0f);
98         auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
99         float occupiedWidth = 0.0f;
100         // left padding
101         if (GetNavigationBackButtonState(titleBarNode)) {
102             occupiedWidth += isCustom ? (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() :
103                 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
104         } else {
105             occupiedWidth += isCustom ? 0.0f : maxPaddingStart_.ConvertToPx();
106         }
107         // right padding
108         occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
109         return titleBarSize.Width() < occupiedWidth ? 0 : titleBarSize.Width() - occupiedWidth;
110     }
111     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
112     CHECK_NULL_RETURN(navBarNode, 0.0f);
113     float occupiedWidth = 0.0f;
114     auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
115     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
116         occupiedWidth = isCustom ? 0.0f : (maxPaddingStart_ + maxPaddingEnd_).ConvertToPx();
117         return titleBarSize.Width() < occupiedWidth ? 0 : titleBarSize.Width() - occupiedWidth;
118     }
119     // mini mode
120     if (titleBarLayoutProperty->GetHideBackButtonValue(false)) {
121         occupiedWidth += isCustom ? 0 : maxPaddingStart_.ConvertToPx();
122     } else {
123         occupiedWidth += (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE).ConvertToPx();
124         // custom right padding is the back button hot zone
125         occupiedWidth += isCustom ? BUTTON_PADDING.ConvertToPx() : (NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
126     }
127     // compute right padding
128     if (NearZero(menuWidth_)) {
129         occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
130     } else {
131         occupiedWidth += menuWidth_;
132         // title is custom, the title right margin is not needed
133         occupiedWidth += isCustom ? 0.0f : (NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
134         auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
135         occupiedWidth += isCustomMenu ? 0.0f : (defaultPaddingStart_).ConvertToPx();
136     }
137     return titleBarSize.Width() < occupiedWidth ? 0 : titleBarSize.Width() - occupiedWidth;
138 }
139 
MeasureSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)140 void TitleBarLayoutAlgorithm::MeasureSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
141     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
142 {
143     auto subtitleNode = titleBarNode->GetSubtitle();
144     CHECK_NULL_VOID_NOLOG(subtitleNode);
145     auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
146     auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
147     CHECK_NULL_VOID(subtitleWrapper);
148     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
149     constraint.maxSize.SetHeight(titleBarSize.Height());
150     constraint.maxSize.SetWidth(maxWidth);
151     subtitleWrapper->Measure(constraint);
152 }
153 
MeasureTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)154 void TitleBarLayoutAlgorithm::MeasureTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
155     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
156 {
157     auto titleNode = titleBarNode->GetTitle();
158     CHECK_NULL_VOID(titleNode);
159     auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
160     auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
161     CHECK_NULL_VOID(titleWrapper);
162     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
163     constraint.maxSize.SetHeight(titleBarSize.Height());
164 
165     // navDestination title bar
166     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
167         TitleBarParentType::NAV_DESTINATION) {
168         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
169         CHECK_NULL_VOID(navDestination);
170         auto isCustomTitle = navDestination->GetPrevTitleIsCustomValue(false);
171         if (isCustomTitle) {
172             constraint.parentIdealSize.SetWidth(maxWidth);
173             constraint.maxSize.SetWidth(maxWidth);
174             // custom title must be single line title
175 
176             auto navDestinationProperty = navDestination->GetLayoutProperty<NavDestinationLayoutProperty>();
177             auto titleHeight = navDestinationProperty->GetTitleBarHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT);
178             constraint.parentIdealSize.SetHeight(titleHeight.ConvertToPx());
179             constraint.maxSize.SetHeight(titleHeight.ConvertToPx());
180             titleWrapper->Measure(constraint);
181             return;
182         }
183         constraint.maxSize.SetWidth(maxWidth);
184         if (!titleBarNode->GetSubtitle()) {
185             constraint.maxSize.SetHeight(titleBarSize.Height());
186             titleWrapper->Measure(constraint);
187             return;
188         }
189         auto subtitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
190         auto subtitleHeight = subtitle->GetGeometryNode()->GetFrameSize().Height();
191         constraint.maxSize.SetHeight(titleBarSize.Height() - subtitleHeight);
192         titleWrapper->Measure(constraint);
193         return;
194     }
195     // NavigationCustomTitle: Custom title + height
196     if (titleBarLayoutProperty->HasTitleHeight()) {
197         constraint.parentIdealSize.SetWidth(maxWidth);
198         constraint.maxSize.SetWidth(maxWidth);
199         constraint.parentIdealSize.SetHeight(titleBarLayoutProperty->GetTitleHeightValue().ConvertToPx());
200         constraint.maxSize.SetHeight(titleBarLayoutProperty->GetTitleHeightValue().ConvertToPx());
201         titleWrapper->Measure(constraint);
202         return;
203     }
204     // subTitle
205     auto titleMode = titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE);
206     auto subTitle = titleBarNode->GetSubtitle();
207     if (subTitle) {
208         // common title
209         auto index = titleBarNode->GetChildIndexById(subTitle->GetId());
210         auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
211         CHECK_NULL_VOID(subtitleWrapper);
212         auto geometryNode = subtitleWrapper->GetGeometryNode();
213         // mini mode double title height is 56vp, free/full mode is 82vp
214         auto maxTitleHeight = titleMode == NavigationTitleMode::MINI ? SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() :
215             DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
216         constraint.maxSize.SetWidth(maxWidth);
217         constraint.maxSize.SetHeight(maxTitleHeight - geometryNode->GetFrameSize().Height());
218         titleWrapper->Measure(constraint);
219         return;
220     }
221     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
222     CHECK_NULL_VOID(navBarNode);
223     auto isCustomTitle = navBarNode->GetPrevTitleIsCustomValue(false);
224     // single line title and mini mode
225     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
226         if (isCustomTitle) {
227             constraint.parentIdealSize.SetWidth(maxWidth);
228             constraint.maxSize.SetWidth(maxWidth);
229             constraint.parentIdealSize.SetHeight(titleBarSize.Height());
230             constraint.maxSize.SetHeight(titleBarSize.Height());
231         } else {
232             constraint.maxSize.SetWidth(maxWidth);
233             constraint.maxSize.SetHeight(titleBarSize.Height());
234         }
235         titleWrapper->Measure(constraint);
236         return;
237     }
238     // custom builder
239     if (isCustomTitle) {
240         constraint.parentIdealSize.SetWidth(maxWidth);
241         constraint.maxSize.SetWidth(maxWidth);
242         if (PipelineContext::GetCurrentContext() && (PipelineContext::GetCurrentContext()
243             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN))) {
244             constraint.parentIdealSize.SetHeight(titleBarSize.Height());
245         } else {
246             // if has menu, max height is single line height
247             auto maxHeight = NearZero(menuWidth_) ? titleBarSize.Height() : SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
248             constraint.parentIdealSize.SetHeight(maxHeight);
249             constraint.maxSize.SetHeight(maxHeight);
250         }
251         titleWrapper->Measure(constraint);
252         return;
253     }
254     // resourceStr title
255     constraint.maxSize.SetWidth(maxWidth);
256     constraint.maxSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
257     titleWrapper->Measure(constraint);
258 }
259 
MeasureMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)260 void TitleBarLayoutAlgorithm::MeasureMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
261     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
262 {
263     auto menuNode = titleBarNode->GetMenu();
264     CHECK_NULL_VOID_NOLOG(menuNode);
265     auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
266     auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
267     CHECK_NULL_VOID(menuWrapper);
268     auto constraint = titleBarLayoutProperty->CreateChildConstraint();
269     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
270     CHECK_NULL_VOID(navBarNode);
271     auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
272     if (isCustomMenu) {
273         // custom title can't be higher than 56vp
274         constraint.parentIdealSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
275         if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI &&
276             !titleBarLayoutProperty->HasTitleHeight()) {
277                 auto maxWidth = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * MAX_MENU_ITEMS_NUM +
278                     defaultPaddingStart_.ConvertToPx();
279                 constraint.parentIdealSize.SetWidth(maxWidth);
280             }
281         menuWrapper->Measure(constraint);
282         menuWidth_ = menuWrapper->GetGeometryNode()->GetFrameSize().Width();
283         return;
284     }
285     auto menuItemNum = static_cast<int32_t>(menuNode->GetChildren().size());
286     if (menuItemNum >= MAX_MENU_ITEMS_NUM) {
287         menuWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * MAX_MENU_ITEMS_NUM;
288     } else {
289         menuWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * menuItemNum;
290     }
291     constraint.selfIdealSize = OptionalSizeF(menuWidth_, static_cast<float>(menuHeight_.ConvertToPx()));
292     menuWrapper->Measure(constraint);
293 }
294 
LayoutBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)295 void TitleBarLayoutAlgorithm::LayoutBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
296     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
297 {
298     auto backButtonNode = titleBarNode->GetBackButton();
299     CHECK_NULL_VOID(backButtonNode);
300     auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
301     auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
302     CHECK_NULL_VOID(backButtonWrapper);
303     auto geometryNode = backButtonWrapper->GetGeometryNode();
304 
305     // navDestination title bar
306     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
307         TitleBarParentType::NAV_DESTINATION) {
308         if (!titleBarNode->GetBackButton()) {
309             return;
310         }
311         if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
312             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
313             auto offsetY = ((menuHeight_ - BACK_BUTTON_ICON_SIZE) / 2).ConvertToPx();
314             geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(), offsetY });
315             backButtonWrapper->Layout();
316             return;
317         }
318         auto titleHeight = titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT);
319         auto offsetY = (titleHeight - BACK_BUTTON_SIZE) / 2;
320 
321         OffsetF backButtonOffset = OffsetF(static_cast<float>((maxPaddingStart_ - BUTTON_PADDING).ConvertToPx()),
322             static_cast<float>(offsetY.ConvertToPx()));
323         geometryNode->SetMarginFrameOffset(backButtonOffset);
324         backButtonWrapper->Layout();
325         return;
326     }
327 
328     // navBar title bar
329     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
330         OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
331         geometryNode->SetMarginFrameOffset(backButtonOffset);
332         backButtonWrapper->Layout();
333         return;
334     }
335 
336     if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
337         OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
338         geometryNode->SetMarginFrameOffset(backButtonOffset);
339         backButtonWrapper->Layout();
340         return;
341     }
342     auto titleHeight = titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT);
343     auto offsetY = (titleHeight - BACK_BUTTON_SIZE) / 2;
344     auto offsetX = (maxPaddingStart_ - (BACK_BUTTON_SIZE - BACK_BUTTON_ICON_SIZE) / 2).ConvertToPx();
345     OffsetF backButtonOffset = OffsetF(offsetX, static_cast<float>(offsetY.ConvertToPx()));
346     geometryNode->SetMarginFrameOffset(backButtonOffset);
347     backButtonWrapper->Layout();
348 }
349 
LayoutTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)350 void TitleBarLayoutAlgorithm::LayoutTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
351     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
352 {
353     auto titleNode = titleBarNode->GetTitle();
354     CHECK_NULL_VOID(titleNode);
355     auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
356     auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
357     CHECK_NULL_VOID(titleWrapper);
358     auto geometryNode = titleWrapper->GetGeometryNode();
359 
360     auto titleHeight = geometryNode->GetFrameSize().Height();
361     float offsetY = 0.0f;
362     if (!NearZero(subtitleHeight)) {
363         offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight - subtitleHeight) / 2;
364     } else {
365         offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight) / 2;
366     }
367     // navDestination title bar
368     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
369         TitleBarParentType::NAV_DESTINATION) {
370         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
371         CHECK_NULL_VOID(navDestination);
372         auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
373         // add sdk 9 compatible
374         if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
375             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
376             if (GetNavigationBackButtonState(titleBarNode)) {
377                 geometryNode->SetMarginFrameOffset(OffsetF {
378                     static_cast<float>((maxPaddingStart_ + BACK_BUTTON_ICON_SIZE +
379                         NAV_HORIZONTAL_MARGIN_M).ConvertToPx()), offsetY });
380                 titleWrapper->Layout();
381                 return;
382             }
383             geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(), offsetY});
384             titleWrapper->Layout();
385             return;
386         }
387         if (GetNavigationBackButtonState(titleBarNode)) {
388             auto offsetX = isCustom ? (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() :
389                 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
390             offsetY = isCustom ? 0.0f : offsetY;
391             geometryNode->SetMarginFrameOffset(OffsetF { offsetX, offsetY });
392             titleWrapper->Layout();
393             return;
394         }
395         auto offsetX = isCustom ? 0.0f : maxPaddingStart_.ConvertToPx();
396         offsetY = isCustom ? 0.0f : offsetY;
397         OffsetF offset = OffsetF(offsetX, offsetY);
398         geometryNode->SetMarginFrameOffset(offset);
399         titleWrapper->Layout();
400         return;
401     }
402 
403     // navBar title bar
404     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
405     CHECK_NULL_VOID(navBarNode);
406     auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
407     // full mode
408     if (!isCustom) {
409         auto dividerOffset = 2;
410         if (!NearZero(subtitleHeight)) {
411             offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight -
412                 subtitleHeight) / dividerOffset;
413         } else {
414             offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight) / dividerOffset;
415         }
416     }
417     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
418         if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
419             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
420             if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
421                 geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(), offsetY });
422                 titleWrapper->Layout();
423                 return;
424             }
425             geometryNode->SetMarginFrameOffset(OffsetF { (defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE +
426             NAV_HORIZONTAL_MARGIN_L).ConvertToPx(), offsetY});
427             titleWrapper->Layout();
428             return;
429         }
430         // NavigationCustomTitle and Custom builder layout margin is (0, 0);
431         offsetY = isCustom ? 0 : offsetY;
432         if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
433             auto offsetX = isCustom ? 0.0f : (maxPaddingStart_).ConvertToPx();
434             OffsetF titleOffset = OffsetF(offsetX, offsetY);
435             geometryNode->SetMarginFrameOffset(titleOffset);
436             titleWrapper->Layout();
437             return;
438         }
439 
440         auto offsetX = isCustom ? (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() :
441             (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
442         OffsetF offset = OffsetF(offsetX, offsetY);
443         geometryNode->SetMarginFrameOffset(offset);
444         titleWrapper->Layout();
445         return;
446     }
447 
448     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
449         if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
450             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
451             geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(),
452                 menuHeight_.ConvertToPx() + offsetY});
453             titleWrapper->Layout();
454             return;
455         }
456         // full mode
457         if (isCustom) {
458             // custom title margin is (0.0f, menuHeight_)
459             auto customOffsetY = NearZero(menuWidth_) ? 0.0f : menuHeight_.ConvertToPx();
460             geometryNode->SetMarginFrameOffset(OffsetF { 0.0f, customOffsetY});
461             titleWrapper->Layout();
462         } else {
463             // fixed white space menuHeight
464             OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
465                 static_cast<float>(menuHeight_.ConvertToPx()) + offsetY);
466             geometryNode->SetMarginFrameOffset(titleOffset);
467             titleWrapper->Layout();
468         }
469         return;
470     }
471     if (isInitialTitle_) {
472         // free mode
473         if (isCustom) {
474             // customBuilder and NavigationCustomTitle offset is (0.0f, menuHeight_)
475             auto customOffsetY = NearZero(menuWidth_) ? 0.0f : menuHeight_.ConvertToPx();
476             geometryNode->SetMarginFrameOffset(OffsetF { 0.0f, customOffsetY});
477             titleWrapper->Layout();
478             return;
479         }
480         auto title = AceType::DynamicCast<FrameNode>(titleNode);
481         CHECK_NULL_VOID(title);
482 
483         auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
484         if (!textLayoutProperty) {
485             // current title mode is Navigation common title
486             OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
487                 static_cast<float>(menuHeight_.ConvertToPx())+ offsetY);
488             geometryNode->SetMarginFrameOffset(titleOffset);
489             titleWrapper->Layout();
490             return;
491         }
492         MeasureContext context;
493         context.textContent = textLayoutProperty->GetContentValue();
494         context.fontSize = titleFontSize_;
495 #ifdef ENABLE_ROSEN_BACKEND
496         minTitleHeight_ = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(context).Height());
497 #else
498         minTitleHeight_ = 0.0;
499 #endif
500         initialTitleOffsetY_ = static_cast<float>(menuHeight_.ConvertToPx()) + offsetY;
501         isInitialTitle_ = false;
502         auto titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialTitleOffsetY_);
503         geometryNode->SetMarginFrameOffset(titleOffset);
504         titleWrapper->Layout();
505         return;
506     }
507 
508     auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
509     CHECK_NULL_VOID(titlePattern);
510     if (NearZero(titlePattern->GetTempTitleOffsetY())) {
511         initialTitleOffsetY_ = static_cast<float>(menuHeight_.ConvertToPx()) + offsetY;
512         auto titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialTitleOffsetY_);
513         geometryNode->SetMarginFrameOffset(titleOffset);
514         titleWrapper->Layout();
515         return;
516     }
517     auto overDragOffset = titlePattern->GetOverDragOffset();
518     auto titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
519         titlePattern->GetTempTitleOffsetY() + overDragOffset / 6.0f);
520     geometryNode->SetMarginFrameOffset(titleOffset);
521     titleWrapper->Layout();
522 }
523 
LayoutSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float titleHeight)524 void TitleBarLayoutAlgorithm::LayoutSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
525     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float titleHeight)
526 {
527     auto subtitleNode = titleBarNode->GetSubtitle();
528     CHECK_NULL_VOID_NOLOG(subtitleNode);
529     auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
530     auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
531     CHECK_NULL_VOID(subtitleWrapper);
532     auto geometryNode = subtitleWrapper->GetGeometryNode();
533 
534     auto subtitleHeight = geometryNode->GetFrameSize().Height();
535     float offsetY = 0.0f;
536     if (!NearZero(titleHeight)) {
537         offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight - subtitleHeight) / 2 +
538                   titleHeight;
539     } else {
540         offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - subtitleHeight) / 2;
541     }
542     // navDestination title bar
543     if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
544         TitleBarParentType::NAV_DESTINATION) {
545         // subtitle doesn't support custom title
546         if (GetNavigationBackButtonState(titleBarNode)) {
547             if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
548             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
549                 geometryNode->SetMarginFrameOffset(OffsetF { (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE
550                 + NAV_HORIZONTAL_MARGIN_M).ConvertToPx(), offsetY });
551             } else {
552                 geometryNode->SetMarginFrameOffset(OffsetF { (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE
553                 + NAV_HORIZONTAL_MARGIN_L).ConvertToPx(), offsetY });
554             }
555             subtitleWrapper->Layout();
556             return;
557         }
558 
559         OffsetF offset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
560         geometryNode->SetMarginFrameOffset(offset);
561         subtitleWrapper->Layout();
562         return;
563     }
564 
565     // navBar title bar
566     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
567         if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
568             if (isInitialSubtitle_) {
569                 initialSubtitleOffsetY_ = static_cast<float>(menuHeight_.ConvertToPx()) + offsetY;
570                 isInitialSubtitle_ = false;
571                 OffsetF titleOffset =
572                     OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialSubtitleOffsetY_);
573                 geometryNode->SetMarginFrameOffset(titleOffset);
574                 subtitleWrapper->Layout();
575                 return;
576             }
577 
578             auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
579             CHECK_NULL_VOID(titlePattern);
580             if (NearZero(titlePattern->GetTempTitleOffsetY())) {
581                 OffsetF titleOffset =
582                     OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialSubtitleOffsetY_);
583                 geometryNode->SetMarginFrameOffset(titleOffset);
584                 subtitleWrapper->Layout();
585                 return;
586             }
587             auto overDragOffset = titlePattern->GetOverDragOffset();
588             OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
589                 titlePattern->GetTempSubTitleOffsetY() + overDragOffset / 6.0f);
590             geometryNode->SetMarginFrameOffset(titleOffset);
591             subtitleWrapper->Layout();
592             return;
593         }
594         // full mode
595         OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
596             static_cast<float>(menuHeight_.ConvertToPx()) + offsetY);
597         geometryNode->SetMarginFrameOffset(titleOffset);
598         subtitleWrapper->Layout();
599         return;
600     }
601     // mini mode + hideBackButton true
602     if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
603         OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
604         geometryNode->SetMarginFrameOffset(titleOffset);
605         subtitleWrapper->Layout();
606         return;
607     }
608     Dimension occupiedWidth = Dimension(0.0f, DimensionUnit::PX);
609     // mini mode + back button
610     if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
611             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
612         occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M;
613     } else {
614         occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L;
615     }
616     OffsetF offset = OffsetF(static_cast<float>(occupiedWidth.ConvertToPx()), offsetY);
617     geometryNode->SetMarginFrameOffset(offset);
618     subtitleWrapper->Layout();
619 }
620 
LayoutMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)621 void TitleBarLayoutAlgorithm::LayoutMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
622     const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
623 {
624     auto menuNode = titleBarNode->GetMenu();
625     CHECK_NULL_VOID(menuNode);
626     auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
627     auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
628     CHECK_NULL_VOID(menuWrapper);
629     auto geometryNode = menuWrapper->GetGeometryNode();
630     auto menuWidth = geometryNode->GetMarginFrameSize().Width();
631     auto maxWidth = geometryNode->GetParentLayoutConstraint()->maxSize.Width();
632     auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
633     auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
634     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
635         auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
636         auto overDragOffset = titlePattern->GetOverDragOffset();
637         auto menuOffsetY = (SINGLE_LINE_TITLEBAR_HEIGHT - menuHeight_) / 2;
638         // custom menu width has no right padding
639         auto offsetX = isCustomMenu ? maxWidth - menuWidth :
640             (maxWidth - menuWidth - static_cast<float>(defaultPaddingStart_.ConvertToPx()));
641         if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
642             ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
643             geometryNode->SetMarginFrameOffset(OffsetF { maxWidth - menuWidth - defaultPaddingStart_.ConvertToPx(),
644                 static_cast<float>(menuOffsetY.ConvertToPx()) + overDragOffset / MENU_OFFSET_RATIO });
645             menuWrapper->Layout();
646             return;
647         }
648         OffsetF menuOffset(offsetX, static_cast<float>(menuOffsetY.ConvertToPx()) + overDragOffset / MENU_OFFSET_RATIO);
649         geometryNode->SetMarginFrameOffset(menuOffset);
650         menuWrapper->Layout();
651         return;
652     }
653     if (PipelineContext::GetCurrentContext() && (PipelineContext::GetCurrentContext()->GetMinPlatformVersion() <
654         static_cast<int32_t>(PlatformVersion::VERSION_TEN))) {
655         auto totalHeight = NearZero(subtitleHeight) ? SINGLE_LINE_TITLEBAR_HEIGHT : DOUBLE_LINE_TITLEBAR_HEIGHT;
656         geometryNode->SetMarginFrameOffset(OffsetF { maxWidth - menuWidth - defaultPaddingStart_.ConvertToPx(),
657             ((totalHeight - menuHeight_).ConvertToPx()) / 2 });
658         menuWrapper->Layout();
659         return;
660     }
661     auto menuOffsetY =  (SINGLE_LINE_TITLEBAR_HEIGHT - menuHeight_) / 2;
662     auto menuOffsetX = maxWidth - menuWidth;
663     // custom menu doesn't have right padding. if menu isn't custom, menu items has right padding
664     menuOffsetX = isCustomMenu ? menuOffsetX : menuOffsetX - defaultPaddingStart_.ConvertToPx();
665 
666     OffsetF menuOffset(menuOffsetX, static_cast<float>(menuOffsetY.ConvertToPx()));
667     geometryNode->SetMarginFrameOffset(menuOffset);
668     menuWrapper->Layout();
669 }
670 
671 // set variables from theme
InitializeTheme()672 void TitleBarLayoutAlgorithm::InitializeTheme()
673 {
674     auto theme = NavigationGetTheme();
675     CHECK_NULL_VOID(theme);
676     maxPaddingStart_ = theme->GetMaxPaddingStart();
677     maxPaddingEnd_ = theme->GetMaxPaddingEnd();
678     menuHeight_ = theme->GetHeight();
679     defaultPaddingStart_ = theme->GetDefaultPaddingStart();
680     iconSize_ = theme->GetMenuIconSize();
681     titleFontSize_ = theme->GetTitleFontSize();
682 }
683 
Measure(LayoutWrapper * layoutWrapper)684 void TitleBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
685 {
686     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
687     CHECK_NULL_VOID(titleBarNode);
688     auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
689     CHECK_NULL_VOID(layoutProperty);
690     const auto& constraint = layoutProperty->GetLayoutConstraint();
691     CHECK_NULL_VOID(constraint);
692     auto size = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT, true);
693     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
694     MinusPaddingToSize(padding, size);
695     InitializeTheme();
696 
697     MeasureBackButton(layoutWrapper, titleBarNode, layoutProperty);
698     MeasureMenu(layoutWrapper, titleBarNode, layoutProperty);
699     auto titleMaxWidth = GetTitleWidth(titleBarNode, layoutProperty, size);
700     MeasureSubtitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
701     MeasureTitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
702     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
703 }
704 
Layout(LayoutWrapper * layoutWrapper)705 void TitleBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
706 {
707     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
708     CHECK_NULL_VOID(titleBarNode);
709     auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
710     CHECK_NULL_VOID(layoutProperty);
711     LayoutBackButton(layoutWrapper, titleBarNode, layoutProperty);
712 
713     float subtitleHeight = 0.0f;
714     auto subtitleNode = titleBarNode->GetSubtitle();
715     if (subtitleNode) {
716         auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
717         auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
718         CHECK_NULL_VOID(subtitleWrapper);
719         auto geometryNode = subtitleWrapper->GetGeometryNode();
720         subtitleHeight = geometryNode->GetFrameSize().Height();
721     }
722     LayoutTitle(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
723 
724     float titleHeight = 0.0f;
725     auto titleNode = titleBarNode->GetTitle();
726     if (titleNode) {
727         auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
728         auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
729         CHECK_NULL_VOID(titleWrapper);
730         auto geometryNode = titleWrapper->GetGeometryNode();
731         titleHeight = geometryNode->GetFrameSize().Height();
732     }
733     LayoutSubtitle(layoutWrapper, titleBarNode, layoutProperty, titleHeight);
734 
735     LayoutMenu(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
736 }
737 
GetNavigationBackButtonState(const RefPtr<TitleBarNode> & titleBarNode)738 bool TitleBarLayoutAlgorithm::GetNavigationBackButtonState(const RefPtr<TitleBarNode>& titleBarNode)
739 {
740     auto backButton = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
741     CHECK_NULL_RETURN_NOLOG(backButton, false);
742     auto layoutProperty = backButton->GetLayoutProperty();
743     CHECK_NULL_RETURN(layoutProperty, false);
744     return layoutProperty->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE;
745 }
746 } // namespace OHOS::Ace::NG
747