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