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