1 /*
2 * Copyright (c) 2022-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/syntax/lazy_layout_wrapper_builder.h"
17
18 #include <cstdint>
19 #include <iterator>
20 #include <list>
21 #include <map>
22 #include <optional>
23 #include <string>
24 #include <unordered_map>
25
26 #include "base/log/ace_trace.h"
27 #include "base/memory/referenced.h"
28 #include "base/utils/utils.h"
29 #include "core/components_ng/base/frame_node.h"
30 #include "core/components_ng/base/ui_node.h"
31 #include "core/components_ng/layout/layout_wrapper.h"
32 #include "core/components_ng/syntax/lazy_for_each_node.h"
33
34 namespace OHOS::Ace::NG {
35
LazyLayoutWrapperBuilder(const RefPtr<LazyForEachBuilder> & builder,const WeakPtr<LazyForEachNode> & host)36 LazyLayoutWrapperBuilder::LazyLayoutWrapperBuilder(
37 const RefPtr<LazyForEachBuilder>& builder, const WeakPtr<LazyForEachNode>& host)
38 : builder_(builder), host_(host)
39 {}
40
SwapDirtyAndUpdateBuildCache()41 void LazyLayoutWrapperBuilder::SwapDirtyAndUpdateBuildCache() {}
42
AdjustGridOffset()43 void LazyLayoutWrapperBuilder::AdjustGridOffset()
44 {
45 for (const auto& wrapper : childWrappers_) {
46 auto frameNode = wrapper->GetHostNode();
47 CHECK_NULL_VOID(frameNode);
48 frameNode->AdjustGridOffset();
49 }
50 }
51
OnGetTotalCount()52 int32_t LazyLayoutWrapperBuilder::OnGetTotalCount()
53 {
54 CHECK_NULL_RETURN_NOLOG(builder_, 0);
55 return builder_->GetTotalCount();
56 }
57
OnGetOrCreateWrapperByIndex(int32_t index)58 RefPtr<LayoutWrapper> LazyLayoutWrapperBuilder::OnGetOrCreateWrapperByIndex(int32_t index)
59 {
60 LOGD("OnGetOrCreateWrapperByIndex index: %{private}d startIndex: %{private}d endIndex: %{private}d", index,
61 startIndex_.value_or(-1), endIndex_.value_or(-1));
62 auto totalCount = GetTotalCount();
63 if ((index < 0) || (index >= totalCount)) {
64 LOGE("index is illegal: %{public}d", index);
65 return nullptr;
66 }
67 // check if the index needs to be converted to virtual index.
68 if (lazySwiper_ &&
69 ((startIndex_ && index < startIndex_.value() - 1) || (endIndex_ && index > endIndex_.value() + 1))) {
70 if (index > startIndex_.value()) {
71 index -= totalCount;
72 } else {
73 index += totalCount;
74 }
75 }
76 return OnGetOrCreateWrapperByIndexLegacy(index);
77 }
78
OnGetOrCreateWrapperByIndexLegacy(int32_t index)79 RefPtr<LayoutWrapper> LazyLayoutWrapperBuilder::OnGetOrCreateWrapperByIndexLegacy(int32_t index)
80 {
81 auto totalCount = GetTotalCount();
82 // The first time get the item, do not do the range check, and the subsequent get the item
83 // needs to check whether it is in the upper and lower bounds (-1, +1) of the existing index.
84 if (!startIndex_) {
85 startIndex_ = index;
86 endIndex_ = index;
87 } else {
88 if ((index >= startIndex_.value()) && (index <= endIndex_.value())) {
89 auto iter = childWrappers_.begin();
90 std::advance(iter, index - startIndex_.value());
91 return *iter;
92 }
93 if ((index < (startIndex_.value() - 1)) || (index > (endIndex_.value() + 1))) {
94 LOGE("need to obtain the item node in order and by step one: %{public}d", index);
95 return nullptr;
96 }
97 }
98
99 CHECK_NULL_RETURN(builder_, nullptr);
100 RefPtr<UINode> uiNode;
101 std::string id;
102 // get frame node from previous cached.
103 if ((index >= preStartIndex_) && (index <= preEndIndex_)) {
104 auto iter = preNodeIds_.begin();
105 std::advance(iter, index - preStartIndex_);
106 if ((iter != preNodeIds_.end()) && (iter->has_value())) {
107 id = iter->value();
108 uiNode = builder_->GetChildByKey(id);
109 }
110 }
111 if (!uiNode) {
112 // convert index to real index.
113 int32_t realIndex = index;
114 if (lazySwiper_) {
115 if (index >= totalCount) {
116 realIndex -= totalCount;
117 } else if (index < 0) {
118 realIndex += totalCount;
119 }
120 }
121 // create frame node.
122 auto itemInfo = builder_->GetChildByIndex(realIndex, true);
123 id = itemInfo.first;
124 uiNode = itemInfo.second;
125 }
126 CHECK_NULL_RETURN(uiNode, nullptr);
127 RefPtr<LayoutWrapper> wrapper;
128 auto frameNode = DynamicCast<FrameNode>(uiNode);
129 if (frameNode) {
130 wrapper = frameNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
131 } else {
132 wrapper = uiNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
133 }
134 CHECK_NULL_RETURN(wrapper, nullptr);
135 if (index == (startIndex_.value() - 1)) {
136 // insert at begin.
137 startIndex_ = index;
138 childWrappers_.emplace_front(wrapper);
139 nodeIds_.emplace_front(id);
140 return wrapper;
141 }
142 // insert at end.
143 endIndex_ = index;
144 childWrappers_.emplace_back(wrapper);
145 nodeIds_.emplace_back(id);
146 return wrapper;
147 }
148
GetCachedChildLayoutWrapper()149 const std::list<RefPtr<LayoutWrapper>>& LazyLayoutWrapperBuilder::GetCachedChildLayoutWrapper()
150 {
151 return childWrappers_;
152 }
153
OnExpandChildLayoutWrapper()154 const std::list<RefPtr<LayoutWrapper>>& LazyLayoutWrapperBuilder::OnExpandChildLayoutWrapper()
155 {
156 auto total = GetTotalCount();
157 if (!childWrappers_.empty()) {
158 if (static_cast<int32_t>(childWrappers_.size()) == total) {
159 return childWrappers_;
160 }
161 LOGE("can not mix lazy get and full get method!");
162 childWrappers_.clear();
163 return childWrappers_;
164 }
165
166 CHECK_NULL_RETURN(builder_, childWrappers_);
167 for (int32_t index = 0; index < total; ++index) {
168 auto itemInfo = builder_->GetChildByIndex(index, true);
169 RefPtr<LayoutWrapper> wrapper;
170 auto frameNode = DynamicCast<FrameNode>(itemInfo.second);
171 auto uiNode = itemInfo.second;
172 if (frameNode) {
173 wrapper = frameNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
174 } else if (uiNode) {
175 wrapper = uiNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
176 }
177 if (!wrapper) {
178 LOGE("fail to create wrapper");
179 childWrappers_.clear();
180 return childWrappers_;
181 }
182 nodeIds_.emplace_back(itemInfo.first);
183 childWrappers_.emplace_back(wrapper);
184 }
185 startIndex_ = 0;
186 endIndex_ = total - 1;
187 return childWrappers_;
188 }
189
GetKeyByIndexFromPreNodes(int32_t index)190 std::optional<std::string> LazyLayoutWrapperBuilder::GetKeyByIndexFromPreNodes(int32_t index)
191 {
192 if ((index >= preStartIndex_) && (index <= preEndIndex_)) {
193 auto iter = preNodeIds_.begin();
194 std::advance(iter, index - preStartIndex_);
195 if ((iter != preNodeIds_.end()) && (iter->has_value())) {
196 return iter->value();
197 }
198 }
199 return std::nullopt;
200 }
201
202 } // namespace OHOS::Ace::NG
203