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