• 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/pipeline_ng/pipeline_context.h"
17 #include "core/components_ng/layout/box_layout_algorithm.h"
18 
19 #include "core/components_ng/base/frame_node.h"
20 #include "core/components_ng/pattern/pattern.h"
21 #include "core/components_ng/property/measure_utils.h"
22 #include "core/pipeline/pipeline_base.h"
23 
24 namespace OHOS::Ace::NG {
25 
Measure(LayoutWrapper * layoutWrapper)26 void BoxLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
27 {
28     const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
29     CHECK_NULL_VOID(layoutProperty);
30     auto layoutConstraint = layoutProperty->CreateChildConstraint();
31     auto host = layoutWrapper->GetHostNode();
32     CHECK_NULL_VOID(host);
33     auto pattern = host->GetPattern();
34     CHECK_NULL_VOID(pattern);
35     bool isEnableChildrenMatchParent = pattern->IsEnableChildrenMatchParent();
36     for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
37         auto childLayoutProperty = child->GetLayoutProperty();
38         CHECK_NULL_CONTINUE(childLayoutProperty);
39         auto layoutPolicy = childLayoutProperty->GetLayoutPolicyProperty();
40         if (isEnableChildrenMatchParent && layoutPolicy.has_value()) {
41             if (layoutPolicy->IsMatch()) {
42                 layoutPolicyChildren_.emplace_back(child);
43                 continue;
44             }
45         }
46         child->Measure(layoutConstraint);
47     }
48     PerformMeasureSelf(layoutWrapper);
49     if (isEnableChildrenMatchParent) {
50         auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
51         MeasureAdaptiveLayoutChildren(layoutWrapper, frameSize);
52     }
53 }
54 
Layout(LayoutWrapper * layoutWrapper)55 void BoxLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
56 {
57     PerformLayout(layoutWrapper);
58     for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
59         child->Layout();
60     }
61 }
62 
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)63 std::optional<SizeF> BoxLayoutAlgorithm::MeasureContent(
64     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
65 {
66     return PerformMeasureContent(contentConstraint, layoutWrapper);
67 }
68 
PerformMeasureSelfWithChildList(LayoutWrapper * layoutWrapper,const std::list<RefPtr<LayoutWrapper>> & childList)69 void BoxLayoutAlgorithm::PerformMeasureSelfWithChildList(
70     LayoutWrapper* layoutWrapper, const std::list<RefPtr<LayoutWrapper>>& childList)
71 {
72     const auto& hostLayoutProperty = layoutWrapper->GetLayoutProperty();
73     CHECK_NULL_VOID(hostLayoutProperty);
74     const auto& layoutConstraint = hostLayoutProperty->GetLayoutConstraint();
75     const auto& minSize = layoutConstraint->minSize;
76     const auto& maxSize = layoutConstraint->maxSize;
77     const auto& padding = hostLayoutProperty->CreatePaddingAndBorder();
78     auto measureType = hostLayoutProperty->GetMeasureType();
79     OptionalSizeF frameSize;
80     auto host = layoutWrapper->GetHostNode();
81     CHECK_NULL_VOID(host);
82     bool version10OrLarger = host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TEN);
83     const auto& pattern = host->GetPattern();
84     bool isEnableMatchParent = pattern && pattern->IsEnableMatchParent();
85     bool isEnableFix = pattern && pattern->IsEnableFix();
86     auto widthLayoutPolicy = LayoutCalPolicy::NO_MATCH;
87     auto heightLayoutPolicy = LayoutCalPolicy::NO_MATCH;
88     auto layoutPolicy = hostLayoutProperty->GetLayoutPolicyProperty();
89     if (layoutPolicy.has_value()) {
90         widthLayoutPolicy = layoutPolicy.value().widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
91         heightLayoutPolicy = layoutPolicy.value().heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
92     }
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         auto fixIdealSize = OptionalSizeF();
110         if (content) {
111             // use content size.
112             auto contentSize = content->GetRect().GetSize();
113             AddPaddingToSize(padding, contentSize);
114             frameSize.UpdateIllegalSizeWithCheck(contentSize);
115             fixIdealSize.UpdateIllegalSizeWithCheck(contentSize);
116         } else {
117             // use the max child size.
118             auto childFrame = SizeF();
119             float maxWidth = 0.0f;
120             float maxHeight = 0.0f;
121             for (const auto& child : childList) {
122                 if (!child) {
123                     continue;
124                 }
125                 auto layoutProperty = child->GetLayoutProperty();
126                 CHECK_NULL_CONTINUE(layoutProperty);
127                 if (layoutProperty && layoutProperty->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE) {
128                     continue;
129                 }
130                 const auto& layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
131                 auto singleSideFrame = CalcLayoutPolicySingleSide(layoutPolicy,
132                     layoutProperty->GetCalcLayoutConstraint(),
133                     hostLayoutProperty->CreateChildConstraint(),
134                     layoutProperty->GetMagicItemProperty());
135                 if (singleSideFrame.AtLeastOneValid()) {
136                     auto margin = layoutProperty->CreateMargin();
137                     CalcSingleSideMarginFrame(margin, singleSideFrame, maxWidth, maxHeight);
138                 }
139                 auto childSize = (layoutPolicy.has_value() && layoutPolicy->IsMatch())
140                                      ? SizeF()
141                                      : child->GetGeometryNode()->GetMarginFrameSize();
142                 if (maxWidth < childSize.Width()) {
143                     maxWidth = childSize.Width();
144                 }
145                 if (maxHeight < childSize.Height()) {
146                     maxHeight = childSize.Height();
147                 }
148                 childFrame.SetSizeT(SizeF { maxWidth, maxHeight });
149             }
150             AddPaddingToSize(padding, childFrame);
151             frameSize.UpdateIllegalSizeWithCheck(childFrame);
152             fixIdealSize =
153                 UpdateOptionSizeByCalcLayoutConstraint(OptionalSizeF(childFrame.Width(), childFrame.Height()),
154                     hostLayoutProperty->GetCalcLayoutConstraint(),
155                     hostLayoutProperty->GetLayoutConstraint()->percentReference);
156         }
157         if (layoutConstraint->selfIdealSize.Width()) {
158             frameSize.ConstrainFloat(minSize, maxSize, false, version10OrLarger);
159         } else if (layoutConstraint->selfIdealSize.Height()) {
160             frameSize.ConstrainFloat(minSize, maxSize, true, version10OrLarger);
161         } else {
162             frameSize.Constrain(minSize, maxSize, version10OrLarger);
163         }
164         if (isEnableFix) {
165             if (widthLayoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
166                 frameSize.SetWidth(fixIdealSize.Width());
167             }
168             if (heightLayoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
169                 frameSize.SetHeight(fixIdealSize.Height());
170             }
171         }
172         frameSize.UpdateIllegalSizeWithCheck(SizeF { 0.0f, 0.0f });
173     } while (false);
174     if (isEnableMatchParent && layoutPolicy.has_value()) {
175         auto layoutPolicySize = ConstrainIdealSizeByLayoutPolicy(
176             layoutConstraint.value(), widthLayoutPolicy, heightLayoutPolicy, Axis::HORIZONTAL)
177                                     .ConvertToSizeT();
178         frameSize.UpdateSizeWithCheck(layoutPolicySize);
179     }
180     layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize.ConvertToSizeT());
181 }
182 
CalcSingleSideMarginFrame(MarginPropertyF & margin,const OptionalSizeF & singleSideFrame,float & maxWidth,float & maxHeight)183 void BoxLayoutAlgorithm::CalcSingleSideMarginFrame(
184     MarginPropertyF& margin, const OptionalSizeF& singleSideFrame, float& maxWidth, float& maxHeight)
185 {
186     if (singleSideFrame.Width().has_value()) {
187         maxWidth = std::max(singleSideFrame.Width().value() + margin.Width(), maxWidth);
188     }
189     if (singleSideFrame.Height().has_value()) {
190         maxHeight = std::max(singleSideFrame.Height().value() + margin.Height(), maxHeight);
191     }
192 }
193 
194 // Called to perform measure current render node.
PerformMeasureSelf(LayoutWrapper * layoutWrapper)195 void BoxLayoutAlgorithm::PerformMeasureSelf(LayoutWrapper* layoutWrapper)
196 {
197     CHECK_NULL_VOID(layoutWrapper);
198     PerformMeasureSelfWithChildList(layoutWrapper, layoutWrapper->GetAllChildrenWithBuild());
199 }
200 
MeasureAdaptiveLayoutChildren(LayoutWrapper * layoutWrapper,SizeF & frameSize)201 void BoxLayoutAlgorithm::MeasureAdaptiveLayoutChildren(LayoutWrapper* layoutWrapper, SizeF& frameSize)
202 {
203     const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
204     CHECK_NULL_VOID(layoutProperty);
205     auto layoutConstraint = layoutProperty->CreateChildConstraint();
206     auto padding = layoutProperty->CreatePaddingAndBorder();
207     MinusPaddingToNonNegativeSize(padding, frameSize);
208     layoutConstraint.parentIdealSize.SetSize(frameSize);
209     auto host = layoutWrapper->GetHostNode();
210     IgnoreLayoutSafeAreaBundle bundle;
211     for (const auto& child : layoutPolicyChildren_) {
212         auto childNode = child->GetHostNode();
213         if (childNode && childNode->GetLayoutProperty() && childNode->GetLayoutProperty()->IsExpandConstraintNeeded()) {
214             bundle.first.emplace_back(childNode);
215             child->SetDelaySelfLayoutForIgnore();
216             child->GetGeometryNode()->SetParentLayoutConstraint(layoutConstraint);
217             continue;
218         }
219         child->Measure(layoutConstraint);
220     }
221     if (host && host->GetContext() && !bundle.first.empty()) {
222         host->SetDelaySelfLayoutForIgnore();
223         auto context = host->GetContext();
224         bundle.second = host;
225         context->AddIgnoreLayoutSafeAreaBundle(std::move(bundle));
226     }
227 }
228 
229 // Called to perform layout render node and child.
PerformLayout(LayoutWrapper * layoutWrapper)230 void BoxLayoutAlgorithm::PerformLayout(LayoutWrapper* layoutWrapper)
231 {
232     CHECK_NULL_VOID(layoutWrapper);
233     // update child position.
234     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
235     const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
236     CHECK_NULL_VOID(layoutProperty);
237     const auto& padding = layoutProperty->CreatePaddingAndBorder();
238     MinusPaddingToSize(padding, size);
239     auto left = padding.left.value_or(0);
240     auto top = padding.top.value_or(0);
241     auto paddingOffset = OffsetF(left, top);
242     auto align = Alignment::CENTER;
243     const auto& positionProperty = layoutProperty->GetPositionProperty();
244     if (positionProperty) {
245         auto isMirrorable = positionProperty->GetIsMirrorable()
246             .value_or(false);
247         if (isMirrorable) {
248             auto alignment = positionProperty->GetLocalizedAlignment()
249                 .value_or("center");
250             align= MapLocalizedToAlignment(alignment);
251         } else {
252             align = positionProperty->GetAlignment().value_or(align);
253         }
254     }
255     // Update child position.
256     for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
257         SizeF childSize = child->GetGeometryNode()->GetMarginFrameSize();
258         auto host = layoutWrapper->GetHostNode();
259         auto childNode = child->GetHostNode();
260         if (host && childNode && childNode->GetLayoutProperty() &&
261             childNode->GetLayoutProperty()->IsIgnoreOptsValid()) {
262             IgnoreLayoutSafeAreaOpts& opts = *(childNode->GetLayoutProperty()->GetIgnoreLayoutSafeAreaOpts());
263             auto sae = host->GetAccumulatedSafeAreaExpand(true, opts);
264             auto adjustSize = size + sae.Size();
265             auto translate = Alignment::GetAlignPosition(adjustSize, childSize, align) + paddingOffset;
266             translate -= sae.Offset();
267             child->GetGeometryNode()->SetMarginFrameOffset(translate);
268         } else {
269             auto translate = Alignment::GetAlignPosition(size, childSize, align) + paddingOffset;
270             child->GetGeometryNode()->SetMarginFrameOffset(translate);
271         }
272     }
273     // Update content position.
274     const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
275     if (content) {
276         auto translate = Alignment::GetAlignPosition(size, content->GetRect().GetSize(), align) + paddingOffset;
277         content->SetOffset(translate);
278     }
279 }
280 
PerformMeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)281 std::optional<SizeF> BoxLayoutAlgorithm::PerformMeasureContent(
282     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
283 {
284     auto host = layoutWrapper->GetHostNode();
285     CHECK_NULL_RETURN(host, std::nullopt);
286     if (!host->IsAtomicNode()) {
287         return std::nullopt;
288     }
289     const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
290     CHECK_NULL_RETURN(layoutProperty, std::nullopt);
291     auto measureType = layoutProperty->GetMeasureType(MeasureType::MATCH_CONTENT);
292     OptionalSizeF contentSize;
293     do {
294         // Use idea size first if it is valid.
295         contentSize.UpdateSizeWithCheck(contentConstraint.selfIdealSize);
296         if (contentSize.IsValid()) {
297             break;
298         }
299 
300         if (measureType == MeasureType::MATCH_PARENT) {
301             contentSize.UpdateIllegalSizeWithCheck(contentConstraint.parentIdealSize);
302             // use max is parent ideal size is invalid.
303             contentSize.UpdateIllegalSizeWithCheck(contentConstraint.percentReference);
304             break;
305         }
306 
307         // wrap content case use min size default.
308         contentSize.UpdateIllegalSizeWithCheck(contentConstraint.minSize);
309     } while (false);
310     return contentSize.ConvertToSizeT();
311 }
312 
MapLocalizedToAlignment(std::string localizedAlignment)313 Alignment BoxLayoutAlgorithm::MapLocalizedToAlignment(std::string localizedAlignment)
314 {
315     static const std::unordered_map<std::string, Alignment> alignmentMap = {
316         {"top_start", Alignment::TOP_LEFT},
317         {"top", Alignment::TOP_CENTER},
318         {"top_end", Alignment::TOP_RIGHT},
319         {"start", Alignment::CENTER_LEFT},
320         {"center", Alignment::CENTER},
321         {"end", Alignment::CENTER_RIGHT},
322         {"bottom_start", Alignment::BOTTOM_LEFT},
323         {"bottom", Alignment::BOTTOM_CENTER},
324         {"bottom_end", Alignment::BOTTOM_RIGHT}
325     };
326 
327     auto it = alignmentMap.find(localizedAlignment);
328     if (it != alignmentMap.end()) {
329         return it->second;
330     }
331     return Alignment::CENTER;
332 }
333 } // namespace OHOS::Ace::NG
334