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