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_engine/impl/ark/ark_native_engine.h"
26 #include "native_value.h"
27 #include "node_api.h"
28 
29 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
30 #include "jsnapi.h"
31 #include "pixel_map.h"
32 #include "pixel_map_napi.h"
33 
34 #include "adapter/ohos/capability/interaction/start_drag_listener_impl.h"
35 #include "base/log/log_wrapper.h"
36 #include "base/memory/referenced.h"
37 #include "base/msdp/device_status/interfaces/innerkits/interaction/include/interaction_manager.h"
38 #include "base/utils/utils.h"
39 #include "bridge/common/utils/utils.h"
40 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
41 #include "bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
42 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
43 #include "core/common/ace_engine.h"
44 #include "core/common/container_scope.h"
45 #include "core/common/udmf/udmf_client.h"
46 #include "core/components/common/layout/grid_system_manager.h"
47 #include "core/components_ng/manager/drag_drop/drag_drop_func_wrapper.h"
48 #include "core/event/ace_events.h"
49 #include "frameworks/bridge/common/utils/engine_helper.h"
50 #include "frameworks/base/json/json_util.h"
51 #include "drag_preview.h"
52 #endif
53 namespace OHOS::Ace::Napi {
54 class DragAction;
55 static constexpr uint32_t DRAG_STARTED = 0;
56 static constexpr uint32_t DRAG_ENDED = 1;
57 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
58 namespace {
59 constexpr float PIXELMAP_WIDTH_RATE = -0.5f;
60 constexpr float PIXELMAP_HEIGHT_RATE = -0.2f;
61 constexpr size_t STR_BUFFER_SIZE = 1024;
62 constexpr int32_t PARAMETER_NUM = 2;
63 constexpr int32_t argCount3 = 3;
64 constexpr int32_t SOURCE_TYPE_MOUSE = 1;
65 constexpr int32_t MOUSE_POINTER_ID = 1001;
66 constexpr int32_t SOURCE_TOOL_PEN = 1;
67 constexpr int32_t SOURCE_TYPE_TOUCH = 2;
68 constexpr int32_t PEN_POINTER_ID = 102;
69 
70 using DragNotifyMsg = Msdp::DeviceStatus::DragNotifyMsg;
71 using DragRet = OHOS::Ace::DragRet;
72 using OnDragCallback = std::function<void(const DragNotifyMsg&)>;
73 using StopDragCallback = std::function<void()>;
74 using PixelMapNapiEntry = void* (*)(void*, void*);
75 
76 enum class DragState { PENDING, SENDING, REJECT, SUCCESS };
77 enum class DragStatus { STARTED, ENDED };
78 enum class ParameterType { CUSTOMBUILDER, DRAGITEMINFO, DRAGITEMINFO_ARRAY, MIX, ERROR };
79 
80 // the context of drag controller
81 struct DragControllerAsyncCtx {
82     napi_env env = nullptr;
83     size_t argc = 3;
84     napi_value argv[3] { nullptr };
85     napi_ref callbackRef = nullptr;
86     napi_deferred deferred = nullptr;
87     std::shared_ptr<Media::PixelMap> pixelMap = nullptr;
88     std::vector<std::shared_ptr<Media::PixelMap>> pixelMapList;
89     bool isArray = false;
90     napi_value customBuilder;
91     std::vector<napi_ref> customBuilderList;
92     int32_t pointerId = -1;
93     RefPtr<OHOS::Ace::UnifiedData> unifiedData;
94     std::string extraParams;
95     int32_t instanceId = -1;
96     int32_t errCode = -1;
97     std::mutex mutex;
98     bool hasHandle = false;
99     int32_t globalX = -1;
100     int32_t globalY = -1;
101     uint64_t displayId = 0;
102     int32_t sourceType = 0;
103     float windowScale = 1.0f;
104     float dipScale = 0.0;
105     int parseBuilderCount = 0;
106     std::mutex dragStateMutex;
107     DragState dragState = DragState::PENDING;
108     DimensionOffset touchPoint = DimensionOffset(0.0_vp, 0.0_vp);
109     bool hasTouchPoint = false;
110     DragAction *dragAction = nullptr;
111     NG::DragPreviewOption dragPreviewOption;
112     ~DragControllerAsyncCtx();
113 };
114 } // namespace
115 
116 void OnMultipleComplete(DragControllerAsyncCtx* asyncCtx);
117 void OnComplete(DragControllerAsyncCtx* asyncCtx);
118 bool GetPixelMapByCustom(DragControllerAsyncCtx* asyncCtx);
119 bool GetPixelMapArrayByCustom(DragControllerAsyncCtx* asyncCtx, napi_value customBuilder, int arrayLength);
120 ParameterType getParameterType(DragControllerAsyncCtx* asyncCtx);
121 void SetMouseDragMonitorState(DragControllerAsyncCtx *asyncCtx, bool state);
122 void HandleExecuteDrag(napi_env env, DragControllerAsyncCtx *asyncCtx);
123 
124 class DragAction {
125 public:
DragAction(DragControllerAsyncCtx * asyncCtx)126     DragAction(DragControllerAsyncCtx* asyncCtx) : asyncCtx_(asyncCtx) {}
~DragAction()127     ~DragAction()
128     {
129         CHECK_NULL_VOID(env_);
130         for (auto& item : cbList_) {
131             napi_delete_reference(env_, item);
132         }
133     }
134 
OnNapiCallback(napi_value resultArg)135     void OnNapiCallback(napi_value resultArg)
136     {
137         std::vector<napi_value> cbList(cbList_.size());
138         for (auto& cbRef : cbList_) {
139             napi_value cb = nullptr;
140             napi_get_reference_value(env_, cbRef, &cb);
141             cbList.push_back(cb);
142         }
143         for (auto& cb : cbList) {
144             napi_call_function(env_, nullptr, cb, 1, &resultArg, nullptr);
145         }
146     }
147 
NapiSerializer(napi_env & env,napi_value & result)148     void NapiSerializer(napi_env& env, napi_value& result)
149     {
150         napi_wrap(
151             env, result, this,
152             [](napi_env env, void* data, void* hint) {
153                 DragAction* dragAction = static_cast<DragAction*>(data);
154                 if (dragAction != nullptr) {
155                     dragAction->DeleteRef();
156                     delete dragAction;
157                 }
158             },
159             nullptr, nullptr);
160 
161         /* insert callback functions */
162         const char* funName = "on";
163         napi_value funcValue = nullptr;
164         napi_create_function(env, funName, NAPI_AUTO_LENGTH, On, nullptr, &funcValue);
165         napi_set_named_property(env, result, funName, funcValue);
166 
167         funName = "off";
168         napi_create_function(env, funName, NAPI_AUTO_LENGTH, Off, nullptr, &funcValue);
169         napi_set_named_property(env, result, funName, funcValue);
170 
171         funName = "startDrag";
172         napi_create_function(env, funName, NAPI_AUTO_LENGTH, StartDrag, nullptr, &funcValue);
173         napi_set_named_property(env, result, funName, funcValue);
174     }
175 
DeleteRef()176     void DeleteRef()
177     {
178         CHECK_NULL_VOID(asyncCtx_);
179         for (auto customBuilderValue : asyncCtx_->customBuilderList) {
180             if (customBuilderValue == nullptr) {
181                 continue;
182             }
183             napi_delete_reference(asyncCtx_->env, customBuilderValue);
184         }
185         delete asyncCtx_;
186         asyncCtx_ = nullptr;
187     }
188 
On(napi_env env,napi_callback_info info)189     static napi_value On(napi_env env, napi_callback_info info)
190     {
191         TAG_LOGI(AceLogTag::ACE_DRAG, "drag action On function called.");
192         auto jsEngine = EngineHelper::GetCurrentEngineSafely();
193         CHECK_NULL_RETURN(jsEngine, nullptr);
194 
195         napi_handle_scope scope = nullptr;
196         napi_open_handle_scope(env, &scope);
197         CHECK_NULL_RETURN(scope, nullptr);
198         napi_value thisVar = nullptr;
199         napi_value cb = nullptr;
200         size_t argc = ParseArgs(env, info, thisVar, cb);
201         NAPI_ASSERT(env, (argc == 2 && thisVar != nullptr && cb != nullptr), "Invalid arguments");
202         napi_valuetype valueType = napi_undefined;
203         napi_typeof(env, cb, &valueType);
204         if (valueType != napi_function) {
205             NapiThrow(env, "Check param failed", ERROR_CODE_PARAM_INVALID);
206             napi_close_handle_scope(env, scope);
207             return nullptr;
208         }
209         DragAction* dragAction = ConvertDragAction(env, thisVar);
210         if (!dragAction) {
211             NapiThrow(env, "convert drag action failed.", ERROR_CODE_PARAM_INVALID);
212             napi_close_handle_scope(env, scope);
213             return nullptr;
214         }
215         auto iter = dragAction->FindCbList(cb);
216         if (iter != dragAction->cbList_.end()) {
217             NapiThrow(env, "get js callback function error.", ERROR_CODE_PARAM_INVALID);
218             napi_close_handle_scope(env, scope);
219             return nullptr;
220         }
221         napi_ref ref = nullptr;
222         napi_create_reference(env, cb, 1, &ref);
223         dragAction->cbList_.emplace_back(ref);
224         napi_close_handle_scope(env, scope);
225         return nullptr;
226     }
227 
Off(napi_env env,napi_callback_info info)228     static napi_value Off(napi_env env, napi_callback_info info)
229     {
230         TAG_LOGI(AceLogTag::ACE_DRAG, "drag action Off function called.");
231         napi_value thisVar = nullptr;
232         napi_value cb = nullptr;
233         size_t argc = ParseArgs(env, info, thisVar, cb);
234         DragAction* dragAction = ConvertDragAction(env, thisVar);
235         CHECK_NULL_RETURN(dragAction, nullptr);
236         if (argc == 1) {
237             for (const auto& item : dragAction->cbList_) {
238                 napi_delete_reference(dragAction->env_, item);
239             }
240             dragAction->cbList_.clear();
241         } else {
242             NAPI_ASSERT(env, (argc == 2 && dragAction != nullptr && cb != nullptr), "Invalid arguments");
243             napi_valuetype valueType = napi_undefined;
244             napi_typeof(env, cb, &valueType);
245             if (valueType != napi_function) {
246                 NapiThrow(env, "Check param failed", ERROR_CODE_PARAM_INVALID);
247                 return nullptr;
248             }
249             auto iter = dragAction->FindCbList(cb);
250             if (iter != dragAction->cbList_.end()) {
251                 napi_delete_reference(dragAction->env_, *iter);
252                 dragAction->cbList_.erase(iter);
253             }
254         }
255         return nullptr;
256     }
257 
StartDrag(napi_env env,napi_callback_info info)258     static napi_value StartDrag(napi_env env, napi_callback_info info)
259     {
260         TAG_LOGI(AceLogTag::ACE_DRAG, "drag action StartDrag function called.");
261         auto jsEngine = EngineHelper::GetCurrentEngineSafely();
262         CHECK_NULL_RETURN(jsEngine, nullptr);
263 
264         napi_escapable_handle_scope scope = nullptr;
265         napi_open_escapable_handle_scope(env, &scope);
266         CHECK_NULL_RETURN(scope, nullptr);
267         napi_value thisVar = nullptr;
268         napi_value cb = nullptr;
269         size_t argc = ParseArgs(env, info, thisVar, cb);
270         NAPI_ASSERT(env, (argc == 0 && thisVar != nullptr), "Invalid arguments");
271         DragAction* dragAction = ConvertDragAction(env, thisVar);
272         if (!dragAction) {
273             NapiThrow(env, "convert drag action failed.", ERROR_CODE_INTERNAL_ERROR);
274             napi_close_escapable_handle_scope(env, scope);
275             return nullptr;
276         }
277         if (dragAction->asyncCtx_ == nullptr) {
278             NapiThrow(env, "drag action must be recreated for each dragging", ERROR_CODE_INTERNAL_ERROR);
279             napi_close_escapable_handle_scope(env, scope);
280             return nullptr;
281         }
282         napi_value promiseResult = nullptr;
283         napi_status status = napi_create_promise(env, &dragAction->asyncCtx_->deferred, &promiseResult);
284         if (status != napi_ok) {
285             NapiThrow(env, "ace engine delegate is null", ERROR_CODE_INTERNAL_ERROR);
286             napi_close_escapable_handle_scope(env, scope);
287             return nullptr;
288         }
289 
290         SetMouseDragMonitorState(dragAction->asyncCtx_, true);
291         dragAction->StartDragInternal(dragAction->asyncCtx_);
292         napi_escape_handle(env, scope, promiseResult, &promiseResult);
293         napi_close_escapable_handle_scope(env, scope);
294         return promiseResult;
295     }
296 
FindCbList(napi_value cb)297     std::list<napi_ref>::iterator FindCbList(napi_value cb)
298     {
299         return std::find_if(cbList_.begin(), cbList_.end(), [env = env_, cb](const napi_ref& item) -> bool {
300             bool result = false;
301             napi_value refItem;
302             napi_get_reference_value(env, item, &refItem);
303             napi_strict_equals(env, refItem, cb, &result);
304             return result;
305         });
306     }
307 
308 private:
Initialize(napi_env env,napi_value thisVar)309     void Initialize(napi_env env, napi_value thisVar)
310     {
311         env_ = env;
312     }
313 
ParseArgs(napi_env & env,napi_callback_info & info,napi_value & thisVar,napi_value & cb)314     static size_t ParseArgs(napi_env& env, napi_callback_info& info, napi_value& thisVar, napi_value& cb)
315     {
316         size_t argc = 2;
317         napi_value argv[argCount2] = { 0 };
318         void* data = nullptr;
319         napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
320         if (argc == 0) {
321             return argc;
322         }
323         NAPI_ASSERT_BASE(env, argc > 0, "too few parameter", 0);
324 
325         napi_valuetype napiType;
326         NAPI_CALL_BASE(env, napi_typeof(env, argv[0], &napiType), 0);
327         NAPI_ASSERT_BASE(env, napiType == napi_string, "parameter 1 should be string", 0);
328         char type[STR_BUFFER_SIZE] = { 0 };
329         size_t len = 0;
330         napi_get_value_string_utf8(env, argv[0], type, STR_BUFFER_SIZE, &len);
331         NAPI_ASSERT_BASE(env, len < STR_BUFFER_SIZE, "condition string too long", 0);
332         NAPI_ASSERT_BASE(env, strcmp("statusChange", type) == 0, "type mismatch('change')", 0);
333         if (argc <= 1) {
334             return argc;
335         }
336         NAPI_CALL_BASE(env, napi_typeof(env, argv[1], &napiType), 0);
337         NAPI_ASSERT_BASE(env, napiType == napi_function, "type mismatch for parameter 2", 0);
338         cb = argv[1];
339         return argc;
340     }
341 
ConvertDragAction(napi_env env,napi_value thisVar)342     static DragAction* ConvertDragAction(napi_env env, napi_value thisVar)
343     {
344         DragAction* dragAction = nullptr;
345         napi_unwrap(env, thisVar, (void**)&dragAction);
346         if (dragAction) {
347             dragAction->Initialize(env, thisVar);
348         }
349         return dragAction;
350     }
351 
StartDragInternal(DragControllerAsyncCtx * dragCtx)352     void StartDragInternal(DragControllerAsyncCtx *dragCtx)
353     {
354         CHECK_NULL_VOID(dragCtx);
355         ParameterType parameterType = getParameterType(dragCtx);
356         TAG_LOGI(AceLogTag::ACE_DRAG, "parameter type is %{public}d", static_cast<int32_t>(parameterType));
357         if (parameterType == ParameterType::DRAGITEMINFO_ARRAY) {
358             OnMultipleComplete(dragCtx);
359         } else if (parameterType == ParameterType::MIX) {
360             int32_t arrayLenth = static_cast<int32_t>(dragCtx->customBuilderList.size());
361             for (auto customBuilderValue: dragCtx->customBuilderList) {
362                 napi_value cb = nullptr;
363                 napi_get_reference_value(dragCtx->env, customBuilderValue, &cb);
364                 GetPixelMapArrayByCustom(dragCtx, cb, arrayLenth);
365             }
366         } else {
367             NapiThrow(dragCtx->env, "parameter parsing failed.", ERROR_CODE_PARAM_INVALID);
368         }
369     }
370 
371     napi_env env_ = nullptr;
372     std::list<napi_ref> cbList_;
373     DragControllerAsyncCtx* asyncCtx_;
374 };
375 
~DragControllerAsyncCtx()376 DragControllerAsyncCtx::~DragControllerAsyncCtx()
377 {
378     if (!dragAction) {
379         dragAction = nullptr;
380     }
381 }
382 
IsExecutingWithDragAction(DragControllerAsyncCtx * asyncCtx)383 bool IsExecutingWithDragAction(DragControllerAsyncCtx* asyncCtx)
384 {
385     CHECK_NULL_RETURN(asyncCtx, false);
386     return (asyncCtx->isArray && asyncCtx->argc == 2);
387 }
388 
CreateCallbackErrorValue(napi_env env,int32_t errCode,const std::string & errMsg="")389 napi_value CreateCallbackErrorValue(napi_env env, int32_t errCode, const std::string& errMsg = "")
390 {
391     napi_value code = nullptr;
392     std::string strCode = std::to_string(errCode);
393     napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
394     napi_value msg = nullptr;
395     napi_create_string_utf8(env, errMsg.c_str(), errMsg.length(), &msg);
396     napi_value error = nullptr;
397     napi_create_error(env, code, msg, &error);
398     return error;
399 }
400 
ConvertToPx(DragControllerAsyncCtx * asyncCtx,const Dimension & dimension,double size)401 double ConvertToPx(DragControllerAsyncCtx* asyncCtx, const Dimension& dimension, double size)
402 {
403     auto unit = dimension.Unit();
404     auto value = dimension.Value();
405     if (unit == DimensionUnit::PERCENT) {
406         return value * size;
407     }
408     if (unit == DimensionUnit::NONE || unit == DimensionUnit::PX) {
409         return value;
410     }
411     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
412     if (!container) {
413         return 0.0;
414     }
415     auto pipeline = container->GetPipelineContext();
416     CHECK_NULL_RETURN(pipeline, 0.0);
417     if (unit == DimensionUnit::VP) {
418         return value * pipeline->GetDipScale();
419     }
420     if (unit == DimensionUnit::FP) {
421         return value * pipeline->GetDipScale() * pipeline->GetFontScale();
422     }
423     if (unit == DimensionUnit::LPX) {
424         return value * pipeline->GetLogicScale();
425     }
426     return 0.0;
427 }
428 
HandleDimensionType(napi_value parameterNapi,napi_env env)429 static std::optional<Dimension> HandleDimensionType(napi_value parameterNapi, napi_env env)
430 {
431     size_t ret = 0;
432     std::string parameterStr;
433     napi_valuetype valueType = napi_undefined;
434     napi_typeof(env, parameterNapi, &valueType);
435     Dimension parameter;
436     if (valueType == napi_number) {
437         double parameterValue;
438         napi_get_value_double(env, parameterNapi, &parameterValue);
439         parameter.SetValue(parameterValue);
440         parameter.SetUnit(DimensionUnit::VP);
441     } else if (valueType == napi_string) {
442         size_t parameterLen = GetParamLen(env, parameterNapi) + 1;
443         std::unique_ptr<char[]> parameterTemp = std::make_unique<char[]>(parameterLen);
444         napi_get_value_string_utf8(env, parameterNapi, parameterTemp.get(), parameterLen, &ret);
445         parameterStr = parameterTemp.get();
446         parameter = StringUtils::StringToDimensionWithUnit(parameterStr, DimensionUnit::VP);
447     } else if (valueType == napi_object) {
448         ResourceInfo recv;
449         if (!ParseResourceParam(env, parameterNapi, recv)) {
450             return std::nullopt;
451         }
452         if (!ParseString(recv, parameterStr)) {
453             return std::nullopt;
454         }
455         parameter = StringUtils::StringToDimensionWithUnit(parameterStr, DimensionUnit::VP);
456     } else {
457         return std::nullopt;
458     }
459     return parameter;
460 }
461 
CallBackForJs(DragControllerAsyncCtx * asyncCtx,napi_value result)462 void CallBackForJs(DragControllerAsyncCtx* asyncCtx, napi_value result)
463 {
464     CHECK_NULL_VOID(asyncCtx);
465     CHECK_NULL_VOID(result);
466 
467     if (IsExecutingWithDragAction(asyncCtx) && asyncCtx->dragAction) {
468         asyncCtx->dragAction->OnNapiCallback(result);
469         if (asyncCtx->deferred != nullptr) {
470             napi_value promiseResult = nullptr;
471             napi_get_undefined(asyncCtx->env, &promiseResult);
472             napi_resolve_deferred(asyncCtx->env, asyncCtx->deferred, promiseResult);
473         }
474     } else {
475         napi_value resultVal[PARAMETER_NUM] = { nullptr };
476         napi_get_undefined(asyncCtx->env, &resultVal[0]);
477         napi_get_undefined(asyncCtx->env, &resultVal[1]);
478         resultVal[1] = result;
479         if (asyncCtx->callbackRef) {
480             napi_value ret = nullptr;
481             napi_value napiCallback = nullptr;
482             napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
483             napi_call_function(asyncCtx->env, nullptr, napiCallback, PARAMETER_NUM, resultVal, &ret);
484             napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
485         } else {
486             napi_resolve_deferred(asyncCtx->env, asyncCtx->deferred, resultVal[1]);
487         }
488     }
489     asyncCtx->deferred = nullptr;
490     asyncCtx->hasHandle = false;
491 }
492 
GetCallBackDataForJs(DragControllerAsyncCtx * asyncCtx,const DragNotifyMsg & dragNotifyMsg,const DragStatus dragStatus,napi_value & result)493 void GetCallBackDataForJs(DragControllerAsyncCtx* asyncCtx, const DragNotifyMsg& dragNotifyMsg,
494     const DragStatus dragStatus, napi_value& result)
495 {
496     CHECK_NULL_VOID(asyncCtx);
497     napi_handle_scope scope = nullptr;
498     napi_open_handle_scope(asyncCtx->env, &scope);
499     napi_get_undefined(asyncCtx->env, &result);
500     auto resultCode = dragNotifyMsg.result;
501     napi_create_object(asyncCtx->env, &result);
502     napi_value eventNapi = nullptr;
503     napi_value globalObj = nullptr;
504     napi_value customDragEvent = nullptr;
505     napi_create_object(asyncCtx->env, &customDragEvent);
506     napi_get_global(asyncCtx->env, &globalObj);
507     napi_get_named_property(asyncCtx->env, globalObj, "DragEvent", &customDragEvent);
508     napi_status status = napi_new_instance(asyncCtx->env, customDragEvent, 0, nullptr, &eventNapi);
509     if (status != napi_ok) {
510         TAG_LOGE(AceLogTag::ACE_DRAG,
511             "create new instance dragEvent failed, return value is %{public}d", status);
512         napi_close_handle_scope(asyncCtx->env, scope);
513         return;
514     }
515     auto localRef = NapiValueToLocalValue(eventNapi);
516     if (localRef->IsNull()) {
517         TAG_LOGE(AceLogTag::ACE_DRAG, "napi value convert to local value failed.");
518         napi_close_handle_scope(asyncCtx->env, scope);
519         return;
520     }
521     auto vm = reinterpret_cast<NativeEngine*>(asyncCtx->env)->GetEcmaVm();
522     auto* jsDragEvent =
523         static_cast<Framework::JsDragEvent*>(Local<panda::ObjectRef>(localRef)->GetNativePointerField(vm, 0));
524     CHECK_NULL_VOID(jsDragEvent);
525     auto dragEvent = AceType::MakeRefPtr<DragEvent>();
526     CHECK_NULL_VOID(dragEvent);
527     dragEvent->SetResult(static_cast<DragRet>(resultCode));
528     dragEvent->SetDragBehavior(static_cast<DragBehavior>(dragNotifyMsg.dragBehavior));
529     jsDragEvent->SetDragEvent(dragEvent);
530     napi_set_named_property(asyncCtx->env, result, "event", eventNapi);
531 
532     napi_value extraParamsNapi = nullptr;
533     napi_create_string_utf8(
534         asyncCtx->env, asyncCtx->extraParams.c_str(), asyncCtx->extraParams.length(), &extraParamsNapi);
535     napi_set_named_property(asyncCtx->env, result, "extraParams", extraParamsNapi);
536 
537     if (asyncCtx->isArray) {
538         napi_value dragStatusValue = nullptr;
539         napi_create_int32(asyncCtx->env, static_cast<int32_t>(dragStatus), &dragStatusValue);
540         napi_set_named_property(asyncCtx->env, result, "status", dragStatusValue);
541     }
542 
543     CallBackForJs(asyncCtx, result);
544     napi_close_handle_scope(asyncCtx->env, scope);
545 }
546 
SetMouseDragMonitorState(DragControllerAsyncCtx * asyncCtx,bool state)547 void SetMouseDragMonitorState(DragControllerAsyncCtx *asyncCtx, bool state)
548 {
549     if (asyncCtx->sourceType != SOURCE_TYPE_MOUSE) {
550         return;
551     }
552     auto ret = Msdp::DeviceStatus::InteractionManager::GetInstance()->SetMouseDragMonitorState(state);
553     if (ret != 0) {
554         TAG_LOGW(AceLogTag::ACE_DRAG, "Set mouse drag monitor state %{public}d failed, return value is %{public}d",
555             state, ret);
556         return;
557     }
558     TAG_LOGI(AceLogTag::ACE_DRAG, "Set mouse drag monitor state %{public}d success", state);
559 }
560 
HandleExecuteDrag(napi_env env,DragControllerAsyncCtx * asyncCtx)561 void HandleExecuteDrag(napi_env env, DragControllerAsyncCtx *asyncCtx)
562 {
563     ParameterType parameterType = getParameterType(asyncCtx);
564     if (parameterType == ParameterType::DRAGITEMINFO) {
565         OnComplete(asyncCtx);
566     } else if (parameterType == ParameterType::CUSTOMBUILDER) {
567         GetPixelMapByCustom(asyncCtx);
568     } else {
569         NapiThrow(env, "parameter parsing error.", ERROR_CODE_PARAM_INVALID);
570     }
571 }
572 
HandleSuccess(DragControllerAsyncCtx * asyncCtx,const DragNotifyMsg & dragNotifyMsg,const DragStatus dragStatus)573 void HandleSuccess(DragControllerAsyncCtx* asyncCtx, const DragNotifyMsg& dragNotifyMsg,
574     const DragStatus dragStatus)
575 {
576     TAG_LOGI(AceLogTag::ACE_DRAG, "drag notify message result is %{public}d.", dragNotifyMsg.result);
577     CHECK_NULL_VOID(asyncCtx);
578     bool hasHandle = false;
579     {
580         std::lock_guard<std::mutex> lock(asyncCtx->mutex);
581         hasHandle = asyncCtx->hasHandle;
582         asyncCtx->hasHandle = true;
583     }
584     if (hasHandle) {
585         return;
586     }
587     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
588     CHECK_NULL_VOID(container);
589     if (dragStatus == DragStatus::ENDED) {
590         auto pipelineContext = container->GetPipelineContext();
591         CHECK_NULL_VOID(pipelineContext);
592         pipelineContext->ResetDragging();
593     }
594     auto taskExecutor = container->GetTaskExecutor();
595     CHECK_NULL_VOID(taskExecutor);
596     taskExecutor->PostSyncTask(
597         [asyncCtx, dragNotifyMsg, dragStatus]() {
598             CHECK_NULL_VOID(asyncCtx);
599             napi_value dragAndDropInfoValue;
600             GetCallBackDataForJs(asyncCtx, dragNotifyMsg, dragStatus, dragAndDropInfoValue);
601         },
602         TaskExecutor::TaskType::JS, "ArkUIDragHandleSuccess");
603 }
604 
HandleFail(DragControllerAsyncCtx * asyncCtx,int32_t errorCode,const std::string & errMsg="")605 void HandleFail(DragControllerAsyncCtx* asyncCtx, int32_t errorCode, const std::string& errMsg = "")
606 {
607     CHECK_NULL_VOID(asyncCtx);
608     bool hasHandle = false;
609     {
610         std::lock_guard<std::mutex> lock(asyncCtx->mutex);
611         hasHandle = asyncCtx->hasHandle;
612         asyncCtx->hasHandle = true;
613     }
614     if (hasHandle) {
615         return;
616     }
617     napi_value result[2] = { nullptr };
618     result[0] = CreateCallbackErrorValue(asyncCtx->env, errorCode, errMsg);
619     if (asyncCtx->callbackRef) {
620         napi_value ret = nullptr;
621         napi_value napiCallback = nullptr;
622         napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
623         napi_create_object(asyncCtx->env, &result[1]);
624         napi_call_function(asyncCtx->env, nullptr, napiCallback, 2, result, &ret);
625         napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
626     } else {
627         napi_reject_deferred(asyncCtx->env, asyncCtx->deferred, result[0]);
628     }
629     asyncCtx->deferred = nullptr;
630 }
631 
HandleDragEnd(DragControllerAsyncCtx * asyncCtx,const DragNotifyMsg & dragNotifyMsg)632 void HandleDragEnd(DragControllerAsyncCtx* asyncCtx, const DragNotifyMsg& dragNotifyMsg)
633 {
634     TAG_LOGI(AceLogTag::ACE_DRAG, "handleDragEnd notify message result is %{public}d.", dragNotifyMsg.result);
635     CHECK_NULL_VOID(asyncCtx);
636     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
637     CHECK_NULL_VOID(container);
638     auto pipelineContext = container->GetPipelineContext();
639     CHECK_NULL_VOID(pipelineContext);
640     pipelineContext->ResetDragging();
641     auto taskExecutor = container->GetTaskExecutor();
642     CHECK_NULL_VOID(taskExecutor);
643     taskExecutor->PostSyncTask(
644         [asyncCtx, dragNotifyMsg]() {
645             CHECK_NULL_VOID(asyncCtx);
646             napi_value dragAndDropInfoValue;
647             GetCallBackDataForJs(asyncCtx, dragNotifyMsg, DragStatus::ENDED, dragAndDropInfoValue);
648         },
649         TaskExecutor::TaskType::JS, "ArkUIDragHandleDragEnd");
650 }
651 
HandleOnDragStart(DragControllerAsyncCtx * asyncCtx)652 void HandleOnDragStart(DragControllerAsyncCtx* asyncCtx)
653 {
654     ContainerScope scope(asyncCtx->instanceId);
655     auto container = Container::CurrentSafely();
656     CHECK_NULL_VOID(container);
657     auto pipelineContext = container->GetPipelineContext();
658     CHECK_NULL_VOID(pipelineContext);
659     auto taskExecutor = container->GetTaskExecutor();
660     CHECK_NULL_VOID(taskExecutor);
661     taskExecutor->PostTask(
662         [ctx = asyncCtx, context = pipelineContext]() {
663             context->OnDragEvent({ ctx->globalX, ctx->globalY }, DragEventAction::DRAG_EVENT_START_FOR_CONTROLLER);
664             NG::DragDropFuncWrapper::DecideWhetherToStopDragging(
665                 { ctx->globalX, ctx->globalY }, ctx->extraParams, ctx->pointerId, ctx->instanceId);
666         },
667         TaskExecutor::TaskType::UI, "ArkUIDragHandleDragEventStart", PriorityType::VIP);
668 }
669 
GetShadowInfoArray(DragControllerAsyncCtx * asyncCtx,std::vector<Msdp::DeviceStatus::ShadowInfo> & shadowInfos)670 void GetShadowInfoArray(DragControllerAsyncCtx* asyncCtx,
671     std::vector<Msdp::DeviceStatus::ShadowInfo>& shadowInfos)
672 {
673     std::set<Media::PixelMap*> scaledPixelMaps;
674     auto minScaleWidth = NG::DragDropFuncWrapper::GetScaleWidth(asyncCtx->instanceId);
675     for (const auto& pixelMap: asyncCtx->pixelMapList) {
676         double scale = 1.0;
677         if (!scaledPixelMaps.count(pixelMap.get())) {
678             if (pixelMap->GetWidth() > minScaleWidth && asyncCtx->dragPreviewOption.isScaleEnabled) {
679                 scale = minScaleWidth / pixelMap->GetWidth();
680             }
681             auto pixelMapScale = asyncCtx->windowScale * scale;
682             pixelMap->scale(pixelMapScale, pixelMapScale, Media::AntiAliasingOption::HIGH);
683             scaledPixelMaps.insert(pixelMap.get());
684         }
685         int32_t width = pixelMap->GetWidth();
686         int32_t height = pixelMap->GetHeight();
687         double x = ConvertToPx(asyncCtx, asyncCtx->touchPoint.GetX(), width);
688         double y = ConvertToPx(asyncCtx, asyncCtx->touchPoint.GetY(), height);
689         if (!asyncCtx->hasTouchPoint) {
690             x = -width * PIXELMAP_WIDTH_RATE;
691             y = -height * PIXELMAP_HEIGHT_RATE;
692         }
693         Msdp::DeviceStatus::ShadowInfo shadowInfo { pixelMap, -x, -y  };
694         shadowInfos.push_back(shadowInfo);
695     }
696 }
697 
JudgeCoordinateCanDrag(Msdp::DeviceStatus::ShadowInfo & shadowInfo)698 bool JudgeCoordinateCanDrag(Msdp::DeviceStatus::ShadowInfo& shadowInfo)
699 {
700     CHECK_NULL_RETURN(shadowInfo.pixelMap, false);
701     int32_t x = -shadowInfo.x;
702     int32_t y = -shadowInfo.y;
703     int32_t width = shadowInfo.pixelMap->GetWidth();
704     int32_t height = shadowInfo.pixelMap->GetHeight();
705     if (x < 0 || y < 0 || x > width || y > height) {
706         return false;
707     }
708     return true;
709 }
710 
SetIsDragging(const RefPtr<Container> & container,bool isDragging)711 static void SetIsDragging(const RefPtr<Container>& container, bool isDragging)
712 {
713     if (!container) {
714         return;
715     }
716     auto pipelineContext = container->GetPipelineContext();
717     if (!pipelineContext) {
718         return;
719     }
720     pipelineContext->SetIsDragging(isDragging);
721 }
722 
EnvelopedDragData(DragControllerAsyncCtx * asyncCtx,std::optional<Msdp::DeviceStatus::DragData> & dragData)723 void EnvelopedDragData(DragControllerAsyncCtx* asyncCtx, std::optional<Msdp::DeviceStatus::DragData>& dragData)
724 {
725     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
726     CHECK_NULL_VOID(container);
727     auto displayInfo = container->GetDisplayInfo();
728     CHECK_NULL_VOID(displayInfo);
729     asyncCtx->displayId = displayInfo->GetDisplayId();
730     std::vector<Msdp::DeviceStatus::ShadowInfo> shadowInfos;
731     GetShadowInfoArray(asyncCtx, shadowInfos);
732     if (shadowInfos.empty()) {
733         TAG_LOGE(AceLogTag::ACE_DRAG, "shadowInfo array is empty");
734         return;
735     }
736     if (!JudgeCoordinateCanDrag(shadowInfos[0])) {
737         napi_handle_scope scope = nullptr;
738         napi_open_handle_scope(asyncCtx->env, &scope);
739         HandleFail(asyncCtx, ERROR_CODE_PARAM_INVALID, "touchPoint's coordinate out of range");
740         napi_close_handle_scope(asyncCtx->env, scope);
741         return;
742     }
743     auto pointerId = asyncCtx->pointerId;
744     std::string udKey;
745     std::map<std::string, int64_t> summary;
746     int32_t dataSize = 1;
747     if (asyncCtx->unifiedData) {
748         int32_t ret = UdmfClient::GetInstance()->SetData(asyncCtx->unifiedData, udKey);
749         if (ret != 0) {
750             TAG_LOGI(AceLogTag::ACE_DRAG, "udmf set data failed, return value is %{public}d", ret);
751         } else {
752             UdmfClient::GetInstance()->GetSummary(udKey, summary);
753         }
754         dataSize = static_cast<int32_t>(asyncCtx->unifiedData->GetSize());
755     }
756     int32_t recordSize = (dataSize != 0 ? dataSize : static_cast<int32_t>(shadowInfos.size()));
757     auto badgeNumber = asyncCtx->dragPreviewOption.GetCustomerBadgeNumber();
758     if (badgeNumber.has_value()) {
759         recordSize = badgeNumber.value();
760     }
761     auto windowId = container->GetWindowId();
762     auto arkExtraInfoJson = JsonUtil::Create(true);
763     arkExtraInfoJson->Put("dip_scale", asyncCtx->dipScale);
764     NG::DragDropFuncWrapper::UpdateExtraInfo(arkExtraInfoJson, asyncCtx->dragPreviewOption);
765     dragData = { shadowInfos, {}, udKey, asyncCtx->extraParams, arkExtraInfoJson->ToString(), asyncCtx->sourceType,
766         recordSize, pointerId, asyncCtx->globalX, asyncCtx->globalY,
767         asyncCtx->displayId, windowId, true, false, summary };
768 }
769 
StartDragService(DragControllerAsyncCtx * asyncCtx)770 void StartDragService(DragControllerAsyncCtx* asyncCtx)
771 {
772     std::optional<Msdp::DeviceStatus::DragData> dragData;
773     EnvelopedDragData(asyncCtx, dragData);
774     if (!dragData) {
775         napi_handle_scope scope = nullptr;
776         napi_open_handle_scope(asyncCtx->env, &scope);
777         HandleFail(asyncCtx, ERROR_CODE_PARAM_INVALID, "did not has any drag data.");
778         napi_close_handle_scope(asyncCtx->env, scope);
779         return;
780     }
781     OnDragCallback callback = [asyncCtx](const DragNotifyMsg& dragNotifyMsg) {
782         HandleDragEnd(asyncCtx, dragNotifyMsg);
783     };
784     NG::DragDropFuncWrapper::SetDraggingPointerAndPressedState(asyncCtx->pointerId, asyncCtx->instanceId);
785     NG::DragDropFuncWrapper::SetExtraInfo(asyncCtx->instanceId, asyncCtx->extraParams);
786     int32_t ret = Msdp::DeviceStatus::InteractionManager::GetInstance()->StartDrag(dragData.value(),
787         std::make_shared<OHOS::Ace::StartDragListenerImpl>(callback));
788     if (ret != 0) {
789         napi_handle_scope scope = nullptr;
790         napi_open_handle_scope(asyncCtx->env, &scope);
791         HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "msdp start drag failed.");
792         napi_close_handle_scope(asyncCtx->env, scope);
793         return;
794     }
795     napi_handle_scope scope = nullptr;
796     napi_open_handle_scope(asyncCtx->env, &scope);
797     HandleSuccess(asyncCtx, DragNotifyMsg {}, DragStatus::STARTED);
798     napi_close_handle_scope(asyncCtx->env, scope);
799     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
800     SetIsDragging(container, true);
801     TAG_LOGI(AceLogTag::ACE_DRAG, "msdp start drag successfully");
802     std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
803     if (asyncCtx->dragState == DragState::SENDING) {
804         asyncCtx->dragState = DragState::SUCCESS;
805         Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(true);
806         napi_handle_scope scope = nullptr;
807         napi_open_handle_scope(asyncCtx->env, &scope);
808         HandleOnDragStart(asyncCtx);
809         napi_close_handle_scope(asyncCtx->env, scope);
810     }
811 }
812 
OnMultipleComplete(DragControllerAsyncCtx * asyncCtx)813 void OnMultipleComplete(DragControllerAsyncCtx* asyncCtx)
814 {
815     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
816     CHECK_NULL_VOID(container);
817     auto taskExecutor = container->GetTaskExecutor();
818     CHECK_NULL_VOID(taskExecutor);
819     auto windowScale = container->GetWindowScale();
820     asyncCtx->windowScale = windowScale;
821     taskExecutor->PostTask(
822         [asyncCtx]() {
823             CHECK_NULL_VOID(asyncCtx);
824             ContainerScope scope(asyncCtx->instanceId);
825             DragState dragState = DragState::PENDING;
826             {
827                 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
828                 if (asyncCtx->dragState == DragState::PENDING) {
829                     asyncCtx->dragState = DragState::SENDING;
830                 }
831                 dragState = asyncCtx->dragState;
832             }
833             if (dragState == DragState::REJECT) {
834                 napi_handle_scope scope = nullptr;
835                 napi_open_handle_scope(asyncCtx->env, &scope);
836                 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "drag state is reject.");
837                 SetMouseDragMonitorState(asyncCtx, false);
838                 napi_close_handle_scope(asyncCtx->env, scope);
839                 return;
840             }
841             StartDragService(asyncCtx);
842         },
843         TaskExecutor::TaskType::JS, "ArkUIDragMultipleComplete", PriorityType::VIP);
844 }
845 
OnComplete(DragControllerAsyncCtx * asyncCtx)846 void OnComplete(DragControllerAsyncCtx* asyncCtx)
847 {
848     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
849     CHECK_NULL_VOID(container);
850     auto taskExecutor = container->GetTaskExecutor();
851     CHECK_NULL_VOID(taskExecutor);
852     auto windowScale = container->GetWindowScale();
853     asyncCtx->windowScale = windowScale;
854     auto displayInfo = container->GetDisplayInfo();
855     CHECK_NULL_VOID(displayInfo);
856     asyncCtx->displayId = displayInfo->GetDisplayId();
857     taskExecutor->PostTask(
858         [asyncCtx]() {
859             CHECK_NULL_VOID(asyncCtx);
860             ContainerScope scope(asyncCtx->instanceId);
861             DragState dragState = DragState::PENDING;
862             {
863                 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
864                 if (asyncCtx->dragState == DragState::PENDING) {
865                     asyncCtx->dragState = DragState::SENDING;
866                 }
867                 dragState = asyncCtx->dragState;
868             }
869             if (dragState == DragState::REJECT) {
870                 napi_handle_scope scope = nullptr;
871                 napi_open_handle_scope(asyncCtx->env, &scope);
872                 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "drag state is reject.");
873                 napi_close_handle_scope(asyncCtx->env, scope);
874                 return;
875             }
876             CHECK_NULL_VOID(asyncCtx->pixelMap);
877             int32_t dataSize = 1;
878             auto pointerId = asyncCtx->pointerId;
879             std::string udKey;
880             std::map<std::string, int64_t> summary;
881             if (asyncCtx->unifiedData) {
882                 int32_t ret = UdmfClient::GetInstance()->SetData(asyncCtx->unifiedData, udKey);
883                 if (ret != 0) {
884                     TAG_LOGI(AceLogTag::ACE_DRAG, "udmf set data failed, return value is %{public}d", ret);
885                 } else {
886                     UdmfClient::GetInstance()->GetSummary(udKey, summary);
887                 }
888                 dataSize = static_cast<int32_t>(asyncCtx->unifiedData->GetSize());
889             }
890             auto badgeNumber = asyncCtx->dragPreviewOption.GetCustomerBadgeNumber();
891             if (badgeNumber.has_value()) {
892                 dataSize = badgeNumber.value();
893             }
894             double scale = 1.0;
895             auto minScaleWidth = NG::DragDropFuncWrapper::GetScaleWidth(asyncCtx->instanceId);
896             if (asyncCtx->pixelMap->GetWidth() > minScaleWidth && asyncCtx->dragPreviewOption.isScaleEnabled) {
897                 scale = minScaleWidth / asyncCtx->pixelMap->GetWidth();
898             }
899             auto pixelMapScale = asyncCtx->windowScale * scale;
900             asyncCtx->pixelMap->scale(pixelMapScale, pixelMapScale, Media::AntiAliasingOption::HIGH);
901             int32_t width = asyncCtx->pixelMap->GetWidth();
902             int32_t height = asyncCtx->pixelMap->GetHeight();
903             double x = ConvertToPx(asyncCtx, asyncCtx->touchPoint.GetX(), width);
904             double y = ConvertToPx(asyncCtx, asyncCtx->touchPoint.GetY(), height);
905             if (!asyncCtx->hasTouchPoint) {
906                 x = -width * PIXELMAP_WIDTH_RATE;
907                 y = -height * PIXELMAP_HEIGHT_RATE;
908             } else if (x < 0 || y < 0 || x > static_cast<double>(width) || y > static_cast<double>(height)) {
909                 napi_handle_scope scope = nullptr;
910                 napi_open_handle_scope(asyncCtx->env, &scope);
911                 HandleFail(asyncCtx, ERROR_CODE_PARAM_INVALID, "touchPoint's coordinate out of range.");
912                 napi_close_handle_scope(asyncCtx->env, scope);
913                 return;
914             }
915             auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
916             CHECK_NULL_VOID(container);
917             auto arkExtraInfoJson = JsonUtil::Create(true);
918             arkExtraInfoJson->Put("dip_scale", asyncCtx->dipScale);
919             NG::DragDropFuncWrapper::UpdateExtraInfo(arkExtraInfoJson, asyncCtx->dragPreviewOption);
920             auto windowId = container->GetWindowId();
921             Msdp::DeviceStatus::ShadowInfo shadowInfo { asyncCtx->pixelMap, -x, -y };
922             Msdp::DeviceStatus::DragData dragData { { shadowInfo }, {}, udKey, asyncCtx->extraParams,
923                 arkExtraInfoJson->ToString(), asyncCtx->sourceType, dataSize, pointerId, asyncCtx->globalX,
924                 asyncCtx->globalY, asyncCtx->displayId, windowId, true, false, summary };
925 
926             OnDragCallback callback = [asyncCtx](const DragNotifyMsg& dragNotifyMsg) {
927                 HandleSuccess(asyncCtx, dragNotifyMsg, DragStatus::ENDED);
928             };
929             NG::DragDropFuncWrapper::SetDraggingPointerAndPressedState(asyncCtx->pointerId, asyncCtx->instanceId);
930             int32_t ret = Msdp::DeviceStatus::InteractionManager::GetInstance()->StartDrag(dragData,
931                 std::make_shared<OHOS::Ace::StartDragListenerImpl>(callback));
932             if (ret != 0) {
933                 napi_handle_scope scope = nullptr;
934                 napi_open_handle_scope(asyncCtx->env, &scope);
935                 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "msdp start drag failed.");
936                 napi_close_handle_scope(asyncCtx->env, scope);
937                 return;
938             }
939             SetIsDragging(container, true);
940             TAG_LOGI(AceLogTag::ACE_DRAG, "msdp start drag successfully");
941             {
942                 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
943                 if (asyncCtx->dragState == DragState::SENDING) {
944                     asyncCtx->dragState = DragState::SUCCESS;
945                     Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(true);
946                     napi_handle_scope scope = nullptr;
947                     napi_open_handle_scope(asyncCtx->env, &scope);
948                     HandleOnDragStart(asyncCtx);
949                     napi_close_handle_scope(asyncCtx->env, scope);
950                 }
951             }
952         },
953         TaskExecutor::TaskType::JS, "ArkUIDragComplete", PriorityType::VIP);
954 }
955 
ParseTouchPoint(DragControllerAsyncCtx * asyncCtx,napi_valuetype & valueType)956 bool ParseTouchPoint(DragControllerAsyncCtx* asyncCtx, napi_valuetype& valueType)
957 {
958     napi_value touchPointNapi = nullptr;
959     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "touchPoint", &touchPointNapi);
960     napi_typeof(asyncCtx->env, touchPointNapi, &valueType);
961     if (valueType == napi_object) {
962         napi_value xNapi = nullptr;
963         napi_get_named_property(asyncCtx->env, touchPointNapi, "x", &xNapi);
964         std::optional<Dimension> dx = HandleDimensionType(xNapi, asyncCtx->env);
965         if (dx == std::nullopt) {
966             return false;
967         }
968         napi_value yNapi = nullptr;
969         napi_get_named_property(asyncCtx->env, touchPointNapi, "y", &yNapi);
970         std::optional<Dimension> dy = HandleDimensionType(yNapi, asyncCtx->env);
971         if (dy == std::nullopt) {
972             return false;
973         }
974         asyncCtx->touchPoint = DimensionOffset(dx.value(), dy.value());
975     } else {
976         return false;
977     }
978     return true;
979 }
980 
ParseDragItemInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)981 bool ParseDragItemInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
982 {
983     CHECK_NULL_RETURN(asyncCtx, false);
984     napi_valuetype valueType = napi_undefined;
985     napi_typeof(asyncCtx->env, asyncCtx->argv[0], &valueType);
986     if (valueType == napi_function) {
987         asyncCtx->customBuilder = asyncCtx->argv[0];
988         return true;
989     }
990 
991     if (valueType != napi_object) {
992         errMsg = "The type of first parameter is incorrect.";
993         return false;
994     }
995     // Parse the DragItemInfo
996     napi_value pixelMapValue;
997     napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "pixelMap", &pixelMapValue);
998     PixelMapNapiEntry pixelMapNapiEntry = Framework::JsEngine::GetPixelMapNapiEntry();
999     if (pixelMapNapiEntry == nullptr) {
1000         TAG_LOGW(AceLogTag::ACE_DRAG, "failed to parse pixelMap from the first argument");
1001     } else {
1002         void* pixmapPtrAddr = pixelMapNapiEntry(asyncCtx->env, pixelMapValue);
1003         if (pixmapPtrAddr == nullptr) {
1004             napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "builder", &(asyncCtx->customBuilder));
1005             napi_typeof(asyncCtx->env, asyncCtx->customBuilder, &valueType);
1006             if (valueType != napi_function) {
1007                 errMsg = "The first parameter is not a pixelMap or customBuilder.";
1008                 return false;
1009             }
1010         } else {
1011             asyncCtx->pixelMap = *(reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(pixmapPtrAddr));
1012         }
1013     }
1014 
1015     napi_value extraInfoValue;
1016     napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "extraInfo", &extraInfoValue);
1017     napi_typeof(asyncCtx->env, extraInfoValue, &valueType);
1018     if (valueType == napi_string) {
1019         GetNapiString(asyncCtx->env, extraInfoValue, asyncCtx->extraParams, valueType);
1020     } else if (valueType != napi_undefined) {
1021         errMsg = "The type of extraInfo of the first parameter is incorrect.";
1022         return false;
1023     }
1024     return true;
1025 }
1026 
GetPixelMapByCustom(DragControllerAsyncCtx * asyncCtx)1027 bool GetPixelMapByCustom(DragControllerAsyncCtx* asyncCtx)
1028 {
1029     CHECK_NULL_RETURN(asyncCtx, false);
1030     napi_escapable_handle_scope scope = nullptr;
1031     napi_open_escapable_handle_scope(asyncCtx->env, &scope);
1032     auto delegate = EngineHelper::GetCurrentDelegateSafely();
1033     if (!delegate) {
1034         NapiThrow(asyncCtx->env, "ace engine delegate is null", ERROR_CODE_INTERNAL_ERROR);
1035         napi_close_escapable_handle_scope(asyncCtx->env, scope);
1036         return false;
1037     }
1038     auto callback = [asyncCtx](std::shared_ptr<Media::PixelMap> pixelMap, int32_t errCode,
1039         std::function<void()> finishCallback) {
1040         CHECK_NULL_VOID(asyncCtx);
1041         auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1042         CHECK_NULL_VOID(container);
1043         auto taskExecutor = container->GetTaskExecutor();
1044         CHECK_NULL_VOID(taskExecutor);
1045         taskExecutor->PostTask(
1046             [finishCallback]() {
1047                 CHECK_NULL_VOID(finishCallback);
1048                 finishCallback();
1049             },
1050             TaskExecutor::TaskType::JS, "ArkUIGetPixelMapByCustom");
1051         CHECK_NULL_VOID(pixelMap);
1052         asyncCtx->errCode = errCode;
1053         asyncCtx->pixelMap = std::move(pixelMap);
1054         OnComplete(asyncCtx);
1055     };
1056     auto builder = [build = asyncCtx->customBuilder, env = asyncCtx->env] {
1057         napi_call_function(env, nullptr, build, 0, nullptr, nullptr);
1058     };
1059     NG::SnapshotParam param;
1060     delegate->CreateSnapshot(builder, callback, true, param);
1061     napi_close_escapable_handle_scope(asyncCtx->env, scope);
1062     return true;
1063 }
1064 
GetPixelMapArrayByCustom(DragControllerAsyncCtx * asyncCtx,napi_value customBuilder,int arrayLength)1065 bool GetPixelMapArrayByCustom(DragControllerAsyncCtx* asyncCtx, napi_value customBuilder, int arrayLength)
1066 {
1067     CHECK_NULL_RETURN(asyncCtx, false);
1068     napi_escapable_handle_scope scope = nullptr;
1069     napi_open_escapable_handle_scope(asyncCtx->env, &scope);
1070 
1071     auto delegate = EngineHelper::GetCurrentDelegateSafely();
1072     if (!delegate) {
1073         NapiThrow(asyncCtx->env, "ace engine delegate is null", ERROR_CODE_INTERNAL_ERROR);
1074         napi_close_escapable_handle_scope(asyncCtx->env, scope);
1075         return false;
1076     }
1077     auto callback = [asyncCtx, arrayLength](
1078         std::shared_ptr<Media::PixelMap> pixelMap, int32_t errCode, std::function<void()> finishCallback) {
1079         CHECK_NULL_VOID(asyncCtx);
1080         auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1081         CHECK_NULL_VOID(container);
1082         auto taskExecutor = container->GetTaskExecutor();
1083         CHECK_NULL_VOID(taskExecutor);
1084         taskExecutor->PostTask(
1085             [finishCallback]() {
1086                 CHECK_NULL_VOID(finishCallback);
1087                 finishCallback();
1088             },
1089             TaskExecutor::TaskType::JS, "ArkUIGetPixelMapArrayByCustom");
1090         CHECK_NULL_VOID(pixelMap);
1091         asyncCtx->errCode = errCode;
1092         asyncCtx->pixelMapList.push_back(std::move(pixelMap));
1093         asyncCtx->parseBuilderCount++;
1094         if (asyncCtx->parseBuilderCount == arrayLength) {
1095             OnMultipleComplete(asyncCtx);
1096         }
1097     };
1098     auto builder = [build = customBuilder, env = asyncCtx->env] {
1099         napi_call_function(env, nullptr, build, 0, nullptr, nullptr);
1100     };
1101     NG::SnapshotParam param;
1102     delegate->CreateSnapshot(builder, callback, true, param);
1103     napi_close_escapable_handle_scope(asyncCtx->env, scope);
1104     return true;
1105 }
1106 
ParseExtraInfo(DragControllerAsyncCtx * asyncCtx,std::string & errMsg,napi_value element)1107 bool ParseExtraInfo(DragControllerAsyncCtx* asyncCtx, std::string& errMsg, napi_value element)
1108 {
1109     CHECK_NULL_RETURN(asyncCtx, false);
1110     napi_value extraInfoValue;
1111     napi_get_named_property(asyncCtx->env, element, "extraInfo", &extraInfoValue);
1112     napi_valuetype valueType = napi_undefined;
1113     napi_typeof(asyncCtx->env, extraInfoValue, &valueType);
1114     if (valueType != napi_string) {
1115         errMsg = "The type of extraInfo of the first parameter is incorrect.";
1116         return false;
1117     }
1118     GetNapiString(asyncCtx->env, extraInfoValue, asyncCtx->extraParams, valueType);
1119     return true;
1120 }
1121 
ParsePixelMapAndBuilder(DragControllerAsyncCtx * asyncCtx,std::string & errMsg,napi_value element)1122 bool ParsePixelMapAndBuilder(DragControllerAsyncCtx* asyncCtx, std::string& errMsg, napi_value element)
1123 {
1124     CHECK_NULL_RETURN(asyncCtx, false);
1125     napi_value pixelMapValue;
1126     napi_get_named_property(asyncCtx->env, element, "pixelMap", &pixelMapValue);
1127     PixelMapNapiEntry pixelMapNapiEntry = Framework::JsEngine::GetPixelMapNapiEntry();
1128     if (pixelMapNapiEntry == nullptr) {
1129         TAG_LOGW(AceLogTag::ACE_DRAG, "failed to parse pixelMap from the first argument");
1130     } else {
1131         void* pixmapPtrAddr = pixelMapNapiEntry(asyncCtx->env, pixelMapValue);
1132         if (pixmapPtrAddr == nullptr) {
1133             TAG_LOGW(AceLogTag::ACE_DRAG, "the pixelMap parsed from the first argument is null");
1134             napi_value customBuilderValue;
1135             napi_get_named_property(asyncCtx->env, element, "builder", &customBuilderValue);
1136             napi_valuetype valueType = napi_undefined;
1137             napi_typeof(asyncCtx->env, customBuilderValue, &valueType);
1138             if (valueType != napi_function) {
1139                 errMsg = "The type of customBuilder of the first parameter is incorrect.";
1140                 return false;
1141             }
1142             napi_ref ref = nullptr;
1143             napi_create_reference(asyncCtx->env, customBuilderValue, 1, &ref);
1144             asyncCtx->customBuilderList.push_back(ref);
1145         } else {
1146             asyncCtx->pixelMapList.push_back(*(reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(pixmapPtrAddr)));
1147         }
1148     }
1149     return true;
1150 }
1151 
ParseDragItemListInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)1152 bool ParseDragItemListInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
1153 {
1154     CHECK_NULL_RETURN(asyncCtx, false);
1155     bool isParseSucess;
1156     uint32_t arrayLength = 0;
1157     napi_get_array_length(asyncCtx->env, asyncCtx->argv[0], &arrayLength);
1158     for (size_t i = 0; i < arrayLength; i++) {
1159         bool hasElement = false;
1160         napi_has_element(asyncCtx->env, asyncCtx->argv[0], i, &hasElement);
1161         napi_value element = nullptr;
1162         napi_get_element(asyncCtx->env, asyncCtx->argv[0], i, &element);
1163         napi_valuetype valueType = napi_undefined;
1164         napi_typeof(asyncCtx->env, element, &valueType);
1165         if (valueType == napi_function) {
1166             napi_ref ref = nullptr;
1167             napi_create_reference(asyncCtx->env, element, 1, &ref);
1168             asyncCtx->customBuilderList.push_back(ref);
1169             isParseSucess = true;
1170             continue;
1171         }
1172         if (valueType != napi_object) {
1173             errMsg = "The type of first parameter is incorrect";
1174             isParseSucess = false;
1175             break;
1176         }
1177         if (!ParseExtraInfo(asyncCtx, errMsg, element)) {
1178             errMsg = "The type of first parameter is incorrect by extraInfo";
1179             isParseSucess = false;
1180             break;
1181         }
1182         if (!ParsePixelMapAndBuilder(asyncCtx, errMsg, element)) {
1183             errMsg = "The type of first parameter is incorrect by pixelMap or builder";
1184             isParseSucess = false;
1185             break;
1186         }
1187         isParseSucess = true;
1188         continue;
1189     }
1190     return isParseSucess;
1191 }
1192 
ParseDragParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)1193 bool ParseDragParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
1194 {
1195     CHECK_NULL_RETURN(asyncCtx, false);
1196     napi_valuetype valueType = napi_undefined;
1197     napi_typeof(asyncCtx->env, asyncCtx->argv[0], &valueType);
1198     if (valueType == napi_function) {
1199         asyncCtx->customBuilder = asyncCtx->argv[0];
1200         return true;
1201     }
1202     if (valueType != napi_object) {
1203         errMsg = "The type of first parameter is incorrect.";
1204         return false;
1205     }
1206 
1207     bool isArray = false;
1208     napi_is_array(asyncCtx->env, asyncCtx->argv[0], &isArray);
1209     if (isArray) {
1210         TAG_LOGI(AceLogTag::ACE_DRAG, "drag controller is multi object drag.");
1211         asyncCtx->isArray = true;
1212         return ParseDragItemListInfoParam(asyncCtx, errMsg);
1213     }
1214     asyncCtx->isArray = false;
1215     return ParseDragItemInfoParam(asyncCtx, errMsg);
1216 }
1217 
ApplyPreviewOptionsFromModifier(DragControllerAsyncCtx * asyncCtx,napi_value modifierObj,NG::DragPreviewOption & option)1218 bool ApplyPreviewOptionsFromModifier(
1219     DragControllerAsyncCtx* asyncCtx, napi_value modifierObj, NG::DragPreviewOption& option)
1220 {
1221     CHECK_NULL_RETURN(asyncCtx, false);
1222     napi_valuetype valueType = napi_undefined;
1223     napi_typeof(asyncCtx->env, modifierObj, &valueType);
1224     if (valueType == napi_undefined) {
1225         return true;
1226     }
1227     if (valueType != napi_object) {
1228         return false;
1229     }
1230 
1231     napi_value globalObj = nullptr;
1232     napi_get_global(asyncCtx->env, &globalObj);
1233     napi_value globalFunc = nullptr;
1234     napi_get_named_property(asyncCtx->env, globalObj, "applyImageModifierToNode", &globalFunc);
1235     napi_typeof(asyncCtx->env, globalFunc, &valueType);
1236     if (globalFunc == nullptr || valueType != napi_function) {
1237         return false;
1238     }
1239 
1240     auto applyOnNodeSync =
1241         [modifierObj, globalFunc, asyncCtx](WeakPtr<NG::FrameNode> frameNode) {
1242             // convert nodeptr to js value
1243             auto nodePtr = frameNode.Upgrade();
1244             const size_t size = 64; // fake size for gc
1245             napi_value nodeJsValue = nullptr;
1246             napi_create_external_with_size(
1247                 asyncCtx->env, static_cast<void*>(AceType::RawPtr(nodePtr)),
1248                 [](napi_env env, void* data, void* hint) {}, static_cast<void*>(AceType::RawPtr(nodePtr)),
1249                 &nodeJsValue, size);
1250             if (nodeJsValue == nullptr) {
1251                 return;
1252             }
1253             // apply modifier
1254             napi_value ret;
1255             napi_value params[2];
1256             params[0] = modifierObj;
1257             params[1] = nodeJsValue;
1258             napi_call_function(asyncCtx->env, nullptr, globalFunc, 2, params, &ret);
1259         };
1260 
1261     NG::DragDropFuncWrapper::UpdateDragPreviewOptionsFromModifier(applyOnNodeSync, option);
1262     return true;
1263 }
1264 
GetNamedPropertyModifier(DragControllerAsyncCtx * asyncCtx,napi_value previewOptionsNApi,std::string & errMsg)1265 bool GetNamedPropertyModifier(
1266     DragControllerAsyncCtx* asyncCtx, napi_value previewOptionsNApi, std::string& errMsg)
1267 {
1268     napi_value modifierObj = nullptr;
1269     napi_get_named_property(asyncCtx->env, previewOptionsNApi, "modifier", &modifierObj);
1270     if (!ApplyPreviewOptionsFromModifier(asyncCtx, modifierObj, asyncCtx->dragPreviewOption)) {
1271         errMsg = "apply modifier failed.";
1272         return false;
1273     }
1274     return true;
1275 }
1276 
SetDragPreviewOptionMode(DragControllerAsyncCtx * asyncCtx,napi_value & modeNApi,std::string & errMsg,bool & isAuto)1277 bool SetDragPreviewOptionMode(DragControllerAsyncCtx* asyncCtx, napi_value& modeNApi,
1278     std::string& errMsg, bool& isAuto)
1279 {
1280     napi_valuetype valueType = napi_undefined;
1281     napi_typeof(asyncCtx->env, modeNApi, &valueType);
1282     if (valueType == napi_undefined) {
1283         return true;
1284     } else if (valueType != napi_number) {
1285         errMsg = "mode type is wrong";
1286         return false;
1287     } else if (isAuto) {
1288         return true;
1289     }
1290 
1291     int32_t dragPreviewMode = 0;
1292     napi_get_value_int32(asyncCtx->env, modeNApi, &dragPreviewMode);
1293     auto mode = static_cast<NG::DragPreviewMode>(dragPreviewMode);
1294     switch (mode) {
1295         case NG::DragPreviewMode::AUTO:
1296             asyncCtx->dragPreviewOption.ResetDragPreviewMode();
1297             isAuto = true;
1298             break;
1299         case NG::DragPreviewMode::DISABLE_SCALE:
1300             asyncCtx->dragPreviewOption.isScaleEnabled = false;
1301             break;
1302         case NG::DragPreviewMode::ENABLE_DEFAULT_SHADOW:
1303             asyncCtx->dragPreviewOption.isDefaultShadowEnabled = true;
1304             break;
1305         case NG::DragPreviewMode::ENABLE_DEFAULT_RADIUS:
1306             asyncCtx->dragPreviewOption.isDefaultRadiusEnabled = true;
1307             break;
1308         default:
1309             break;
1310     }
1311     return true;
1312 }
1313 
ParseDragPreviewMode(DragControllerAsyncCtx * asyncCtx,napi_value & previewOptionsNApi,std::string & errMsg)1314 bool ParseDragPreviewMode(DragControllerAsyncCtx* asyncCtx, napi_value& previewOptionsNApi, std::string& errMsg)
1315 {
1316     napi_value modeNApi = nullptr;
1317     napi_get_named_property(asyncCtx->env, previewOptionsNApi, "mode", &modeNApi);
1318     bool isArray = false;
1319     bool isAuto = false;
1320     napi_is_array(asyncCtx->env, modeNApi, &isArray);
1321     if (isArray) {
1322         uint32_t arrayLength = 0;
1323         napi_get_array_length(asyncCtx->env, modeNApi, &arrayLength);
1324         for (size_t i = 0; i < arrayLength; i++) {
1325             bool hasElement = false;
1326             napi_has_element(asyncCtx->env, modeNApi, i, &hasElement);
1327             if (!hasElement) {
1328                 continue;
1329             }
1330             napi_value element = nullptr;
1331             napi_get_element(asyncCtx->env, modeNApi, i, &element);
1332             if (!SetDragPreviewOptionMode(asyncCtx, element, errMsg, isAuto)) {
1333                 return false;
1334             }
1335         }
1336     } else if (!SetDragPreviewOptionMode(asyncCtx, modeNApi, errMsg, isAuto)) {
1337         return false;
1338     }
1339     NG::DragDropFuncWrapper::UpdatePreviewOptionDefaultAttr(asyncCtx->dragPreviewOption);
1340     return true;
1341 }
1342 
GetCurrentDipScale(DragControllerAsyncCtx * asyncCtx)1343 void GetCurrentDipScale(DragControllerAsyncCtx* asyncCtx)
1344 {
1345     auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1346     CHECK_NULL_VOID(container);
1347     auto pipeline = container->GetPipelineContext();
1348     CHECK_NULL_VOID(pipeline);
1349     asyncCtx->dipScale = pipeline->GetDipScale();
1350 }
1351 
ParsePreviewOptions(DragControllerAsyncCtx * asyncCtx,napi_valuetype & valueType,std::string & errMsg)1352 bool ParsePreviewOptions(
1353     DragControllerAsyncCtx* asyncCtx, napi_valuetype& valueType, std::string& errMsg)
1354 {
1355     CHECK_NULL_RETURN(asyncCtx, false);
1356     napi_handle_scope scope = nullptr;
1357     napi_open_handle_scope(asyncCtx->env, &scope);
1358     asyncCtx->dragPreviewOption.isNumber = false;
1359     asyncCtx->dragPreviewOption.isShowBadge = true;
1360     napi_value previewOptionsNApi = nullptr;
1361     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "previewOptions", &previewOptionsNApi);
1362     napi_typeof(asyncCtx->env, previewOptionsNApi, &valueType);
1363     if (valueType == napi_object) {
1364         if (!ParseDragPreviewMode(asyncCtx, previewOptionsNApi, errMsg)) {
1365             napi_close_handle_scope(asyncCtx->env, scope);
1366             return false;
1367         }
1368 
1369         napi_value numberBadgeNApi = nullptr;
1370         napi_get_named_property(asyncCtx->env, previewOptionsNApi, "numberBadge", &numberBadgeNApi);
1371         napi_typeof(asyncCtx->env, numberBadgeNApi, &valueType);
1372         if (valueType == napi_number) {
1373             int64_t number = 0;
1374             napi_get_value_int64(asyncCtx->env, numberBadgeNApi, &number);
1375             if (number < 0 || number > INT_MAX) {
1376                 asyncCtx->dragPreviewOption.isNumber = false;
1377                 asyncCtx->dragPreviewOption.isShowBadge = true;
1378             } else {
1379                 asyncCtx->dragPreviewOption.isNumber = true;
1380                 asyncCtx->dragPreviewOption.isShowBadge = false;
1381                 asyncCtx->dragPreviewOption.badgeNumber = number;
1382             }
1383         } else if (valueType == napi_boolean) {
1384             asyncCtx->dragPreviewOption.isNumber = false;
1385             napi_get_value_bool(asyncCtx->env, numberBadgeNApi, &asyncCtx->dragPreviewOption.isShowBadge);
1386         } else if (valueType != napi_undefined) {
1387             errMsg = "numberBadge type is wrong.";
1388             napi_close_handle_scope(asyncCtx->env, scope);
1389             return false;
1390         }
1391 
1392         if (!(GetNamedPropertyModifier(asyncCtx, previewOptionsNApi, errMsg))) {
1393             napi_close_handle_scope(asyncCtx->env, scope);
1394             return false;
1395         }
1396     } else if (valueType != napi_undefined) {
1397         errMsg = "previewOptions type is wrong";
1398         napi_close_handle_scope(asyncCtx->env, scope);
1399         return false;
1400     }
1401     napi_close_handle_scope(asyncCtx->env, scope);
1402     return true;
1403 }
1404 
ParseDragInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)1405 bool ParseDragInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
1406 {
1407     CHECK_NULL_RETURN(asyncCtx, false);
1408     napi_valuetype valueType = napi_undefined;
1409     napi_typeof(asyncCtx->env, asyncCtx->argv[1], &valueType);
1410     if (valueType != napi_object) {
1411         errMsg = "The type of second parameter is incorrect.";
1412         return false;
1413     }
1414     napi_value pointerIdNApi = nullptr;
1415     napi_status status = napi_ok;
1416     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "pointerId", &pointerIdNApi);
1417     napi_typeof(asyncCtx->env, pointerIdNApi, &valueType);
1418     if (valueType != napi_number) {
1419         errMsg = "pointerId which type is number must be given";
1420         return false;
1421     }
1422     status = napi_get_value_int32(asyncCtx->env, pointerIdNApi, &asyncCtx->pointerId);
1423     if (status != napi_ok) {
1424         errMsg = "parse pointerId fail";
1425         return false;
1426     }
1427 
1428     napi_value dataNApi = nullptr;
1429     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "data", &dataNApi);
1430     napi_typeof(asyncCtx->env, dataNApi, &valueType);
1431     if (valueType == napi_object) {
1432         asyncCtx->unifiedData = UdmfClient::GetInstance()->TransformUnifiedData(dataNApi);
1433     } else if (valueType != napi_undefined) {
1434         errMsg = "data's type is wrong";
1435         return false;
1436     }
1437 
1438     napi_value extraParamsNApi = nullptr;
1439     napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "extraParams", &extraParamsNApi);
1440     napi_typeof(asyncCtx->env, extraParamsNApi, &valueType);
1441     if (valueType == napi_string) {
1442         GetNapiString(asyncCtx->env, extraParamsNApi, asyncCtx->extraParams, valueType);
1443     } else if (valueType != napi_undefined) {
1444         errMsg = "extraParams's type is wrong";
1445         return false;
1446     }
1447 
1448     if (!ParsePreviewOptions(asyncCtx, valueType, errMsg)) {
1449         return false;
1450     }
1451 
1452     GetCurrentDipScale(asyncCtx);
1453     asyncCtx->hasTouchPoint = ParseTouchPoint(asyncCtx, valueType);
1454     return true;
1455 }
1456 
CheckAndParseParams(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)1457 bool CheckAndParseParams(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
1458 {
1459     // Check the number of the argument
1460     CHECK_NULL_RETURN(asyncCtx, false);
1461     if ((asyncCtx->argc != 2) && (asyncCtx->argc != argCount3)) {
1462         errMsg = "The number of parameters must be 2 or 3.";
1463         return false;
1464     }
1465 
1466     // Check and parse the first parameter
1467     if (!ParseDragParam(asyncCtx, errMsg)) {
1468         return false;
1469     }
1470 
1471     // Check and parse the second parameter
1472     return ParseDragInfoParam(asyncCtx, errMsg);
1473 }
1474 
CreateCallback(DragControllerAsyncCtx * asyncCtx,napi_value * result)1475 void CreateCallback(DragControllerAsyncCtx* asyncCtx, napi_value* result)
1476 {
1477     CHECK_NULL_VOID(asyncCtx);
1478     if (asyncCtx->argc == argCount3) {
1479         // Create the JsCallback
1480         napi_create_reference(asyncCtx->env, asyncCtx->argv[2], 1, &asyncCtx->callbackRef);
1481     }
1482     if (!asyncCtx->callbackRef) {
1483         // Create the promise
1484         napi_create_promise(asyncCtx->env, &asyncCtx->deferred, result);
1485     } else {
1486         napi_get_undefined(asyncCtx->env, result);
1487     }
1488 }
1489 
InitializeDragControllerCtx(napi_env env,napi_callback_info info,DragControllerAsyncCtx * asyncCtx)1490 void InitializeDragControllerCtx(napi_env env, napi_callback_info info, DragControllerAsyncCtx* asyncCtx)
1491 {
1492     CHECK_NULL_VOID(asyncCtx);
1493     napi_value thisVar = nullptr;
1494     void* data = nullptr;
1495     asyncCtx->instanceId = Container::CurrentIdSafely();
1496     asyncCtx->env = env;
1497     // get arguments from JS
1498     napi_get_cb_info(asyncCtx->env, info, &(asyncCtx->argc), asyncCtx->argv, &thisVar, &data);
1499 }
1500 
getParameterType(DragControllerAsyncCtx * asyncCtx)1501 ParameterType getParameterType(DragControllerAsyncCtx* asyncCtx)
1502 {
1503     CHECK_NULL_RETURN(asyncCtx, ParameterType::ERROR);
1504     if (asyncCtx->pixelMap != nullptr) {
1505         return ParameterType::DRAGITEMINFO;
1506     }
1507     if (asyncCtx->customBuilder != nullptr) {
1508         return ParameterType::CUSTOMBUILDER;
1509     }
1510     if (!asyncCtx->pixelMapList.empty() && asyncCtx->customBuilderList.empty()) {
1511         return ParameterType::DRAGITEMINFO_ARRAY;
1512     }
1513     if (!asyncCtx->customBuilderList.empty() || !asyncCtx->pixelMapList.empty()) {
1514         return ParameterType::MIX;
1515     } else {
1516         return ParameterType::ERROR;
1517     }
1518 }
1519 
ConfirmCurPointerEventInfo(DragControllerAsyncCtx * asyncCtx,const RefPtr<Container> & container)1520 bool ConfirmCurPointerEventInfo(DragControllerAsyncCtx *asyncCtx, const RefPtr<Container>& container)
1521 {
1522     CHECK_NULL_RETURN(asyncCtx, false);
1523     CHECK_NULL_RETURN(container, false);
1524     StopDragCallback stopDragCallback = [asyncCtx, container]() {
1525         CHECK_NULL_VOID(asyncCtx);
1526         CHECK_NULL_VOID(container);
1527         bool needPostStopDrag = false;
1528         {
1529             std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
1530             needPostStopDrag = (asyncCtx->dragState == DragState::SENDING);
1531             asyncCtx->dragState = DragState::REJECT;
1532         }
1533         if (needPostStopDrag) {
1534             auto taskExecutor = container->GetTaskExecutor();
1535             CHECK_NULL_VOID(taskExecutor);
1536             auto windowId = container->GetWindowId();
1537             taskExecutor->PostTask(
1538                 [asyncCtx, windowId]() {
1539                     CHECK_NULL_VOID(asyncCtx);
1540                     napi_handle_scope scope = nullptr;
1541                     napi_open_handle_scope(asyncCtx->env, &scope);
1542                     HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "drag state error, stop drag.");
1543                     napi_close_handle_scope(asyncCtx->env, scope);
1544                     TAG_LOGI(AceLogTag::ACE_DRAG,
1545                         "drag state is reject, stop drag, windowId is %{public}d.", windowId);
1546                     Msdp::DeviceStatus::DragDropResult dropResult { Msdp::DeviceStatus::DragResult::DRAG_CANCEL, false,
1547                         windowId, Msdp::DeviceStatus::DragBehavior::UNKNOWN };
1548                     Msdp::DeviceStatus::InteractionManager::GetInstance()->StopDrag(dropResult);
1549                     Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(false);
1550                 },
1551                 TaskExecutor::TaskType::JS, "ArkUIDragStop");
1552         }
1553     };
1554     int32_t sourceTool = -1;
1555     bool getPointSuccess = container->GetCurPointerEventInfo(
1556         asyncCtx->pointerId, asyncCtx->globalX, asyncCtx->globalY, asyncCtx->sourceType,
1557         sourceTool, std::move(stopDragCallback));
1558     if (asyncCtx->sourceType == SOURCE_TYPE_MOUSE) {
1559         asyncCtx->pointerId = MOUSE_POINTER_ID;
1560     } else if (asyncCtx->sourceType == SOURCE_TYPE_TOUCH && sourceTool == SOURCE_TOOL_PEN) {
1561         asyncCtx->pointerId = PEN_POINTER_ID;
1562     }
1563     return getPointSuccess;
1564 }
1565 
CheckDragging(const RefPtr<Container> & container)1566 static bool CheckDragging(const RefPtr<Container>& container)
1567 {
1568     CHECK_NULL_RETURN(container, false);
1569     auto pipelineContext = container->GetPipelineContext();
1570     if (!pipelineContext || !pipelineContext->IsDragging()) {
1571         return false;
1572     }
1573     return true;
1574 }
1575 
JSExecuteDrag(napi_env env,napi_callback_info info)1576 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
1577 {
1578     napi_escapable_handle_scope scope = nullptr;
1579     napi_open_escapable_handle_scope(env, &scope);
1580 
1581     auto dragAsyncContext = new (std::nothrow) DragControllerAsyncCtx();
1582     if (dragAsyncContext == nullptr) {
1583         NapiThrow(env, "create drag controller async context failed.", ERROR_CODE_INTERNAL_ERROR);
1584         napi_close_escapable_handle_scope(env, scope);
1585         return nullptr;
1586     }
1587     InitializeDragControllerCtx(env, info, dragAsyncContext);
1588 
1589     std::string errMsg;
1590     if (!CheckAndParseParams(dragAsyncContext, errMsg)) {
1591         NapiThrow(env, errMsg, ERROR_CODE_PARAM_INVALID);
1592         napi_close_escapable_handle_scope(env, scope);
1593         delete dragAsyncContext;
1594         dragAsyncContext = nullptr;
1595         return nullptr;
1596     }
1597     napi_value result = nullptr;
1598     CreateCallback(dragAsyncContext, &result);
1599     auto container = AceEngine::Get().GetContainer(dragAsyncContext->instanceId);
1600     if (!container) {
1601         NapiThrow(env, "get container failed.", ERROR_CODE_INTERNAL_ERROR);
1602         napi_close_escapable_handle_scope(env, scope);
1603         delete dragAsyncContext;
1604         dragAsyncContext = nullptr;
1605         return nullptr;
1606     }
1607     if (CheckDragging(container)) {
1608         NapiThrow(env, "only one drag is allowed at the same time", ERROR_CODE_INTERNAL_ERROR);
1609         napi_escape_handle(env, scope, result, &result);
1610         delete dragAsyncContext;
1611         dragAsyncContext = nullptr;
1612         napi_close_escapable_handle_scope(env, scope);
1613         return nullptr;
1614     }
1615     auto getPointSuccess = ConfirmCurPointerEventInfo(dragAsyncContext, container);
1616     if (!getPointSuccess) {
1617         NapiThrow(env, "confirm current point info failed.", ERROR_CODE_INTERNAL_ERROR);
1618         napi_escape_handle(env, scope, result, &result);
1619         napi_close_escapable_handle_scope(env, scope);
1620         return result;
1621     }
1622     SetMouseDragMonitorState(dragAsyncContext, true);
1623     HandleExecuteDrag(env, dragAsyncContext);
1624     napi_escape_handle(env, scope, result, &result);
1625     napi_close_escapable_handle_scope(env, scope);
1626     return result;
1627 }
1628 
JSCreateDragAction(napi_env env,napi_callback_info info)1629 static napi_value JSCreateDragAction(napi_env env, napi_callback_info info)
1630 {
1631     napi_escapable_handle_scope scope = nullptr;
1632     napi_open_escapable_handle_scope(env, &scope);
1633 
1634     auto dragAsyncContext = new (std::nothrow) DragControllerAsyncCtx();
1635     if (dragAsyncContext == nullptr) {
1636         NapiThrow(env, "create drag controller async context failed.", ERROR_CODE_INTERNAL_ERROR);
1637         napi_close_escapable_handle_scope(env, scope);
1638         return nullptr;
1639     }
1640     InitializeDragControllerCtx(env, info, dragAsyncContext);
1641 
1642     std::string errMsg = "";
1643     if (!CheckAndParseParams(dragAsyncContext, errMsg)) {
1644         NapiThrow(env, errMsg, ERROR_CODE_PARAM_INVALID);
1645         napi_close_escapable_handle_scope(env, scope);
1646         return nullptr;
1647     }
1648 
1649     auto container = AceEngine::Get().GetContainer(dragAsyncContext->instanceId);
1650     if (!container) {
1651         NapiThrow(env, "get container failed.", ERROR_CODE_INTERNAL_ERROR);
1652         napi_close_escapable_handle_scope(env, scope);
1653         return nullptr;
1654     }
1655 
1656     if (CheckDragging(container)) {
1657         NapiThrow(env, "only one drag is allowed at the same time", ERROR_CODE_INTERNAL_ERROR);
1658         delete dragAsyncContext;
1659         dragAsyncContext = nullptr;
1660         napi_close_escapable_handle_scope(env, scope);
1661         return nullptr;
1662     }
1663 
1664     auto getPointSuccess = ConfirmCurPointerEventInfo(dragAsyncContext, container);
1665     if (!getPointSuccess) {
1666         NapiThrow(env, "confirm pointer info failed", ERROR_CODE_PARAM_INVALID);
1667         napi_close_escapable_handle_scope(env, scope);
1668         return nullptr;
1669     }
1670 
1671     napi_value result = nullptr;
1672     napi_create_object(env, &result);
1673     DragAction* dragAction = new (std::nothrow) DragAction(dragAsyncContext);
1674     dragAction->NapiSerializer(env, result);
1675     dragAsyncContext->dragAction = dragAction;
1676     napi_escape_handle(env, scope, result, &result);
1677     napi_close_escapable_handle_scope(env, scope);
1678     return result;
1679 }
1680 
JSGetDragPreview(napi_env env,napi_callback_info info)1681 static napi_value JSGetDragPreview(napi_env env, napi_callback_info info)
1682 {
1683     DragPreview* dragPreview = new DragPreview();
1684     napi_value result = nullptr;
1685     napi_create_object(env, &result);
1686     dragPreview->NapiSerializer(env, result);
1687     return result;
1688 }
1689 #else
1690 
JSGetDragPreview(napi_env env,napi_callback_info info)1691 static napi_value JSGetDragPreview(napi_env env, napi_callback_info info)
1692 {
1693     napi_escapable_handle_scope scope = nullptr;
1694     napi_open_escapable_handle_scope(env, &scope);
1695     NapiThrow(env, "The current environment does not enable drag framework or does not support drag preview.",
1696         ERROR_CODE_INTERNAL_ERROR);
1697     napi_close_escapable_handle_scope(env, scope);
1698     return nullptr;
1699 }
1700 
JSExecuteDrag(napi_env env,napi_callback_info info)1701 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
1702 {
1703     napi_escapable_handle_scope scope = nullptr;
1704     napi_open_escapable_handle_scope(env, &scope);
1705     NapiThrow(env, "The current environment does not enable drag framework or does not support pixelMap.",
1706         ERROR_CODE_INTERNAL_ERROR);
1707     napi_close_escapable_handle_scope(env, scope);
1708     return nullptr;
1709 }
1710 
JSCreateDragAction(napi_env env,napi_callback_info info)1711 static napi_value JSCreateDragAction(napi_env env, napi_callback_info info)
1712 {
1713     napi_escapable_handle_scope scope = nullptr;
1714     napi_open_escapable_handle_scope(env, &scope);
1715     NapiThrow(env, "The current environment does not enable drag framework or does not support pixelMap.",
1716         ERROR_CODE_INTERNAL_ERROR);
1717     napi_close_escapable_handle_scope(env, scope);
1718     return nullptr;
1719 }
1720 #endif
1721 
1722 // The default empty implementation function setForegroundColor for dragPreview.
JsDragPreviewSetForegroundColor(napi_env env,napi_callback_info info)1723 static napi_value JsDragPreviewSetForegroundColor(napi_env env, napi_callback_info info)
1724 {
1725     return nullptr;
1726 }
1727 
1728 // The default empty implementation function animate for dragPreview.
JsDragPreviewAnimate(napi_env env,napi_callback_info info)1729 static napi_value JsDragPreviewAnimate(napi_env env, napi_callback_info info)
1730 {
1731     return nullptr;
1732 }
1733 
1734 // The default empty constructor for dragPreview.
DragPreviewConstructor(napi_env env,napi_callback_info info)1735 static napi_value DragPreviewConstructor(napi_env env, napi_callback_info info)
1736 {
1737     napi_value thisArg = nullptr;
1738     void* data = nullptr;
1739     napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
1740     napi_value global = nullptr;
1741     napi_get_global(env, &global);
1742     return thisArg;
1743 }
1744 
DragControllerExport(napi_env env,napi_value exports)1745 static napi_value DragControllerExport(napi_env env, napi_value exports)
1746 {
1747     napi_value dragStatus = nullptr;
1748     napi_create_object(env, &dragStatus);
1749     napi_value prop = nullptr;
1750     napi_create_uint32(env, DRAG_STARTED, &prop);
1751     napi_set_named_property(env, dragStatus, "STARTED", prop);
1752     napi_create_uint32(env, DRAG_ENDED, &prop);
1753     napi_set_named_property(env, dragStatus, "ENDED", prop);
1754 
1755     napi_property_descriptor dragPreviewDesc[] = {
1756         DECLARE_NAPI_FUNCTION("setForegroundColor", JsDragPreviewSetForegroundColor),
1757         DECLARE_NAPI_FUNCTION("animate", JsDragPreviewAnimate),
1758     };
1759     napi_value classDragPreview = nullptr;
1760     napi_define_class(env, "DragPreview", NAPI_AUTO_LENGTH, DragPreviewConstructor, nullptr,
1761         sizeof(dragPreviewDesc) / sizeof(*dragPreviewDesc), dragPreviewDesc, &classDragPreview);
1762 
1763     napi_property_descriptor dragControllerDesc[] = {
1764         DECLARE_NAPI_FUNCTION("executeDrag", JSExecuteDrag),
1765         DECLARE_NAPI_FUNCTION("getDragPreview", JSGetDragPreview),
1766         DECLARE_NAPI_FUNCTION("createDragAction", JSCreateDragAction),
1767         DECLARE_NAPI_PROPERTY("DragStatus", dragStatus),
1768         DECLARE_NAPI_PROPERTY("DragPreview", classDragPreview),
1769     };
1770     NAPI_CALL(env, napi_define_properties(
1771         env, exports, sizeof(dragControllerDesc) / sizeof(dragControllerDesc[0]), dragControllerDesc));
1772     return exports;
1773 }
1774 
1775 static napi_module dragControllerModule = {
1776     .nm_version = 1,
1777     .nm_flags = 0,
1778     .nm_filename = nullptr,
1779     .nm_register_func = DragControllerExport,
1780     .nm_modname = "arkui.dragController",
1781     .nm_priv = ((void*)0),
1782     .reserved = { 0 },
1783 };
1784 
DragControllerRegister()1785 extern "C" __attribute__((constructor)) void DragControllerRegister()
1786 {
1787     napi_module_register(&dragControllerModule);
1788 }
1789 } // namespace OHOS::Ace::Napi
1790