• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 };
54 
GetType(napi_env env,napi_value root)55 static napi_valuetype GetType(napi_env env, napi_value root)
56 {
57     napi_valuetype res = napi_undefined;
58     napi_typeof(env, root, &res);
59     return res;
60 }
61 
GetDisplayId(napi_env env,std::unique_ptr<Param> & param,napi_value & argv)62 static void GetDisplayId(napi_env env, std::unique_ptr<Param> &param, napi_value &argv)
63 {
64     GNAPI_LOG("Get Screenshot Option: GetDisplayId");
65     napi_value displayId;
66     NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "displayId", &displayId));
67     if (displayId != nullptr && GetType(env, displayId) == napi_number) {
68         int64_t dispId;
69         NAPI_CALL_RETURN_VOID(env, napi_get_value_int64(env, displayId, &dispId));
70         param->option.displayId = static_cast<DisplayId>(dispId);
71         GNAPI_LOG("GetDisplayId success, displayId = %{public}" PRIu64"", param->option.displayId);
72     } else {
73         GNAPI_LOG("GetDisplayId failed, invalid param, use default displayId = 0");
74     }
75 }
76 
GetRotation(napi_env env,std::unique_ptr<Param> & param,napi_value & argv)77 static void GetRotation(napi_env env, std::unique_ptr<Param> &param, napi_value &argv)
78 {
79     GNAPI_LOG("Get Screenshot Option: GetRotation");
80     napi_value rotation;
81     NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "rotation", &rotation));
82     if (rotation != nullptr && GetType(env, rotation) == napi_number) {
83         NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, rotation, &param->option.rotation));
84         GNAPI_LOG("GetRotation success, rotation = %{public}d", param->option.rotation);
85     } else {
86         GNAPI_LOG("GetRotation failed, invalid param, use default rotation = 0");
87     }
88 }
89 
GetScreenRect(napi_env env,std::unique_ptr<Param> & param,napi_value & argv)90 static void GetScreenRect(napi_env env, std::unique_ptr<Param> &param, napi_value &argv)
91 {
92     GNAPI_LOG("Get Screenshot Option: GetScreenRect");
93     napi_value screenRect;
94     NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "screenRect", &screenRect));
95     if (screenRect != nullptr && GetType(env, screenRect) == napi_object) {
96         GNAPI_LOG("get ScreenRect success");
97 
98         napi_value left;
99         NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "left", &left));
100         if (left != nullptr && GetType(env, left) == napi_number) {
101             NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, left, &param->option.rect.left));
102             GNAPI_LOG("get ScreenRect.left success, left = %{public}d", param->option.rect.left);
103         } else {
104             GNAPI_LOG("get ScreenRect.left failed, invalid param, use default left = 0");
105         }
106 
107         napi_value top;
108         NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "top", &top));
109         if (top != nullptr && GetType(env, top) == napi_number) {
110             NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, top, &param->option.rect.top));
111             GNAPI_LOG("get ScreenRect.top success, top = %{public}d", param->option.rect.top);
112         } else {
113             GNAPI_LOG("get ScreenRect.top failed, invalid param, use default top = 0");
114         }
115 
116         napi_value width;
117         NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "width", &width));
118         if (width != nullptr && GetType(env, width) == napi_number) {
119             NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, width, &param->option.rect.width));
120             GNAPI_LOG("get ScreenRect.width success, width = %{public}d", param->option.rect.width);
121         } else {
122             GNAPI_LOG("get ScreenRect.width failed, invalid param, use default width = 0");
123         }
124 
125         napi_value height;
126         NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, screenRect, "height", &height));
127         if (height != nullptr && GetType(env, height) == napi_number) {
128             NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, height, &param->option.rect.height));
129             GNAPI_LOG("get ScreenRect.height success, height = %{public}d", param->option.rect.height);
130         } else {
131             GNAPI_LOG("get ScreenRect.height failed, invalid param, use default height = 0");
132         }
133     } else {
134         GNAPI_LOG("get ScreenRect failed, use default ScreenRect param");
135     }
136 }
137 
GetImageSize(napi_env env,std::unique_ptr<Param> & param,napi_value & argv)138 static void GetImageSize(napi_env env, std::unique_ptr<Param> &param, napi_value &argv)
139 {
140     GNAPI_LOG("Get Screenshot Option: ImageSize");
141     napi_value imageSize;
142     NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, argv, "imageSize", &imageSize));
143     if (imageSize != nullptr && GetType(env, imageSize) == napi_object) {
144         napi_value width;
145         NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, imageSize, "width", &width));
146         if (width != nullptr && GetType(env, width) == napi_number) {
147             NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, width, &param->option.size.width));
148             GNAPI_LOG("get ImageSize.width success, width = %{public}d", param->option.size.width);
149         } else {
150             GNAPI_LOG("get ImageSize.width failed, invalid param, use default width = 0");
151         }
152 
153         napi_value height;
154         NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, imageSize, "height", &height));
155         if (height != nullptr && GetType(env, height) == napi_number) {
156             NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, height, &param->option.size.height));
157             GNAPI_LOG("get ImageSize.height success, height = %{public}d", param->option.size.height);
158         } else {
159             GNAPI_LOG("get ImageSize.height failed, invalid param, use default height = 0");
160         }
161     }
162 }
163 
GetScreenshotParam(napi_env env,std::unique_ptr<Param> & param,napi_value & argv)164 static void GetScreenshotParam(napi_env env, std::unique_ptr<Param> &param, napi_value &argv)
165 {
166     if (param == nullptr) {
167         GNAPI_LOG("param == nullptr, use default param");
168         return;
169     }
170     GetDisplayId(env, param, argv);
171     GetRotation(env, param, argv);
172     GetScreenRect(env, param, argv);
173     GetImageSize(env, param, argv);
174 }
175 
AsyncGetScreenshot(napi_env env,std::unique_ptr<Param> & param)176 static void AsyncGetScreenshot(napi_env env, std::unique_ptr<Param> &param)
177 {
178     if (!param->validInputParam) {
179         WLOGFE("Invalid Input Param!");
180         param->image = nullptr;
181         param->wret = DmErrorCode::DM_ERROR_INVALID_PARAM;
182         param->errMessage = "Get Screenshot Failed: Invalid input param";
183         return;
184     }
185     if (param->useInputOption) {
186         GNAPI_LOG("Get Screenshot by input option");
187         param->image = DisplayManager::GetInstance().GetScreenshot(param->option.displayId,
188             param->option.rect, param->option.size, param->option.rotation);
189     } else {
190         GNAPI_LOG("Get Screenshot by default option");
191         param->image = DisplayManager::GetInstance().GetScreenshot(param->option.displayId);
192     }
193     if (param->image == nullptr) {
194         GNAPI_LOG("Get Screenshot failed!");
195         param->wret = DmErrorCode::DM_ERROR_INVALID_SCREEN;
196         param->errMessage = "Get Screenshot failed: Screenshot image is nullptr";
197         return;
198     }
199     param->wret = DmErrorCode::DM_OK;
200 }
201 
Resolve(napi_env env,std::unique_ptr<Param> & param)202 napi_value Resolve(napi_env env, std::unique_ptr<Param> &param)
203 {
204     napi_value result;
205     napi_value error;
206     napi_value code;
207     if (param->wret == DmErrorCode::DM_ERROR_INVALID_PARAM) {
208         napi_create_error(env, nullptr, nullptr, &error);
209         napi_create_int32(env, (int32_t)DmErrorCode::DM_ERROR_INVALID_PARAM, &code);
210         napi_set_named_property(env, error, "DM_ERROR_INVALID_PARAM", code);
211         napi_throw(env, error);
212         return error;
213     } else if (param->wret != DmErrorCode::DM_OK) {
214         NAPI_CALL(env, napi_get_undefined(env, &result));
215         return result;
216     }
217 
218     GNAPI_LOG("Screenshot image Width %{public}d, Height %{public}d",
219         param->image->GetWidth(), param->image->GetHeight());
220     napi_value jsImage = OHOS::Media::PixelMapNapi::CreatePixelMap(env, param->image);
221     return jsImage;
222 }
223 
MainFunc(napi_env env,napi_callback_info info)224 napi_value MainFunc(napi_env env, napi_callback_info info)
225 {
226     GNAPI_LOG("%{public}s called", __PRETTY_FUNCTION__);
227     napi_value argv[2] = {0}; // the max number of input parameters is 2
228     size_t argc = 2; // the max number of input parameters is 2
229     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
230 
231     auto param = std::make_unique<Param>();
232     if (param == nullptr) {
233         WLOGFE("Create param failed.");
234         return nullptr;
235     }
236     param->option.displayId = DisplayManager::GetInstance().GetDefaultDisplayId();
237     napi_ref ref = nullptr;
238     if (argc == 0) { // 0 valid parameters
239         GNAPI_LOG("argc == 0");
240         param->validInputParam = true;
241     } else if (GetType(env, argv[0]) == napi_function) { // 1 valid parameters napi_function
242         GNAPI_LOG("argc >= 1, argv[0]'s type is napi_function");
243         param->validInputParam = true;
244         NAPI_CALL(env, napi_create_reference(env, argv[0], 1, &ref));
245     } else if (GetType(env, argv[0]) == napi_object) {
246         if ((argc >= 2) && (GetType(env, argv[1]) == napi_function)) { // 2 valid parameters napi_object napi_function
247             GNAPI_LOG("argc >= 2, argv[0]'s type is napi_object, argv[1]'s type is napi_function");
248             param->validInputParam = true;
249             param->useInputOption = true;
250             GetScreenshotParam(env, param, argv[0]);
251             NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &ref));
252         } else { // 1 valid parameters napi_object
253             GNAPI_LOG("argc >= 1, argv[0]'s type is napi_object");
254             param->validInputParam = true;
255             param->useInputOption = true;
256             GetScreenshotParam(env, param, argv[0]);
257         }
258     } else { // 0 valid parameters
259         GNAPI_LOG("argc == 0");
260         param->validInputParam = true;
261     }
262 
263     return AsyncProcess<Param>(env, __PRETTY_FUNCTION__, AsyncGetScreenshot, Resolve, ref, param);
264 }
265 } // namespace save
266 
SetNamedProperty(napi_env env,napi_value dstObj,const int32_t objValue,const char * propName)267 void SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName)
268 {
269     napi_value prop = nullptr;
270     napi_create_int32(env, objValue, &prop);
271     napi_set_named_property(env, dstObj, propName, prop);
272 }
273 
ScreenshotModuleInit(napi_env env,napi_value exports)274 napi_value ScreenshotModuleInit(napi_env env, napi_value exports)
275 {
276     GNAPI_LOG("%{public}s called", __PRETTY_FUNCTION__);
277 
278     napi_value errorCode = nullptr;
279     napi_value dmErrorCode = nullptr;
280     napi_create_object(env, &errorCode);
281     napi_create_object(env, &dmErrorCode);
282 
283     SetNamedProperty(env, errorCode,
284         (int32_t)DMError::DM_ERROR_INIT_DMS_PROXY_LOCKED, "DM_ERROR_INIT_DMS_PROXY_LOCKED");
285     SetNamedProperty(env, errorCode,
286         (int32_t)DMError::DM_ERROR_IPC_FAILED, "DM_ERROR_IPC_FAILED");
287     SetNamedProperty(env, errorCode,
288         (int32_t)DMError::DM_ERROR_REMOTE_CREATE_FAILED, "DM_ERROR_REMOTE_CREATE_FAILED");
289     SetNamedProperty(env, errorCode,
290         (int32_t)DMError::DM_ERROR_NULLPTR, "DM_ERROR_NULLPTR");
291     SetNamedProperty(env, errorCode,
292         (int32_t)DMError::DM_ERROR_INVALID_PARAM, "DM_ERROR_INVALID_PARAM");
293     SetNamedProperty(env, errorCode,
294         (int32_t)DMError::DM_ERROR_WRITE_INTERFACE_TOKEN_FAILED, "DM_ERROR_WRITE_INTERFACE_TOKEN_FAILED");
295     SetNamedProperty(env, errorCode,
296         (int32_t)DMError::DM_ERROR_DEATH_RECIPIENT, "DM_ERROR_DEATH_RECIPIENT");
297     SetNamedProperty(env, errorCode,
298         (int32_t)DMError::DM_ERROR_INVALID_MODE_ID, "DM_ERROR_INVALID_MODE_ID");
299     SetNamedProperty(env, errorCode,
300         (int32_t)DMError::DM_ERROR_WRITE_DATA_FAILED, "DM_ERROR_WRITE_DATA_FAILED");
301     SetNamedProperty(env, errorCode,
302         (int32_t)DMError::DM_ERROR_RENDER_SERVICE_FAILED, "DM_ERROR_RENDER_SERVICE_FAILED");
303     SetNamedProperty(env, errorCode,
304         (int32_t)DMError::DM_ERROR_UNREGISTER_AGENT_FAILED, "DM_ERROR_UNREGISTER_AGENT_FAILED");
305     SetNamedProperty(env, errorCode,
306         (int32_t)DMError::DM_ERROR_INVALID_CALLING, "DM_ERROR_INVALID_CALLING");
307     SetNamedProperty(env, errorCode,
308         (int32_t)DMError::DM_ERROR_UNKNOWN, "DM_ERROR_UNKNOWN");
309 
310     SetNamedProperty(env, dmErrorCode,
311         (int32_t)DmErrorCode::DM_ERROR_NO_PERMISSION, "DM_ERROR_NO_PERMISSION");
312     SetNamedProperty(env, dmErrorCode,
313         (int32_t)DmErrorCode::DM_ERROR_INVALID_PARAM, "DM_ERROR_INVALID_PARAM");
314     SetNamedProperty(env, dmErrorCode,
315         (int32_t)DmErrorCode::DM_ERROR_DEVICE_NOT_SUPPORT, "DM_ERROR_DEVICE_NOT_SUPPORT");
316     SetNamedProperty(env, dmErrorCode,
317         (int32_t)DmErrorCode::DM_ERROR_INVALID_SCREEN, "DM_ERROR_INVALID_SCREEN");
318     SetNamedProperty(env, dmErrorCode,
319         (int32_t)DmErrorCode::DM_ERROR_INVALID_CALLING, "DM_ERROR_INVALID_CALLING");
320     SetNamedProperty(env, dmErrorCode,
321         (int32_t)DmErrorCode::DM_ERROR_SYSTEM_INNORMAL, "DM_ERROR_SYSTEM_INNORMAL");
322 
323     napi_property_descriptor properties[] = {
324         DECLARE_NAPI_FUNCTION("save", save::MainFunc),
325         DECLARE_NAPI_PROPERTY("DMError", errorCode),
326         DECLARE_NAPI_PROPERTY("DmErrorCode", dmErrorCode),
327     };
328 
329     NAPI_CALL(env, napi_define_properties(env,
330         exports, sizeof(properties) / sizeof(properties[0]), properties));
331     return exports;
332 }
333 } // namespace OHOS::Rosen
334 
RegisterModule(void)335 extern "C" __attribute__((constructor)) void RegisterModule(void)
336 {
337     napi_module screenshotModule = {
338         .nm_version = 1, // NAPI v1
339         .nm_flags = 0, // normal
340         .nm_filename = nullptr,
341         .nm_register_func = OHOS::Rosen::ScreenshotModuleInit,
342         .nm_modname = "screenshot",
343         .nm_priv = nullptr,
344     };
345     napi_module_register(&screenshotModule);
346 }
347