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_screen_utils.h"
17
18 #include <js_runtime_utils.h>
19 #include <event_handler.h>
20 #include "process_options.h"
21
22 #include "dm_common.h"
23 #include "window_manager_hilog.h"
24
25 namespace OHOS::Rosen {
26 using namespace AbilityRuntime;
27 namespace {
28 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "JsScreenUtils" };
29 }
30
NapiGetUndefined(napi_env env)31 napi_value NapiGetUndefined(napi_env env)
32 {
33 napi_value result = nullptr;
34 napi_get_undefined(env, &result);
35 return result;
36 }
37
NapiIsCallable(napi_env env,napi_value value)38 bool NapiIsCallable(napi_env env, napi_value value)
39 {
40 bool result = false;
41 napi_is_callable(env, value, &result);
42 return result;
43 }
44
GetType(napi_env env,napi_value value)45 napi_valuetype GetType(napi_env env, napi_value value)
46 {
47 napi_valuetype res = napi_undefined;
48 napi_typeof(env, value, &res);
49 return res;
50 }
51
CreateJsScreenProperty(napi_env env,const ScreenProperty & screenProperty)52 napi_value JsScreenUtils::CreateJsScreenProperty(napi_env env, const ScreenProperty& screenProperty)
53 {
54 napi_value objValue = nullptr;
55 napi_create_object(env, &objValue);
56 if (objValue == nullptr) {
57 WLOGFE("Failed to create object!");
58 return NapiGetUndefined(env);
59 }
60
61 napi_set_named_property(env, objValue, "propertyChangeReason",
62 CreateJsValue(env, screenProperty.GetPropertyChangeReason()));
63 napi_set_named_property(env, objValue, "rotation", CreateJsValue(env, screenProperty.GetRotation()));
64 napi_set_named_property(env, objValue, "bounds", CreateJsRRect(env, screenProperty.GetBounds()));
65 return objValue;
66 }
67
CreateJsRRect(napi_env env,const RRect & rrect)68 napi_value JsScreenUtils::CreateJsRRect(napi_env env, const RRect& rrect)
69 {
70 napi_value objValue = nullptr;
71 napi_create_object(env, &objValue);
72 if (objValue == nullptr) {
73 WLOGFE("Failed to create object!");
74 return NapiGetUndefined(env);
75 }
76
77 napi_set_named_property(env, objValue, "left", CreateJsValue(env, rrect.rect_.left_));
78 napi_set_named_property(env, objValue, "top", CreateJsValue(env, rrect.rect_.top_));
79 napi_set_named_property(env, objValue, "width", CreateJsValue(env, rrect.rect_.width_));
80 napi_set_named_property(env, objValue, "height", CreateJsValue(env, rrect.rect_.height_));
81 napi_set_named_property(env, objValue, "radius", CreateJsValue(env, rrect.radius_[0].x_));
82 return objValue;
83 }
84
CreateJsScreenConnectChangeType(napi_env env)85 napi_value JsScreenUtils::CreateJsScreenConnectChangeType(napi_env env)
86 {
87 napi_value objValue = nullptr;
88 napi_create_object(env, &objValue);
89 if (objValue == nullptr) {
90 WLOGFE("Failed to create object!");
91 return NapiGetUndefined(env);
92 }
93
94 napi_set_named_property(env, objValue, "CONNECT", CreateJsValue(env, 0));
95 napi_set_named_property(env, objValue, "DISCONNECT", CreateJsValue(env, 1));
96 return objValue;
97 }
98
CreateJsScreenPropertyChangeReason(napi_env env)99 napi_value JsScreenUtils::CreateJsScreenPropertyChangeReason(napi_env env)
100 {
101 napi_value objValue = nullptr;
102 napi_create_object(env, &objValue);
103 if (objValue == nullptr) {
104 WLOGFE("Failed to create object!");
105 return NapiGetUndefined(env);
106 }
107
108 napi_set_named_property(env, objValue, "UNDEFINED", CreateJsValue(env,
109 static_cast<int32_t>(ScreenPropertyChangeReason::UNDEFINED)));
110 napi_set_named_property(env, objValue, "ROTATION", CreateJsValue(env,
111 static_cast<int32_t>(ScreenPropertyChangeReason::ROTATION)));
112 napi_set_named_property(env, objValue, "CHANGE_MODE", CreateJsValue(env,
113 static_cast<int32_t>(ScreenPropertyChangeReason::CHANGE_MODE)));
114 napi_set_named_property(env, objValue, "FOLD_SCREEN_EXPAND", CreateJsValue(env,
115 static_cast<int32_t>(ScreenPropertyChangeReason::FOLD_SCREEN_EXPAND)));
116 napi_set_named_property(env, objValue, "SCREEN_CONNECT", CreateJsValue(env,
117 static_cast<int32_t>(ScreenPropertyChangeReason::SCREEN_CONNECT)));
118 napi_set_named_property(env, objValue, "SCREEN_DISCONNECT", CreateJsValue(env,
119 static_cast<int32_t>(ScreenPropertyChangeReason::SCREEN_DISCONNECT)));
120 napi_set_named_property(env, objValue, "FOLD_SCREEN_FOLDING", CreateJsValue(env,
121 static_cast<int32_t>(ScreenPropertyChangeReason::FOLD_SCREEN_FOLDING)));
122 napi_set_named_property(env, objValue, "VIRTUAL_SCREEN_RESIZE", CreateJsValue(env,
123 static_cast<int32_t>(ScreenPropertyChangeReason::VIRTUAL_SCREEN_RESIZE)));
124 return objValue;
125 }
126
CreateJsFoldStatus(napi_env env)127 napi_value JsScreenUtils::CreateJsFoldStatus(napi_env env)
128 {
129 napi_value objValue = nullptr;
130 napi_create_object(env, &objValue);
131 if (objValue == nullptr) {
132 WLOGFE("Failed to create object!");
133 return NapiGetUndefined(env);
134 }
135
136 napi_set_named_property(env, objValue, "FOLD_STATUS_UNKNOWN", CreateJsValue(env,
137 static_cast<int32_t>(FoldStatus::UNKNOWN)));
138 napi_set_named_property(env, objValue, "FOLD_STATUS_EXPANDED", CreateJsValue(env,
139 static_cast<int32_t>(FoldStatus::EXPAND)));
140 napi_set_named_property(env, objValue, "FOLD_STATUS_FOLDED", CreateJsValue(env,
141 static_cast<int32_t>(FoldStatus::FOLDED)));
142 napi_set_named_property(env, objValue, "FOLD_STATUS_HALF_FOLDED", CreateJsValue(env,
143 static_cast<int32_t>(FoldStatus::HALF_FOLD)));
144 return objValue;
145 }
146
CreateJsScreenPropertyChangeType(napi_env env)147 napi_value JsScreenUtils::CreateJsScreenPropertyChangeType(napi_env env)
148 {
149 napi_value objValue = nullptr;
150 napi_create_object(env, &objValue);
151 if (objValue == nullptr) {
152 WLOGFE("Failed to create object!");
153 return NapiGetUndefined(env);
154 }
155
156 napi_set_named_property(env, objValue, "UNSPECIFIED", CreateJsValue(env,
157 static_cast<int32_t>(ScreenPropertyChangeType::UNSPECIFIED)));
158 napi_set_named_property(env, objValue, "ROTATION_BEGIN", CreateJsValue(env,
159 static_cast<int32_t>(ScreenPropertyChangeType::ROTATION_BEGIN)));
160 napi_set_named_property(env, objValue, "ROTATION_END", CreateJsValue(env,
161 static_cast<int32_t>(ScreenPropertyChangeType::ROTATION_END)));
162 napi_set_named_property(env, objValue, "ROTATION_UPDATE_PROPERTY_ONLY", CreateJsValue(env,
163 static_cast<int32_t>(ScreenPropertyChangeType::ROTATION_UPDATE_PROPERTY_ONLY)));
164 return objValue;
165 }
166
ConvertRRectFromJs(napi_env env,napi_value jsObject,RRect & bound)167 bool ConvertRRectFromJs(napi_env env, napi_value jsObject, RRect& bound)
168 {
169 napi_value jsLeft = nullptr, jsTop = nullptr, jsWidth = nullptr, jsHeight = nullptr, jsRadius = nullptr;
170 napi_get_named_property(env, jsObject, "left", &jsLeft);
171 napi_get_named_property(env, jsObject, "top", &jsTop);
172 napi_get_named_property(env, jsObject, "width", &jsWidth);
173 napi_get_named_property(env, jsObject, "height", &jsHeight);
174 napi_get_named_property(env, jsObject, "radius", &jsRadius);
175
176 if (GetType(env, jsLeft) != napi_undefined) {
177 int32_t left;
178 if (!ConvertFromJsValue(env, jsLeft, left)) {
179 WLOGFE("[NAPI]Failed to convert parameter to left");
180 return false;
181 }
182 bound.rect_.left_ = left;
183 }
184 if (GetType(env, jsTop) != napi_undefined) {
185 int32_t top;
186 if (!ConvertFromJsValue(env, jsTop, top)) {
187 WLOGFE("[NAPI]Failed to convert parameter to top");
188 return false;
189 }
190 bound.rect_.top_ = top;
191 }
192 if (GetType(env, jsWidth) != napi_undefined) {
193 int32_t width;
194 if (!ConvertFromJsValue(env, jsWidth, width)) {
195 WLOGFE("[NAPI]Failed to convert parameter to width");
196 return false;
197 }
198 bound.rect_.width_ = width;
199 }
200 if (GetType(env, jsHeight) != napi_undefined) {
201 int32_t height;
202 if (!ConvertFromJsValue(env, jsHeight, height)) {
203 WLOGFE("[NAPI]Failed to convert parameter to height");
204 return false;
205 }
206 bound.rect_.height_ = height;
207 }
208 if (GetType(env, jsRadius) != napi_undefined) {
209 int radius;
210 if (!ConvertFromJsValue(env, jsRadius, radius)) {
211 WLOGFE("[NAPI]Failed to convert parameter to radius");
212 return false;
213 }
214 bound.radius_[0].x_ = static_cast<float>(radius);
215 }
216 return true;
217 }
218
ConvertScreenDirectionInfoFromJs(napi_env env,napi_value jsObject,ScreenDirectionInfo & directionInfo)219 bool ConvertScreenDirectionInfoFromJs(napi_env env, napi_value jsObject, ScreenDirectionInfo& directionInfo)
220 {
221 napi_value jsNotifyRotation = nullptr, jsScreenRotation = nullptr, jsRotation = nullptr, jsPhyRotation = nullptr;
222 napi_get_named_property(env, jsObject, "notifyRotation", &jsNotifyRotation);
223 napi_get_named_property(env, jsObject, "screenRotation", &jsScreenRotation);
224 napi_get_named_property(env, jsObject, "rotation", &jsRotation);
225 napi_get_named_property(env, jsObject, "phyRotation", &jsPhyRotation);
226 if (GetType(env, jsNotifyRotation) != napi_undefined) {
227 int32_t notifyRotation;
228 if (!ConvertFromJsValue(env, jsNotifyRotation, notifyRotation)) {
229 WLOGFE("[NAPI]Failed to convert parameter to notifyRotation");
230 return false;
231 }
232 directionInfo.notifyRotation_ = notifyRotation;
233 }
234 if (GetType(env, jsScreenRotation) != napi_undefined) {
235 int32_t screenRotation;
236 if (!ConvertFromJsValue(env, jsScreenRotation, screenRotation)) {
237 WLOGFE("[NAPI]Failed to convert parameter to screenRotation");
238 return false;
239 }
240 directionInfo.screenRotation_ = screenRotation;
241 }
242 if (GetType(env, jsRotation) != napi_undefined) {
243 int32_t rotation;
244 if (!ConvertFromJsValue(env, jsRotation, rotation)) {
245 WLOGFE("[NAPI]Failed to convert parameter to rotation");
246 return false;
247 }
248 directionInfo.rotation_ = rotation;
249 }
250 if (GetType(env, jsPhyRotation) != napi_undefined) {
251 int32_t phyRotation;
252 if (!ConvertFromJsValue(env, jsPhyRotation, phyRotation)) {
253 WLOGFE("[NAPI]Failed to convert parameter to phyRotation");
254 return false;
255 }
256 directionInfo.phyRotation_ = phyRotation;
257 }
258 return true;
259 }
260
ConvertDMRectFromJs(napi_env env,napi_value jsObject,DMRect & rect)261 bool ConvertDMRectFromJs(napi_env env, napi_value jsObject, DMRect& rect)
262 {
263 napi_value jsPosX = nullptr, jsPosY = nullptr, jsWidth = nullptr, jsHeight = nullptr;
264 napi_get_named_property(env, jsObject, "posX", &jsPosX);
265 napi_get_named_property(env, jsObject, "posY", &jsPosY);
266 napi_get_named_property(env, jsObject, "width", &jsWidth);
267 napi_get_named_property(env, jsObject, "height", &jsHeight);
268
269 if (GetType(env, jsPosX) != napi_undefined) {
270 int32_t posX;
271 if (!ConvertFromJsValue(env, jsPosX, posX)) {
272 WLOGFE("[NAPI]Failed to convert parameter to posX");
273 return false;
274 }
275 rect.posX_ = posX;
276 }
277 if (GetType(env, jsPosY) != napi_undefined) {
278 int32_t top;
279 if (!ConvertFromJsValue(env, jsPosY, top)) {
280 WLOGFE("[NAPI]Failed to convert parameter to posY");
281 return false;
282 }
283 rect.posY_ = top;
284 }
285 if (GetType(env, jsWidth) != napi_undefined) {
286 int32_t width;
287 if (!ConvertFromJsValue(env, jsWidth, width)) {
288 WLOGFE("[NAPI]Failed to convert parameter to width");
289 return false;
290 }
291 rect.width_ = static_cast<uint32_t>(width);
292 }
293 if (GetType(env, jsHeight) != napi_undefined) {
294 int32_t height;
295 if (!ConvertFromJsValue(env, jsHeight, height)) {
296 WLOGFE("[NAPI]Failed to convert parameter to height");
297 return false;
298 }
299 rect.height_ = static_cast<uint32_t>(height);
300 }
301 return true;
302 }
303
304
305 struct AsyncInfo {
306 napi_env env;
307 napi_async_work work;
308 std::function<void()> func;
309 };
310
NapiAsyncWork(napi_env env,std::function<void ()> task)311 void NapiAsyncWork(napi_env env, std::function<void()> task)
312 {
313 napi_value resource = nullptr;
314 AsyncInfo* info = new (std::nothrow) AsyncInfo();
315 if (info == nullptr) {
316 TLOGE(WmsLogTag::DMS, "malloc asyncinfo failed");
317 return;
318 }
319 info->env = env;
320 info->func = task;
321 napi_create_string_utf8(env, "DMSAsyncWork", NAPI_AUTO_LENGTH, &resource);
322 napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
323 },
324 [](napi_env env, napi_status status, void* data) {
325 AsyncInfo* info = (AsyncInfo*)data;
326 if (info == nullptr) {
327 TLOGE(WmsLogTag::DMS, "async info is nullptr");
328 return;
329 }
330 info->func();
331 napi_delete_async_work(env, info->work);
332 delete info;
333 }, (void*)info, &info->work);
334 napi_queue_async_work(env, info->work);
335 }
336
MainThreadScheduler(napi_env env)337 MainThreadScheduler::MainThreadScheduler(napi_env env)
338 : env_(env)
339 {
340 GetMainEventHandler();
341 }
342
GetMainEventHandler()343 inline void MainThreadScheduler::GetMainEventHandler()
344 {
345 if (handler_ != nullptr) {
346 return;
347 }
348 auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
349 if (runner == nullptr) {
350 return;
351 }
352 handler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
353 }
354
PostMainThreadTask(Task && localTask,std::string traceInfo,int64_t delayTime)355 void MainThreadScheduler::PostMainThreadTask(Task&& localTask, std::string traceInfo, int64_t delayTime)
356 {
357 GetMainEventHandler();
358 auto task = [env = env_, localTask, traceInfo] () {
359 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "DMS:%s", traceInfo.c_str());
360 napi_handle_scope scope = nullptr;
361 napi_open_handle_scope(env, &scope);
362 localTask();
363 napi_close_handle_scope(env, scope);
364 };
365 if (handler_ && handler_->GetEventRunner()->IsCurrentRunnerThread()) {
366 return task();
367 } else if (handler_ && !handler_->GetEventRunner()->IsCurrentRunnerThread()) {
368 handler_->PostTask(std::move(task), "dms:" + traceInfo, delayTime,
369 OHOS::AppExecFwk::EventQueue::Priority::IMMEDIATE);
370 } else {
371 NapiAsyncWork(env_, task);
372 }
373 }
374 } // namespace OHOS::Rosen
375