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