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