• 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 "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