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