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 "frameworks/bridge/js_frontend/engine/jsi/jsi_component_api_bridge.h"
17
18 #include "frameworks/bridge/common/dom/dom_list.h"
19
20 namespace OHOS::Ace::Framework {
21
JsGetScrollOffset(const shared_ptr<JsRuntime> & runtime,NodeId nodeId)22 shared_ptr<JsValue> JsiComponentApiBridge::JsGetScrollOffset(const shared_ptr<JsRuntime>& runtime, NodeId nodeId)
23 {
24 if (!runtime) {
25 LOGE("JsGetScrollOffset failed. runtime is null.");
26 return nullptr;
27 }
28 auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
29 if (!engine) {
30 LOGE("JsGetScrollOffset failed. engine is null.");
31 return runtime->NewUndefined();
32 }
33 auto page = engine->GetRunningPage();
34 if (!page) {
35 LOGE("JsGetScrollOffset failed. page is null.");
36 return runtime->NewUndefined();
37 }
38 Offset offset;
39 auto task = [nodeId, page, &offset]() {
40 auto domDoc = page->GetDomDocument();
41 if (!domDoc) {
42 return;
43 }
44 auto domNode = domDoc->GetDOMNodeById(nodeId);
45 if (!domNode) {
46 return;
47 }
48 auto domList = AceType::DynamicCast<DOMList>(domNode);
49 if (domList) {
50 offset = domList->GetCurrentOffset();
51 return;
52 }
53
54 auto scrollComponent = domNode->GetScrollComponent();
55 if (!scrollComponent) {
56 return;
57 }
58 auto controller = scrollComponent->GetScrollPositionController();
59 if (!controller) {
60 return;
61 }
62 offset = controller->GetCurrentOffset();
63 };
64 auto delegate = engine->GetFrontendDelegate();
65 if (!delegate) {
66 LOGE("JsGetScrollOffset failed. delegate is null.");
67 return runtime->NewUndefined();
68 }
69 delegate->PostSyncTaskToPage(task, "ArkUIJsGetScrollOffset");
70 shared_ptr<JsValue> offsetContext = runtime->NewObject();
71 offsetContext->SetProperty(runtime, "x", runtime->NewNumber(offset.GetX()));
72 offsetContext->SetProperty(runtime, "y", runtime->NewNumber(offset.GetY()));
73 return offsetContext;
74 }
75
JsGetBoundingRect(const shared_ptr<JsRuntime> & runtime,NodeId nodeId)76 shared_ptr<JsValue> JsiComponentApiBridge::JsGetBoundingRect(const shared_ptr<JsRuntime>& runtime, NodeId nodeId)
77 {
78 if (!runtime) {
79 LOGE("JsGetBoundingRect failed. runtime is null.");
80 return nullptr;
81 }
82 auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
83 if (!engine) {
84 LOGE("JsGetBoundingRect failed. engine is null.");
85 return runtime->NewUndefined();
86 }
87 auto delegate = engine->GetFrontendDelegate();
88 if (!delegate) {
89 LOGE("JsGetBoundingRect failed. delegate is null.");
90 return runtime->NewUndefined();
91 }
92 Rect boundingRect = delegate->GetBoundingRectData(nodeId);
93 shared_ptr<JsValue> rectContext = runtime->NewObject();
94 rectContext->SetProperty(runtime, "width", runtime->NewNumber(boundingRect.Width()));
95 rectContext->SetProperty(runtime, "height", runtime->NewNumber(boundingRect.Height()));
96 rectContext->SetProperty(runtime, "top", runtime->NewNumber(boundingRect.Top()));
97 rectContext->SetProperty(runtime, "left", runtime->NewNumber(boundingRect.Left()));
98 return rectContext;
99 }
100
JsGetInspector(const shared_ptr<JsRuntime> & runtime,NodeId nodeId)101 shared_ptr<JsValue> JsiComponentApiBridge::JsGetInspector(const shared_ptr<JsRuntime>& runtime, NodeId nodeId)
102 {
103 if (!runtime) {
104 LOGE("JsGetInspector failed. runtime is null.");
105 return nullptr;
106 }
107 auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
108 if (!engine) {
109 LOGE("JsGetInspector failed. engine is null.");
110 return runtime->NewUndefined();
111 }
112 auto delegate = engine->GetFrontendDelegate();
113 if (!delegate) {
114 LOGE("JsGetInspector failed. delegate is null.");
115 return runtime->NewUndefined();
116 }
117 auto attributes = delegate->GetInspector(nodeId);
118 shared_ptr<JsValue> result = runtime->NewString(attributes);
119 return result;
120 }
121
JsScrollTo(const shared_ptr<JsRuntime> & runtime,const std::string & arguments,NodeId nodeId)122 void JsiComponentApiBridge::JsScrollTo(
123 const shared_ptr<JsRuntime>& runtime, const std::string& arguments, NodeId nodeId)
124 {
125 if (!runtime) {
126 LOGE("JsScrollTo failed. runtime is null.");
127 return;
128 }
129 auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
130 if (!engine) {
131 LOGE("JsScrollTo failed. engine is null.");
132 return;
133 }
134 auto page = engine->GetRunningPage();
135 if (!page) {
136 LOGE("JsScrollTo failed. page is null.");
137 return;
138 }
139 auto task = [nodeId, page, arguments]() {
140 auto domDoc = page->GetDomDocument();
141 if (!domDoc) {
142 LOGE("JsScrollTo failed. dom document is null!");
143 return;
144 }
145 auto domNode = domDoc->GetDOMNodeById(nodeId);
146 if (!domNode) {
147 LOGE("JsScrollTo failed. dom node is null!");
148 return;
149 }
150 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(arguments);
151 if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() < 1) {
152 LOGE("JsScrollTo failed. parse args error");
153 return;
154 }
155 std::unique_ptr<JsonValue> scrollToPara = argsValue->GetArrayItem(0);
156 int32_t index = scrollToPara->GetInt("index", 0);
157 auto domList = AceType::DynamicCast<DOMList>(domNode);
158 if (domList) {
159 // list has specialized scrollTo method.
160 domList->ScrollToMethod(index);
161 return;
162 }
163
164 auto scrollComponent = domNode->GetScrollComponent();
165 if (!scrollComponent) {
166 return;
167 }
168 auto controller = scrollComponent->GetScrollPositionController();
169 if (!controller) {
170 return;
171 }
172
173 std::string id = scrollToPara->GetString("id", "");
174 double position = scrollToPara->GetDouble("position", 0.0);
175 double duration = scrollToPara->GetDouble("duration", 300.0); // Default duration is 300ms.
176 std::string timingFunction = scrollToPara->GetString("timingFunction", "ease");
177 std::string successId = scrollToPara->GetString("success", "");
178 std::string failId = scrollToPara->GetString("fail", "");
179 std::string completeId = scrollToPara->GetString("complete", "");
180 auto context = domNode->GetPipelineContext();
181 auto callback = [context, successId, completeId]() {
182 auto refContext = context.Upgrade();
183 if (refContext) {
184 refContext->SendCallbackMessageToFrontend(successId, std::string("\"success\",null"));
185 refContext->SendCallbackMessageToFrontend(completeId, std::string("\"complete\",null"));
186 }
187 };
188
189 bool result = false;
190 if (scrollToPara->Contains("position")) {
191 result = controller->AnimateTo(position, duration, CreateCurve(timingFunction), false, callback);
192 } else if (scrollToPara->Contains("id") && !id.empty()) {
193 result = controller->AnimateToTarget(id, duration, CreateCurve(timingFunction), false, callback);
194 } else {
195 LOGW("JsScrollTo failed. param not valid.");
196 }
197 if (!result) {
198 auto refContext = context.Upgrade();
199 if (refContext) {
200 refContext->SendCallbackMessageToFrontend(failId, std::string("\"fail\",null"));
201 refContext->SendCallbackMessageToFrontend(completeId, std::string("\"complete\",null"));
202 }
203 }
204 };
205
206 auto delegate = engine->GetFrontendDelegate();
207 if (!delegate) {
208 LOGE("JsScrollTo failed. delegate is null.");
209 return;
210 }
211 delegate->PostSyncTaskToPage(task, "ArkUIJsScrollTo");
212 }
213
214 } // namespace OHOS::Ace::Framework