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