• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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", &regionObject);
287     if (!regionObject) {
288         options.regionMode = NG::SnapshotRegionMode::NO_REGION;
289         return;
290     }
291 
292     options.regionMode = NG::SnapshotRegionMode::COMMON;
293     if (ParseLocalizedRegion(&regionObject, options)) {
294         options.regionMode = NG::SnapshotRegionMode::LOCALIZED;
295     } else {
296         ParseRegion(&regionObject, 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