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