1 /*
2 * Copyright (c) 2023 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_wrapper_node.h"
17
18 #include "core/pipeline_ng/pipeline_context.h"
19
20 namespace OHOS::Ace::NG {
Update(WeakPtr<FrameNode> hostNode,RefPtr<GeometryNode> geometryNode,RefPtr<LayoutProperty> layoutProperty)21 void LayoutWrapperNode::Update(
22 WeakPtr<FrameNode> hostNode, RefPtr<GeometryNode> geometryNode, RefPtr<LayoutProperty> layoutProperty)
23 {
24 hostNode_ = std::move(hostNode);
25 geometryNode_ = std::move(geometryNode);
26 layoutProperty_ = std::move(layoutProperty);
27 }
28
LayoutWrapperNode(WeakPtr<FrameNode> hostNode,RefPtr<GeometryNode> geometryNode,RefPtr<LayoutProperty> layoutProperty)29 LayoutWrapperNode::LayoutWrapperNode(
30 WeakPtr<FrameNode> hostNode, RefPtr<GeometryNode> geometryNode, RefPtr<LayoutProperty> layoutProperty)
31 : LayoutWrapper(std::move(hostNode)), geometryNode_(std::move(geometryNode)),
32 layoutProperty_(std::move(layoutProperty))
33 {}
34
AppendChild(const RefPtr<LayoutWrapperNode> & child,bool isOverlayNode)35 void LayoutWrapperNode::AppendChild(const RefPtr<LayoutWrapperNode>& child, bool isOverlayNode)
36 {
37 CHECK_NULL_VOID(child);
38 if (!isOverlayNode) {
39 children_.emplace_back(child);
40 childrenMap_.try_emplace(currentChildCount_, child);
41 ++currentChildCount_;
42 } else {
43 overlayChild_ = child;
44 }
45 }
GetOrCreateChildByIndex(uint32_t index,bool addToRenderTree,bool isCache)46 RefPtr<LayoutWrapper> LayoutWrapperNode::GetOrCreateChildByIndex(uint32_t index, bool addToRenderTree, bool isCache)
47 {
48 if ((index >= static_cast<uint32_t>(currentChildCount_)) || (index < 0)) {
49 return nullptr;
50 }
51 auto iter = childrenMap_.find(index);
52 if (iter != childrenMap_.end()) {
53 if (addToRenderTree) {
54 iter->second->BuildLazyItem();
55 iter->second->SetActive(true);
56 }
57 return iter->second;
58 }
59 CHECK_NULL_RETURN(layoutWrapperBuilder_, nullptr);
60 auto wrapper = layoutWrapperBuilder_->GetOrCreateWrapperByIndex(index);
61 CHECK_NULL_RETURN(wrapper, nullptr);
62 if (addToRenderTree) {
63 wrapper->SetActive(true);
64 }
65 return wrapper;
66 }
67
SetCacheCount(int32_t cacheCount,const std::optional<LayoutConstraintF> & itemConstraint)68 void LayoutWrapperNode::SetCacheCount(int32_t cacheCount, const std::optional<LayoutConstraintF>& itemConstraint)
69 {
70 CHECK_NULL_VOID(layoutWrapperBuilder_);
71 layoutWrapperBuilder_->SetCacheCount(cacheCount, itemConstraint);
72 }
73
Build(bool addToRenderTree)74 void LayoutWrapperNode::Build(bool addToRenderTree)
75 {
76 for (const auto& child : children_) {
77 cachedList_.push_back(child);
78 }
79 if (layoutWrapperBuilder_) {
80 auto buildItems = layoutWrapperBuilder_->ExpandAllChildWrappers();
81 auto index = layoutWrapperBuilder_->GetStartIndex();
82 auto insertIter = cachedList_.begin();
83 std::advance(insertIter, index);
84 cachedList_.splice(insertIter, buildItems);
85 }
86 if (addToRenderTree) {
87 for (const auto& child : cachedList_) {
88 child->BuildLazyItem();
89 if (!child->IsActive()) {
90 child->SetActive(true);
91 }
92 }
93 if (overlayChild_) {
94 overlayChild_->BuildLazyItem();
95 if (!overlayChild_->IsActive()) {
96 overlayChild_->SetActive(true);
97 }
98 }
99 }
100 }
101
GetAllChildrenWithBuild(bool addToRenderTree)102 ChildrenListWithGuard LayoutWrapperNode::GetAllChildrenWithBuild(bool addToRenderTree)
103 {
104 if (cachedList_.empty()) {
105 Build(addToRenderTree);
106 }
107 static RecursiveLock dummyLock;
108 return ChildrenListWithGuard(cachedList_, dummyLock);
109 }
110
RemoveChildInRenderTree(uint32_t index)111 void LayoutWrapperNode::RemoveChildInRenderTree(uint32_t index)
112 {
113 auto wrapper = GetOrCreateChildByIndex(index, false);
114 CHECK_NULL_VOID(wrapper);
115 wrapper->SetActive(false);
116 }
117
RemoveAllChildInRenderTree()118 void LayoutWrapperNode::RemoveAllChildInRenderTree()
119 {
120 for (auto& child : childrenMap_) {
121 child.second->SetActive(false);
122 }
123 CHECK_NULL_VOID(layoutWrapperBuilder_);
124 layoutWrapperBuilder_->RemoveAllChildInRenderTree();
125 }
126
ResetHostNode()127 void LayoutWrapperNode::ResetHostNode()
128 {
129 hostNode_.Reset();
130 }
131
GetHostTag() const132 const std::string& LayoutWrapperNode::GetHostTag() const
133 {
134 auto host = GetHostNode();
135 if (!host) {
136 static std::string retFailed;
137 return retFailed;
138 }
139 return host->GetTag();
140 }
141
GetHostDepth() const142 int32_t LayoutWrapperNode::GetHostDepth() const
143 {
144 auto host = GetHostNode();
145 CHECK_NULL_RETURN(host, -1);
146 return host->GetDepth();
147 }
148
149 // This will call child and self measure process.
Measure(const std::optional<LayoutConstraintF> & parentConstraint)150 void LayoutWrapperNode::Measure(const std::optional<LayoutConstraintF>& parentConstraint)
151 {
152 auto host = GetHostNode();
153 CHECK_NULL_VOID(layoutProperty_);
154 CHECK_NULL_VOID(geometryNode_);
155 CHECK_NULL_VOID(host);
156
157 CHECK_NULL_VOID(layoutAlgorithm_);
158 if (layoutAlgorithm_->SkipMeasure()) {
159 return;
160 }
161
162 const auto& geometryTransition = layoutProperty_->GetGeometryTransition();
163 if (geometryTransition != nullptr && geometryTransition->IsRunning(GetHostNode())) {
164 geometryTransition->WillLayout(Claim(this));
165 }
166
167 auto preConstraint = layoutProperty_->GetLayoutConstraint();
168 auto contentConstraint = layoutProperty_->GetContentLayoutConstraint();
169 layoutProperty_->BuildGridProperty(host);
170 if (parentConstraint) {
171 ApplyConstraint(*parentConstraint);
172 } else {
173 CreateRootConstraint();
174 }
175 layoutProperty_->UpdateContentConstraint();
176 geometryNode_->UpdateMargin(layoutProperty_->CreateMargin());
177 geometryNode_->UpdatePaddingWithBorder(layoutProperty_->CreatePaddingAndBorder());
178
179 isConstraintNotChanged_ = preConstraint ? preConstraint == layoutProperty_->GetLayoutConstraint() : false;
180 if (!isConstraintNotChanged_) {
181 isConstraintNotChanged_ =
182 contentConstraint ? contentConstraint == layoutProperty_->GetContentLayoutConstraint() : false;
183 }
184
185 if (isConstraintNotChanged_ && !skipMeasureContent_) {
186 if (!CheckNeedForceMeasureAndLayout()) {
187 skipMeasureContent_ = true;
188 }
189 }
190
191 if (!skipMeasureContent_.value_or(false)) {
192 skipMeasureContent_ = false;
193 auto size = layoutAlgorithm_->MeasureContent(layoutProperty_->CreateContentConstraint(), this);
194 if (size.has_value()) {
195 geometryNode_->SetContentSize(size.value());
196 }
197 layoutAlgorithm_->Measure(this);
198
199 if (overlayChild_) {
200 overlayChild_->Measure(GetLayoutProperty()->CreateChildConstraint());
201 }
202
203 // check aspect radio.
204 auto pattern = host->GetPattern();
205 if (pattern && pattern->IsNeedAdjustByAspectRatio()) {
206 const auto& magicItemProperty = layoutProperty_->GetMagicItemProperty();
207 auto aspectRatio = magicItemProperty.GetAspectRatioValue();
208 // Adjust by aspect ratio, firstly pick height based on width. It means that when width, height and
209 // aspectRatio are all set, the height is not used.
210 auto width = geometryNode_->GetFrameSize().Width();
211 auto height = width / aspectRatio;
212 geometryNode_->SetFrameSize(SizeF({ width, height }));
213 }
214 }
215 }
216
217 // Called to perform layout children.
Layout()218 void LayoutWrapperNode::Layout()
219 {
220 int64_t time = GetSysTimestamp();
221 auto host = GetHostNode();
222 CHECK_NULL_VOID(layoutProperty_);
223 CHECK_NULL_VOID(geometryNode_);
224 CHECK_NULL_VOID(host);
225 CHECK_NULL_VOID(layoutAlgorithm_);
226
227 OffsetNodeToSafeArea();
228
229 if (layoutAlgorithm_->SkipLayout()) {
230 return;
231 }
232
233 if ((skipMeasureContent_ == true)) {
234 return;
235 }
236
237 if (!layoutProperty_->GetLayoutConstraint()) {
238 const auto& parentLayoutConstraint = geometryNode_->GetParentLayoutConstraint();
239 if (parentLayoutConstraint) {
240 layoutProperty_->UpdateLayoutConstraint(parentLayoutConstraint.value());
241 } else {
242 LayoutConstraintF layoutConstraint;
243 layoutConstraint.percentReference.SetWidth(PipelineContext::GetCurrentRootWidth());
244 layoutConstraint.percentReference.SetHeight(PipelineContext::GetCurrentRootHeight());
245 layoutProperty_->UpdateLayoutConstraint(layoutConstraint);
246 }
247 layoutProperty_->UpdateContentConstraint();
248 }
249 layoutAlgorithm_->Layout(this);
250 LayoutOverlay();
251
252 time = GetSysTimestamp() - time;
253 AddNodeFlexLayouts();
254 AddNodeLayoutTime(time);
255 }
256
SkipMeasureContent() const257 bool LayoutWrapperNode::SkipMeasureContent() const
258 {
259 return (skipMeasureContent_ == true) || layoutAlgorithm_->SkipMeasure();
260 }
261
CheckNeedForceMeasureAndLayout()262 bool LayoutWrapperNode::CheckNeedForceMeasureAndLayout()
263 {
264 if (needForceMeasureAndLayout_) {
265 return needForceMeasureAndLayout_.value();
266 }
267 PropertyChangeFlag flag = layoutProperty_->GetPropertyChangeFlag();
268 // Need to remove layout flag when measure and layout make independent in each pattern layoutAlgorithm like
269 // flex.
270 bool needForceMeasureAndLayout = CheckNeedMeasure(flag) || CheckNeedLayout(flag);
271 if (needForceMeasureAndLayout) {
272 needForceMeasureAndLayout_ = true;
273 return true;
274 }
275 // check child flag.
276 needForceMeasureAndLayout_ = std::any_of(
277 children_.begin(), children_.end(), [](const auto& item) { return item->CheckNeedForceMeasureAndLayout(); });
278 return needForceMeasureAndLayout_.value();
279 }
280
CheckChildNeedForceMeasureAndLayout()281 bool LayoutWrapperNode::CheckChildNeedForceMeasureAndLayout()
282 {
283 return std::any_of(
284 children_.begin(), children_.end(), [](const auto& item) { return item->CheckNeedForceMeasureAndLayout(); });
285 }
286
MountToHostOnMainThread()287 void LayoutWrapperNode::MountToHostOnMainThread()
288 {
289 SwapDirtyLayoutWrapperOnMainThread();
290 }
291
SwapDirtyLayoutWrapperOnMainThreadForChild(RefPtr<LayoutWrapperNode> child)292 void LayoutWrapperNode::SwapDirtyLayoutWrapperOnMainThreadForChild(RefPtr<LayoutWrapperNode> child)
293 {
294 if (!child) {
295 return;
296 }
297 auto node = child->GetHostNode();
298 if (node && node->GetLayoutProperty()) {
299 const auto& geometryTransition = node->GetLayoutProperty()->GetGeometryTransition();
300 if (geometryTransition != nullptr && geometryTransition->IsNodeInAndActive(node)) {
301 return;
302 }
303 }
304 child->SwapDirtyLayoutWrapperOnMainThread();
305 }
306
SwapDirtyLayoutWrapperOnMainThread()307 void LayoutWrapperNode::SwapDirtyLayoutWrapperOnMainThread()
308 {
309 if (IsActive()) {
310 for (const auto& child : children_) {
311 SwapDirtyLayoutWrapperOnMainThreadForChild(child);
312 }
313
314 if (overlayChild_) {
315 SwapDirtyLayoutWrapperOnMainThreadForChild(overlayChild_);
316 }
317
318 if (layoutWrapperBuilder_) {
319 layoutWrapperBuilder_->SwapDirtyAndUpdateBuildCache();
320 }
321 }
322
323 auto host = hostNode_.Upgrade();
324 CHECK_NULL_VOID(host);
325 host->SwapDirtyLayoutWrapperOnMainThread(Claim(this));
326
327 /* Adjust components' position which have been set grid properties */
328 for (const auto& child : children_) {
329 if (child && child->GetHostNode()) {
330 child->GetHostNode()->AdjustGridOffset();
331 }
332 }
333 CHECK_NULL_VOID(layoutWrapperBuilder_);
334 layoutWrapperBuilder_->AdjustGridOffset();
335 }
336
BuildLazyItem()337 void LayoutWrapperNode::BuildLazyItem()
338 {
339 if (!lazyBuildFunction_) {
340 return;
341 }
342 ACE_FUNCTION_TRACE();
343 lazyBuildFunction_(Claim(this));
344 lazyBuildFunction_ = nullptr;
345 }
346
GetLazyBuildRange()347 std::pair<int32_t, int32_t> LayoutWrapperNode::GetLazyBuildRange()
348 {
349 if (layoutWrapperBuilder_) {
350 auto start = layoutWrapperBuilder_->GetStartIndex();
351 auto end = start + layoutWrapperBuilder_->GetTotalCount();
352 return { start, end };
353 }
354 return { -1, 0 };
355 }
356
SetLongPredictTask()357 void LayoutWrapperNode::SetLongPredictTask()
358 {
359 CHECK_NULL_VOID(layoutWrapperBuilder_);
360 layoutWrapperBuilder_->SetLongPredictTask();
361 }
362
LayoutOverlay()363 void LayoutWrapperNode::LayoutOverlay()
364 {
365 if (!overlayChild_) {
366 return;
367 }
368 overlayChild_->Layout();
369 auto size = GetGeometryNode()->GetFrameSize();
370 auto align = Alignment::TOP_LEFT;
371 Dimension offsetX, offsetY;
372 auto childLayoutProperty = overlayChild_->GetLayoutProperty();
373 childLayoutProperty->GetOverlayOffset(offsetX, offsetY);
374 auto offset = OffsetF(offsetX.ConvertToPx(), offsetY.ConvertToPx());
375 if (childLayoutProperty->GetPositionProperty()) {
376 align = childLayoutProperty->GetPositionProperty()->GetAlignment().value_or(align);
377 }
378
379 auto childSize = overlayChild_->GetGeometryNode()->GetMarginFrameSize();
380 auto translate = Alignment::GetAlignPosition(size, childSize, align) + offset;
381 overlayChild_->GetGeometryNode()->SetMarginFrameOffset(translate);
382 }
383
384 } // namespace OHOS::Ace::NG
385