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