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