• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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_scroll.h"
17 
18 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
19 
20 #include "base/utils/utils.h"
21 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_scroll_theme.h"
22 #include "bridge/declarative_frontend/jsview/js_scrollable.h"
23 #include "bridge/declarative_frontend/jsview/js_scroller.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/scroll_model_impl.h"
26 #include "core/common/container.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components/scroll/scrollable.h"
29 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h"
30 #include "core/components_ng/pattern/scroll/scroll_model_ng.h"
31 
32 namespace OHOS::Ace {
33 
34 std::unique_ptr<ScrollModel> ScrollModel::instance_ = nullptr;
35 std::mutex ScrollModel::mutex_;
36 
GetInstance()37 ScrollModel* ScrollModel::GetInstance()
38 {
39     if (!instance_) {
40         std::lock_guard<std::mutex> lock(mutex_);
41         if (!instance_) {
42 #ifdef NG_BUILD
43             instance_.reset(new NG::ScrollModelNG());
44 #else
45             if (Container::IsCurrentUseNewPipeline()) {
46                 instance_.reset(new NG::ScrollModelNG());
47             } else {
48                 instance_.reset(new Framework::ScrollModelImpl());
49             }
50 #endif
51         }
52     }
53     return instance_.get();
54 }
55 
56 } // namespace OHOS::Ace
57 
58 namespace OHOS::Ace::Framework {
59 namespace {
60 const std::vector<Axis> AXIS = { Axis::VERTICAL, Axis::HORIZONTAL, Axis::NONE, Axis::NONE, Axis::FREE };
61 
ParseJsDimensionArray(const JSRef<JSVal> & jsValue,std::vector<Dimension> & result,std::vector<RefPtr<ResourceObject>> & resObjs)62 bool ParseJsDimensionArray(
63     const JSRef<JSVal>& jsValue, std::vector<Dimension>& result, std::vector<RefPtr<ResourceObject>>& resObjs)
64 {
65     if (!jsValue->IsArray()) {
66         return false;
67     }
68     bool parseOK = true;
69     JSRef<JSArray> array = JSRef<JSArray>::Cast(jsValue);
70     for (size_t i = 0; i < array->Length(); i++) {
71         JSRef<JSVal> value = array->GetValueAt(i);
72         CalcDimension dimension;
73         RefPtr<ResourceObject> resObj;
74         auto parseDimensionOK = JSViewAbstract::ParseJsDimensionVp(value, dimension, resObj);
75         result.emplace_back(static_cast<Dimension>(dimension));
76         resObjs.emplace_back(resObj);
77         if (!parseDimensionOK) {
78             parseOK = false;
79         }
80     }
81     return parseOK;
82 }
83 
CheckSnapPaginations(std::vector<Dimension> snapPaginations)84 bool CheckSnapPaginations(std::vector<Dimension> snapPaginations)
85 {
86     CHECK_NULL_RETURN(!snapPaginations.empty(), false);
87     float preValue = (*snapPaginations.begin()).Value();
88     CHECK_NULL_RETURN(!Negative(preValue), false);
89     auto unit = (*snapPaginations.begin()).Unit();
90     for (auto iter = snapPaginations.begin() + 1; iter < snapPaginations.end(); ++iter) {
91         if (Negative((*iter).Value()) || (*iter).Unit() != unit || LessOrEqual((*iter).Value(), preValue)) {
92             return false;
93         }
94         preValue = (*iter).Value();
95     }
96     return true;
97 }
98 } // namespace
99 
Create(const JSCallbackInfo & info)100 void JSScroll::Create(const JSCallbackInfo& info)
101 {
102     ScrollModel::GetInstance()->Create();
103     if (info.Length() > 0 && info[0]->IsObject()) {
104         JSScroller* jsScroller = JSRef<JSObject>::Cast(info[0])->Unwrap<JSScroller>();
105         if (jsScroller) {
106             jsScroller->SetInstanceId(Container::CurrentId());
107             auto positionController = ScrollModel::GetInstance()->GetOrCreateController();
108             jsScroller->SetController(positionController);
109             // Init scroll bar proxy.
110             auto proxy = jsScroller->GetScrollBarProxy();
111             if (!proxy) {
112                 proxy = ScrollModel::GetInstance()->CreateScrollBarProxy();
113                 jsScroller->SetScrollBarProxy(proxy);
114             }
115             ScrollModel::GetInstance()->SetScrollBarProxy(proxy);
116         }
117     }
118     JSScrollTheme::ApplyTheme();
119 }
120 
SetScrollable(int32_t value)121 void JSScroll::SetScrollable(int32_t value)
122 {
123     if (value < 0 || value >= static_cast<int32_t>(AXIS.size())) {
124         return;
125     }
126     ScrollModel::GetInstance()->SetAxis(AXIS[value]);
127 }
128 
SetScrollEnabled(const JSCallbackInfo & args)129 void JSScroll::SetScrollEnabled(const JSCallbackInfo& args)
130 {
131     ScrollModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
132 }
133 
OnScrollBeginCallback(const JSCallbackInfo & args)134 void JSScroll::OnScrollBeginCallback(const JSCallbackInfo& args)
135 {
136     if (args[0]->IsFunction()) {
137         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
138                                  const Dimension& dx, const Dimension& dy) -> ScrollInfo {
139             ScrollInfo scrollInfo { .dx = dx, .dy = dy };
140             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo);
141             auto params = ConvertToJSValues(dx, dy);
142             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
143             if (result.IsEmpty()) {
144                 return scrollInfo;
145             }
146 
147             if (!result->IsObject()) {
148                 return scrollInfo;
149             }
150 
151             auto resObj = JSRef<JSObject>::Cast(result);
152             auto dxRemainValue = resObj->GetProperty("dxRemain");
153             if (dxRemainValue->IsNumber()) {
154                 scrollInfo.dx = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
155             }
156             auto dyRemainValue = resObj->GetProperty("dyRemain");
157             if (dyRemainValue->IsNumber()) {
158                 scrollInfo.dy = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
159             }
160             return scrollInfo;
161         };
162         ScrollModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin));
163     }
164     args.SetReturnValue(args.This());
165 }
166 
OnScrollFrameBeginCallback(const JSCallbackInfo & args)167 void JSScroll::OnScrollFrameBeginCallback(const JSCallbackInfo& args)
168 {
169     if (args[0]->IsFunction()) {
170         auto onScrollFrameBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
171                                       const Dimension& offset, ScrollState state) -> ScrollFrameResult {
172             OHOS::Ace::ScrollFrameResult scrollRes { .offset = offset };
173             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
174             auto params = ConvertToJSValues(offset, state);
175             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
176             if (result.IsEmpty()) {
177                 return scrollRes;
178             }
179 
180             if (!result->IsObject()) {
181                 return scrollRes;
182             }
183 
184             auto resObj = JSRef<JSObject>::Cast(result);
185             auto dxRemainValue = resObj->GetProperty("offsetRemain");
186             if (dxRemainValue->IsNumber()) {
187                 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
188             }
189             return scrollRes;
190         };
191         ScrollModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollFrameBegin));
192     }
193     args.SetReturnValue(args.This());
194 }
195 
OnScrollCallback(const JSCallbackInfo & args)196 void JSScroll::OnScrollCallback(const JSCallbackInfo& args)
197 {
198     auto callbackInfo = args[0];
199     if (callbackInfo->IsFunction()) {
200         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(callbackInfo)](
201                             const Dimension& xOffset, const Dimension& yOffset) {
202             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
203             auto params = ConvertToJSValues(xOffset, yOffset);
204             func->Call(JSRef<JSObject>(), params.size(), params.data());
205         };
206         ScrollModel::GetInstance()->SetOnScroll(std::move(onScroll));
207     }
208 }
209 
OnWillScrollCallback(const JSCallbackInfo & args)210 void JSScroll::OnWillScrollCallback(const JSCallbackInfo& args)
211 {
212     if (args.Length() <= 0) {
213         return;
214     }
215 
216     if (args[0]->IsFunction()) {
217         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
218                             const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState,
219                             ScrollSource scrollSource) {
220             auto params = ConvertToJSValues(xOffset, yOffset, scrollState, scrollSource);
221             NG::TwoDimensionScrollResult scrollRes { .xOffset = xOffset, .yOffset = yOffset };
222             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
223             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
224             if (result.IsEmpty()) {
225                 return scrollRes;
226             }
227 
228             if (!result->IsObject()) {
229                 return scrollRes;
230             }
231 
232             auto resObj = JSRef<JSObject>::Cast(result);
233             auto dxRemainValue = resObj->GetProperty("xOffset");
234             if (dxRemainValue->IsNumber()) {
235                 scrollRes.xOffset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
236             }
237             auto dyRemainValue = resObj->GetProperty("yOffset");
238             if (dyRemainValue->IsNumber()) {
239                 scrollRes.yOffset = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
240             }
241             return scrollRes;
242         };
243         ScrollModel::GetInstance()->SetOnWillScroll(std::move(onScroll));
244     } else {
245         ScrollModel::GetInstance()->SetOnWillScroll(nullptr);
246     }
247 }
248 
OnDidScrollCallback(const JSCallbackInfo & args)249 void JSScroll::OnDidScrollCallback(const JSCallbackInfo& args)
250 {
251     if (args.Length() > 0 && args[0]->IsFunction()) {
252         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
253                             const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState) {
254             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
255             auto params = ConvertToJSValues(xOffset, yOffset, scrollState);
256             func->Call(JSRef<JSObject>(), params.size(), params.data());
257         };
258         ScrollModel::GetInstance()->SetOnDidScroll(std::move(onScroll));
259     }
260 }
261 
OnScrollEdgeCallback(const JSCallbackInfo & args)262 void JSScroll::OnScrollEdgeCallback(const JSCallbackInfo& args)
263 {
264     if (args[0]->IsFunction()) {
265         auto scrollEdge = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
266                               const NG::ScrollEdge& side) {
267             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
268             auto params = ConvertToJSValues(side);
269             func->Call(JSRef<JSObject>(), 1, params.data());
270             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEdge");
271         };
272         ScrollModel::GetInstance()->SetOnScrollEdge(std::move(scrollEdge));
273     }
274     args.SetReturnValue(args.This());
275 }
276 
OnScrollEndCallback(const JSCallbackInfo & args)277 void JSScroll::OnScrollEndCallback(const JSCallbackInfo& args)
278 {
279     if (args[0]->IsFunction()) {
280         auto scrollEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
281             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
282             func->Call(JSRef<JSObject>(), 0, nullptr);
283             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEnd");
284         };
285         ScrollModel::GetInstance()->SetOnScrollEnd(std::move(scrollEnd));
286     }
287     args.SetReturnValue(args.This());
288 }
289 
OnScrollStartCallback(const JSCallbackInfo & args)290 void JSScroll::OnScrollStartCallback(const JSCallbackInfo& args)
291 {
292     if (args[0]->IsFunction()) {
293         auto scrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
294             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
295             func->Call(JSRef<JSObject>(), 0, nullptr);
296         };
297         ScrollModel::GetInstance()->SetOnScrollStart(std::move(scrollStart));
298     }
299     args.SetReturnValue(args.This());
300 }
301 
OnScrollStopCallback(const JSCallbackInfo & args)302 void JSScroll::OnScrollStopCallback(const JSCallbackInfo& args)
303 {
304     if (args[0]->IsFunction()) {
305         auto scrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
306             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
307             func->Call(JSRef<JSObject>(), 0, nullptr);
308             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollStop");
309         };
310         ScrollModel::GetInstance()->SetOnScrollStop(std::move(scrollStop));
311     }
312     args.SetReturnValue(args.This());
313 }
314 
ReachStartCallback(const JSCallbackInfo & args)315 void JSScroll::ReachStartCallback(const JSCallbackInfo& args)
316 {
317     if (args[0]->IsFunction()) {
318         auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
319             func->Call(JSRef<JSObject>());
320             return;
321         };
322         ScrollModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
323     }
324     args.ReturnSelf();
325 }
326 
ReachEndCallback(const JSCallbackInfo & args)327 void JSScroll::ReachEndCallback(const JSCallbackInfo& args)
328 {
329     if (args[0]->IsFunction()) {
330         auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
331             func->Call(JSRef<JSObject>());
332             return;
333         };
334         ScrollModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
335     }
336     args.ReturnSelf();
337 }
338 
JSBind(BindingTarget globalObj)339 void JSScroll::JSBind(BindingTarget globalObj)
340 {
341     JSClass<JSScroll>::Declare("Scroll");
342     MethodOptions opt = MethodOptions::NONE;
343     JSClass<JSScroll>::StaticMethod("create", &JSScroll::Create, opt);
344     JSClass<JSScroll>::StaticMethod("scrollable", &JSScroll::SetScrollable, opt);
345     JSClass<JSScroll>::StaticMethod("onScrollBegin", &JSScroll::OnScrollBeginCallback, opt);
346     JSClass<JSScroll>::StaticMethod("onScrollFrameBegin", &JSScroll::OnScrollFrameBeginCallback, opt);
347     JSClass<JSScroll>::StaticMethod("onScroll", &JSScroll::OnScrollCallback, opt);
348     JSClass<JSScroll>::StaticMethod("onWillScroll", &JSScroll::OnWillScrollCallback, opt);
349     JSClass<JSScroll>::StaticMethod("onDidScroll", &JSScroll::OnDidScrollCallback, opt);
350     JSClass<JSScroll>::StaticMethod("onScrollEdge", &JSScroll::OnScrollEdgeCallback, opt);
351     JSClass<JSScroll>::StaticMethod("onScrollEnd", &JSScroll::OnScrollEndCallback, opt);
352     JSClass<JSScroll>::StaticMethod("onScrollStart", &JSScroll::OnScrollStartCallback, opt);
353     JSClass<JSScroll>::StaticMethod("onScrollStop", &JSScroll::OnScrollStopCallback, opt);
354     JSClass<JSScroll>::StaticMethod("onReachStart", &JSScroll::ReachStartCallback);
355     JSClass<JSScroll>::StaticMethod("onReachEnd", &JSScroll::ReachEndCallback);
356     JSClass<JSScroll>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
357     JSClass<JSScroll>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
358     JSClass<JSScroll>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
359     JSClass<JSScroll>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
360     JSClass<JSScroll>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
361     JSClass<JSScroll>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
362     JSClass<JSScroll>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
363     JSClass<JSScroll>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
364     JSClass<JSScroll>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
365     JSClass<JSScroll>::StaticMethod("edgeEffect", &JSScroll::SetEdgeEffect, opt);
366     JSClass<JSScroll>::StaticMethod("scrollBar", &JSScroll::SetScrollBar, opt);
367     JSClass<JSScroll>::StaticMethod("scrollBarColor", &JSScroll::SetScrollBarColor, opt);
368     JSClass<JSScroll>::StaticMethod("scrollBarWidth", &JSScroll::SetScrollBarWidth, opt);
369     JSClass<JSScroll>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
370     JSClass<JSScroll>::StaticMethod("width", &JSScroll::JsWidth);
371     JSClass<JSScroll>::StaticMethod("height", &JSScroll::JsHeight);
372     JSClass<JSScroll>::StaticMethod("nestedScroll", &JSScroll::SetNestedScroll);
373     JSClass<JSScroll>::StaticMethod("enableScrollInteraction", &JSScroll::SetScrollEnabled);
374     JSClass<JSScroll>::StaticMethod("friction", &JSScroll::SetFriction);
375     JSClass<JSScroll>::StaticMethod("scrollSnap", &JSScroll::SetScrollSnap);
376     JSClass<JSScroll>::StaticMethod("enablePaging", &JSScroll::SetEnablePaging);
377     JSClass<JSScroll>::StaticMethod("clip", &JSScrollable::JsClip);
378     JSClass<JSScroll>::StaticMethod("initialOffset", &JSScroll::SetInitialOffset);
379     JSClass<JSScroll>::StaticMethod("maxZoomScale", &JSScroll::SetMaxZoomScale);
380     JSClass<JSScroll>::StaticMethod("minZoomScale", &JSScroll::SetMinZoomScale);
381     JSClass<JSScroll>::StaticMethod("zoomScale", &JSScroll::SetZoomScale);
382     JSClass<JSScroll>::StaticMethod("enableBouncesZoom", &JSScroll::SetEnableBouncesZoom);
383     JSClass<JSScroll>::StaticMethod("onDidZoom", &JSScroll::OnDidZoomCallback, opt);
384     JSClass<JSScroll>::StaticMethod("onZoomStart", &JSScroll::OnZoomStartCallback, opt);
385     JSClass<JSScroll>::StaticMethod("onZoomStop", &JSScroll::OnZoomStopCallback, opt);
386     JSClass<JSScroll>::InheritAndBind<JSScrollableBase>(globalObj);
387 }
388 
SetScrollBar(const JSCallbackInfo & args)389 void JSScroll::SetScrollBar(const JSCallbackInfo& args)
390 {
391     if (args.Length() < 1) {
392         return;
393     }
394     int32_t displayMode;
395     if (args[0]->IsNull() || args[0]->IsUndefined() || !ParseJsInt32(args[0], displayMode)) {
396         displayMode = static_cast<int32_t>(DisplayMode::AUTO);
397     }
398     ScrollModel::GetInstance()->SetDisplayMode(displayMode);
399 }
400 
SetScrollBarWidth(const JSCallbackInfo & args)401 void JSScroll::SetScrollBarWidth(const JSCallbackInfo& args)
402 {
403     auto pipelineContext = PipelineContext::GetCurrentContext();
404     CHECK_NULL_VOID(pipelineContext);
405     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
406     CHECK_NULL_VOID(theme);
407     CalcDimension scrollBarWidth;
408     if (args.Length() < 1) {
409         return;
410     }
411     if (!ParseJsDimensionVp(args[0], scrollBarWidth) || args[0]->IsNull() || args[0]->IsUndefined() ||
412         (args[0]->IsString() && args[0]->ToString().empty()) || LessNotEqual(scrollBarWidth.Value(), 0.0) ||
413         scrollBarWidth.Unit() == DimensionUnit::PERCENT) {
414         scrollBarWidth = theme->GetNormalWidth();
415     }
416     ScrollModel::GetInstance()->SetScrollBarWidth(scrollBarWidth);
417 }
418 
SetScrollBarColor(const JSCallbackInfo & args)419 void JSScroll::SetScrollBarColor(const JSCallbackInfo& args)
420 {
421     auto pipelineContext = PipelineContext::GetCurrentContext();
422     CHECK_NULL_VOID(pipelineContext);
423     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
424     CHECK_NULL_VOID(theme);
425     Color color(theme->GetForegroundColor());
426     RefPtr<ResourceObject> resObj;
427     JSViewAbstract::ParseJsColor(args[0], color, resObj);
428     if (SystemProperties::ConfigChangePerform()) {
429         ScrollModel::GetInstance()->CreateWithResourceObjScrollBarColor(resObj);
430     }
431     ScrollModel::GetInstance()->SetScrollBarColor(color);
432 }
433 
SetEdgeEffect(const JSCallbackInfo & args)434 void JSScroll::SetEdgeEffect(const JSCallbackInfo& args)
435 {
436     auto edgeEffect = EdgeEffect::NONE;
437     auto effectEdge = EffectEdge::ALL;
438     if (args.Length() > 0) {
439         edgeEffect = JSScrollable::ParseEdgeEffect(args[0], EdgeEffect::NONE);
440     }
441     auto alwaysEnabled = true;
442     if (args.Length() > 1) {
443         alwaysEnabled = JSScrollable::ParseAlwaysEnable(args[1], true);
444         effectEdge = JSScrollable::ParseEffectEdge(args[1]);
445     }
446     ScrollModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled, effectEdge);
447 }
448 
JsWidth(const JSCallbackInfo & info)449 void JSScroll::JsWidth(const JSCallbackInfo& info)
450 {
451     JSViewAbstract::JsWidth(info);
452     ScrollModel::GetInstance()->SetHasWidth(true);
453 }
454 
JsHeight(const JSCallbackInfo & info)455 void JSScroll::JsHeight(const JSCallbackInfo& info)
456 {
457     JSViewAbstract::JsHeight(info);
458     ScrollModel::GetInstance()->SetHasHeight(true);
459 }
460 
SetNestedScroll(const JSCallbackInfo & args)461 void JSScroll::SetNestedScroll(const JSCallbackInfo& args)
462 {
463     NestedScrollOptions nestedOpt = {
464         .forward = NestedScrollMode::SELF_ONLY,
465         .backward = NestedScrollMode::SELF_ONLY,
466     };
467     if (args.Length() < 1 || !args[0]->IsObject()) {
468         ScrollModel::GetInstance()->SetNestedScroll(nestedOpt);
469         return;
470     }
471     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
472     int32_t froward = 0;
473     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
474     if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
475         froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
476         froward = 0;
477     }
478     int32_t backward = 0;
479     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
480     if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
481         backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
482         backward = 0;
483     }
484     nestedOpt.forward = static_cast<NestedScrollMode>(froward);
485     nestedOpt.backward = static_cast<NestedScrollMode>(backward);
486     ScrollModel::GetInstance()->SetNestedScroll(nestedOpt);
487     args.ReturnSelf();
488 }
489 
SetFriction(const JSCallbackInfo & info)490 void JSScroll::SetFriction(const JSCallbackInfo& info)
491 {
492     double friction = -1.0;
493     RefPtr<ResourceObject> resObj;
494     if (!JSViewAbstract::ParseJsDouble(info[0], friction, resObj)) {
495         friction = -1.0;
496     }
497     if (SystemProperties::ConfigChangePerform()) {
498         ScrollModel::GetInstance()->CreateWithResourceObjFriction(resObj);
499     }
500     ScrollModel::GetInstance()->SetFriction(friction);
501 }
502 
SetScrollSnap(const JSCallbackInfo & args)503 void JSScroll::SetScrollSnap(const JSCallbackInfo& args)
504 {
505     if (args.Length() < 1 || !args[0]->IsObject()) {
506         return;
507     }
508     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
509     auto snapAlignValue = obj->GetProperty("snapAlign");
510     int32_t snapAlign = static_cast<int32_t>(ScrollSnapAlign::NONE);
511     if (snapAlignValue->IsNull() || snapAlignValue->IsUndefined() || !ParseJsInt32(snapAlignValue, snapAlign) ||
512         snapAlign < static_cast<int32_t>(ScrollSnapAlign::NONE) ||
513         snapAlign > static_cast<int32_t>(ScrollSnapAlign::END)) {
514         snapAlign = static_cast<int32_t>(ScrollSnapAlign::NONE);
515     }
516 
517     auto paginationValue = obj->GetProperty("snapPagination");
518     CalcDimension intervalSize;
519     RefPtr<ResourceObject> resObj;
520     std::vector<Dimension> snapPaginations;
521     std::vector<RefPtr<ResourceObject>> resObjs;
522     if (!ParseJsDimensionVp(paginationValue, intervalSize, resObj) || intervalSize.IsNegative()) {
523         intervalSize = CalcDimension(0.0);
524     }
525     auto parseArrayOK = ParseJsDimensionArray(paginationValue, snapPaginations, resObjs);
526     if (SystemProperties::ConfigChangePerform()) {
527         ScrollModel::GetInstance()->CreateWithResourceObjIntervalSize(resObj);
528         ScrollModel::GetInstance()->CreateWithResourceObjSnapPaginations(snapPaginations, resObjs);
529     }
530     if (!parseArrayOK || !CheckSnapPaginations(snapPaginations)) {
531         std::vector<Dimension>().swap(snapPaginations);
532     }
533 
534     bool enableSnapToStart = true;
535     bool enableSnapToEnd = true;
536     ParseJsBool(obj->GetProperty("enableSnapToStart"), enableSnapToStart);
537     ParseJsBool(obj->GetProperty("enableSnapToEnd"), enableSnapToEnd);
538     std::pair<bool, bool> enableSnapToSide = { enableSnapToStart, enableSnapToEnd };
539     ScrollModel::GetInstance()->SetScrollSnap(
540         static_cast<ScrollSnapAlign>(snapAlign), intervalSize, snapPaginations, enableSnapToSide);
541 }
542 
SetEnablePaging(const JSCallbackInfo & args)543 void JSScroll::SetEnablePaging(const JSCallbackInfo& args)
544 {
545     if (args.Length() < 1 || !args[0]->IsBoolean()) {
546         return;
547     }
548     ScrollModel::GetInstance()->SetEnablePaging(args[0]->ToBoolean());
549 }
550 
SetInitialOffset(const JSCallbackInfo & args)551 void JSScroll::SetInitialOffset(const JSCallbackInfo& args)
552 {
553     if (args.Length() < 1 || !args[0]->IsObject()) {
554         return;
555     }
556 
557     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
558     CalcDimension xOffset;
559     ParseJsDimensionVp(obj->GetProperty("xOffset"), xOffset);
560     CalcDimension yOffset;
561     ParseJsDimensionVp(obj->GetProperty("yOffset"), yOffset);
562     ScrollModel::GetInstance()->SetInitialOffset(NG::OffsetT(xOffset, yOffset));
563 }
564 
SetMaxZoomScale(const JSCallbackInfo & args)565 void JSScroll::SetMaxZoomScale(const JSCallbackInfo& args)
566 {
567     if (args.Length() < 1) {
568         return;
569     }
570     double maxZoomScale = 1.0;
571     JSViewAbstract::ParseJsDouble(args[0], maxZoomScale);
572     ScrollModel::GetInstance()->SetMaxZoomScale(maxZoomScale);
573 }
574 
SetMinZoomScale(const JSCallbackInfo & args)575 void JSScroll::SetMinZoomScale(const JSCallbackInfo& args)
576 {
577     if (args.Length() < 1) {
578         return;
579     }
580     double minZoomScale = 1.0;
581     JSViewAbstract::ParseJsDouble(args[0], minZoomScale);
582     ScrollModel::GetInstance()->SetMinZoomScale(minZoomScale);
583 }
584 
SetZoomScale(const JSCallbackInfo & args)585 void JSScroll::SetZoomScale(const JSCallbackInfo& args)
586 {
587     if (args.Length() < 1) {
588         return;
589     }
590     double zoomScale = 1.0;
591     JSRef<JSVal> changeEventVal;
592     auto scaleValue = args[0];
593     if (scaleValue->IsObject()) {
594         JSRef<JSObject> obj = JSRef<JSObject>::Cast(scaleValue);
595         scaleValue = obj->GetProperty("value");
596         changeEventVal = obj->GetProperty("$value");
597     }
598     if (JSViewAbstract::ParseJsDouble(scaleValue, zoomScale)) {
599         ScrollModel::GetInstance()->SetZoomScale(zoomScale);
600     } else {
601         ScrollModel::GetInstance()->ResetZoomScale();
602     }
603     if (changeEventVal->IsFunction()) {
604         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
605         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
606         auto changeEvent = [execCtx = args.GetExecutionContext(),
607             func = std::move(jsFunc), node = targetNode](float param) {
608             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
609             auto newJSVal = JSRef<JSVal>::Make(ToJSValue(param));
610             PipelineContext::SetCallBackNode(node);
611             func->ExecuteJS(1, &newJSVal);
612         };
613         ScrollModel::GetInstance()->SetZoomScaleChangeEvent(std::move(changeEvent));
614     }
615 }
616 
SetEnableBouncesZoom(const JSCallbackInfo & args)617 void JSScroll::SetEnableBouncesZoom(const JSCallbackInfo& args)
618 {
619     if (args.Length() < 1) {
620         return;
621     }
622     bool enableBouncesZoom = true;
623     if (args[0]->IsBoolean()) {
624         enableBouncesZoom = args[0]->ToBoolean();
625     }
626     ScrollModel::GetInstance()->SetEnableBouncesZoom(enableBouncesZoom);
627 }
628 
OnDidZoomCallback(const JSCallbackInfo & args)629 void JSScroll::OnDidZoomCallback(const JSCallbackInfo& args)
630 {
631     if (args.Length() > 0 && args[0]->IsFunction()) {
632         auto onZoom = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](float scale) {
633             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
634             auto params = ConvertToJSValues(scale);
635             func->Call(JSRef<JSObject>(), params.size(), params.data());
636         };
637         ScrollModel::GetInstance()->SetOnDidZoom(std::move(onZoom));
638     } else {
639         ScrollModel::GetInstance()->SetOnDidZoom(nullptr);
640     }
641     args.SetReturnValue(args.This());
642 }
643 
OnZoomStartCallback(const JSCallbackInfo & args)644 void JSScroll::OnZoomStartCallback(const JSCallbackInfo& args)
645 {
646     if (args[0]->IsFunction()) {
647         auto zoomStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
648             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
649             func->Call(JSRef<JSObject>(), 0, nullptr);
650         };
651         ScrollModel::GetInstance()->SetOnZoomStart(std::move(zoomStart));
652     } else {
653         ScrollModel::GetInstance()->SetOnZoomStart(nullptr);
654     }
655     args.SetReturnValue(args.This());
656 }
657 
OnZoomStopCallback(const JSCallbackInfo & args)658 void JSScroll::OnZoomStopCallback(const JSCallbackInfo& args)
659 {
660     if (args[0]->IsFunction()) {
661         auto zoomStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
662             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
663             func->Call(JSRef<JSObject>(), 0, nullptr);
664         };
665         ScrollModel::GetInstance()->SetOnZoomStop(std::move(zoomStop));
666     } else {
667         ScrollModel::GetInstance()->SetOnZoomStop(nullptr);
668     }
669     args.SetReturnValue(args.This());
670 }
671 } // namespace OHOS::Ace::Framework
672