1 /*
2 * Copyright (c) 2022 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 #include "native_screenshot_module.h"
16
17 #include <cinttypes>
18 #include <cstddef>
19 #include <cstdint>
20 #include <image_type.h>
21 #include <iosfwd>
22 #include <js_native_api.h>
23 #include <js_native_api_types.h>
24 #include <memory>
25 #include <napi/native_api.h>
26 #include <napi/native_common.h>
27 #include <string>
28 #include <type_traits>
29
30 #include "display_manager.h"
31 #include "pixel_map.h"
32 #include "pixel_map_napi.h"
33 #include "window_manager_hilog.h"
34 #include "dm_common.h"
35 #include "dm_napi_common.h"
36
37 namespace OHOS::Rosen {
38 namespace save {
39 struct Option {
40 Media::Rect rect;
41 Media::Size size;
42 int rotation = 0;
43 DisplayId displayId = 0;
44 };
45
46 struct Param {
47 DmErrorCode wret;
48 Option option;
49 std::string errMessage;
50 bool useInputOption;
51 bool validInputParam;
52 std::shared_ptr<Media::PixelMap> image;
53 Media::Rect imageRect;
54 bool isPick;
55 };
56
GetType(napi_env env, napi_value root)57 static napi_valuetype GetType(napi_env env, napi_value root)
58 {
59 napi_valuetype res = napi_undefined;
60 napi_typeof(env, root, &res);
61 return res;
62 }
63
GetDisplayId(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)64 static void GetDisplayId(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)
65 {
66 GNAPI_LOG("Get Screenshot Option: GetDisplayId");
67 napi_value displayId;
68 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "displayId", &displayId));
69 if (displayId != nullptr && GetType(env, displayId) == napi_number) {
70 int64_t dispId;
71 NAPI_CALL_RETURN_VOID(env, napi_get_value_int64(env, displayId, &dispId));
72 param->option.displayId = static_cast<DisplayId>(dispId);
73 GNAPI_LOG("GetDisplayId success, displayId = %{public}" PRIu64"", param->option.displayId);
74 } else {
75 GNAPI_LOG("GetDisplayId failed, invalid param, use default displayId = 0");
76 }
77 }
78
GetRotation(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)79 static void GetRotation(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)
80 {
81 GNAPI_LOG("Get Screenshot Option: GetRotation");
82 napi_value rotation;
83 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "rotation", &rotation));
84 if (rotation != nullptr && GetType(env, rotation) == napi_number) {
85 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, rotation, ¶m->option.rotation));
86 GNAPI_LOG("GetRotation success, rotation = %{public}d", param->option.rotation);
87 } else {
88 GNAPI_LOG("GetRotation failed, invalid param, use default rotation = 0");
89 }
90 }
91
GetScreenRect(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)92 static void GetScreenRect(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)
93 {
94 GNAPI_LOG("Get Screenshot Option: GetScreenRect");
95 napi_value screenRect;
96 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "screenRect", &screenRect));
97 if (screenRect != nullptr && GetType(env, screenRect) == napi_object) {
98 GNAPI_LOG("get ScreenRect success");
99
100 napi_value left;
101 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "left", &left));
102 if (left != nullptr && GetType(env, left) == napi_number) {
103 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, left, ¶m->option.rect.left));
104 GNAPI_LOG("get ScreenRect.left success, left = %{public}d", param->option.rect.left);
105 } else {
106 GNAPI_LOG("get ScreenRect.left failed, invalid param, use default left = 0");
107 }
108
109 napi_value top;
110 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "top", &top));
111 if (top != nullptr && GetType(env, top) == napi_number) {
112 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, top, ¶m->option.rect.top));
113 GNAPI_LOG("get ScreenRect.top success, top = %{public}d", param->option.rect.top);
114 } else {
115 GNAPI_LOG("get ScreenRect.top failed, invalid param, use default top = 0");
116 }
117
118 napi_value width;
119 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "width", &width));
120 if (width != nullptr && GetType(env, width) == napi_number) {
121 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, width, ¶m->option.rect.width));
122 GNAPI_LOG("get ScreenRect.width success, width = %{public}d", param->option.rect.width);
123 } else {
124 GNAPI_LOG("get ScreenRect.width failed, invalid param, use default width = 0");
125 }
126
127 napi_value height;
128 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "height", &height));
129 if (height != nullptr && GetType(env, height) == napi_number) {
130 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, height, ¶m->option.rect.height));
131 GNAPI_LOG("get ScreenRect.height success, height = %{public}d", param->option.rect.height);
132 } else {
133 GNAPI_LOG("get ScreenRect.height failed, invalid param, use default height = 0");
134 }
135 } else {
136 GNAPI_LOG("get ScreenRect failed, use default ScreenRect param");
137 }
138 }
139
GetImageSize(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)140 static void GetImageSize(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)
141 {
142 GNAPI_LOG("Get Screenshot Option: ImageSize");
143 napi_value imageSize;
144 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "imageSize", &imageSize));
145 if (imageSize != nullptr && GetType(env, imageSize) == napi_object) {
146 napi_value width;
147 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, imageSize, "width", &width));
148 if (width != nullptr && GetType(env, width) == napi_number) {
149 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, width, ¶m->option.size.width));
150 GNAPI_LOG("get ImageSize.width success, width = %{public}d", param->option.size.width);
151 } else {
152 GNAPI_LOG("get ImageSize.width failed, invalid param, use default width = 0");
153 }
154
155 napi_value height;
156 NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, imageSize, "height", &height));
157 if (height != nullptr && GetType(env, height) == napi_number) {
158 NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, height, ¶m->option.size.height));
159 GNAPI_LOG("get ImageSize.height success, height = %{public}d", param->option.size.height);
160 } else {
161 GNAPI_LOG("get ImageSize.height failed, invalid param, use default height = 0");
162 }
163 }
164 }
165
GetScreenshotParam(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)166 static void GetScreenshotParam(napi_env env, std::unique_ptr<Param> ¶m, napi_value &argv)
167 {
168 if (param == nullptr) {
169 GNAPI_LOG("param == nullptr, use default param");
170 return;
171 }
172 GetDisplayId(env, param, argv);
173 GetRotation(env, param, argv);
174 GetScreenRect(env, param, argv);
175 GetImageSize(env, param, argv);
176 }
177
AsyncGetScreenshot(napi_env env, std::unique_ptr<Param> ¶m)178 static void AsyncGetScreenshot(napi_env env, std::unique_ptr<Param> ¶m)
179 {
180 if (!param->validInputParam) {
181 WLOGFE("Invalid Input Param!");
182 param->image = nullptr;
183 param->wret = DmErrorCode::DM_ERROR_INVALID_PARAM;
184 param->errMessage = "Get Screenshot Failed: Invalid input param";
185 return;
186 }
187 if (param->useInputOption) {
188 GNAPI_LOG("Get Screenshot by input option");
189 param->image = DisplayManager::GetInstance().GetScreenshot(param->option.displayId,
190 param->option.rect, param->option.size, param->option.rotation, ¶m->wret);
191 } else if (param->isPick) {
192 GNAPI_LOG("Get Screenshot by picker");
193 param->image = DisplayManager::GetInstance().GetSnapshotByPicker(param->imageRect, ¶m->wret);
194 } else {
195 GNAPI_LOG("Get Screenshot by default option");
196 param->image = DisplayManager::GetInstance().GetScreenshot(param->option.displayId, ¶m->wret);
197 }
198 if (param->image == nullptr && param->wret == DmErrorCode::DM_OK) {
199 GNAPI_LOG("Get Screenshot failed!");
200 param->wret = DmErrorCode::DM_ERROR_INVALID_SCREEN;
201 param->errMessage = "Get Screenshot failed: Screenshot image is nullptr";
202 return;
203 }
204 }
205
CreateJsNumber(napi_env env, int32_t value)206 napi_value CreateJsNumber(napi_env env, int32_t value)
207 {
208 napi_value valRet = nullptr;
209 napi_create_int32(env, value, &valRet);
210 return valRet;
211 }
212
CreateJsRectObject(napi_env env, Media::Rect imageRect)213 napi_value CreateJsRectObject(napi_env env, Media::Rect imageRect)
214 {
215 napi_value objValue = nullptr;
216 NAPI_CALL(env, napi_create_object(env, &objValue));
217 napi_set_named_property(env, objValue, "left", CreateJsNumber(env, imageRect.left));
218 napi_set_named_property(env, objValue, "top", CreateJsNumber(env, imageRect.top));
219 napi_set_named_property(env, objValue, "width", CreateJsNumber(env, imageRect.width));
220 napi_set_named_property(env, objValue, "height", CreateJsNumber(env, imageRect.height));
221 return objValue;
222 }
223
CreateJsPickerObject(napi_env env, std::unique_ptr<Param> ¶m)224 napi_value CreateJsPickerObject(napi_env env, std::unique_ptr<Param> ¶m)
225 {
226 napi_value objValue = nullptr;
227 NAPI_CALL(env, napi_create_object(env, &objValue));
228 if (param == nullptr) {
229 napi_value result;
230 WLOGFE("param nullptr.");
231 NAPI_CALL(env, napi_get_undefined(env, &result));
232 return result;
233 }
234 napi_set_named_property(env, objValue, "pixelMap", OHOS::Media::PixelMapNapi::CreatePixelMap(env, param->image));
235 napi_set_named_property(env, objValue, "pickRect", CreateJsRectObject(env, param->imageRect));
236 WLOGFI("pick end");
237 return objValue;
238 }
239
Resolve(napi_env env, std::unique_ptr<Param> ¶m)240 napi_value Resolve(napi_env env, std::unique_ptr<Param> ¶m)
241 {
242 napi_value result;
243 napi_value error;
244 napi_value code;
245 if (param->wret == DmErrorCode::DM_ERROR_INVALID_PARAM) {
246 napi_create_error(env, nullptr, nullptr, &error);
247 napi_create_int32(env, (int32_t)DmErrorCode::DM_ERROR_INVALID_PARAM, &code);
248 napi_set_named_property(env, error, "DM_ERROR_INVALID_PARAM", code);
249 napi_throw(env, error);
250 return error;
251 } else if (param->wret != DmErrorCode::DM_OK) {
252 NAPI_CALL(env, napi_get_undefined(env, &result));
253 return result;
254 }
255 if (param->isPick) {
256 GNAPI_LOG("Resolve Screenshot by picker");
257 return CreateJsPickerObject(env, param);
258 }
259 GNAPI_LOG("Screenshot image Width %{public}d, Height %{public}d",
260 param->image->GetWidth(), param->image->GetHeight());
261 napi_value jsImage = OHOS::Media::PixelMapNapi::CreatePixelMap(env, param->image);
262 return jsImage;
263 }
264
PickFunc(napi_env env, napi_callback_info info)265 napi_value PickFunc(napi_env env, napi_callback_info info)
266 {
267 GNAPI_LOG("%{public}s called", __PRETTY_FUNCTION__);
268 napi_value argv[1] = { nullptr }; // the max number of input parameters is 1
269 size_t argc = 1; // the max number of input parameters is 1
270 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
271
272 auto param = std::make_unique<Param>();
273 if (param == nullptr) {
274 WLOGFE("Create param failed.");
275 return nullptr;
276 }
277 napi_ref ref = nullptr;
278 if (argc == 0) { // 0 valid parameters
279 GNAPI_LOG("argc == 0");
280 param->validInputParam = true;
281 } else if (GetType(env, argv[0]) == napi_function) { // 1 valid parameters napi_function
282 GNAPI_LOG("argc >= 1, argv[0]'s type is napi_function");
283 param->validInputParam = true;
284 NAPI_CALL(env, napi_create_reference(env, argv[0], 1, &ref));
285 } else { // 0 valid parameters
286 GNAPI_LOG("argc == 0");
287 param->validInputParam = true;
288 }
289 param->isPick = true;
290 return AsyncProcess<Param>(env, __PRETTY_FUNCTION__, AsyncGetScreenshot, Resolve, ref, param);
291 }
292
MainFunc(napi_env env, napi_callback_info info)293 napi_value MainFunc(napi_env env, napi_callback_info info)
294 {
295 GNAPI_LOG("%{public}s called", __PRETTY_FUNCTION__);
296 napi_value argv[2] = {nullptr}; // the max number of input parameters is 2
297 size_t argc = 2; // the max number of input parameters is 2
298 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
299
300 auto param = std::make_unique<Param>();
301 if (param == nullptr) {
302 WLOGFE("Create param failed.");
303 return nullptr;
304 }
305 param->option.displayId = DisplayManager::GetInstance().GetDefaultDisplayId();
306 napi_ref ref = nullptr;
307 if (argc == 0) { // 0 valid parameters
308 GNAPI_LOG("argc == 0");
309 param->validInputParam = true;
310 } else if (GetType(env, argv[0]) == napi_function) { // 1 valid parameters napi_function
311 GNAPI_LOG("argc >= 1, argv[0]'s type is napi_function");
312 param->validInputParam = true;
313 NAPI_CALL(env, napi_create_reference(env, argv[0], 1, &ref));
314 } else if (GetType(env, argv[0]) == napi_object) {
315 if ((argc >= 2) && (GetType(env, argv[1]) == napi_function)) { // 2 valid parameters napi_object napi_function
316 GNAPI_LOG("argc >= 2, argv[0]'s type is napi_object, argv[1]'s type is napi_function");
317 param->validInputParam = true;
318 param->useInputOption = true;
319 GetScreenshotParam(env, param, argv[0]);
320 NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &ref));
321 } else { // 1 valid parameters napi_object
322 GNAPI_LOG("argc >= 1, argv[0]'s type is napi_object");
323 param->validInputParam = true;
324 param->useInputOption = true;
325 GetScreenshotParam(env, param, argv[0]);
326 }
327 } else { // 0 valid parameters
328 GNAPI_LOG("argc == 0");
329 param->validInputParam = true;
330 }
331 param->isPick = false;
332 return AsyncProcess<Param>(env, __PRETTY_FUNCTION__, AsyncGetScreenshot, Resolve, ref, param);
333 }
334 } // namespace save
335
SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName)336 void SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName)
337 {
338 napi_value prop = nullptr;
339 napi_create_int32(env, objValue, &prop);
340 napi_set_named_property(env, dstObj, propName, prop);
341 }
342
ScreenshotModuleInit(napi_env env, napi_value exports)343 napi_value ScreenshotModuleInit(napi_env env, napi_value exports)
344 {
345 GNAPI_LOG("%{public}s called", __PRETTY_FUNCTION__);
346
347 napi_value errorCode = nullptr;
348 napi_value dmErrorCode = nullptr;
349 napi_create_object(env, &errorCode);
350 napi_create_object(env, &dmErrorCode);
351
352 SetNamedProperty(env, errorCode,
353 (int32_t)DMError::DM_ERROR_INIT_DMS_PROXY_LOCKED, "DM_ERROR_INIT_DMS_PROXY_LOCKED");
354 SetNamedProperty(env, errorCode,
355 (int32_t)DMError::DM_ERROR_IPC_FAILED, "DM_ERROR_IPC_FAILED");
356 SetNamedProperty(env, errorCode,
357 (int32_t)DMError::DM_ERROR_REMOTE_CREATE_FAILED, "DM_ERROR_REMOTE_CREATE_FAILED");
358 SetNamedProperty(env, errorCode,
359 (int32_t)DMError::DM_ERROR_NULLPTR, "DM_ERROR_NULLPTR");
360 SetNamedProperty(env, errorCode,
361 (int32_t)DMError::DM_ERROR_INVALID_PARAM, "DM_ERROR_INVALID_PARAM");
362 SetNamedProperty(env, errorCode,
363 (int32_t)DMError::DM_ERROR_WRITE_INTERFACE_TOKEN_FAILED, "DM_ERROR_WRITE_INTERFACE_TOKEN_FAILED");
364 SetNamedProperty(env, errorCode,
365 (int32_t)DMError::DM_ERROR_DEATH_RECIPIENT, "DM_ERROR_DEATH_RECIPIENT");
366 SetNamedProperty(env, errorCode,
367 (int32_t)DMError::DM_ERROR_INVALID_MODE_ID, "DM_ERROR_INVALID_MODE_ID");
368 SetNamedProperty(env, errorCode,
369 (int32_t)DMError::DM_ERROR_WRITE_DATA_FAILED, "DM_ERROR_WRITE_DATA_FAILED");
370 SetNamedProperty(env, errorCode,
371 (int32_t)DMError::DM_ERROR_RENDER_SERVICE_FAILED, "DM_ERROR_RENDER_SERVICE_FAILED");
372 SetNamedProperty(env, errorCode,
373 (int32_t)DMError::DM_ERROR_UNREGISTER_AGENT_FAILED, "DM_ERROR_UNREGISTER_AGENT_FAILED");
374 SetNamedProperty(env, errorCode,
375 (int32_t)DMError::DM_ERROR_INVALID_CALLING, "DM_ERROR_INVALID_CALLING");
376 SetNamedProperty(env, errorCode,
377 (int32_t)DMError::DM_ERROR_UNKNOWN, "DM_ERROR_UNKNOWN");
378
379 SetNamedProperty(env, dmErrorCode,
380 (int32_t)DmErrorCode::DM_ERROR_NO_PERMISSION, "DM_ERROR_NO_PERMISSION");
381 SetNamedProperty(env, dmErrorCode,
382 (int32_t)DmErrorCode::DM_ERROR_INVALID_PARAM, "DM_ERROR_INVALID_PARAM");
383 SetNamedProperty(env, dmErrorCode,
384 (int32_t)DmErrorCode::DM_ERROR_DEVICE_NOT_SUPPORT, "DM_ERROR_DEVICE_NOT_SUPPORT");
385 SetNamedProperty(env, dmErrorCode,
386 (int32_t)DmErrorCode::DM_ERROR_INVALID_SCREEN, "DM_ERROR_INVALID_SCREEN");
387 SetNamedProperty(env, dmErrorCode,
388 (int32_t)DmErrorCode::DM_ERROR_INVALID_CALLING, "DM_ERROR_INVALID_CALLING");
389 SetNamedProperty(env, dmErrorCode,
390 (int32_t)DmErrorCode::DM_ERROR_SYSTEM_INNORMAL, "DM_ERROR_SYSTEM_INNORMAL");
391
392 napi_property_descriptor properties[] = {
393 DECLARE_NAPI_FUNCTION("save", save::MainFunc),
394 DECLARE_NAPI_FUNCTION("pick", save::PickFunc),
395 DECLARE_NAPI_PROPERTY("DMError", errorCode),
396 DECLARE_NAPI_PROPERTY("DmErrorCode", dmErrorCode),
397 };
398
399 NAPI_CALL(env, napi_define_properties(env,
400 exports, sizeof(properties) / sizeof(properties[0]), properties));
401 return exports;
402 }
403 } // namespace OHOS::Rosen
404
405 static napi_module g_screenshotModule = {
406 .nm_version = 1, // NAPI v1
407 .nm_flags = 0, // normal
408 .nm_filename = nullptr,
409 .nm_register_func = OHOS::Rosen::ScreenshotModuleInit,
410 .nm_modname = "screenshot",
411 .nm_priv = nullptr,
412 };
413
RegisterModule(void)414 extern "C" __attribute__((constructor)) void RegisterModule(void)
415 {
416 napi_module_register(&g_screenshotModule);
417 }
418