/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "bridge/declarative_frontend/jsview/js_scroll.h" #include "interfaces/inner_api/ui_session/ui_session_manager.h" #include "base/utils/utils.h" #include "bridge/declarative_frontend/ark_theme/theme_apply/js_scroll_theme.h" #include "bridge/declarative_frontend/jsview/js_scrollable.h" #include "bridge/declarative_frontend/jsview/js_scroller.h" #include "bridge/declarative_frontend/jsview/js_view_common_def.h" #include "bridge/declarative_frontend/jsview/models/scroll_model_impl.h" #include "core/common/container.h" #include "core/components/common/layout/constants.h" #include "core/components/scroll/scrollable.h" #include "core/components_ng/pattern/scroll/inner/scroll_bar.h" #include "core/components_ng/pattern/scroll/scroll_model_ng.h" namespace OHOS::Ace { std::unique_ptr ScrollModel::instance_ = nullptr; std::mutex ScrollModel::mutex_; ScrollModel* ScrollModel::GetInstance() { if (!instance_) { std::lock_guard lock(mutex_); if (!instance_) { #ifdef NG_BUILD instance_.reset(new NG::ScrollModelNG()); #else if (Container::IsCurrentUseNewPipeline()) { instance_.reset(new NG::ScrollModelNG()); } else { instance_.reset(new Framework::ScrollModelImpl()); } #endif } } return instance_.get(); } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { const std::vector AXIS = { Axis::VERTICAL, Axis::HORIZONTAL, Axis::NONE, Axis::NONE, Axis::FREE }; bool ParseJsDimensionArray( const JSRef& jsValue, std::vector& result, std::vector>& resObjs) { if (!jsValue->IsArray()) { return false; } bool parseOK = true; JSRef array = JSRef::Cast(jsValue); for (size_t i = 0; i < array->Length(); i++) { JSRef value = array->GetValueAt(i); CalcDimension dimension; RefPtr resObj; auto parseDimensionOK = JSViewAbstract::ParseJsDimensionVp(value, dimension, resObj); result.emplace_back(static_cast(dimension)); resObjs.emplace_back(resObj); if (!parseDimensionOK) { parseOK = false; } } return parseOK; } bool CheckSnapPaginations(std::vector snapPaginations) { CHECK_NULL_RETURN(!snapPaginations.empty(), false); float preValue = (*snapPaginations.begin()).Value(); CHECK_NULL_RETURN(!Negative(preValue), false); auto unit = (*snapPaginations.begin()).Unit(); for (auto iter = snapPaginations.begin() + 1; iter < snapPaginations.end(); ++iter) { if (Negative((*iter).Value()) || (*iter).Unit() != unit || LessOrEqual((*iter).Value(), preValue)) { return false; } preValue = (*iter).Value(); } return true; } } // namespace void JSScroll::Create(const JSCallbackInfo& info) { ScrollModel::GetInstance()->Create(); if (info.Length() > 0 && info[0]->IsObject()) { JSScroller* jsScroller = JSRef::Cast(info[0])->Unwrap(); if (jsScroller) { jsScroller->SetInstanceId(Container::CurrentId()); auto positionController = ScrollModel::GetInstance()->GetOrCreateController(); jsScroller->SetController(positionController); // Init scroll bar proxy. auto proxy = jsScroller->GetScrollBarProxy(); if (!proxy) { proxy = ScrollModel::GetInstance()->CreateScrollBarProxy(); jsScroller->SetScrollBarProxy(proxy); } ScrollModel::GetInstance()->SetScrollBarProxy(proxy); } } JSScrollTheme::ApplyTheme(); } void JSScroll::SetScrollable(int32_t value) { if (value < 0 || value >= static_cast(AXIS.size())) { return; } ScrollModel::GetInstance()->SetAxis(AXIS[value]); } void JSScroll::SetScrollEnabled(const JSCallbackInfo& args) { ScrollModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true); } void JSScroll::OnScrollBeginCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]( const Dimension& dx, const Dimension& dy) -> ScrollInfo { ScrollInfo scrollInfo { .dx = dx, .dy = dy }; JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo); auto params = ConvertToJSValues(dx, dy); auto result = func->Call(JSRef(), params.size(), params.data()); if (result.IsEmpty()) { return scrollInfo; } if (!result->IsObject()) { return scrollInfo; } auto resObj = JSRef::Cast(result); auto dxRemainValue = resObj->GetProperty("dxRemain"); if (dxRemainValue->IsNumber()) { scrollInfo.dx = Dimension(dxRemainValue->ToNumber(), DimensionUnit::VP); } auto dyRemainValue = resObj->GetProperty("dyRemain"); if (dyRemainValue->IsNumber()) { scrollInfo.dy = Dimension(dyRemainValue->ToNumber(), DimensionUnit::VP); } return scrollInfo; }; ScrollModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin)); } args.SetReturnValue(args.This()); } void JSScroll::OnScrollFrameBeginCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto onScrollFrameBegin = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]( const Dimension& offset, ScrollState state) -> ScrollFrameResult { OHOS::Ace::ScrollFrameResult scrollRes { .offset = offset }; JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes); auto params = ConvertToJSValues(offset, state); auto result = func->Call(JSRef(), params.size(), params.data()); if (result.IsEmpty()) { return scrollRes; } if (!result->IsObject()) { return scrollRes; } auto resObj = JSRef::Cast(result); auto dxRemainValue = resObj->GetProperty("offsetRemain"); if (dxRemainValue->IsNumber()) { scrollRes.offset = Dimension(dxRemainValue->ToNumber(), DimensionUnit::VP); } return scrollRes; }; ScrollModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollFrameBegin)); } args.SetReturnValue(args.This()); } void JSScroll::OnScrollCallback(const JSCallbackInfo& args) { auto callbackInfo = args[0]; if (callbackInfo->IsFunction()) { auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(callbackInfo)]( const Dimension& xOffset, const Dimension& yOffset) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); auto params = ConvertToJSValues(xOffset, yOffset); func->Call(JSRef(), params.size(), params.data()); }; ScrollModel::GetInstance()->SetOnScroll(std::move(onScroll)); } } void JSScroll::OnWillScrollCallback(const JSCallbackInfo& args) { if (args.Length() <= 0) { return; } if (args[0]->IsFunction()) { auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]( const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState, ScrollSource scrollSource) { auto params = ConvertToJSValues(xOffset, yOffset, scrollState, scrollSource); NG::TwoDimensionScrollResult scrollRes { .xOffset = xOffset, .yOffset = yOffset }; JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes); auto result = func->Call(JSRef(), params.size(), params.data()); if (result.IsEmpty()) { return scrollRes; } if (!result->IsObject()) { return scrollRes; } auto resObj = JSRef::Cast(result); auto dxRemainValue = resObj->GetProperty("xOffset"); if (dxRemainValue->IsNumber()) { scrollRes.xOffset = Dimension(dxRemainValue->ToNumber(), DimensionUnit::VP); } auto dyRemainValue = resObj->GetProperty("yOffset"); if (dyRemainValue->IsNumber()) { scrollRes.yOffset = Dimension(dyRemainValue->ToNumber(), DimensionUnit::VP); } return scrollRes; }; ScrollModel::GetInstance()->SetOnWillScroll(std::move(onScroll)); } else { ScrollModel::GetInstance()->SetOnWillScroll(nullptr); } } void JSScroll::OnDidScrollCallback(const JSCallbackInfo& args) { if (args.Length() > 0 && args[0]->IsFunction()) { auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]( const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); auto params = ConvertToJSValues(xOffset, yOffset, scrollState); func->Call(JSRef(), params.size(), params.data()); }; ScrollModel::GetInstance()->SetOnDidScroll(std::move(onScroll)); } } void JSScroll::OnScrollEdgeCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto scrollEdge = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]( const NG::ScrollEdge& side) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); auto params = ConvertToJSValues(side); func->Call(JSRef(), 1, params.data()); UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEdge"); }; ScrollModel::GetInstance()->SetOnScrollEdge(std::move(scrollEdge)); } args.SetReturnValue(args.This()); } void JSScroll::OnScrollEndCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto scrollEnd = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->Call(JSRef(), 0, nullptr); UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEnd"); }; ScrollModel::GetInstance()->SetOnScrollEnd(std::move(scrollEnd)); } args.SetReturnValue(args.This()); } void JSScroll::OnScrollStartCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto scrollStart = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->Call(JSRef(), 0, nullptr); }; ScrollModel::GetInstance()->SetOnScrollStart(std::move(scrollStart)); } args.SetReturnValue(args.This()); } void JSScroll::OnScrollStopCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto scrollStop = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->Call(JSRef(), 0, nullptr); UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollStop"); }; ScrollModel::GetInstance()->SetOnScrollStop(std::move(scrollStop)); } args.SetReturnValue(args.This()); } void JSScroll::ReachStartCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { func->Call(JSRef()); return; }; ScrollModel::GetInstance()->SetOnReachStart(std::move(onReachStart)); } args.ReturnSelf(); } void JSScroll::ReachEndCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { func->Call(JSRef()); return; }; ScrollModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd)); } args.ReturnSelf(); } void JSScroll::JSBind(BindingTarget globalObj) { JSClass::Declare("Scroll"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSScroll::Create, opt); JSClass::StaticMethod("scrollable", &JSScroll::SetScrollable, opt); JSClass::StaticMethod("onScrollBegin", &JSScroll::OnScrollBeginCallback, opt); JSClass::StaticMethod("onScrollFrameBegin", &JSScroll::OnScrollFrameBeginCallback, opt); JSClass::StaticMethod("onScroll", &JSScroll::OnScrollCallback, opt); JSClass::StaticMethod("onWillScroll", &JSScroll::OnWillScrollCallback, opt); JSClass::StaticMethod("onDidScroll", &JSScroll::OnDidScrollCallback, opt); JSClass::StaticMethod("onScrollEdge", &JSScroll::OnScrollEdgeCallback, opt); JSClass::StaticMethod("onScrollEnd", &JSScroll::OnScrollEndCallback, opt); JSClass::StaticMethod("onScrollStart", &JSScroll::OnScrollStartCallback, opt); JSClass::StaticMethod("onScrollStop", &JSScroll::OnScrollStopCallback, opt); JSClass::StaticMethod("onReachStart", &JSScroll::ReachStartCallback); JSClass::StaticMethod("onReachEnd", &JSScroll::ReachEndCallback); JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onHover", &JSInteractableView::JsOnHover); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onAttach", &JSInteractableView::JsOnAttach); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDetach", &JSInteractableView::JsOnDetach); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("edgeEffect", &JSScroll::SetEdgeEffect, opt); JSClass::StaticMethod("scrollBar", &JSScroll::SetScrollBar, opt); JSClass::StaticMethod("scrollBarColor", &JSScroll::SetScrollBarColor, opt); JSClass::StaticMethod("scrollBarWidth", &JSScroll::SetScrollBarWidth, opt); JSClass::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage); JSClass::StaticMethod("width", &JSScroll::JsWidth); JSClass::StaticMethod("height", &JSScroll::JsHeight); JSClass::StaticMethod("nestedScroll", &JSScroll::SetNestedScroll); JSClass::StaticMethod("enableScrollInteraction", &JSScroll::SetScrollEnabled); JSClass::StaticMethod("friction", &JSScroll::SetFriction); JSClass::StaticMethod("scrollSnap", &JSScroll::SetScrollSnap); JSClass::StaticMethod("enablePaging", &JSScroll::SetEnablePaging); JSClass::StaticMethod("clip", &JSScrollable::JsClip); JSClass::StaticMethod("initialOffset", &JSScroll::SetInitialOffset); JSClass::StaticMethod("maxZoomScale", &JSScroll::SetMaxZoomScale); JSClass::StaticMethod("minZoomScale", &JSScroll::SetMinZoomScale); JSClass::StaticMethod("zoomScale", &JSScroll::SetZoomScale); JSClass::StaticMethod("enableBouncesZoom", &JSScroll::SetEnableBouncesZoom); JSClass::StaticMethod("onDidZoom", &JSScroll::OnDidZoomCallback, opt); JSClass::StaticMethod("onZoomStart", &JSScroll::OnZoomStartCallback, opt); JSClass::StaticMethod("onZoomStop", &JSScroll::OnZoomStopCallback, opt); JSClass::InheritAndBind(globalObj); } void JSScroll::SetScrollBar(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } int32_t displayMode; if (args[0]->IsNull() || args[0]->IsUndefined() || !ParseJsInt32(args[0], displayMode)) { displayMode = static_cast(DisplayMode::AUTO); } ScrollModel::GetInstance()->SetDisplayMode(displayMode); } void JSScroll::SetScrollBarWidth(const JSCallbackInfo& args) { auto pipelineContext = PipelineContext::GetCurrentContext(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); CalcDimension scrollBarWidth; if (args.Length() < 1) { return; } if (!ParseJsDimensionVp(args[0], scrollBarWidth) || args[0]->IsNull() || args[0]->IsUndefined() || (args[0]->IsString() && args[0]->ToString().empty()) || LessNotEqual(scrollBarWidth.Value(), 0.0) || scrollBarWidth.Unit() == DimensionUnit::PERCENT) { scrollBarWidth = theme->GetNormalWidth(); } ScrollModel::GetInstance()->SetScrollBarWidth(scrollBarWidth); } void JSScroll::SetScrollBarColor(const JSCallbackInfo& args) { auto pipelineContext = PipelineContext::GetCurrentContext(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); Color color(theme->GetForegroundColor()); RefPtr resObj; JSViewAbstract::ParseJsColor(args[0], color, resObj); if (SystemProperties::ConfigChangePerform()) { ScrollModel::GetInstance()->CreateWithResourceObjScrollBarColor(resObj); } ScrollModel::GetInstance()->SetScrollBarColor(color); } void JSScroll::SetEdgeEffect(const JSCallbackInfo& args) { auto edgeEffect = EdgeEffect::NONE; auto effectEdge = EffectEdge::ALL; if (args.Length() > 0) { edgeEffect = JSScrollable::ParseEdgeEffect(args[0], EdgeEffect::NONE); } auto alwaysEnabled = true; if (args.Length() > 1) { alwaysEnabled = JSScrollable::ParseAlwaysEnable(args[1], true); effectEdge = JSScrollable::ParseEffectEdge(args[1]); } ScrollModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled, effectEdge); } void JSScroll::JsWidth(const JSCallbackInfo& info) { JSViewAbstract::JsWidth(info); ScrollModel::GetInstance()->SetHasWidth(true); } void JSScroll::JsHeight(const JSCallbackInfo& info) { JSViewAbstract::JsHeight(info); ScrollModel::GetInstance()->SetHasHeight(true); } void JSScroll::SetNestedScroll(const JSCallbackInfo& args) { NestedScrollOptions nestedOpt = { .forward = NestedScrollMode::SELF_ONLY, .backward = NestedScrollMode::SELF_ONLY, }; if (args.Length() < 1 || !args[0]->IsObject()) { ScrollModel::GetInstance()->SetNestedScroll(nestedOpt); return; } JSRef obj = JSRef::Cast(args[0]); int32_t froward = 0; JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward); if (froward < static_cast(NestedScrollMode::SELF_ONLY) || froward > static_cast(NestedScrollMode::PARALLEL)) { froward = 0; } int32_t backward = 0; JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward); if (backward < static_cast(NestedScrollMode::SELF_ONLY) || backward > static_cast(NestedScrollMode::PARALLEL)) { backward = 0; } nestedOpt.forward = static_cast(froward); nestedOpt.backward = static_cast(backward); ScrollModel::GetInstance()->SetNestedScroll(nestedOpt); args.ReturnSelf(); } void JSScroll::SetFriction(const JSCallbackInfo& info) { double friction = -1.0; RefPtr resObj; if (!JSViewAbstract::ParseJsDouble(info[0], friction, resObj)) { friction = -1.0; } if (SystemProperties::ConfigChangePerform()) { ScrollModel::GetInstance()->CreateWithResourceObjFriction(resObj); } ScrollModel::GetInstance()->SetFriction(friction); } void JSScroll::SetScrollSnap(const JSCallbackInfo& args) { if (args.Length() < 1 || !args[0]->IsObject()) { return; } JSRef obj = JSRef::Cast(args[0]); auto snapAlignValue = obj->GetProperty("snapAlign"); int32_t snapAlign = static_cast(ScrollSnapAlign::NONE); if (snapAlignValue->IsNull() || snapAlignValue->IsUndefined() || !ParseJsInt32(snapAlignValue, snapAlign) || snapAlign < static_cast(ScrollSnapAlign::NONE) || snapAlign > static_cast(ScrollSnapAlign::END)) { snapAlign = static_cast(ScrollSnapAlign::NONE); } auto paginationValue = obj->GetProperty("snapPagination"); CalcDimension intervalSize; RefPtr resObj; std::vector snapPaginations; std::vector> resObjs; if (!ParseJsDimensionVp(paginationValue, intervalSize, resObj) || intervalSize.IsNegative()) { intervalSize = CalcDimension(0.0); } auto parseArrayOK = ParseJsDimensionArray(paginationValue, snapPaginations, resObjs); if (SystemProperties::ConfigChangePerform()) { ScrollModel::GetInstance()->CreateWithResourceObjIntervalSize(resObj); ScrollModel::GetInstance()->CreateWithResourceObjSnapPaginations(snapPaginations, resObjs); } if (!parseArrayOK || !CheckSnapPaginations(snapPaginations)) { std::vector().swap(snapPaginations); } bool enableSnapToStart = true; bool enableSnapToEnd = true; ParseJsBool(obj->GetProperty("enableSnapToStart"), enableSnapToStart); ParseJsBool(obj->GetProperty("enableSnapToEnd"), enableSnapToEnd); std::pair enableSnapToSide = { enableSnapToStart, enableSnapToEnd }; ScrollModel::GetInstance()->SetScrollSnap( static_cast(snapAlign), intervalSize, snapPaginations, enableSnapToSide); } void JSScroll::SetEnablePaging(const JSCallbackInfo& args) { if (args.Length() < 1 || !args[0]->IsBoolean()) { return; } ScrollModel::GetInstance()->SetEnablePaging(args[0]->ToBoolean()); } void JSScroll::SetInitialOffset(const JSCallbackInfo& args) { if (args.Length() < 1 || !args[0]->IsObject()) { return; } JSRef obj = JSRef::Cast(args[0]); CalcDimension xOffset; ParseJsDimensionVp(obj->GetProperty("xOffset"), xOffset); CalcDimension yOffset; ParseJsDimensionVp(obj->GetProperty("yOffset"), yOffset); ScrollModel::GetInstance()->SetInitialOffset(NG::OffsetT(xOffset, yOffset)); } void JSScroll::SetMaxZoomScale(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } double maxZoomScale = 1.0; JSViewAbstract::ParseJsDouble(args[0], maxZoomScale); ScrollModel::GetInstance()->SetMaxZoomScale(maxZoomScale); } void JSScroll::SetMinZoomScale(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } double minZoomScale = 1.0; JSViewAbstract::ParseJsDouble(args[0], minZoomScale); ScrollModel::GetInstance()->SetMinZoomScale(minZoomScale); } void JSScroll::SetZoomScale(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } double zoomScale = 1.0; JSRef changeEventVal; auto scaleValue = args[0]; if (scaleValue->IsObject()) { JSRef obj = JSRef::Cast(scaleValue); scaleValue = obj->GetProperty("value"); changeEventVal = obj->GetProperty("$value"); } if (JSViewAbstract::ParseJsDouble(scaleValue, zoomScale)) { ScrollModel::GetInstance()->SetZoomScale(zoomScale); } else { ScrollModel::GetInstance()->ResetZoomScale(); } if (changeEventVal->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(changeEventVal)); auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto changeEvent = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](float param) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); auto newJSVal = JSRef::Make(ToJSValue(param)); PipelineContext::SetCallBackNode(node); func->ExecuteJS(1, &newJSVal); }; ScrollModel::GetInstance()->SetZoomScaleChangeEvent(std::move(changeEvent)); } } void JSScroll::SetEnableBouncesZoom(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } bool enableBouncesZoom = true; if (args[0]->IsBoolean()) { enableBouncesZoom = args[0]->ToBoolean(); } ScrollModel::GetInstance()->SetEnableBouncesZoom(enableBouncesZoom); } void JSScroll::OnDidZoomCallback(const JSCallbackInfo& args) { if (args.Length() > 0 && args[0]->IsFunction()) { auto onZoom = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])](float scale) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); auto params = ConvertToJSValues(scale); func->Call(JSRef(), params.size(), params.data()); }; ScrollModel::GetInstance()->SetOnDidZoom(std::move(onZoom)); } else { ScrollModel::GetInstance()->SetOnDidZoom(nullptr); } args.SetReturnValue(args.This()); } void JSScroll::OnZoomStartCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto zoomStart = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->Call(JSRef(), 0, nullptr); }; ScrollModel::GetInstance()->SetOnZoomStart(std::move(zoomStart)); } else { ScrollModel::GetInstance()->SetOnZoomStart(nullptr); } args.SetReturnValue(args.This()); } void JSScroll::OnZoomStopCallback(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto zoomStop = [execCtx = args.GetExecutionContext(), func = JSRef::Cast(args[0])]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->Call(JSRef(), 0, nullptr); }; ScrollModel::GetInstance()->SetOnZoomStop(std::move(zoomStop)); } else { ScrollModel::GetInstance()->SetOnZoomStop(nullptr); } args.SetReturnValue(args.This()); } } // namespace OHOS::Ace::Framework