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