• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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_scroller.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/utils/linear_map.h"
20 #include "base/utils/utils.h"
21 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
22 #include "core/animation/curves.h"
23 #include "core/common/container.h"
24 #include "core/components/common/layout/align_declaration.h"
25 
26 namespace OHOS::Ace::Framework {
27 namespace {
28 
29 constexpr Axis DIRECTION_TABLE[] = { Axis::VERTICAL, Axis::HORIZONTAL };
30 
31 constexpr AlignDeclaration::Edge EDGE_TABLE[] = {
32     AlignDeclaration::Edge::TOP,
33     AlignDeclaration::Edge::CENTER,
34     AlignDeclaration::Edge::BOTTOM,
35     AlignDeclaration::Edge::BASELINE,
36     AlignDeclaration::Edge::START,
37     AlignDeclaration::Edge::MIDDLE,
38     AlignDeclaration::Edge::END,
39 };
40 
41 // corresponding to EDGE_TABLE[]
42 constexpr ScrollEdgeType EDGE_TYPE_TABLE[] = { ScrollEdgeType::SCROLL_TOP, ScrollEdgeType::SCROLL_NONE,
43     ScrollEdgeType::SCROLL_BOTTOM, ScrollEdgeType::SCROLL_NONE, ScrollEdgeType::SCROLL_TOP, ScrollEdgeType::SCROLL_NONE,
44     ScrollEdgeType::SCROLL_BOTTOM };
45 
46 const LinearMapNode<RefPtr<Curve>> CURVE_MAP[] = {
47     { "ease", Curves::EASE },
48     { "ease-in", Curves::EASE_IN },
49     { "ease-in-out", Curves::EASE_IN_OUT },
50     { "ease-out", Curves::EASE_OUT },
51     { "friction", Curves::FRICTION },
52     { "linear", Curves::LINEAR },
53 };
54 
55 } // namespace
56 
JSBind(BindingTarget globalObj)57 void JSScroller::JSBind(BindingTarget globalObj)
58 {
59     JSClass<JSScroller>::Declare("Scroller");
60     JSClass<JSScroller>::CustomMethod("scrollTo", &JSScroller::ScrollTo);
61     JSClass<JSScroller>::CustomMethod("scrollEdge", &JSScroller::ScrollEdge);
62     JSClass<JSScroller>::CustomMethod("scrollPage", &JSScroller::ScrollPage);
63     JSClass<JSScroller>::CustomMethod("currentOffset", &JSScroller::CurrentOffset);
64     JSClass<JSScroller>::CustomMethod("scrollToIndex", &JSScroller::ScrollToIndex);
65     JSClass<JSScroller>::CustomMethod("scrollBy", &JSScroller::ScrollBy);
66     JSClass<JSScroller>::Bind(globalObj, JSScroller::Constructor, JSScroller::Destructor);
67 }
68 
Constructor(const JSCallbackInfo & args)69 void JSScroller::Constructor(const JSCallbackInfo& args)
70 {
71     auto scroller = Referenced::MakeRefPtr<JSScroller>();
72     scroller->IncRefCount();
73     args.SetReturnValue(Referenced::RawPtr(scroller));
74 }
75 
Destructor(JSScroller * scroller)76 void JSScroller::Destructor(JSScroller* scroller)
77 {
78     if (scroller != nullptr) {
79         scroller->DecRefCount();
80     }
81 }
82 
ScrollTo(const JSCallbackInfo & args)83 void JSScroller::ScrollTo(const JSCallbackInfo& args)
84 {
85     if (args.Length() < 1 || !args[0]->IsObject()) {
86         LOGW("Invalid params");
87         return;
88     }
89 
90     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
91     Dimension xOffset;
92     Dimension yOffset;
93     if (!ConvertFromJSValue(obj->GetProperty("xOffset"), xOffset) ||
94         !ConvertFromJSValue(obj->GetProperty("yOffset"), yOffset)) {
95         LOGW("Failed to parse param 'xOffset' or 'yOffset'");
96         return;
97     }
98 
99     double duration = 0.0;
100     RefPtr<Curve> curve = Curves::EASE;
101     auto animationValue = obj->GetProperty("animation");
102     if (animationValue->IsObject()) {
103         auto animationObj = JSRef<JSObject>::Cast(animationValue);
104         ConvertFromJSValue(animationObj->GetProperty("duration"), duration);
105 
106         std::string curveName;
107         if (ConvertFromJSValue(animationObj->GetProperty("curve"), curveName)) {
108             auto index = BinarySearchFindIndex(CURVE_MAP, ArraySize(CURVE_MAP), curveName.c_str());
109             if (index >= 0) {
110                 curve = CURVE_MAP[index].value;
111             }
112         }
113     }
114 
115     if (GreatNotEqual(duration, 0.0)) {
116         LOGD("ScrollTo(%lf, %lf, %lf)", xOffset.Value(), yOffset.Value(), duration);
117     } else {
118         LOGD("ScrollTo(%lf, %lf)", xOffset.Value(), yOffset.Value());
119     }
120     auto scrollController = controllerWeak_.Upgrade();
121     if (!scrollController) {
122         LOGE("controller_ is nullptr");
123         return;
124     }
125     auto direction = scrollController->GetScrollDirection();
126     auto position = direction == Axis::VERTICAL ? yOffset : xOffset;
127     scrollController->AnimateTo(position, static_cast<float>(duration), curve);
128 }
129 
ScrollEdge(const JSCallbackInfo & args)130 void JSScroller::ScrollEdge(const JSCallbackInfo& args)
131 {
132     AlignDeclaration::Edge edge = AlignDeclaration::Edge::AUTO;
133     if (args.Length() < 1 || !ConvertFromJSValue(args[0], EDGE_TABLE, edge)) {
134         LOGW("Invalid params");
135         return;
136     }
137     auto scrollController = controllerWeak_.Upgrade();
138     if (!scrollController) {
139         LOGE("controller_ is nullptr");
140         return;
141     }
142     LOGD("ScrollEdge(%{public}d)", static_cast<int32_t>(edge));
143     ScrollEdgeType edgeType = EDGE_TYPE_TABLE[static_cast<int32_t>(edge)];
144     scrollController->ScrollToEdge(edgeType, true);
145 }
146 
ScrollToIndex(const JSCallbackInfo & args)147 void JSScroller::ScrollToIndex(const JSCallbackInfo& args)
148 {
149     int32_t index = 0;
150     if (args.Length() < 1 || !ConvertFromJSValue(args[0], index)) {
151         LOGW("Invalid params");
152         return;
153     }
154     auto scrollController = controllerWeak_.Upgrade();
155     if (!scrollController) {
156         LOGE("controller_ is nullptr");
157         return;
158     }
159     scrollController->JumpTo(index, SCROLL_FROM_JUMP);
160 }
161 
ScrollPage(const JSCallbackInfo & args)162 void JSScroller::ScrollPage(const JSCallbackInfo& args)
163 {
164     if (args.Length() < 1 || !args[0]->IsObject()) {
165         LOGW("Invalid params");
166         return;
167     }
168 
169     auto obj = JSRef<JSObject>::Cast(args[0]);
170     bool next = true;
171     if (!ConvertFromJSValue(obj->GetProperty("next"), next)) {
172         LOGW("Failed to parse param 'next'");
173         return;
174     }
175 
176     Axis direction = Axis::NONE;
177     ConvertFromJSValue(obj->GetProperty("direction"), DIRECTION_TABLE, direction);
178     auto scrollController = controllerWeak_.Upgrade();
179     if (!scrollController) {
180         LOGE("controller_ is nullptr");
181         return;
182     }
183     LOGD("ScrollPage(%{public}s, %{public}d)", next ? "true" : "false", static_cast<int32_t>(direction));
184     scrollController->ScrollPage(!next, true);
185 }
186 
CurrentOffset(const JSCallbackInfo & args)187 void JSScroller::CurrentOffset(const JSCallbackInfo& args)
188 {
189     LOGD("CurrentOffset()");
190     auto scrollController = controllerWeak_.Upgrade();
191     if (!scrollController) {
192         LOGE("controller_ is nullptr");
193         return;
194     }
195     auto retObj = JSRef<JSObject>::New();
196     auto offset = scrollController->GetCurrentOffset();
197     retObj->SetProperty("xOffset", offset.GetX());
198     retObj->SetProperty("yOffset", offset.GetY());
199     args.SetReturnValue(retObj);
200 }
201 
ScrollBy(const JSCallbackInfo & args)202 void JSScroller::ScrollBy(const JSCallbackInfo& args)
203 {
204     if (args.Length() < 2) {
205         LOGW("Invalid params");
206         return;
207     }
208 
209     Dimension xOffset;
210     Dimension yOffset;
211     if (!ConvertFromJSValue(args[0], xOffset) ||
212         !ConvertFromJSValue(args[1], yOffset)) {
213         LOGW("Failed to parse param");
214         return;
215     }
216 
217     auto deltaX = xOffset.Value();
218     auto deltaY = yOffset.Value();
219     auto container = Container::Current();
220     if (container) {
221         auto context = container->GetPipelineContext();
222         if (context) {
223             deltaX = context->NormalizeToPx(xOffset);
224             deltaY = context->NormalizeToPx(yOffset);
225         }
226     }
227     auto scrollController = controllerWeak_.Upgrade();
228     if (scrollController) {
229         scrollController->ScrollBy(deltaX, deltaY, false);
230     }
231 }
232 
233 } // namespace OHOS::Ace::Framework
234