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(builder_, 0);
55 return builder_->GetTotalCount();
56 }
57
OnGetOrCreateWrapperByIndex(int32_t index)58 RefPtr<LayoutWrapper> LazyLayoutWrapperBuilder::OnGetOrCreateWrapperByIndex(int32_t index)
59 {
60 auto totalCount = GetTotalCount();
61 if ((index < 0) || (index >= totalCount)) {
62 LOGE("index is illegal: %{public}d", index);
63 return nullptr;
64 }
65 // check if the index needs to be converted to virtual index.
66 if (lazySwiper_ &&
67 ((startIndex_ && index < startIndex_.value() - 1) || (endIndex_ && index > endIndex_.value() + 1))) {
68 if (index > startIndex_.value()) {
69 index -= totalCount;
70 } else {
71 index += totalCount;
72 }
73 }
74 return OnGetOrCreateWrapperByIndexLegacy(index);
75 }
76
OnGetOrCreateWrapperByIndexLegacy(int32_t index)77 RefPtr<LayoutWrapper> LazyLayoutWrapperBuilder::OnGetOrCreateWrapperByIndexLegacy(int32_t index)
78 {
79 auto totalCount = GetTotalCount();
80 // The first time get the item, do not do the range check, and the subsequent get the item
81 // needs to check whether it is in the upper and lower bounds (-1, +1) of the existing index.
82 if (!startIndex_) {
83 startIndex_ = index;
84 endIndex_ = index;
85 } else {
86 if ((index >= startIndex_.value()) && (index <= endIndex_.value())) {
87 auto iter = childWrappers_.begin();
88 std::advance(iter, index - startIndex_.value());
89 return *iter;
90 }
91 if ((index < (startIndex_.value() - 1)) || (index > (endIndex_.value() + 1))) {
92 LOGE("need to obtain the item node in order and by step one: %{public}d", index);
93 return nullptr;
94 }
95 }
96
97 CHECK_NULL_RETURN(builder_, nullptr);
98 RefPtr<UINode> uiNode;
99 std::string id;
100 // get frame node from previous cached.
101 if ((index >= preStartIndex_) && (index <= preEndIndex_)) {
102 auto iter = preNodeIds_.begin();
103 std::advance(iter, index - preStartIndex_);
104 if ((iter != preNodeIds_.end()) && (iter->has_value())) {
105 id = iter->value();
106 uiNode = builder_->GetChildByKey(id);
107 }
108 }
109 if (!uiNode) {
110 // convert index to real index.
111 int32_t realIndex = index;
112 if (lazySwiper_) {
113 if (index >= totalCount) {
114 realIndex -= totalCount;
115 } else if (index < 0) {
116 realIndex += totalCount;
117 }
118 }
119 // create frame node.
120 auto itemInfo = builder_->GetChildByIndex(realIndex, true);
121 id = itemInfo.first;
122 uiNode = itemInfo.second;
123 }
124 CHECK_NULL_RETURN(uiNode, nullptr);
125 RefPtr<LayoutWrapper> wrapper;
126 auto frameNode = DynamicCast<FrameNode>(uiNode);
127 if (frameNode) {
128 wrapper = frameNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
129 } else {
130 wrapper = uiNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
131 }
132 CHECK_NULL_RETURN(wrapper, nullptr);
133 if (index == (startIndex_.value() - 1)) {
134 // insert at begin.
135 startIndex_ = index;
136 childWrappers_.emplace_front(wrapper);
137 nodeIds_.emplace_front(id);
138 return wrapper;
139 }
140 // insert at end.
141 endIndex_ = index;
142 childWrappers_.emplace_back(wrapper);
143 nodeIds_.emplace_back(id);
144 return wrapper;
145 }
146
GetCachedChildLayoutWrapper()147 const std::list<RefPtr<LayoutWrapper>>& LazyLayoutWrapperBuilder::GetCachedChildLayoutWrapper()
148 {
149 return childWrappers_;
150 }
151
OnExpandChildLayoutWrapper()152 const std::list<RefPtr<LayoutWrapper>>& LazyLayoutWrapperBuilder::OnExpandChildLayoutWrapper()
153 {
154 auto total = GetTotalCount();
155 if (!childWrappers_.empty()) {
156 if (static_cast<int32_t>(childWrappers_.size()) == total) {
157 return childWrappers_;
158 }
159 LOGE("can not mix lazy get and full get method!");
160 childWrappers_.clear();
161 return childWrappers_;
162 }
163
164 CHECK_NULL_RETURN(builder_, childWrappers_);
165 for (int32_t index = 0; index < total; ++index) {
166 auto itemInfo = builder_->GetChildByIndex(index, true);
167 RefPtr<LayoutWrapper> wrapper;
168 auto frameNode = DynamicCast<FrameNode>(itemInfo.second);
169 auto uiNode = itemInfo.second;
170 if (frameNode) {
171 wrapper = frameNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
172 } else if (uiNode) {
173 wrapper = uiNode->CreateLayoutWrapper(forceMeasure_, forceLayout_);
174 }
175 if (!wrapper) {
176 LOGE("fail to create wrapper");
177 childWrappers_.clear();
178 return childWrappers_;
179 }
180 nodeIds_.emplace_back(itemInfo.first);
181 childWrappers_.emplace_back(wrapper);
182 }
183 startIndex_ = 0;
184 endIndex_ = total - 1;
185 return childWrappers_;
186 }
187
GetKeyByIndexFromPreNodes(int32_t index)188 std::optional<std::string> LazyLayoutWrapperBuilder::GetKeyByIndexFromPreNodes(int32_t index)
189 {
190 if ((index >= preStartIndex_) && (index <= preEndIndex_)) {
191 auto iter = preNodeIds_.begin();
192 std::advance(iter, index - preStartIndex_);
193 if ((iter != preNodeIds_.end()) && (iter->has_value())) {
194 return iter->value();
195 }
196 }
197 return std::nullopt;
198 }
199
200 } // namespace OHOS::Ace::NG
201