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/relative_container/relative_container_layout_algorithm.h"
17
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/geometry/ng/size_t.h"
20 #include "base/log/ace_trace.h"
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/components_ng/layout/layout_algorithm.h"
24 #include "core/components_ng/layout/layout_wrapper.h"
25 #include "core/components_ng/pattern/relative_container/relative_container_layout_property.h"
26 #include "core/components_ng/pattern/relative_container/relative_container_pattern.h"
27 #include "core/components_ng/property/flex_property.h"
28 #include "core/components_ng/property/layout_constraint.h"
29 #include "core/components_ng/property/measure_property.h"
30 #include "core/components_ng/property/measure_utils.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr float DEFAULT_BIAS = 0.5f;
36 constexpr float HALF_MULTIPLY = 0.5f;
37 constexpr float DEFAULT_WEIGHT = 0.0f;
38 const std::string CONCAT_ID_PREFIX = "@concat";
IsAnchorContainer(const std::string & anchor)39 inline bool IsAnchorContainer(const std::string& anchor)
40 {
41 return anchor == "__container__";
42 }
43
GetOrCreateNodeInspectorId(const RefPtr<FrameNode> & node)44 std::string GetOrCreateNodeInspectorId(const RefPtr<FrameNode>& node)
45 {
46 auto inspectorId = node->GetInspectorIdValue("");
47 if (!node->HasInspectorId()) {
48 inspectorId = CONCAT_ID_PREFIX + node->GetTag() + std::to_string(node->GetId());
49 }
50 return inspectorId;
51 }
52 } // namespace
53
UpdateTwoAlignValues(TwoAlignedValues & twoAlignedValues,AlignRule alignRule,LineDirection direction)54 void RelativeContainerLayoutAlgorithm::UpdateTwoAlignValues(
55 TwoAlignedValues& twoAlignedValues, AlignRule alignRule, LineDirection direction)
56 {
57 if (twoAlignedValues.first.has_value() && twoAlignedValues.second.has_value()) {
58 return;
59 }
60
61 auto result = (direction == LineDirection::HORIZONTAL) ? GetHorizontalAnchorValueByAlignRule(alignRule)
62 : GetVerticalAnchorValueByAlignRule(alignRule);
63
64 if (!twoAlignedValues.first.has_value()) {
65 twoAlignedValues.first = result;
66 return;
67 }
68 if (!twoAlignedValues.second.has_value()) {
69 twoAlignedValues.second = result;
70 }
71 }
72
DetermineTopologicalOrder(LayoutWrapper * layoutWrapper)73 void RelativeContainerLayoutAlgorithm::DetermineTopologicalOrder(LayoutWrapper* layoutWrapper)
74 {
75 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
76 CHECK_NULL_VOID(relativeContainerLayoutProperty);
77 idNodeMap_.clear();
78 reliedOnMap_.clear();
79 recordOffsetMap_.clear();
80 incomingDegreeMap_.clear();
81 horizontalChainNodeMap_.clear();
82 verticalChainNodeMap_.clear();
83 renderList_.clear();
84 auto layoutConstraint = relativeContainerLayoutProperty->GetLayoutConstraint();
85 CHECK_NULL_VOID(layoutConstraint.has_value());
86 bool idealWidthValid = layoutConstraint.value().selfIdealSize.Width().has_value();
87 bool idealHeightValid = layoutConstraint.value().selfIdealSize.Height().has_value();
88 auto idealSize = CreateIdealSizeByPercentRef(layoutConstraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
89 if (!idealWidthValid) {
90 idealSize.SetWidth(
91 std::min(idealSize.Width().value_or(Infinity<float>()), layoutConstraint.value().maxSize.Width()));
92 idealSize.SetWidth(std::max(idealSize.Width().value_or(0.0f), layoutConstraint.value().minSize.Width()));
93 }
94 if (!idealHeightValid) {
95 idealSize.SetHeight(
96 std::min(idealSize.Height().value_or(Infinity<float>()), layoutConstraint.value().maxSize.Height()));
97 idealSize.SetHeight(std::max(idealSize.Height().value_or(0.0f), layoutConstraint.value().minSize.Height()));
98 }
99 containerSizeWithoutPaddingBorder_ = idealSize.ConvertToSizeT();
100 layoutWrapper->GetGeometryNode()->SetFrameSize(containerSizeWithoutPaddingBorder_);
101 if (relativeContainerLayoutProperty->GetPaddingProperty() ||
102 relativeContainerLayoutProperty->GetBorderWidthProperty()) {
103 padding_ = relativeContainerLayoutProperty->CreatePaddingAndBorder();
104 MinusPaddingToSize(padding_, containerSizeWithoutPaddingBorder_);
105 }
106 CollectNodesById(layoutWrapper);
107 CheckChain(layoutWrapper);
108 GetDependencyRelationship();
109 if (!PreTopologicalLoopDetection()) {
110 const auto& childrenWrappers = layoutWrapper->GetAllChildrenWithBuild();
111 auto constraint = relativeContainerLayoutProperty->CreateChildConstraint();
112 for (const auto& childrenWrapper : childrenWrappers) {
113 childrenWrapper->SetActive(false);
114 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
115 childrenWrapper->Measure(constraint);
116 constraint.Reset();
117 }
118 return;
119 }
120 TopologicalSort(renderList_);
121 }
122
UpdateSizeWhenChildrenEmpty(LayoutWrapper * layoutWrapper)123 void RelativeContainerLayoutAlgorithm::UpdateSizeWhenChildrenEmpty(LayoutWrapper* layoutWrapper)
124 {
125 CHECK_NULL_VOID(layoutWrapper);
126 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
127 CHECK_NULL_VOID(relativeContainerLayoutProperty);
128 const auto& layoutConstraint = relativeContainerLayoutProperty->GetLayoutConstraint();
129 CHECK_NULL_VOID(layoutConstraint.has_value());
130 auto idealSize =
131 CreateIdealSizeByPercentRef(layoutConstraint.value(), Axis::FREE, MeasureType::MATCH_PARENT).ConvertToSizeT();
132 layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize.IsPositive() ? idealSize : SizeF(0.0f, 0.0f));
133 const auto& calcLayoutConstraint = relativeContainerLayoutProperty->GetCalcLayoutConstraint();
134 CHECK_NULL_VOID(calcLayoutConstraint);
135 auto selfIdealSize = calcLayoutConstraint->selfIdealSize;
136 padding_ = relativeContainerLayoutProperty->CreatePaddingAndBorder();
137 if (selfIdealSize->Width()->GetDimension().Unit() == DimensionUnit::AUTO) {
138 layoutWrapper->GetGeometryNode()->SetFrameSize(
139 SizeF(padding_.Width(), layoutWrapper->GetGeometryNode()->GetFrameSize().Height()));
140 }
141 if (selfIdealSize->Height()->GetDimension().Unit() == DimensionUnit::AUTO) {
142 layoutWrapper->GetGeometryNode()->SetFrameSize(
143 SizeF(layoutWrapper->GetGeometryNode()->GetFrameSize().Width(), padding_.Height()));
144 }
145 }
146
CalcHorizontalGuideline(std::optional<CalcSize> & selfIdealSize,float containerHeight,const GuidelineInfo & guidelineInfo)147 void RelativeContainerLayoutAlgorithm::CalcHorizontalGuideline(
148 std::optional<CalcSize>& selfIdealSize, float containerHeight, const GuidelineInfo& guidelineInfo)
149 {
150 ScaleProperty scaleProperty = ScaleProperty::CreateScaleProperty();
151 bool heightAuto = (selfIdealSize->Height()->GetDimension().Unit() == DimensionUnit::AUTO);
152 if (guidelineInfo.start.has_value()) {
153 if ((guidelineInfo.start.value().Unit() == DimensionUnit::PERCENT) && heightAuto) {
154 guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::HORIZONTAL, 0.0f);
155 } else {
156 auto start = ConvertToPx(guidelineInfo.start.value(), scaleProperty, containerHeight);
157 guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::HORIZONTAL, start.value_or(0.0f));
158 }
159 } else if (guidelineInfo.end.has_value()) {
160 if (heightAuto) {
161 guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::HORIZONTAL, 0.0f);
162 } else {
163 auto end = ConvertToPx(guidelineInfo.end.value(), scaleProperty, containerHeight);
164 guidelines_[guidelineInfo.id] =
165 std::make_pair(LineDirection::HORIZONTAL, (containerHeight - end.value_or(0.0f)));
166 }
167 }
168 }
169
CalcVerticalGuideline(std::optional<CalcSize> & selfIdealSize,float containerWidth,const GuidelineInfo & guidelineInfo)170 void RelativeContainerLayoutAlgorithm::CalcVerticalGuideline(
171 std::optional<CalcSize>& selfIdealSize, float containerWidth, const GuidelineInfo& guidelineInfo)
172 {
173 ScaleProperty scaleProperty = ScaleProperty::CreateScaleProperty();
174 bool widthAuto = (selfIdealSize->Width()->GetDimension().Unit() == DimensionUnit::AUTO);
175 if (guidelineInfo.start.has_value()) {
176 if ((guidelineInfo.start.value().Unit() == DimensionUnit::PERCENT) && widthAuto) {
177 guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::VERTICAL, 0.0f);
178 } else {
179 auto start = ConvertToPx(guidelineInfo.start.value(), scaleProperty, containerWidth);
180 guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::VERTICAL, start.value_or(0.0f));
181 }
182 } else if (guidelineInfo.end.has_value()) {
183 if (widthAuto) {
184 guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::VERTICAL, 0.0f);
185 } else {
186 auto end = ConvertToPx(guidelineInfo.end.value(), scaleProperty, containerWidth);
187 guidelines_[guidelineInfo.id] =
188 std::make_pair(LineDirection::VERTICAL, (containerWidth - end.value_or(0.0f)));
189 }
190 }
191 }
192
CalcBarrier(LayoutWrapper * layoutWrapper)193 void RelativeContainerLayoutAlgorithm::CalcBarrier(LayoutWrapper* layoutWrapper)
194 {
195 CHECK_NULL_VOID(versionGreatorOrEqualToEleven_);
196 CHECK_NULL_VOID(layoutWrapper);
197 auto layoutProperty = DynamicCast<RelativeContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
198 CHECK_NULL_VOID(layoutProperty);
199
200 barriers_.clear();
201 if (!layoutProperty->HasBarrier()) {
202 return;
203 }
204
205 for (const auto& barrierInfo : layoutProperty->GetBarrierValue()) {
206 if (barrierInfo.id.empty() || IsGuideline(barrierInfo.id) ||
207 (idNodeMap_.find(barrierInfo.id) != idNodeMap_.end())) {
208 continue;
209 }
210 auto barrierDirection = BarrierDirectionRtl(barrierInfo.direction);
211 barriers_[barrierInfo.id] = std::make_pair(barrierDirection, barrierInfo.referencedId);
212 }
213 }
214
CalcGuideline(LayoutWrapper * layoutWrapper)215 void RelativeContainerLayoutAlgorithm::CalcGuideline(LayoutWrapper* layoutWrapper)
216 {
217 CHECK_NULL_VOID(versionGreatorOrEqualToEleven_);
218 CHECK_NULL_VOID(layoutWrapper);
219 auto layoutProperty = DynamicCast<RelativeContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
220 CHECK_NULL_VOID(layoutProperty);
221 const auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
222 CHECK_NULL_VOID(calcLayoutConstraint);
223 auto calcSelfIdealSize = calcLayoutConstraint->selfIdealSize;
224 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
225 CHECK_NULL_VOID(layoutConstraint);
226 auto selfIdealSize = layoutConstraint->selfIdealSize;
227
228 guidelines_.clear();
229 if (!layoutProperty->HasGuideline()) {
230 return;
231 }
232
233 for (const auto& guidelineInfo : layoutProperty->GetGuidelineValue()) {
234 if (guidelineInfo.id.empty() || (idNodeMap_.find(guidelineInfo.id) != idNodeMap_.end())) {
235 continue;
236 }
237 if (guidelineInfo.direction == LineDirection::HORIZONTAL) {
238 CalcHorizontalGuideline(calcSelfIdealSize, selfIdealSize.Height().value_or(0), guidelineInfo);
239 } else {
240 CalcVerticalGuideline(calcSelfIdealSize, selfIdealSize.Width().value_or(0), guidelineInfo);
241 }
242 }
243
244 for (const auto& guideline : guidelines_) {
245 if (guideline.second.first == LineDirection::HORIZONTAL) {
246 recordOffsetMap_[guideline.first] = OffsetF(0.0f, guideline.second.second);
247 } else {
248 recordOffsetMap_[guideline.first] = OffsetF(guideline.second.second, 0.0f);
249 }
250 }
251 }
252
IsGuideline(const std::string & id)253 bool RelativeContainerLayoutAlgorithm::IsGuideline(const std::string& id)
254 {
255 CHECK_NULL_RETURN(versionGreatorOrEqualToEleven_, false);
256 CHECK_NULL_RETURN(!guidelines_.empty(), false);
257 if (guidelines_.find(id) == guidelines_.end()) {
258 return false;
259 }
260
261 return true;
262 }
263
IsBarrier(const std::string & id)264 bool RelativeContainerLayoutAlgorithm::IsBarrier(const std::string& id)
265 {
266 CHECK_NULL_RETURN(versionGreatorOrEqualToEleven_, false);
267 CHECK_NULL_RETURN(!barriers_.empty(), false);
268
269 if (barriers_.find(id) == barriers_.end()) {
270 return false;
271 }
272
273 return true;
274 }
275
GetBarrierRectByReferencedIds(const std::vector<std::string> & referencedIds)276 RelativeContainerLayoutAlgorithm::BarrierRect RelativeContainerLayoutAlgorithm::GetBarrierRectByReferencedIds(
277 const std::vector<std::string>& referencedIds)
278 {
279 BarrierRect barrierRect;
280 for (const auto& nodeName : referencedIds) {
281 if (IsGuideline(nodeName)) {
282 if (guidelines_[nodeName].first == LineDirection::VERTICAL) {
283 barrierRect.minLeft = std::min(barrierRect.minLeft, recordOffsetMap_[nodeName].GetX());
284 barrierRect.maxRight = std::max(barrierRect.maxRight, recordOffsetMap_[nodeName].GetX());
285 } else {
286 barrierRect.minTop = std::min(barrierRect.minTop, recordOffsetMap_[nodeName].GetY());
287 barrierRect.maxBottom = std::max(barrierRect.maxBottom, recordOffsetMap_[nodeName].GetY());
288 }
289 continue;
290 }
291
292 if (IsBarrier(nodeName)) {
293 switch (barriers_[nodeName].first) {
294 case BarrierDirection::LEFT:
295 barrierRect.minLeft = std::min(barrierRect.minLeft, recordOffsetMap_[nodeName].GetX());
296 break;
297 case BarrierDirection::RIGHT:
298 barrierRect.maxRight = std::max(barrierRect.maxRight, recordOffsetMap_[nodeName].GetX());
299 break;
300 case BarrierDirection::TOP:
301 barrierRect.minTop = std::min(barrierRect.minTop, recordOffsetMap_[nodeName].GetY());
302 break;
303 case BarrierDirection::BOTTOM:
304 barrierRect.maxBottom = std::max(barrierRect.maxBottom, recordOffsetMap_[nodeName].GetY());
305 break;
306 default:
307 break;
308 }
309 continue;
310 }
311 auto it = idNodeMap_.find(nodeName);
312 if (it == idNodeMap_.end()) {
313 continue;
314 }
315
316 auto childWrapper = it->second.layoutWrapper;
317 if (childWrapper->GetLayoutProperty()->GetVisibility() == VisibleType::GONE) {
318 continue;
319 }
320 auto& recordOffset = recordOffsetMap_[nodeName];
321 barrierRect.minLeft = std::min(barrierRect.minLeft, recordOffset.GetX());
322 barrierRect.minTop = std::min(barrierRect.minTop, recordOffset.GetY());
323 barrierRect.maxRight = std::max(
324 barrierRect.maxRight, recordOffset.GetX() + childWrapper->GetGeometryNode()->GetMarginFrameSize().Width());
325 barrierRect.maxBottom = std::max(barrierRect.maxBottom,
326 recordOffset.GetY() + childWrapper->GetGeometryNode()->GetMarginFrameSize().Height());
327 }
328 return barrierRect;
329 }
330
MeasureBarrier(const std::string & barrierName)331 void RelativeContainerLayoutAlgorithm::MeasureBarrier(const std::string& barrierName)
332 {
333 BarrierRect barrierRect = GetBarrierRectByReferencedIds(barriers_[barrierName].second);
334 switch (barriers_[barrierName].first) {
335 case BarrierDirection::LEFT:
336 recordOffsetMap_[barrierName] = OffsetF(barrierRect.minLeft, 0.0f);
337 break;
338 case BarrierDirection::RIGHT:
339 recordOffsetMap_[barrierName] = OffsetF(barrierRect.maxRight, 0.0f);
340 break;
341 case BarrierDirection::TOP:
342 recordOffsetMap_[barrierName] = OffsetF(0.0f, barrierRect.minTop);
343 break;
344 case BarrierDirection::BOTTOM:
345 recordOffsetMap_[barrierName] = OffsetF(0.0f, barrierRect.maxBottom);
346 break;
347 default:
348 break;
349 }
350 }
351
CheckNodeInHorizontalChain(std::string & currentNode,AlignRulesItem & currentAlignRules,std::vector<std::string> & chainNodes,AlignRule & rightAnchor,float & totalChainWeight)352 void RelativeContainerLayoutAlgorithm::CheckNodeInHorizontalChain(std::string& currentNode,
353 AlignRulesItem& currentAlignRules, std::vector<std::string>& chainNodes,
354 AlignRule& rightAnchor, float& totalChainWeight)
355 {
356 std::string nextNode = rightAnchor.anchor;
357 while (idNodeMap_.find(nextNode) != idNodeMap_.end()) {
358 if (currentAlignRules[AlignDirection::RIGHT].horizontal != HorizontalAlign::START) {
359 break;
360 }
361 CHECK_NULL_BREAK(idNodeMap_.find(nextNode) != idNodeMap_.end());
362 auto nextNodeWrapper = idNodeMap_[nextNode].layoutWrapper;
363 const auto& nextNodeFlexItem = nextNodeWrapper->GetLayoutProperty()->GetFlexItemProperty();
364 if (!nextNodeFlexItem) {
365 break;
366 }
367 AlignRulesItem nextNodeAlignRules = nextNodeFlexItem->GetAlignRulesValue();
368 if (nextNodeAlignRules.find(AlignDirection::LEFT) == nextNodeAlignRules.end() ||
369 nextNodeAlignRules.find(AlignDirection::RIGHT) == nextNodeAlignRules.end()) {
370 break;
371 }
372 if (nextNodeAlignRules[AlignDirection::LEFT].anchor != currentNode ||
373 nextNodeAlignRules[AlignDirection::LEFT].horizontal != HorizontalAlign::END) {
374 break;
375 }
376 chainNodes.emplace_back(nextNode);
377 bool childGone = nextNodeWrapper->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
378 VisibleType::GONE;
379 float childLayoutWeight = DEFAULT_WEIGHT;
380 if (!childGone) {
381 childLayoutWeight = nextNodeFlexItem->GetChainWeight()->first.value_or(0.0f);
382 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
383 isChainWeightMode_ = true;
384 totalChainWeight += childLayoutWeight;
385 }
386 }
387 currentNode = nextNode;
388 currentAlignRules = nextNodeAlignRules;
389 nextNode = nextNodeAlignRules[AlignDirection::RIGHT].anchor;
390 rightAnchor = nextNodeAlignRules[AlignDirection::RIGHT];
391 }
392 }
393
CheckHorizontalChain(const ChildMeasureWrapper & measureParam)394 void RelativeContainerLayoutAlgorithm::CheckHorizontalChain(const ChildMeasureWrapper& measureParam)
395 {
396 auto childWrapper = measureParam.layoutWrapper;
397 auto childHostNode = childWrapper->GetHostNode();
398 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
399 AlignRulesItem currentAlignRules = flexItem->GetAlignRulesValue();
400 ChainInfo chainInfo = flexItem->GetHorizontalChainStyleValue();
401 CHECK_NULL_VOID(chainInfo.direction.has_value());
402 CHECK_NULL_VOID(chainInfo.style.has_value());
403 BiasPair bias(0.5f, 0.5f);
404 float totalChainWeight = DEFAULT_WEIGHT;
405 if (flexItem->HasBias()) {
406 bias = flexItem->GetBiasValue();
407 }
408 if (currentAlignRules.find(AlignDirection::LEFT) == currentAlignRules.end() ||
409 currentAlignRules.find(AlignDirection::RIGHT) == currentAlignRules.end()) {
410 return;
411 }
412 AlignRule leftAnchor = currentAlignRules[AlignDirection::LEFT];
413 CHECK_NULL_VOID(IsAnchorLegal(leftAnchor.anchor));
414 AlignRule rightAnchor = currentAlignRules[AlignDirection::RIGHT];
415 std::string currentNode = measureParam.id;
416 std::vector<std::string> chainNodes;
417 chainNodes.emplace_back(currentNode);
418 if (childWrapper->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::GONE) {
419 float childLayoutWeight = flexItem->GetChainWeight()->first.value_or(DEFAULT_WEIGHT);
420 isChainWeightMode_ += GreatNotEqual(childLayoutWeight, DEFAULT_WEIGHT);
421 totalChainWeight += std::max(childLayoutWeight, DEFAULT_WEIGHT);
422 }
423 CheckNodeInHorizontalChain(currentNode, currentAlignRules, chainNodes, rightAnchor, totalChainWeight);
424 CHECK_NULL_VOID(IsAnchorLegal(rightAnchor.anchor) && chainNodes.size() > 1);
425 if (IsAnchorContainer(leftAnchor.anchor) || IsAnchorContainer(rightAnchor.anchor)) {
426 isHorizontalRelyOnContainer_ = true;
427 }
428 ChainParam chainParam;
429 chainParam.ids = chainNodes;
430 chainParam.anchorHead = leftAnchor;
431 chainParam.anchorTail = rightAnchor;
432 chainParam.chainStyle = chainInfo.style.value();
433 chainParam.bias = bias;
434 chainParam.totalChainWeight = totalChainWeight;
435 for (const auto& id : chainParam.ids) {
436 chainParam.itemSize[id] = std::nullopt;
437 horizontalChainNodeMap_[id] = measureParam.id;
438 }
439 horizontalChains_[measureParam.id] = chainParam;
440 }
441
CheckNodeInVerticalChain(std::string & currentNode,AlignRulesItem & currentAlignRules,std::vector<std::string> & chainNodes,AlignRule & bottomAnchor,float & totalChainWeight)442 void RelativeContainerLayoutAlgorithm::CheckNodeInVerticalChain(std::string& currentNode,
443 AlignRulesItem& currentAlignRules, std::vector<std::string>& chainNodes,
444 AlignRule& bottomAnchor, float& totalChainWeight)
445 {
446 std::string nextNode = bottomAnchor.anchor;
447 while (idNodeMap_.find(nextNode) != idNodeMap_.end()) {
448 if (currentAlignRules[AlignDirection::BOTTOM].vertical != VerticalAlign::TOP) {
449 break;
450 }
451 CHECK_NULL_BREAK(idNodeMap_.find(nextNode) != idNodeMap_.end());
452 auto nextNodeWrapper = idNodeMap_[nextNode].layoutWrapper;
453 const auto& nextNodeFlexItem = nextNodeWrapper->GetLayoutProperty()->GetFlexItemProperty();
454 if (!nextNodeFlexItem) {
455 break;
456 }
457 AlignRulesItem nextNodeAlignRules = nextNodeFlexItem->GetAlignRulesValue();
458 if (nextNodeAlignRules.find(AlignDirection::TOP) == nextNodeAlignRules.end() ||
459 nextNodeAlignRules.find(AlignDirection::BOTTOM) == nextNodeAlignRules.end()) {
460 break;
461 }
462 if (nextNodeAlignRules[AlignDirection::TOP].anchor != currentNode ||
463 nextNodeAlignRules[AlignDirection::TOP].vertical != VerticalAlign::BOTTOM) {
464 break;
465 }
466 chainNodes.emplace_back(nextNode);
467 bool childGone = nextNodeWrapper->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
468 VisibleType::GONE;
469 float childLayoutWeight = DEFAULT_WEIGHT;
470 if (!childGone) {
471 childLayoutWeight = nextNodeFlexItem->GetChainWeight()->second.value_or(0.0f);
472 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
473 isChainWeightMode_ = true;
474 totalChainWeight += childLayoutWeight;
475 }
476 }
477 currentNode = nextNode;
478 currentAlignRules = nextNodeAlignRules;
479 nextNode = nextNodeAlignRules[AlignDirection::BOTTOM].anchor;
480 bottomAnchor = nextNodeAlignRules[AlignDirection::BOTTOM];
481 }
482 }
483
CheckVerticalChain(const ChildMeasureWrapper & measureParam)484 void RelativeContainerLayoutAlgorithm::CheckVerticalChain(const ChildMeasureWrapper& measureParam)
485 {
486 auto childWrapper = measureParam.layoutWrapper;
487 auto childHostNode = childWrapper->GetHostNode();
488 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
489 AlignRulesItem currentAlignRules = flexItem->GetAlignRulesValue();
490 ChainInfo chainInfo = flexItem->GetVerticalChainStyleValue();
491 BiasPair bias(0.5f, 0.5f);
492 float totalChainWeight = DEFAULT_WEIGHT;
493 CHECK_NULL_VOID(chainInfo.direction.has_value());
494 CHECK_NULL_VOID(chainInfo.style.has_value());
495 if (flexItem->HasBias()) {
496 bias = flexItem->GetBiasValue();
497 }
498 if (currentAlignRules.find(AlignDirection::TOP) == currentAlignRules.end() ||
499 currentAlignRules.find(AlignDirection::BOTTOM) == currentAlignRules.end()) {
500 return;
501 }
502 AlignRule topAnchor = currentAlignRules[AlignDirection::TOP];
503 CHECK_NULL_VOID(IsAnchorLegal(topAnchor.anchor));
504 AlignRule bottomAnchor = currentAlignRules[AlignDirection::BOTTOM];
505 std::string currentNode = measureParam.id;
506 std::vector<std::string> chainNodes;
507 chainNodes.emplace_back(currentNode);
508 if (childWrapper->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::GONE) {
509 float childLayoutWeight = flexItem->GetChainWeight()->second.value_or(DEFAULT_WEIGHT);
510 isChainWeightMode_ += GreatNotEqual(childLayoutWeight, DEFAULT_WEIGHT);
511 totalChainWeight += std::max(childLayoutWeight, DEFAULT_WEIGHT);
512 }
513 CheckNodeInVerticalChain(currentNode, currentAlignRules, chainNodes, bottomAnchor, totalChainWeight);
514 CHECK_NULL_VOID(IsAnchorLegal(bottomAnchor.anchor) && chainNodes.size() > 1);
515 if (IsAnchorContainer(topAnchor.anchor) || IsAnchorContainer(bottomAnchor.anchor)) {
516 isVerticalRelyOnContainer_ = true;
517 }
518 ChainParam chainParam;
519 chainParam.ids = chainNodes;
520 chainParam.anchorHead = topAnchor;
521 chainParam.anchorTail = bottomAnchor;
522 chainParam.chainStyle = chainInfo.style.value();
523 chainParam.bias = bias;
524 chainParam.totalChainWeight = totalChainWeight;
525 for (const auto& id : chainParam.ids) {
526 chainParam.itemSize[id] = std::nullopt;
527 verticalChainNodeMap_[id] = measureParam.id;
528 }
529 verticalChains_[measureParam.id] = chainParam;
530 }
531
CheckChain(LayoutWrapper * layoutWrapper)532 void RelativeContainerLayoutAlgorithm::CheckChain(LayoutWrapper* layoutWrapper)
533 {
534 CHECK_NULL_VOID(versionGreatorOrEqualToEleven_);
535 horizontalChains_.clear();
536 verticalChains_.clear();
537 for (const auto& mapItem : idNodeMap_) {
538 auto childWrapper = mapItem.second.layoutWrapper;
539 auto childLayoutProperty = childWrapper->GetLayoutProperty();
540 CHECK_NULL_VOID(childLayoutProperty);
541 const auto& flexItem = childLayoutProperty->GetFlexItemProperty();
542 if (!flexItem || !flexItem->HasAlignRules()) {
543 continue;
544 }
545
546 std::string chainName;
547 if (flexItem->HasHorizontalChainStyle() && !IsNodeInHorizontalChain(mapItem.first, chainName)) {
548 CheckHorizontalChain(mapItem.second);
549 }
550
551 if (flexItem->HasVerticalChainStyle() && !IsNodeInVerticalChain(mapItem.first, chainName)) {
552 CheckVerticalChain(mapItem.second);
553 }
554 }
555 }
556
RecordSizeInChain(const std::string & nodeName)557 void RelativeContainerLayoutAlgorithm::RecordSizeInChain(const std::string& nodeName)
558 {
559 CHECK_NULL_VOID(versionGreatorOrEqualToEleven_);
560 CHECK_NULL_VOID(idNodeMap_.find(nodeName) != idNodeMap_.end());
561 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
562 CHECK_NULL_VOID(childWrapper);
563 auto childLayoutProperty = childWrapper->GetLayoutProperty();
564 CHECK_NULL_VOID(childLayoutProperty);
565 const auto& flexItem = childLayoutProperty->GetFlexItemProperty();
566 std::string chainName;
567 if (IsNodeInHorizontalChain(nodeName, chainName) &&
568 !GreatNotEqual(flexItem->GetChainWeight()->first.value_or(0.0f), 0.0f)) {
569 horizontalChains_[chainName].itemSize[nodeName] =
570 childWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
571 horizontalChains_[chainName].remainingSpace -= childWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
572 }
573 if (IsNodeInVerticalChain(nodeName, chainName) &&
574 !GreatNotEqual(flexItem->GetChainWeight()->second.value_or(0.0f), 0.0f)) {
575 verticalChains_[chainName].itemSize[nodeName] =
576 childWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
577 verticalChains_[chainName].remainingSpace -= childWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
578 }
579 }
580
IsNodeInHorizontalChain(const std::string & nodeName,std::string & chainName)581 bool RelativeContainerLayoutAlgorithm::IsNodeInHorizontalChain(const std::string& nodeName, std::string& chainName)
582 {
583 CHECK_NULL_RETURN(versionGreatorOrEqualToEleven_, false);
584 CHECK_NULL_RETURN(!horizontalChains_.empty(), false);
585 auto it = horizontalChainNodeMap_.find(nodeName);
586 if (it != horizontalChainNodeMap_.end()) {
587 chainName = it->second;
588 return true;
589 }
590 return false;
591 }
IsNodeInVerticalChain(const std::string & nodeName,std::string & chainName)592 bool RelativeContainerLayoutAlgorithm::IsNodeInVerticalChain(const std::string& nodeName, std::string& chainName)
593 {
594 CHECK_NULL_RETURN(versionGreatorOrEqualToEleven_, false);
595 CHECK_NULL_RETURN(!verticalChains_.empty(), false);
596 auto it = verticalChainNodeMap_.find(nodeName);
597 if (it != verticalChainNodeMap_.end()) {
598 chainName = it->second;
599 return true;
600 }
601 return false;
602 }
603
GetHorizontalAnchorValueByAlignRule(AlignRule & alignRule)604 float RelativeContainerLayoutAlgorithm::GetHorizontalAnchorValueByAlignRule(AlignRule& alignRule)
605 {
606 if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) {
607 return recordOffsetMap_[alignRule.anchor].GetX();
608 }
609 bool anchorIsContainer = IsAnchorContainer(alignRule.anchor);
610 float anchorWidth = 0.0f;
611 if (anchorIsContainer) {
612 anchorWidth = containerSizeWithoutPaddingBorder_.Width();
613 } else {
614 anchorWidth = versionGreatorOrEqualToEleven_
615 ? idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetFrameSize().Width()
616 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
617 }
618
619 std::optional<float> marginLeft;
620 if (!anchorIsContainer && versionGreatorOrEqualToEleven_) {
621 auto anchorWrapper = idNodeMap_[alignRule.anchor].layoutWrapper;
622 if (anchorWrapper->GetGeometryNode()->GetMargin()) {
623 marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left;
624 }
625 }
626
627 float offsetX = 0.0f;
628 switch (alignRule.horizontal) {
629 case HorizontalAlign::START:
630 offsetX = 0.0f;
631 break;
632 case HorizontalAlign::CENTER:
633 offsetX = anchorWidth * HALF_MULTIPLY;
634 break;
635 case HorizontalAlign::END:
636 offsetX = anchorWidth;
637 break;
638 default:
639 break;
640 }
641
642 offsetX += anchorIsContainer ? 0.0f : recordOffsetMap_[alignRule.anchor].GetX() + marginLeft.value_or(0);
643 return offsetX;
644 }
645
GetVerticalAnchorValueByAlignRule(AlignRule & alignRule)646 float RelativeContainerLayoutAlgorithm::GetVerticalAnchorValueByAlignRule(AlignRule& alignRule)
647 {
648 if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) {
649 return recordOffsetMap_[alignRule.anchor].GetY();
650 }
651 bool anchorIsContainer = IsAnchorContainer(alignRule.anchor);
652 float anchorHeight = 0.0f;
653 if (anchorIsContainer) {
654 anchorHeight = containerSizeWithoutPaddingBorder_.Height();
655 } else {
656 anchorHeight =
657 versionGreatorOrEqualToEleven_
658 ? idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetFrameSize().Height()
659 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
660 }
661
662 std::optional<float> marginTop;
663 if (!anchorIsContainer && versionGreatorOrEqualToEleven_) {
664 auto anchorWrapper = idNodeMap_[alignRule.anchor].layoutWrapper;
665 if (anchorWrapper->GetGeometryNode()->GetMargin()) {
666 marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top;
667 }
668 }
669
670 float offsetY = 0.0f;
671 switch (alignRule.vertical) {
672 case VerticalAlign::TOP:
673 offsetY = 0.0f;
674 break;
675 case VerticalAlign::CENTER:
676 offsetY = anchorHeight * HALF_MULTIPLY;
677 break;
678 case VerticalAlign::BOTTOM:
679 offsetY = anchorHeight;
680 break;
681 default:
682 break;
683 }
684
685 offsetY += anchorIsContainer ? 0.0f : recordOffsetMap_[alignRule.anchor].GetY() + marginTop.value_or(0);
686 return offsetY;
687 }
688
CalcOffsetInChainGetStart(const float & anchorDistance,const float & contentSize,int32_t itemCount,const ChainParam & chainParam,LineDirection direction)689 std::pair<float, float> RelativeContainerLayoutAlgorithm::CalcOffsetInChainGetStart(const float& anchorDistance,
690 const float& contentSize, int32_t itemCount, const ChainParam& chainParam, LineDirection direction)
691 {
692 float spaceSize = 0.0f;
693 float start = 0.0f;
694 float bias = (direction == LineDirection::HORIZONTAL) ? chainParam.bias.first : chainParam.bias.second;
695 if (GreatOrEqual(anchorDistance, contentSize)) {
696 switch (chainParam.chainStyle) {
697 case ChainStyle::SPREAD:
698 spaceSize = (anchorDistance - contentSize) / (itemCount + 1);
699 start = spaceSize;
700 break;
701 case ChainStyle::SPREAD_INSIDE:
702 spaceSize = anchorDistance - contentSize;
703 spaceSize = GreatNotEqual(itemCount, 1) ? spaceSize / (itemCount - 1) : spaceSize;
704 break;
705 case ChainStyle::PACKED:
706 spaceSize = 0.0f;
707 start = (anchorDistance - contentSize) * bias;
708 break;
709 default:
710 break;
711 }
712 } else {
713 switch (chainParam.chainStyle) {
714 case ChainStyle::SPREAD:
715 case ChainStyle::SPREAD_INSIDE:
716 start = (anchorDistance - contentSize) * HALF_MULTIPLY;
717 break;
718 case ChainStyle::PACKED:
719 start = (anchorDistance - contentSize) * bias;
720 break;
721 default:
722 break;
723 }
724 }
725 return { spaceSize, start };
726 }
727
RecordOffsetInChain(float offset,float spaceSize,const std::string & chainName,LineDirection direction)728 void RelativeContainerLayoutAlgorithm::RecordOffsetInChain(
729 float offset, float spaceSize, const std::string& chainName, LineDirection direction)
730 {
731 std::unordered_map<std::string, ChainParam>& chains =
732 (direction == LineDirection::HORIZONTAL) ? horizontalChains_ : verticalChains_;
733
734 if (direction == LineDirection::HORIZONTAL) {
735 for (const auto& nodeName : chains[chainName].ids) {
736 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
737 if (childWrapper->GetLayoutProperty()->GetVisibility() == VisibleType::GONE) {
738 continue;
739 }
740 recordOffsetMap_[nodeName] = OffsetF(offset, recordOffsetMap_[nodeName].GetY());
741 offset += chains[chainName].itemSize[nodeName].value() + spaceSize;
742 }
743 } else {
744 for (const auto& nodeName : chains[chainName].ids) {
745 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
746 if (childWrapper->GetLayoutProperty()->GetVisibility() == VisibleType::GONE) {
747 continue;
748 }
749 recordOffsetMap_[nodeName] = OffsetF(recordOffsetMap_[nodeName].GetX(), offset);
750 offset += chains[chainName].itemSize[nodeName].value() + spaceSize;
751 }
752 }
753 }
754
CalcOffsetInChain(const std::string & chainName,LineDirection direction)755 bool RelativeContainerLayoutAlgorithm::CalcOffsetInChain(const std::string& chainName, LineDirection direction)
756 {
757 float contentSize = 0.0f;
758 float anchorDistance = 0.0f;
759 float spaceSize = 0.0f;
760 float start = 0.0f;
761 float end = 0.0f;
762 std::unordered_map<std::string, ChainParam>& chains =
763 (direction == LineDirection::HORIZONTAL) ? horizontalChains_ : verticalChains_;
764 if (chains[chainName].isCalculated) {
765 return true;
766 }
767 auto itemCount = chains[chainName].ids.size();
768 for (const auto& itemSize : chains[chainName].itemSize) {
769 auto childWrapper = idNodeMap_[itemSize.first].layoutWrapper;
770 if (childWrapper->GetLayoutProperty()->GetVisibility() == VisibleType::GONE) {
771 itemCount--;
772 continue;
773 }
774 if (!itemSize.second.has_value()) {
775 return false;
776 }
777 contentSize += itemSize.second.value();
778 }
779
780 if (direction == LineDirection::HORIZONTAL) {
781 start = GetHorizontalAnchorValueByAlignRule(chains[chainName].anchorHead);
782 end = GetHorizontalAnchorValueByAlignRule(chains[chainName].anchorTail);
783 } else {
784 start = GetVerticalAnchorValueByAlignRule(chains[chainName].anchorHead);
785 end = GetVerticalAnchorValueByAlignRule(chains[chainName].anchorTail);
786 }
787 anchorDistance = end - start;
788 std::pair<float, float> spaceSizeAndStart =
789 CalcOffsetInChainGetStart(anchorDistance, contentSize, itemCount, chains[chainName], direction);
790 spaceSize = spaceSizeAndStart.first;
791 start += spaceSizeAndStart.second;
792 RecordOffsetInChain(start, spaceSize, chainName, direction);
793 chains[chainName].isCalculated = true;
794 return true;
795 }
796
Measure(LayoutWrapper * layoutWrapper)797 void RelativeContainerLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
798 {
799 CHECK_NULL_VOID(layoutWrapper);
800 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
801 CHECK_NULL_VOID(relativeContainerLayoutProperty);
802 versionGreatorOrEqualToEleven_ = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN);
803 if (layoutWrapper->GetAllChildrenWithBuild().empty()) {
804 UpdateSizeWhenChildrenEmpty(layoutWrapper);
805 return;
806 }
807 DetermineTopologicalOrder(layoutWrapper);
808 if (SystemProperties::GetDebugEnabled()) {
809 std::string result = "[";
810 for (const auto& nodeName : renderList_) {
811 result += nodeName + ",";
812 }
813 if (!renderList_.empty()) {
814 result = result.substr(0, result.length() - 1);
815 }
816 result += "]";
817 auto pattern = layoutWrapper->GetHostNode()->GetPattern<RelativeContainerPattern>();
818 CHECK_NULL_VOID(pattern);
819 pattern->SetTopologicalResult(result);
820 }
821
822 MeasureChild(layoutWrapper);
823 MeasureChainWeight(layoutWrapper);
824 const auto& calcLayoutConstraint = relativeContainerLayoutProperty->GetCalcLayoutConstraint();
825 CHECK_NULL_VOID(calcLayoutConstraint);
826 auto selfIdealSize = calcLayoutConstraint->selfIdealSize;
827 CHECK_NULL_VOID(selfIdealSize.has_value());
828 if ((selfIdealSize.value().Width().has_value() &&
829 selfIdealSize.value().Width().value().GetDimension().Unit() == DimensionUnit::AUTO) ||
830 (selfIdealSize.value().Height().has_value() &&
831 selfIdealSize.value().Height().value().GetDimension().Unit() == DimensionUnit::AUTO)) {
832 MeasureSelf(layoutWrapper);
833 }
834 AdjustOffsetRtl(layoutWrapper);
835 }
836
MeasureChainWeight(LayoutWrapper * layoutWrapper)837 void RelativeContainerLayoutAlgorithm::MeasureChainWeight(LayoutWrapper* layoutWrapper)
838 {
839 CHECK_NULL_VOID(isChainWeightMode_);
840 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
841 CHECK_NULL_VOID(relativeContainerLayoutProperty);
842 for (const auto& nodeName : renderList_) {
843 auto it = idNodeMap_.find(nodeName);
844 if (it == idNodeMap_.end()) {
845 continue;
846 }
847 auto childWrapper = it->second.layoutWrapper;
848 auto childConstraint = relativeContainerLayoutProperty->CreateChildConstraint();
849 if (!childWrapper->IsActive()||!childWrapper->GetLayoutProperty() ||
850 !childWrapper->GetLayoutProperty()->GetFlexItemProperty()) {
851 continue;
852 }
853 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
854 std::string chainName;
855 if (!flexItem->HasAlignRules()) {
856 continue;
857 }
858 if (!(IsNodeInHorizontalChain(nodeName, chainName) || IsNodeInVerticalChain(nodeName, chainName))) {
859 flexItem->ClearAlignValue();
860 CalcSizeParam(layoutWrapper, nodeName);
861 CalcOffsetParam(layoutWrapper, nodeName);
862 continue;
863 }
864 if (IsNodeInHorizontalChain(nodeName, chainName) && HasWeight(flexItem, LineDirection::HORIZONTAL)) {
865 CalcChainWeightSize(flexItem, childConstraint, chainName, LineDirection::HORIZONTAL);
866 }
867 if (IsNodeInVerticalChain(nodeName, chainName) && HasWeight(flexItem, LineDirection::VERTICAL)) {
868 CalcChainWeightSize(flexItem, childConstraint, chainName, LineDirection::VERTICAL);
869 }
870 childWrapper->Measure(childConstraint);
871 if (IsNodeInHorizontalChain(nodeName, chainName)) {
872 horizontalChains_[chainName].itemSize[nodeName] =
873 childWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
874 }
875 if (IsNodeInVerticalChain(nodeName, chainName)) {
876 verticalChains_[chainName].itemSize[nodeName] =
877 childWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
878 }
879 CalcOffsetParam(layoutWrapper, nodeName);
880 }
881 }
882
InitRemainingSpace(const std::string & chainName,LineDirection direction)883 void RelativeContainerLayoutAlgorithm::InitRemainingSpace(const std::string & chainName, LineDirection direction)
884 {
885 std::unordered_map<std::string, ChainParam> &chains =
886 (direction == LineDirection::HORIZONTAL) ? horizontalChains_ : verticalChains_;
887 CHECK_NULL_VOID(!chains[chainName].isWeightCalculated);
888 float start = 0.0f;
889 float end = 0.0f;
890 if (direction == LineDirection::HORIZONTAL) {
891 start = GetHorizontalAnchorValueByAlignRule(chains[chainName].anchorHead);
892 end = GetHorizontalAnchorValueByAlignRule(chains[chainName].anchorTail);
893 } else {
894 start = GetVerticalAnchorValueByAlignRule(chains[chainName].anchorHead);
895 end = GetVerticalAnchorValueByAlignRule(chains[chainName].anchorTail);
896 }
897 chains[chainName].remainingSpace += end - start;
898 chains[chainName].isWeightCalculated = true;
899 }
900
HasWeight(const std::unique_ptr<FlexItemProperty> & flexItem,LineDirection direction)901 bool RelativeContainerLayoutAlgorithm::HasWeight(
902 const std::unique_ptr<FlexItemProperty>& flexItem, LineDirection direction)
903 {
904 if (direction == LineDirection::HORIZONTAL) {
905 return GreatNotEqual(flexItem->GetChainWeight()->first.value_or(DEFAULT_WEIGHT), DEFAULT_WEIGHT);
906 } else {
907 return GreatNotEqual(flexItem->GetChainWeight()->second.value_or(DEFAULT_WEIGHT), DEFAULT_WEIGHT);
908 }
909 }
910
CalcChainWeightSize(const std::unique_ptr<FlexItemProperty> & flexItem,LayoutConstraintF & childConstraint,const std::string & chainName,LineDirection direction)911 void RelativeContainerLayoutAlgorithm::CalcChainWeightSize(
912 const std::unique_ptr<FlexItemProperty>& flexItem, LayoutConstraintF& childConstraint,
913 const std::string & chainName, LineDirection direction)
914 {
915 std::optional<float> childIdealSize;
916 std::unordered_map<std::string, ChainParam> &chains =
917 (direction == LineDirection::HORIZONTAL) ? horizontalChains_ : verticalChains_;
918 if (!chains[chainName].isWeightCalculated) {
919 InitRemainingSpace(chainName, direction);
920 }
921 if (chains[chainName].remainingSpace <= DEFAULT_WEIGHT) {
922 (direction == LineDirection::HORIZONTAL) ?
923 childConstraint.selfIdealSize.SetWidth(0.0f) : childConstraint.selfIdealSize.SetHeight(0.0f);
924 } else {
925 auto chainWeight = (direction == LineDirection::HORIZONTAL) ?
926 flexItem->GetChainWeight()->first.value_or(DEFAULT_WEIGHT) :
927 flexItem->GetChainWeight()->second.value_or(DEFAULT_WEIGHT);
928 childIdealSize = chains[chainName].remainingSpace * chainWeight / chains[chainName].totalChainWeight;
929 (direction == LineDirection::HORIZONTAL) ?
930 childConstraint.selfIdealSize.SetWidth(childIdealSize.value()) :
931 childConstraint.selfIdealSize.SetHeight(childIdealSize.value());
932 }
933 }
934
MeasureChild(LayoutWrapper * layoutWrapper)935 void RelativeContainerLayoutAlgorithm::MeasureChild(LayoutWrapper* layoutWrapper)
936 {
937 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
938 CHECK_NULL_VOID(relativeContainerLayoutProperty);
939 for (const auto& nodeName : renderList_) {
940 if (IsBarrier(nodeName)) {
941 MeasureBarrier(nodeName);
942 }
943 auto it = idNodeMap_.find(nodeName);
944 if (it == idNodeMap_.end()) {
945 continue;
946 }
947 auto childWrapper = it->second.layoutWrapper;
948 auto childConstraint = relativeContainerLayoutProperty->CreateChildConstraint();
949 if (!childWrapper->IsActive()) {
950 childWrapper->Measure(childConstraint);
951 continue;
952 }
953 if (!childWrapper->GetLayoutProperty() || !childWrapper->GetLayoutProperty()->GetFlexItemProperty()) {
954 childWrapper->Measure(childConstraint);
955 recordOffsetMap_[nodeName] = OffsetF(0.0f, 0.0f);
956 continue;
957 }
958 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
959 if (!flexItem->HasAlignRules()) {
960 childWrapper->Measure(childConstraint);
961 recordOffsetMap_[nodeName] = OffsetF(0.0f, 0.0f);
962 continue;
963 }
964 flexItem->ClearAlignValue();
965 auto alignRules = flexItem->GetAlignRulesValue();
966 auto frameNode = childWrapper->GetHostNode();
967 if (!alignRules.empty() && frameNode && frameNode->GetLayoutProperty()) {
968 // when child has alignRules and position, the position property do not work.
969 frameNode->GetLayoutProperty()->SetUsingPosition(false);
970 }
971 CalcSizeParam(layoutWrapper, nodeName);
972 CalcOffsetParam(layoutWrapper, nodeName);
973 }
974 }
975
MeasureSelf(LayoutWrapper * layoutWrapper)976 void RelativeContainerLayoutAlgorithm::MeasureSelf(LayoutWrapper* layoutWrapper)
977 {
978 CHECK_NULL_VOID(versionGreatorOrEqualToEleven_);
979 CHECK_NULL_VOID(layoutWrapper);
980 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
981 CHECK_NULL_VOID(relativeContainerLayoutProperty);
982 RectF relativeContainerRect(0, 0, 0, 0);
983 auto selfIdealSize = relativeContainerLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize;
984 for (const auto& nodeName : renderList_) {
985 auto it = idNodeMap_.find(nodeName);
986 if (it == idNodeMap_.end()) {
987 continue;
988 }
989 auto childWrapper = it->second.layoutWrapper;
990 if (childWrapper->GetLayoutProperty()->GetVisibility() == VisibleType::GONE) {
991 continue;
992 }
993 RectF tempRect(recordOffsetMap_[nodeName].GetX(), recordOffsetMap_[nodeName].GetY(),
994 childWrapper->GetGeometryNode()->GetMarginFrameSize().Width(),
995 childWrapper->GetGeometryNode()->GetMarginFrameSize().Height());
996 relativeContainerRect = relativeContainerRect.CombineRectT(tempRect);
997 }
998
999 relativeContainerRect =
1000 relativeContainerRect.IntersectRectT(RectF(0.0f, 0.0f, Infinity<float>(), Infinity<float>()));
1001 if (selfIdealSize->Width()->GetDimension().Unit() == DimensionUnit::AUTO && !isHorizontalRelyOnContainer_) {
1002 layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF(relativeContainerRect.Width() + padding_.Width(),
1003 layoutWrapper->GetGeometryNode()->GetFrameSize().Height()));
1004 }
1005 if (selfIdealSize->Height()->GetDimension().Unit() == DimensionUnit::AUTO && !isVerticalRelyOnContainer_) {
1006 layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF(layoutWrapper->GetGeometryNode()->GetFrameSize().Width(),
1007 relativeContainerRect.Height() + padding_.Height()));
1008 }
1009 }
1010
Layout(LayoutWrapper * layoutWrapper)1011 void RelativeContainerLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1012 {
1013 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
1014 CHECK_NULL_VOID(relativeContainerLayoutProperty);
1015 auto left = padding_.left.value_or(0);
1016 auto top = padding_.top.value_or(0);
1017 auto paddingOffset = OffsetF(left, top);
1018 auto textDirection = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection();
1019 for (auto&& childWrapper : layoutWrapper->GetAllChildrenWithBuild()) {
1020 auto nodeName = GetOrCreateNodeInspectorId(childWrapper->GetHostNode());
1021 if (!childWrapper->GetLayoutProperty()->GetFlexItemProperty() && (textDirection != TextDirection::RTL)) {
1022 childWrapper->GetGeometryNode()->SetMarginFrameOffset(OffsetF(0.0f, 0.0f) + paddingOffset);
1023 childWrapper->Layout();
1024 continue;
1025 }
1026 auto it = recordOffsetMap_.find(nodeName);
1027 if (it == recordOffsetMap_.end()) {
1028 continue;
1029 }
1030 if (it == recordOffsetMap_.end()) {
1031 childWrapper->GetGeometryNode()->SetMarginFrameOffset(OffsetF(0.0f, 0.0f) + paddingOffset);
1032 childWrapper->Layout();
1033 continue;
1034 }
1035 auto curOffset = it->second;
1036 childWrapper->GetGeometryNode()->SetMarginFrameOffset(curOffset + paddingOffset);
1037 childWrapper->Layout();
1038 }
1039 }
1040
CollectNodesById(LayoutWrapper * layoutWrapper)1041 void RelativeContainerLayoutAlgorithm::CollectNodesById(LayoutWrapper* layoutWrapper)
1042 {
1043 idNodeMap_.clear();
1044 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
1045 auto left = padding_.left.value_or(0);
1046 auto top = padding_.top.value_or(0);
1047 auto paddingOffset = OffsetF(left, top);
1048 const auto& childrenWrappers = layoutWrapper->GetAllChildrenWithBuild();
1049 for (const auto& childWrapper : childrenWrappers) {
1050 if (!childWrapper) {
1051 continue;
1052 }
1053 auto childHostNode = childWrapper->GetHostNode();
1054 if (!childHostNode) {
1055 continue;
1056 }
1057 childWrapper->SetActive();
1058 ChildMeasureWrapper childMeasureWrapper = { .layoutWrapper = childWrapper,
1059 .id = GetOrCreateNodeInspectorId(childHostNode) };
1060 idNodeMap_.emplace(childMeasureWrapper.id, childMeasureWrapper);
1061 }
1062 CalcGuideline(layoutWrapper);
1063 CalcBarrier(layoutWrapper);
1064 }
1065
GetDependencyRelationshipInChain(const std::string & anchor,const std::string & nodeName)1066 void RelativeContainerLayoutAlgorithm::GetDependencyRelationshipInChain(
1067 const std::string& anchor, const std::string& nodeName)
1068 {
1069 if (IsAnchorContainer(anchor) || IsGuideline(anchor)) {
1070 return;
1071 }
1072 if (IsBarrier(anchor) || idNodeMap_.find(anchor) != idNodeMap_.end()) {
1073 InsertToReliedOnMap(anchor, nodeName);
1074 }
1075 }
1076
GetDependencyRelationshipInBarrier()1077 void RelativeContainerLayoutAlgorithm::GetDependencyRelationshipInBarrier()
1078 {
1079 CHECK_NULL_VOID(versionGreatorOrEqualToEleven_);
1080 for (const auto& barrier : barriers_) {
1081 for (const auto& nodeName : barrier.second.second) {
1082 InsertToReliedOnMap(nodeName, barrier.first);
1083 }
1084 }
1085 }
1086
IsAlignRuleInChain(const AlignDirection & direction,const std::string & nodeName)1087 bool RelativeContainerLayoutAlgorithm::IsAlignRuleInChain(const AlignDirection& direction, const std::string& nodeName)
1088 {
1089 CHECK_NULL_RETURN(versionGreatorOrEqualToEleven_, false);
1090 std::string chainName;
1091 if ((direction == AlignDirection::LEFT || direction == AlignDirection::RIGHT) &&
1092 IsNodeInHorizontalChain(nodeName, chainName)) {
1093 GetDependencyRelationshipInChain(horizontalChains_[chainName].anchorHead.anchor, nodeName);
1094 GetDependencyRelationshipInChain(horizontalChains_[chainName].anchorTail.anchor, nodeName);
1095 return true;
1096 }
1097 if ((direction == AlignDirection::TOP || direction == AlignDirection::BOTTOM) &&
1098 IsNodeInVerticalChain(nodeName, chainName)) {
1099 GetDependencyRelationshipInChain(verticalChains_[chainName].anchorHead.anchor, nodeName);
1100 GetDependencyRelationshipInChain(verticalChains_[chainName].anchorTail.anchor, nodeName);
1101 return true;
1102 }
1103 return false;
1104 }
1105
InsertToReliedOnMap(const std::string & anchorName,const std::string & nodeName)1106 void RelativeContainerLayoutAlgorithm::InsertToReliedOnMap(const std::string& anchorName, const std::string& nodeName)
1107 {
1108 auto iter = reliedOnMap_.find(anchorName);
1109 if (iter == reliedOnMap_.end()) {
1110 std::set<std::string> reliedList;
1111 reliedList.insert(nodeName);
1112 reliedOnMap_[anchorName] = reliedList;
1113 return;
1114 }
1115 iter->second.insert(nodeName);
1116 }
1117
GetDependencyRelationship()1118 void RelativeContainerLayoutAlgorithm::GetDependencyRelationship()
1119 {
1120 for (const auto& mapItem : idNodeMap_) {
1121 auto childWrapper = mapItem.second.layoutWrapper;
1122 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
1123 auto childHostNode = childWrapper->GetHostNode();
1124 if (!flexItem || !flexItem->HasAlignRules()) {
1125 continue;
1126 }
1127 for (const auto& alignRule : flexItem->GetAlignRulesValue()) {
1128 if (IsAlignRuleInChain(alignRule.first, mapItem.first)) {
1129 continue;
1130 }
1131
1132 if (IsBarrier(alignRule.second.anchor)) {
1133 InsertToReliedOnMap(alignRule.second.anchor, mapItem.second.id);
1134 continue;
1135 }
1136
1137 if (IsAnchorContainer(alignRule.second.anchor) || IsGuideline(alignRule.second.anchor)) {
1138 if (static_cast<uint32_t>(alignRule.first) < HORIZONTAL_DIRECTION_RANGE) {
1139 isHorizontalRelyOnContainer_ = true;
1140 } else if (static_cast<uint32_t>(alignRule.first) < VERTICAL_DIRECTION_RANGE) {
1141 isVerticalRelyOnContainer_ = true;
1142 }
1143 continue;
1144 }
1145 auto it = idNodeMap_.find(alignRule.second.anchor);
1146 if (it == idNodeMap_.end()) {
1147 continue;
1148 }
1149
1150 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1151 auto anchorChildWrapper = it->second.layoutWrapper;
1152 auto anchorChildLayoutProp = anchorChildWrapper->GetLayoutProperty();
1153 auto anchorChildVisibility = anchorChildLayoutProp->GetVisibility();
1154 if (anchorChildVisibility == VisibleType::GONE) {
1155 childWrapper->SetActive(false);
1156 }
1157 }
1158 // if a is the anchor of b, then reliedOnMap should place <a, [b]> for the first appearance
1159 // of key a. Otherwise b will be inserted into the existing value list
1160 InsertToReliedOnMap(alignRule.second.anchor, mapItem.second.id);
1161 }
1162 }
1163 GetDependencyRelationshipInBarrier();
1164 }
1165
PreTopologicalLoopDetectionGetAnchorSet(const std::string & nodeName,const AlignRulesItem & alignRulesItem,std::set<std::string> & anchorSet)1166 void RelativeContainerLayoutAlgorithm::PreTopologicalLoopDetectionGetAnchorSet(
1167 const std::string& nodeName, const AlignRulesItem& alignRulesItem, std::set<std::string>& anchorSet)
1168 {
1169 for (const auto& alignRule : alignRulesItem) {
1170 std::string anchor = alignRule.second.anchor;
1171 std::string chainName;
1172 if (IsNodeInHorizontalChain(nodeName, chainName)) {
1173 if (alignRule.first == AlignDirection::LEFT) {
1174 anchor = horizontalChains_[chainName].anchorHead.anchor;
1175 } else if (alignRule.first == AlignDirection::RIGHT) {
1176 anchor = horizontalChains_[chainName].anchorTail.anchor;
1177 }
1178 }
1179 if (IsNodeInVerticalChain(nodeName, chainName)) {
1180 if (alignRule.first == AlignDirection::TOP) {
1181 anchor = verticalChains_[chainName].anchorHead.anchor;
1182 } else if (alignRule.first == AlignDirection::BOTTOM) {
1183 anchor = verticalChains_[chainName].anchorTail.anchor;
1184 }
1185 }
1186
1187 if (IsBarrier(anchor)) {
1188 anchorSet.insert(anchor);
1189 continue;
1190 }
1191
1192 if (IsAnchorContainer(anchor) || IsGuideline(anchor) || idNodeMap_.find(anchor) == idNodeMap_.end()) {
1193 continue;
1194 }
1195 anchorSet.insert(anchor);
1196 }
1197 }
1198
PreTopologicalLoopDetection()1199 bool RelativeContainerLayoutAlgorithm::PreTopologicalLoopDetection()
1200 {
1201 std::queue<std::string> visitedNode;
1202 std::queue<std::string> layoutQueue;
1203
1204 for (const auto& mapItem : idNodeMap_) {
1205 auto childWrapper = mapItem.second.layoutWrapper;
1206 auto childHostNode = childWrapper->GetHostNode();
1207 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
1208 if (!flexItem || !flexItem->HasAlignRules()) {
1209 visitedNode.push(mapItem.first);
1210 layoutQueue.push(mapItem.second.id);
1211 continue;
1212 }
1213 std::set<std::string> anchorSet;
1214 PreTopologicalLoopDetectionGetAnchorSet(mapItem.first, flexItem->GetAlignRulesValue(), anchorSet);
1215 incomingDegreeMap_[mapItem.second.id] = anchorSet.size();
1216 if (incomingDegreeMap_[mapItem.second.id] == 0) {
1217 layoutQueue.push(mapItem.second.id);
1218 }
1219 }
1220
1221 for (const auto& barrier : barriers_) {
1222 std::set<std::string> anchorSet;
1223 for (const auto& nodeName : barrier.second.second) {
1224 if (IsBarrier(nodeName)) {
1225 anchorSet.insert(nodeName);
1226 continue;
1227 }
1228 if (IsGuideline(nodeName) || idNodeMap_.find(nodeName) == idNodeMap_.end()) {
1229 continue;
1230 }
1231 anchorSet.insert(nodeName);
1232 }
1233 incomingDegreeMap_[barrier.first] = anchorSet.size();
1234 if (incomingDegreeMap_[barrier.first] == 0) {
1235 layoutQueue.push(barrier.first);
1236 }
1237 }
1238
1239 std::map<std::string, uint32_t> incomingDegreeMapCopy;
1240 incomingDegreeMapCopy.insert(incomingDegreeMap_.begin(), incomingDegreeMap_.end());
1241 while (!layoutQueue.empty()) {
1242 auto currentNodeInspectorId = layoutQueue.front();
1243 layoutQueue.pop();
1244 auto reliedSet = reliedOnMap_[currentNodeInspectorId];
1245 for (const auto& node : reliedSet) {
1246 auto it = incomingDegreeMapCopy.find(node);
1247 if (it == incomingDegreeMapCopy.end() || IsAnchorContainer(node)) {
1248 continue;
1249 }
1250 it->second -= 1;
1251 if (it->second == 0) {
1252 layoutQueue.push(node);
1253 }
1254 }
1255 incomingDegreeMapCopy.erase(currentNodeInspectorId);
1256 visitedNode.push(currentNodeInspectorId);
1257 }
1258 if (!incomingDegreeMapCopy.empty()) {
1259 std::string loopDependentNodes;
1260 for (const auto& node : incomingDegreeMapCopy) {
1261 loopDependentNodes += node.first + ",";
1262 }
1263 return false;
1264 }
1265 return true;
1266 }
1267
TopologicalSort(std::list<std::string> & renderList)1268 void RelativeContainerLayoutAlgorithm::TopologicalSort(std::list<std::string>& renderList)
1269 {
1270 std::queue<std::string> layoutQueue;
1271 for (const auto& mapItem : idNodeMap_) {
1272 auto childWrapper = mapItem.second.layoutWrapper;
1273 auto childHostNode = childWrapper->GetHostNode();
1274 const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty();
1275 if (!flexItem || incomingDegreeMap_[mapItem.second.id] == 0) {
1276 layoutQueue.push(mapItem.second.id);
1277 }
1278 }
1279 while (!layoutQueue.empty()) {
1280 auto currentNodeInspectorId = layoutQueue.front();
1281 layoutQueue.pop();
1282 // reduce incoming degree of nodes relied on currentNode
1283 auto reliedList = reliedOnMap_[currentNodeInspectorId];
1284 for (const auto& node : reliedList) {
1285 auto it = incomingDegreeMap_.find(node);
1286 if (it == incomingDegreeMap_.end() || IsAnchorContainer(node)) {
1287 continue;
1288 }
1289 it->second -= 1;
1290 if (it->second == 0) {
1291 layoutQueue.push(node);
1292 }
1293 }
1294 renderList.emplace_back(currentNodeInspectorId);
1295 }
1296 }
1297
CalcSizeParam(LayoutWrapper * layoutWrapper,const std::string & nodeName)1298 void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrapper, const std::string& nodeName)
1299 {
1300 std::string chainName;
1301 auto it = idNodeMap_.find(nodeName);
1302 if (it == idNodeMap_.end()) {
1303 return;
1304 }
1305 auto childWrapper = it->second.layoutWrapper;
1306 auto childLayoutProperty = childWrapper->GetLayoutProperty();
1307 CHECK_NULL_VOID(childLayoutProperty);
1308 CHECK_NULL_VOID(childWrapper->GetLayoutProperty()->GetFlexItemProperty());
1309 CHECK_NULL_VOID(childWrapper->GetLayoutProperty()->GetFlexItemProperty()->HasAlignRules());
1310 auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty();
1311 CHECK_NULL_VOID(relativeContainerLayoutProperty);
1312 auto childConstraint = relativeContainerLayoutProperty->CreateChildConstraint();
1313 auto alignRules = childWrapper->GetLayoutProperty()->GetFlexItemProperty()->GetAlignRulesValue();
1314 const auto& calcConstraint = childLayoutProperty->GetCalcLayoutConstraint();
1315 bool horizontalHasIdealSize = false;
1316 bool verticalHasIdealSize = false;
1317 if (calcConstraint && calcConstraint->selfIdealSize.has_value() &&
1318 calcConstraint->selfIdealSize.value().Width().has_value()) {
1319 horizontalHasIdealSize = true;
1320 }
1321 if (calcConstraint && calcConstraint->selfIdealSize.has_value() &&
1322 calcConstraint->selfIdealSize.value().Height().has_value()) {
1323 verticalHasIdealSize = true;
1324 }
1325 horizontalHasIdealSize = horizontalHasIdealSize && versionGreatorOrEqualToEleven_;
1326 verticalHasIdealSize = verticalHasIdealSize && versionGreatorOrEqualToEleven_;
1327 const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
1328 std::optional<float> childIdealWidth;
1329 std::optional<float> childIdealHeight;
1330
1331 for (const auto& alignRule : alignRules) {
1332 if (!IsAnchorLegal(alignRule.second.anchor)) {
1333 continue;
1334 }
1335 if (static_cast<uint32_t>(alignRule.first) < HORIZONTAL_DIRECTION_RANGE) {
1336 if (!childFlexItemProperty->GetTwoHorizontalDirectionAligned()) {
1337 CalcHorizontalLayoutParam(alignRule.first, alignRule.second, layoutWrapper, nodeName);
1338 }
1339 } else {
1340 if (!childFlexItemProperty->GetTwoVerticalDirectionAligned()) {
1341 CalcVerticalLayoutParam(alignRule.first, alignRule.second, layoutWrapper, nodeName);
1342 }
1343 }
1344 }
1345 if (childFlexItemProperty->GetTwoHorizontalDirectionAligned()) {
1346 auto checkAlign = AlignDirection::MIDDLE;
1347 if (childFlexItemProperty->GetAligned(checkAlign)) {
1348 auto middleValue = childFlexItemProperty->GetAlignValue(checkAlign);
1349 checkAlign = AlignDirection::LEFT;
1350 if (childFlexItemProperty->GetAligned(checkAlign)) {
1351 childIdealWidth = 2.0f * std::max(middleValue - childFlexItemProperty->GetAlignValue(checkAlign), 0.0f);
1352 } else {
1353 checkAlign = AlignDirection::RIGHT;
1354 childIdealWidth = 2.0f * std::max(childFlexItemProperty->GetAlignValue(checkAlign) - middleValue, 0.0f);
1355 }
1356 } else {
1357 childIdealWidth = std::max(childFlexItemProperty->GetAlignValue(AlignDirection::RIGHT) -
1358 childFlexItemProperty->GetAlignValue(AlignDirection::LEFT),
1359 0.0f);
1360 }
1361 if (childIdealWidth.has_value() && LessOrEqual(childIdealWidth.value(), 0.0f) &&
1362 !IsNodeInHorizontalChain(nodeName, chainName)) {
1363 childConstraint.selfIdealSize.SetWidth(0.0f);
1364 childConstraint.selfIdealSize.SetHeight(0.0f);
1365 childWrapper->Measure(childConstraint);
1366 RecordSizeInChain(nodeName);
1367 return;
1368 }
1369 }
1370 if (childFlexItemProperty->GetTwoVerticalDirectionAligned()) {
1371 auto checkAlign = AlignDirection::CENTER;
1372 if (childFlexItemProperty->GetAligned(checkAlign)) {
1373 auto centerValue = childFlexItemProperty->GetAlignValue(checkAlign);
1374 checkAlign = AlignDirection::TOP;
1375 if (childFlexItemProperty->GetAligned(checkAlign)) {
1376 childIdealHeight =
1377 2.0f * std::max(centerValue - childFlexItemProperty->GetAlignValue(checkAlign), 0.0f);
1378 } else {
1379 checkAlign = AlignDirection::BOTTOM;
1380 childIdealHeight =
1381 2.0f * std::max(childFlexItemProperty->GetAlignValue(checkAlign) - centerValue, 0.0f);
1382 }
1383 } else {
1384 childIdealHeight = std::max(childFlexItemProperty->GetAlignValue(AlignDirection::BOTTOM) -
1385 childFlexItemProperty->GetAlignValue(AlignDirection::TOP),
1386 0.0f);
1387 }
1388 if (childIdealHeight.has_value() && LessOrEqual(childIdealHeight.value(), 0.0f) &&
1389 !IsNodeInVerticalChain(nodeName, chainName)) {
1390 childConstraint.selfIdealSize.SetWidth(0.0f);
1391 childConstraint.selfIdealSize.SetHeight(0.0f);
1392 childWrapper->Measure(childConstraint);
1393 RecordSizeInChain(nodeName);
1394 return;
1395 }
1396 }
1397
1398 // for api 11 or larger, alignRules will not effect child component size as described in doc
1399 if (horizontalHasIdealSize && verticalHasIdealSize) {
1400 childWrapper->Measure(childConstraint);
1401 RecordSizeInChain(nodeName);
1402 return;
1403 }
1404
1405 if (childIdealWidth.has_value() && !horizontalHasIdealSize && !IsNodeInHorizontalChain(nodeName, chainName)) {
1406 childConstraint.selfIdealSize.SetWidth(childIdealWidth.value());
1407 }
1408 if (childIdealHeight.has_value() && !verticalHasIdealSize && !IsNodeInVerticalChain(nodeName, chainName)) {
1409 childConstraint.selfIdealSize.SetHeight(childIdealHeight.value());
1410 }
1411 childWrapper->Measure(childConstraint);
1412 RecordSizeInChain(nodeName);
1413 }
1414
CalcOffsetParam(LayoutWrapper * layoutWrapper,const std::string & nodeName)1415 void RelativeContainerLayoutAlgorithm::CalcOffsetParam(LayoutWrapper* layoutWrapper, const std::string& nodeName)
1416 {
1417 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
1418 auto alignRules = childWrapper->GetLayoutProperty()->GetFlexItemProperty()->GetAlignRulesValue();
1419 float offsetX = 0.0f;
1420 bool offsetXCalculated = false;
1421 float offsetY = 0.0f;
1422 bool offsetYCalculated = false;
1423 std::string chainName;
1424 if (IsNodeInHorizontalChain(nodeName, chainName)) {
1425 if (CalcOffsetInChain(chainName, LineDirection::HORIZONTAL)) {
1426 offsetX = recordOffsetMap_[nodeName].GetX();
1427 }
1428 offsetXCalculated = true;
1429 }
1430 if (IsNodeInVerticalChain(nodeName, chainName)) {
1431 if (CalcOffsetInChain(chainName, LineDirection::VERTICAL)) {
1432 offsetY = recordOffsetMap_[nodeName].GetY();
1433 }
1434 offsetYCalculated = true;
1435 }
1436
1437 for (const auto& alignRule : alignRules) {
1438 if (!IsAnchorLegal(alignRule.second.anchor)) {
1439 continue;
1440 }
1441 if (static_cast<uint32_t>(alignRule.first) < HORIZONTAL_DIRECTION_RANGE) {
1442 if (!offsetXCalculated) {
1443 offsetX = CalcHorizontalOffset(
1444 alignRule.first, alignRule.second, containerSizeWithoutPaddingBorder_.Width(), nodeName);
1445 offsetXCalculated = true;
1446 }
1447 } else {
1448 if (!offsetYCalculated) {
1449 offsetY = CalcVerticalOffset(
1450 alignRule.first, alignRule.second, containerSizeWithoutPaddingBorder_.Height(), nodeName);
1451 offsetYCalculated = true;
1452 }
1453 }
1454 }
1455 recordOffsetMap_[nodeName] = OffsetF(offsetX, offsetY) + CalcBias(nodeName);
1456 }
1457
IsValidBias(float bias)1458 bool RelativeContainerLayoutAlgorithm::IsValidBias(float bias)
1459 {
1460 return GreatOrEqual(bias, 0.0f);
1461 }
1462
CalcBiasTowDirection(std::pair<TwoAlignedValues,TwoAlignedValues> & alignedValuesOnTwoDirections,ChildIdealSize & childIdealSize,BiasPair & biasPair,float & horizontalOffset,float & verticalOffset)1463 void RelativeContainerLayoutAlgorithm::CalcBiasTowDirection(
1464 std::pair<TwoAlignedValues, TwoAlignedValues>& alignedValuesOnTwoDirections, ChildIdealSize& childIdealSize,
1465 BiasPair& biasPair, float& horizontalOffset, float& verticalOffset)
1466 {
1467 auto horizontalValues = alignedValuesOnTwoDirections.first;
1468 auto verticalValues = alignedValuesOnTwoDirections.second;
1469 auto biasX = biasPair.first;
1470 auto biasY = biasPair.second;
1471 if (horizontalValues.first.has_value() && horizontalValues.second.has_value() && childIdealSize.first.has_value()) {
1472 auto alignDiff = std::abs(horizontalValues.first.value() - horizontalValues.second.value());
1473 horizontalOffset = (alignDiff - childIdealSize.first.value()) * (IsValidBias(biasX) ? biasX : DEFAULT_BIAS);
1474 }
1475 if (verticalValues.first.has_value() && verticalValues.second.has_value() && childIdealSize.second.has_value()) {
1476 auto alignDiff = std::abs(verticalValues.first.value() - verticalValues.second.value());
1477 verticalOffset = (alignDiff - childIdealSize.second.value()) * (IsValidBias(biasY) ? biasY : DEFAULT_BIAS);
1478 }
1479 }
1480
CalcBias(const std::string & nodeName)1481 OffsetF RelativeContainerLayoutAlgorithm::CalcBias(const std::string& nodeName)
1482 {
1483 OffsetF emptyBiasOffset;
1484 std::string chainName;
1485 CHECK_NULL_RETURN(versionGreatorOrEqualToEleven_, emptyBiasOffset);
1486 if (IsNodeInHorizontalChain(nodeName, chainName) && IsNodeInVerticalChain(nodeName, chainName)) {
1487 return emptyBiasOffset;
1488 }
1489 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
1490 auto layoutProperty = childWrapper->GetLayoutProperty();
1491 CHECK_NULL_RETURN(layoutProperty, emptyBiasOffset);
1492 const auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
1493 CHECK_NULL_RETURN(flexItemProperty, emptyBiasOffset);
1494 CHECK_NULL_RETURN(flexItemProperty->HasBias(), emptyBiasOffset);
1495 auto biasPair = flexItemProperty->GetBiasValue();
1496 CHECK_NULL_RETURN(flexItemProperty->HasAlignRules(), emptyBiasOffset);
1497 auto alignRules = flexItemProperty->GetAlignRulesValue();
1498 const auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1499 ChildIdealSize childIdealSize;
1500 if (calcLayoutConstraint && calcLayoutConstraint->selfIdealSize.has_value() &&
1501 calcLayoutConstraint->selfIdealSize.value().Width().has_value()) {
1502 childIdealSize.first = childWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
1503 }
1504
1505 if (calcLayoutConstraint && calcLayoutConstraint->selfIdealSize.has_value() &&
1506 calcLayoutConstraint->selfIdealSize.value().Height().has_value()) {
1507 childIdealSize.second = childWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
1508 }
1509 if (!childIdealSize.first.has_value() && !childIdealSize.second.has_value()) {
1510 return OffsetF(0.0f, 0.0f);
1511 }
1512 auto alignedValuesOnTwoDirections = GetFirstTwoAlignValues(childWrapper, flexItemProperty, childIdealSize);
1513 auto horizontalOffset = 0.0f;
1514 auto verticalOffset = 0.0f;
1515 CalcBiasTowDirection(alignedValuesOnTwoDirections, childIdealSize, biasPair, horizontalOffset, verticalOffset);
1516 horizontalOffset = (IsNodeInHorizontalChain(nodeName, chainName)) ? 0.0f : horizontalOffset;
1517 verticalOffset = ((IsNodeInVerticalChain(nodeName, chainName))) ? 0.0f : verticalOffset;
1518 return OffsetF(horizontalOffset, verticalOffset);
1519 }
1520
GetFirstTwoAlignValues(const RefPtr<LayoutWrapper> & childWrapper,const std::unique_ptr<FlexItemProperty> & flexItemProperty,const ChildIdealSize & childIdealSize)1521 std::pair<TwoAlignedValues, TwoAlignedValues> RelativeContainerLayoutAlgorithm::GetFirstTwoAlignValues(
1522 const RefPtr<LayoutWrapper>& childWrapper, const std::unique_ptr<FlexItemProperty>& flexItemProperty,
1523 const ChildIdealSize& childIdealSize)
1524 {
1525 CHECK_NULL_RETURN(flexItemProperty, {});
1526 CHECK_NULL_RETURN(flexItemProperty->HasAlignRules(), {});
1527 auto alignRules = flexItemProperty->GetAlignRulesValue();
1528 TwoAlignedValues horizontalValues;
1529 TwoAlignedValues verticalValues;
1530 for (const auto& alignRule : alignRules) {
1531 bool horizontalCheckTwoSidesAligned = horizontalValues.first.has_value() && horizontalValues.second.has_value();
1532 bool verticalCheckTwoSidesAligned = verticalValues.second.has_value() && verticalValues.second.has_value();
1533 if (horizontalCheckTwoSidesAligned && verticalCheckTwoSidesAligned) {
1534 break;
1535 }
1536 if (!IsAnchorLegal(alignRule.second.anchor)) {
1537 continue;
1538 }
1539 if (static_cast<uint32_t>(alignRule.first) < HORIZONTAL_DIRECTION_RANGE && !horizontalCheckTwoSidesAligned &&
1540 childIdealSize.first.has_value()) {
1541 UpdateTwoAlignValues(horizontalValues, alignRule.second, LineDirection::HORIZONTAL);
1542 } else if (static_cast<uint32_t>(alignRule.first) >= HORIZONTAL_DIRECTION_RANGE &&
1543 !verticalCheckTwoSidesAligned && childIdealSize.second.has_value()) {
1544 UpdateTwoAlignValues(verticalValues, alignRule.second, LineDirection::VERTICAL);
1545 }
1546 }
1547 return { horizontalValues, verticalValues };
1548 }
1549
CalcHorizontalLayoutParam(AlignDirection alignDirection,const AlignRule & alignRule,LayoutWrapper * layoutWrapper,const std::string & nodeName)1550 void RelativeContainerLayoutAlgorithm::CalcHorizontalLayoutParam(AlignDirection alignDirection,
1551 const AlignRule& alignRule, LayoutWrapper* layoutWrapper, const std::string& nodeName)
1552 {
1553 auto it = idNodeMap_.find(nodeName);
1554 if (it == idNodeMap_.end()) {
1555 return;
1556 }
1557 auto childWrapper = it->second.layoutWrapper;
1558 auto childLayoutProperty = childWrapper->GetLayoutProperty();
1559 CHECK_NULL_VOID(childLayoutProperty);
1560 const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
1561 if (IsGuideline(alignRule.anchor)) {
1562 if (guidelines_[alignRule.anchor].first == LineDirection::VERTICAL) {
1563 childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetX());
1564 } else {
1565 childFlexItemProperty->SetAlignValue(alignDirection, 0.0f);
1566 }
1567 return;
1568 }
1569
1570 if (IsBarrier(alignRule.anchor)) {
1571 if (barriers_[alignRule.anchor].first == BarrierDirection::LEFT ||
1572 barriers_[alignRule.anchor].first == BarrierDirection::RIGHT) {
1573 childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetX());
1574 } else {
1575 childFlexItemProperty->SetAlignValue(alignDirection, 0.0f);
1576 }
1577 return;
1578 }
1579
1580 switch (alignRule.horizontal) {
1581 case HorizontalAlign::START:
1582 childFlexItemProperty->SetAlignValue(
1583 alignDirection, IsAnchorContainer(alignRule.anchor) ? 0.0f : recordOffsetMap_[alignRule.anchor].GetX());
1584 break;
1585 case HorizontalAlign::CENTER:
1586 childFlexItemProperty->SetAlignValue(alignDirection,
1587 IsAnchorContainer(alignRule.anchor)
1588 ? containerSizeWithoutPaddingBorder_.Width() * HALF_MULTIPLY
1589 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Width() *
1590 HALF_MULTIPLY +
1591 recordOffsetMap_[alignRule.anchor].GetX());
1592 break;
1593 case HorizontalAlign::END:
1594 childFlexItemProperty->SetAlignValue(alignDirection,
1595 IsAnchorContainer(alignRule.anchor)
1596 ? containerSizeWithoutPaddingBorder_.Width()
1597 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Width() +
1598 recordOffsetMap_[alignRule.anchor].GetX());
1599 break;
1600 default:
1601 break;
1602 }
1603 }
1604
CalcVerticalLayoutParam(AlignDirection alignDirection,const AlignRule & alignRule,LayoutWrapper * layoutWrapper,const std::string & nodeName)1605 void RelativeContainerLayoutAlgorithm::CalcVerticalLayoutParam(AlignDirection alignDirection,
1606 const AlignRule& alignRule, LayoutWrapper* layoutWrapper, const std::string& nodeName)
1607 {
1608 auto it = idNodeMap_.find(nodeName);
1609 if (it == idNodeMap_.end()) {
1610 return;
1611 }
1612 auto childWrapper = it->second.layoutWrapper;
1613 auto childLayoutProperty = childWrapper->GetLayoutProperty();
1614 CHECK_NULL_VOID(childLayoutProperty);
1615 const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
1616 if (IsGuideline(alignRule.anchor)) {
1617 if (guidelines_[alignRule.anchor].first == LineDirection::HORIZONTAL) {
1618 childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetY());
1619 } else {
1620 childFlexItemProperty->SetAlignValue(alignDirection, 0.0f);
1621 }
1622 return;
1623 }
1624
1625 if (IsBarrier(alignRule.anchor)) {
1626 if (barriers_[alignRule.anchor].first == BarrierDirection::TOP ||
1627 barriers_[alignRule.anchor].first == BarrierDirection::BOTTOM) {
1628 childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetY());
1629 } else {
1630 childFlexItemProperty->SetAlignValue(alignDirection, 0.0f);
1631 }
1632 return;
1633 }
1634
1635 switch (alignRule.vertical) {
1636 case VerticalAlign::TOP:
1637 childFlexItemProperty->SetAlignValue(
1638 alignDirection, IsAnchorContainer(alignRule.anchor) ? 0.0f : recordOffsetMap_[alignRule.anchor].GetY());
1639 break;
1640 case VerticalAlign::CENTER:
1641 childFlexItemProperty->SetAlignValue(alignDirection,
1642 IsAnchorContainer(alignRule.anchor)
1643 ? containerSizeWithoutPaddingBorder_.Height() * HALF_MULTIPLY
1644 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Height() *
1645 HALF_MULTIPLY +
1646 recordOffsetMap_[alignRule.anchor].GetY());
1647 break;
1648 case VerticalAlign::BOTTOM:
1649 childFlexItemProperty->SetAlignValue(alignDirection,
1650 IsAnchorContainer(alignRule.anchor)
1651 ? containerSizeWithoutPaddingBorder_.Height()
1652 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Height() +
1653 recordOffsetMap_[alignRule.anchor].GetY());
1654 break;
1655 default:
1656 break;
1657 }
1658 }
1659
CalcHorizontalOffsetAlignLeft(const HorizontalAlign & alignRule,float & anchorWidth)1660 float RelativeContainerLayoutAlgorithm::CalcHorizontalOffsetAlignLeft(
1661 const HorizontalAlign& alignRule, float& anchorWidth)
1662 {
1663 float offsetX = 0.0f;
1664 switch (alignRule) {
1665 case HorizontalAlign::START:
1666 offsetX = 0.0f;
1667 break;
1668 case HorizontalAlign::CENTER:
1669 offsetX = anchorWidth * HALF_MULTIPLY;
1670 break;
1671 case HorizontalAlign::END:
1672 offsetX = anchorWidth;
1673 break;
1674 default:
1675 break;
1676 }
1677 return offsetX;
1678 }
1679
CalcHorizontalOffsetAlignMiddle(const HorizontalAlign & alignRule,float & anchorWidth,float & flexItemWidth)1680 float RelativeContainerLayoutAlgorithm::CalcHorizontalOffsetAlignMiddle(
1681 const HorizontalAlign& alignRule, float& anchorWidth, float& flexItemWidth)
1682 {
1683 float offsetX = 0.0f;
1684 switch (alignRule) {
1685 case HorizontalAlign::START:
1686 offsetX = (-1) * flexItemWidth * HALF_MULTIPLY;
1687 break;
1688 case HorizontalAlign::CENTER:
1689 offsetX = (anchorWidth - flexItemWidth) * HALF_MULTIPLY;
1690 break;
1691 case HorizontalAlign::END:
1692 offsetX = anchorWidth - flexItemWidth * HALF_MULTIPLY;
1693 break;
1694 default:
1695 break;
1696 }
1697 return offsetX;
1698 }
1699
CalcHorizontalOffsetAlignRight(const HorizontalAlign & alignRule,float & anchorWidth,float & flexItemWidth)1700 float RelativeContainerLayoutAlgorithm::CalcHorizontalOffsetAlignRight(
1701 const HorizontalAlign& alignRule, float& anchorWidth, float& flexItemWidth)
1702 {
1703 float offsetX = 0.0f;
1704 switch (alignRule) {
1705 case HorizontalAlign::START:
1706 offsetX = (-1) * flexItemWidth;
1707 break;
1708 case HorizontalAlign::CENTER:
1709 offsetX = anchorWidth * HALF_MULTIPLY - flexItemWidth;
1710 break;
1711 case HorizontalAlign::END:
1712 offsetX = anchorWidth - flexItemWidth;
1713 break;
1714 default:
1715 break;
1716 }
1717 return offsetX;
1718 }
1719
CalcHorizontalOffset(AlignDirection alignDirection,const AlignRule & alignRule,float containerWidth,const std::string & nodeName)1720 float RelativeContainerLayoutAlgorithm::CalcHorizontalOffset(
1721 AlignDirection alignDirection, const AlignRule& alignRule, float containerWidth, const std::string& nodeName)
1722 {
1723 float offsetX = 0.0f;
1724 CHECK_NULL_RETURN(idNodeMap_.find(nodeName) != idNodeMap_.end(), offsetX);
1725 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
1726 bool anchorIsContainer = IsAnchorContainer(alignRule.anchor);
1727 float flexItemWidth = childWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
1728 float anchorWidth;
1729 if (!versionGreatorOrEqualToEleven_) {
1730 anchorWidth = anchorIsContainer
1731 ? containerWidth
1732 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
1733 } else {
1734 if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) {
1735 anchorWidth = 0;
1736 } else if (anchorIsContainer) {
1737 anchorWidth = containerWidth;
1738 } else {
1739 anchorWidth = idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
1740 }
1741 }
1742 std::optional<float> marginLeft;
1743 if (!anchorIsContainer && !IsGuideline(alignRule.anchor) && !IsBarrier(alignRule.anchor)) {
1744 auto anchorWrapper = idNodeMap_[alignRule.anchor].layoutWrapper;
1745 if (anchorWrapper->GetGeometryNode()->GetMargin()) {
1746 marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left;
1747 }
1748 }
1749 switch (alignDirection) {
1750 case AlignDirection::LEFT:
1751 offsetX = CalcHorizontalOffsetAlignLeft(alignRule.horizontal, anchorWidth);
1752 break;
1753 case AlignDirection::MIDDLE:
1754 offsetX = CalcHorizontalOffsetAlignMiddle(alignRule.horizontal, anchorWidth, flexItemWidth);
1755 break;
1756 case AlignDirection::RIGHT:
1757 offsetX = CalcHorizontalOffsetAlignRight(alignRule.horizontal, anchorWidth, flexItemWidth);
1758 break;
1759 default:
1760 break;
1761 }
1762
1763 if (!versionGreatorOrEqualToEleven_) {
1764 offsetX += anchorIsContainer ? 0.0f : recordOffsetMap_[alignRule.anchor].GetX();
1765 } else {
1766 offsetX += anchorIsContainer ? 0.0f : recordOffsetMap_[alignRule.anchor].GetX() + marginLeft.value_or(0);
1767 }
1768 return offsetX;
1769 }
1770
CalcVerticalOffsetAlignTop(const VerticalAlign & alignRule,float & anchorHeight)1771 float RelativeContainerLayoutAlgorithm::CalcVerticalOffsetAlignTop(const VerticalAlign& alignRule, float& anchorHeight)
1772 {
1773 float offsetY = 0.0f;
1774 switch (alignRule) {
1775 case VerticalAlign::TOP:
1776 offsetY = 0.0f;
1777 break;
1778 case VerticalAlign::CENTER:
1779 offsetY = anchorHeight * HALF_MULTIPLY;
1780 break;
1781 case VerticalAlign::BOTTOM:
1782 offsetY = anchorHeight;
1783 break;
1784 default:
1785 break;
1786 }
1787 return offsetY;
1788 }
1789
CalcVerticalOffsetAlignCenter(const VerticalAlign & alignRule,float & anchorHeight,float & flexItemHeight)1790 float RelativeContainerLayoutAlgorithm::CalcVerticalOffsetAlignCenter(
1791 const VerticalAlign& alignRule, float& anchorHeight, float& flexItemHeight)
1792 {
1793 float offsetY = 0.0f;
1794 switch (alignRule) {
1795 case VerticalAlign::TOP:
1796 offsetY = (-1) * flexItemHeight * HALF_MULTIPLY;
1797 break;
1798 case VerticalAlign::CENTER:
1799 offsetY = (anchorHeight - flexItemHeight) * HALF_MULTIPLY;
1800 break;
1801 case VerticalAlign::BOTTOM:
1802 offsetY = anchorHeight - flexItemHeight * HALF_MULTIPLY;
1803 break;
1804 default:
1805 break;
1806 }
1807 return offsetY;
1808 }
1809
CalcVerticalOffsetAlignBottom(const VerticalAlign & alignRule,float & anchorHeight,float & flexItemHeight)1810 float RelativeContainerLayoutAlgorithm::CalcVerticalOffsetAlignBottom(
1811 const VerticalAlign& alignRule, float& anchorHeight, float& flexItemHeight)
1812 {
1813 float offsetY = 0.0f;
1814 switch (alignRule) {
1815 case VerticalAlign::TOP:
1816 offsetY = (-1) * flexItemHeight;
1817 break;
1818 case VerticalAlign::CENTER:
1819 offsetY = anchorHeight * HALF_MULTIPLY - flexItemHeight;
1820 break;
1821 case VerticalAlign::BOTTOM:
1822 offsetY = anchorHeight - flexItemHeight;
1823 break;
1824 default:
1825 break;
1826 }
1827 return offsetY;
1828 }
1829
CalcVerticalOffset(AlignDirection alignDirection,const AlignRule & alignRule,float containerHeight,const std::string & nodeName)1830 float RelativeContainerLayoutAlgorithm::CalcVerticalOffset(
1831 AlignDirection alignDirection, const AlignRule& alignRule, float containerHeight, const std::string& nodeName)
1832 {
1833 float offsetY = 0.0f;
1834 CHECK_NULL_RETURN(idNodeMap_.find(nodeName) != idNodeMap_.end(), offsetY);
1835 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
1836 bool anchorIsContainer = IsAnchorContainer(alignRule.anchor);
1837 float flexItemHeight = childWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
1838 float anchorHeight;
1839 if (!versionGreatorOrEqualToEleven_) {
1840 anchorHeight =
1841 anchorIsContainer
1842 ? containerHeight
1843 : idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetMarginFrameSize().Height();
1844 } else {
1845 if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) {
1846 anchorHeight = 0;
1847 } else if (anchorIsContainer) {
1848 anchorHeight = containerHeight;
1849 } else {
1850 anchorHeight = idNodeMap_[alignRule.anchor].layoutWrapper->GetGeometryNode()->GetFrameSize().Height();
1851 }
1852 }
1853 std::optional<float> marginTop;
1854 if (!anchorIsContainer && !IsGuideline(alignRule.anchor) && !IsBarrier(alignRule.anchor)) {
1855 auto anchorWrapper = idNodeMap_[alignRule.anchor].layoutWrapper;
1856 if (anchorWrapper->GetGeometryNode()->GetMargin()) {
1857 marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top;
1858 }
1859 }
1860 switch (alignDirection) {
1861 case AlignDirection::TOP:
1862 offsetY = CalcVerticalOffsetAlignTop(alignRule.vertical, anchorHeight);
1863 break;
1864 case AlignDirection::CENTER:
1865 offsetY = CalcVerticalOffsetAlignCenter(alignRule.vertical, anchorHeight, flexItemHeight);
1866 break;
1867 case AlignDirection::BOTTOM:
1868 offsetY = CalcVerticalOffsetAlignBottom(alignRule.vertical, anchorHeight, flexItemHeight);
1869 break;
1870 default:
1871 break;
1872 }
1873 if (!versionGreatorOrEqualToEleven_) {
1874 offsetY += anchorIsContainer ? 0.0f : recordOffsetMap_[alignRule.anchor].GetY();
1875 } else {
1876 offsetY += anchorIsContainer ? 0.0f : recordOffsetMap_[alignRule.anchor].GetY() + marginTop.value_or(0);
1877 }
1878 return offsetY;
1879 }
1880
IsAnchorLegal(const std::string & anchorName)1881 bool RelativeContainerLayoutAlgorithm::IsAnchorLegal(const std::string& anchorName)
1882 {
1883 if (!IsAnchorContainer(anchorName) && !IsGuideline(anchorName) && !IsBarrier(anchorName) &&
1884 idNodeMap_.find(anchorName) == idNodeMap_.end()) {
1885 return false;
1886 }
1887 return true;
1888 }
1889
BarrierDirectionRtl(BarrierDirection barrierDirection)1890 BarrierDirection RelativeContainerLayoutAlgorithm::BarrierDirectionRtl(BarrierDirection barrierDirection)
1891 {
1892 auto barrierDirectionRtl = barrierDirection;
1893 if (barrierDirection == BarrierDirection::START) {
1894 barrierDirectionRtl = BarrierDirection::LEFT;
1895 } else if (barrierDirection == BarrierDirection::END) {
1896 barrierDirectionRtl = BarrierDirection::RIGHT;
1897 }
1898 return barrierDirectionRtl;
1899 }
1900
AdjustOffsetRtl(LayoutWrapper * layoutWrapper)1901 void RelativeContainerLayoutAlgorithm::AdjustOffsetRtl(LayoutWrapper* layoutWrapper)
1902 {
1903 auto textDirection = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection();
1904 if (textDirection != TextDirection::RTL) {
1905 return;
1906 }
1907 auto containerWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
1908 for (const auto& nodeName : renderList_) {
1909 auto it = idNodeMap_.find(nodeName);
1910 if (it == idNodeMap_.end()) {
1911 continue;
1912 }
1913 auto childWrapper = idNodeMap_[nodeName].layoutWrapper;
1914 if (!childWrapper) {
1915 continue;
1916 }
1917 auto oldNodeX = recordOffsetMap_[nodeName].GetX();
1918 auto oldNodeY = recordOffsetMap_[nodeName].GetY();
1919 auto nodeWidth = childWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
1920 auto newNodeX = containerWidth - nodeWidth - oldNodeX - padding_.Width();
1921 recordOffsetMap_[nodeName] = OffsetF(newNodeX, oldNodeY);
1922 }
1923 }
1924 } // namespace OHOS::Ace::NG
1925