• 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 
16 #include "js_screen.h"
17 
18 #include <cinttypes>
19 #include <hitrace_meter.h>
20 
21 #include "screen.h"
22 #include "screen_info.h"
23 #include "window_manager_hilog.h"
24 #ifdef XPOWER_EVENT_ENABLE
25 #include "xpower_event_js.h"
26 #endif // XPOWER_EVENT_ENABLE
27 
28 namespace OHOS {
29 namespace Rosen {
30 using namespace AbilityRuntime;
31 constexpr size_t ARGC_ONE = 1;
32 constexpr size_t ARGC_TWO = 2;
33 namespace {
34 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "JsScreen"};
35 }
36 
37 static thread_local std::map<ScreenId, std::shared_ptr<NativeReference>> g_JsScreenMap;
38 std::recursive_mutex g_mutex;
39 
JsScreen(const sptr<Screen> & screen)40 JsScreen::JsScreen(const sptr<Screen>& screen) : screen_(screen)
41 {
42 }
43 
~JsScreen()44 JsScreen::~JsScreen()
45 {
46     WLOGI("JsScreen::~JsScreen is called");
47 }
48 
Finalizer(napi_env env,void * data,void * hint)49 void JsScreen::Finalizer(napi_env env, void* data, void* hint)
50 {
51     WLOGI("JsScreen::Finalizer is called");
52     auto jsScreen = std::unique_ptr<JsScreen>(static_cast<JsScreen*>(data));
53     if (jsScreen == nullptr) {
54         WLOGFE("jsScreen::Finalizer jsScreen is null");
55         return;
56     }
57     sptr<Screen> screen = jsScreen->screen_;
58     if (screen == nullptr) {
59         WLOGFE("JsScreen::Finalizer screen is null");
60         return;
61     }
62     ScreenId screenId = screen->GetId();
63     WLOGI("JsScreen::Finalizer screenId : %{public}" PRIu64"", screenId);
64     std::lock_guard<std::recursive_mutex> lock(g_mutex);
65     if (g_JsScreenMap.find(screenId) != g_JsScreenMap.end()) {
66         WLOGI("JsScreen::Finalizer screen is destroyed: %{public}" PRIu64"", screenId);
67         g_JsScreenMap.erase(screenId);
68     }
69 }
70 
SetOrientation(napi_env env,napi_callback_info info)71 napi_value JsScreen::SetOrientation(napi_env env, napi_callback_info info)
72 {
73     JsScreen* me = CheckParamsAndGetThis<JsScreen>(env, info);
74     return (me != nullptr) ? me->OnSetOrientation(env, info) : nullptr;
75 }
76 
NapiGetUndefined(napi_env env)77 napi_value NapiGetUndefined(napi_env env)
78 {
79     napi_value result = nullptr;
80     napi_get_undefined(env, &result);
81     return result;
82 }
83 
GetType(napi_env env,napi_value value)84 napi_valuetype GetType(napi_env env, napi_value value)
85 {
86     napi_valuetype res = napi_undefined;
87     napi_typeof(env, value, &res);
88     return res;
89 }
90 
OnSetOrientation(napi_env env,napi_callback_info info)91 napi_value JsScreen::OnSetOrientation(napi_env env, napi_callback_info info)
92 {
93     WLOGI("OnSetOrientation is called");
94     bool paramValidFlag = true;
95     Orientation orientation = Orientation::UNSPECIFIED;
96     size_t argc = 4;
97     napi_value argv[4] = {nullptr};
98     std::string errMsg = "";
99     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
100     if (argc < ARGC_ONE) {
101         WLOGFE("OnSetOrientation Params not match, info argc: %{public}zu", argc);
102         errMsg = "Invalid args count, need one arg at least!";
103         paramValidFlag = false;
104     } else if (!ConvertFromJsValue(env, argv[0], orientation)) {
105         paramValidFlag = false;
106         WLOGFE("Failed to convert parameter to orientation");
107         errMsg = "Failed to convert parameter to orientation";
108     }
109     if (!paramValidFlag) {
110         WLOGE("OnSetOrientation paramValidFlag error");
111         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
112         return NapiGetUndefined(env);
113     }
114     if (orientation < Orientation::BEGIN || orientation > Orientation::END) {
115         WLOGE("Orientation param error! orientation value must from enum Orientation");
116         errMsg = "orientation value must from enum Orientation";
117         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
118         return NapiGetUndefined(env);
119     }
120     napi_value lastParam = nullptr;
121     if (argc >= ARGC_TWO && argv[ARGC_TWO - 1] != nullptr &&
122         GetType(env, argv[ARGC_TWO - 1]) == napi_function) {
123         lastParam = argv[ARGC_TWO - 1];
124     }
125     napi_value result = nullptr;
126     std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
127     auto asyncTask = [this, orientation, env, task = napiAsyncTask.get()]() {
128         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreen::OnSetOrientation");
129         DmErrorCode ret = DM_JS_TO_ERROR_CODE_MAP.at(screen_->SetOrientation(orientation));
130         if (ret == DmErrorCode::DM_OK) {
131             task->Resolve(env, NapiGetUndefined(env));
132             WLOGI("OnSetOrientation success");
133         } else {
134             task->Reject(env, CreateJsError(env, static_cast<int32_t>(ret), "JsScreen::OnSetOrientation failed."));
135             WLOGFE("OnSetOrientation failed");
136         }
137         delete task;
138     };
139     NapiSendDmsEvent(env, asyncTask, napiAsyncTask);
140     return result;
141 }
142 
SetScreenActiveMode(napi_env env,napi_callback_info info)143 napi_value JsScreen::SetScreenActiveMode(napi_env env, napi_callback_info info)
144 {
145     WLOGI("SetScreenActiveMode is called");
146     JsScreen* me = CheckParamsAndGetThis<JsScreen>(env, info);
147 #ifdef XPOWER_EVENT_ENABLE
148     if (me != nullptr) {
149         HiviewDFX::ReportXPowerJsStackSysEvent(env, "EPS_LCD_FREQ");
150     }
151 #endif // XPOWER_EVENT_ENABLE
152     return (me != nullptr) ? me->OnSetScreenActiveMode(env, info) : nullptr;
153 }
154 
OnSetScreenActiveMode(napi_env env,napi_callback_info info)155 napi_value JsScreen::OnSetScreenActiveMode(napi_env env, napi_callback_info info)
156 {
157     WLOGI("OnSetScreenActiveMode is called");
158     bool paramValidFlag = true;
159     uint32_t modeId = 0;
160     size_t argc = 4;
161     napi_value argv[4] = {nullptr};
162     std::string errMsg = "";
163     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
164     if (argc < ARGC_ONE) {
165         WLOGFE("OnSetScreenActiveMode Params not match %{public}zu", argc);
166         errMsg = "Invalid args count, need one arg at least!";
167         paramValidFlag = false;
168     } else {
169         if (!ConvertFromJsValue(env, argv[0], modeId)) {
170             WLOGFE("Failed to convert parameter to modeId");
171             errMsg = "Failed to convert parameter to modeId";
172             paramValidFlag = false;
173         }
174     }
175     if (!paramValidFlag) {
176         WLOGFE("OnSetScreenActiveMode paramValidFlag error");
177         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
178         return NapiGetUndefined(env);
179     }
180     napi_value lastParam = nullptr;
181     if (argc >= ARGC_TWO && argv[ARGC_TWO - 1] != nullptr &&
182         GetType(env, argv[ARGC_TWO - 1]) == napi_function) {
183         lastParam = argv[ARGC_TWO - 1];
184     }
185     napi_value result = nullptr;
186     std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
187     auto asyncTask = [this, modeId, env, task = napiAsyncTask.get()]() {
188         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreen::OnSetScreenActiveMode");
189         DmErrorCode ret = DM_JS_TO_ERROR_CODE_MAP.at(screen_->SetScreenActiveMode(modeId));
190         if (ret == DmErrorCode::DM_OK) {
191             task->Resolve(env, NapiGetUndefined(env));
192             WLOGI("OnSetScreenActiveMode success");
193         } else {
194             task->Reject(env, CreateJsError(env, static_cast<int32_t>(ret),
195                                             "JsScreen::OnSetScreenActiveMode failed."));
196             WLOGFE("OnSetScreenActiveMode failed");
197         }
198         delete task;
199     };
200     NapiSendDmsEvent(env, asyncTask, napiAsyncTask);
201     return result;
202 }
203 
SetDensityDpi(napi_env env,napi_callback_info info)204 napi_value JsScreen::SetDensityDpi(napi_env env, napi_callback_info info)
205 {
206     WLOGI("SetDensityDpi is called");
207     JsScreen* me = CheckParamsAndGetThis<JsScreen>(env, info);
208     return (me != nullptr) ? me->OnSetDensityDpi(env, info) : nullptr;
209 }
210 
OnSetDensityDpi(napi_env env,napi_callback_info info)211 napi_value JsScreen::OnSetDensityDpi(napi_env env, napi_callback_info info)
212 {
213     WLOGI("OnSetDensityDpi is called");
214     bool paramValidFlag = true;
215     uint32_t densityDpi = 0;
216     size_t argc = 4;
217     std::string errMsg = "";
218     napi_value argv[4] = {nullptr};
219     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
220     if (argc < ARGC_ONE) {
221         WLOGFE("OnSetDensityDpi Params not match %{public}zu", argc);
222         errMsg = "Invalid args count, need one arg at least!";
223         paramValidFlag = false;
224     } else {
225         if (!ConvertFromJsValue(env, argv[0], densityDpi)) {
226             WLOGFE("Failed to convert parameter to densityDpi");
227             errMsg = "Failed to convert parameter to densityDpi";
228             paramValidFlag = false;
229         }
230     }
231     if (!paramValidFlag) {
232         WLOGFE("OnSetDensityDpi paramValidFlag error");
233         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
234         return NapiGetUndefined(env);
235     }
236     napi_value lastParam = nullptr;
237     if (argc >= ARGC_TWO && argv[ARGC_TWO - 1] != nullptr &&
238         GetType(env, argv[ARGC_TWO - 1]) == napi_function) {
239         lastParam = argv[ARGC_TWO - 1];
240     }
241     napi_value result = nullptr;
242     std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
243     auto asyncTask = [this, densityDpi, env, task = napiAsyncTask.get()]() {
244         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreen::OnSetDensityDpi");
245         DmErrorCode ret = DM_JS_TO_ERROR_CODE_MAP.at(screen_->SetDensityDpi(densityDpi));
246         if (ret == DmErrorCode::DM_OK) {
247             task->Resolve(env, NapiGetUndefined(env));
248             WLOGI("OnSetDensityDpi success");
249         } else {
250             task->Reject(env, CreateJsError(env, static_cast<int32_t>(ret),
251                                             "JsScreen::OnSetDensityDpi failed."));
252             WLOGFE("OnSetDensityDpi failed");
253         }
254         delete task;
255     };
256     NapiSendDmsEvent(env, asyncTask, napiAsyncTask);
257     return result;
258 }
259 
NapiSendDmsEvent(napi_env env,std::function<void ()> asyncTask,std::unique_ptr<AbilityRuntime::NapiAsyncTask> & napiAsyncTask)260 void JsScreen::NapiSendDmsEvent(napi_env env, std::function<void()> asyncTask,
261     std::unique_ptr<AbilityRuntime::NapiAsyncTask>& napiAsyncTask)
262 {
263     if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
264         napiAsyncTask->Reject(env, CreateJsError(env,
265                 static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_SCREEN), "Send event failed!"));
266     } else {
267         napiAsyncTask.release();
268         WLOGFE("send event success");
269     }
270 }
271 
FindJsDisplayObject(ScreenId screenId)272 std::shared_ptr<NativeReference> FindJsDisplayObject(ScreenId screenId)
273 {
274     WLOGD("[NAPI]Try to find screen %{public}" PRIu64" in g_JsScreenMap", screenId);
275     std::lock_guard<std::recursive_mutex> lock(g_mutex);
276     if (g_JsScreenMap.find(screenId) == g_JsScreenMap.end()) {
277         WLOGI("[NAPI]Can not find screen %{public}" PRIu64" in g_JsScreenMap", screenId);
278         return nullptr;
279     }
280     return g_JsScreenMap[screenId];
281 }
282 
CreateJsScreenObject(napi_env env,sptr<Screen> & screen)283 napi_value CreateJsScreenObject(napi_env env, sptr<Screen>& screen)
284 {
285     WLOGD("JsScreen::CreateJsScreen is called");
286     napi_value objValue = nullptr;
287     std::shared_ptr<NativeReference> jsScreenObj = FindJsDisplayObject(screen->GetId());
288     if (jsScreenObj != nullptr && jsScreenObj->GetNapiValue() != nullptr) {
289         WLOGI("[NAPI]FindJsScreenObject %{public}" PRIu64"", screen->GetId());
290         objValue = jsScreenObj->GetNapiValue();
291     }
292     if (objValue == nullptr) {
293         napi_create_object(env, &objValue);
294     }
295     if (objValue == nullptr) {
296         WLOGFE("Failed to convert prop to jsObject");
297         return NapiGetUndefined(env);
298     }
299     std::unique_ptr<JsScreen> jsScreen = std::make_unique<JsScreen>(screen);
300     napi_wrap(env, objValue, jsScreen.release(), JsScreen::Finalizer, nullptr, nullptr);
301     auto info = screen->GetScreenInfo();
302     if (info == nullptr) {
303         WLOGFE("Failed to GetScreenInfo");
304         return NapiGetUndefined(env);
305     }
306     ScreenId screenId = info->GetScreenId();
307     napi_set_named_property(env, objValue, "id",
308         CreateJsValue(env, screenId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(screenId)));
309     ScreenId parentId = info->GetParentId();
310     napi_set_named_property(env, objValue, "parent",
311         CreateJsValue(env, parentId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(parentId)));
312     napi_set_named_property(env, objValue, "orientation", CreateJsValue(env, info->GetOrientation()));
313     napi_set_named_property(env, objValue, "serialNumber", CreateJsValue(env, info->GetSerialNumber()));
314     napi_set_named_property(env, objValue, "sourceMode", CreateJsValue(env, info->GetSourceMode()));
315     napi_set_named_property(env, objValue, "activeModeIndex", CreateJsValue(env, info->GetModeId()));
316     napi_set_named_property(env, objValue, "supportedModeInfo", CreateJsScreenModeArrayObject(env, info->GetModes()));
317     napi_set_named_property(env, objValue, "densityDpi", CreateJsValue(env,
318         static_cast<uint32_t>(info->GetVirtualPixelRatio() * DOT_PER_INCH))); // Dpi = Density(VPR) * 160.
319     if (jsScreenObj == nullptr || jsScreenObj->GetNapiValue() == nullptr) {
320         std::shared_ptr<NativeReference> JsScreenRef;
321         napi_ref result = nullptr;
322         napi_create_reference(env, objValue, 1, &result);
323         JsScreenRef.reset(reinterpret_cast<NativeReference*>(result));
324         std::lock_guard<std::recursive_mutex> lock(g_mutex);
325         g_JsScreenMap[screenId] = JsScreenRef;
326         const char *moduleName = "JsScreen";
327         BindNativeFunction(env, objValue, "setScreenActiveMode", moduleName, JsScreen::SetScreenActiveMode);
328         BindNativeFunction(env, objValue, "setOrientation", moduleName, JsScreen::SetOrientation);
329         BindNativeFunction(env, objValue, "setDensityDpi", moduleName, JsScreen::SetDensityDpi);
330     }
331     return objValue;
332 }
333 
CreateJsScreenModeArrayObject(napi_env env,std::vector<sptr<SupportedScreenModes>> screenModes)334 napi_value CreateJsScreenModeArrayObject(napi_env env, std::vector<sptr<SupportedScreenModes>> screenModes)
335 {
336     napi_value arrayValue = nullptr;
337     napi_create_array_with_length(env, screenModes.size(), &arrayValue);
338     size_t i = 0;
339     for (const auto& mode : screenModes) {
340         napi_set_element(env, arrayValue, i++, CreateJsScreenModeObject(env, mode));
341     }
342     return arrayValue;
343 }
344 
CreateJsScreenModeObject(napi_env env,const sptr<SupportedScreenModes> & mode)345 napi_value CreateJsScreenModeObject(napi_env env, const sptr<SupportedScreenModes>& mode)
346 {
347     WLOGD("JsScreen::CreateJsScreenMode is called");
348     napi_value objValue = nullptr;
349     napi_create_object(env, &objValue);
350     if (objValue == nullptr) {
351         WLOGFE("Failed to convert prop to jsObject");
352         return NapiGetUndefined(env);
353     }
354     uint32_t id = mode->id_;
355     uint32_t width = mode->width_;
356     uint32_t height = mode->height_;
357     uint32_t refreshRate = mode->refreshRate_;
358     napi_set_named_property(env, objValue, "id", CreateJsValue(env, id));
359     napi_set_named_property(env, objValue, "width", CreateJsValue(env, width));
360     napi_set_named_property(env, objValue, "height", CreateJsValue(env, height));
361     napi_set_named_property(env, objValue, "refreshRate", CreateJsValue(env, refreshRate));
362     return objValue;
363 }
364 }  // namespace Rosen
365 }  // namespace OHOS
366