• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 <cstddef>
17 #include <cstdint>
18 #include <cstring>
19 #include <optional>
20 
21 #include "interfaces/napi/kits/utils/napi_utils.h"
22 #include "js_native_api.h"
23 #include "js_native_api_types.h"
24 #include "napi/native_common.h"
25 #include "native_value.h"
26 #include "node_api.h"
27 
28 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
29 #include "jsnapi.h"
30 #include "pixel_map.h"
31 #include "pixel_map_napi.h"
32 
33 #include "base/log/log_wrapper.h"
34 #include "base/memory/referenced.h"
35 #include "base/msdp/device_status/interfaces/innerkits/interaction/include/interaction_manager.h"
36 #include "bridge/common/utils/utils.h"
37 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
38 #include "bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
39 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
40 #include "core/common/ace_engine.h"
41 #include "core/common/udmf/udmf_client.h"
42 #include "core/event/ace_events.h"
43 #include "core/gestures/gesture_info.h"
44 #include "frameworks/bridge/common/utils/engine_helper.h"
45 #endif
46 
47 namespace OHOS::Ace::Napi {
48 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
49 namespace {
50 constexpr float PIXELMAP_WIDTH_RATE = -0.5f;
51 constexpr float PIXELMAP_HEIGHT_RATE = -0.2f;
52 
53 constexpr int32_t argCount2 = 2;
54 constexpr int32_t argCount3 = 3;
55 
56 using DragNotifyMsg = Msdp::DeviceStatus::DragNotifyMsg;
57 using OnDragCallback = std::function<void(const DragNotifyMsg&)>;
58 using StopDragCallback = std::function<void()>;
59 using PixelMapNapiEntry = void* (*)(void*, void*);
60 
61 enum class DragState { PENDING, SENDING, REJECT, SUCCESS };
62 
63 // the context of drag controller
64 struct DragControllerAsyncCtx {
65     napi_env env = nullptr;
66     size_t argc = 3;
67     napi_value argv[3] { nullptr };
68     napi_ref callbackRef = nullptr;
69     napi_deferred deferred = nullptr;
70     std::shared_ptr<Media::PixelMap> pixmap = nullptr;
71     napi_value customBuilder;
72     int32_t pointerId = -1;
73     RefPtr<OHOS::Ace::UnifiedData> unifiedData;
74     std::string extraParams;
75     int32_t instanceId = -1;
76     int32_t errCode = -1;
77     std::mutex mutex;
78     bool hasHandle = false;
79     int32_t globalX = -1;
80     int32_t globalY = -1;
81     int32_t sourceType = 0;
82     std::mutex dragStateMutex;
83     DragState dragState = DragState::PENDING;
84 };
85 } // namespace
86 
CreateCallbackErrorValue(napi_env env,int32_t errCode)87 napi_value CreateCallbackErrorValue(napi_env env, int32_t errCode)
88 {
89     napi_value jsObject = nullptr;
90     napi_value jsValue = nullptr;
91     NAPI_CALL(env, napi_create_int32(env, errCode, &jsValue));
92     NAPI_CALL(env, napi_create_object(env, &jsObject));
93     NAPI_CALL(env, napi_set_named_property(env, jsObject, "code", jsValue));
94     return jsObject;
95 }
96 
HandleSuccess(DragControllerAsyncCtx * asyncCtx,const DragNotifyMsg & dragNotifyMsg)97 void HandleSuccess(DragControllerAsyncCtx* asyncCtx, const DragNotifyMsg& dragNotifyMsg)
98 {
99     if (!asyncCtx) {
100         LOGE("DragControllerAsyncContext is null");
101         return;
102     }
103     bool hasHandle = false;
104     {
105         std::lock_guard<std::mutex> lock(asyncCtx->mutex);
106         hasHandle = asyncCtx->hasHandle;
107         asyncCtx->hasHandle = true;
108     }
109     if (hasHandle) {
110         return;
111     }
112     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
113     if (!container) {
114         LOGW("container is null. %{public}d", asyncCtx->instanceId);
115         return;
116     }
117     auto taskExecutor = container->GetTaskExecutor();
118     if (!taskExecutor) {
119         LOGW("taskExecutor is null.");
120         return;
121     }
122     taskExecutor->PostSyncTask(
123         [asyncCtx, dragNotifyMsg]() {
124             // callback result format: {DragEvent, ExtraParams}
125             if (!asyncCtx) {
126                 LOGE("DragControllerAsyncContext is null");
127                 return;
128             }
129             napi_value result[2] = { nullptr };
130             napi_get_undefined(asyncCtx->env, &result[1]);
131             auto resultCode = dragNotifyMsg.result;
132             LOGI("resultCode = %{public}d", static_cast<int32_t>(resultCode));
133             // do success thing
134             napi_create_object(asyncCtx->env, &result[1]);
135             napi_value eventNapi = nullptr;
136             napi_value globalObj = nullptr;
137             napi_value customDragEvent = nullptr;
138             napi_create_object(asyncCtx->env, &customDragEvent);
139             napi_get_global(asyncCtx->env, &globalObj);
140             if (!globalObj) {
141                 LOGE("globalObj is null");
142                 return;
143             }
144             napi_get_named_property(asyncCtx->env, globalObj, "DragEvent", &customDragEvent);
145             if (!customDragEvent) {
146                 LOGE("customDragEvent is null");
147                 return;
148             }
149             napi_status status = napi_new_instance(asyncCtx->env, customDragEvent, 0, nullptr, &eventNapi);
150             if (status != napi_ok) {
151                 LOGE("status = %{public}d", status);
152                 return;
153             }
154             auto* nativeValue = reinterpret_cast<NativeValue*>(eventNapi);
155             panda::CopyableGlobal<JSValueRef> globalRef = *nativeValue;
156             auto localRef = globalRef.ToLocal();
157             if (localRef->IsNull()) {
158                 LOGE("localRef is null");
159                 return;
160             }
161             auto* jsDragEvent =
162                 static_cast<Framework::JsDragEvent*>(Local<panda::ObjectRef>(localRef)->GetNativePointerField(0));
163             if (!jsDragEvent) {
164                 LOGE("jsDragEvent is null");
165                 return;
166             }
167             auto dragEvent = AceType::MakeRefPtr<DragEvent>();
168             if (!dragEvent) {
169                 LOGE("dragEvent is null");
170                 return;
171             }
172             dragEvent->SetResult(static_cast<DragRet>(resultCode));
173             jsDragEvent->SetDragEvent(dragEvent);
174             status = napi_set_named_property(asyncCtx->env, result[1], "event", eventNapi);
175 
176             napi_value extraParamsNapi = nullptr;
177             napi_create_string_utf8(
178                 asyncCtx->env, asyncCtx->extraParams.c_str(), asyncCtx->extraParams.length(), &extraParamsNapi);
179             napi_set_named_property(asyncCtx->env, result[1], "extraParams", extraParamsNapi);
180             if (asyncCtx->callbackRef) {
181                 napi_value ret = nullptr;
182                 napi_value napiCallback = nullptr;
183                 napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
184                 result[0] = CreateCallbackErrorValue(asyncCtx->env, 0);
185                 napi_call_function(asyncCtx->env, nullptr, napiCallback, argCount2, result, &ret);
186                 napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
187             } else {
188                 napi_resolve_deferred(asyncCtx->env, asyncCtx->deferred, result[1]);
189             }
190         },
191         TaskExecutor::TaskType::JS);
192 }
193 
HandleFail(DragControllerAsyncCtx * asyncCtx,int32_t errorCode)194 void HandleFail(DragControllerAsyncCtx* asyncCtx, int32_t errorCode)
195 {
196     if (!asyncCtx) {
197         LOGE("DragControllerAsyncContext is null");
198         return;
199     }
200     bool hasHandle = false;
201     {
202         std::lock_guard<std::mutex> lock(asyncCtx->mutex);
203         hasHandle = asyncCtx->hasHandle;
204         asyncCtx->hasHandle = true;
205     }
206     if (hasHandle) {
207         return;
208     }
209     napi_value result[2] = { nullptr };
210     result[0] = CreateCallbackErrorValue(asyncCtx->env, errorCode);
211     if (asyncCtx->callbackRef) {
212         napi_value ret = nullptr;
213         napi_value napiCallback = nullptr;
214         napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
215         napi_create_object(asyncCtx->env, &result[1]);
216         napi_call_function(asyncCtx->env, nullptr, napiCallback, argCount2, result, &ret);
217         napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
218     } else {
219         napi_reject_deferred(asyncCtx->env, asyncCtx->deferred, result[0]);
220     }
221 }
222 
OnComplete(DragControllerAsyncCtx * asyncCtx)223 void OnComplete(DragControllerAsyncCtx* asyncCtx)
224 {
225     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
226     if (!container) {
227         LOGW("container is null. %{public}d", asyncCtx->instanceId);
228         return;
229     }
230     auto taskExecutor = container->GetTaskExecutor();
231     if (!taskExecutor) {
232         LOGW("taskExecutor is null.");
233         return;
234     }
235     taskExecutor->PostTask(
236         [asyncCtx]() {
237             if (!asyncCtx) {
238                 LOGE("DragControllerAsyncContext is null");
239                 return;
240             }
241             DragState dragState = DragState::PENDING;
242             {
243                 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
244                 if (asyncCtx->dragState == DragState::PENDING) {
245                     asyncCtx->dragState = DragState::SENDING;
246                 }
247                 dragState = asyncCtx->dragState;
248             }
249             if (dragState == DragState::REJECT) {
250                 napi_handle_scope scope = nullptr;
251                 napi_open_handle_scope(asyncCtx->env, &scope);
252                 HandleFail(asyncCtx, -1);
253                 napi_close_handle_scope(asyncCtx->env, scope);
254                 return;
255             }
256             if (!asyncCtx->pixmap) {
257                 LOGE("The pixmap is null");
258                 return;
259             }
260             int32_t dataSize = 1;
261             auto pointerId = asyncCtx->pointerId;
262             std::string udKey;
263             if (asyncCtx->unifiedData) {
264                 int32_t ret = UdmfClient::GetInstance()->SetData(asyncCtx->unifiedData, udKey);
265                 if (ret != 0) {
266                     LOGW("Udmf set data fail, error code is %{public}d", ret);
267                 }
268                 dataSize = static_cast<int32_t>(asyncCtx->unifiedData->GetSize());
269             }
270             int32_t width = asyncCtx->pixmap->GetWidth();
271             int32_t height = asyncCtx->pixmap->GetHeight();
272 
273             Msdp::DeviceStatus::DragData dragData { { asyncCtx->pixmap, width * PIXELMAP_WIDTH_RATE,
274                                                         height * PIXELMAP_HEIGHT_RATE },
275                 {}, udKey, asyncCtx->sourceType, dataSize, pointerId, asyncCtx->globalX, asyncCtx->globalY, 0, true };
276 
277             OnDragCallback callback = [asyncCtx](const DragNotifyMsg& dragNotifyMsg) {
278                 napi_handle_scope scope = nullptr;
279                 napi_open_handle_scope(asyncCtx->env, &scope);
280                 HandleSuccess(asyncCtx, dragNotifyMsg);
281                 napi_close_handle_scope(asyncCtx->env, scope);
282             };
283 
284             int32_t ret = Msdp::DeviceStatus::InteractionManager::GetInstance()->StartDrag(dragData, callback);
285             if (ret != 0) {
286                 LOGE("drag start error");
287                 napi_handle_scope scope = nullptr;
288                 napi_open_handle_scope(asyncCtx->env, &scope);
289                 HandleFail(asyncCtx, ret);
290                 napi_close_handle_scope(asyncCtx->env, scope);
291                 return;
292             }
293             LOGI("drag start success");
294             {
295                 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
296                 if (asyncCtx->dragState == DragState::SENDING) {
297                     asyncCtx->dragState = DragState::SUCCESS;
298                     Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(true);
299                 }
300             }
301         },
302         TaskExecutor::TaskType::JS);
303 }
304 
ParseDragItemInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)305 bool ParseDragItemInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
306 {
307     if (!asyncCtx) {
308         LOGE("DragControllerAsyncContext is null");
309         errMsg = "DragControllerAsyncContext is null";
310         return false;
311     }
312     napi_valuetype valueType = napi_undefined;
313     napi_typeof(asyncCtx->env, asyncCtx->argv[0], &valueType);
314     if (valueType == napi_function) {
315         asyncCtx->customBuilder = asyncCtx->argv[0];
316         return true;
317     }
318 
319     if (valueType != napi_object) {
320         errMsg = "The type of first parameter is incorrect.";
321         return false;
322     }
323     // Parse the DragItemInfo
324     napi_value pixelMapValue;
325     napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "pixelMap", &pixelMapValue);
326     PixelMapNapiEntry pixelMapNapiEntry = Framework::JsEngine::GetPixelMapNapiEntry();
327     if (pixelMapNapiEntry == nullptr) {
328         LOGW("Failed to parse pixelMap from the first argument.");
329     } else {
330         void* pixmapPtrAddr = pixelMapNapiEntry(asyncCtx->env, pixelMapValue);
331         if (pixmapPtrAddr == nullptr) {
332             LOGW("The pixelMap parsed from the first argument is null");
333         } else {
334             asyncCtx->pixmap = *(reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(pixmapPtrAddr));
335         }
336     }
337 
338     napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "builder", &(asyncCtx->customBuilder));
339     napi_typeof(asyncCtx->env, asyncCtx->customBuilder, &valueType);
340     if (valueType != napi_function) {
341         errMsg = "The type of customBuilder of the first parameter is incorrect.";
342         return false;
343     }
344 
345     napi_value extraInfoValue;
346     napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "extraInfo", &extraInfoValue);
347     napi_typeof(asyncCtx->env, extraInfoValue, &valueType);
348     if (valueType != napi_string) {
349         errMsg = "The type of extraInfo of the first parameter is incorrect.";
350         return false;
351     }
352     GetNapiString(asyncCtx->env, extraInfoValue, asyncCtx->extraParams, valueType);
353     return true;
354 }
355 
ParseDragInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)356 bool ParseDragInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
357 {
358     if (!asyncCtx) {
359         LOGE("DragControllerAsyncContext is null");
360         errMsg = "DragControllerAsyncContext is null";
361         return false;
362     }
363     napi_valuetype valueType = napi_undefined;
364     napi_typeof(asyncCtx->env, asyncCtx->argv[1], &valueType);
365     if (valueType != napi_object) {
366         errMsg = "The type of second parameter is incorrect.";
367         return false;
368     }
369     napi_value pointerIdNApi = nullptr;
370     napi_status status = napi_ok;
371     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "pointerId", &pointerIdNApi);
372     napi_typeof(asyncCtx->env, pointerIdNApi, &valueType);
373     if (valueType != napi_number) {
374         errMsg = "pointerId which type is number must be given";
375         return false;
376     }
377     status = napi_get_value_int32(asyncCtx->env, pointerIdNApi, &asyncCtx->pointerId);
378     if (status != napi_ok) {
379         errMsg = "parse pointerId fail";
380         return false;
381     }
382 
383     napi_value dataNApi = nullptr;
384     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "data", &dataNApi);
385     napi_typeof(asyncCtx->env, dataNApi, &valueType);
386     if (valueType == napi_object) {
387         auto* nativeValue = reinterpret_cast<NativeValue*>(dataNApi);
388         if (!nativeValue) {
389             errMsg = "parse data fail";
390             return false;
391         }
392         asyncCtx->unifiedData = UdmfClient::GetInstance()->TransformUnifiedData(nativeValue);
393     } else if (valueType != napi_undefined) {
394         errMsg = "data's type is wrong";
395         return false;
396     }
397 
398     napi_value extraParamsNApi = nullptr;
399     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "extraParams", &extraParamsNApi);
400     napi_typeof(asyncCtx->env, extraParamsNApi, &valueType);
401     if (valueType == napi_string) {
402         GetNapiString(asyncCtx->env, extraParamsNApi, asyncCtx->extraParams, valueType);
403     } else if (valueType != napi_undefined) {
404         errMsg = "extraParams's type is wrong";
405         return false;
406     }
407     return true;
408 }
409 
CheckAndParseParams(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)410 bool CheckAndParseParams(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
411 {
412     // Check the number of the argument
413     if (!asyncCtx) {
414         LOGE("DragControllerAsyncContext is null");
415         errMsg = "DragControllerAsyncContext is null";
416         return false;
417     }
418     if ((asyncCtx->argc != argCount2) && (asyncCtx->argc != argCount3)) {
419         errMsg = "The number of parameters must be 2 or 3.";
420         return false;
421     }
422 
423     // Check and parse the first parameter
424     if (!ParseDragItemInfoParam(asyncCtx, errMsg)) {
425         return false;
426     }
427 
428     // Check and parse the second parameter
429     return ParseDragInfoParam(asyncCtx, errMsg);
430 }
431 
CreateCallback(DragControllerAsyncCtx * asyncCtx,napi_value * result)432 void CreateCallback(DragControllerAsyncCtx* asyncCtx, napi_value* result)
433 {
434     if (!asyncCtx) {
435         LOGE("DragControllerAsyncContext is null");
436         return;
437     }
438     if (asyncCtx->argc == argCount3) {
439         // Create the JsCallback
440         napi_create_reference(asyncCtx->env, asyncCtx->argv[2], 1, &asyncCtx->callbackRef);
441     }
442     if (!asyncCtx->callbackRef) {
443         // Create the promise
444         napi_create_promise(asyncCtx->env, &asyncCtx->deferred, result);
445     } else {
446         napi_get_undefined(asyncCtx->env, result);
447     }
448 }
449 
InitializeDragControllerCtx(napi_env env,napi_callback_info info,DragControllerAsyncCtx * asyncCtx)450 void InitializeDragControllerCtx(napi_env env, napi_callback_info info, DragControllerAsyncCtx* asyncCtx)
451 {
452     if (!asyncCtx) {
453         LOGE("DragControllerAsyncContext is null");
454         return;
455     }
456     napi_value thisVar = nullptr;
457     void* data = nullptr;
458     asyncCtx->instanceId = Container::CurrentId();
459     asyncCtx->env = env;
460     // get arguments from JS
461     napi_get_cb_info(asyncCtx->env, info, &(asyncCtx->argc), asyncCtx->argv, &thisVar, &data);
462 }
463 
JSExecuteDrag(napi_env env,napi_callback_info info)464 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
465 {
466     napi_escapable_handle_scope scope = nullptr;
467     napi_open_escapable_handle_scope(env, &scope);
468 
469     auto* asyncCtx = new DragControllerAsyncCtx();
470     InitializeDragControllerCtx(env, info, asyncCtx);
471 
472     std::string errMsg;
473     if (!CheckAndParseParams(asyncCtx, errMsg)) {
474         NapiThrow(asyncCtx->env, errMsg, Framework::ERROR_CODE_INTERNAL_ERROR);
475         return nullptr;
476     }
477 
478     napi_value result = nullptr;
479     CreateCallback(asyncCtx, &result);
480     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
481     if (!container) {
482         NapiThrow(asyncCtx->env, "container is null", Framework::ERROR_CODE_INTERNAL_ERROR);
483         return nullptr;
484     }
485     StopDragCallback stopDragCallback = [asyncCtx, container]() {
486         if (!asyncCtx) {
487             LOGE("DragControllerAsyncContext is null");
488             return;
489         }
490         if (!container) {
491             LOGE("container is null");
492             return;
493         }
494         bool needPostStopDrag = false;
495         {
496             std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
497             needPostStopDrag = (asyncCtx->dragState == DragState::SENDING);
498             asyncCtx->dragState = DragState::REJECT;
499         }
500         if (needPostStopDrag) {
501             auto taskExecutor = container->GetTaskExecutor();
502             if (!taskExecutor) {
503                 LOGE("taskExecutor is null.");
504                 return;
505             }
506             taskExecutor->PostTask(
507                 [asyncCtx]() {
508                     if (!asyncCtx) {
509                         LOGE("DragControllerAsyncContext is null");
510                         return;
511                     }
512                     napi_handle_scope scope = nullptr;
513                     napi_open_handle_scope(asyncCtx->env, &scope);
514                     HandleFail(asyncCtx, -1);
515                     napi_close_handle_scope(asyncCtx->env, scope);
516                     Msdp::DeviceStatus::InteractionManager::GetInstance()->StopDrag(
517                         Msdp::DeviceStatus::DragResult::DRAG_CANCEL, false);
518                     Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(false);
519                 },
520                 TaskExecutor::TaskType::JS);
521         }
522     };
523     auto getPointSuccess = container->GetCurPointerEventInfo(
524         asyncCtx->pointerId, asyncCtx->globalX, asyncCtx->globalY, asyncCtx->sourceType, std::move(stopDragCallback));
525     if (!getPointSuccess) {
526         HandleFail(asyncCtx, -1);
527         napi_escape_handle(env, scope, result, &result);
528         napi_close_escapable_handle_scope(env, scope);
529         return result;
530     }
531 
532     if (asyncCtx && asyncCtx->pixmap != nullptr) {
533         OnComplete(asyncCtx);
534     } else {
535         auto delegate = EngineHelper::GetCurrentDelegate();
536         if (!delegate) {
537             NapiThrow(env, "ace engine delegate is null", Framework::ERROR_CODE_INTERNAL_ERROR);
538             napi_close_escapable_handle_scope(env, scope);
539             return nullptr;
540         }
541         auto callback = [asyncCtx](std::shared_ptr<Media::PixelMap> pixmap, int32_t errCode) {
542             if (!asyncCtx) {
543                 LOGE("DragControllerAsyncContext is null");
544                 return;
545             }
546             asyncCtx->pixmap = std::move(pixmap);
547             asyncCtx->errCode = errCode;
548             OnComplete(asyncCtx);
549         };
550         auto builder = [build = asyncCtx->customBuilder, env] {
551             napi_call_function(env, nullptr, build, 0, nullptr, nullptr);
552         };
553         delegate->CreateSnapshot(builder, callback);
554     }
555 
556     napi_escape_handle(env, scope, result, &result);
557     napi_close_escapable_handle_scope(env, scope);
558     return result;
559 }
560 #else
561 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
562 {
563     napi_escapable_handle_scope scope = nullptr;
564     napi_open_escapable_handle_scope(env, &scope);
565     NapiThrow(env, "The current environment does not enable drag framework or does not support pixmap.",
566         Framework::ERROR_CODE_INTERNAL_ERROR);
567     napi_close_escapable_handle_scope(env, scope);
568     return nullptr;
569 }
570 #endif
571 
DragControllerExport(napi_env env,napi_value exports)572 static napi_value DragControllerExport(napi_env env, napi_value exports)
573 {
574     napi_property_descriptor dragControllerDesc[] = {
575         DECLARE_NAPI_FUNCTION("executeDrag", JSExecuteDrag),
576     };
577     NAPI_CALL(env, napi_define_properties(
578                        env, exports, sizeof(dragControllerDesc) / sizeof(dragControllerDesc[0]), dragControllerDesc));
579     return exports;
580 }
581 
582 static napi_module dragControllerModule = {
583     .nm_version = 1,
584     .nm_flags = 0,
585     .nm_filename = nullptr,
586     .nm_register_func = DragControllerExport,
587     .nm_modname = "arkui.dragController",
588     .nm_priv = ((void*)0),
589     .reserved = { 0 },
590 };
591 
DragControllerRegister()592 extern "C" __attribute__((constructor)) void DragControllerRegister()
593 {
594     napi_module_register(&dragControllerModule);
595 }
596 } // namespace OHOS::Ace::Napi
597