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/layout/layout_property.h"
17 
18 #include <optional>
19 
20 #include "base/geometry/ng/size_t.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/base/frame_node.h"
24 #include "core/components_ng/base/inspector_filter.h"
25 #include "core/components_ng/base/ui_node.h"
26 #include "core/components_ng/property/calc_length.h"
27 #include "core/components_ng/property/layout_constraint.h"
28 #include "core/components_ng/property/measure_utils.h"
29 #include "core/components_ng/property/safe_area_insets.h"
30 #include "core/components_v2/inspector/inspector_constants.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 // safeaAreaPadding does not provide default param
36 struct DefaultPaddingBorderParam {
37     float horizontalPadding = 0.0f;
38     float verticalPadding = 0.0f;
39     float horizontalBorder = 0.0f;
40     float verticalBorder = 0.0f;
41 };
42 
CombinePaddingsAndBorder(const PaddingPropertyF & safeAreaPadding,const PaddingPropertyF & padding,const BorderWidthPropertyF & borderWidth,const DefaultPaddingBorderParam & defaultParam)43 PaddingPropertyF CombinePaddingsAndBorder(const PaddingPropertyF& safeAreaPadding, const PaddingPropertyF& padding,
44     const BorderWidthPropertyF& borderWidth, const DefaultPaddingBorderParam& defaultParam)
45 {
46     PaddingPropertyF result;
47     result.left = safeAreaPadding.left.value_or(0.0f) + padding.left.value_or(defaultParam.horizontalPadding) +
48                   borderWidth.leftDimen.value_or(defaultParam.horizontalBorder);
49     result.right = safeAreaPadding.right.value_or(0.0f) + padding.right.value_or(defaultParam.horizontalPadding) +
50                    borderWidth.rightDimen.value_or(defaultParam.horizontalBorder);
51     result.top = safeAreaPadding.top.value_or(0.0f) + padding.top.value_or(defaultParam.verticalPadding) +
52                  borderWidth.topDimen.value_or(defaultParam.verticalBorder);
53     result.bottom = safeAreaPadding.bottom.value_or(0.0f) + padding.bottom.value_or(defaultParam.verticalPadding) +
54                     borderWidth.bottomDimen.value_or(defaultParam.verticalBorder);
55     return result;
56 }
57 
VisibleTypeToString(VisibleType type)58 std::string VisibleTypeToString(VisibleType type)
59 {
60     static const LinearEnumMapNode<VisibleType, std::string> visibilityMap[] = {
61         { VisibleType::VISIBLE, "Visibility.Visible" },
62         { VisibleType::INVISIBLE, "Visibility.Hidden" },
63         { VisibleType::GONE, "Visibility.None" },
64     };
65     auto idx = BinarySearchFindIndex(visibilityMap, ArraySize(visibilityMap), type);
66     if (idx >= 0) {
67         return visibilityMap[idx].value;
68     }
69     return "Visibility.Visible";
70 }
71 
StringToVisibleType(const std::string & str)72 VisibleType StringToVisibleType(const std::string& str)
73 {
74     static const std::unordered_map<std::string, VisibleType> uMap {
75         { "Visibility.Visible", VisibleType::VISIBLE },
76         { "Visibility.Hidden", VisibleType::INVISIBLE },
77         { "Visibility.None", VisibleType::GONE },
78     };
79 
80     auto iter = uMap.find(str);
81     if (iter != uMap.end()) {
82         return iter->second;
83     }
84     return VisibleType::VISIBLE;
85 }
86 
TextDirectionToString(TextDirection type)87 std::string TextDirectionToString(TextDirection type)
88 {
89     static const LinearEnumMapNode<TextDirection, std::string> toStringMap[] = {
90         { TextDirection::LTR, "Direction.Ltr" },
91         { TextDirection::RTL, "Direction.Rtl" },
92         { TextDirection::INHERIT, "Direction.Inherit" },
93         { TextDirection::AUTO, "Direction.Auto" },
94     };
95     auto idx = BinarySearchFindIndex(toStringMap, ArraySize(toStringMap), type);
96     if (idx >= 0) {
97         return toStringMap[idx].value;
98     }
99     return "Direction.Ltr";
100 }
101 
StringToTextDirection(const std::string & str)102 TextDirection StringToTextDirection(const std::string& str)
103 {
104     static const std::unordered_map<std::string, TextDirection> uMap {
105         { "Direction.Ltr", TextDirection::LTR },
106         { "Direction.Rtl", TextDirection::RTL },
107         { "Direction.Inherit", TextDirection::INHERIT },
108         { "Direction.Auto", TextDirection::AUTO },
109     };
110 
111     auto iter = uMap.find(str);
112     if (iter != uMap.end()) {
113         return iter->second;
114     }
115     return TextDirection::LTR;
116 }
117 
ConstrainContentByBorderAndPadding(std::optional<LayoutConstraintF> & contentConstraint,std::optional<LayoutConstraintF> & layoutConstraint,std::unique_ptr<BorderWidthProperty> & borderWidth,std::unique_ptr<PaddingProperty> & padding)118 void ConstrainContentByBorderAndPadding(std::optional<LayoutConstraintF>& contentConstraint,
119     std::optional<LayoutConstraintF>& layoutConstraint, std::unique_ptr<BorderWidthProperty>& borderWidth,
120     std::unique_ptr<PaddingProperty>& padding)
121 {
122     if (padding) {
123         auto paddingF = ConvertToPaddingPropertyF(
124             *padding, contentConstraint->scaleProperty, contentConstraint->percentReference.Width());
125         contentConstraint->MinusPaddingToNonNegativeSize(paddingF.left, paddingF.right, paddingF.top, paddingF.bottom);
126     }
127     CHECK_NULL_VOID(borderWidth);
128     auto borderWidthF = ConvertToBorderWidthPropertyF(
129         *borderWidth, contentConstraint->scaleProperty, layoutConstraint->percentReference.Width());
130     contentConstraint->MinusPaddingToNonNegativeSize(
131         borderWidthF.leftDimen, borderWidthF.rightDimen, borderWidthF.topDimen, borderWidthF.bottomDimen);
132 }
133 
TruncateSafeAreaPadding(const std::optional<float> & range,std::optional<float> & start,std::optional<float> & end)134 void TruncateSafeAreaPadding(const std::optional<float>& range, std::optional<float>& start, std::optional<float>& end)
135 {
136     if (range && start && GreatNotEqual(start.value(), range.value())) {
137         start = range;
138     }
139     if (range && end) {
140         if (start) {
141             end = std::min(range.value() - start.value(), end.value());
142         } else {
143             end = std::min(range, end);
144         }
145     }
146 }
147 } // namespace
148 
Reset()149 void LayoutProperty::Reset()
150 {
151     layoutConstraint_.reset();
152     calcLayoutConstraint_.reset();
153     padding_.reset();
154     safeAreaPadding_.reset();
155     margin_.reset();
156     borderWidth_.reset();
157     outerBorderWidth_.reset();
158     magicItemProperty_.Reset();
159     positionProperty_.reset();
160     measureType_.reset();
161     layoutDirection_.reset();
162     propVisibility_.reset();
163     propIsBindOverlay_.reset();
164     CleanDirty();
165 }
166 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const167 void LayoutProperty::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
168 {
169     ACE_PROPERTY_TO_JSON_VALUE(calcLayoutConstraint_, MeasureProperty);
170     ACE_PROPERTY_TO_JSON_VALUE(positionProperty_, PositionProperty);
171     magicItemProperty_.ToJsonValue(json, filter);
172     ACE_PROPERTY_TO_JSON_VALUE(flexItemProperty_, FlexItemProperty);
173     ACE_PROPERTY_TO_JSON_VALUE(gridProperty_, GridProperty);
174     /* no fixed attr below, just return */
175     if (filter.IsFastFilter()) {
176         return;
177     }
178 
179     PaddingToJsonValue(json, filter);
180     MarginToJsonValue(json, filter);
181 
182     json->PutExtAttr("visibility",
183         VisibleTypeToString(propVisibility_.value_or(VisibleType::VISIBLE)).c_str(), filter);
184     json->PutExtAttr("direction", TextDirectionToString(GetLayoutDirection()).c_str(), filter);
185     json->PutExtAttr("pixelRound", PixelRoundToJsonValue().c_str(), filter);
186 }
187 
PaddingToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const188 void LayoutProperty::PaddingToJsonValue(std::unique_ptr<JsonValue>& json,
189     const InspectorFilter& filter) const
190 {
191     if (padding_) {
192         if (!padding_->top.has_value() || !padding_->right.has_value()
193             || !padding_->left.has_value() || !padding_->bottom.has_value()) {
194             auto paddingJsonValue = JsonUtil::Create(true);
195             paddingJsonValue->Put("top", padding_->top.has_value()
196                 ? padding_->top.value().ToString().c_str() : "0.00vp");
197             paddingJsonValue->Put("right", padding_->right.has_value()
198                 ? padding_->right.value().ToString().c_str() : "0.00vp");
199             paddingJsonValue->Put("bottom", padding_->bottom.has_value()
200                 ? padding_->bottom.value().ToString().c_str() : "0.00vp");
201             paddingJsonValue->Put("left", padding_->left.has_value()
202                 ? padding_->left.value().ToString().c_str() : "0.00vp");
203             json->PutExtAttr("padding", paddingJsonValue->ToString().c_str(), filter);
204         } else {
205             json->PutExtAttr("padding", padding_->ToJsonString().c_str(), filter);
206         }
207     } else {
208         json->PutExtAttr("padding", "0.00vp", filter);
209     }
210 }
211 
MarginToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const212 void LayoutProperty::MarginToJsonValue(std::unique_ptr<JsonValue>& json,
213     const InspectorFilter& filter) const
214 {
215     if (margin_) {
216         if (!margin_->top.has_value() || !margin_->right.has_value()
217             || !margin_->left.has_value() || !margin_->bottom.has_value()) {
218             auto marginJsonValue = JsonUtil::Create(true);
219             marginJsonValue->Put("top", margin_->top.has_value()
220                 ? margin_->top.value().ToString().c_str() : "0.00vp");
221             marginJsonValue->Put("right", margin_->right.has_value()
222                 ? margin_->right.value().ToString().c_str() : "0.00vp");
223             marginJsonValue->Put("bottom", margin_->bottom.has_value()
224                 ? margin_->bottom.value().ToString().c_str() : "0.00vp");
225             marginJsonValue->Put("left", margin_->left.has_value()
226                 ? margin_->left.value().ToString().c_str() : "0.00vp");
227             json->PutExtAttr("margin", marginJsonValue->ToString().c_str(), filter);
228         } else {
229             json->PutExtAttr("margin", margin_->ToJsonString().c_str(), filter);
230         }
231     } else {
232         json->PutExtAttr("margin", "0.00vp", filter);
233     }
234 }
235 
FromJson(const std::unique_ptr<JsonValue> & json)236 void LayoutProperty::FromJson(const std::unique_ptr<JsonValue>& json)
237 {
238     UpdateCalcLayoutProperty(MeasureProperty::FromJson(json));
239     UpdateLayoutWeight(json->GetDouble("layoutWeight"));
240     UpdateAlignment(Alignment::GetAlignment(TextDirection::LTR, json->GetString("align")));
241     auto padding = json->GetString("padding");
242     if (padding != "0.0") {
243         UpdatePadding(PaddingProperty::FromJsonString(padding));
244     }
245     auto margin = json->GetString("margin");
246     if (margin != "0.0") {
247         UpdateMargin(MarginProperty::FromJsonString(margin));
248     }
249     UpdateVisibility(StringToVisibleType(json->GetString("visibility")));
250     UpdateLayoutDirection(StringToTextDirection(json->GetString("direction")));
251 }
252 
PixelRoundToJsonValue() const253 const std::string LayoutProperty::PixelRoundToJsonValue() const
254 {
255     auto res = JsonUtil::Create(true);
256     if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_START)) {
257         res->Put("start", "PixelRoundCalcPolicy.FORCE_CEIL");
258     } else if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_START)) {
259         res->Put("start", "PixelRoundCalcPolicy.FORCE_FLOOR");
260     } else {
261         res->Put("start", "PixelRoundCalcPolicy.NO_FORCE_ROUND");
262     }
263     if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_TOP)) {
264         res->Put("top", "PixelRoundCalcPolicy.FORCE_CEIL");
265     } else if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_TOP)) {
266         res->Put("top", "PixelRoundCalcPolicy.FORCE_FLOOR");
267     } else {
268         res->Put("top", "PixelRoundCalcPolicy.NO_FORCE_ROUND");
269     }
270     if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_END)) {
271         res->Put("end", "PixelRoundCalcPolicy.FORCE_CEIL");
272     } else if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_END)) {
273         res->Put("end", "PixelRoundCalcPolicy.FORCE_FLOOR");
274     } else {
275         res->Put("end", "PixelRoundCalcPolicy.NO_FORCE_ROUND");
276     }
277     if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM)) {
278         res->Put("bottom", "PixelRoundCalcPolicy.FORCE_CEIL");
279     } else if (pixelRoundFlag_ & static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_BOTTOM)) {
280         res->Put("bottom", "PixelRoundCalcPolicy.FORCE_FLOOR");
281     } else {
282         res->Put("bottom", "PixelRoundCalcPolicy.NO_FORCE_ROUND");
283     }
284     return res->ToString();
285 }
286 
Clone() const287 RefPtr<LayoutProperty> LayoutProperty::Clone() const
288 {
289     auto layoutProperty = MakeRefPtr<LayoutProperty>();
290     Clone(layoutProperty);
291     return layoutProperty;
292 }
293 
Clone(RefPtr<LayoutProperty> layoutProperty) const294 void LayoutProperty::Clone(RefPtr<LayoutProperty> layoutProperty) const
295 {
296     layoutProperty->UpdateLayoutProperty(this);
297 }
298 
DecideMirror()299 bool LayoutProperty::DecideMirror()
300 {
301     auto host = GetHost();
302     CHECK_NULL_RETURN(host, false);
303     auto layoutProperty = host->GetLayoutProperty();
304     CHECK_NULL_RETURN(layoutProperty, false);
305     return layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
306 }
307 
UpdateLayoutProperty(const LayoutProperty * layoutProperty)308 void LayoutProperty::UpdateLayoutProperty(const LayoutProperty* layoutProperty)
309 {
310     CHECK_NULL_VOID(layoutProperty);
311     layoutConstraint_ = layoutProperty->layoutConstraint_;
312     if (layoutProperty->gridProperty_) {
313         gridProperty_ = std::make_unique<GridProperty>(*layoutProperty->gridProperty_);
314     }
315     if (layoutProperty->calcLayoutConstraint_) {
316         calcLayoutConstraint_ = std::make_unique<MeasureProperty>(*layoutProperty->calcLayoutConstraint_);
317     }
318     if (layoutProperty->padding_) {
319         padding_ = std::make_unique<PaddingProperty>(*layoutProperty->padding_);
320     }
321     if (layoutProperty->margin_) {
322         margin_ = std::make_unique<PaddingProperty>(*layoutProperty->margin_);
323     }
324     if (layoutProperty->borderWidth_) {
325         borderWidth_ = std::make_unique<BorderWidthProperty>(*layoutProperty->borderWidth_);
326     }
327     magicItemProperty_ = layoutProperty->magicItemProperty_;
328     if (layoutProperty->positionProperty_) {
329         positionProperty_ = std::make_unique<PositionProperty>(*layoutProperty->positionProperty_);
330     }
331     if (layoutProperty->flexItemProperty_) {
332         flexItemProperty_ = std::make_unique<FlexItemProperty>(*layoutProperty->flexItemProperty_);
333     }
334     if (layoutProperty->safeAreaInsets_) {
335         safeAreaInsets_ = std::make_unique<SafeAreaInsets>(*layoutProperty->safeAreaInsets_);
336     }
337     if (layoutProperty->safeAreaExpandOpts_) {
338         safeAreaExpandOpts_ = std::make_unique<SafeAreaExpandOpts>(*layoutProperty->safeAreaExpandOpts_);
339     }
340     geometryTransition_ = layoutProperty->geometryTransition_;
341     propVisibility_ = layoutProperty->GetVisibility();
342     measureType_ = layoutProperty->measureType_;
343     layoutDirection_ = layoutProperty->layoutDirection_;
344     propertyChangeFlag_ = layoutProperty->propertyChangeFlag_;
345     propIsBindOverlay_ = layoutProperty->propIsBindOverlay_;
346     isOverlayNode_ = layoutProperty->isOverlayNode_;
347     overlayOffsetX_ = layoutProperty->overlayOffsetX_;
348     overlayOffsetY_ = layoutProperty->overlayOffsetY_;
349 }
350 
UpdateCalcLayoutProperty(const MeasureProperty & constraint)351 void LayoutProperty::UpdateCalcLayoutProperty(const MeasureProperty& constraint)
352 {
353     if (!calcLayoutConstraint_) {
354         calcLayoutConstraint_ = std::make_unique<MeasureProperty>(constraint);
355         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
356         return;
357     }
358     if (*calcLayoutConstraint_ == constraint) {
359         return;
360     }
361     calcLayoutConstraint_->selfIdealSize = constraint.selfIdealSize;
362     calcLayoutConstraint_->maxSize = constraint.maxSize;
363     calcLayoutConstraint_->minSize = constraint.minSize;
364     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
365 }
366 
UpdateLayoutConstraint(const LayoutConstraintF & parentConstraint)367 void LayoutProperty::UpdateLayoutConstraint(const LayoutConstraintF& parentConstraint)
368 {
369     layoutConstraint_ = parentConstraint;
370     if (margin_) {
371         marginResult_.reset();
372         auto margin = CreateMargin();
373         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
374             MinusPaddingToNonNegativeSize(margin, layoutConstraint_->maxSize);
375             MinusPaddingToNonNegativeSize(margin, layoutConstraint_->minSize);
376             MinusPaddingToNonNegativeSize(margin, layoutConstraint_->percentReference);
377         } else {
378             MinusPaddingToSize(margin, layoutConstraint_->maxSize);
379             MinusPaddingToSize(margin, layoutConstraint_->minSize);
380             MinusPaddingToSize(margin, layoutConstraint_->percentReference);
381         }
382         // already has non negative protection
383         MinusPaddingToSize(margin, layoutConstraint_->selfIdealSize);
384         MinusPaddingToSize(margin, layoutConstraint_->parentIdealSize);
385     }
386     auto originMax = layoutConstraint_->maxSize;
387     if (calcLayoutConstraint_) {
388         if (calcLayoutConstraint_->maxSize.has_value()) {
389             layoutConstraint_->UpdateMaxSizeWithCheck(ConvertToSize(calcLayoutConstraint_->maxSize.value(),
390                 parentConstraint.scaleProperty, parentConstraint.percentReference));
391         }
392         if (calcLayoutConstraint_->minSize.has_value()) {
393             layoutConstraint_->UpdateMinSizeWithCheck(ConvertToSize(calcLayoutConstraint_->minSize.value(),
394                 parentConstraint.scaleProperty, parentConstraint.percentReference));
395         }
396         if (calcLayoutConstraint_->selfIdealSize.has_value()) {
397             layoutConstraint_->UpdateIllegalSelfIdealSizeWithCheck(
398                 ConvertToOptionalSize(calcLayoutConstraint_->selfIdealSize.value(), parentConstraint.scaleProperty,
399                     parentConstraint.percentReference));
400         }
401     }
402 
403     CheckSelfIdealSize(parentConstraint, originMax);
404     CheckBorderAndPadding();
405     CheckAspectRatio();
406 }
407 
UpdateLayoutConstraintWithLayoutRect()408 void LayoutProperty::UpdateLayoutConstraintWithLayoutRect()
409 {
410     CHECK_NULL_VOID(layoutRect_);
411     auto size = layoutRect_.value().GetSize();
412     layoutConstraint_ = {
413         .scaleProperty = ScaleProperty::CreateScaleProperty(),
414         .minSize = size,
415         .maxSize = size,
416         .percentReference = size,
417         .selfIdealSize = OptionalSizeF(size),
418     };
419 }
420 
CheckBorderAndPadding()421 void LayoutProperty::CheckBorderAndPadding()
422 {
423     auto selfWidth = layoutConstraint_->selfIdealSize.Width();
424     auto selfHeight = layoutConstraint_->selfIdealSize.Height();
425     if (!selfWidth && !selfHeight) {
426         return;
427     }
428     auto selfWidthFloat = selfWidth.value_or(Infinity<float>());
429     auto selfHeightFloat = selfHeight.value_or(Infinity<float>());
430     auto paddingWithBorder = CreatePaddingAndBorder(true, true);
431     auto deflateWidthF = paddingWithBorder.Width();
432     auto deflateHeightF = paddingWithBorder.Height();
433     if (LessOrEqual(deflateWidthF, selfWidthFloat) && LessOrEqual(deflateHeightF, selfHeightFloat)) {
434         return;
435     }
436     if (GreatNotEqual(deflateWidthF, selfWidthFloat)) {
437         layoutConstraint_->selfIdealSize.SetWidth(deflateWidthF);
438     }
439     if (GreatNotEqual(deflateHeightF, selfHeightFloat)) {
440         layoutConstraint_->selfIdealSize.SetHeight(deflateHeightF);
441     }
442 }
443 
CheckAspectRatio()444 void LayoutProperty::CheckAspectRatio()
445 {
446     if (!magicItemProperty_.HasAspectRatio()) {
447         return;
448     }
449     auto aspectRatio = magicItemProperty_.GetAspectRatioValue();
450     // Adjust by aspect ratio, firstly pick height based on width. It means that when width, height and aspectRatio are
451     // all set, the height is not used.
452     auto maxWidth = layoutConstraint_->maxSize.Width();
453     auto maxHeight = layoutConstraint_->maxSize.Height();
454     if (maxHeight > maxWidth / aspectRatio) {
455         maxHeight = maxWidth / aspectRatio;
456     }
457     layoutConstraint_->maxSize.SetWidth(maxWidth);
458     layoutConstraint_->maxSize.SetHeight(maxHeight);
459     std::optional<float> selfWidth;
460     std::optional<float> selfHeight;
461     if (layoutConstraint_->selfIdealSize.Width()) {
462         selfWidth = layoutConstraint_->selfIdealSize.Width().value();
463         selfHeight = selfWidth.value() / aspectRatio;
464         if (selfHeight > maxHeight) {
465             selfHeight = maxHeight;
466             selfWidth = selfHeight.value() * aspectRatio;
467         }
468     } else if (layoutConstraint_->selfIdealSize.Height()) {
469         selfHeight = layoutConstraint_->selfIdealSize.Height().value();
470         selfWidth = selfHeight.value() * aspectRatio;
471         if (selfWidth > maxWidth) {
472             selfWidth = maxWidth;
473             selfHeight = selfWidth.value() / aspectRatio;
474         }
475     }
476 
477     if (selfHeight) {
478         layoutConstraint_->selfIdealSize.SetHeight(selfHeight);
479     }
480     if (selfWidth) {
481         layoutConstraint_->selfIdealSize.SetWidth(selfWidth);
482     }
483 }
484 
BuildGridProperty(const RefPtr<FrameNode> & host)485 void LayoutProperty::BuildGridProperty(const RefPtr<FrameNode>& host)
486 {
487     CHECK_NULL_VOID(gridProperty_);
488     auto parent = host->GetAncestorNodeOfFrame();
489     while (parent) {
490         if (parent->GetTag() == V2::GRIDCONTAINER_ETS_TAG) {
491             auto containerLayout = parent->GetLayoutProperty();
492             gridProperty_->UpdateContainer(containerLayout, host);
493             UpdateUserDefinedIdealSize(CalcSize(CalcLength(gridProperty_->GetWidth()), std::nullopt));
494             break;
495         }
496         parent = parent->GetAncestorNodeOfFrame();
497     }
498 }
499 
UpdateGridProperty(std::optional<int32_t> span,std::optional<int32_t> offset,GridSizeType type)500 void LayoutProperty::UpdateGridProperty(std::optional<int32_t> span, std::optional<int32_t> offset, GridSizeType type)
501 {
502     if (!gridProperty_) {
503         gridProperty_ = std::make_unique<GridProperty>();
504     }
505 
506     bool isSpanUpdated = (span.has_value() && gridProperty_->UpdateSpan(span.value(), type));
507     bool isOffsetUpdated = (offset.has_value() && gridProperty_->UpdateOffset(offset.value(), type));
508     if (isSpanUpdated || isOffsetUpdated) {
509         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
510     }
511 }
512 
UpdateGridOffset(const RefPtr<FrameNode> & host)513 bool LayoutProperty::UpdateGridOffset(const RefPtr<FrameNode>& host)
514 {
515     CHECK_NULL_RETURN(gridProperty_, false);
516     auto optOffset = gridProperty_->GetOffset();
517     if (optOffset == UNDEFINED_DIMENSION) {
518         return false;
519     }
520 
521     RefPtr<FrameNode> parent = host->GetAncestorNodeOfFrame();
522     if (!parent) {
523         return false;
524     }
525     auto parentOffset = parent->GetOffsetRelativeToWindow();
526     auto globalOffset = gridProperty_->GetContainerPosition();
527 
528     OffsetF offset(optOffset.ConvertToPx(), 0);
529     offset = offset + globalOffset - parentOffset;
530     const auto& geometryNode = host->GetGeometryNode();
531     if (offset.GetX() == geometryNode->GetFrameOffset().GetX()) {
532         return false;
533     }
534     offset.SetY(geometryNode->GetFrameOffset().GetY());
535     geometryNode->SetFrameOffset(offset);
536     auto renderContext = host->GetRenderContext();
537     if (renderContext) {
538         renderContext->SavePaintRect();
539     }
540     return true;
541 }
542 
CheckSelfIdealSize(const LayoutConstraintF & parentConstraint,const SizeF & originMax)543 void LayoutProperty::CheckSelfIdealSize(const LayoutConstraintF& parentConstraint, const SizeF& originMax)
544 {
545     if (measureType_ == MeasureType::MATCH_PARENT) {
546         layoutConstraint_->UpdateIllegalSelfIdealSizeWithCheck(layoutConstraint_->parentIdealSize);
547     }
548     if (!calcLayoutConstraint_) {
549         return;
550     }
551     SizeF minSize(-1.0f, -1.0f);
552     SizeF maxSize(-1.0f, -1.0f);
553     if (calcLayoutConstraint_->maxSize.has_value()) {
554         maxSize = ConvertToSize(calcLayoutConstraint_->maxSize.value(), layoutConstraint_->scaleProperty,
555             layoutConstraint_->percentReference);
556     }
557     if (calcLayoutConstraint_->minSize.has_value()) {
558         minSize = ConvertToSize(calcLayoutConstraint_->minSize.value(), layoutConstraint_->scaleProperty,
559             layoutConstraint_->percentReference);
560     }
561     if (calcLayoutConstraint_->maxSize.has_value()) {
562         layoutConstraint_->selfIdealSize.UpdateWidthWhenSmaller(maxSize);
563         if (GreatNotEqual(maxSize.Width(), 0.0f) && GreatOrEqual(maxSize.Width(), minSize.Width())) {
564             layoutConstraint_->UpdateMaxWidthWithCheck(maxSize);
565         } else if (GreatNotEqual(maxSize.Width(), 0.0f) && LessNotEqual(maxSize.Width(), minSize.Width())) {
566             layoutConstraint_->maxSize.SetWidth(minSize.Width());
567         } else {
568             layoutConstraint_->maxSize.SetWidth(originMax.Width());
569         }
570         layoutConstraint_->selfIdealSize.UpdateHeightWhenSmaller(maxSize);
571         if (GreatNotEqual(maxSize.Height(), 0.0f) && GreatOrEqual(maxSize.Height(), minSize.Height())) {
572             layoutConstraint_->UpdateMaxHeightWithCheck(maxSize);
573         } else if (GreatNotEqual(maxSize.Height(), 0.0f) && LessNotEqual(maxSize.Height(), minSize.Height())) {
574             layoutConstraint_->maxSize.SetHeight(minSize.Height());
575         } else {
576             layoutConstraint_->maxSize.SetHeight(originMax.Height());
577         }
578     }
579     layoutConstraint_->UpdateMinSizeWithCheck(minSize);
580     layoutConstraint_->selfIdealSize.UpdateSizeWhenLarger(minSize);
581 }
582 
CreateChildConstraint() const583 LayoutConstraintF LayoutProperty::CreateChildConstraint() const
584 {
585     CHECK_NULL_RETURN(layoutConstraint_, {});
586     auto layoutConstraint = contentConstraint_.value();
587     layoutConstraint.parentIdealSize = layoutConstraint.selfIdealSize;
588     // update max size when ideal size has value.
589     if (layoutConstraint.parentIdealSize.Width()) {
590         layoutConstraint.maxSize.SetWidth(layoutConstraint.parentIdealSize.Width().value());
591         layoutConstraint.percentReference.SetWidth(layoutConstraint.parentIdealSize.Width().value());
592     }
593     if (layoutConstraint.parentIdealSize.Height()) {
594         layoutConstraint.maxSize.SetHeight(layoutConstraint.parentIdealSize.Height().value());
595         layoutConstraint.percentReference.SetHeight(layoutConstraint.parentIdealSize.Height().value());
596     }
597     // for child constraint, reset current selfIdealSize and minSize.
598     layoutConstraint.selfIdealSize.Reset();
599     layoutConstraint.minSize.Reset();
600     return layoutConstraint;
601 }
602 
UpdateContentConstraint()603 void LayoutProperty::UpdateContentConstraint()
604 {
605     CHECK_NULL_VOID(layoutConstraint_);
606     contentConstraint_ = layoutConstraint_.value();
607     // update percent reference when parent has size.
608     if (contentConstraint_->parentIdealSize.Width()) {
609         contentConstraint_->percentReference.SetWidth(contentConstraint_->parentIdealSize.Width().value());
610     }
611     if (contentConstraint_->parentIdealSize.Height()) {
612         contentConstraint_->percentReference.SetHeight(contentConstraint_->parentIdealSize.Height().value());
613     }
614     ConstraintContentByPadding();
615     ConstraintContentByBorder();
616     ConstraintContentBySafeAreaPadding();
617 }
618 
ConstraintContentByPadding()619 void LayoutProperty::ConstraintContentByPadding()
620 {
621     CHECK_NULL_VOID(padding_);
622     auto paddingF = ConvertToPaddingPropertyF(
623         *padding_, contentConstraint_->scaleProperty, contentConstraint_->percentReference.Width());
624     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
625         contentConstraint_->MinusPaddingToNonNegativeSize(paddingF.left, paddingF.right, paddingF.top, paddingF.bottom);
626     } else {
627         contentConstraint_->MinusPadding(paddingF.left, paddingF.right, paddingF.top, paddingF.bottom);
628     }
629 }
630 
ConstraintContentByBorder()631 void LayoutProperty::ConstraintContentByBorder()
632 {
633     CHECK_NULL_VOID(borderWidth_);
634     auto borderWidthF = ConvertToBorderWidthPropertyF(
635         *borderWidth_, contentConstraint_->scaleProperty, layoutConstraint_->percentReference.Width());
636     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
637         contentConstraint_->MinusPaddingToNonNegativeSize(
638             borderWidthF.leftDimen, borderWidthF.rightDimen, borderWidthF.topDimen, borderWidthF.bottomDimen);
639     } else {
640         contentConstraint_->MinusPadding(
641             borderWidthF.leftDimen, borderWidthF.rightDimen, borderWidthF.topDimen, borderWidthF.bottomDimen);
642     }
643 }
644 
ConstraintContentBySafeAreaPadding()645 void LayoutProperty::ConstraintContentBySafeAreaPadding()
646 {
647     CHECK_NULL_VOID(safeAreaPadding_);
648     auto safeAreaPaddingF = ConvertToPaddingPropertyF(
649         *safeAreaPadding_, contentConstraint_->scaleProperty, contentConstraint_->percentReference.Width(), true, true);
650     contentConstraint_->MinusPaddingToNonNegativeSize(
651         safeAreaPaddingF.left, safeAreaPaddingF.right, safeAreaPaddingF.top, safeAreaPaddingF.bottom);
652 }
653 
GetOrCreateSafeAreaPadding(bool forceReCreate)654 PaddingPropertyF LayoutProperty::GetOrCreateSafeAreaPadding(bool forceReCreate)
655 {
656     auto host = GetHost();
657     CHECK_NULL_RETURN(host, CreateSafeAreaPadding());
658     const auto& geometryNode = host->GetGeometryNode();
659     CHECK_NULL_RETURN(geometryNode, CreateSafeAreaPadding());
660     auto& resolvedSafeAreaPadding = geometryNode->GetResolvedSingleSafeAreaPadding();
661     if (forceReCreate || !resolvedSafeAreaPadding) {
662         host->ResetSafeAreaPadding();
663         auto safeAreaPadding = CreateSafeAreaPadding();
664         geometryNode->SetResolvedSingleSafeAreaPadding(safeAreaPadding);
665         return safeAreaPadding;
666     }
667     return *(resolvedSafeAreaPadding.get());
668 }
669 
CreateSafeAreaPadding()670 PaddingPropertyF LayoutProperty::CreateSafeAreaPadding()
671 {
672     if (layoutConstraint_.has_value()) {
673         std::optional<LayoutConstraintF> contentWithSafeArea = layoutConstraint_.value();
674         ConstrainContentByBorderAndPadding(contentWithSafeArea, layoutConstraint_, borderWidth_, padding_);
675         PaddingPropertyF truncatedSafeAreaPadding = ConvertToPaddingPropertyF(safeAreaPadding_,
676             ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width(), true, true);
677         TruncateSafeAreaPadding(
678             contentWithSafeArea->selfIdealSize.Height(), truncatedSafeAreaPadding.top, truncatedSafeAreaPadding.bottom);
679 
680         bool isRtl = DecideMirror() && safeAreaPadding_ &&
681                      (safeAreaPadding_->start.has_value() || safeAreaPadding_->end.has_value());
682         TruncateSafeAreaPadding(contentWithSafeArea->selfIdealSize.Width(),
683             isRtl ? truncatedSafeAreaPadding.right : truncatedSafeAreaPadding.left,
684             isRtl ? truncatedSafeAreaPadding.left : truncatedSafeAreaPadding.right);
685         return truncatedSafeAreaPadding;
686     }
687     return ConvertToPaddingPropertyF(
688         safeAreaPadding_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth(), true, true);
689 }
690 
CreatePaddingAndBorder(bool includeSafeAreaPadding,bool forceReCreate)691 PaddingPropertyF LayoutProperty::CreatePaddingAndBorder(bool includeSafeAreaPadding, bool forceReCreate)
692 {
693     PaddingPropertyF safeAreaPadding;
694     if (includeSafeAreaPadding) {
695         safeAreaPadding = GetOrCreateSafeAreaPadding(forceReCreate);
696     }
697     if (layoutConstraint_.has_value()) {
698         auto padding = ConvertToPaddingPropertyF(
699             padding_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
700         auto borderWidth = ConvertToBorderWidthPropertyF(
701             borderWidth_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
702         return CombinePaddingsAndBorder(safeAreaPadding, padding, borderWidth, {});
703     }
704     auto padding = ConvertToPaddingPropertyF(
705         padding_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
706     auto borderWidth = ConvertToBorderWidthPropertyF(
707         borderWidth_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
708     return CombinePaddingsAndBorder(safeAreaPadding, padding, borderWidth, {});
709 }
710 
CreatePaddingAndBorderWithDefault(float paddingHorizontalDefault,float paddingVerticalDefault,float borderHorizontalDefault,float borderVerticalDefault)711 PaddingPropertyF LayoutProperty::CreatePaddingAndBorderWithDefault(float paddingHorizontalDefault,
712     float paddingVerticalDefault, float borderHorizontalDefault, float borderVerticalDefault)
713 {
714     auto safeAreaPadding = GetOrCreateSafeAreaPadding();
715     DefaultPaddingBorderParam defaultParam = { .horizontalPadding = paddingHorizontalDefault,
716         .verticalPadding = paddingVerticalDefault,
717         .horizontalBorder = borderHorizontalDefault,
718         .verticalBorder = borderVerticalDefault };
719     if (layoutConstraint_.has_value()) {
720         auto padding = ConvertToPaddingPropertyF(
721             padding_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
722         auto borderWidth = ConvertToBorderWidthPropertyF(
723             borderWidth_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
724         return CombinePaddingsAndBorder(safeAreaPadding, padding, borderWidth, defaultParam);
725     }
726     auto padding = ConvertToPaddingPropertyF(
727         padding_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
728     auto borderWidth = ConvertToBorderWidthPropertyF(
729         borderWidth_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
730     return CombinePaddingsAndBorder(safeAreaPadding, padding, borderWidth, defaultParam);
731 }
732 
CreatePaddingWithoutBorder(bool useRootConstraint,bool roundPixel)733 PaddingPropertyF LayoutProperty::CreatePaddingWithoutBorder(bool useRootConstraint, bool roundPixel)
734 {
735     auto safeAreaPadding = GetOrCreateSafeAreaPadding();
736     if (layoutConstraint_.has_value()) {
737         auto padding = ConvertToPaddingPropertyF(
738             padding_, layoutConstraint_->scaleProperty, layoutConstraint_->percentReference.Width(), roundPixel);
739         auto totalPadding = CombinePaddingsAndBorder(safeAreaPadding, padding, {}, {});
740         return totalPadding;
741     }
742 
743     auto padding = ConvertToPaddingPropertyF(padding_, ScaleProperty::CreateScaleProperty(),
744         useRootConstraint ? PipelineContext::GetCurrentRootWidth() : 0.0f, roundPixel);
745     auto totalPadding = CombinePaddingsAndBorder(safeAreaPadding, padding, {}, {});
746     return totalPadding;
747 }
748 
CreateBorder()749 BorderWidthPropertyF LayoutProperty::CreateBorder()
750 {
751     // no pixel rounding
752     if (layoutConstraint_.has_value()) {
753         return ConvertToBorderWidthPropertyF(
754             borderWidth_, layoutConstraint_->scaleProperty, layoutConstraint_->percentReference.Width(), false);
755     }
756 
757     return ConvertToBorderWidthPropertyF(
758         borderWidth_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth(), false);
759 }
760 
CreateMargin()761 MarginPropertyF LayoutProperty::CreateMargin()
762 {
763     CHECK_NULL_RETURN(margin_, MarginPropertyF());
764     if (!marginResult_.has_value() && margin_) {
765         if (layoutConstraint_.has_value()) {
766             marginResult_ = ConvertToMarginPropertyF(
767                 margin_, layoutConstraint_->scaleProperty, layoutConstraint_->percentReference.Width());
768         } else {
769             // root node
770             marginResult_ = ConvertToMarginPropertyF(
771                 margin_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
772         }
773     }
774     return marginResult_.value_or(MarginPropertyF());
775 }
776 
CreateMarginWithoutCache()777 MarginPropertyF LayoutProperty::CreateMarginWithoutCache()
778 {
779     CHECK_NULL_RETURN(margin_, MarginPropertyF());
780     auto host = GetHost();
781     CHECK_NULL_RETURN(host, MarginPropertyF());
782     const auto& parentConstraint = host->GetGeometryNode()->GetParentLayoutConstraint();
783     // no pixel rounding
784     if (parentConstraint) {
785         return ConvertToMarginPropertyF(
786             margin_, parentConstraint->scaleProperty, parentConstraint->percentReference.Width(), false);
787     }
788     // the root width is not considered at present.
789     return ConvertToMarginPropertyF(margin_, ScaleProperty::CreateScaleProperty(), 0.0f, false);
790 }
791 
SetHost(const WeakPtr<FrameNode> & host)792 void LayoutProperty::SetHost(const WeakPtr<FrameNode>& host)
793 {
794     host_ = host;
795 }
796 
GetHost() const797 RefPtr<FrameNode> LayoutProperty::GetHost() const
798 {
799     return host_.Upgrade();
800 }
801 
OnVisibilityUpdate(VisibleType visible,bool allowTransition)802 void LayoutProperty::OnVisibilityUpdate(VisibleType visible, bool allowTransition)
803 {
804     auto host = GetHost();
805     CHECK_NULL_VOID(host);
806     // store the previous visibility value.
807     auto preVisibility = propVisibility_;
808 
809     // update visibility value.
810     propVisibility_ = visible;
811     host->NotifyVisibleChange(preVisibility.value_or(VisibleType::VISIBLE), visible);
812     if (allowTransition && preVisibility) {
813         if (preVisibility.value() == VisibleType::VISIBLE && visible != VisibleType::VISIBLE) {
814             host->GetRenderContext()->OnNodeDisappear(false);
815         } else if (preVisibility.value() != VisibleType::VISIBLE && visible == VisibleType::VISIBLE) {
816             host->GetRenderContext()->OnNodeAppear(false);
817         }
818     }
819 
820     auto parent = host->GetAncestorNodeOfFrame();
821     CHECK_NULL_VOID(parent);
822     // if visible is not changed to/from VisibleType::Gone, only need to update render tree.
823     if (preVisibility.value_or(VisibleType::VISIBLE) != VisibleType::GONE && visible != VisibleType::GONE) {
824         parent->MarkNeedSyncRenderTree();
825         parent->RebuildRenderContextTree();
826         return;
827     }
828     UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
829     parent->MarkNeedSyncRenderTree();
830     parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
831 }
832 
UpdateSafeAreaExpandOpts(const SafeAreaExpandOpts & opts)833 void LayoutProperty::UpdateSafeAreaExpandOpts(const SafeAreaExpandOpts& opts)
834 {
835     if (!safeAreaExpandOpts_) {
836         safeAreaExpandOpts_ = std::make_unique<SafeAreaExpandOpts>();
837     }
838     if (*safeAreaExpandOpts_ != opts) {
839         *safeAreaExpandOpts_ = opts;
840         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
841         safeAreaExpandOpts_->switchToNone = !opts.Expansive();
842     }
843 }
844 
UpdateSafeAreaInsets(const SafeAreaInsets & safeArea)845 void LayoutProperty::UpdateSafeAreaInsets(const SafeAreaInsets& safeArea)
846 {
847     if (!safeAreaInsets_) {
848         safeAreaInsets_ = std::make_unique<SafeAreaInsets>();
849     }
850     if (*safeAreaInsets_ != safeArea) {
851         *safeAreaInsets_ = safeArea;
852     }
853 }
854 
HasFixedWidth(bool checkPercent) const855 bool LayoutProperty::HasFixedWidth(bool checkPercent) const
856 {
857     CHECK_NULL_RETURN(calcLayoutConstraint_, false);
858     auto&& idealSize = calcLayoutConstraint_->selfIdealSize;
859     return (idealSize && idealSize->WidthFixed(checkPercent));
860 }
861 
HasFixedHeight(bool checkPercent) const862 bool LayoutProperty::HasFixedHeight(bool checkPercent) const
863 {
864     CHECK_NULL_RETURN(calcLayoutConstraint_, false);
865     auto&& idealSize = calcLayoutConstraint_->selfIdealSize;
866     return (idealSize && idealSize->HeightFixed(checkPercent));
867 }
868 
HasAspectRatio() const869 bool LayoutProperty::HasAspectRatio() const
870 {
871     return magicItemProperty_.HasAspectRatio();
872 }
873 
GetAspectRatio() const874 float LayoutProperty::GetAspectRatio() const
875 {
876     if (magicItemProperty_.HasAspectRatio()) {
877         return magicItemProperty_.GetAspectRatioValue();
878     }
879     return 0.0f;
880 }
881 
UpdateAspectRatio(float ratio)882 void LayoutProperty::UpdateAspectRatio(float ratio)
883 {
884     if (magicItemProperty_.UpdateAspectRatio(ratio)) {
885         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
886     }
887 }
888 
ResetAspectRatio()889 void LayoutProperty::ResetAspectRatio()
890 {
891     if (magicItemProperty_.HasAspectRatio()) {
892         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
893         magicItemProperty_.ResetAspectRatio();
894     }
895 }
896 
UpdateGeometryTransition(const std::string & id,bool followWithoutTransition,bool doRegisterSharedTransition)897 void LayoutProperty::UpdateGeometryTransition(const std::string& id,
898     bool followWithoutTransition, bool doRegisterSharedTransition)
899 {
900     auto host = GetHost();
901     CHECK_NULL_VOID(host);
902 
903     auto geometryTransitionOld = GetGeometryTransition();
904     auto geometryTransitionNew =
905         ElementRegister::GetInstance()->GetOrCreateGeometryTransition(id,
906             followWithoutTransition, doRegisterSharedTransition);
907     CHECK_NULL_VOID(geometryTransitionOld != geometryTransitionNew);
908     if (geometryTransitionOld) {
909         if (geometryTransitionOld->Update(host_, host_)) {
910             geometryTransitionOld->OnFollowWithoutTransition();
911         }
912         // unregister node from old geometry transition
913         geometryTransitionOld->Update(host_, nullptr);
914         // register node into new geometry transition
915         if (geometryTransitionNew && !geometryTransitionNew->Update(nullptr, host_)) {
916             TAG_LOGE(AceLogTag::ACE_GEOMETRY_TRANSITION, "redundant node%{public}d has same geoid: %{public}s",
917                 host->GetId(), id.c_str());
918         }
919     } else if (geometryTransitionNew) {
920         if (geometryTransitionNew->IsInAndOutValid()) {
921             TAG_LOGE(AceLogTag::ACE_GEOMETRY_TRANSITION, "redundant node%{public}d has same geoid: %{public}s",
922                 host->GetId(), id.c_str());
923         }
924         geometryTransitionNew->Build(host_, true);
925     }
926     geometryTransition_ = geometryTransitionNew;
927 
928     TAG_LOGD(AceLogTag::ACE_GEOMETRY_TRANSITION, "node: %{public}d update id, old id: %{public}s, new id: %{public}s",
929         host->GetId(), geometryTransitionOld ? geometryTransitionOld->GetId().c_str() : "empty",
930         geometryTransitionNew ? id.c_str() : "empty");
931     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
932 }
933 
ResetGeometryTransition()934 void LayoutProperty::ResetGeometryTransition()
935 {
936     if (!GetGeometryTransition()) {
937         return;
938     }
939     UpdateGeometryTransition("");
940 }
941 
UpdateLayoutDirection(TextDirection value)942 void LayoutProperty::UpdateLayoutDirection(TextDirection value)
943 {
944     if (layoutDirection_ == value) {
945         return;
946     }
947     layoutDirection_ = value;
948     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
949 }
950 
GetNonAutoLayoutDirection() const951 TextDirection LayoutProperty::GetNonAutoLayoutDirection() const
952 {
953     auto direction = layoutDirection_.value_or(TextDirection::AUTO);
954     return direction != TextDirection::AUTO
955                ? direction
956                : (AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
957 }
958 
UpdateLayoutWeight(float value)959 void LayoutProperty::UpdateLayoutWeight(float value)
960 {
961     if (magicItemProperty_.UpdateLayoutWeight(value)) {
962         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
963     }
964 }
965 
UpdateChainWeight(const LayoutWeightPair & value)966 void LayoutProperty::UpdateChainWeight(const LayoutWeightPair& value)
967 {
968     if (flexItemProperty_->UpdateChainWeight(value)) {
969         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
970     }
971 }
972 
UpdateBorderWidth(const BorderWidthProperty & value)973 void LayoutProperty::UpdateBorderWidth(const BorderWidthProperty& value)
974 {
975     if (!borderWidth_) {
976         borderWidth_ = std::make_unique<BorderWidthProperty>();
977     }
978     if (borderWidth_->UpdateWithCheck(value)) {
979         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
980     }
981 }
982 
UpdateOuterBorderWidth(const BorderWidthProperty & value)983 void LayoutProperty::UpdateOuterBorderWidth(const BorderWidthProperty& value)
984 {
985     if (!outerBorderWidth_) {
986         outerBorderWidth_ = std::make_unique<BorderWidthProperty>();
987     }
988     if (outerBorderWidth_->UpdateWithCheck(value)) {
989         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
990     }
991 }
992 
UpdateAlignment(Alignment value)993 void LayoutProperty::UpdateAlignment(Alignment value)
994 {
995     if (!positionProperty_) {
996         positionProperty_ = std::make_unique<PositionProperty>();
997     }
998     if (positionProperty_->UpdateAlignment(value)) {
999         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT;
1000     }
1001 }
1002 
UpdateMargin(const MarginProperty & value)1003 void LayoutProperty::UpdateMargin(const MarginProperty& value)
1004 {
1005     if (!margin_) {
1006         margin_ = std::make_unique<MarginProperty>();
1007     }
1008     if (margin_->UpdateWithCheck(value)) {
1009         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
1010     }
1011 }
1012 
UpdatePadding(const PaddingProperty & value)1013 void LayoutProperty::UpdatePadding(const PaddingProperty& value)
1014 {
1015     if (!padding_) {
1016         padding_ = std::make_unique<PaddingProperty>();
1017     }
1018     if (padding_->UpdateWithCheck(value)) {
1019         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
1020     }
1021 }
1022 
UpdateSafeAreaPadding(const PaddingProperty & value)1023 void LayoutProperty::UpdateSafeAreaPadding(const PaddingProperty& value)
1024 {
1025     auto host = GetHost();
1026     if (!safeAreaPadding_) {
1027         safeAreaPadding_ = std::make_unique<PaddingProperty>();
1028     }
1029     if (safeAreaPadding_->UpdateWithCheck(value)) {
1030         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
1031     }
1032 }
1033 
ResetSafeAreaPadding()1034 void LayoutProperty::ResetSafeAreaPadding()
1035 {
1036     if (!safeAreaPadding_) {
1037         return;
1038     }
1039     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1040     safeAreaPadding_.reset();
1041 }
1042 
UpdateUserDefinedIdealSize(const CalcSize & value)1043 void LayoutProperty::UpdateUserDefinedIdealSize(const CalcSize& value)
1044 {
1045     if (!calcLayoutConstraint_) {
1046         calcLayoutConstraint_ = std::make_unique<MeasureProperty>();
1047     }
1048     if (calcLayoutConstraint_->UpdateSelfIdealSizeWithCheck(value)) {
1049         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1050     }
1051 }
1052 
ClearUserDefinedIdealSize(bool clearWidth,bool clearHeight)1053 void LayoutProperty::ClearUserDefinedIdealSize(bool clearWidth, bool clearHeight)
1054 {
1055     if (!calcLayoutConstraint_) {
1056         return;
1057     }
1058     if (calcLayoutConstraint_->ClearSelfIdealSize(clearWidth, clearHeight)) {
1059         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1060     }
1061 }
1062 
UpdateCalcMinSize(const CalcSize & value)1063 void LayoutProperty::UpdateCalcMinSize(const CalcSize& value)
1064 {
1065     if (!calcLayoutConstraint_) {
1066         calcLayoutConstraint_ = std::make_unique<MeasureProperty>();
1067     }
1068     if (calcLayoutConstraint_->UpdateMinSizeWithCheck(value)) {
1069         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1070     }
1071 }
1072 
UpdateCalcMaxSize(const CalcSize & value)1073 void LayoutProperty::UpdateCalcMaxSize(const CalcSize& value)
1074 {
1075     if (!calcLayoutConstraint_) {
1076         calcLayoutConstraint_ = std::make_unique<MeasureProperty>();
1077     }
1078     if (calcLayoutConstraint_->UpdateMaxSizeWithCheck(value)) {
1079         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1080     }
1081 }
1082 
UpdateMarginSelfIdealSize(const SizeF & value)1083 void LayoutProperty::UpdateMarginSelfIdealSize(const SizeF& value)
1084 {
1085     if (!layoutConstraint_.has_value()) {
1086         layoutConstraint_ = LayoutConstraintF();
1087     }
1088     if (layoutConstraint_->UpdateSelfMarginSizeWithCheck(OptionalSizeF(value))) {
1089         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1090     }
1091 }
1092 
ResetCalcMinSize()1093 void LayoutProperty::ResetCalcMinSize()
1094 {
1095     if (!calcLayoutConstraint_) {
1096         return;
1097     }
1098     if (calcLayoutConstraint_->minSize.has_value()) {
1099         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1100     }
1101     calcLayoutConstraint_->minSize.reset();
1102 }
1103 
ResetCalcMaxSize()1104 void LayoutProperty::ResetCalcMaxSize()
1105 {
1106     if (!calcLayoutConstraint_) {
1107         return;
1108     }
1109     if (calcLayoutConstraint_->maxSize.has_value()) {
1110         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1111     }
1112     calcLayoutConstraint_->maxSize.reset();
1113 }
1114 
ResetCalcMinSize(bool resetWidth)1115 void LayoutProperty::ResetCalcMinSize(bool resetWidth)
1116 {
1117     if (!calcLayoutConstraint_) {
1118         return;
1119     }
1120     CHECK_NULL_VOID(calcLayoutConstraint_->minSize.has_value());
1121     bool resetSizeHasValue = resetWidth ? calcLayoutConstraint_->minSize.value().Width().has_value()
1122                                         : calcLayoutConstraint_->minSize.value().Height().has_value();
1123     CHECK_NULL_VOID(resetSizeHasValue);
1124     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1125     if (resetWidth) {
1126         calcLayoutConstraint_->minSize.value().SetWidth(std::nullopt);
1127     } else {
1128         calcLayoutConstraint_->minSize.value().SetHeight(std::nullopt);
1129     }
1130 }
1131 
ResetCalcMaxSize(bool resetWidth)1132 void LayoutProperty::ResetCalcMaxSize(bool resetWidth)
1133 {
1134     if (!calcLayoutConstraint_) {
1135         return;
1136     }
1137     CHECK_NULL_VOID(calcLayoutConstraint_->maxSize.has_value());
1138     bool resetSizeHasValue = resetWidth ? calcLayoutConstraint_->maxSize.value().Width().has_value()
1139                                         : calcLayoutConstraint_->maxSize.value().Height().has_value();
1140     CHECK_NULL_VOID(resetSizeHasValue);
1141     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1142     if (resetWidth) {
1143         calcLayoutConstraint_->maxSize.value().SetWidth(std::nullopt);
1144     } else {
1145         calcLayoutConstraint_->maxSize.value().SetHeight(std::nullopt);
1146     }
1147 }
1148 
UpdateFlexGrow(float flexGrow)1149 void LayoutProperty::UpdateFlexGrow(float flexGrow)
1150 {
1151     if (!flexItemProperty_) {
1152         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1153     }
1154     if (flexItemProperty_->UpdateFlexGrow(flexGrow)) {
1155         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1156     }
1157 }
1158 
ResetFlexGrow()1159 void LayoutProperty::ResetFlexGrow()
1160 {
1161     if (!flexItemProperty_) {
1162         return;
1163     }
1164     if (flexItemProperty_->HasFlexGrow()) {
1165         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1166     }
1167     flexItemProperty_->ResetFlexGrow();
1168 }
1169 
UpdateFlexShrink(float flexShrink)1170 void LayoutProperty::UpdateFlexShrink(float flexShrink)
1171 {
1172     if (!flexItemProperty_) {
1173         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1174     }
1175     if (flexItemProperty_->UpdateFlexShrink(flexShrink)) {
1176         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1177     }
1178 }
1179 
ResetFlexShrink()1180 void LayoutProperty::ResetFlexShrink()
1181 {
1182     if (!flexItemProperty_) {
1183         return;
1184     }
1185     if (flexItemProperty_->HasFlexShrink()) {
1186         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1187     }
1188     flexItemProperty_->ResetFlexShrink();
1189 }
1190 
UpdateFlexBasis(const Dimension & flexBasis)1191 void LayoutProperty::UpdateFlexBasis(const Dimension& flexBasis)
1192 {
1193     if (!flexItemProperty_) {
1194         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1195     }
1196     if (flexItemProperty_->UpdateFlexBasis(flexBasis)) {
1197         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1198     }
1199 }
1200 
UpdateAlignSelf(const FlexAlign & flexAlign)1201 void LayoutProperty::UpdateAlignSelf(const FlexAlign& flexAlign)
1202 {
1203     if (!flexItemProperty_) {
1204         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1205     }
1206     if (flexItemProperty_->UpdateAlignSelf(flexAlign)) {
1207         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1208     }
1209 }
1210 
ResetAlignSelf()1211 void LayoutProperty::ResetAlignSelf()
1212 {
1213     if (!flexItemProperty_) {
1214         return;
1215     }
1216     if (flexItemProperty_->HasAlignSelf()) {
1217         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1218     }
1219     flexItemProperty_->ResetAlignSelf();
1220 }
1221 
UpdateAlignRules(const std::map<AlignDirection,AlignRule> & alignRules)1222 void LayoutProperty::UpdateAlignRules(const std::map<AlignDirection, AlignRule>& alignRules)
1223 {
1224     if (!flexItemProperty_) {
1225         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1226     }
1227     if (flexItemProperty_->UpdateAlignRules(alignRules)) {
1228         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1229     }
1230 }
1231 
UpdateChainStyle(const ChainInfo & chainInfo)1232 void LayoutProperty::UpdateChainStyle(const ChainInfo& chainInfo)
1233 {
1234     if (!flexItemProperty_) {
1235         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1236     }
1237     if (!chainInfo.direction.has_value()) {
1238         ChainInfo nullChainInfo;
1239         if (flexItemProperty_->UpdateHorizontalChainStyle(nullChainInfo)) {
1240             propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1241         }
1242         if (flexItemProperty_->UpdateVerticalChainStyle(nullChainInfo)) {
1243             propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1244         }
1245     }
1246     if (chainInfo.direction == LineDirection::HORIZONTAL) {
1247         if (flexItemProperty_->UpdateHorizontalChainStyle(chainInfo)) {
1248             propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1249         }
1250     } else {
1251         if (flexItemProperty_->UpdateVerticalChainStyle(chainInfo)) {
1252             propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1253         }
1254     }
1255 }
1256 
UpdateBias(const BiasPair & biasPair)1257 void LayoutProperty::UpdateBias(const BiasPair& biasPair)
1258 {
1259     if (!flexItemProperty_) {
1260         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1261     }
1262     if (flexItemProperty_->UpdateBias(biasPair)) {
1263         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1264     }
1265 }
1266 
UpdateDisplayIndex(int32_t displayIndex)1267 void LayoutProperty::UpdateDisplayIndex(int32_t displayIndex)
1268 {
1269     if (!flexItemProperty_) {
1270         flexItemProperty_ = std::make_unique<FlexItemProperty>();
1271     }
1272     if (flexItemProperty_->UpdateDisplayIndex(displayIndex)) {
1273         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
1274         auto host = GetHost();
1275         CHECK_NULL_VOID(host);
1276         auto parent = host->GetAncestorNodeOfFrame();
1277         CHECK_NULL_VOID(parent);
1278         const auto& children = parent->GetChildren();
1279         CHECK_EQUAL_VOID(children.empty(), true);
1280         for (const auto& child : children) {
1281             auto childFrameNode = AceType::DynamicCast<NG::FrameNode>(child);
1282             CHECK_NULL_CONTINUE(childFrameNode);
1283             auto layoutProperty = childFrameNode->GetLayoutProperty();
1284             CHECK_NULL_CONTINUE(layoutProperty);
1285             layoutProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE_SELF);
1286         }
1287     }
1288 }
1289 
CreateContentConstraint() const1290 LayoutConstraintF LayoutProperty::CreateContentConstraint() const
1291 {
1292     auto layoutConstraint = contentConstraint_.value_or(LayoutConstraintF());
1293     layoutConstraint.maxSize.UpdateSizeWhenSmaller(layoutConstraint.selfIdealSize.ConvertToSizeT());
1294     return layoutConstraint;
1295 }
1296 
UpdateLayoutConstraint(const RefPtr<LayoutProperty> & layoutProperty)1297 void LayoutProperty::UpdateLayoutConstraint(const RefPtr<LayoutProperty>& layoutProperty)
1298 {
1299     layoutConstraint_ = layoutProperty->layoutConstraint_;
1300     contentConstraint_ = layoutProperty->contentConstraint_;
1301     gridProperty_ =
1302         (layoutProperty->gridProperty_) ? std::make_unique<GridProperty>(*layoutProperty->gridProperty_) : nullptr;
1303 }
1304 
UpdateVisibility(const VisibleType & value,bool allowTransition)1305 void LayoutProperty::UpdateVisibility(const VisibleType& value, bool allowTransition)
1306 {
1307     if (propVisibility_.has_value()) {
1308         if (NearEqual(propVisibility_.value(), value)) {
1309             return;
1310         }
1311     }
1312     OnVisibilityUpdate(value, allowTransition);
1313 }
1314 
SetOverlayOffset(const std::optional<Dimension> & overlayOffsetX,const std::optional<Dimension> & overlayOffsetY)1315 void LayoutProperty::SetOverlayOffset(
1316     const std::optional<Dimension>& overlayOffsetX, const std::optional<Dimension>& overlayOffsetY)
1317 {
1318     bool xChanged = true;
1319     bool yChanged = false;
1320     if ((!overlayOffsetX.has_value() && overlayOffsetX_.Value() == 0) ||
1321         (overlayOffsetX.has_value() && overlayOffsetX.value() == overlayOffsetX_)) {
1322         xChanged = false;
1323     }
1324 
1325     if ((!overlayOffsetY.has_value() && overlayOffsetY_.Value() == 0) ||
1326         (overlayOffsetY.has_value() && overlayOffsetY.value() == overlayOffsetY_)) {
1327         yChanged = false;
1328     }
1329 
1330     if (!xChanged && !yChanged) {
1331         return;
1332     }
1333 
1334     if (overlayOffsetX.has_value()) {
1335         overlayOffsetX_ = overlayOffsetX.value();
1336     } else {
1337         overlayOffsetX_.Reset();
1338     }
1339 
1340     if (overlayOffsetY.has_value()) {
1341         overlayOffsetY_ = overlayOffsetY.value();
1342     } else {
1343         overlayOffsetY_.Reset();
1344     }
1345 
1346     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
1347 }
1348 
GetOverlayOffset(Dimension & overlayOffsetX,Dimension & overlayOffsetY)1349 void LayoutProperty::GetOverlayOffset(Dimension& overlayOffsetX, Dimension& overlayOffsetY)
1350 {
1351     overlayOffsetX = overlayOffsetX_;
1352     overlayOffsetY = overlayOffsetY_;
1353 }
1354 
UpdateAllGeometryTransition(const RefPtr<UINode> & parent)1355 void LayoutProperty::UpdateAllGeometryTransition(const RefPtr<UINode>& parent)
1356 {
1357     std::queue<RefPtr<UINode>> q;
1358     q.push(parent);
1359     while (!q.empty()) {
1360         auto node = q.front();
1361         q.pop();
1362         auto frameNode = AceType::DynamicCast<FrameNode>(node);
1363         if (frameNode) {
1364             auto layoutProperty = frameNode->GetLayoutProperty();
1365             if (layoutProperty && layoutProperty->GetGeometryTransition()) {
1366                 auto geometryTransitionId = layoutProperty->GetGeometryTransition()->GetId();
1367                 layoutProperty->UpdateGeometryTransition("");
1368                 layoutProperty->UpdateGeometryTransition(geometryTransitionId);
1369             }
1370         }
1371         const auto& children = node->GetChildren();
1372         for (const auto& child : children) {
1373             q.push(child);
1374         }
1375     }
1376 }
1377 
GetPercentSensitive()1378 std::pair<bool, bool> LayoutProperty::GetPercentSensitive()
1379 {
1380     if (!contentConstraint_.has_value()) {
1381         return { false, false };
1382     }
1383     std::pair<bool, bool> res = { false, false };
1384     const auto& constraint = contentConstraint_.value();
1385     if (GreaterOrEqualToInfinity(constraint.maxSize.Height())) {
1386         if (calcLayoutConstraint_ && calcLayoutConstraint_->PercentHeight()) {
1387             res.second = true;
1388         }
1389     }
1390     if (GreaterOrEqualToInfinity(constraint.maxSize.Width())) {
1391         if (calcLayoutConstraint_ && calcLayoutConstraint_->PercentWidth()) {
1392             res.first = true;
1393         }
1394     }
1395     return res;
1396 }
1397 
UpdatePercentSensitive(bool width,bool height)1398 std::pair<bool, bool> LayoutProperty::UpdatePercentSensitive(bool width, bool height)
1399 {
1400     if (!contentConstraint_.has_value()) {
1401         return { false, false };
1402     }
1403     const auto& constraint = contentConstraint_.value();
1404     if (GreaterOrEqualToInfinity(constraint.maxSize.Height())) {
1405         heightPercentSensitive_ = heightPercentSensitive_ || height;
1406     }
1407     if (GreaterOrEqualToInfinity(constraint.maxSize.Width())) {
1408         widthPercentSensitive_ = heightPercentSensitive_ || width;
1409     }
1410     return { widthPercentSensitive_, heightPercentSensitive_ };
1411 }
1412 
ConstraintEqual(const std::optional<LayoutConstraintF> & preLayoutConstraint,const std::optional<LayoutConstraintF> & preContentConstraint)1413 bool LayoutProperty::ConstraintEqual(const std::optional<LayoutConstraintF>& preLayoutConstraint,
1414     const std::optional<LayoutConstraintF>& preContentConstraint)
1415 {
1416     if (!preLayoutConstraint || !layoutConstraint_) {
1417         return false;
1418     }
1419     if (!preContentConstraint || !contentConstraint_) {
1420         return false;
1421     }
1422     bool isNeedPercent = false;
1423     auto host = GetHost();
1424     if (host) {
1425         auto pattern = host->GetPattern();
1426         isNeedPercent = pattern ? pattern->IsNeedPercent() : false;
1427     }
1428     const auto& layout = layoutConstraint_.value();
1429     const auto& content = contentConstraint_.value();
1430     if (!isNeedPercent && GreaterOrEqualToInfinity(layout.maxSize.Width()) && !widthPercentSensitive_) {
1431         return (layout.EqualWithoutPercentWidth(preLayoutConstraint.value()) &&
1432             content.EqualWithoutPercentWidth(preContentConstraint.value()));
1433     }
1434     if (!isNeedPercent && GreaterOrEqualToInfinity(layout.maxSize.Height()) && !heightPercentSensitive_) {
1435         return (layout.EqualWithoutPercentHeight(preLayoutConstraint.value()) &&
1436             content.EqualWithoutPercentHeight(preContentConstraint.value()));
1437     }
1438     return (preLayoutConstraint == layoutConstraint_ && preContentConstraint == contentConstraint_);
1439 }
1440 
CheckPositionLocalizedEdges(TextDirection layoutDirection)1441 void LayoutProperty::CheckPositionLocalizedEdges(TextDirection layoutDirection)
1442 {
1443     auto host = GetHost();
1444     CHECK_NULL_VOID(host);
1445     const auto& target = host->GetRenderContext();
1446     CHECK_NULL_VOID(target);
1447     EdgesParam edges;
1448     auto positionEdges = target->GetPositionEdgesValue(EdgesParam {});
1449     if (positionEdges.top.has_value()) {
1450         edges.SetTop(positionEdges.top.value_or(Dimension(0.0)));
1451     }
1452     if (positionEdges.bottom.has_value()) {
1453         edges.SetBottom(positionEdges.bottom.value_or(Dimension(0.0)));
1454     }
1455     if (positionEdges.left.has_value()) {
1456         if (layoutDirection == TextDirection::RTL) {
1457             edges.SetRight(positionEdges.left.value_or(Dimension(0.0)));
1458         } else {
1459             edges.SetLeft(positionEdges.left.value_or(Dimension(0.0)));
1460         }
1461     }
1462     if (positionEdges.right.has_value()) {
1463         if (layoutDirection == TextDirection::RTL) {
1464             edges.SetLeft(positionEdges.right.value_or(Dimension(0.0)));
1465         } else {
1466             edges.SetRight(positionEdges.right.value_or(Dimension(0.0)));
1467         }
1468     }
1469     target->UpdatePositionEdges(edges);
1470 }
1471 
CheckMarkAnchorPosition(TextDirection layoutDirection)1472 void LayoutProperty::CheckMarkAnchorPosition(TextDirection layoutDirection)
1473 {
1474     auto host = GetHost();
1475     CHECK_NULL_VOID(host);
1476     const auto& target = host->GetRenderContext();
1477     CHECK_NULL_VOID(target);
1478     CalcDimension x;
1479     CalcDimension y;
1480     auto anchor = target->GetAnchorValue({});
1481     x = layoutDirection == TextDirection::RTL ? -anchor.GetX() : anchor.GetX();
1482     y = anchor.GetY();
1483     target->UpdateAnchor({ x, y });
1484 }
1485 
CheckOffsetLocalizedEdges(TextDirection layoutDirection)1486 void LayoutProperty::CheckOffsetLocalizedEdges(TextDirection layoutDirection)
1487 {
1488     auto host = GetHost();
1489     CHECK_NULL_VOID(host);
1490     const auto& target = host->GetRenderContext();
1491     CHECK_NULL_VOID(target);
1492     EdgesParam edges;
1493     auto offsetEdges = target->GetOffsetEdgesValue(EdgesParam {});
1494     if (offsetEdges.top.has_value()) {
1495         edges.SetTop(offsetEdges.top.value_or(Dimension(0.0)));
1496     }
1497     if (offsetEdges.bottom.has_value()) {
1498         edges.SetBottom(offsetEdges.bottom.value_or(Dimension(0.0)));
1499     }
1500     if (offsetEdges.left.has_value()) {
1501         if (layoutDirection == TextDirection::RTL) {
1502             edges.SetRight(offsetEdges.left.value_or(Dimension(0.0)));
1503         } else {
1504             edges.SetLeft(offsetEdges.left.value_or(Dimension(0.0)));
1505         }
1506     }
1507     if (offsetEdges.right.has_value()) {
1508         if (layoutDirection == TextDirection::RTL) {
1509             edges.SetLeft(offsetEdges.right.value_or(Dimension(0.0)));
1510         } else {
1511             edges.SetRight(offsetEdges.right.value_or(Dimension(0.0)));
1512         }
1513     }
1514     target->UpdateOffsetEdges(edges);
1515 }
1516 
CheckLocalizedBorderRadiuses(const TextDirection & direction)1517 void LayoutProperty::CheckLocalizedBorderRadiuses(const TextDirection& direction)
1518 {
1519     auto host = GetHost();
1520     CHECK_NULL_VOID(host);
1521     const auto& target = host->GetRenderContext();
1522     CHECK_NULL_VOID(target);
1523     BorderRadiusProperty borderRadius;
1524     BorderRadiusProperty borderRadiusProperty = target->GetBorderRadiusValue(BorderRadiusProperty {});
1525     if (!borderRadiusProperty.radiusTopStart.has_value() && !borderRadiusProperty.radiusTopEnd.has_value() &&
1526         !borderRadiusProperty.radiusBottomStart.has_value() && !borderRadiusProperty.radiusBottomEnd.has_value()) {
1527         return;
1528     }
1529     if (borderRadiusProperty.radiusTopStart.has_value()) {
1530         borderRadius.radiusTopStart = borderRadiusProperty.radiusTopStart;
1531         if (direction == TextDirection::RTL) {
1532             borderRadius.radiusTopRight = borderRadiusProperty.radiusTopStart;
1533         } else {
1534             borderRadius.radiusTopLeft = borderRadiusProperty.radiusTopStart;
1535         }
1536     }
1537     if (borderRadiusProperty.radiusTopEnd.has_value()) {
1538         borderRadius.radiusTopEnd = borderRadiusProperty.radiusTopEnd;
1539         if (direction == TextDirection::RTL) {
1540             borderRadius.radiusTopLeft = borderRadiusProperty.radiusTopEnd;
1541         } else {
1542             borderRadius.radiusTopRight = borderRadiusProperty.radiusTopEnd;
1543         }
1544     }
1545     if (borderRadiusProperty.radiusBottomStart.has_value()) {
1546         borderRadius.radiusBottomStart = borderRadiusProperty.radiusBottomStart;
1547         if (direction == TextDirection::RTL) {
1548             borderRadius.radiusBottomRight = borderRadiusProperty.radiusBottomStart;
1549         } else {
1550             borderRadius.radiusBottomLeft = borderRadiusProperty.radiusBottomStart;
1551         }
1552     }
1553     if (borderRadiusProperty.radiusBottomEnd.has_value()) {
1554         borderRadius.radiusBottomEnd = borderRadiusProperty.radiusBottomEnd;
1555         if (direction == TextDirection::RTL) {
1556             borderRadius.radiusBottomLeft = borderRadiusProperty.radiusBottomEnd;
1557         } else {
1558             borderRadius.radiusBottomRight = borderRadiusProperty.radiusBottomEnd;
1559         }
1560     }
1561     target->UpdateBorderRadius(borderRadius);
1562 }
1563 
CheckLocalizedOuterBorderColor(const TextDirection & direction)1564 void LayoutProperty::CheckLocalizedOuterBorderColor(const TextDirection& direction)
1565 {
1566     auto host = GetHost();
1567     CHECK_NULL_VOID(host);
1568     const auto& target = host->GetRenderContext();
1569     CHECK_NULL_VOID(target);
1570     NG::BorderColorProperty borderColors;
1571     borderColors.multiValued = true;
1572     auto outerBorderColorProperty = target->GetOuterBorderColorValue(BorderColorProperty {});
1573     if (!outerBorderColorProperty.startColor.has_value() && !outerBorderColorProperty.endColor.has_value()) {
1574         return;
1575     }
1576     if (outerBorderColorProperty.startColor.has_value()) {
1577         borderColors.startColor = outerBorderColorProperty.startColor;
1578         if (direction == TextDirection::RTL) {
1579             borderColors.rightColor = outerBorderColorProperty.startColor;
1580         } else {
1581             borderColors.leftColor = outerBorderColorProperty.startColor;
1582         }
1583     }
1584     if (outerBorderColorProperty.endColor.has_value()) {
1585         borderColors.endColor = outerBorderColorProperty.endColor;
1586         if (direction == TextDirection::RTL) {
1587             borderColors.leftColor = outerBorderColorProperty.endColor;
1588         } else {
1589             borderColors.rightColor = outerBorderColorProperty.endColor;
1590         }
1591     }
1592     if (outerBorderColorProperty.topColor.has_value()) {
1593         borderColors.topColor = outerBorderColorProperty.topColor;
1594     }
1595     if (outerBorderColorProperty.bottomColor.has_value()) {
1596         borderColors.bottomColor = outerBorderColorProperty.bottomColor;
1597     }
1598     target->UpdateOuterBorderColor(borderColors);
1599 }
1600 
CheckLocalizedPadding(const RefPtr<LayoutProperty> & layoutProperty,const TextDirection & direction)1601 void LayoutProperty::CheckLocalizedPadding(const RefPtr<LayoutProperty>& layoutProperty, const TextDirection& direction)
1602 {
1603     CHECK_NULL_VOID(layoutProperty);
1604     const auto& paddingProperty = layoutProperty->GetPaddingProperty();
1605     CHECK_NULL_VOID(paddingProperty);
1606     if (!paddingProperty->start.has_value() && !paddingProperty->end.has_value()) {
1607         return;
1608     }
1609     PaddingProperty padding;
1610     if (paddingProperty->start.has_value()) {
1611         padding.start = paddingProperty->start;
1612         if (direction == TextDirection::RTL) {
1613             padding.right = paddingProperty->start;
1614         } else {
1615             padding.left = paddingProperty->start;
1616         }
1617     }
1618     if (paddingProperty->end.has_value()) {
1619         padding.end = paddingProperty->end;
1620         if (direction == TextDirection::RTL) {
1621             padding.left = paddingProperty->end;
1622         } else {
1623             padding.right = paddingProperty->end;
1624         }
1625     }
1626     if (paddingProperty->top.has_value()) {
1627         padding.top = paddingProperty->top;
1628     }
1629     if (paddingProperty->bottom.has_value()) {
1630         padding.bottom = paddingProperty->bottom;
1631     }
1632     if (padding.left.has_value() && !padding.right.has_value()) {
1633         padding.right = std::optional<CalcLength>(CalcLength(0));
1634     }
1635     if (!padding.left.has_value() && padding.right.has_value()) {
1636         padding.left = std::optional<CalcLength>(CalcLength(0));
1637     }
1638     LocalizedPaddingOrMarginChange(padding, padding_);
1639 }
1640 
CheckLocalizedMargin(const RefPtr<LayoutProperty> & layoutProperty,const TextDirection & direction)1641 void LayoutProperty::CheckLocalizedMargin(const RefPtr<LayoutProperty>& layoutProperty, const TextDirection& direction)
1642 {
1643     CHECK_NULL_VOID(layoutProperty);
1644     const auto& marginProperty = layoutProperty->GetMarginProperty();
1645     CHECK_NULL_VOID(marginProperty);
1646     if (!marginProperty->start.has_value() && !marginProperty->end.has_value()) {
1647         return;
1648     }
1649     MarginProperty margin;
1650     if (marginProperty->start.has_value()) {
1651         margin.start = marginProperty->start;
1652         if (direction == TextDirection::RTL) {
1653             margin.right = marginProperty->start;
1654         } else {
1655             margin.left = marginProperty->start;
1656         }
1657     }
1658     if (marginProperty->end.has_value()) {
1659         margin.end = marginProperty->end;
1660         if (direction == TextDirection::RTL) {
1661             margin.left = marginProperty->end;
1662         } else {
1663             margin.right = marginProperty->end;
1664         }
1665     }
1666     if (marginProperty->top.has_value()) {
1667         margin.top = marginProperty->top;
1668     }
1669     if (marginProperty->bottom.has_value()) {
1670         margin.bottom = marginProperty->bottom;
1671     }
1672     if (margin.left.has_value() && !margin.right.has_value()) {
1673         margin.right = std::optional<CalcLength>(CalcLength(0));
1674     }
1675     if (!margin.left.has_value() && margin.right.has_value()) {
1676         margin.left = std::optional<CalcLength>(CalcLength(0));
1677     }
1678     LocalizedPaddingOrMarginChange(margin, margin_);
1679 }
1680 
CheckLocalizedSafeAreaPadding(const TextDirection & direction)1681 void LayoutProperty::CheckLocalizedSafeAreaPadding(const TextDirection& direction)
1682 {
1683     const auto& safeAreaPaddingProperty = GetSafeAreaPaddingProperty();
1684     CHECK_NULL_VOID(safeAreaPaddingProperty);
1685     if (!safeAreaPaddingProperty->start.has_value() && !safeAreaPaddingProperty->end.has_value()) {
1686         return;
1687     }
1688     PaddingProperty safeAreaPadding;
1689     if (safeAreaPaddingProperty->start.has_value()) {
1690         safeAreaPadding.start = safeAreaPaddingProperty->start;
1691         if (direction == TextDirection::RTL) {
1692             safeAreaPadding.right = safeAreaPaddingProperty->start;
1693         } else {
1694             safeAreaPadding.left = safeAreaPaddingProperty->start;
1695         }
1696     }
1697     if (safeAreaPaddingProperty->end.has_value()) {
1698         safeAreaPadding.end = safeAreaPaddingProperty->end;
1699         if (direction == TextDirection::RTL) {
1700             safeAreaPadding.left = safeAreaPaddingProperty->end;
1701         } else {
1702             safeAreaPadding.right = safeAreaPaddingProperty->end;
1703         }
1704     }
1705     if (safeAreaPaddingProperty->top.has_value()) {
1706         safeAreaPadding.top = safeAreaPaddingProperty->top;
1707     }
1708     if (safeAreaPaddingProperty->bottom.has_value()) {
1709         safeAreaPadding.bottom = safeAreaPaddingProperty->bottom;
1710     }
1711     if (safeAreaPadding.left.has_value() && !safeAreaPadding.right.has_value()) {
1712         safeAreaPadding.right = std::optional<CalcLength>(CalcLength(0));
1713     }
1714     if (!safeAreaPadding.left.has_value() && safeAreaPadding.right.has_value()) {
1715         safeAreaPadding.left = std::optional<CalcLength>(CalcLength(0));
1716     }
1717     LocalizedPaddingOrMarginChange(safeAreaPadding, safeAreaPadding_);
1718 }
1719 
LocalizedPaddingOrMarginChange(const PaddingProperty & value,std::unique_ptr<PaddingProperty> & padding)1720 void LayoutProperty::LocalizedPaddingOrMarginChange(
1721     const PaddingProperty& value, std::unique_ptr<PaddingProperty>& padding)
1722 {
1723     if (value != *padding || padding->start != value.start || padding->end != value.end) {
1724         padding->start = value.start;
1725         padding->end = value.end;
1726         padding->left = value.left;
1727         padding->right = value.right;
1728         padding->top = value.top;
1729         padding->bottom = value.bottom;
1730         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_LAYOUT | PROPERTY_UPDATE_MEASURE;
1731     }
1732 }
1733 
CheckLocalizedEdgeWidths(const RefPtr<LayoutProperty> & layoutProperty,const TextDirection & direction)1734 void LayoutProperty::CheckLocalizedEdgeWidths(
1735     const RefPtr<LayoutProperty>& layoutProperty, const TextDirection& direction)
1736 {
1737     CHECK_NULL_VOID(layoutProperty);
1738     auto host = GetHost();
1739     CHECK_NULL_VOID(host);
1740     const auto& target = host->GetRenderContext();
1741     CHECK_NULL_VOID(target);
1742     auto borderWidthProperty = target->GetBorderWidth();
1743     CHECK_NULL_VOID(borderWidthProperty);
1744     if (!borderWidthProperty->startDimen.has_value() && !borderWidthProperty->endDimen.has_value()) {
1745         return;
1746     }
1747     BorderWidthProperty borderWidth;
1748     if (borderWidthProperty->startDimen.has_value()) {
1749         borderWidth.startDimen = borderWidthProperty->startDimen;
1750         if (direction == TextDirection::RTL) {
1751             borderWidth.rightDimen = borderWidthProperty->startDimen;
1752         } else {
1753             borderWidth.leftDimen = borderWidthProperty->startDimen;
1754         }
1755     }
1756     if (borderWidthProperty->endDimen.has_value()) {
1757         borderWidth.endDimen = borderWidthProperty->endDimen;
1758         if (direction == TextDirection::RTL) {
1759             borderWidth.leftDimen = borderWidthProperty->endDimen;
1760         } else {
1761             borderWidth.rightDimen = borderWidthProperty->endDimen;
1762         }
1763     }
1764     if (borderWidthProperty->topDimen.has_value()) {
1765         borderWidth.topDimen = borderWidthProperty->topDimen;
1766     }
1767     if (borderWidthProperty->bottomDimen.has_value()) {
1768         borderWidth.bottomDimen = borderWidthProperty->bottomDimen;
1769     }
1770     if (borderWidth.leftDimen.has_value() && !borderWidth.rightDimen.has_value()) {
1771         borderWidth.rightDimen = std::optional<Dimension>(Dimension(0));
1772     }
1773     if (!borderWidth.leftDimen.has_value() && borderWidth.rightDimen.has_value()) {
1774         borderWidth.leftDimen = std::optional<Dimension>(Dimension(0));
1775     }
1776     borderWidth.multiValued = true;
1777     layoutProperty->UpdateBorderWidth(borderWidth);
1778     target->UpdateBorderWidth(borderWidth);
1779 }
1780 
CheckLocalizedEdgeColors(const TextDirection & direction)1781 void LayoutProperty::CheckLocalizedEdgeColors(const TextDirection& direction)
1782 {
1783     auto host = GetHost();
1784     CHECK_NULL_VOID(host);
1785     const auto& target = host->GetRenderContext();
1786     CHECK_NULL_VOID(target);
1787     BorderColorProperty borderColors;
1788     BorderColorProperty colorProperty = target->GetBorderColorValue(BorderColorProperty {});
1789     if (!colorProperty.startColor.has_value() && !colorProperty.endColor.has_value()) {
1790         return;
1791     }
1792     if (colorProperty.startColor.has_value()) {
1793         borderColors.startColor = colorProperty.startColor;
1794         if (direction == TextDirection::RTL) {
1795             borderColors.rightColor = colorProperty.startColor;
1796         } else {
1797             borderColors.leftColor = colorProperty.startColor;
1798         }
1799     }
1800     if (colorProperty.endColor.has_value()) {
1801         borderColors.endColor = colorProperty.endColor;
1802         if (direction == TextDirection::RTL) {
1803             borderColors.leftColor = colorProperty.endColor;
1804         } else {
1805             borderColors.rightColor = colorProperty.endColor;
1806         }
1807     }
1808     if (colorProperty.topColor.has_value()) {
1809         borderColors.topColor = colorProperty.topColor;
1810     }
1811     if (colorProperty.bottomColor.has_value()) {
1812         borderColors.topColor = colorProperty.bottomColor;
1813     }
1814     borderColors.multiValued = true;
1815     target->UpdateBorderColor(borderColors);
1816 }
1817 
CheckLocalizedBorderImageSlice(const TextDirection & direction)1818 void LayoutProperty::CheckLocalizedBorderImageSlice(const TextDirection& direction)
1819 {
1820     auto host = GetHost();
1821     CHECK_NULL_VOID(host);
1822     const auto& target = host->GetRenderContext();
1823     CHECK_NULL_VOID(target);
1824     auto borderImage = target->GetBorderImage();
1825     CHECK_NULL_VOID(borderImage);
1826     auto borderImageProperty = borderImage.value();
1827     CHECK_NULL_VOID(borderImageProperty);
1828     if (!borderImageProperty->borderImageStart_.has_value() && !borderImageProperty->borderImageEnd_.has_value()) {
1829         return;
1830     }
1831     Dimension leftSlice;
1832     Dimension rightSlice;
1833     Dimension startSlice;
1834     Dimension endSlice;
1835     if (borderImageProperty->borderImageStart_.has_value()) {
1836         startSlice = borderImageProperty->borderImageStart_->GetBorderImageSlice();
1837         borderImageProperty->SetEdgeSlice(BorderImageDirection::START, startSlice);
1838         if (direction == TextDirection::RTL) {
1839             rightSlice = borderImageProperty->borderImageStart_->GetBorderImageSlice();
1840         } else {
1841             leftSlice = borderImageProperty->borderImageStart_->GetBorderImageSlice();
1842         }
1843     }
1844     if (borderImageProperty->borderImageEnd_.has_value()) {
1845         endSlice = borderImageProperty->borderImageEnd_->GetBorderImageSlice();
1846         borderImageProperty->SetEdgeSlice(BorderImageDirection::END, endSlice);
1847         if (direction == TextDirection::RTL) {
1848             leftSlice = borderImageProperty->borderImageEnd_->GetBorderImageSlice();
1849         } else {
1850             rightSlice = borderImageProperty->borderImageEnd_->GetBorderImageSlice();
1851         }
1852     }
1853     borderImageProperty->SetEdgeSlice(BorderImageDirection::LEFT, leftSlice);
1854     borderImageProperty->SetEdgeSlice(BorderImageDirection::RIGHT, rightSlice);
1855     target->UpdateBorderImage(borderImageProperty);
1856 }
1857 
CheckLocalizedBorderImageWidth(const TextDirection & direction)1858 void LayoutProperty::CheckLocalizedBorderImageWidth(const TextDirection& direction)
1859 {
1860     auto host = GetHost();
1861     CHECK_NULL_VOID(host);
1862     const auto& target = host->GetRenderContext();
1863     CHECK_NULL_VOID(target);
1864     auto borderImage = target->GetBorderImage();
1865     CHECK_NULL_VOID(borderImage);
1866     auto borderImageProperty = borderImage.value();
1867     CHECK_NULL_VOID(borderImageProperty);
1868     if (!borderImageProperty->borderImageStart_.has_value() && !borderImageProperty->borderImageEnd_.has_value()) {
1869         return;
1870     }
1871     Dimension leftWidth;
1872     Dimension rightWidth;
1873     Dimension startWidth;
1874     Dimension endWidth;
1875     if (borderImageProperty->borderImageStart_.has_value()) {
1876         startWidth = borderImageProperty->borderImageStart_->GetBorderImageWidth();
1877         borderImageProperty->SetEdgeWidth(BorderImageDirection::START, startWidth);
1878         if (direction == TextDirection::RTL) {
1879             rightWidth = borderImageProperty->borderImageStart_->GetBorderImageWidth();
1880         } else {
1881             leftWidth = borderImageProperty->borderImageStart_->GetBorderImageWidth();
1882         }
1883     }
1884     if (borderImageProperty->borderImageEnd_.has_value()) {
1885         endWidth = borderImageProperty->borderImageEnd_->GetBorderImageWidth();
1886         borderImageProperty->SetEdgeWidth(BorderImageDirection::END, endWidth);
1887         if (direction == TextDirection::RTL) {
1888             leftWidth = borderImageProperty->borderImageEnd_->GetBorderImageWidth();
1889         } else {
1890             rightWidth = borderImageProperty->borderImageEnd_->GetBorderImageWidth();
1891         }
1892     }
1893     borderImageProperty->SetEdgeWidth(BorderImageDirection::LEFT, leftWidth);
1894     borderImageProperty->SetEdgeWidth(BorderImageDirection::RIGHT, rightWidth);
1895     target->UpdateBorderImage(borderImageProperty);
1896 }
1897 
CheckLocalizedBorderImageOutset(const TextDirection & direction)1898 void LayoutProperty::CheckLocalizedBorderImageOutset(const TextDirection& direction)
1899 {
1900     auto host = GetHost();
1901     CHECK_NULL_VOID(host);
1902     const auto& target = host->GetRenderContext();
1903     CHECK_NULL_VOID(target);
1904     auto borderImage = target->GetBorderImage();
1905     CHECK_NULL_VOID(borderImage);
1906     auto borderImageProperty = borderImage.value();
1907     CHECK_NULL_VOID(borderImageProperty);
1908     if (!borderImageProperty->borderImageStart_.has_value() && !borderImageProperty->borderImageEnd_.has_value()) {
1909         return;
1910     }
1911     Dimension leftOutset;
1912     Dimension rightOutset;
1913     Dimension startOutset;
1914     Dimension endOutset;
1915     if (borderImageProperty->borderImageStart_.has_value()) {
1916         startOutset = borderImageProperty->borderImageStart_->GetBorderImageOutset();
1917         borderImageProperty->SetEdgeOutset(BorderImageDirection::START, startOutset);
1918         if (direction == TextDirection::RTL) {
1919             rightOutset = borderImageProperty->borderImageStart_->GetBorderImageOutset();
1920         } else {
1921             leftOutset = borderImageProperty->borderImageStart_->GetBorderImageOutset();
1922         }
1923     }
1924     if (borderImageProperty->borderImageEnd_.has_value()) {
1925         endOutset = borderImageProperty->borderImageEnd_->GetBorderImageOutset();
1926         borderImageProperty->SetEdgeOutset(BorderImageDirection::END, endOutset);
1927         if (direction == TextDirection::RTL) {
1928             leftOutset = borderImageProperty->borderImageEnd_->GetBorderImageOutset();
1929         } else {
1930             rightOutset = borderImageProperty->borderImageEnd_->GetBorderImageOutset();
1931         }
1932     }
1933     borderImageProperty->SetEdgeOutset(BorderImageDirection::LEFT, leftOutset);
1934     borderImageProperty->SetEdgeOutset(BorderImageDirection::RIGHT, rightOutset);
1935     target->UpdateBorderImage(borderImageProperty);
1936 }
1937 } // namespace OHOS::Ace::NG
1938