• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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