• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <ani.h>
17 #include "core/components_ng/manager/display_sync/ui_display_sync.h"
18 
19 namespace OHOS::Ace::Ani {
20 
21 class DisplaySync final {
22 public:
23     DisplaySync() = delete;
DisplaySync(RefPtr<UIDisplaySync> & uiDisplaySync)24     explicit DisplaySync(RefPtr<UIDisplaySync>& uiDisplaySync)
25         : uiDisplaySync_(uiDisplaySync) {}
26 
~DisplaySync()27     ~DisplaySync()
28     {
29         if (uiDisplaySync_) {
30             uiDisplaySync_->DelFromPipelineOnContainer();
31         }
32     }
33 
GetUIDisplaySync() const34     RefPtr<UIDisplaySync> GetUIDisplaySync() const
35     {
36         return uiDisplaySync_;
37     }
38 
GetOnframeRef() const39     ani_ref GetOnframeRef() const
40     {
41         return onFrameRef_;
42     }
43 
SetOnframeRef(const ani_ref & onframe)44     void SetOnframeRef(const ani_ref& onframe)
45     {
46         onFrameRef_ = onframe;
47     }
48 
49     ani_ref onFrameRef_ = nullptr;
50 
51 private:
52     RefPtr<UIDisplaySync> uiDisplaySync_;
53 };
54 
ANIUtils_ANIStringToStdString(ani_env * env,ani_string ani_str)55 std::string ANIUtils_ANIStringToStdString(ani_env *env, ani_string ani_str)
56 {
57     ani_size strSize;
58     env->String_GetUTF8Size(ani_str, &strSize);
59 
60     std::vector<char> buffer(strSize + 1);
61     char *utf8Buffer = buffer.data();
62 
63     ani_size bytesWritten = 0;
64     env->String_GetUTF8(ani_str, utf8Buffer, strSize + 1, &bytesWritten);
65     utf8Buffer[bytesWritten] = '\0';
66     std::string content = std::string(utf8Buffer);
67     return content;
68 }
69 
ParseExpectedFrameRateRange(ani_env * env,ani_object objOption,FrameRateRange & frameRateRange)70 void ParseExpectedFrameRateRange(ani_env *env, ani_object objOption,
71     FrameRateRange& frameRateRange)
72 {
73     static const char *className = "arkui.component.common.ExpectedFrameRateRange";
74     ani_class cls;
75     if (ANI_OK != env->FindClass(className, &cls)) {
76         return;
77     }
78 
79     ani_boolean isInstance;
80     if (ANI_OK != env->Object_InstanceOf(objOption, cls, &isInstance)) {
81         return;
82     }
83 
84     int32_t minFPS = 0;
85     int32_t maxFPS = 0;
86     int32_t expectedFPS = 0;
87 
88     ani_double minAni;
89     ani_double maxAni;
90     ani_double expectedAni;
91     env->Object_GetPropertyByName_Double(objOption, "min", &minAni);
92     env->Object_GetPropertyByName_Double(objOption, "max", &maxAni);
93     env->Object_GetPropertyByName_Double(objOption, "expected", &expectedAni);
94 
95     minFPS = static_cast<int32_t>(minAni);
96     maxFPS = static_cast<int32_t>(maxAni);
97     expectedFPS = static_cast<int32_t>(expectedAni);
98     frameRateRange.Set(minFPS, maxFPS, expectedFPS);
99 }
100 
GetDisplaySync(ani_env * env,ani_object obj)101 static DisplaySync *GetDisplaySync(ani_env *env, ani_object obj)
102 {
103     ani_long displaySync;
104     if (ANI_OK != env->Object_GetFieldByName_Long(obj, "displaySync", &displaySync)) {
105         return nullptr;
106     }
107     return reinterpret_cast<DisplaySync *>(displaySync);
108 }
109 
GetUIDisplaySync(ani_env * env,ani_object obj)110 static RefPtr<UIDisplaySync> GetUIDisplaySync(ani_env *env, ani_object obj)
111 {
112     auto displaySync = GetDisplaySync(env, obj);
113     if (displaySync == nullptr) {
114         return nullptr;
115     }
116     auto uiDisplaySync = displaySync->GetUIDisplaySync();
117     if (uiDisplaySync == nullptr) {
118         return nullptr;
119     }
120     return uiDisplaySync;
121 }
122 
createIntervalInfo(ani_env * env,int64_t timestamp,int64_t targetTimestamp)123 ani_object createIntervalInfo(ani_env *env, int64_t timestamp, int64_t targetTimestamp)
124 {
125     static const char *className = "@ohos.graphics.displaySync.displaySync.IntervalInfo";
126     ani_class intervalInfo_cls;
127 
128     if (ANI_OK != env->FindClass(className, &intervalInfo_cls))
129     {
130         return nullptr;
131     }
132     ani_method intervalInfoCtor;
133     env->Class_FindMethod(intervalInfo_cls, "<ctor>", "ll:", &intervalInfoCtor);
134     ani_object intervalInfoObj;
135     env->Object_New(
136         intervalInfo_cls, intervalInfoCtor, &intervalInfoObj, ani_long(timestamp), ani_long(targetTimestamp));
137     return intervalInfoObj;
138 }
139 
JSOnFrame_On(ani_env * env,ani_object obj,ani_string callbackType,ani_object callbackObj)140 static void JSOnFrame_On(ani_env *env, ani_object obj, ani_string callbackType, ani_object callbackObj)
141 {
142     if (ANIUtils_ANIStringToStdString(env, callbackType) != "frame") {
143         return;
144     }
145     auto displaySync = GetDisplaySync(env, obj);
146     if (displaySync == nullptr) {
147         return;
148     }
149     if (displaySync->GetOnframeRef()) {
150         return;
151     }
152     auto uiDisplaySync = displaySync->GetUIDisplaySync();
153     if (uiDisplaySync == nullptr) {
154         return;
155     }
156 
157     ani_ref onFrameRef = reinterpret_cast<ani_ref>(callbackObj);
158     ani_ref onFrameGlobalRef;
159     env->GlobalReference_Create(onFrameRef, &onFrameGlobalRef);
160     displaySync->SetOnframeRef(onFrameGlobalRef);
161     uiDisplaySync->RegisterOnFrameWithData([env, onFrameGlobalRef] (RefPtr<DisplaySyncData> displaySyncData) {
162         auto fnObj = reinterpret_cast<ani_fn_object>(onFrameGlobalRef);
163         ani_ref result;
164         auto intervalInfo = createIntervalInfo(env, displaySyncData->timestamp_, displaySyncData->targetTimestamp_);
165         std::vector<ani_ref> tmp = { reinterpret_cast<ani_ref>(intervalInfo) };
166         env->FunctionalObject_Call(fnObj, tmp.size(), tmp.data(), &result);
167     });
168 }
169 
JSOnFrame_Off(ani_env * env,ani_object obj,ani_string callbackType,ani_object callbackObj)170 static void JSOnFrame_Off(ani_env *env, ani_object obj, ani_string callbackType, ani_object callbackObj)
171 {
172     if (ANIUtils_ANIStringToStdString(env, callbackType) != "frame") {
173         return;
174     }
175     auto displaySync = GetDisplaySync(env, obj);
176     if (displaySync == nullptr) {
177         return;
178     }
179     auto uiDisplaySync = displaySync->GetUIDisplaySync();
180     if (uiDisplaySync == nullptr) {
181         return;
182     }
183     displaySync->SetOnframeRef(nullptr);
184     uiDisplaySync->UnregisterOnFrame();
185 }
186 
JSStart(ani_env * env,ani_object obj)187 static void JSStart(ani_env *env, ani_object obj) {
188     if (auto uiDisplaySync = GetUIDisplaySync(env, obj); uiDisplaySync != nullptr) {
189         uiDisplaySync->AddToPipelineOnContainer();
190     }
191 }
192 
JSStop(ani_env * env,ani_object obj)193 static void JSStop(ani_env *env, ani_object obj) {
194     if (auto uiDisplaySync = GetUIDisplaySync(env, obj); uiDisplaySync != nullptr) {
195         uiDisplaySync->DelFromPipelineOnContainer();
196     }
197 }
198 
JSSetExpectedFrameRateRange(ani_env * env,ani_object obj,ani_object objOption)199 static void JSSetExpectedFrameRateRange(ani_env *env, ani_object obj, ani_object objOption)
200 {
201     if (auto uiDisplaySync = GetUIDisplaySync(env, obj); uiDisplaySync != nullptr) {
202         FrameRateRange frameRateRange;
203         ParseExpectedFrameRateRange(env, objOption, frameRateRange);
204         uiDisplaySync->SetExpectedFrameRateRange(frameRateRange);
205     }
206 }
207 
ANICreate(ani_env * env,ani_object object,ani_object aniOption)208 ani_object ANICreate(ani_env *env, [[maybe_unused]] ani_object object, [[maybe_unused]] ani_object aniOption)
209 {
210     ani_object displaySync_obj = {};
211     static const char *className = "@ohos.graphics.displaySync.displaySync.DisplaySync";
212     ani_class cls;
213     if (ANI_OK != env->FindClass(className, &cls)) {
214         TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[ANI] find class fail");
215         return displaySync_obj;
216     }
217 
218     ani_method ctor;
219     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
220         TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[ANI] find method fail");
221         return displaySync_obj;
222     }
223 
224     auto uiDisplaySync = AceType::MakeRefPtr<UIDisplaySync>();
225     DisplaySync* displaySync = new DisplaySync(uiDisplaySync);
226     if (ANI_OK != env->Object_New(cls, ctor, &displaySync_obj, reinterpret_cast<ani_long>(displaySync))) {
227         TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[ANI] create displaySync fail");
228         delete displaySync;
229         return displaySync_obj;
230     }
231     return displaySync_obj;
232 }
233 
clean(ani_env * env,ani_object object)234 static void clean([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object) {
235     ani_long ptr;
236     if (ANI_OK != env->Object_GetFieldByName_Long(object, "ptr", &ptr)) {
237         return;
238     }
239     delete reinterpret_cast<DisplaySync *>(ptr);
240 }
241 
242 
BindDisplaySync(ani_env * env)243 ani_status BindDisplaySync(ani_env *env)
244 {
245     static const char *className = "@ohos.graphics.displaySync.displaySync.DisplaySync";
246     ani_class cls;
247     if (ANI_OK != env->FindClass(className, &cls)) {
248         TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[ANI] bind DisplaySync result fail");
249         return ANI_ERROR;
250     }
251 
252     std::array methods = {
253         ani_native_function{"on", nullptr, reinterpret_cast<void *>(JSOnFrame_On)},
254         ani_native_function{"off", nullptr, reinterpret_cast<void *>(JSOnFrame_Off)},
255         ani_native_function{"start", ":", reinterpret_cast<void *>(JSStart)},
256         ani_native_function{"stop", ":", reinterpret_cast<void *>(JSStop)},
257         ani_native_function{"setExpectedFrameRateRange", nullptr,
258             reinterpret_cast<void *>(JSSetExpectedFrameRateRange)},
259     };
260     if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
261         TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[ANI] bind native method fail");
262         return ANI_ERROR;
263     };
264 
265     static const char *cleanerName = "@ohos.graphics.displaySync.displaySync.Cleaner";
266     ani_class cleanerCls;
267     if (ANI_OK != env->FindClass(cleanerName, &cleanerCls)) {
268         return (ani_status)ANI_ERROR;
269     }
270 
271     std::array cleanerMethods = {
272         ani_native_function {"clean", nullptr, reinterpret_cast<void *>(clean) },
273     };
274 
275     if (ANI_OK != env->Class_BindNativeMethods(cleanerCls, cleanerMethods.data(), cleanerMethods.size())) {
276         return (ani_status)ANI_ERROR;
277     };
278     return ANI_OK;
279 }
280 }  // namespace OHOS::Ace::Ani
281 
ANI_Constructor(ani_vm * vm,uint32_t * result)282 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
283 {
284     ani_env *env;
285     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
286         return ANI_ERROR;
287     }
288     ani_namespace displaySyncNamespace;
289     if (ANI_OK != env->FindNamespace("@ohos.graphics.displaySync.displaySync", &displaySyncNamespace)) {
290         return ANI_ERROR;
291     }
292     std::array staticMethods = {
293         ani_native_function {"create", nullptr,
294             reinterpret_cast<void *>(OHOS::Ace::Ani::ANICreate)},
295     };
296     if (ANI_OK != env->Namespace_BindNativeFunctions(
297         displaySyncNamespace, staticMethods.data(), staticMethods.size())) {
298         return ANI_ERROR;
299     };
300 
301     ani_status retBindResult = OHOS::Ace::Ani::BindDisplaySync(env);
302     if (retBindResult != ANI_OK) {
303         TAG_LOGE(OHOS::Ace::AceLogTag::ACE_DISPLAY_SYNC, "[ANI] BindDisplaySyncResult fail");
304         return retBindResult;
305     }
306     *result = ANI_VERSION_1;
307     return ANI_OK;
308 }
309