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 "js_component_snapshot.h"
17
18 #include "interfaces/napi/kits/utils/napi_utils.h"
19 #ifdef PIXEL_MAP_SUPPORTED
20 #include "pixel_map.h"
21 #include "pixel_map_napi.h"
22 #endif
23
24 #include "core/common/ace_engine.h"
25
26 #include "frameworks/bridge/common/utils/engine_helper.h"
27
28 namespace OHOS::Ace::Napi {
29 namespace {
30
31 struct SnapshotAsyncCtx {
32 napi_env env = nullptr;
33 napi_deferred deferred = nullptr;
34 napi_ref callbackRef = nullptr;
35 std::shared_ptr<Media::PixelMap> pixmap = nullptr;
36 int32_t errCode = -1;
37 int32_t instanceId = -1;
38 };
39 constexpr int32_t GETWITHRANGE_ISSTARTRECT_NUMBER = 2;
40 constexpr int32_t GETWITHRANGE_ARGV_VALUE = 4;
41 constexpr int32_t GETWITHRANGE_OPTIONS_NUMBER = 3;
42
OnComplete(SnapshotAsyncCtx * asyncCtx,std::function<void ()> finishCallback)43 void OnComplete(SnapshotAsyncCtx* asyncCtx, std::function<void()> finishCallback)
44 {
45 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
46 if (!container) {
47 LOGW("container is null. %{public}d", asyncCtx->instanceId);
48 return;
49 }
50
51 auto taskExecutor = container->GetTaskExecutor();
52 if (!taskExecutor) {
53 LOGW("taskExecutor is null.");
54 return;
55 }
56 taskExecutor->PostTask(
57 [asyncCtx, finishCallback]() {
58 std::unique_ptr<SnapshotAsyncCtx> ctx(asyncCtx);
59 napi_handle_scope scope = nullptr;
60 napi_open_handle_scope(ctx->env, &scope);
61
62 // callback result format: [Error, PixelMap]
63 napi_value result[2] = { nullptr };
64 napi_get_undefined(ctx->env, &result[0]);
65 napi_get_undefined(ctx->env, &result[1]);
66
67 if (ctx->errCode == ERROR_CODE_NO_ERROR) {
68 #ifdef PIXEL_MAP_SUPPORTED
69 // convert pixelMap to napi value
70 result[1] = Media::PixelMapNapi::CreatePixelMap(ctx->env, ctx->pixmap);
71 #endif
72 }
73 napi_create_int32(ctx->env, ctx->errCode, &result[0]);
74
75 if (ctx->deferred) {
76 // promise
77 if (ctx->errCode == ERROR_CODE_NO_ERROR) {
78 napi_resolve_deferred(ctx->env, ctx->deferred, result[1]);
79 } else {
80 napi_reject_deferred(ctx->env, ctx->deferred, result[0]);
81 }
82 } else {
83 // callback
84 napi_value ret = nullptr;
85 napi_value napiCallback = nullptr;
86 napi_get_reference_value(ctx->env, ctx->callbackRef, &napiCallback);
87 napi_call_function(ctx->env, nullptr, napiCallback, 2, result, &ret);
88 napi_delete_reference(ctx->env, ctx->callbackRef);
89 }
90
91 napi_close_handle_scope(ctx->env, scope);
92 if (finishCallback) {
93 finishCallback();
94 }
95 },
96 TaskExecutor::TaskType::JS, "ArkUIComponentSnapshotComplete");
97 }
98 } // namespace
99
JsComponentSnapshot(napi_env env,napi_callback_info info)100 JsComponentSnapshot::JsComponentSnapshot(napi_env env, napi_callback_info info) : env_(env), argc_(ARGC_MAX)
101 {
102 napi_value thisVar = nullptr;
103 void* data = nullptr;
104
105 // get arguments from JS
106 napi_get_cb_info(env, info, &argc_, argv_, &thisVar, &data);
107 }
108
CheckArgs(napi_valuetype firstArgType)109 bool JsComponentSnapshot::CheckArgs(napi_valuetype firstArgType)
110
111 {
112 size_t minArgc = 1;
113 std::string errorMsg;
114 if (argc_ < minArgc) {
115 errorMsg = "The number of parameters must be greater than or equal to 1.";
116 LOGE("%{public}s", errorMsg.c_str());
117 NapiThrow(env_, errorMsg, ERROR_CODE_PARAM_INVALID);
118
119 return false;
120 }
121 if (argc_ > ARGC_MAX) {
122 errorMsg = "The largest number of parameters is 2.";
123 LOGE("%{public}s", errorMsg.c_str());
124 NapiThrow(env_, errorMsg, ERROR_CODE_PARAM_INVALID);
125 return false;
126 }
127 napi_valuetype type = napi_undefined;
128 napi_typeof(env_, argv_[0], &type);
129 if (type != firstArgType) {
130 errorMsg = "parameter id is not of type string";
131 LOGE("%{public}s", errorMsg.c_str());
132 NapiThrow(env_, errorMsg, ERROR_CODE_PARAM_INVALID);
133 return false;
134 }
135 return true;
136 }
137
CreateCallback(napi_value * result)138 auto JsComponentSnapshot::CreateCallback(napi_value* result)
139 {
140 auto* asyncCtx = new SnapshotAsyncCtx;
141 napi_valuetype type = napi_undefined;
142 // parse JsCallback
143 if (argc_ >= 2) {
144 napi_typeof(env_, argv_[1], &type);
145 if (type == napi_function) {
146 napi_create_reference(env_, argv_[1], 1, &asyncCtx->callbackRef);
147 }
148 }
149 // init promise
150 if (!asyncCtx->callbackRef) {
151 napi_create_promise(env_, &asyncCtx->deferred, result);
152 } else {
153 napi_get_undefined(env_, result);
154 }
155
156 asyncCtx->env = env_;
157 asyncCtx->instanceId = Container::CurrentIdSafely();
158
159 return [asyncCtx](std::shared_ptr<Media::PixelMap> pixmap, int32_t errCode, std::function<void()> finishCallback) {
160 asyncCtx->pixmap = std::move(pixmap);
161 asyncCtx->errCode = errCode;
162 OnComplete(asyncCtx, finishCallback);
163 };
164 }
165
GetArgv(int32_t idx)166 napi_value JsComponentSnapshot::GetArgv(int32_t idx)
167 {
168 if (idx >= ARGC_MAX) {
169 return nullptr;
170 }
171 return argv_[idx];
172 }
173
ParseParamForBuilder(NG::SnapshotParam & param)174 void JsComponentSnapshot::ParseParamForBuilder(NG::SnapshotParam& param)
175 {
176 // parse second param for builder interface
177 if (argc_ >= 2) {
178 napi_valuetype type = napi_undefined;
179 napi_typeof(env_, argv_[1], &type);
180 if (type != napi_function) {
181 ParseParam(1, param);
182 }
183 }
184 // parse third param for builder interface
185 if (argc_ >= 3) {
186 ParseParam(2, param);
187 }
188 // parse fourth param for builder interface
189 if (argc_ >= 4) {
190 ParseParam(3, param);
191 }
192 // parse fifth param for builder interface
193 if (argc_ == 5) {
194 ParseParam(4, param);
195 }
196 }
197
ParseParamForGet(NG::SnapshotOptions & options)198 void JsComponentSnapshot::ParseParamForGet(NG::SnapshotOptions& options)
199 {
200 // parse options param for Promise
201 if (argc_ >= 2) {
202 napi_valuetype type = napi_undefined;
203 napi_typeof(env_, argv_[1], &type);
204 if (type != napi_function) {
205 ParseOptions(1, options);
206 }
207 }
208 // parse options param for Callback
209 if (argc_ == 3) {
210 ParseOptions(2, options);
211 }
212 if (argc_ == GETWITHRANGE_ARGV_VALUE) {
213 ParseOptions(GETWITHRANGE_OPTIONS_NUMBER, options);
214 }
215 }
216
ParseParam(int32_t idx,NG::SnapshotParam & param)217 void JsComponentSnapshot::ParseParam(int32_t idx, NG::SnapshotParam& param)
218 {
219 if (static_cast<int32_t>(argc_) <= idx) {
220 return;
221 }
222 napi_valuetype type = napi_undefined;
223 napi_typeof(env_, argv_[idx], &type);
224 // parse delay param
225 if (type == napi_number) {
226 int32_t delayTime = 0;
227 napi_get_value_int32(env_, argv_[idx], &delayTime);
228 if (delayTime >= 0) {
229 param.delay = delayTime;
230 }
231 }
232 // parse checkImageStatus param
233 if (type == napi_boolean) {
234 bool checkImageStatus = 0;
235 napi_get_value_bool(env_, argv_[idx], &checkImageStatus);
236 param.checkImageStatus = checkImageStatus;
237 }
238 // parse SnapshotOptions param
239 if (type == napi_object) {
240 NG::SnapshotOptions options;
241 ParseOptions(idx, options);
242 param.options = options;
243 }
244 }
245
ParseOptions(int32_t idx,NG::SnapshotOptions & options)246 void JsComponentSnapshot::ParseOptions(int32_t idx, NG::SnapshotOptions& options)
247 {
248 if (static_cast<int32_t>(argc_) <= idx) {
249 return;
250 }
251 napi_valuetype type = napi_undefined;
252 napi_typeof(env_, argv_[idx], &type);
253 if (type != napi_object) {
254 return;
255 }
256
257 bool result = false;
258 napi_has_named_property(env_, argv_[idx], "scale", &result);
259 if (result) {
260 napi_value scaleNapi = nullptr;
261 napi_get_named_property(env_, argv_[idx], "scale", &scaleNapi);
262 double scale = 0.0;
263 napi_get_value_double(env_, scaleNapi, &scale);
264 if (GreatNotEqual(scale, 0.0)) {
265 options.scale = static_cast<float>(scale);
266 }
267 }
268
269 result = false;
270 napi_has_named_property(env_, argv_[idx], "waitUntilRenderFinished", &result);
271 if (result) {
272 napi_value waitUntilRenderFinishedNapi = nullptr;
273 napi_get_named_property(env_, argv_[idx], "waitUntilRenderFinished", &waitUntilRenderFinishedNapi);
274 bool waitUntilRenderFinished = false;
275 napi_get_value_bool(env_, waitUntilRenderFinishedNapi, &waitUntilRenderFinished);
276 options.waitUntilRenderFinished = waitUntilRenderFinished;
277 }
278
279 result = false;
280 napi_has_named_property(env_, argv_[idx], "region", &result);
281 if (!result) {
282 options.regionMode = NG::SnapshotRegionMode::NO_REGION;
283 return;
284 }
285 napi_value regionObject = nullptr;
286 napi_get_named_property(env_, argv_[idx], "region", ®ionObject);
287 if (!regionObject) {
288 options.regionMode = NG::SnapshotRegionMode::NO_REGION;
289 return;
290 }
291
292 options.regionMode = NG::SnapshotRegionMode::COMMON;
293 if (ParseLocalizedRegion(®ionObject, options)) {
294 options.regionMode = NG::SnapshotRegionMode::LOCALIZED;
295 } else {
296 ParseRegion(®ionObject, options);
297 }
298 }
299
ParseRegion(napi_value * regionObject,NG::SnapshotOptions & options)300 bool JsComponentSnapshot::ParseRegion(napi_value* regionObject, NG::SnapshotOptions& options)
301 {
302 bool getReigonResult = false;
303 options.snapshotRegion = NG::LocalizedSnapshotRegion {};
304 napi_has_named_property(env_, *regionObject, "left", &getReigonResult);
305 if (!getReigonResult) {
306 LOGE("The \"left\" attribute cannot be obtained from the parameter.");
307 return false;
308 }
309 napi_value leftPxNapi;
310 napi_get_named_property(env_, *regionObject, "left", &leftPxNapi);
311 napi_get_value_double(env_, leftPxNapi, &options.snapshotRegion.start);
312
313 napi_has_named_property(env_, *regionObject, "right", &getReigonResult);
314 if (!getReigonResult) {
315 LOGE("The \"right\" attribute cannot be obtained from the parameter.");
316 return false;
317 }
318 napi_value rightPxNapi;
319 napi_get_named_property(env_, *regionObject, "right", &rightPxNapi);
320 napi_get_value_double(env_, rightPxNapi, &options.snapshotRegion.end);
321
322 napi_has_named_property(env_, *regionObject, "top", &getReigonResult);
323 if (!getReigonResult) {
324 LOGE("The \"top\" attribute cannot be obtained from the parameter.");
325 return false;
326 }
327 napi_value topPxNapi;
328 napi_get_named_property(env_, *regionObject, "top", &topPxNapi);
329 napi_get_value_double(env_, topPxNapi, &options.snapshotRegion.top);
330
331 napi_has_named_property(env_, *regionObject, "bottom", &getReigonResult);
332 if (!getReigonResult) {
333 LOGE("The \"bottom\" attribute cannot be obtained from the parameter.");
334 return false;
335 }
336 napi_value bottomPxNapi;
337 napi_get_named_property(env_, *regionObject, "bottom", &bottomPxNapi);
338 napi_get_value_double(env_, bottomPxNapi, &options.snapshotRegion.bottom);
339 return true;
340 }
341
ParseLocalizedRegion(napi_value * regionObject,NG::SnapshotOptions & options)342 bool JsComponentSnapshot::ParseLocalizedRegion(napi_value* regionObject, NG::SnapshotOptions& options)
343 {
344 options.snapshotRegion = NG::LocalizedSnapshotRegion {};
345 bool getReigonResult = false;
346 napi_has_named_property(env_, *regionObject, "start", &getReigonResult);
347 if (!getReigonResult) {
348 LOGE("The \"start\" attribute cannot be obtained from the parameter.");
349 return false;
350 }
351 napi_value startPxNapi;
352 napi_get_named_property(env_, *regionObject, "start", &startPxNapi);
353 napi_get_value_double(env_, startPxNapi, &options.snapshotRegion.start);
354
355 napi_has_named_property(env_, *regionObject, "end", &getReigonResult);
356 if (!getReigonResult) {
357 LOGE("The \"end\" attribute cannot be obtained from the parameter.");
358 return false;
359 }
360 napi_value endPxNapi;
361 napi_get_named_property(env_, *regionObject, "end", &endPxNapi);
362 napi_get_value_double(env_, endPxNapi, &options.snapshotRegion.end);
363
364 napi_has_named_property(env_, *regionObject, "top", &getReigonResult);
365 if (!getReigonResult) {
366 LOGE("The \"top\" attribute cannot be obtained from the parameter.");
367 return false;
368 }
369 napi_value topPxNapi;
370 napi_get_named_property(env_, *regionObject, "top", &topPxNapi);
371 napi_get_value_double(env_, topPxNapi, &options.snapshotRegion.top);
372
373 napi_has_named_property(env_, *regionObject, "bottom", &getReigonResult);
374 if (!getReigonResult) {
375 LOGE("The \"bottom\" attribute cannot be obtained from the parameter.");
376 return false;
377 }
378 napi_value bottomPxNapi;
379 napi_get_named_property(env_, *regionObject, "bottom", &bottomPxNapi);
380 napi_get_value_double(env_, bottomPxNapi, &options.snapshotRegion.bottom);
381 return true;
382 }
383
JSSnapshotGet(napi_env env,napi_callback_info info)384 static napi_value JSSnapshotGet(napi_env env, napi_callback_info info)
385 {
386 napi_escapable_handle_scope scope = nullptr;
387 napi_open_escapable_handle_scope(env, &scope);
388
389 JsComponentSnapshot helper(env, info);
390
391 napi_value result = nullptr;
392
393 if (!helper.CheckArgs(napi_valuetype::napi_string)) {
394 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of string type.");
395 napi_close_escapable_handle_scope(env, scope);
396 return result;
397 }
398
399 // parse id
400 std::string componentId;
401 napi_valuetype valueType = napi_null;
402 GetNapiString(env, helper.GetArgv(0), componentId, valueType);
403
404 auto delegate = EngineHelper::GetCurrentDelegateSafely();
405 if (!delegate) {
406 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
407 "Can't get delegate of ace_engine. param: " SEC_PLD(%{public}s),
408 SEC_PARAM(componentId.c_str()));
409 auto callback = helper.CreateCallback(&result);
410 callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
411 napi_close_escapable_handle_scope(env, scope);
412 return result;
413 }
414
415 NG::SnapshotOptions options;
416 helper.ParseParamForGet(options);
417
418 delegate->GetSnapshot(componentId, helper.CreateCallback(&result), options);
419
420 napi_escape_handle(env, scope, result, &result);
421 napi_close_escapable_handle_scope(env, scope);
422 return result;
423 }
424
JSSnapshotFromBuilder(napi_env env,napi_callback_info info)425 static napi_value JSSnapshotFromBuilder(napi_env env, napi_callback_info info)
426 {
427 napi_escapable_handle_scope scope = nullptr;
428 napi_open_escapable_handle_scope(env, &scope);
429
430 JsComponentSnapshot helper(env, info);
431 if (!helper.CheckArgs(napi_valuetype::napi_function)) {
432 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of function type.");
433 napi_close_escapable_handle_scope(env, scope);
434 return nullptr;
435 }
436
437 napi_value result = nullptr;
438 auto delegate = EngineHelper::GetCurrentDelegateSafely();
439 if (!delegate) {
440 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Can't get delegate of ace_engine. ");
441 auto callback = helper.CreateCallback(&result);
442 callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
443 napi_close_escapable_handle_scope(env, scope);
444 return nullptr;
445 }
446
447 // create builder closure
448 auto builder = [build = helper.GetArgv(0), env] { napi_call_function(env, nullptr, build, 0, nullptr, nullptr); };
449
450 NG::SnapshotParam param;
451 helper.ParseParamForBuilder(param);
452
453 delegate->CreateSnapshot(builder, helper.CreateCallback(&result), true, param);
454
455 napi_escape_handle(env, scope, result, &result);
456 napi_close_escapable_handle_scope(env, scope);
457 return result;
458 }
459
JSSnapshotGetSync(napi_env env,napi_callback_info info)460 static napi_value JSSnapshotGetSync(napi_env env, napi_callback_info info)
461 {
462 napi_escapable_handle_scope scope = nullptr;
463 napi_open_escapable_handle_scope(env, &scope);
464
465 JsComponentSnapshot helper(env, info);
466
467 napi_value result = nullptr;
468
469 if (!helper.CheckArgs(napi_valuetype::napi_string)) {
470 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of string type.");
471 napi_close_escapable_handle_scope(env, scope);
472 return result;
473 }
474
475 // parse id
476 std::string componentId;
477 napi_valuetype valueType = napi_null;
478 GetNapiString(env, helper.GetArgv(0), componentId, valueType);
479
480 auto delegate = EngineHelper::GetCurrentDelegateSafely();
481 if (!delegate) {
482 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
483 "Can't get delegate of ace_engine. param: " SEC_PLD(%{public}s),
484 SEC_PARAM(componentId.c_str()));
485 NapiThrow(env, "Delegate is null", ERROR_CODE_INTERNAL_ERROR);
486 napi_close_escapable_handle_scope(env, scope);
487 return result;
488 }
489
490 NG::SnapshotOptions options;
491 helper.ParseParamForGet(options);
492
493 auto pair = delegate->GetSyncSnapshot(componentId, options);
494
495 switch (pair.first) {
496 case ERROR_CODE_NO_ERROR :
497 #ifdef PIXEL_MAP_SUPPORTED
498 result = Media::PixelMapNapi::CreatePixelMap(env, pair.second);
499 #endif
500 break;
501 case ERROR_CODE_INTERNAL_ERROR :
502 napi_get_null(env, &result);
503 NapiThrow(env, "Internal error!", ERROR_CODE_INTERNAL_ERROR);
504 break;
505 case ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT :
506 napi_get_null(env, &result);
507 NapiThrow(env, "ComponentSnapshot timeout!", ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT);
508 break;
509 case ERROR_CODE_PARAM_INVALID :
510 napi_get_null(env, &result);
511 NapiThrow(env, "Snapshot region is invalid or out of range!", ERROR_CODE_PARAM_INVALID);
512 break;
513 }
514 napi_escape_handle(env, scope, result, &result);
515 napi_close_escapable_handle_scope(env, scope);
516 return result;
517 }
518
JSSnapshotGetWithUniqueId(napi_env env,napi_callback_info info)519 static napi_value JSSnapshotGetWithUniqueId(napi_env env, napi_callback_info info)
520 {
521 napi_escapable_handle_scope scope = nullptr;
522 napi_open_escapable_handle_scope(env, &scope);
523
524 JsComponentSnapshot helper(env, info);
525
526 napi_value result = nullptr;
527
528 napi_valuetype type = napi_undefined;
529 napi_typeof(env, helper.GetArgv(0), &type);
530 if (type != napi_valuetype::napi_number) {
531 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of number type.");
532 NapiThrow(env, "parameter uniqueId is not of type number", ERROR_CODE_PARAM_INVALID);
533 napi_close_escapable_handle_scope(env, scope);
534 return result;
535 }
536 // parse uniqueId
537 int32_t uniqueId;
538 napi_get_value_int32(env, helper.GetArgv(0), &uniqueId);
539
540 auto delegate = EngineHelper::GetCurrentDelegateSafely();
541 if (!delegate) {
542 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
543 "Can't get delegate of ace_engine. param: %{public}d",
544 uniqueId);
545 auto callback = helper.CreateCallback(&result);
546 callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
547 napi_close_escapable_handle_scope(env, scope);
548 return result;
549 }
550
551 NG::SnapshotOptions options;
552 helper.ParseParamForGet(options);
553
554 delegate->GetSnapshotByUniqueId(uniqueId, helper.CreateCallback(&result), options);
555
556 napi_escape_handle(env, scope, result, &result);
557 napi_close_escapable_handle_scope(env, scope);
558 return result;
559 }
560
JSSnapshotGetSyncWithUniqueId(napi_env env,napi_callback_info info)561 static napi_value JSSnapshotGetSyncWithUniqueId(napi_env env, napi_callback_info info)
562 {
563 napi_escapable_handle_scope scope = nullptr;
564 napi_open_escapable_handle_scope(env, &scope);
565
566 JsComponentSnapshot helper(env, info);
567
568 napi_value result = nullptr;
569
570 napi_valuetype type = napi_undefined;
571 napi_typeof(env, helper.GetArgv(0), &type);
572 if (type != napi_valuetype::napi_number) {
573 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of number type.");
574 NapiThrow(env, "parameter uniqueId is not of type number", ERROR_CODE_PARAM_INVALID);
575 napi_close_escapable_handle_scope(env, scope);
576 return result;
577 }
578 // parse uniqueId
579 int32_t uniqueId;
580 napi_get_value_int32(env, helper.GetArgv(0), &uniqueId);
581
582 auto delegate = EngineHelper::GetCurrentDelegateSafely();
583 if (!delegate) {
584 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
585 "Can't get delegate of ace_engine. param: %{public}d", uniqueId);
586 NapiThrow(env, "Delegate is null", ERROR_CODE_INTERNAL_ERROR);
587 napi_close_escapable_handle_scope(env, scope);
588 return result;
589 }
590
591 NG::SnapshotOptions options;
592 helper.ParseParamForGet(options);
593
594 auto pair = delegate->GetSyncSnapshotByUniqueId(uniqueId, options);
595
596 switch (pair.first) {
597 case ERROR_CODE_NO_ERROR :
598 #ifdef PIXEL_MAP_SUPPORTED
599 result = Media::PixelMapNapi::CreatePixelMap(env, pair.second);
600 #endif
601 break;
602 case ERROR_CODE_INTERNAL_ERROR :
603 napi_get_null(env, &result);
604 NapiThrow(env, "Internal error!", ERROR_CODE_INTERNAL_ERROR);
605 break;
606 case ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT :
607 napi_get_null(env, &result);
608 NapiThrow(env, "ComponentSnapshot timeout!", ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT);
609 break;
610 case ERROR_CODE_PARAM_INVALID :
611 napi_get_null(env, &result);
612 NapiThrow(env, "Snapshot region is invalid or out of range!", ERROR_CODE_PARAM_INVALID);
613 break;
614 }
615 napi_escape_handle(env, scope, result, &result);
616 napi_close_escapable_handle_scope(env, scope);
617 return result;
618 }
619
JSSnapshotFromComponent(napi_env env,napi_callback_info info)620 static napi_value JSSnapshotFromComponent(napi_env env, napi_callback_info info)
621 {
622 napi_escapable_handle_scope scope = nullptr;
623 napi_open_escapable_handle_scope(env, &scope);
624
625 JsComponentSnapshot helper(env, info);
626 if (!helper.CheckArgs(napi_valuetype::napi_object)) {
627 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of object type.");
628 napi_close_escapable_handle_scope(env, scope);
629 return nullptr;
630 }
631
632 napi_value result = nullptr;
633 auto delegate = EngineHelper::GetCurrentDelegateSafely();
634 if (!delegate) {
635 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Can't get delegate of ace_engine. ");
636 NapiThrow(env, "Delegate is null", ERROR_CODE_INTERNAL_ERROR);
637 napi_close_escapable_handle_scope(env, scope);
638 return nullptr;
639 }
640
641 napi_value frameNodePtr = nullptr;
642 auto componentResult = napi_get_named_property(env, helper.GetArgv(0), "nodePtr_", &frameNodePtr);
643 if (componentResult != napi_ok) {
644 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
645 napi_close_escapable_handle_scope(env, scope);
646 return nullptr;
647 }
648 void* nativePtr = nullptr;
649 componentResult = napi_get_value_external(env, frameNodePtr, &nativePtr);
650 if (componentResult != napi_ok) {
651 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
652 napi_close_escapable_handle_scope(env, scope);
653 return nullptr;
654 }
655 if (!nativePtr) {
656 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
657 napi_close_escapable_handle_scope(env, scope);
658 return nullptr;
659 }
660 WeakPtr<NG::UINode> nodeWk;
661 auto* uiNodePtr = reinterpret_cast<OHOS::Ace::NG::UINode*>(nativePtr);
662 nodeWk = AceType::WeakClaim(uiNodePtr);
663
664 NG::SnapshotParam param;
665 helper.ParseParamForBuilder(param);
666
667 delegate->CreateSnapshotFromComponent(nodeWk.Upgrade(), helper.CreateCallback(&result), false, param);
668
669 napi_escape_handle(env, scope, result, &result);
670 napi_close_escapable_handle_scope(env, scope);
671 return result;
672 }
673
JudgeRangeType(napi_env env,napi_callback_info info,int32_t argNum)674 bool JudgeRangeType(napi_env env, napi_callback_info info, int32_t argNum)
675 {
676 napi_escapable_handle_scope scope = nullptr;
677 napi_open_escapable_handle_scope(env, &scope);
678
679 JsComponentSnapshot helper(env, info);
680
681 napi_valuetype type = napi_undefined;
682 napi_value argv = helper.GetArgv(argNum);
683 if (argv == nullptr) {
684 napi_close_escapable_handle_scope(env, scope);
685 return false;
686 }
687 napi_typeof(env, argv, &type);
688 if (type != napi_valuetype::napi_number && type != napi_valuetype::napi_string) {
689 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing argument failed, not of number or string type.");
690 NapiThrow(env, "parameter uniqueId is not of type number or string", ERROR_CODE_PARAM_INVALID);
691 napi_close_escapable_handle_scope(env, scope);
692 return false;
693 }
694 napi_close_escapable_handle_scope(env, scope);
695 return true;
696 }
697
JudgeRectValue(napi_env env,napi_callback_info info)698 bool JudgeRectValue(napi_env env, napi_callback_info info)
699 {
700 napi_escapable_handle_scope scope = nullptr;
701 napi_open_escapable_handle_scope(env, &scope);
702
703 JsComponentSnapshot helper(env, info);
704
705 napi_valuetype type = napi_undefined;
706 napi_value argv = helper.GetArgv(GETWITHRANGE_ISSTARTRECT_NUMBER);
707 if (argv == nullptr) {
708 napi_close_escapable_handle_scope(env, scope);
709 return true;
710 }
711 napi_typeof(env, argv, &type);
712 bool isRect = true;
713 if (type == napi_valuetype::napi_boolean) {
714 napi_get_value_bool(env, argv, &isRect);
715 }
716 napi_close_escapable_handle_scope(env, scope);
717 return isRect;
718 }
719
GetNodeIdentity(napi_env env,napi_callback_info info,int32_t index)720 NG::NodeIdentity GetNodeIdentity(napi_env env, napi_callback_info info, int32_t index)
721 {
722 napi_escapable_handle_scope scope = nullptr;
723 napi_open_escapable_handle_scope(env, &scope);
724
725 JsComponentSnapshot helper(env, info);
726
727 NG::NodeIdentity nodeIdentity;
728 napi_valuetype type = napi_undefined;
729 napi_value argv = helper.GetArgv(index);
730 if (argv == nullptr) {
731 napi_close_escapable_handle_scope(env, scope);
732 return nodeIdentity;
733 }
734 napi_typeof(env, argv, &type);
735 if (type == napi_valuetype::napi_number) {
736 napi_get_value_int32(env, argv, &nodeIdentity.second);
737 } else {
738 napi_valuetype valueType = napi_null;
739 GetNapiString(env, argv, nodeIdentity.first, valueType);
740 }
741 napi_close_escapable_handle_scope(env, scope);
742 return nodeIdentity;
743 }
744
JSSnapshotGetWithRange(napi_env env,napi_callback_info info)745 static napi_value JSSnapshotGetWithRange(napi_env env, napi_callback_info info)
746 {
747 napi_escapable_handle_scope scope = nullptr;
748 napi_open_escapable_handle_scope(env, &scope);
749 JsComponentSnapshot helper(env, info);
750 napi_value result = nullptr;
751
752 if (!JudgeRangeType(env, info, 0) || !JudgeRangeType(env, info, 1)) {
753 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing argument failed, not of number or string type.");
754 napi_close_escapable_handle_scope(env, scope);
755 return result;
756 }
757
758 auto startID = GetNodeIdentity(env, info, 0);
759 auto endID = GetNodeIdentity(env, info, 1);
760 bool isStartRect = JudgeRectValue(env, info);
761
762 auto delegate = EngineHelper::GetCurrentDelegateSafely();
763 if (!delegate) {
764 TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Can't get delegate of ace_engine. ");
765 NapiThrow(env, "Delegate is null", ERROR_CODE_INTERNAL_ERROR);
766 napi_close_escapable_handle_scope(env, scope);
767 return result;
768 }
769 NG::SnapshotOptions options;
770 helper.ParseParamForGet(options);
771 delegate->GetSnapshotWithRange(startID, endID, isStartRect, helper.CreateCallback(&result), options);
772
773 napi_escape_handle(env, scope, result, &result);
774 napi_close_escapable_handle_scope(env, scope);
775 return result;
776 }
777
ComponentSnapshotExport(napi_env env,napi_value exports)778 static napi_value ComponentSnapshotExport(napi_env env, napi_value exports)
779 {
780 napi_property_descriptor snapshotDesc[] = {
781 DECLARE_NAPI_FUNCTION("get", JSSnapshotGet),
782 DECLARE_NAPI_FUNCTION("createFromBuilder", JSSnapshotFromBuilder),
783 DECLARE_NAPI_FUNCTION("getSync", JSSnapshotGetSync),
784 DECLARE_NAPI_FUNCTION("getWithUniqueId", JSSnapshotGetWithUniqueId),
785 DECLARE_NAPI_FUNCTION("getSyncWithUniqueId", JSSnapshotGetSyncWithUniqueId),
786 DECLARE_NAPI_FUNCTION("createFromComponent", JSSnapshotFromComponent),
787 DECLARE_NAPI_FUNCTION("getWithRange", JSSnapshotGetWithRange),
788 };
789 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(snapshotDesc) / sizeof(snapshotDesc[0]), snapshotDesc));
790
791 return exports;
792 }
793
794 static napi_module snapshotModule = {
795 .nm_version = 1,
796 .nm_flags = 0,
797 .nm_filename = nullptr,
798 .nm_register_func = ComponentSnapshotExport,
799 .nm_modname = "arkui.componentSnapshot",
800 .nm_priv = ((void*)0),
801 .reserved = { 0 },
802 };
803
ComponentSnapshotRegister()804 extern "C" __attribute__((constructor)) void ComponentSnapshotRegister()
805 {
806 napi_module_register(&snapshotModule);
807 }
808 } // namespace OHOS::Ace::Napi
809