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