• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/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_ng/base/frame_node.h"
23 #include "core/components_ng/base/ui_node.h"
24 #include "core/components_ng/property/calc_length.h"
25 #include "core/components_ng/property/layout_constraint.h"
26 #include "core/components_ng/property/measure_utils.h"
27 #include "core/components_v2/inspector/inspector_constants.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 
30 namespace OHOS::Ace::NG {
31 namespace {
VisibleTypeToString(VisibleType type)32 std::string VisibleTypeToString(VisibleType type)
33 {
34     static const LinearEnumMapNode<VisibleType, std::string> visibilityMap[] = {
35         { VisibleType::VISIBLE, "Visibility.Visible" },
36         { VisibleType::INVISIBLE, "Visibility.Hidden" },
37         { VisibleType::GONE, "Visibility.None" },
38     };
39     auto idx = BinarySearchFindIndex(visibilityMap, ArraySize(visibilityMap), type);
40     if (idx >= 0) {
41         return visibilityMap[idx].value;
42     }
43     return "Visibility.Visible";
44 }
45 
TextDirectionToString(TextDirection type)46 std::string TextDirectionToString(TextDirection type)
47 {
48     static const LinearEnumMapNode<TextDirection, std::string> toStringMap[] = {
49         { TextDirection::LTR, "Direction.Ltr" },
50         { TextDirection::RTL, "Direction.Rtl" },
51         { TextDirection::INHERIT, "Direction.Inherit" },
52         { TextDirection::AUTO, "Direction.Auto" },
53     };
54     auto idx = BinarySearchFindIndex(toStringMap, ArraySize(toStringMap), type);
55     if (idx >= 0) {
56         return toStringMap[idx].value;
57     }
58     return "Direction.Ltr";
59 }
60 } // namespace
61 
Reset()62 void LayoutProperty::Reset()
63 {
64     layoutConstraint_.reset();
65     calcLayoutConstraint_.reset();
66     padding_.reset();
67     margin_.reset();
68     borderWidth_.reset();
69     magicItemProperty_.reset();
70     positionProperty_.reset();
71     measureType_.reset();
72     layoutDirection_.reset();
73     propVisibility_.reset();
74     CleanDirty();
75 }
76 
ToJsonValue(std::unique_ptr<JsonValue> & json) const77 void LayoutProperty::ToJsonValue(std::unique_ptr<JsonValue>& json) const
78 {
79     ACE_PROPERTY_TO_JSON_VALUE(calcLayoutConstraint_, MeasureProperty);
80     ACE_PROPERTY_TO_JSON_VALUE(positionProperty_, PositionProperty);
81     ACE_PROPERTY_TO_JSON_VALUE(magicItemProperty_, MagicItemProperty);
82     ACE_PROPERTY_TO_JSON_VALUE(flexItemProperty_, FlexItemProperty);
83     ACE_PROPERTY_TO_JSON_VALUE(borderWidth_, BorderWidthProperty);
84     ACE_PROPERTY_TO_JSON_VALUE(gridProperty_, GridProperty);
85 
86     if (padding_) {
87         json->Put("padding", padding_->ToJsonString().c_str());
88     } else {
89         json->Put("padding", "0.00vp");
90     }
91 
92     if (margin_) {
93         json->Put("margin", margin_->ToJsonString().c_str());
94     } else {
95         json->Put("margin", "0.00vp");
96     }
97 
98     json->Put("visibility", VisibleTypeToString(propVisibility_.value_or(VisibleType::VISIBLE)).c_str());
99     json->Put("direction", TextDirectionToString(GetLayoutDirection()).c_str());
100 }
101 
Clone() const102 RefPtr<LayoutProperty> LayoutProperty::Clone() const
103 {
104     auto layoutProperty = MakeRefPtr<LayoutProperty>();
105     Clone(layoutProperty);
106     return layoutProperty;
107 }
108 
Clone(RefPtr<LayoutProperty> layoutProperty) const109 void LayoutProperty::Clone(RefPtr<LayoutProperty> layoutProperty) const
110 {
111     layoutProperty->UpdateLayoutProperty(this);
112 }
113 
UpdateLayoutProperty(const LayoutProperty * layoutProperty)114 void LayoutProperty::UpdateLayoutProperty(const LayoutProperty* layoutProperty)
115 {
116     layoutConstraint_ = layoutProperty->layoutConstraint_;
117     if (layoutProperty->gridProperty_) {
118         gridProperty_ = std::make_unique<GridProperty>(*layoutProperty->gridProperty_);
119     }
120     if (layoutProperty->calcLayoutConstraint_) {
121         calcLayoutConstraint_ = std::make_unique<MeasureProperty>(*layoutProperty->calcLayoutConstraint_);
122     }
123     if (layoutProperty->padding_) {
124         padding_ = std::make_unique<PaddingProperty>(*layoutProperty->padding_);
125     }
126     if (layoutProperty->margin_) {
127         margin_ = std::make_unique<PaddingProperty>(*layoutProperty->margin_);
128     }
129     if (layoutProperty->borderWidth_) {
130         borderWidth_ = std::make_unique<BorderWidthProperty>(*layoutProperty->borderWidth_);
131     }
132     if (layoutProperty->magicItemProperty_) {
133         magicItemProperty_ = std::make_unique<MagicItemProperty>(*layoutProperty->magicItemProperty_);
134     }
135     if (layoutProperty->positionProperty_) {
136         positionProperty_ = std::make_unique<PositionProperty>(*layoutProperty->positionProperty_);
137     }
138     if (layoutProperty->flexItemProperty_) {
139         flexItemProperty_ = std::make_unique<FlexItemProperty>(*layoutProperty->flexItemProperty_);
140     }
141     propVisibility_ = layoutProperty->GetVisibility();
142     measureType_ = layoutProperty->measureType_;
143     layoutDirection_ = layoutProperty->layoutDirection_;
144     propertyChangeFlag_ = layoutProperty->propertyChangeFlag_;
145 }
146 
UpdateCalcLayoutProperty(const MeasureProperty & constraint)147 void LayoutProperty::UpdateCalcLayoutProperty(const MeasureProperty& constraint)
148 {
149     if (!calcLayoutConstraint_) {
150         calcLayoutConstraint_ = std::make_unique<MeasureProperty>(constraint);
151         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
152         return;
153     }
154     if (*calcLayoutConstraint_ == constraint) {
155         return;
156     }
157     calcLayoutConstraint_->selfIdealSize = constraint.selfIdealSize;
158     calcLayoutConstraint_->maxSize = constraint.maxSize;
159     calcLayoutConstraint_->minSize = constraint.minSize;
160     propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
161 }
162 
UpdateLayoutConstraint(const LayoutConstraintF & parentConstraint)163 void LayoutProperty::UpdateLayoutConstraint(const LayoutConstraintF& parentConstraint)
164 {
165     layoutConstraint_ = parentConstraint;
166     if (margin_) {
167         // TODO: add margin is negative case.
168         auto margin = CreateMargin();
169         MinusPaddingToSize(margin, layoutConstraint_->maxSize);
170         MinusPaddingToSize(margin, layoutConstraint_->minSize);
171         MinusPaddingToSize(margin, layoutConstraint_->percentReference);
172         MinusPaddingToSize(margin, layoutConstraint_->selfIdealSize);
173         MinusPaddingToSize(margin, layoutConstraint_->parentIdealSize);
174     }
175     if (calcLayoutConstraint_) {
176         if (calcLayoutConstraint_->maxSize.has_value()) {
177             layoutConstraint_->UpdateMaxSizeWithCheck(ConvertToSize(calcLayoutConstraint_->maxSize.value(),
178                 parentConstraint.scaleProperty, parentConstraint.percentReference));
179         }
180         if (calcLayoutConstraint_->minSize.has_value()) {
181             layoutConstraint_->UpdateMinSizeWithCheck(ConvertToSize(calcLayoutConstraint_->minSize.value(),
182                 parentConstraint.scaleProperty, parentConstraint.percentReference));
183         }
184         if (calcLayoutConstraint_->selfIdealSize.has_value()) {
185             LOGD("CalcLayoutConstraint->selfIdealSize = %{public}s",
186                 calcLayoutConstraint_->selfIdealSize.value().ToString().c_str());
187             layoutConstraint_->UpdateIllegalSelfIdealSizeWithCheck(
188                 ConvertToOptionalSize(calcLayoutConstraint_->selfIdealSize.value(), parentConstraint.scaleProperty,
189                     parentConstraint.percentReference));
190         }
191     }
192 
193     CheckSelfIdealSize();
194     CheckBorderAndPadding();
195     CheckAspectRatio();
196 }
197 
CheckBorderAndPadding()198 void LayoutProperty::CheckBorderAndPadding()
199 {
200     auto selfWidth = layoutConstraint_->selfIdealSize.Width();
201     auto selfHeight = layoutConstraint_->selfIdealSize.Height();
202     if (!selfWidth && !selfHeight) {
203         return;
204     }
205     auto selfWidthFloat = selfWidth.value_or(Infinity<float>());
206     auto selfHeightFloat = selfHeight.value_or(Infinity<float>());
207     auto paddingWithBorder = CreatePaddingAndBorder();
208     auto deflateWidthF = paddingWithBorder.Width();
209     auto deflateHeightF = paddingWithBorder.Height();
210     if (LessOrEqual(deflateWidthF, selfWidthFloat) && LessOrEqual(deflateHeightF, selfHeightFloat)) {
211         return;
212     }
213     if (GreatNotEqual(deflateWidthF, selfWidthFloat)) {
214         layoutConstraint_->selfIdealSize.SetWidth(deflateWidthF);
215     }
216     if (GreatNotEqual(deflateHeightF, selfHeightFloat)) {
217         layoutConstraint_->selfIdealSize.SetHeight(deflateHeightF);
218     }
219 }
220 
CheckAspectRatio()221 void LayoutProperty::CheckAspectRatio()
222 {
223     auto hasAspectRatio = magicItemProperty_ ? magicItemProperty_->HasAspectRatio() : false;
224     if (!hasAspectRatio) {
225         return;
226     }
227     auto aspectRatio = magicItemProperty_->GetAspectRatioValue();
228     // Adjust by aspect ratio, firstly pick height based on width. It means that when width, height and aspectRatio are
229     // all set, the height is not used.
230     auto maxWidth = layoutConstraint_->maxSize.Width();
231     auto maxHeight = layoutConstraint_->maxSize.Height();
232     if (maxHeight > maxWidth / aspectRatio) {
233         maxHeight = maxWidth / aspectRatio;
234     }
235     layoutConstraint_->maxSize.SetWidth(maxWidth);
236     layoutConstraint_->maxSize.SetHeight(maxHeight);
237     std::optional<float> selfWidth;
238     std::optional<float> selfHeight;
239     if (layoutConstraint_->selfIdealSize.Width()) {
240         selfWidth = layoutConstraint_->selfIdealSize.Width().value();
241         selfHeight = selfWidth.value() / aspectRatio;
242         if (selfHeight > maxHeight) {
243             selfHeight = maxHeight;
244             selfWidth = selfHeight.value() * aspectRatio;
245         }
246     } else if (layoutConstraint_->selfIdealSize.Height()) {
247         selfHeight = layoutConstraint_->selfIdealSize.Height().value();
248         selfWidth = selfHeight.value() * aspectRatio;
249         if (selfWidth > maxWidth) {
250             selfWidth = maxWidth;
251             selfHeight = selfWidth.value() / aspectRatio;
252         }
253     }
254 
255     if (selfHeight) {
256         layoutConstraint_->selfIdealSize.SetHeight(selfHeight);
257     }
258     if (selfWidth) {
259         layoutConstraint_->selfIdealSize.SetWidth(selfWidth);
260     }
261     // TODO: after measure done, need to check AspectRatio again.
262 }
263 
BuildGridProperty(const RefPtr<FrameNode> & host)264 void LayoutProperty::BuildGridProperty(const RefPtr<FrameNode>& host)
265 {
266     CHECK_NULL_VOID_NOLOG(gridProperty_);
267     auto parent = host->GetAncestorNodeOfFrame();
268     while (parent) {
269         if (parent->GetTag() == V2::GRIDCONTAINER_ETS_TAG) {
270             auto containerLayout = parent->GetLayoutProperty();
271             gridProperty_->UpdateContainer(containerLayout, host);
272             UpdateUserDefinedIdealSize(CalcSize(CalcLength(gridProperty_->GetWidth()), std::nullopt));
273             break;
274         }
275         parent = parent->GetAncestorNodeOfFrame();
276     }
277 }
278 
UpdateGridProperty(std::optional<int32_t> span,std::optional<int32_t> offset,GridSizeType type)279 void LayoutProperty::UpdateGridProperty(std::optional<int32_t> span, std::optional<int32_t> offset, GridSizeType type)
280 {
281     if (!gridProperty_) {
282         gridProperty_ = std::make_unique<GridProperty>();
283     }
284 
285     bool isSpanUpdated = (span.has_value() && gridProperty_->UpdateSpan(span.value(), type));
286     bool isOffsetUpdated = (offset.has_value() && gridProperty_->UpdateOffset(offset.value(), type));
287     if (isSpanUpdated || isOffsetUpdated) {
288         propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE;
289     }
290 }
291 
UpdateGridOffset(const RefPtr<FrameNode> & host)292 bool LayoutProperty::UpdateGridOffset(const RefPtr<FrameNode>& host)
293 {
294     CHECK_NULL_RETURN_NOLOG(gridProperty_, false);
295     auto optOffset = gridProperty_->GetOffset();
296     if (optOffset == UNDEFINED_DIMENSION) {
297         return false;
298     }
299 
300     RefPtr<FrameNode> parent = host->GetAncestorNodeOfFrame();
301     auto parentOffset = parent->GetOffsetRelativeToWindow();
302     auto globalOffset = gridProperty_->GetContainerPosition();
303 
304     OffsetF offset(optOffset.ConvertToPx(), 0);
305     offset = offset + globalOffset - parentOffset;
306     const auto& geometryNode = host->GetGeometryNode();
307     if (offset.GetX() == geometryNode->GetFrameOffset().GetX()) {
308         return false;
309     }
310     offset.SetY(geometryNode->GetFrameOffset().GetY());
311     geometryNode->SetFrameOffset(offset);
312     return true;
313 }
314 
CheckSelfIdealSize()315 void LayoutProperty::CheckSelfIdealSize()
316 {
317     if (measureType_ == MeasureType::MATCH_PARENT) {
318         layoutConstraint_->UpdateIllegalSelfIdealSizeWithCheck(layoutConstraint_->parentIdealSize);
319     }
320     if (!calcLayoutConstraint_) {
321         return;
322     }
323     if (calcLayoutConstraint_->minSize.has_value()) {
324         layoutConstraint_->selfIdealSize.UpdateSizeWhenLarger(ConvertToSize(calcLayoutConstraint_->minSize.value(),
325             layoutConstraint_->scaleProperty, layoutConstraint_->percentReference));
326     }
327     if (calcLayoutConstraint_->maxSize.has_value()) {
328         layoutConstraint_->selfIdealSize.UpdateSizeWhenSmaller(ConvertToSize(calcLayoutConstraint_->maxSize.value(),
329             layoutConstraint_->scaleProperty, layoutConstraint_->percentReference));
330     }
331 }
332 
CreateChildConstraint() const333 LayoutConstraintF LayoutProperty::CreateChildConstraint() const
334 {
335     CHECK_NULL_RETURN(layoutConstraint_, {});
336     auto layoutConstraint = contentConstraint_.value();
337     layoutConstraint.parentIdealSize = layoutConstraint.selfIdealSize;
338     // update max size when ideal size has value.
339     if (layoutConstraint.parentIdealSize.Width()) {
340         layoutConstraint.maxSize.SetWidth(layoutConstraint.parentIdealSize.Width().value());
341         layoutConstraint.percentReference.SetWidth(layoutConstraint.parentIdealSize.Width().value());
342     }
343     if (layoutConstraint.parentIdealSize.Height()) {
344         layoutConstraint.maxSize.SetHeight(layoutConstraint.parentIdealSize.Height().value());
345         layoutConstraint.percentReference.SetHeight(layoutConstraint.parentIdealSize.Height().value());
346     }
347     // for child constraint, reset current selfIdealSize and minSize.
348     layoutConstraint.selfIdealSize.Reset();
349     layoutConstraint.minSize.Reset();
350     return layoutConstraint;
351 }
352 
UpdateContentConstraint()353 void LayoutProperty::UpdateContentConstraint()
354 {
355     CHECK_NULL_VOID(layoutConstraint_);
356     contentConstraint_ = layoutConstraint_.value();
357     // update percent reference when parent has size.
358     if (contentConstraint_->parentIdealSize.Width()) {
359         contentConstraint_->percentReference.SetWidth(contentConstraint_->parentIdealSize.Width().value());
360     }
361     if (contentConstraint_->parentIdealSize.Height()) {
362         contentConstraint_->percentReference.SetHeight(contentConstraint_->parentIdealSize.Height().value());
363     }
364     if (padding_) {
365         auto paddingF = ConvertToPaddingPropertyF(
366             *padding_, contentConstraint_->scaleProperty, contentConstraint_->percentReference.Width());
367         contentConstraint_->MinusPaddingOnBothSize(paddingF.left, paddingF.right, paddingF.top, paddingF.bottom);
368     }
369     if (borderWidth_) {
370         auto borderWidthF = ConvertToBorderWidthPropertyF(
371             *borderWidth_, contentConstraint_->scaleProperty, contentConstraint_->percentReference.Width());
372         contentConstraint_->MinusPaddingOnBothSize(
373             borderWidthF.leftDimen, borderWidthF.rightDimen, borderWidthF.topDimen, borderWidthF.bottomDimen);
374     }
375 }
376 
CreatePaddingAndBorder()377 PaddingPropertyF LayoutProperty::CreatePaddingAndBorder()
378 {
379     if (layoutConstraint_.has_value()) {
380         auto padding = ConvertToPaddingPropertyF(
381             padding_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
382         auto borderWidth = ConvertToBorderWidthPropertyF(
383             borderWidth_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
384 
385         return PaddingPropertyF { padding.left.value_or(0) + borderWidth.leftDimen.value_or(0),
386             padding.right.value_or(0) + borderWidth.rightDimen.value_or(0),
387             padding.top.value_or(0) + borderWidth.topDimen.value_or(0),
388             padding.bottom.value_or(0) + borderWidth.bottomDimen.value_or(0) };
389     }
390     auto padding = ConvertToPaddingPropertyF(
391         padding_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
392     auto borderWidth = ConvertToBorderWidthPropertyF(
393         borderWidth_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
394 
395     return PaddingPropertyF { padding.left.value_or(0) + borderWidth.leftDimen.value_or(0),
396         padding.right.value_or(0) + borderWidth.rightDimen.value_or(0),
397         padding.top.value_or(0) + borderWidth.topDimen.value_or(0),
398         padding.bottom.value_or(0) + borderWidth.bottomDimen.value_or(0) };
399 }
400 
CreatePaddingAndBorderWithDefault(float paddingHorizontalDefault,float paddingVerticalDefault,float borderHorizontalDefault,float borderVerticalDefault)401 PaddingPropertyF LayoutProperty::CreatePaddingAndBorderWithDefault(float paddingHorizontalDefault,
402     float paddingVerticalDefault, float borderHorizontalDefault, float borderVerticalDefault)
403 {
404     if (layoutConstraint_.has_value()) {
405         auto padding = ConvertToPaddingPropertyF(
406             padding_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
407         auto borderWidth = ConvertToBorderWidthPropertyF(
408             borderWidth_, ScaleProperty::CreateScaleProperty(), layoutConstraint_->percentReference.Width());
409         return PaddingPropertyF { padding.left.value_or(paddingHorizontalDefault) +
410                                       borderWidth.leftDimen.value_or(borderHorizontalDefault),
411             padding.right.value_or(paddingHorizontalDefault) + borderWidth.rightDimen.value_or(borderHorizontalDefault),
412             padding.top.value_or(paddingVerticalDefault) + borderWidth.topDimen.value_or(borderVerticalDefault),
413             padding.bottom.value_or(paddingVerticalDefault) + borderWidth.bottomDimen.value_or(borderVerticalDefault) };
414     }
415     auto padding = ConvertToPaddingPropertyF(
416         padding_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
417     auto borderWidth = ConvertToBorderWidthPropertyF(
418         borderWidth_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
419 
420     return PaddingPropertyF { padding.left.value_or(paddingHorizontalDefault) +
421                                   borderWidth.leftDimen.value_or(borderHorizontalDefault),
422         padding.right.value_or(paddingHorizontalDefault) + borderWidth.rightDimen.value_or(borderHorizontalDefault),
423         padding.top.value_or(paddingVerticalDefault) + borderWidth.topDimen.value_or(borderVerticalDefault),
424         padding.bottom.value_or(paddingVerticalDefault) + borderWidth.bottomDimen.value_or(borderVerticalDefault) };
425 }
426 
CreatePaddingWithoutBorder()427 PaddingPropertyF LayoutProperty::CreatePaddingWithoutBorder()
428 {
429     if (layoutConstraint_.has_value()) {
430         return ConvertToPaddingPropertyF(
431             padding_, layoutConstraint_->scaleProperty, layoutConstraint_->percentReference.Width());
432     }
433 
434     return ConvertToPaddingPropertyF(
435         padding_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
436 }
437 
CreateMargin()438 MarginPropertyF LayoutProperty::CreateMargin()
439 {
440     if (layoutConstraint_.has_value()) {
441         return ConvertToMarginPropertyF(
442             margin_, layoutConstraint_->scaleProperty, layoutConstraint_->percentReference.Width());
443     }
444 
445     return ConvertToMarginPropertyF(
446         margin_, ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth());
447 }
448 
SetHost(const WeakPtr<FrameNode> & host)449 void LayoutProperty::SetHost(const WeakPtr<FrameNode>& host)
450 {
451     host_ = host;
452 }
453 
GetHost() const454 RefPtr<FrameNode> LayoutProperty::GetHost() const
455 {
456     return host_.Upgrade();
457 }
458 
OnVisibilityUpdate(VisibleType visible) const459 void LayoutProperty::OnVisibilityUpdate(VisibleType visible) const
460 {
461     auto host = GetHost();
462     CHECK_NULL_VOID(host);
463     host->OnVisibleChange(visible == VisibleType::VISIBLE);
464     auto parent = host->GetAncestorNodeOfFrame();
465     if (parent) {
466         parent->MarkNeedSyncRenderTree();
467         parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
468     }
469 }
470 
471 } // namespace OHOS::Ace::NG
472