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/box_layout_algorithm.h"
17
18 #include <optional>
19
20 #include "base/geometry/ng/offset_t.h"
21 #include "base/geometry/ng/size_t.h"
22 #include "base/geometry/size.h"
23 #include "base/utils/utils.h"
24 #include "core/common/window.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/layout/layout_wrapper.h"
27 #include "core/components_ng/property/measure_property.h"
28 #include "core/components_ng/property/measure_utils.h"
29 #include "core/components_ng/property/property.h"
30 #include "core/pipeline/pipeline_base.h"
31
32 namespace OHOS::Ace::NG {
33
Measure(LayoutWrapper * layoutWrapper)34 void BoxLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
35 {
36 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
37 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
38 child->Measure(layoutConstraint);
39 }
40 PerformMeasureSelf(layoutWrapper);
41 }
42
Layout(LayoutWrapper * layoutWrapper)43 void BoxLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
44 {
45 PerformLayout(layoutWrapper);
46 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
47 child->Layout();
48 }
49 }
50
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)51 std::optional<SizeF> BoxLayoutAlgorithm::MeasureContent(
52 const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
53 {
54 auto host = layoutWrapper->GetHostNode();
55 CHECK_NULL_RETURN(host, std::nullopt);
56 if (!host->IsAtomicNode()) {
57 return std::nullopt;
58 }
59 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
60 auto measureType = layoutProperty->GetMeasureType(MeasureType::MATCH_CONTENT);
61 OptionalSizeF contentSize;
62 do {
63 // Use idea size first if it is valid.
64 contentSize.UpdateSizeWithCheck(contentConstraint.selfIdealSize);
65 if (contentSize.IsValid()) {
66 break;
67 }
68
69 if (measureType == MeasureType::MATCH_PARENT) {
70 contentSize.UpdateIllegalSizeWithCheck(contentConstraint.parentIdealSize);
71 // use max is parent ideal size is invalid.
72 contentSize.UpdateIllegalSizeWithCheck(contentConstraint.percentReference);
73 break;
74 }
75
76 // wrap content case use min size default.
77 contentSize.UpdateIllegalSizeWithCheck(contentConstraint.minSize);
78 } while (false);
79 return contentSize.ConvertToSizeT();
80 }
81
PerformMeasureSelfWithChildList(LayoutWrapper * layoutWrapper,const std::list<RefPtr<LayoutWrapper>> & childList)82 void BoxLayoutAlgorithm::PerformMeasureSelfWithChildList(
83 LayoutWrapper* layoutWrapper, const std::list<RefPtr<LayoutWrapper>>& childList)
84 {
85 const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
86 const auto& minSize = layoutConstraint->minSize;
87 const auto& maxSize = layoutConstraint->maxSize;
88 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
89 auto measureType = layoutWrapper->GetLayoutProperty()->GetMeasureType();
90 OptionalSizeF frameSize;
91 auto version10OrLarger =
92 PipelineBase::GetCurrentContext() && PipelineBase::GetCurrentContext()->GetMinPlatformVersion() > 9;
93 do {
94 // Use idea size first if it is valid.
95 frameSize.UpdateSizeWithCheck(layoutConstraint->selfIdealSize);
96 if (frameSize.IsValid()) {
97 break;
98 }
99
100 if (measureType == MeasureType::MATCH_PARENT) {
101 frameSize.UpdateIllegalSizeWithCheck(layoutConstraint->parentIdealSize);
102 if (frameSize.IsValid()) {
103 frameSize.Constrain(minSize, maxSize, version10OrLarger);
104 break;
105 }
106 }
107
108 const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
109 if (content) {
110 // use content size.
111 auto contentSize = content->GetRect().GetSize();
112 AddPaddingToSize(padding, contentSize);
113 frameSize.UpdateIllegalSizeWithCheck(contentSize);
114 } else {
115 // use the max child size.
116 auto childFrame = SizeF();
117 float maxWidth = 0.0f;
118 float maxHeight = 0.0f;
119 for (const auto& child : childList) {
120 if (!child) {
121 continue;
122 }
123 auto layoutProperty = child->GetLayoutProperty();
124 if (layoutProperty && layoutProperty->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE) {
125 continue;
126 }
127 auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
128 if (maxWidth < childSize.Width()) {
129 maxWidth = childSize.Width();
130 }
131 if (maxHeight < childSize.Height()) {
132 maxHeight = childSize.Height();
133 }
134 childFrame.SetSizeT(SizeF { maxWidth, maxHeight });
135 }
136 AddPaddingToSize(padding, childFrame);
137 frameSize.UpdateIllegalSizeWithCheck(childFrame);
138 }
139 if (layoutConstraint->selfIdealSize.Width()) {
140 frameSize.ConstrainFloat(minSize, maxSize, false, version10OrLarger);
141 } else if (layoutConstraint->selfIdealSize.Height()) {
142 frameSize.ConstrainFloat(minSize, maxSize, true, version10OrLarger);
143 } else {
144 frameSize.Constrain(minSize, maxSize, version10OrLarger);
145 }
146 frameSize.UpdateIllegalSizeWithCheck(SizeF { 0.0f, 0.0f });
147 } while (false);
148 layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize.ConvertToSizeT());
149 }
150
151 // Called to perform measure current render node.
PerformMeasureSelf(LayoutWrapper * layoutWrapper)152 void BoxLayoutAlgorithm::PerformMeasureSelf(LayoutWrapper* layoutWrapper)
153 {
154 PerformMeasureSelfWithChildList(layoutWrapper, layoutWrapper->GetAllChildrenWithBuild());
155 }
156
157 // Called to perform layout render node and child.
PerformLayout(LayoutWrapper * layoutWrapper)158 void BoxLayoutAlgorithm::PerformLayout(LayoutWrapper* layoutWrapper)
159 {
160 // update child position.
161 auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
162 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
163 MinusPaddingToSize(padding, size);
164 auto left = padding.left.value_or(0);
165 auto top = padding.top.value_or(0);
166 auto paddingOffset = OffsetF(left, top);
167 auto align = Alignment::CENTER;
168 if (layoutWrapper->GetLayoutProperty()->GetPositionProperty()) {
169 align = layoutWrapper->GetLayoutProperty()->GetPositionProperty()->GetAlignment().value_or(align);
170 }
171 // Update child position.
172 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
173 SizeF childSize = child->GetGeometryNode()->GetMarginFrameSize();
174 auto translate = Alignment::GetAlignPosition(size, childSize, align) + paddingOffset;
175 child->GetGeometryNode()->SetMarginFrameOffset(translate);
176 }
177 // Update content position.
178 const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
179 if (content) {
180 auto translate = Alignment::GetAlignPosition(size, content->GetRect().GetSize(), align) + paddingOffset;
181 content->SetOffset(translate);
182 }
183 }
184 } // namespace OHOS::Ace::NG
185