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> ¶m, 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> ¶m, 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, ¶m->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> ¶m, 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, ¶m->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, ¶m->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, ¶m->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, ¶m->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> ¶m, 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, ¶m->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, ¶m->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> ¶m, 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> ¶m)
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> ¶m)
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