• 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/tabs/tab_bar_layout_algorithm.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/geometry/dimension.h"
20 #include "base/geometry/ng/offset_t.h"
21 #include "base/geometry/ng/size_t.h"
22 #include "base/log/ace_trace.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/layout/grid_layout_info.h"
25 #include "core/components/common/layout/grid_system_manager.h"
26 #include "core/components/tab_bar/tab_theme.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/layout/layout_algorithm.h"
29 #include "core/components_ng/pattern/image/image_layout_property.h"
30 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
31 #include "core/components_ng/pattern/tabs/tab_bar_paint_property.h"
32 #include "core/components_ng/pattern/tabs/tab_bar_pattern.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 #include "core/pipeline_ng/pipeline_context.h"
38 
39 namespace OHOS::Ace::NG {
40 namespace {
41 constexpr int8_t MASK_COUNT = 2;
42 constexpr int8_t SM_COLUMN_NUM = 4;
43 constexpr int8_t MD_COLUMN_NUM = 8;
44 constexpr int8_t LG_COLUMN_NUM = 12;
45 } // namespace
UpdateChildConstraint(LayoutConstraintF & childConstraint,const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & ideaSize,int32_t childCount,Axis axis)46 void TabBarLayoutAlgorithm::UpdateChildConstraint(LayoutConstraintF& childConstraint,
47     const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& ideaSize, int32_t childCount, Axis axis)
48 {
49     childConstraint.parentIdealSize = OptionalSizeF(ideaSize);
50     const auto& barMode = layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED);
51     auto pipelineContext = PipelineContext::GetCurrentContext();
52     CHECK_NULL_VOID(pipelineContext);
53     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
54     CHECK_NULL_VOID(tabTheme);
55     if (barMode == TabBarMode::FIXED) {
56         auto childIdeaSize = ideaSize;
57         if (axis == Axis::HORIZONTAL) {
58             childIdeaSize.SetWidth(GetContentWidth(layoutProperty, ideaSize) / childCount);
59             childConstraint.maxSize.SetHeight(childConstraint.maxSize.Height());
60             if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
61                 childConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
62             }
63         } else if (axis == Axis::VERTICAL) {
64             childIdeaSize.SetHeight(tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE
65                                         ? ideaSize.Height() / (childCount * 2)
66                                         : ideaSize.Height() / childCount);
67         }
68         childConstraint.selfIdealSize = OptionalSizeF(childIdeaSize);
69     } else {
70         if (axis == Axis::HORIZONTAL) {
71             childConstraint.maxSize.SetWidth(Infinity<float>());
72             childConstraint.maxSize.SetHeight(childConstraint.maxSize.Height());
73             childConstraint.selfIdealSize.SetHeight(ideaSize.Height());
74             if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
75                 childConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
76             }
77         } else if (axis == Axis::VERTICAL) {
78             childConstraint.maxSize.SetHeight(Infinity<float>());
79             childConstraint.selfIdealSize.SetWidth(ideaSize.Width());
80         }
81     }
82 }
83 
Measure(LayoutWrapper * layoutWrapper)84 void TabBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
85 {
86     previousChildrenMainSize_ = childrenMainSize_;
87     auto pipelineContext = PipelineContext::GetCurrentContext();
88     CHECK_NULL_VOID(pipelineContext);
89     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
90     CHECK_NULL_VOID(tabTheme);
91     auto geometryNode = layoutWrapper->GetGeometryNode();
92     CHECK_NULL_VOID(geometryNode);
93     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
94     CHECK_NULL_VOID(layoutProperty);
95     auto axis = GetAxis(layoutWrapper);
96     auto constraint = layoutProperty->GetLayoutConstraint();
97     auto idealSize =
98         CreateIdealSize(constraint.value(), axis, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT));
99 
100     auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
101     if (childCount <= 0) {
102         return;
103     }
104 
105     if (axis == Axis::VERTICAL && constraint->selfIdealSize.Width().has_value() &&
106         constraint->selfIdealSize.Width().value() < constraint->parentIdealSize.Width().value_or(0.0f) &&
107         constraint->selfIdealSize.Width().value() > tabTheme->GetHorizontalBottomTabMinWidth().ConvertToPx()) {
108         // Vertical tab bar may apply LayoutMode.AUTO
109         ApplyLayoutMode(layoutWrapper, constraint->selfIdealSize.Width().value(), childCount);
110     }
111     if (constraint->selfIdealSize.Width().has_value() &&
112         constraint->selfIdealSize.Width().value() > constraint->parentIdealSize.Width().value_or(0.0f)) {
113         idealSize.SetWidth(static_cast<float>(
114             axis == Axis::HORIZONTAL                         ? constraint->parentIdealSize.Width().value_or(0.0f)
115             : tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE ? tabTheme->GetTabBarDefaultWidth().ConvertToPx()
116                                                              : tabTheme->GetTabBarDefaultHeight().ConvertToPx()));
117     }
118     if (constraint->selfIdealSize.Height().has_value() &&
119         constraint->selfIdealSize.Height().value() > constraint->parentIdealSize.Height().value_or(0.0f)) {
120         idealSize.SetHeight(
121             static_cast<float>(axis == Axis::HORIZONTAL ? tabTheme->GetTabBarDefaultHeight().ConvertToPx()
122                                                         : constraint->parentIdealSize.Height().value_or(0.0f)));
123     }
124     if (!constraint->selfIdealSize.Width().has_value() && axis == Axis::VERTICAL) {
125         idealSize.SetWidth(static_cast<float>(tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE
126                                                   ? tabTheme->GetTabBarDefaultWidth().ConvertToPx()
127                                                   : tabTheme->GetTabBarDefaultHeight().ConvertToPx()));
128     }
129 
130     auto frameSize = idealSize.ConvertToSizeT();
131 
132     if (axis == Axis::HORIZONTAL) {
133         ConfigHorizontal(layoutWrapper, frameSize, childCount);
134     } else {
135         UpdateHorizontalPadding(layoutWrapper, 0.0f);
136     }
137 
138     if (!constraint->selfIdealSize.Height().has_value() && axis == Axis::HORIZONTAL) {
139         idealSize.SetHeight(std::max(static_cast<float>(tabTheme->GetTabBarDefaultHeight().ConvertToPx()), maxHeight_));
140     }
141 
142     geometryNode->SetFrameSize(idealSize.ConvertToSizeT());
143 
144     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
145     UpdateChildConstraint(childLayoutConstraint, layoutProperty, idealSize.ConvertToSizeT(), childCount, axis);
146 
147     // Measure children.
148     childrenMainSize_ = (axis == Axis::VERTICAL ? 0.0f : scrollMargin_ * 2);
149     for (int32_t index = 0; index < childCount; ++index) {
150         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
151         if (!childWrapper) {
152             continue;
153         }
154         if (static_cast<int32_t>(itemWidths_.size()) == childCount && useItemWidth_) {
155             auto childIdeaSize = idealSize.ConvertToSizeT();
156             childIdeaSize.SetWidth(itemWidths_[index]);
157             childLayoutConstraint.selfIdealSize = OptionalSizeF(childIdeaSize);
158         }
159         childWrapper->Measure(childLayoutConstraint);
160         if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
161             // In fixed mode, large paddings may overwhelm the constraint after measure
162             AdjustFixedItem(childWrapper, childLayoutConstraint.selfIdealSize, axis);
163         }
164         childrenMainSize_ += childWrapper->GetGeometryNode()->GetMarginFrameSize().MainSize(axis);
165     }
166     MeasureMask(layoutWrapper, childCount);
167 }
168 
CheckMarqueeForScrollable(LayoutWrapper * layoutWrapper,int32_t childCount) const169 void TabBarLayoutAlgorithm::CheckMarqueeForScrollable(LayoutWrapper* layoutWrapper, int32_t childCount) const
170 {
171     for (int32_t index = 0; index < childCount; ++index) {
172         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
173         CHECK_NULL_VOID(childWrapper);
174         auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
175         CHECK_NULL_VOID(textWrapper);
176         auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
177         CHECK_NULL_VOID(textLayoutProperty);
178         if (textLayoutProperty->GetTextOverflow().value_or(TextOverflow::NONE) == TextOverflow::MARQUEE) {
179             textLayoutProperty->UpdateTextOverflow(TextOverflow::NONE);
180         }
181     }
182 }
183 
MeasureMask(LayoutWrapper * layoutWrapper,int32_t childCount) const184 void TabBarLayoutAlgorithm::MeasureMask(LayoutWrapper* layoutWrapper, int32_t childCount) const
185 {
186     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
187     CHECK_NULL_VOID(layoutProperty);
188     auto maskLayoutConstraint = layoutProperty->CreateChildConstraint();
189     auto selectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount);
190     CHECK_NULL_VOID(selectedMaskWrapper);
191     maskLayoutConstraint.selfIdealSize = OptionalSizeF(selectedMaskWrapper->GetGeometryNode()->GetFrameSize());
192     selectedMaskWrapper->Measure(maskLayoutConstraint);
193 
194     auto unselectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount + 1);
195     CHECK_NULL_VOID(unselectedMaskWrapper);
196     maskLayoutConstraint.selfIdealSize = OptionalSizeF(unselectedMaskWrapper->GetGeometryNode()->GetFrameSize());
197     unselectedMaskWrapper->Measure(maskLayoutConstraint);
198 }
199 
ConfigHorizontal(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)200 void TabBarLayoutAlgorithm::ConfigHorizontal(LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
201 {
202     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
203     CHECK_NULL_VOID(layoutProperty);
204 
205     // Apply grid column options to the tab bar
206     auto horizontalPadding = ApplyBarGridAlign(layoutProperty, frameSize);
207 
208     UpdateHorizontalPadding(layoutWrapper, horizontalPadding);
209 
210     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
211         HandleFixedMode(layoutWrapper, frameSize, childCount);
212     } else {
213         // Handle scrollable mode
214         auto layoutStyle = layoutProperty->GetScrollableBarModeOptions().value_or(ScrollableBarModeOptions());
215         scrollMargin_ = layoutStyle.margin.ConvertToPx();
216         CheckMarqueeForScrollable(layoutWrapper, childCount);
217         MeasureItemWidths(layoutWrapper, childCount);
218 
219         if (layoutStyle.nonScrollableLayoutStyle == LayoutStyle::ALWAYS_AVERAGE_SPLIT) {
220             HandleAlwaysAverageSplitLayoutStyle(layoutWrapper, frameSize, childCount);
221         } else if (layoutStyle.nonScrollableLayoutStyle == LayoutStyle::SPACE_BETWEEN_OR_CENTER) {
222             HandleSpaceBetweenOrCenterLayoutStyle(layoutWrapper, frameSize, childCount);
223         } else if (layoutStyle.nonScrollableLayoutStyle == LayoutStyle::ALWAYS_CENTER) {
224             if (LessOrEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize))) {
225                 childrenMainSize_ -= scrollMargin_ * 2;
226                 scrollMargin_ = 0.0f;
227             } else {
228                 useItemWidth_ = false;
229             }
230         }
231     }
232     if (layoutProperty->GetBarAdaptiveHeight().value_or(false)) {
233         MeasureMaxHeight(layoutWrapper, childCount);
234     }
235 }
236 
HandleFixedMode(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)237 void TabBarLayoutAlgorithm::HandleFixedMode(LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
238 {
239     if (childCount <= 0) {
240         return;
241     }
242     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
243     CHECK_NULL_VOID(layoutProperty);
244 
245     auto allocatedWidth = GetContentWidth(layoutProperty, frameSize) / childCount;
246     MeasureItemWidths(layoutWrapper, childCount);
247     ApplyLayoutMode(layoutWrapper, allocatedWidth, childCount);
248     ApplySymmetricExtensible(layoutWrapper, allocatedWidth, childCount);
249 }
250 
MeasureItemWidths(LayoutWrapper * layoutWrapper,int32_t childCount)251 void TabBarLayoutAlgorithm::MeasureItemWidths(LayoutWrapper* layoutWrapper, int32_t childCount)
252 {
253     auto pipelineContext = PipelineContext::GetCurrentContext();
254     CHECK_NULL_VOID(pipelineContext);
255     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
256     CHECK_NULL_VOID(tabTheme);
257     auto host = layoutWrapper->GetHostNode();
258     CHECK_NULL_VOID(host);
259     auto tabBarPattern = host->GetPattern<TabBarPattern>();
260     CHECK_NULL_VOID(tabBarPattern);
261 
262     childrenMainSize_ = scrollMargin_ * 2;
263     itemWidths_.clear();
264     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
265     CHECK_NULL_VOID(layoutProperty);
266     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
267     childLayoutConstraint.maxSize.SetWidth(Infinity<float>());
268     if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
269         childLayoutConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
270     }
271     for (int32_t index = 0; index < childCount; ++index) {
272         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
273         CHECK_NULL_VOID (childWrapper);
274         if (tabBarPattern->GetTabBarStyle(index) == TabBarStyle::BOTTOMTABBATSTYLE) {
275             auto imageWrapper = childWrapper->GetOrCreateChildByIndex(0);
276             CHECK_NULL_VOID(imageWrapper);
277             auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(imageWrapper->GetLayoutProperty());
278             CHECK_NULL_VOID(imageLayoutProperty);
279             imageLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {} });
280             auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
281             CHECK_NULL_VOID(textWrapper);
282             auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
283             CHECK_NULL_VOID(textLayoutProperty);
284             textLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {} });
285         }
286 
287         childWrapper->Measure(childLayoutConstraint);
288         auto geometryNode = childWrapper->GetGeometryNode();
289         CHECK_NULL_VOID(geometryNode);
290         itemWidths_.emplace_back(geometryNode->GetMarginFrameSize().MainSize(Axis::HORIZONTAL));
291         childrenMainSize_ += itemWidths_.back();
292     }
293 }
294 
MeasureMaxHeight(LayoutWrapper * layoutWrapper,int32_t childCount)295 void TabBarLayoutAlgorithm::MeasureMaxHeight(LayoutWrapper* layoutWrapper, int32_t childCount)
296 {
297     auto pipelineContext = PipelineContext::GetCurrentContext();
298     CHECK_NULL_VOID(pipelineContext);
299     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
300     CHECK_NULL_VOID(tabTheme);
301 
302     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
303     CHECK_NULL_VOID(layoutProperty);
304     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
305     childLayoutConstraint.maxSize.SetWidth(Infinity<float>());
306     if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
307         childLayoutConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
308     }
309     for (int32_t index = 0; index < childCount; ++index) {
310         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
311         CHECK_NULL_VOID(childWrapper);
312         if (static_cast<int32_t>(itemWidths_.size()) == childCount) {
313             childLayoutConstraint.selfIdealSize.SetWidth(itemWidths_[index]);
314         }
315         childWrapper->Measure(childLayoutConstraint);
316         auto geometryNode = childWrapper->GetGeometryNode();
317         CHECK_NULL_VOID(geometryNode);
318         maxHeight_ =
319             std::max(maxHeight_, geometryNode->GetMarginFrameSize().MainSize(Axis::VERTICAL));
320     }
321 }
322 
HandleAlwaysAverageSplitLayoutStyle(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)323 void TabBarLayoutAlgorithm::HandleAlwaysAverageSplitLayoutStyle(
324     LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
325 {
326     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
327     CHECK_NULL_VOID(layoutProperty);
328 
329     if (GreatNotEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize)) || childCount <= 0 ||
330         childCount != static_cast<int32_t>(itemWidths_.size())) {
331         useItemWidth_ = false;
332         return;
333     }
334 
335     bool hasLongItem = false;
336     int32_t remainingChildCount = childCount;
337     childrenMainSize_ -= scrollMargin_ * 2;
338     auto totalWidth = GetContentWidth(layoutProperty, frameSize) - scrollMargin_ * 2;
339     scrollMargin_ = 0.0f;
340     auto allocatedItemWidth = totalWidth / remainingChildCount;
341 
342     std::vector<float> originalWidth;
343     for (int32_t index = 0; index < childCount; index++) {
344         originalWidth.emplace_back(itemWidths_[index]);
345         itemWidths_[index] = 0.0f;
346     }
347 
348     /* Calculate the widths of long items. A long item refers to an item whose length is above the average,
349         so remainingChildCount can't be zero */
350     do {
351         hasLongItem = false;
352         for (int32_t index = 0; index < childCount; index++) {
353             if (NearZero(itemWidths_[index]) && GreatNotEqual(originalWidth[index], allocatedItemWidth)) {
354                 itemWidths_[index] = originalWidth[index];
355                 hasLongItem = true;
356                 remainingChildCount--;
357                 totalWidth -= originalWidth[index];
358             }
359         }
360         allocatedItemWidth = totalWidth / remainingChildCount;
361     } while (hasLongItem);
362 
363     // Calculate the widths of other items
364     for (int32_t index = 0; index < childCount; index++) {
365         if (NearZero(itemWidths_[index])) {
366             itemWidths_[index] = allocatedItemWidth;
367         }
368     }
369 }
370 
HandleSpaceBetweenOrCenterLayoutStyle(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)371 void TabBarLayoutAlgorithm::HandleSpaceBetweenOrCenterLayoutStyle(
372     LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
373 {
374     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
375     CHECK_NULL_VOID(layoutProperty);
376 
377     if (GreatNotEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize)) || childCount <= 0 ||
378         childCount != static_cast<int32_t>(itemWidths_.size())) {
379         useItemWidth_ = false;
380         return;
381     }
382 
383     childrenMainSize_ -= scrollMargin_ * 2;
384     scrollMargin_ = 0.0f;
385 
386     if (GreatNotEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize) / 2)) {
387         useItemWidth_ = false;
388         return;
389     }
390     auto additionalWidth = (GetContentWidth(layoutProperty, frameSize) / 2 - childrenMainSize_) / childCount;
391 
392     for (int32_t index = 0; index < childCount; ++index) {
393         itemWidths_[index] += additionalWidth;
394     }
395 }
396 
ApplyLayoutMode(LayoutWrapper * layoutWrapper,float allocatedWidth,int32_t childCount)397 void TabBarLayoutAlgorithm::ApplyLayoutMode(LayoutWrapper* layoutWrapper, float allocatedWidth, int32_t childCount)
398 {
399     auto pipelineContext = PipelineContext::GetCurrentContext();
400     CHECK_NULL_VOID(pipelineContext);
401     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
402     CHECK_NULL_VOID(tabTheme);
403     auto host = layoutWrapper->GetHostNode();
404     CHECK_NULL_VOID(host);
405     auto tabBarPattern = host->GetPattern<TabBarPattern>();
406     CHECK_NULL_VOID(tabBarPattern);
407 
408     bool isVertical = true;
409     if (GreatNotEqual(allocatedWidth, tabTheme->GetHorizontalBottomTabMinWidth().ConvertToPx())) {
410         isVertical = false;
411     }
412 
413     // Calculate the initial buffer and initial space request of each item.
414     for (int32_t index = 0; index < childCount; ++index) {
415         auto bottomTabBarStyle = tabBarPattern->GetBottomTabBarStyle(index);
416         if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE ||
417             bottomTabBarStyle.layoutMode != LayoutMode::AUTO) {
418             continue;
419         }
420         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
421         CHECK_NULL_VOID(childWrapper);
422         auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
423         CHECK_NULL_VOID(linearLayoutProperty);
424         auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
425         CHECK_NULL_VOID(textWrapper);
426         auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
427         CHECK_NULL_VOID(textLayoutProperty);
428         if (isVertical) {
429             linearLayoutProperty->UpdateFlexDirection(FlexDirection::COLUMN);
430             linearLayoutProperty->UpdateSpace(tabTheme->GetBottomTabBarSpace());
431             linearLayoutProperty->UpdateMainAxisAlign(bottomTabBarStyle.verticalAlign);
432             linearLayoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
433             linearLayoutProperty->SetIsVertical(true);
434             textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
435         } else {
436             linearLayoutProperty->UpdateFlexDirection(FlexDirection::ROW);
437             linearLayoutProperty->UpdateSpace(tabTheme->GetHorizontalBottomTabBarSpace());
438             linearLayoutProperty->UpdateMainAxisAlign(FlexAlign::CENTER);
439             linearLayoutProperty->UpdateCrossAxisAlign(bottomTabBarStyle.verticalAlign);
440             linearLayoutProperty->SetIsVertical(false);
441             textLayoutProperty->UpdateTextAlign(TextAlign::LEFT);
442         }
443     }
444 }
445 
ApplySymmetricExtensible(LayoutWrapper * layoutWrapper,float allocatedWidth,int32_t childCount)446 void TabBarLayoutAlgorithm::ApplySymmetricExtensible(
447     LayoutWrapper* layoutWrapper, float allocatedWidth, int32_t childCount)
448 {
449     auto host = layoutWrapper->GetHostNode();
450     CHECK_NULL_VOID(host);
451     auto tabBarPattern = host->GetPattern<TabBarPattern>();
452     CHECK_NULL_VOID(tabBarPattern);
453 
454     if (childCount <= 2 || static_cast<int32_t>(itemWidths_.size()) != childCount) {
455         useItemWidth_ = false;
456         for (int32_t index = 0; index < static_cast<int32_t>(itemWidths_.size()); ++index) {
457             itemWidths_[index] = allocatedWidth;
458         }
459         return;
460     }
461 
462     std::vector<float> leftBuffers(childCount);
463     std::vector<float> rightBuffers(childCount);
464     std::vector<float> spaceRequests(childCount);
465 
466     // Calculate the initial buffer and initial space request of each item.
467     for (int32_t index = 0; index < childCount; ++index) {
468         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
469         CHECK_NULL_VOID(childWrapper);
470         auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
471         CHECK_NULL_VOID(linearLayoutProperty);
472         if (GreatNotEqual(itemWidths_[index], allocatedWidth)) {
473             if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE ||
474                 !tabBarPattern->GetBottomTabBarStyle(index).symmetricExtensible || index == 0 ||
475                 index == childCount - 1) {
476                 spaceRequests[index] = 0.0f;
477             } else {
478                 spaceRequests[index] = (itemWidths_[index] - allocatedWidth) / 2;
479             }
480             leftBuffers[index] = 0.0f;
481             rightBuffers[index] = 0.0f;
482         } else {
483             if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE) {
484                 leftBuffers[index] = 0.0f;
485                 rightBuffers[index] = 0.0f;
486             } else {
487                 leftBuffers[index] = (index == 0 ? 0.0f : (allocatedWidth - itemWidths_[index]) / 2);
488                 rightBuffers[index] = (index == childCount - 1 ? 0.0f : (allocatedWidth - itemWidths_[index]) / 2);
489             }
490             spaceRequests[index] = 0.0f;
491         }
492     }
493 
494     // Decide the used buffer and used space request of each item.
495     for (int32_t index = 1; index < childCount - 1; ++index) {
496         auto actualRequest = std::min(std::min(rightBuffers[index - 1], leftBuffers[index + 1]), spaceRequests[index]);
497         spaceRequests[index] = actualRequest;
498         rightBuffers[index - 1] = actualRequest;
499         leftBuffers[index + 1] = actualRequest;
500     }
501 
502     spaceRequests[0] = 0.0f;
503     spaceRequests[childCount - 1] = 0.0f;
504 
505     leftBuffers[1] = 0.0f;
506     rightBuffers[childCount - 2] = 0.0f;
507 
508     CalculateItemWidthsForSymmetricExtensible(
509         layoutWrapper, childCount, spaceRequests, leftBuffers, rightBuffers, allocatedWidth);
510 }
511 
CalculateItemWidthsForSymmetricExtensible(LayoutWrapper * layoutWrapper,int32_t childCount,const std::vector<float> & spaceRequests,const std::vector<float> & leftBuffers,const std::vector<float> & rightBuffers,float allocatedWidth)512 void TabBarLayoutAlgorithm::CalculateItemWidthsForSymmetricExtensible(LayoutWrapper* layoutWrapper, int32_t childCount,
513     const std::vector<float>& spaceRequests, const std::vector<float>& leftBuffers,
514     const std::vector<float>& rightBuffers, float allocatedWidth)
515 {
516     auto host = layoutWrapper->GetHostNode();
517     CHECK_NULL_VOID(host);
518     auto tabBarPattern = host->GetPattern<TabBarPattern>();
519     CHECK_NULL_VOID(tabBarPattern);
520 
521     if ((static_cast<int32_t>(spaceRequests.size()) != childCount) ||
522         (static_cast<int32_t>(leftBuffers.size()) != childCount) ||
523         (static_cast<int32_t>(rightBuffers.size()) != childCount) ||
524         (static_cast<int32_t>(itemWidths_.size()) != childCount)) {
525         return;
526     }
527 
528     for (int32_t index = 0; index < childCount; ++index) {
529         if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE) {
530             itemWidths_[index] = allocatedWidth;
531             continue;
532         }
533         if (!NearZero(spaceRequests[index])) {
534             itemWidths_[index] = allocatedWidth + spaceRequests[index] * 2;
535         } else if (!NearZero(leftBuffers[index]) || !NearZero(rightBuffers[index])) {
536             itemWidths_[index] = allocatedWidth - leftBuffers[index] - rightBuffers[index];
537             auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
538             CHECK_NULL_VOID(childWrapper);
539             auto imageWrapper = childWrapper->GetOrCreateChildByIndex(0);
540             CHECK_NULL_VOID(imageWrapper);
541             auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(imageWrapper->GetLayoutProperty());
542             CHECK_NULL_VOID(imageLayoutProperty);
543 
544             // Adjust margin to keep the position of current item.
545             auto leftMargin = rightBuffers[index];
546             auto rightMargin = leftBuffers[index];
547             if (GreatNotEqual(leftMargin, rightMargin)) {
548                 leftMargin -= rightMargin;
549                 rightMargin = 0.0f;
550             } else {
551                 rightMargin -= leftMargin;
552                 leftMargin = 0.0f;
553             }
554             imageLayoutProperty->UpdateMargin(
555                 { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {} });
556             auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
557             CHECK_NULL_VOID(textWrapper);
558             auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
559             CHECK_NULL_VOID(textLayoutProperty);
560             textLayoutProperty->UpdateMargin(
561                 { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {} });
562             auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
563             CHECK_NULL_VOID(linearLayoutProperty);
564             if (linearLayoutProperty->GetFlexDirection().value_or(FlexDirection::COLUMN) == FlexDirection::ROW) {
565                 imageLayoutProperty->UpdateMargin({ CalcLength(Dimension(leftMargin)), {}, {}, {} });
566                 textLayoutProperty->UpdateMargin({ {}, CalcLength(Dimension(rightMargin)), {}, {} });
567             }
568         } else {
569             itemWidths_[index] = allocatedWidth;
570         }
571     }
572 }
573 
ApplyBarGridAlign(const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & frameSize) const574 float TabBarLayoutAlgorithm::ApplyBarGridAlign(
575     const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& frameSize) const
576 {
577     if (!layoutProperty->GetBarGridAlign()) {
578         return 0.0f;
579     }
580     auto option = layoutProperty->GetBarGridAlign().value();
581     auto gridSizeType = GetGridSizeType(frameSize);
582     int32_t columnNum = -1;
583     if (gridSizeType == GridSizeType::SM) {
584         columnNum = option.sm;
585         if (columnNum > SM_COLUMN_NUM) {
586             return 0.0f;
587         }
588     } else if (gridSizeType == GridSizeType::MD) {
589         columnNum = option.md;
590         if (columnNum > MD_COLUMN_NUM) {
591             return 0.0f;
592         }
593     } else if (gridSizeType == GridSizeType::LG) {
594         columnNum = option.lg;
595         if (columnNum > LG_COLUMN_NUM) {
596             return 0.0f;
597         }
598     } else {
599         return 0.0f;
600     }
601     if (columnNum < 0 || columnNum % 2) {
602         return 0.0f;
603     }
604     auto gridWidth = GetGridWidth(option, frameSize, columnNum);
605     return (frameSize.Width() - gridWidth) / 2;
606 }
607 
Layout(LayoutWrapper * layoutWrapper)608 void TabBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
609 {
610     tabItemOffset_.clear();
611     CHECK_NULL_VOID(layoutWrapper);
612     auto geometryNode = layoutWrapper->GetGeometryNode();
613     CHECK_NULL_VOID(geometryNode);
614     auto axis = GetAxis(layoutWrapper);
615     auto frameSize = geometryNode->GetPaddingSize();
616 
617     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
618     CHECK_NULL_VOID(layoutProperty);
619     int32_t indicator = layoutProperty->GetIndicatorValue(0);
620     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED &&
621         tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE && axis == Axis::VERTICAL) {
622         indicator_ = indicator;
623         auto space = frameSize.Height() / 4;
624         OffsetF childOffset = OffsetF(0.0f, space);
625         LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
626         return;
627     }
628     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED &&
629         tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
630         indicator_ = indicator;
631         currentOffset_ = 0.0f;
632         OffsetF childOffset = OffsetF(0.0f, 0.0f);
633         LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
634         return;
635     }
636     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
637         childrenMainSize_ <= frameSize.MainSize(axis)) {
638         indicator_ = indicator;
639         auto frontSpace = (frameSize.MainSize(axis) - childrenMainSize_) / 2;
640         OffsetF childOffset = (axis == Axis::HORIZONTAL ? OffsetF(frontSpace, 0.0f) : OffsetF(0.0f, frontSpace));
641         LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
642         return;
643     }
644     if ((indicator != indicator_ || (indicator == indicator_ && needSetCentered_)) &&
645         layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
646         if (childrenMainSize_ > frameSize.MainSize(axis) && tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE &&
647             axis == Axis::HORIZONTAL) {
648             OffsetF childOffset = OffsetF(currentOffset_, 0.0f);
649             indicator_ = indicator;
650             LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
651             return;
652         }
653         indicator_ = indicator;
654         auto space = GetSpace(layoutWrapper, indicator, frameSize, axis);
655         float frontChildrenMainSize = CalculateFrontChildrenMainSize(layoutWrapper, indicator, axis);
656         if (space < 0.0f) {
657             OffsetF childOffset = (axis == Axis::HORIZONTAL ? OffsetF(-frontChildrenMainSize, 0.0f)
658                                                             : OffsetF(0.0f, -frontChildrenMainSize));
659             currentOffset_ = -frontChildrenMainSize;
660             LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
661             return;
662         }
663         if (frontChildrenMainSize < space) {
664             OffsetF childOffset = OffsetF(0.0f, 0.0f);
665             currentOffset_ = 0.0f;
666             LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
667             return;
668         }
669         float backChildrenMainSize = CalculateBackChildrenMainSize(layoutWrapper, indicator, axis);
670         if (backChildrenMainSize < space) {
671             auto scrollableDistance = std::max(childrenMainSize_ - frameSize.MainSize(axis), 0.0f);
672             currentOffset_ = -scrollableDistance;
673             OffsetF childOffset =
674                 (axis == Axis::HORIZONTAL ? OffsetF(-scrollableDistance, 0.0f) : OffsetF(0.0f, -scrollableDistance));
675             LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
676             return;
677         }
678         auto scrollableDistance = std::max(frontChildrenMainSize - space, 0.0f);
679         currentOffset_ = -scrollableDistance;
680         OffsetF childOffset =
681             (axis == Axis::HORIZONTAL ? OffsetF(-scrollableDistance, 0.0f) : OffsetF(0.0f, -scrollableDistance));
682         LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
683         return;
684     }
685     if (tabBarStyle_ != TabBarStyle::SUBTABBATSTYLE || axis == Axis::VERTICAL ||
686         previousChildrenMainSize_ != childrenMainSize_) {
687         auto scrollableDistance = std::max(childrenMainSize_ - frameSize.MainSize(axis), 0.0f);
688         currentOffset_ = std::clamp(currentOffset_, -scrollableDistance, 0.0f);
689     }
690     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
691         currentOffset_ = 0.0f;
692     }
693     OffsetF childOffset = (axis == Axis::HORIZONTAL ? OffsetF(currentOffset_, 0.0f) : OffsetF(0.0f, currentOffset_));
694     indicator_ = indicator;
695     LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
696 }
697 
GetAxis(LayoutWrapper * layoutWrapper) const698 Axis TabBarLayoutAlgorithm::GetAxis(LayoutWrapper* layoutWrapper) const
699 {
700     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
701     CHECK_NULL_RETURN(layoutProperty, Axis::HORIZONTAL);
702     return layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
703 }
704 
GetSpace(LayoutWrapper * layoutWrapper,int32_t indicator,const SizeF & frameSize,Axis axis)705 float TabBarLayoutAlgorithm::GetSpace(
706     LayoutWrapper* layoutWrapper, int32_t indicator, const SizeF& frameSize, Axis axis)
707 {
708     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(indicator);
709     if (!childWrapper) {
710         return 0.0f;
711     }
712     auto childGeometryNode = childWrapper->GetGeometryNode();
713     auto childFrameSize = childGeometryNode->GetMarginFrameSize();
714     return (frameSize.MainSize(axis) - childFrameSize.MainSize(axis)) / 2;
715 }
716 
CalculateFrontChildrenMainSize(LayoutWrapper * layoutWrapper,int32_t indicator,Axis axis)717 float TabBarLayoutAlgorithm::CalculateFrontChildrenMainSize(LayoutWrapper* layoutWrapper, int32_t indicator, Axis axis)
718 {
719     float frontChildrenMainSize = scrollMargin_;
720     for (int32_t index = 0; index < indicator; ++index) {
721         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
722         if (!childWrapper) {
723             return 0.0f;
724         }
725         auto childGeometryNode = childWrapper->GetGeometryNode();
726         auto childFrameSize = childGeometryNode->GetMarginFrameSize();
727         frontChildrenMainSize += childFrameSize.MainSize(axis);
728     }
729     return indicator == 0 ? 0.0f : frontChildrenMainSize;
730 }
731 
LayoutChildren(LayoutWrapper * layoutWrapper,const SizeF & frameSize,Axis axis,OffsetF & childOffset)732 void TabBarLayoutAlgorithm::LayoutChildren(
733     LayoutWrapper* layoutWrapper, const SizeF& frameSize, Axis axis, OffsetF& childOffset)
734 {
735     auto pipelineContext = PipelineContext::GetCurrentContext();
736     CHECK_NULL_VOID(pipelineContext);
737     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
738     CHECK_NULL_VOID(tabTheme);
739     auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
740     if (childCount < 0) {
741         return;
742     }
743     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
744     CHECK_NULL_VOID(layoutProperty);
745 
746     if (layoutProperty->GetPaddingProperty()) {
747         childOffset += OffsetF(
748             layoutProperty->GetPaddingProperty()->left.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx(), 0.0f);
749     }
750 
751     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
752         childrenMainSize_ > frameSize.MainSize(axis) && axis == Axis::HORIZONTAL) {
753         childOffset += OffsetF(scrollMargin_, 0);
754     }
755 
756     std::vector<OffsetF> childOffsetDelta;
757     for (int32_t index = 0; index < childCount; ++index) {
758         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
759         if (!childWrapper) {
760             childOffsetDelta.emplace_back(OffsetF());
761             continue;
762         }
763         auto childGeometryNode = childWrapper->GetGeometryNode();
764         auto childFrameSize = childGeometryNode->GetMarginFrameSize();
765         OffsetF centerOffset = (axis == Axis::HORIZONTAL)
766                                    ? OffsetF(0, (frameSize.Height() - childFrameSize.Height()) / 2.0)
767                                    : OffsetF((frameSize.Width() - childFrameSize.Width()) / 2.0, 0);
768         childOffsetDelta.emplace_back(childOffset + centerOffset - childGeometryNode->GetMarginFrameOffset());
769         childGeometryNode->SetMarginFrameOffset(childOffset + centerOffset);
770         childWrapper->Layout();
771         tabItemOffset_.emplace_back(childOffset);
772 
773         childOffset +=
774             axis == Axis::HORIZONTAL ? OffsetF(childFrameSize.Width(), 0.0f) : OffsetF(0.0f, childFrameSize.Height());
775     }
776     tabItemOffset_.emplace_back(childOffset);
777     LayoutMask(layoutWrapper, childOffsetDelta);
778 }
779 
LayoutMask(LayoutWrapper * layoutWrapper,const std::vector<OffsetF> & childOffsetDelta)780 void TabBarLayoutAlgorithm::LayoutMask(LayoutWrapper* layoutWrapper, const std::vector<OffsetF>& childOffsetDelta)
781 {
782     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
783     CHECK_NULL_VOID(layoutProperty);
784     auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
785     if (childCount < 0) {
786         return;
787     }
788     auto selectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount);
789     CHECK_NULL_VOID(selectedMaskWrapper);
790     auto unselectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount + 1);
791     CHECK_NULL_VOID(unselectedMaskWrapper);
792     for (int32_t i = 0; i < MASK_COUNT; i++) {
793         auto currentWrapper = (i == 0 ? selectedMaskWrapper : unselectedMaskWrapper);
794         auto currentMask = (i == 0 ? layoutProperty->GetSelectedMask().value_or(-1)
795                                    : layoutProperty->GetUnselectedMask().value_or(-1));
796         if (currentMask < 0) {
797             currentWrapper->GetGeometryNode()->SetFrameSize(SizeF());
798         } else {
799             auto offset = currentWrapper->GetGeometryNode()->GetMarginFrameOffset();
800             currentWrapper->GetGeometryNode()->SetMarginFrameOffset(offset + childOffsetDelta[currentMask]);
801             auto imageWrapper = currentWrapper->GetOrCreateChildByIndex(0);
802             CHECK_NULL_VOID(imageWrapper);
803             auto imageNode = imageWrapper->GetHostNode();
804             CHECK_NULL_VOID(imageNode);
805             auto imageRenderContext = imageNode->GetRenderContext();
806             CHECK_NULL_VOID(imageRenderContext);
807             imageRenderContext->SetVisible(true);
808         }
809         currentWrapper->Layout();
810     }
811 }
812 
CalculateBackChildrenMainSize(LayoutWrapper * layoutWrapper,int32_t indicator,Axis axis)813 float TabBarLayoutAlgorithm::CalculateBackChildrenMainSize(LayoutWrapper* layoutWrapper, int32_t indicator, Axis axis)
814 {
815     float backChildrenMainSize = scrollMargin_;
816     auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
817     for (int32_t index = indicator + 1; index < childCount; ++index) {
818         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
819         if (!childWrapper) {
820             return 0.0f;
821         }
822         auto childGeometryNode = childWrapper->GetGeometryNode();
823         auto childFrameSize = childGeometryNode->GetMarginFrameSize();
824         backChildrenMainSize += childFrameSize.MainSize(axis);
825     }
826     return indicator == childCount - 1 ? 0.0f : backChildrenMainSize;
827 }
828 
GetGridSizeType(const SizeF & frameSize) const829 GridSizeType TabBarLayoutAlgorithm::GetGridSizeType(const SizeF& frameSize) const
830 {
831     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TAB_BAR);
832     CHECK_NULL_RETURN(gridColumnInfo, GridSizeType::UNDEFINED);
833     auto parent = gridColumnInfo->GetParent();
834     CHECK_NULL_RETURN(parent, GridSizeType::UNDEFINED);
835     parent->BuildColumnWidth(frameSize.Width());
836     return parent->GetSizeType();
837 }
838 
GetGridWidth(const BarGridColumnOptions & option,const SizeF & frameSize,int32_t columns) const839 float TabBarLayoutAlgorithm::GetGridWidth(
840     const BarGridColumnOptions& option, const SizeF& frameSize, int32_t columns) const
841 {
842     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TAB_BAR);
843     CHECK_NULL_RETURN(gridColumnInfo, 0.0f);
844     auto parent = gridColumnInfo->GetParent();
845     CHECK_NULL_RETURN(parent, 0.0f);
846     parent->SetGutterWidth(option.gutter);
847     parent->SetMarginLeft(option.margin);
848     parent->SetMarginRight(option.margin);
849     parent->BuildColumnWidth(frameSize.Width());
850     if (columns < 0) {
851         return gridColumnInfo->GetMaxWidth();
852     }
853     return gridColumnInfo->GetWidth(columns);
854 }
855 
GetContentWidth(const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & frameSize) const856 float TabBarLayoutAlgorithm::GetContentWidth(
857     const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& frameSize) const
858 {
859     const auto& padding = layoutProperty->GetPaddingProperty();
860     CHECK_NULL_RETURN(padding, frameSize.Width());
861     auto left = padding->left.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx();
862     auto right = padding->right.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx();
863     return Positive(frameSize.Width() - left - right) ? frameSize.Width() - left - right : 0.0f;
864 }
865 
UpdateHorizontalPadding(LayoutWrapper * layoutWrapper,float horizontalPadding) const866 void TabBarLayoutAlgorithm::UpdateHorizontalPadding(LayoutWrapper* layoutWrapper, float horizontalPadding) const
867 {
868     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
869     CHECK_NULL_VOID(layoutProperty);
870 
871     layoutProperty->UpdatePadding(
872         { CalcLength(Dimension(horizontalPadding)), CalcLength(Dimension(horizontalPadding)), {}, {} });
873     auto host = layoutWrapper->GetHostNode();
874     CHECK_NULL_VOID(host);
875     auto hostLayoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
876     CHECK_NULL_VOID(hostLayoutProperty);
877     hostLayoutProperty->UpdatePadding(
878         { CalcLength(Dimension(horizontalPadding)), CalcLength(Dimension(horizontalPadding)), {}, {} });
879     auto geometryNode = layoutWrapper->GetGeometryNode();
880     CHECK_NULL_VOID(geometryNode);
881     geometryNode->UpdatePaddingWithBorder({ horizontalPadding, horizontalPadding, 0.0f, 0.0f });
882 }
883 
AdjustFixedItem(const RefPtr<LayoutWrapper> & childWrapper,const OptionalSizeF & frameSize,Axis axis) const884 void TabBarLayoutAlgorithm::AdjustFixedItem(
885     const RefPtr<LayoutWrapper>& childWrapper, const OptionalSizeF& frameSize, Axis axis) const
886 {
887     auto geometryNode = childWrapper->GetGeometryNode();
888     CHECK_NULL_VOID(geometryNode);
889     if (axis == Axis::HORIZONTAL &&
890         GreatNotEqual(geometryNode->GetMarginFrameSize().MainSize(axis), frameSize.Width().value_or(0.0f))) {
891         geometryNode->SetFrameSize(
892             SizeF(frameSize.Width().value_or(0.0f), geometryNode->GetMarginFrameSize().MainSize(Axis::VERTICAL)));
893     } else if (axis == Axis::VERTICAL &&
894                GreatNotEqual(geometryNode->GetMarginFrameSize().MainSize(axis), frameSize.Height().value_or(0.0f))) {
895         geometryNode->SetFrameSize(
896             SizeF(geometryNode->GetMarginFrameSize().MainSize(Axis::HORIZONTAL), frameSize.Height().value_or(0.0f)));
897     }
898 }
899 } // namespace OHOS::Ace::NG
900