• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "bridge/declarative_frontend/jsview/js_repeat_virtual_scroll.h"
17 
18 #include <string>
19 
20 #include "base/log/ace_trace.h"
21 #include "base/log/log_wrapper.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "core/components_ng/syntax/repeat_virtual_scroll_model_ng.h"
24 
25 #define JSFUNC(opts, propName) (JSRef<JSFunc>::Cast((opts)->GetProperty(propName)))
26 
27 namespace OHOS::Ace {
28 
29 std::unique_ptr<RepeatVirtualScrollModel> RepeatVirtualScrollModel::instance_ = nullptr;
30 #define UNUSED_CACHED_SIZE_PARAM 2
31 
GetInstance()32 RepeatVirtualScrollModel* RepeatVirtualScrollModel::GetInstance()
33 {
34     if (!instance_) {
35         instance_.reset(new NG::RepeatVirtualScrollModelNG());
36     }
37     return instance_.get();
38 }
39 } // namespace OHOS::Ace
40 
41 namespace OHOS::Ace::Framework {
42 
43 enum {
44     PARAM_TOTAL_COUNT = 0,
45     PARAM_TEMPLATE_OPTS = 1,
46     PARAM_HANDLERS = 2,
47     PARAM_REUSABLE = 3,
48     MIN_PARAM_SIZE = 4,
49 };
50 
ParseAndVerifyParams(const JSCallbackInfo & info)51 static bool ParseAndVerifyParams(const JSCallbackInfo& info)
52 {
53     if (info.Length() < MIN_PARAM_SIZE) {
54         return false;
55     }
56 
57     if (!info[PARAM_TOTAL_COUNT]->IsNumber()) {
58         return false;
59     }
60     if (!info[PARAM_TEMPLATE_OPTS]->IsArray()) {
61         return false;
62     }
63     if (!info[PARAM_HANDLERS]->IsObject()) {
64         return false;
65     }
66     if (!info[PARAM_REUSABLE]->IsBoolean()) {
67         return false;
68     }
69 
70     auto templateOptsArray = JSRef<JSArray>::Cast(info[PARAM_TEMPLATE_OPTS]);
71     for (size_t i = 0; i < templateOptsArray->Length(); i++) {
72         JSRef<JSArray> pair = templateOptsArray->GetValueAt(i);
73         if (!pair->GetValueAt(0)->IsString()) {
74             return false;
75         }
76         if (!pair->GetValueAt(1)->IsObject()) {
77             return false;
78         }
79         auto type = pair->GetValueAt(0)->ToString();
80         auto opts = JSRef<JSObject>::Cast(pair->GetValueAt(1));
81         if (!opts->GetProperty("cachedCountSpecified")->IsBoolean()) {
82             return false;
83         }
84     }
85 
86     auto handlers = JSRef<JSObject>::Cast(info[PARAM_HANDLERS]);
87     if (!handlers->GetProperty("onCreateNode")->IsFunction() || !handlers->GetProperty("onUpdateNode")->IsFunction() ||
88         !handlers->GetProperty("onGetKeys4Range")->IsFunction() ||
89         !handlers->GetProperty("onGetTypes4Range")->IsFunction() ||
90         !handlers->GetProperty("onSetActiveRange")->IsFunction()) {
91         return false;
92     }
93 
94     return true;
95 }
96 
Create(const JSCallbackInfo & info)97 void JSRepeatVirtualScroll::Create(const JSCallbackInfo& info)
98 {
99     if (!ParseAndVerifyParams(info)) {
100         TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Invalid arguments for RepeatVirtualScroll");
101         return;
102     }
103 
104     // arg 0
105     auto totalCount = info[PARAM_TOTAL_COUNT]->ToNumber<uint32_t>();
106 
107     // arg 1
108     auto templateOptsArray = JSRef<JSArray>::Cast(info[PARAM_TEMPLATE_OPTS]);
109     std::map<std::string, std::pair<bool, uint32_t>> templateCachedCountMap;
110     for (size_t i = 0; i < templateOptsArray->Length(); i++) {
111         JSRef<JSArray> pair = templateOptsArray->GetValueAt(i);
112         auto type = pair->GetValueAt(0)->ToString();
113         auto opts = JSRef<JSObject>::Cast(pair->GetValueAt(1));
114 
115         templateCachedCountMap[type] =
116             opts->GetProperty("cachedCountSpecified")->ToNumber <bool>()
117                 ? std::pair<bool, uint32_t>(true, opts->GetProperty("cachedCount")->ToNumber<uint32_t>())
118                 : std::pair<bool, uint32_t>(false, UNUSED_CACHED_SIZE_PARAM);
119     }
120 
121     // arg 2
122     auto handlers = JSRef<JSObject>::Cast(info[PARAM_HANDLERS]);
123     auto onCreateNode = [execCtx = info.GetExecutionContext(), func = JSFUNC(handlers, "onCreateNode")](
124                             uint32_t forIndex) -> void {
125         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
126         auto params = ConvertToJSValues(forIndex);
127         func->Call(JSRef<JSObject>(), params.size(), params.data());
128     };
129 
130     auto onUpdateNode = [execCtx = info.GetExecutionContext(), func = JSFUNC(handlers, "onUpdateNode")](
131                             const std::string& fromKey, uint32_t forIndex) -> void {
132         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
133         auto params = ConvertToJSValues(fromKey, forIndex);
134         func->Call(JSRef<JSObject>(), params.size(), params.data());
135     };
136 
137     auto onGetKeys4Range = [execCtx = info.GetExecutionContext(), func = JSFUNC(handlers, "onGetKeys4Range")](
138                                uint32_t from, uint32_t to) -> std::list<std::string> {
139         std::list<std::string> list;
140         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, list);
141         auto params = ConvertToJSValues(from, to);
142         JSRef<JSVal> jsVal = func->Call(JSRef<JSObject>(), params.size(), params.data());
143         // convert js-array to std::list
144         if (!jsVal->IsArray()) {
145             TAG_LOGW(AceLogTag::ACE_REPEAT, "jsVal should be array.");
146             return list;
147         }
148         JSRef<JSArray> jsArr = JSRef<JSArray>::Cast(jsVal);
149         for (size_t i = 0; i < jsArr->Length(); i++) {
150             list.emplace_back(jsArr->GetValueAt(i)->ToString());
151         }
152         return list;
153     };
154 
155     auto onGetTypes4Range = [execCtx = info.GetExecutionContext(), func = JSFUNC(handlers, "onGetTypes4Range")](
156                                 uint32_t from, uint32_t to) -> std::list<std::string> {
157         std::list<std::string> list;
158         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, list);
159         auto params = ConvertToJSValues(from, to);
160         JSRef<JSVal> jsVal = func->Call(JSRef<JSObject>(), params.size(), params.data());
161 
162         // convert js-array to std::list
163         if (!jsVal->IsArray()) {
164             TAG_LOGW(AceLogTag::ACE_REPEAT, "jsVal should be array.");
165             return list;
166         }
167         JSRef<JSArray> jsArr = JSRef<JSArray>::Cast(jsVal);
168         for (size_t i = 0; i < jsArr->Length(); i++) {
169             list.emplace_back(jsArr->GetValueAt(i)->ToString());
170         }
171         return list;
172     };
173 
174     auto onSetActiveRange = [execCtx = info.GetExecutionContext(), func = JSFUNC(handlers, "onSetActiveRange")](
175                             int32_t from, int32_t to) -> void {
176         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
177         auto params = ConvertToJSValues(from, to);
178         func->Call(JSRef<JSObject>(), params.size(), params.data());
179     };
180 
181     // arg 3
182     auto reusable = info[PARAM_REUSABLE]->ToBoolean();
183 
184     RepeatVirtualScrollModel::GetInstance()->Create(
185         totalCount, templateCachedCountMap, onCreateNode, onUpdateNode, onGetKeys4Range, onGetTypes4Range,
186         onSetActiveRange, reusable);
187 }
188 
UpdateRenderState(const JSCallbackInfo & info)189 void JSRepeatVirtualScroll::UpdateRenderState(const JSCallbackInfo& info)
190 {
191     ACE_SCOPED_TRACE("RepeatVirtualScroll:UpdateRenderState");
192     TAG_LOGD(AceLogTag::ACE_REPEAT, "JSRepeatVirtualScroll::UpdateRenderState");
193     if (!info[0]->IsNumber() || !info[1]->IsBoolean()) {
194         return;
195     }
196     auto totalCount = info[0]->ToNumber<uint32_t>();
197     auto visibleItemsChanged = info[1]->ToBoolean();
198     RepeatVirtualScrollModel::GetInstance()->UpdateRenderState(totalCount, visibleItemsChanged);
199 }
200 
OnMove(const JSCallbackInfo & info)201 void JSRepeatVirtualScroll::OnMove(const JSCallbackInfo& info)
202 {
203     if (!info[0]->IsFunction()) {
204         RepeatVirtualScrollModel::GetInstance()->OnMove(nullptr);
205         return;
206     }
207     auto onMove = [execCtx = info.GetExecutionContext(), func = JSRef<JSFunc>::Cast(info[0])](
208                       int32_t from, int32_t to) {
209         auto params = ConvertToJSValues(from, to);
210         func->Call(JSRef<JSObject>(), params.size(), params.data());
211     };
212     RepeatVirtualScrollModel::GetInstance()->OnMove(std::move(onMove));
213 }
214 
SetCreateByTemplate(const JSCallbackInfo & info)215 void JSRepeatVirtualScroll::SetCreateByTemplate(const JSCallbackInfo& info)
216 {
217     if (!info[0]->IsBoolean()) {
218         TAG_LOGE(AceLogTag::ACE_REPEAT, "JSRepeatVirtualScroll::SetCreateByTemplate wrong parameter, internal error.");
219         return;
220     }
221     RepeatVirtualScrollModel::GetInstance()->SetCreateByTemplate(info[0]->ToBoolean());
222 }
223 
JSBind(BindingTarget globalObj)224 void JSRepeatVirtualScroll::JSBind(BindingTarget globalObj)
225 {
226     JSClass<JSRepeatVirtualScroll>::Declare("RepeatVirtualScrollNative");
227     JSClass<JSRepeatVirtualScroll>::StaticMethod("create", &JSRepeatVirtualScroll::Create);
228     JSClass<JSRepeatVirtualScroll>::StaticMethod("updateRenderState", &JSRepeatVirtualScroll::UpdateRenderState);
229     JSClass<JSRepeatVirtualScroll>::StaticMethod("onMove", &JSRepeatVirtualScroll::OnMove);
230     JSClass<JSRepeatVirtualScroll>::StaticMethod("setCreateByTemplate", &JSRepeatVirtualScroll::SetCreateByTemplate);
231     JSClass<JSRepeatVirtualScroll>::Bind<>(globalObj);
232 }
233 
234 } // namespace OHOS::Ace::Framework
235