• 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/tabs/tabs_layout_property.h"
34 #include "core/components_ng/pattern/tabs/tabs_node.h"
35 #include "core/components_ng/pattern/text/text_layout_property.h"
36 #include "core/components_ng/property/layout_constraint.h"
37 #include "core/components_ng/property/measure_property.h"
38 #include "core/components_ng/property/measure_utils.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 
41 namespace OHOS::Ace::NG {
42 namespace {
43 constexpr int8_t MASK_COUNT = 2;
44 constexpr int8_t SM_COLUMN_NUM = 4;
45 constexpr int8_t MD_COLUMN_NUM = 8;
46 constexpr int8_t LG_COLUMN_NUM = 12;
47 constexpr int8_t TWO = 2;
48 constexpr int8_t FOCUS_BOARD = 2;
49 } // namespace
50 
Measure(LayoutWrapper * layoutWrapper)51 void TabBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
52 {
53     CHECK_NULL_VOID(layoutWrapper);
54     auto host = layoutWrapper->GetHostNode();
55     CHECK_NULL_VOID(host);
56     auto pipelineContext = host->GetContext();
57     CHECK_NULL_VOID(pipelineContext);
58     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
59     CHECK_NULL_VOID(tabTheme);
60     auto geometryNode = layoutWrapper->GetGeometryNode();
61     CHECK_NULL_VOID(geometryNode);
62     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
63     CHECK_NULL_VOID(layoutProperty);
64     axis_ = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
65     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
66     CHECK_NULL_VOID(tabsNode);
67     auto tabsLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
68     CHECK_NULL_VOID(tabsLayoutProperty);
69     auto tabsDirection = tabsLayoutProperty->GetNonAutoLayoutDirection();
70     auto tabBarDirection = layoutProperty->GetLayoutDirection();
71     isRTL_ = tabBarDirection == TextDirection::RTL ||
72              (tabBarDirection == TextDirection::AUTO && tabsDirection == TextDirection::RTL);
73     auto constraint = layoutProperty->GetLayoutConstraint();
74     auto idealSize =
75         CreateIdealSize(constraint.value(), axis_, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT));
76 
77     childCount_ = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
78     if (childCount_ <= 0) {
79         return;
80     }
81 
82     if (axis_ == Axis::VERTICAL && constraint->selfIdealSize.Width().has_value() &&
83         constraint->selfIdealSize.Width().value() < constraint->parentIdealSize.Width().value_or(0.0f) &&
84         constraint->selfIdealSize.Width().value() > tabTheme->GetHorizontalBottomTabMinWidth().ConvertToPx()) {
85         // Vertical tab bar may apply LayoutMode.AUTO
86         ApplyLayoutMode(layoutWrapper, constraint->selfIdealSize.Width().value());
87     }
88     if (constraint->selfIdealSize.Width().has_value() &&
89         constraint->selfIdealSize.Width().value() > constraint->parentIdealSize.Width().value_or(0.0f)) {
90         idealSize.SetWidth(static_cast<float>(
91             axis_ == Axis::HORIZONTAL                         ? constraint->parentIdealSize.Width().value_or(0.0f)
92             : tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE ? tabTheme->GetTabBarDefaultWidth().ConvertToPx()
93                                                              : tabTheme->GetTabBarDefaultHeight().ConvertToPx()));
94     }
95     if (constraint->selfIdealSize.Height().has_value() &&
96         constraint->selfIdealSize.Height().value() > constraint->parentIdealSize.Height().value_or(0.0f)) {
97         float height = axis_ == Axis::HORIZONTAL
98                            ? (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE &&
99                                          Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)
100                                      ? tabTheme->GetBottomTabBarDefaultWidth().ConvertToPx()
101                                      : tabTheme->GetTabBarDefaultHeight().ConvertToPx())
102                            : constraint->parentIdealSize.Height().value_or(0.0f);
103 
104         idealSize.SetHeight(static_cast<float>(height));
105     }
106     if (!constraint->selfIdealSize.Width().has_value()) {
107         auto defaultWidth = idealSize.Width().value_or(0.f);
108         if (axis_ == Axis::VERTICAL) {
109             defaultWidth = static_cast<float>(tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE
110                                                   ? tabTheme->GetTabBarDefaultWidth().ConvertToPx()
111                                                   : tabTheme->GetTabBarDefaultHeight().ConvertToPx());
112         }
113         idealSize.SetWidth(std::clamp(defaultWidth, constraint->minSize.Width(), constraint->maxSize.Width()));
114     }
115     if (!constraint->selfIdealSize.Height().has_value()) {
116         if (axis_ == Axis::HORIZONTAL) {
117             defaultHeight_ = (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE &&
118                                  Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))
119                                  ? static_cast<float>(tabTheme->GetBottomTabBarDefaultWidth().ConvertToPx())
120                                  : static_cast<float>(tabTheme->GetTabBarDefaultHeight().ConvertToPx());
121         }
122         auto idealHeight = idealSize.Height().value_or(0.f);
123         idealSize.SetHeight(std::clamp(idealHeight, constraint->minSize.Height(), constraint->maxSize.Height()));
124     }
125 
126     auto tabBarFocusNode = host->GetFocusHub();
127     if ((axis_ == Axis::VERTICAL && NearZero(idealSize.ConvertToSizeT().Width())) ||
128         (axis_ == Axis::HORIZONTAL && NearZero(idealSize.ConvertToSizeT().Height()))) {
129         layoutWrapper->SetActive(false);
130         geometryNode->SetFrameSize(SizeF());
131         if (tabBarFocusNode) {
132             tabBarFocusNode->SetFocusable(false, false);
133         }
134         return;
135     } else {
136         layoutWrapper->SetActive(true);
137         if (tabBarFocusNode) {
138             tabBarFocusNode->SetFocusable(true, false);
139         }
140     }
141 
142     auto frameSize = idealSize.ConvertToSizeT();
143     auto padding = layoutProperty->CreatePaddingAndBorder();
144     verticalPadding_ = padding.Height();
145     auto contentSize = frameSize;
146     MinusPaddingToNonNegativeSize(padding, contentSize);
147     contentMainSize_ = GetContentMainSize(layoutWrapper, contentSize);
148     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
149         MeasureFixedMode(layoutWrapper, contentSize);
150     } else {
151         MeasureScrollableMode(layoutWrapper, contentSize);
152     }
153     if (visibleItemPosition_.empty()) {
154         layoutWrapper->SetActiveChildRange(-1, -1);
155     } else {
156         layoutWrapper->SetActiveChildRange(visibleItemPosition_.begin()->first, visibleItemPosition_.rbegin()->first);
157     }
158     if (defaultHeight_ || maxHeight_) {
159         auto frameHeight = std::max(defaultHeight_.value_or(0.0f), maxHeight_.value_or(0.0f) + verticalPadding_);
160         frameSize.SetHeight(std::clamp(frameHeight, constraint->minSize.Height(), constraint->maxSize.Height()));
161     }
162     CheckBorderAndPadding(frameSize, padding);
163     geometryNode->SetFrameSize(frameSize);
164     MeasureMask(layoutWrapper);
165 }
166 
GetContentMainSize(LayoutWrapper * layoutWrapper,const SizeF & contentSize)167 float TabBarLayoutAlgorithm::GetContentMainSize(LayoutWrapper* layoutWrapper, const SizeF& contentSize)
168 {
169     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
170     CHECK_NULL_RETURN(layoutProperty, 0.0f);
171     if (axis_ == Axis::HORIZONTAL) {
172         // Apply grid column options to the tab bar
173         barGridMargin_ = ApplyBarGridAlign(layoutProperty, contentSize);
174         return Positive(contentSize.Width() - barGridMargin_ * TWO) ? contentSize.Width() - barGridMargin_ * TWO : 0.0f;
175     } else {
176         barGridMargin_ = 0.0f;
177         return contentSize.Height();
178     }
179 }
180 
MeasureFixedMode(LayoutWrapper * layoutWrapper,SizeF frameSize)181 void TabBarLayoutAlgorithm::MeasureFixedMode(LayoutWrapper* layoutWrapper, SizeF frameSize)
182 {
183     auto childLayoutConstraint = GetChildConstraint(layoutWrapper, frameSize);
184     visibleItemLength_.clear();
185     visibleChildrenMainSize_ = 0.0f;
186     if (axis_ == Axis::HORIZONTAL) {
187         auto allocatedWidth = contentMainSize_ / childCount_;
188         ApplyLayoutMode(layoutWrapper, allocatedWidth);
189 
190         auto host = layoutWrapper->GetHostNode();
191         CHECK_NULL_VOID(host);
192         auto tabBarPattern = host->GetPattern<TabBarPattern>();
193         CHECK_NULL_VOID(tabBarPattern);
194         auto isApplySymmetricExtensible = false;
195         for (int32_t index = 0; index < childCount_ && childCount_ > TWO; index++) {
196             if (tabBarPattern->GetTabBarStyle(index) == TabBarStyle::BOTTOMTABBATSTYLE &&
197                 tabBarPattern->GetBottomTabBarStyle(index).symmetricExtensible) {
198                 isApplySymmetricExtensible = true;
199                 break;
200             }
201         }
202         if (!isApplySymmetricExtensible) {
203             childLayoutConstraint.selfIdealSize.SetWidth(allocatedWidth);
204         }
205         for (int32_t index = 0; index < childCount_; index++) {
206             MeasureItem(layoutWrapper, childLayoutConstraint, index);
207             visibleItemPosition_[index] = { allocatedWidth * index, allocatedWidth * (index + 1) };
208         }
209         if (isApplySymmetricExtensible) {
210             ApplySymmetricExtensible(layoutWrapper, allocatedWidth);
211             if (isBarAdaptiveHeight_) {
212                 MeasureMaxHeight(layoutWrapper, childLayoutConstraint);
213             }
214         }
215         if (isApplySymmetricExtensible || isBarAdaptiveHeight_) {
216             MeasureItemSecond(layoutWrapper, childLayoutConstraint, frameSize);
217         }
218     } else {
219         for (int32_t index = 0; index < childCount_; index++) {
220             MeasureItem(layoutWrapper, childLayoutConstraint, index);
221         }
222     }
223 
224     visibleItemPosition_.clear();
225     auto currentOffset =
226         (axis_ == Axis::VERTICAL && tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE) ? contentMainSize_ / 4 : 0.0f;
227     for (int32_t index = 0; index < childCount_; index++) {
228         visibleItemPosition_[index] = { currentOffset, currentOffset + visibleItemLength_[index] };
229         currentOffset += visibleItemLength_[index];
230     }
231 }
232 
UpdateMaxLines(LayoutWrapper * layoutWrapper,int32_t index)233 void TabBarLayoutAlgorithm::UpdateMaxLines(LayoutWrapper* layoutWrapper, int32_t index)
234 {
235     auto host = layoutWrapper->GetHostNode();
236     CHECK_NULL_VOID(host);
237     CHECK_NULL_VOID((tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) && (NeedAdaptForAging(host)
238         && (axis_ == Axis::VERTICAL)));
239     CHECK_NULL_VOID(layoutWrapper);
240     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
241     CHECK_NULL_VOID(childWrapper);
242     auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
243     CHECK_NULL_VOID(textWrapper);
244     auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
245     CHECK_NULL_VOID(textLayoutProperty);
246     textLayoutProperty->UpdateMaxLines(TWO);
247 }
248 
MeasureScrollableMode(LayoutWrapper * layoutWrapper,SizeF frameSize)249 void TabBarLayoutAlgorithm::MeasureScrollableMode(LayoutWrapper* layoutWrapper, SizeF frameSize)
250 {
251     auto childLayoutConstraint = GetChildConstraint(layoutWrapper, frameSize);
252     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
253     CHECK_NULL_VOID(layoutProperty);
254     ScrollableBarModeOptions layoutStyle;
255     if (axis_ == Axis::HORIZONTAL) {
256         auto host = layoutWrapper->GetHostNode();
257         CHECK_NULL_VOID(host);
258         auto pipelineContext = host->GetContext();
259         CHECK_NULL_VOID(pipelineContext);
260         auto tabTheme = pipelineContext->GetTheme<TabTheme>();
261         CHECK_NULL_VOID(tabTheme);
262         ScrollableBarModeOptions defaultOptions;
263         defaultOptions.margin = tabTheme->GetTabBarDefaultMargin();
264         layoutStyle = layoutProperty->GetScrollableBarModeOptions().value_or(defaultOptions);
265         scrollMargin_ = layoutStyle.margin.ConvertToPx();
266         MeasureVisibleItems(layoutWrapper, childLayoutConstraint);
267 
268         useItemWidth_ = true;
269         if (GreatNotEqual(visibleChildrenMainSize_, contentMainSize_) ||
270             childCount_ > static_cast<int32_t>(visibleItemPosition_.size())) {
271             useItemWidth_ = false;
272         } else {
273             visibleChildrenMainSize_ -= scrollMargin_ * TWO;
274             if (layoutStyle.nonScrollableLayoutStyle.value_or(LayoutStyle::ALWAYS_CENTER) ==
275                 LayoutStyle::ALWAYS_CENTER) {
276                 useItemWidth_ = false;
277             } else if (layoutStyle.nonScrollableLayoutStyle.value() == LayoutStyle::ALWAYS_AVERAGE_SPLIT) {
278                 HandleAlwaysAverageSplitLayoutStyle(layoutWrapper);
279             } else if (layoutStyle.nonScrollableLayoutStyle.value() == LayoutStyle::SPACE_BETWEEN_OR_CENTER) {
280                 HandleSpaceBetweenOrCenterLayoutStyle(layoutWrapper);
281             }
282             scrollMargin_ = 0.0f;
283         }
284 
285         if (isBarAdaptiveHeight_ || useItemWidth_) {
286             MeasureItemSecond(layoutWrapper, childLayoutConstraint, frameSize);
287         }
288     } else {
289         MeasureVisibleItems(layoutWrapper, childLayoutConstraint);
290     }
291 
292     if (LessOrEqual(visibleChildrenMainSize_, contentMainSize_) &&
293         childCount_ == static_cast<int32_t>(visibleItemPosition_.size())) {
294         visibleItemPosition_.clear();
295         float currentOffset = GetCurrentOffset(layoutProperty, layoutStyle);
296         for (int32_t index = 0; index < childCount_; index++) {
297             visibleItemPosition_[index] = { currentOffset, currentOffset + visibleItemLength_[index] };
298             currentOffset += visibleItemLength_[index];
299         }
300     }
301 }
302 
GetCurrentOffset(RefPtr<TabBarLayoutProperty> & layoutProperty,ScrollableBarModeOptions & layoutStyle)303 float TabBarLayoutAlgorithm::GetCurrentOffset(
304     RefPtr<TabBarLayoutProperty>& layoutProperty, ScrollableBarModeOptions& layoutStyle)
305 {
306     float currentOffset = (contentMainSize_ - visibleChildrenMainSize_) / TWO;
307     if (layoutStyle.nonScrollableLayoutStyle.has_value()) {
308         return currentOffset;
309     }
310     Alignment alignment = Alignment::CENTER;
311     if (layoutProperty->GetPositionProperty()) {
312         alignment = layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER);
313     }
314     if (axis_ == Axis::HORIZONTAL) {
315         float margin = layoutStyle.margin.ConvertToPx();
316         currentOffset = (1.0 + alignment.GetHorizontal()) * (contentMainSize_ - visibleChildrenMainSize_) / TWO;
317         currentOffset -= alignment.GetHorizontal() * margin;
318     } else {
319         currentOffset = (1.0 + alignment.GetVertical()) * (contentMainSize_ - visibleChildrenMainSize_) / TWO;
320     }
321     return currentOffset;
322 }
323 
CheckBorderAndPadding(SizeF & frameSize,const PaddingPropertyF & padding)324 void TabBarLayoutAlgorithm::CheckBorderAndPadding(SizeF& frameSize, const PaddingPropertyF& padding)
325 {
326     if (GreatNotEqual(padding.Width(), frameSize.Width())) {
327         frameSize.SetWidth(padding.Width());
328     }
329     if (GreatNotEqual(padding.Height(), frameSize.Height())) {
330         frameSize.SetHeight(padding.Height());
331     }
332 }
333 
NeedAdaptForAging(RefPtr<FrameNode> host)334 bool TabBarLayoutAlgorithm::NeedAdaptForAging(RefPtr<FrameNode> host)
335 {
336     CHECK_NULL_RETURN(host, false);
337     auto pipeline = host->GetContext();
338     CHECK_NULL_RETURN(pipeline, false);
339     auto tabTheme = pipeline->GetTheme<TabTheme>();
340     CHECK_NULL_RETURN(tabTheme, false);
341 
342     if (GreatOrEqual(pipeline->GetFontScale(), tabTheme->GetSubTabBarBigFontSizeScale())) {
343         return true;
344     }
345     return false;
346 }
347 
GetBarAdaptiveHeight(LayoutWrapper * layoutWrapper)348 bool TabBarLayoutAlgorithm::GetBarAdaptiveHeight(LayoutWrapper* layoutWrapper)
349 {
350     CHECK_NULL_RETURN(defaultHeight_, false);
351     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
352     CHECK_NULL_RETURN(layoutProperty, false);
353     auto isBarAdaptiveHeight = layoutProperty->GetBarAdaptiveHeight().value_or(false);
354 
355     auto host = layoutWrapper->GetHostNode();
356     CHECK_NULL_RETURN(host, isBarAdaptiveHeight);
357     auto pipeline = host->GetContext();
358     CHECK_NULL_RETURN(pipeline, isBarAdaptiveHeight);
359     auto tabTheme = pipeline->GetTheme<TabTheme>();
360     CHECK_NULL_RETURN(tabTheme, isBarAdaptiveHeight);
361     if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE &&
362         GreatOrEqual(pipeline->GetFontScale(), tabTheme->GetsubTabBarThirdLargeFontSizeScale())) {
363         isBarAdaptiveHeight = true;
364     }
365     return isBarAdaptiveHeight;
366 }
367 
GetChildConstraint(LayoutWrapper * layoutWrapper,SizeF & frameSize)368 LayoutConstraintF TabBarLayoutAlgorithm::GetChildConstraint(LayoutWrapper* layoutWrapper, SizeF& frameSize)
369 {
370     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
371     CHECK_NULL_RETURN(layoutProperty, {});
372     auto host = layoutWrapper->GetHostNode();
373     CHECK_NULL_RETURN(host, {});
374     auto pipelineContext = host->GetContext();
375     CHECK_NULL_RETURN(pipelineContext, {});
376     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
377     CHECK_NULL_RETURN(tabTheme, {});
378     auto focusBoardPadding = tabTheme->GetBoardFocusPadding().ConvertToPx();
379     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
380     if (axis_ == Axis::HORIZONTAL) {
381         isBarAdaptiveHeight_ = GetBarAdaptiveHeight(layoutWrapper);
382         childLayoutConstraint.maxSize.SetWidth(Infinity<float>());
383         if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
384             childLayoutConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
385         }
386         if (!defaultHeight_.has_value()) {
387             childLayoutConstraint.parentIdealSize = OptionalSizeF(frameSize);
388             childLayoutConstraint.selfIdealSize.SetHeight(frameSize.Height());
389         } else if (!isBarAdaptiveHeight_) {
390             frameSize.SetHeight(defaultHeight_.value() - verticalPadding_);
391             frameSize.MinusHeight(focusBoardPadding * FOCUS_BOARD);
392             childLayoutConstraint.parentIdealSize = OptionalSizeF(frameSize);
393             childLayoutConstraint.selfIdealSize.SetHeight(frameSize.Height());
394         }
395     } else {
396         childLayoutConstraint.parentIdealSize = OptionalSizeF(frameSize);
397         if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
398             frameSize.SetHeight(tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE
399                                     ? frameSize.Height() / TWO / childCount_
400                                     : frameSize.Height() / childCount_);
401             childLayoutConstraint.selfIdealSize = OptionalSizeF(frameSize);
402         } else {
403             frameSize.MinusWidth(focusBoardPadding * FOCUS_BOARD);
404             childLayoutConstraint.maxSize.SetHeight(Infinity<float>());
405             childLayoutConstraint.selfIdealSize.SetWidth(frameSize.Width());
406         }
407     }
408     return childLayoutConstraint;
409 }
410 
MeasureVisibleItems(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)411 void TabBarLayoutAlgorithm::MeasureVisibleItems(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
412 {
413     visibleItemLength_.clear();
414     visibleChildrenMainSize_ = scrollMargin_ * TWO;
415     startMainPos_ = 0.0f;
416     endMainPos_ = contentMainSize_;
417 
418     if (targetIndex_) {
419         targetIndex_ = targetIndex_.value() % childCount_;
420         MeasureTargetIndex(layoutWrapper, childLayoutConstraint);
421     } else if (jumpIndex_) {
422         if (jumpIndex_.value() >= childCount_) {
423             jumpIndex_ = 0;
424         }
425         MeasureJumpIndex(layoutWrapper, childLayoutConstraint);
426         if (GreatNotEqual(visibleChildrenMainSize_, scrollMargin_ * TWO)) {
427             jumpIndex_.reset();
428         }
429     } else if (focusIndex_) {
430         MeasureFocusIndex(layoutWrapper, childLayoutConstraint);
431     } else {
432         MeasureWithOffset(layoutWrapper, childLayoutConstraint);
433     }
434 }
435 
MeasureTargetIndex(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)436 void TabBarLayoutAlgorithm::MeasureTargetIndex(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
437 {
438     MeasureWithOffset(layoutWrapper, childLayoutConstraint);
439     if (GreatOrEqual(visibleItemLength_[targetIndex_.value()], endMainPos_ - startMainPos_)) {
440         return;
441     }
442 
443     if (visibleItemPosition_.empty()) {
444         return;
445     }
446     auto iter = visibleItemPosition_.find(targetIndex_.value());
447     if (iter == visibleItemPosition_.end()) {
448         return;
449     }
450     auto space = ((endMainPos_ - startMainPos_) - visibleItemLength_[targetIndex_.value()]) / TWO;
451     startMainPos_ = std::min(startMainPos_, iter->second.startPos - space);
452     endMainPos_ = std::max(endMainPos_, iter->second.endPos + space);
453     auto startIndex = visibleItemPosition_.begin()->first - 1;
454     auto startPos = visibleItemPosition_.begin()->second.startPos;
455     auto endIndex = visibleItemPosition_.rbegin()->first + 1;
456     auto endPos = visibleItemPosition_.rbegin()->second.endPos;
457     LayoutForward(layoutWrapper, childLayoutConstraint, endIndex, endPos);
458     LayoutBackward(layoutWrapper, childLayoutConstraint, startIndex, startPos);
459 
460     startMainPos_ = 0.0f;
461     endMainPos_ = contentMainSize_;
462     AdjustPosition(layoutWrapper, childLayoutConstraint, startIndex, endIndex, startPos, endPos);
463 }
464 
MeasureJumpIndex(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)465 void TabBarLayoutAlgorithm::MeasureJumpIndex(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
466 {
467     visibleItemPosition_.clear();
468     MeasureItem(layoutWrapper, childLayoutConstraint, jumpIndex_.value());
469     if (GreatOrEqual(visibleItemLength_[jumpIndex_.value()], endMainPos_ - startMainPos_)) {
470         visibleItemPosition_[jumpIndex_.value()] = { 0.0f, visibleItemLength_[jumpIndex_.value()] };
471         return;
472     }
473 
474     auto startIndex = jumpIndex_.value() - 1;
475     auto startPos = ((endMainPos_ - startMainPos_) - visibleItemLength_[jumpIndex_.value()]) / TWO;
476     auto endIndex = jumpIndex_.value() + 1;
477     auto endPos = ((endMainPos_ - startMainPos_) + visibleItemLength_[jumpIndex_.value()]) / TWO;
478     visibleItemPosition_[jumpIndex_.value()] = { startPos, endPos };
479     LayoutForward(layoutWrapper, childLayoutConstraint, endIndex, endPos);
480     LayoutBackward(layoutWrapper, childLayoutConstraint, startIndex, startPos);
481 
482     AdjustPosition(layoutWrapper, childLayoutConstraint, startIndex, endIndex, startPos, endPos);
483 }
484 
MeasureFocusIndex(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)485 void TabBarLayoutAlgorithm::MeasureFocusIndex(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
486 {
487     if (visibleItemPosition_.empty()) {
488         return;
489     }
490     auto startIndex = focusIndex_.value();
491     auto startPos = endMainPos_;
492     auto endIndex = focusIndex_.value();
493     auto endPos = 0.0f;
494 
495     auto iter = visibleItemPosition_.find(focusIndex_.value());
496     if ((iter != visibleItemPosition_.end() && LessNotEqual(iter->second.startPos, 0.0f)) ||
497         focusIndex_.value() < visibleItemPosition_.begin()->first) {
498         if (focusIndex_.value() == 0) {
499             endPos += scrollMargin_;
500         }
501         startIndex = endIndex - 1;
502         startPos = endPos;
503     } else if ((iter != visibleItemPosition_.end() && GreatNotEqual(iter->second.endPos, contentMainSize_)) ||
504                focusIndex_.value() > visibleItemPosition_.rbegin()->first) {
505         if (focusIndex_.value() == childCount_ - 1) {
506             startPos -= scrollMargin_;
507         }
508         endIndex = startIndex + 1;
509         endPos = startPos;
510     } else {
511         return;
512     }
513     visibleItemPosition_.clear();
514     LayoutForward(layoutWrapper, childLayoutConstraint, endIndex, endPos);
515     LayoutBackward(layoutWrapper, childLayoutConstraint, startIndex, startPos);
516     if (!canOverScroll_) {
517         AdjustPosition(layoutWrapper, childLayoutConstraint, startIndex, endIndex, startPos, endPos);
518     }
519 }
520 
MeasureWithOffset(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)521 void TabBarLayoutAlgorithm::MeasureWithOffset(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
522 {
523     auto startIndex = -1;
524     auto startPos = scrollMargin_;
525     auto endIndex = 0;
526     auto endPos = scrollMargin_;
527     if (isRTL_ && axis_ == Axis::HORIZONTAL) {
528         currentDelta_ = -currentDelta_;
529     }
530     if (NonNegative(currentDelta_)) {
531         if (!visibleItemPosition_.empty()) {
532             endIndex = visibleItemPosition_.begin()->first;
533             endPos = visibleItemPosition_.begin()->second.startPos;
534         }
535         startIndex = endIndex - 1;
536         startPos = endPos;
537     } else {
538         if (!visibleItemPosition_.empty()) {
539             startIndex = visibleItemPosition_.rbegin()->first;
540             startPos = visibleItemPosition_.rbegin()->second.endPos;
541         }
542         endIndex = startIndex + 1;
543         endPos = startPos;
544     }
545 
546     startPos += currentDelta_;
547     endPos += currentDelta_;
548     visibleItemPosition_.clear();
549     LayoutForward(layoutWrapper, childLayoutConstraint, endIndex, endPos);
550     LayoutBackward(layoutWrapper, childLayoutConstraint, startIndex, startPos);
551 
552     if (!canOverScroll_) {
553         AdjustPosition(layoutWrapper, childLayoutConstraint, startIndex, endIndex, startPos, endPos);
554     }
555 }
556 
AdjustPosition(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint,int32_t startIndex,int32_t endIndex,float startPos,float endPos)557 void TabBarLayoutAlgorithm::AdjustPosition(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint,
558     int32_t startIndex, int32_t endIndex, float startPos, float endPos)
559 {
560     if (GreatNotEqual(startPos, startMainPos_ + scrollMargin_)) {
561         auto offset = startPos - startMainPos_ - scrollMargin_;
562         for (auto& pos : visibleItemPosition_) {
563             pos.second.startPos -= offset;
564             pos.second.endPos -= offset;
565         }
566         endPos -= offset;
567         LayoutForward(layoutWrapper, childLayoutConstraint, endIndex, endPos);
568     } else if (LessNotEqual(endPos, endMainPos_ - scrollMargin_)) {
569         auto offset = endMainPos_ - scrollMargin_ - endPos;
570         for (auto& pos : visibleItemPosition_) {
571             pos.second.startPos += offset;
572             pos.second.endPos += offset;
573         }
574         startPos += offset;
575         LayoutBackward(layoutWrapper, childLayoutConstraint, startIndex, startPos);
576     }
577 }
578 
LayoutForward(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint,int32_t & endIndex,float & endPos)579 void TabBarLayoutAlgorithm::LayoutForward(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint,
580     int32_t& endIndex, float& endPos)
581 {
582     // 1.When first item is invisible and located to the right or below the tab bar, measure at least one item.
583     // 2.When set the height of tab bar to auto, measure all items to find max height of items.
584     // 3.If target index exists, measure items from the end index to target index.
585     while (endIndex < childCount_ && (endIndex == 0 || LessNotEqual(endPos, endMainPos_) || isBarAdaptiveHeight_ ||
586         (targetIndex_ && endIndex <= targetIndex_.value()))) {
587         if (endIndex < 0) {
588             endIndex = 0;
589             continue;
590         }
591         MeasureItem(layoutWrapper, childLayoutConstraint, endIndex);
592         visibleItemPosition_[endIndex] = { endPos, endPos + visibleItemLength_[endIndex] };
593         endPos += visibleItemLength_[endIndex];
594         if (endIndex < childCount_ - 1 && LessOrEqual(endPos, startMainPos_) && !isBarAdaptiveHeight_ &&
595             !targetIndex_.has_value()) {
596             visibleChildrenMainSize_ -= visibleItemLength_[endIndex];
597             visibleItemLength_.erase(endIndex);
598             visibleItemPosition_.erase(endIndex);
599         }
600         endIndex++;
601     }
602 }
603 
LayoutBackward(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint,int32_t & startIndex,float & startPos)604 void TabBarLayoutAlgorithm::LayoutBackward(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint,
605     int32_t& startIndex, float& startPos)
606 {
607     // 1.When last item is invisible and located to the left or above the tab bar, measure at least one item.
608     // 2.When set the height of tab bar to auto, measure all items to find max height of items.
609     // 3.If target index exists, measure items from the start index to target index.
610     while (startIndex >= 0 && (startIndex == childCount_ - 1 || GreatNotEqual(startPos, startMainPos_) ||
611         isBarAdaptiveHeight_ || (targetIndex_ && startIndex >= targetIndex_.value()))) {
612         if (startIndex >= childCount_) {
613             startIndex = childCount_ - 1;
614             continue;
615         }
616         MeasureItem(layoutWrapper, childLayoutConstraint, startIndex);
617         visibleItemPosition_[startIndex] = { startPos - visibleItemLength_[startIndex], startPos };
618         startPos -= visibleItemLength_[startIndex];
619         if (startIndex > 0 && GreatOrEqual(startPos, endMainPos_) && !isBarAdaptiveHeight_ &&
620             !targetIndex_.has_value()) {
621             visibleChildrenMainSize_ -= visibleItemLength_[startIndex];
622             visibleItemLength_.erase(startIndex);
623             visibleItemPosition_.erase(startIndex);
624         }
625         startIndex--;
626     }
627 }
628 
MeasureItem(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint,int32_t index)629 void TabBarLayoutAlgorithm::MeasureItem(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint,
630     int32_t index)
631 {
632     auto host = layoutWrapper->GetHostNode();
633     CHECK_NULL_VOID(host);
634     auto tabBarPattern = host->GetPattern<TabBarPattern>();
635     CHECK_NULL_VOID(tabBarPattern);
636     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
637     CHECK_NULL_VOID (childWrapper);
638     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
639     CHECK_NULL_VOID(layoutProperty);
640     if (tabBarPattern->GetTabBarStyle(index) == TabBarStyle::BOTTOMTABBATSTYLE && axis_ == Axis::HORIZONTAL) {
641         auto iconWrapper = childWrapper->GetOrCreateChildByIndex(0);
642         CHECK_NULL_VOID(iconWrapper);
643         if (iconWrapper->GetHostNode()->GetTag() == V2::SYMBOL_ETS_TAG) {
644             auto symbolLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(iconWrapper->GetLayoutProperty());
645             CHECK_NULL_VOID(symbolLayoutProperty);
646             symbolLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {}, {}, {} });
647         } else {
648             auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(iconWrapper->GetLayoutProperty());
649             CHECK_NULL_VOID(imageLayoutProperty);
650             imageLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {}, {}, {} });
651         }
652         auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
653         CHECK_NULL_VOID(textWrapper);
654         auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
655         CHECK_NULL_VOID(textLayoutProperty);
656         textLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {}, {}, {} });
657     }
658     if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
659         axis_ == Axis::HORIZONTAL) {
660         auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
661         if (textWrapper) {
662             auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
663             if (textLayoutProperty &&
664                 textLayoutProperty->GetTextOverflow().value_or(TextOverflow::NONE) == TextOverflow::MARQUEE) {
665                 textLayoutProperty->UpdateTextOverflow(TextOverflow::NONE);
666             }
667         }
668     }
669     UpdateMaxLines(layoutWrapper, index);
670     SetTabBarMargin(childWrapper, index);
671     childWrapper->Measure(childLayoutConstraint);
672     auto geometryNode = childWrapper->GetGeometryNode();
673     CHECK_NULL_VOID(geometryNode);
674     visibleItemLength_[index] = geometryNode->GetMarginFrameSize().MainSize(axis_);
675     visibleChildrenMainSize_ += visibleItemLength_[index];
676     if (isBarAdaptiveHeight_) {
677         maxHeight_ = std::max(maxHeight_.value_or(0.0f), geometryNode->GetMarginFrameSize().MainSize(Axis::VERTICAL));
678     }
679 }
680 
SetTabBarMargin(RefPtr<LayoutWrapper> layoutWrapper,int32_t index)681 void TabBarLayoutAlgorithm::SetTabBarMargin(RefPtr<LayoutWrapper> layoutWrapper, int32_t index)
682 {
683     auto host = layoutWrapper->GetHostNode();
684     CHECK_NULL_VOID(host);
685     auto tabBarPattern = host->GetPattern<TabBarPattern>();
686     CHECK_NULL_VOID(tabBarPattern);
687     CHECK_NULL_VOID(tabBarPattern->GetTabBarStyle(index) == TabBarStyle::SUBTABBATSTYLE);
688     auto pipelineContext = host->GetContext();
689     CHECK_NULL_VOID(pipelineContext);
690     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
691     CHECK_NULL_VOID(tabTheme);
692     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
693     CHECK_NULL_VOID (childWrapper);
694 
695     auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
696     CHECK_NULL_VOID(textWrapper);
697     auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
698     CHECK_NULL_VOID(textLayoutProperty);
699     if (NeedAdaptForAging(host)) {
700         textLayoutProperty->UpdateMargin({ CalcLength(tabTheme->GetSubTabBarLeftRightMargin()),
701             CalcLength(tabTheme->GetSubTabBarLeftRightMargin()), {}, {}, {}, {} });
702     } else {
703         textLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {}, {}, {} });
704     }
705 }
706 
MeasureItemSecond(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint,SizeF & frameSize)707 void TabBarLayoutAlgorithm::MeasureItemSecond(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint,
708     SizeF& frameSize)
709 {
710     auto host = layoutWrapper->GetHostNode();
711     CHECK_NULL_VOID(host);
712     auto tabBarPattern = host->GetPattern<TabBarPattern>();
713     CHECK_NULL_VOID(tabBarPattern);
714 
715     visibleChildrenMainSize_ = scrollMargin_ * TWO;
716     if (isBarAdaptiveHeight_) {
717         frameSize.SetHeight(std::max(defaultHeight_.value_or(0.0f) - verticalPadding_, maxHeight_.value_or(0.0f)));
718         childLayoutConstraint.parentIdealSize = OptionalSizeF(frameSize);
719         childLayoutConstraint.selfIdealSize.SetHeight(frameSize.Height());
720     }
721     for (auto& iter : visibleItemPosition_) {
722         childLayoutConstraint.selfIdealSize.SetWidth(visibleItemLength_[iter.first]);
723         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(iter.first);
724         CHECK_NULL_VOID(childWrapper);
725         auto iconWrapper = childWrapper->GetOrCreateChildByIndex(0);
726         if (iconWrapper && iconWrapper->GetHostNode() && iconWrapper->GetHostNode()->GetTag() == V2::SYMBOL_ETS_TAG) {
727             childWrapper->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
728         }
729         childWrapper->Measure(childLayoutConstraint);
730         auto geometryNode = childWrapper->GetGeometryNode();
731         CHECK_NULL_VOID(geometryNode);
732         visibleChildrenMainSize_ += geometryNode->GetMarginFrameSize().MainSize(axis_);
733         tabBarPattern->UpdateSymbolEffect(iter.first);
734     }
735 }
736 
MeasureMask(LayoutWrapper * layoutWrapper) const737 void TabBarLayoutAlgorithm::MeasureMask(LayoutWrapper* layoutWrapper) const
738 {
739     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
740     CHECK_NULL_VOID(layoutProperty);
741     auto maskLayoutConstraint = layoutProperty->CreateChildConstraint();
742     auto selectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount_);
743     CHECK_NULL_VOID(selectedMaskWrapper);
744     maskLayoutConstraint.selfIdealSize = OptionalSizeF(selectedMaskWrapper->GetGeometryNode()->GetFrameSize());
745     selectedMaskWrapper->Measure(maskLayoutConstraint);
746 
747     auto unselectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount_ + 1);
748     CHECK_NULL_VOID(unselectedMaskWrapper);
749     maskLayoutConstraint.selfIdealSize = OptionalSizeF(unselectedMaskWrapper->GetGeometryNode()->GetFrameSize());
750     unselectedMaskWrapper->Measure(maskLayoutConstraint);
751 }
752 
MeasureMaxHeight(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)753 void TabBarLayoutAlgorithm::MeasureMaxHeight(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
754 {
755     for (int32_t index = 0; index < childCount_; ++index) {
756         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
757         CHECK_NULL_VOID(childWrapper);
758         if (static_cast<int32_t>(visibleItemLength_.size()) == childCount_) {
759             childLayoutConstraint.selfIdealSize.SetWidth(visibleItemLength_[index]);
760         }
761         childWrapper->Measure(childLayoutConstraint);
762         auto geometryNode = childWrapper->GetGeometryNode();
763         CHECK_NULL_VOID(geometryNode);
764         maxHeight_ = std::max(maxHeight_.value_or(0.0f), geometryNode->GetMarginFrameSize().MainSize(Axis::VERTICAL));
765     }
766 }
767 
HandleAlwaysAverageSplitLayoutStyle(LayoutWrapper * layoutWrapper)768 void TabBarLayoutAlgorithm::HandleAlwaysAverageSplitLayoutStyle(LayoutWrapper* layoutWrapper)
769 {
770     std::map<int32_t, float> originalVisibleItemLength;
771     for (int32_t index = 0; index < childCount_; index++) {
772         originalVisibleItemLength[index] = visibleItemLength_[index];
773         visibleItemLength_[index] = 0.0f;
774     }
775 
776     bool hasLongItem = false;
777     int32_t remainingChildCount = childCount_;
778     auto totalWidth = contentMainSize_ - scrollMargin_ * TWO;
779     auto allocatedItemWidth = 0.0f;
780 
781     /* Calculate the widths of long items. A long item refers to an item whose length is above the average,
782         so remainingChildCount can't be zero */
783     do {
784         allocatedItemWidth = totalWidth / remainingChildCount;
785         hasLongItem = false;
786         for (int32_t index = 0; index < childCount_; index++) {
787             if (NearZero(visibleItemLength_[index]) &&
788                 GreatNotEqual(originalVisibleItemLength[index], allocatedItemWidth)) {
789                 visibleItemLength_[index] = originalVisibleItemLength[index];
790                 hasLongItem = true;
791                 remainingChildCount--;
792                 totalWidth -= originalVisibleItemLength[index];
793             }
794         }
795     } while (hasLongItem && remainingChildCount > 0 && Positive(totalWidth));
796 
797     // Calculate the widths of other items
798     for (int32_t index = 0; index < childCount_; index++) {
799         if (NearZero(visibleItemLength_[index])) {
800             visibleItemLength_[index] = allocatedItemWidth;
801         }
802     }
803 }
804 
HandleSpaceBetweenOrCenterLayoutStyle(LayoutWrapper * layoutWrapper)805 void TabBarLayoutAlgorithm::HandleSpaceBetweenOrCenterLayoutStyle(LayoutWrapper* layoutWrapper)
806 {
807     if (GreatNotEqual(visibleChildrenMainSize_, contentMainSize_ / TWO)) {
808         useItemWidth_ = false;
809         return;
810     }
811     auto additionalWidth = (contentMainSize_ / TWO - visibleChildrenMainSize_) / childCount_;
812 
813     for (int32_t index = 0; index < childCount_; ++index) {
814         visibleItemLength_[index] += additionalWidth;
815     }
816 }
817 
ApplyLayoutMode(LayoutWrapper * layoutWrapper,float allocatedWidth)818 void TabBarLayoutAlgorithm::ApplyLayoutMode(LayoutWrapper* layoutWrapper, float allocatedWidth)
819 {
820     auto host = layoutWrapper->GetHostNode();
821     CHECK_NULL_VOID(host);
822     auto pipelineContext = host->GetContext();
823     CHECK_NULL_VOID(pipelineContext);
824     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
825     CHECK_NULL_VOID(tabTheme);
826     auto tabBarPattern = host->GetPattern<TabBarPattern>();
827     CHECK_NULL_VOID(tabBarPattern);
828 
829     bool isVertical = LessOrEqual(allocatedWidth, tabTheme->GetHorizontalBottomTabMinWidth().ConvertToPx());
830 
831     // Calculate the initial buffer and initial space request of each item.
832     for (int32_t index = 0; index < childCount_; ++index) {
833         auto bottomTabBarStyle = tabBarPattern->GetBottomTabBarStyle(index);
834         if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE ||
835             bottomTabBarStyle.layoutMode != LayoutMode::AUTO) {
836             continue;
837         }
838         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
839         CHECK_NULL_VOID(childWrapper);
840         auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
841         CHECK_NULL_VOID(linearLayoutProperty);
842         auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
843         CHECK_NULL_VOID(textWrapper);
844         auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
845         CHECK_NULL_VOID(textLayoutProperty);
846         if (isVertical) {
847             linearLayoutProperty->UpdateFlexDirection(FlexDirection::COLUMN);
848             linearLayoutProperty->UpdateSpace(tabTheme->GetBottomTabBarSpace());
849             linearLayoutProperty->UpdateMainAxisAlign(bottomTabBarStyle.verticalAlign);
850             linearLayoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
851             linearLayoutProperty->SetIsVertical(true);
852             textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
853         } else {
854             linearLayoutProperty->UpdateFlexDirection(FlexDirection::ROW);
855             linearLayoutProperty->UpdateSpace(tabTheme->GetHorizontalBottomTabBarSpace());
856             linearLayoutProperty->UpdateMainAxisAlign(FlexAlign::CENTER);
857             linearLayoutProperty->UpdateCrossAxisAlign(bottomTabBarStyle.verticalAlign);
858             linearLayoutProperty->SetIsVertical(false);
859             textLayoutProperty->UpdateTextAlign(TextAlign::LEFT);
860         }
861         auto childNode = childWrapper->GetHostNode();
862         CHECK_NULL_VOID(childNode);
863         if (!tabBarPattern->GetBottomTabLabelStyle(childNode->GetId()).fontSize.has_value() &&
864             Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
865             textLayoutProperty->UpdateFontSize(
866                 isVertical ? tabTheme->GetBottomTabTextSize() : tabTheme->GetBottomTabHorizontalTextSize());
867         }
868     }
869 }
870 
ApplySymmetricExtensible(LayoutWrapper * layoutWrapper,float allocatedWidth)871 void TabBarLayoutAlgorithm::ApplySymmetricExtensible(LayoutWrapper* layoutWrapper, float allocatedWidth)
872 {
873     auto host = layoutWrapper->GetHostNode();
874     CHECK_NULL_VOID(host);
875     auto tabBarPattern = host->GetPattern<TabBarPattern>();
876     CHECK_NULL_VOID(tabBarPattern);
877 
878     if (childCount_ <= TWO || childCount_ > static_cast<int32_t>(visibleItemLength_.size())) {
879         for (int32_t index = 0; index < static_cast<int32_t>(visibleItemLength_.size()); ++index) {
880             visibleItemLength_[index] = allocatedWidth;
881         }
882         return;
883     }
884 
885     std::vector<float> leftBuffers(childCount_);
886     std::vector<float> rightBuffers(childCount_);
887     std::vector<float> spaceRequests(childCount_);
888 
889     // Calculate the initial buffer and initial space request of each item.
890     for (int32_t index = 0; index < childCount_; ++index) {
891         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
892         CHECK_NULL_VOID(childWrapper);
893         auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
894         CHECK_NULL_VOID(linearLayoutProperty);
895         if (GreatNotEqual(visibleItemLength_[index], allocatedWidth)) {
896             if (tabBarPattern->GetTabBarStyle(index) == TabBarStyle::BOTTOMTABBATSTYLE &&
897                 tabBarPattern->GetBottomTabBarStyle(index).symmetricExtensible && index > 0 &&
898                 index < childCount_ - 1) {
899                 spaceRequests[index] = (visibleItemLength_[index] - allocatedWidth) / TWO;
900             }
901         } else {
902             if (tabBarPattern->GetTabBarStyle(index) == TabBarStyle::BOTTOMTABBATSTYLE) {
903                 leftBuffers[index] = index == 0 ? 0.0f : (allocatedWidth - visibleItemLength_[index]) / TWO;
904                 rightBuffers[index] =
905                     index == childCount_ - 1 ? 0.0f : (allocatedWidth - visibleItemLength_[index]) / TWO;
906             }
907         }
908     }
909 
910     // Decide the used buffer and used space request of each item.
911     for (int32_t index = 1; index < childCount_ - 1; ++index) {
912         auto actualRequest = std::min(std::min(rightBuffers[index - 1], leftBuffers[index + 1]), spaceRequests[index]);
913         spaceRequests[index] = actualRequest;
914         rightBuffers[index - 1] = actualRequest;
915         leftBuffers[index + 1] = actualRequest;
916     }
917 
918     spaceRequests[0] = 0.0f;
919     spaceRequests[childCount_ - 1] = 0.0f;
920 
921     leftBuffers[1] = 0.0f;
922     rightBuffers[childCount_ - TWO] = 0.0f;
923 
924     CalculateItemWidthsForSymmetricExtensible(layoutWrapper, spaceRequests, leftBuffers, rightBuffers, allocatedWidth);
925 }
926 
CalculateItemWidthsForSymmetricExtensible(LayoutWrapper * layoutWrapper,const std::vector<float> & spaceRequests,const std::vector<float> & leftBuffers,const std::vector<float> & rightBuffers,float allocatedWidth)927 void TabBarLayoutAlgorithm::CalculateItemWidthsForSymmetricExtensible(LayoutWrapper* layoutWrapper,
928     const std::vector<float>& spaceRequests, const std::vector<float>& leftBuffers,
929     const std::vector<float>& rightBuffers, float allocatedWidth)
930 {
931     auto host = layoutWrapper->GetHostNode();
932     CHECK_NULL_VOID(host);
933     auto tabBarPattern = host->GetPattern<TabBarPattern>();
934     CHECK_NULL_VOID(tabBarPattern);
935 
936     if ((static_cast<int32_t>(spaceRequests.size()) != childCount_) ||
937         (static_cast<int32_t>(leftBuffers.size()) != childCount_) ||
938         (static_cast<int32_t>(rightBuffers.size()) != childCount_) ||
939         (static_cast<int32_t>(visibleItemLength_.size()) != childCount_)) {
940         return;
941     }
942 
943     for (int32_t index = 0; index < childCount_; ++index) {
944         if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE) {
945             visibleItemLength_[index] = allocatedWidth;
946             continue;
947         }
948         if (!NearZero(spaceRequests[index])) {
949             visibleItemLength_[index] = allocatedWidth + spaceRequests[index] * TWO;
950         } else if (!NearZero(leftBuffers[index]) || !NearZero(rightBuffers[index])) {
951             visibleItemLength_[index] = allocatedWidth - leftBuffers[index] - rightBuffers[index];
952             auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
953             CHECK_NULL_VOID(childWrapper);
954             // Adjust margin to keep the position of current item.
955             auto leftMargin = rightBuffers[index];
956             auto rightMargin = leftBuffers[index];
957             if (GreatNotEqual(leftMargin, rightMargin)) {
958                 leftMargin -= rightMargin;
959                 rightMargin = 0.0f;
960             } else {
961                 rightMargin -= leftMargin;
962                 leftMargin = 0.0f;
963             }
964             UpdateChildMarginProperty(rightMargin, leftMargin, childWrapper);
965         } else {
966             visibleItemLength_[index] = allocatedWidth;
967         }
968     }
969 }
970 
UpdateChildMarginProperty(float rightMargin,float leftMargin,const RefPtr<LayoutWrapper> & childWrapper)971 void TabBarLayoutAlgorithm::UpdateChildMarginProperty(
972     float rightMargin, float leftMargin, const RefPtr<LayoutWrapper>& childWrapper)
973 {
974     auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
975     CHECK_NULL_VOID(linearLayoutProperty);
976     auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
977     CHECK_NULL_VOID(textWrapper);
978     auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
979     CHECK_NULL_VOID(textLayoutProperty);
980     textLayoutProperty->UpdateMargin(
981         { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {}, {}, {} });
982     auto iconWrapper = childWrapper->GetOrCreateChildByIndex(0);
983     CHECK_NULL_VOID(iconWrapper);
984     if (iconWrapper->GetHostNode()->GetTag() == V2::SYMBOL_ETS_TAG) {
985         auto symbolLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(iconWrapper->GetLayoutProperty());
986         CHECK_NULL_VOID(symbolLayoutProperty);
987         symbolLayoutProperty->UpdateMargin(
988             { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {}, {}, {} });
989         if (linearLayoutProperty->GetFlexDirection().value_or(FlexDirection::COLUMN) == FlexDirection::ROW) {
990             symbolLayoutProperty->UpdateMargin({ CalcLength(Dimension(leftMargin)), {}, {}, {}, {}, {} });
991             textLayoutProperty->UpdateMargin({ {}, CalcLength(Dimension(rightMargin)), {}, {}, {}, {} });
992         }
993     } else {
994         auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(iconWrapper->GetLayoutProperty());
995         CHECK_NULL_VOID(imageLayoutProperty);
996         imageLayoutProperty->UpdateMargin(
997             { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {}, {}, {} });
998         if (linearLayoutProperty->GetFlexDirection().value_or(FlexDirection::COLUMN) == FlexDirection::ROW) {
999             imageLayoutProperty->UpdateMargin({ CalcLength(Dimension(leftMargin)), {}, {}, {}, {}, {} });
1000             textLayoutProperty->UpdateMargin({ {}, CalcLength(Dimension(rightMargin)), {}, {}, {}, {} });
1001         }
1002     }
1003 }
1004 
ApplyBarGridAlign(const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & contentSize) const1005 float TabBarLayoutAlgorithm::ApplyBarGridAlign(
1006     const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& contentSize) const
1007 {
1008     if (!layoutProperty->GetBarGridAlign()) {
1009         return 0.0f;
1010     }
1011     auto option = layoutProperty->GetBarGridAlign().value();
1012     auto gridSizeType = GetGridSizeType(contentSize);
1013     int32_t columnNum = -1;
1014     if (gridSizeType == GridSizeType::SM) {
1015         columnNum = option.sm;
1016         if (columnNum > SM_COLUMN_NUM) {
1017             return 0.0f;
1018         }
1019     } else if (gridSizeType == GridSizeType::MD) {
1020         columnNum = option.md;
1021         if (columnNum > MD_COLUMN_NUM) {
1022             return 0.0f;
1023         }
1024     } else if (gridSizeType == GridSizeType::LG) {
1025         columnNum = option.lg;
1026         if (columnNum > LG_COLUMN_NUM) {
1027             return 0.0f;
1028         }
1029     } else {
1030         return 0.0f;
1031     }
1032     if (columnNum < 0 || columnNum % 2) {
1033         return 0.0f;
1034     }
1035     auto gridWidth = GetGridWidth(option, contentSize, columnNum);
1036     return (contentSize.Width() - gridWidth) / TWO;
1037 }
1038 
Layout(LayoutWrapper * layoutWrapper)1039 void TabBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1040 {
1041     CHECK_NULL_VOID(layoutWrapper);
1042     auto geometryNode = layoutWrapper->GetGeometryNode();
1043     CHECK_NULL_VOID(geometryNode);
1044     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
1045     CHECK_NULL_VOID(layoutProperty);
1046     axis_ = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
1047     if ((axis_ == Axis::VERTICAL && NearZero(geometryNode->GetFrameSize().Width())) ||
1048         (axis_ == Axis::HORIZONTAL && NearZero(geometryNode->GetFrameSize().Height()))) {
1049         return;
1050     }
1051     childCount_ = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
1052     if (childCount_ <= 0) {
1053         return;
1054     }
1055     if (visibleItemPosition_.empty()) {
1056         return;
1057     }
1058 
1059     auto contentSize = geometryNode->GetPaddingSize();
1060     auto childOffset = OffsetF(0.0f, 0.0f);
1061     if (geometryNode->GetPadding()) {
1062         auto left = geometryNode->GetPadding()->left.value_or(0.0f);
1063         auto top = geometryNode->GetPadding()->top.value_or(0.0f);
1064         childOffset += OffsetF(left, top);
1065     }
1066     if (isRTL_ && axis_ == Axis::HORIZONTAL) {
1067         childOffset +=
1068             OffsetF(0.0f, contentSize.Width() - visibleItemPosition_.begin()->second.startPos - barGridMargin_, axis_);
1069     } else {
1070         childOffset += OffsetF(barGridMargin_, 0.0f);
1071         childOffset += OffsetF(0.0f, visibleItemPosition_.begin()->second.startPos, axis_);
1072     }
1073     LayoutChildren(layoutWrapper, contentSize, childOffset);
1074 }
1075 
LayoutChildren(LayoutWrapper * layoutWrapper,const SizeF & contentSize,OffsetF & childOffset)1076 void TabBarLayoutAlgorithm::LayoutChildren(LayoutWrapper* layoutWrapper, const SizeF& contentSize, OffsetF& childOffset)
1077 {
1078     std::map<int32_t, OffsetF> childOffsetDelta;
1079     for (auto& iter : visibleItemPosition_) {
1080         auto pos = iter.first;
1081         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(pos);
1082         if (!childWrapper) {
1083             continue;
1084         }
1085         auto childGeometryNode = childWrapper->GetGeometryNode();
1086         auto childFrameSize = childGeometryNode->GetMarginFrameSize();
1087         if (isRTL_ && axis_ == Axis::HORIZONTAL) {
1088             childOffset -= OffsetF(0.0f, childFrameSize.MainSize(axis_), axis_);
1089         }
1090         OffsetF centerOffset =
1091             OffsetF((contentSize.CrossSize(axis_) - childFrameSize.CrossSize(axis_)) / 2.0, 0.0f, axis_);
1092         childOffsetDelta[pos] = childOffset + centerOffset - childGeometryNode->GetMarginFrameOffset();
1093         childGeometryNode->SetMarginFrameOffset(childOffset + centerOffset);
1094         childWrapper->Layout();
1095         if (!isRTL_ || axis_ != Axis::HORIZONTAL) {
1096             childOffset += OffsetF(0.0f, childFrameSize.MainSize(axis_), axis_);
1097         }
1098     }
1099     LayoutMask(layoutWrapper, childOffsetDelta);
1100 }
1101 
LayoutMask(LayoutWrapper * layoutWrapper,const std::map<int32_t,OffsetF> & childOffsetDelta)1102 void TabBarLayoutAlgorithm::LayoutMask(LayoutWrapper* layoutWrapper,
1103     const std::map<int32_t, OffsetF>& childOffsetDelta)
1104 {
1105     auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
1106     CHECK_NULL_VOID(layoutProperty);
1107     auto selectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount_);
1108     CHECK_NULL_VOID(selectedMaskWrapper);
1109     auto unselectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount_ + 1);
1110     CHECK_NULL_VOID(unselectedMaskWrapper);
1111     for (int32_t i = 0; i < MASK_COUNT; i++) {
1112         auto currentWrapper = (i == 0 ? selectedMaskWrapper : unselectedMaskWrapper);
1113         auto currentMask = (i == 0 ? layoutProperty->GetSelectedMask().value_or(-1)
1114                                    : layoutProperty->GetUnselectedMask().value_or(-1));
1115         if (currentMask < 0) {
1116             currentWrapper->GetGeometryNode()->SetFrameSize(SizeF());
1117             currentWrapper->Layout();
1118             currentWrapper->SetActive(false);
1119         } else {
1120             auto offset = currentWrapper->GetGeometryNode()->GetMarginFrameOffset();
1121             auto iter = childOffsetDelta.find(currentMask);
1122             if (iter != childOffsetDelta.end()) {
1123                 offset += iter->second;
1124             }
1125             currentWrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
1126             auto imageWrapper = currentWrapper->GetOrCreateChildByIndex(0);
1127             CHECK_NULL_VOID(imageWrapper);
1128             auto imageNode = imageWrapper->GetHostNode();
1129             CHECK_NULL_VOID(imageNode);
1130             auto imageRenderContext = imageNode->GetRenderContext();
1131             CHECK_NULL_VOID(imageRenderContext);
1132             imageRenderContext->SetVisible(true);
1133             currentWrapper->Layout();
1134             currentWrapper->SetActive(true);
1135         }
1136     }
1137 }
1138 
GetGridSizeType(const SizeF & frameSize) const1139 GridSizeType TabBarLayoutAlgorithm::GetGridSizeType(const SizeF& frameSize) const
1140 {
1141     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TAB_BAR);
1142     CHECK_NULL_RETURN(gridColumnInfo, GridSizeType::UNDEFINED);
1143     auto parent = gridColumnInfo->GetParent();
1144     CHECK_NULL_RETURN(parent, GridSizeType::UNDEFINED);
1145     parent->BuildColumnWidth(frameSize.Width());
1146     return parent->GetSizeType();
1147 }
1148 
GetGridWidth(const BarGridColumnOptions & option,const SizeF & frameSize,int32_t columns) const1149 float TabBarLayoutAlgorithm::GetGridWidth(
1150     const BarGridColumnOptions& option, const SizeF& frameSize, int32_t columns) const
1151 {
1152     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TAB_BAR);
1153     CHECK_NULL_RETURN(gridColumnInfo, 0.0f);
1154     auto parent = gridColumnInfo->GetParent();
1155     CHECK_NULL_RETURN(parent, 0.0f);
1156     parent->SetGutterWidth(option.gutter);
1157     parent->SetMarginLeft(option.margin);
1158     parent->SetMarginRight(option.margin);
1159     parent->BuildColumnWidth(frameSize.Width());
1160     if (columns < 0) {
1161         return gridColumnInfo->GetMaxWidth();
1162     }
1163     return gridColumnInfo->GetWidth(columns);
1164 }
1165 } // namespace OHOS::Ace::NG
1166