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