• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "interfaces/napi/kits/utils/napi_utils.h"
17 #include "interfaces/napi/kits/display_sync/js_display_sync.h"
18 
19 
20 namespace OHOS::Ace::Napi {
21 constexpr size_t STR_MAX_BUFFER_SIZE = 1024;
22 constexpr size_t CALLBACK_OJECT_NUM = 1;
23 constexpr size_t ARGC_NUM_SIZE = 2;
24 
NapiGetUndefined(napi_env env)25 napi_value NapiGetUndefined(napi_env env)
26 {
27     napi_value result = nullptr;
28     napi_get_undefined(env, &result);
29     return result;
30 }
31 
NapiPrintErrorInfo(napi_env env)32 void NapiPrintErrorInfo(napi_env env)
33 {
34     const napi_extended_error_info *error_info;
35     napi_get_last_error_info(env, &error_info);
36     LOGE("JsDisplaySync ErrorInfo: %{public}s", error_info->error_message);
37     return;
38 }
39 
ParseJsValue(napi_env env,napi_value jsObject,const std::string & name,int32_t & data)40 bool ParseJsValue(napi_env env, napi_value jsObject, const std::string& name, int32_t& data)
41 {
42     napi_value value = nullptr;
43     napi_get_named_property(env, jsObject, name.c_str(), &value);
44     napi_valuetype type = napi_undefined;
45     napi_typeof(env, value, &type);
46     if (type == napi_number) {
47         napi_get_value_int32(env, value, &data);
48         return true;
49     } else {
50         return false;
51     }
52     return true;
53 }
54 
ParseArgs(napi_env & env,napi_callback_info & info,napi_value & thisVar,napi_value & cb,CallbackType & callbackType)55 static size_t ParseArgs(
56     napi_env& env, napi_callback_info& info, napi_value& thisVar, napi_value& cb, CallbackType& callbackType)
57 {
58     size_t argc = ARGC_NUM_SIZE;
59     napi_value argv[ARGC_NUM_SIZE] = { 0 };
60     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
61     NAPI_ASSERT_BASE(env, argc > 0, "too few parameter", 0);
62 
63     napi_valuetype napiType;
64     NAPI_CALL_BASE(env, napi_typeof(env, argv[0], &napiType), 0);
65     NAPI_ASSERT_BASE(env, napiType == napi_string, "parameter 1 should be string", 0);
66     char type[STR_MAX_BUFFER_SIZE] = { 0 };
67     size_t len = 0;
68     napi_get_value_string_utf8(env, argv[0], type, STR_MAX_BUFFER_SIZE, &len);
69     NAPI_ASSERT_BASE(env, len < STR_MAX_BUFFER_SIZE, "condition string too long", 0);
70     NAPI_ASSERT_BASE(
71         env, (strcmp("frame", type) == 0), "type mismatch('frame')", 0);
72     if (strcmp("frame", type) == 0) {
73         callbackType = CallbackType::ONFRAME;
74     } else {
75         callbackType = CallbackType::UNKNOW;
76     }
77 
78     if (argc <= 1) {
79         return argc;
80     }
81 
82     NAPI_CALL_BASE(env, napi_typeof(env, argv[1], &napiType), 0);
83     NAPI_ASSERT_BASE(env, napiType == napi_function, "type mismatch for parameter 2", 0);
84     cb = argv[1];
85     return argc;
86 }
87 
GetDisplaySync(napi_env env,napi_callback_info info)88 DisplaySync* GetDisplaySync(napi_env env, napi_callback_info info)
89 {
90     DisplaySync* displaySync = nullptr;
91     napi_value thisVar = nullptr;
92     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
93     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&displaySync));
94     return displaySync;
95 }
96 
CreateTimeInfoJsObject(const napi_env env,RefPtr<DisplaySyncData> displaySyncData,napi_value & intervalInfo)97 void CreateTimeInfoJsObject(const napi_env env, RefPtr<DisplaySyncData> displaySyncData,
98                             napi_value& intervalInfo)
99 {
100     napi_status status = napi_create_object(env, &intervalInfo);
101     if (status != napi_ok) {
102         NapiPrintErrorInfo(env);
103         return;
104     }
105 
106     napi_value timestamp;
107     napi_value targetTimestamp;
108     napi_create_int64(env, displaySyncData->timestamp_, &timestamp);
109     napi_create_int64(env, displaySyncData->targetTimestamp_, &targetTimestamp);
110     auto resultTimestamp = napi_set_named_property(env, intervalInfo, "timestamp", timestamp);
111     auto resultTargetTimestamp = napi_set_named_property(env, intervalInfo, "targetTimestamp", targetTimestamp);
112     if (resultTimestamp != napi_ok || resultTargetTimestamp != napi_ok) {
113         NapiPrintErrorInfo(env);
114         return;
115     }
116 }
117 
ParseExpectedFrameRateRange(napi_env env,napi_callback_info info,FrameRateRange & frameRateRange)118 napi_value ParseExpectedFrameRateRange(napi_env env, napi_callback_info info, FrameRateRange& frameRateRange)
119 {
120     size_t argc = 1;
121     napi_value argv[1];
122     napi_value thisVar = nullptr;
123     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
124     if (argc != 1) {
125         NapiThrow(env, "The number of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
126         return NapiGetUndefined(env);
127     }
128 
129     napi_value nativeObj = argv[0];
130     if (nativeObj == nullptr) {
131         NapiThrow(env, "The nativeObj is nullptr.", ERROR_CODE_PARAM_INVALID);
132         return NapiGetUndefined(env);
133     }
134 
135     int32_t minFPS = 0;
136     int32_t maxFPS = 0;
137     int32_t expectedFPS = 0;
138     ParseJsValue(env, nativeObj, "min", minFPS);
139     ParseJsValue(env, nativeObj, "max", maxFPS);
140     ParseJsValue(env, nativeObj, "expected", expectedFPS);
141 
142     frameRateRange.Set(minFPS, maxFPS, expectedFPS);
143     if (!frameRateRange.IsValid()) {
144         NapiThrow(env, "ExpectedFrameRateRange Error", ERROR_CODE_PARAM_INVALID);
145         return NapiGetUndefined(env);
146     }
147     return NapiGetUndefined(env);
148 }
149 
JSSetExpectedFrameRateRange(napi_env env,napi_callback_info info)150 napi_value JSSetExpectedFrameRateRange(napi_env env, napi_callback_info info)
151 {
152     FrameRateRange frameRateRange;
153     ParseExpectedFrameRateRange(env, info, frameRateRange);
154 
155     auto displaySync = GetDisplaySync(env, info);
156     if (!displaySync) {
157         TAG_LOGW(AceLogTag::ACE_DISPLAY_SYNC, "JSSetExpectedFrameRateRange: cannot find displaySync.");
158         return NapiGetUndefined(env);
159     }
160     RefPtr<UIDisplaySync> uiDisplaySync = displaySync->GetUIDisplaySync();
161     if (!uiDisplaySync) {
162         TAG_LOGW(AceLogTag::ACE_DISPLAY_SYNC, "JSSetExpectedFrameRateRange: cannot get uiDisplaySync.");
163         return NapiGetUndefined(env);
164     }
165 
166     uiDisplaySync->SetExpectedFrameRateRange(frameRateRange);
167     TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Id: %{public}" PRIu64 " SetExpectedFrameRateRange"
168         "{%{public}d, %{public}d, %{public}d}", uiDisplaySync->GetId(), frameRateRange.min_, frameRateRange.max_,
169         frameRateRange.preferred_);
170     return NapiGetUndefined(env);
171 }
172 
JSStart(napi_env env,napi_callback_info info)173 napi_value JSStart(napi_env env, napi_callback_info info)
174 {
175     auto displaySync = GetDisplaySync(env, info);
176     if (!displaySync) {
177         TAG_LOGW(AceLogTag::ACE_DISPLAY_SYNC, "JSStart: cannot find displaySync.");
178         return NapiGetUndefined(env);
179     }
180     RefPtr<UIDisplaySync> uiDisplaySync = displaySync->GetUIDisplaySync();
181     if (!uiDisplaySync) {
182         TAG_LOGW(AceLogTag::ACE_DISPLAY_SYNC, "JSStart: cannot get uiDisplaySync when starting.");
183         return NapiGetUndefined(env);
184     }
185 
186     uiDisplaySync->AddToPipelineOnContainer();
187     TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Id: %{public}" PRIu64 " Start", uiDisplaySync->GetId());
188     return NapiGetUndefined(env);
189 }
190 
JSStop(napi_env env,napi_callback_info info)191 napi_value JSStop(napi_env env, napi_callback_info info)
192 {
193     auto displaySync = GetDisplaySync(env, info);
194     if (!displaySync) {
195         TAG_LOGW(AceLogTag::ACE_DISPLAY_SYNC, "JSStop: cannot find displaySync.");
196         return NapiGetUndefined(env);
197     }
198     RefPtr<UIDisplaySync> uiDisplaySync = displaySync->GetUIDisplaySync();
199     if (!uiDisplaySync) {
200         TAG_LOGW(AceLogTag::ACE_DISPLAY_SYNC, "JSStop: cannot get uiDisplaySync when stopping.");
201         return NapiGetUndefined(env);
202     }
203 
204     uiDisplaySync->DelFromPipelineOnContainer();
205     TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Id: %{public}" PRIu64 " Stop", uiDisplaySync->GetId());
206     return NapiGetUndefined(env);
207 }
208 
Initialize(napi_env env,napi_value thisVar)209 void DisplaySync::Initialize(napi_env env, napi_value thisVar)
210 {
211     napi_handle_scope scope = nullptr;
212     napi_open_handle_scope(env, &scope);
213     if (!scope) {
214         return;
215     }
216     napi_create_reference(env, thisVar, 1, &thisVarRef_);
217     napi_close_handle_scope(env, scope);
218 }
219 
NapiSerializer(napi_env & env,napi_value & jsDisplaySync)220 void DisplaySync::NapiSerializer(napi_env& env, napi_value& jsDisplaySync)
221 {
222     napi_status status = napi_create_object(env, &jsDisplaySync);
223     if (status != napi_ok) {
224         NapiPrintErrorInfo(env);
225         return;
226     }
227 
228     napi_wrap(
229         env, jsDisplaySync, this,
230         [](napi_env env, void* data, void* hint) {
231             DisplaySync* displaySync = static_cast<DisplaySync*>(data);
232             if (displaySync) {
233                 displaySync->Destroy(env);
234                 delete displaySync;
235             }
236         },
237         nullptr, nullptr);
238 }
239 
RegisterOnFrameCallback(napi_value cb,napi_ref & onFrameRef,CallbackType callbackType,napi_env env)240 void DisplaySync::RegisterOnFrameCallback(napi_value cb, napi_ref& onFrameRef,
241     CallbackType callbackType, napi_env env)
242 {
243     if (onFrameRef) {
244         return;
245     }
246     napi_create_reference(env, cb, 1, &onFrameRef);
247 
248     GetUIDisplaySync()->RegisterOnFrameWithData([env, onFrameRef] (RefPtr<DisplaySyncData> displaySyncData) {
249         napi_handle_scope innerScope = nullptr;
250         napi_status status = napi_open_handle_scope(env, &innerScope);
251         if (status != napi_ok) {
252             NapiPrintErrorInfo(env);
253             return;
254         }
255 
256         napi_value ret = nullptr;
257         napi_value onframe = nullptr;
258         auto result = napi_get_reference_value(env, onFrameRef, &onframe);
259         if (result != napi_ok || onframe == nullptr) {
260             NapiPrintErrorInfo(env);
261             napi_close_handle_scope(env, innerScope);
262             return;
263         }
264 
265         napi_value intervalInfo = nullptr;
266         CreateTimeInfoJsObject(env, displaySyncData, intervalInfo);
267         napi_value args[CALLBACK_OJECT_NUM] = { intervalInfo };
268         napi_call_function(env, nullptr, onframe, CALLBACK_OJECT_NUM, args, &ret);
269         napi_close_handle_scope(env, innerScope);
270     });
271 }
272 
UnregisterOnFrameCallback(napi_env env,size_t argc,napi_ref & onFrameRef)273 void DisplaySync::UnregisterOnFrameCallback(napi_env env, size_t argc, napi_ref& onFrameRef)
274 {
275     if (argc >= 1) {
276         napi_delete_reference(env, onFrameRef);
277         onFrameRef = nullptr;
278         GetUIDisplaySync()->UnregisterOnFrame();
279     }
280     return;
281 }
282 
Destroy(napi_env env)283 void DisplaySync::Destroy(napi_env env)
284 {
285     if (onFrameRef_ != nullptr) {
286         napi_delete_reference(env, onFrameRef_);
287     }
288 
289     if (thisVarRef_ != nullptr) {
290         napi_delete_reference(env, thisVarRef_);
291     }
292 }
293 
JSOnFrame_On(napi_env env,napi_callback_info info)294 napi_value JSOnFrame_On(napi_env env, napi_callback_info info)
295 {
296     napi_value thisVar = nullptr;
297     napi_value cb = nullptr;
298     CallbackType callbackType = CallbackType::UNKNOW;
299     size_t argc = ParseArgs(env, info, thisVar, cb, callbackType);
300     NAPI_ASSERT(env, (argc == ARGC_NUM_SIZE && thisVar != nullptr && cb != nullptr), "Invalid arguments");
301 
302     DisplaySync* displaySync = GetDisplaySync(env, info);
303     if (!displaySync) {
304         return NapiGetUndefined(env);
305     }
306 
307     if (callbackType == CallbackType::ONFRAME) {
308         displaySync->RegisterOnFrameCallback(cb, displaySync->onFrameRef_, callbackType, env);
309     }
310     return NapiGetUndefined(env);
311 }
312 
JSOnFrame_Off(napi_env env,napi_callback_info info)313 napi_value JSOnFrame_Off(napi_env env, napi_callback_info info)
314 {
315     napi_value thisVar = nullptr;
316     napi_value cb = nullptr;
317     CallbackType callbackType = CallbackType::UNKNOW;
318     size_t argc = ParseArgs(env, info, thisVar, cb, callbackType);
319     DisplaySync* displaySync = GetDisplaySync(env, info);
320     if (!displaySync) {
321         return NapiGetUndefined(env);
322     }
323     if (callbackType == CallbackType::ONFRAME) {
324         displaySync->UnregisterOnFrameCallback(env, argc, displaySync->onFrameRef_);
325     }
326     return NapiGetUndefined(env);
327 }
328 
JSCreate(napi_env env,napi_callback_info info)329 static napi_value JSCreate(napi_env env, napi_callback_info info)
330 {
331     auto uiDisplaySync = AceType::MakeRefPtr<UIDisplaySync>();
332     DisplaySync* displaySync = new DisplaySync(uiDisplaySync);
333 
334     napi_value jsDisplaySync = nullptr;
335     displaySync->NapiSerializer(env, jsDisplaySync);
336     if (!jsDisplaySync) {
337         delete displaySync;
338         return nullptr;
339     }
340 
341     napi_property_descriptor resultFuncs[] = {
342         DECLARE_NAPI_FUNCTION("setExpectedFrameRateRange", JSSetExpectedFrameRateRange),
343         DECLARE_NAPI_FUNCTION("on", JSOnFrame_On),
344         DECLARE_NAPI_FUNCTION("off", JSOnFrame_Off),
345         DECLARE_NAPI_FUNCTION("start", JSStart),
346         DECLARE_NAPI_FUNCTION("stop", JSStop),
347     };
348 
349     TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Create UIDisplaySync Id: %{public}" PRIu64 "",
350         uiDisplaySync->GetId());
351     NAPI_CALL(env, napi_define_properties(
352         env, jsDisplaySync, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs));
353     return jsDisplaySync;
354 }
355 
DisplaySyncExport(napi_env env,napi_value exports)356 static napi_value DisplaySyncExport(napi_env env, napi_value exports)
357 {
358     napi_property_descriptor displaySyncDesc[] = {
359         DECLARE_NAPI_FUNCTION("create", JSCreate),
360     };
361     NAPI_CALL(env, napi_define_properties(
362         env, exports, sizeof(displaySyncDesc) / sizeof(displaySyncDesc[0]), displaySyncDesc));
363     return exports;
364 }
365 
366 static napi_module displaySyncModule = {
367     .nm_version = 1,
368     .nm_flags = 0,
369     .nm_filename = nullptr,
370     .nm_register_func = DisplaySyncExport,
371     .nm_modname = "graphics.displaySync",
372     .nm_priv = ((void*)0),
373     .reserved = { 0 },
374 };
375 
DisplaySyncRegister()376 extern "C" __attribute__((constructor)) void DisplaySyncRegister()
377 {
378     napi_module_register(&displaySyncModule);
379 }
380 } // namespace OHOS::Ace::Napi
381