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_uieffect.h"
17 namespace OHOS {
18 namespace Rosen {
BindVisualEffectMethod(ani_env * env)19 ani_status AniEffect::BindVisualEffectMethod(ani_env* env)
20 {
21 static const char* visualEffectClassName = "L@ohos/graphics/uiEffect/uiEffect/VisualEffectInternal;";
22 ani_class visualEffectClass;
23 if (env->FindClass(visualEffectClassName, &visualEffectClass) != ANI_OK) {
24 UIEFFECT_LOG_E("Not found %{public}s", visualEffectClassName);
25 return ANI_NOT_FOUND;
26 };
27 std::array visualEffectMethods = {
28 ani_native_function { "backgroundColorBlenderNative",
29 "L@ohos/graphics/uiEffect/uiEffect/BrightnessBlender;:L@ohos/graphics/uiEffect/uiEffect/VisualEffect;",
30 reinterpret_cast<void*>(OHOS::Rosen::AniEffect::BackgroundColorBlender) },
31 };
32 ani_status ret = env->Class_BindNativeMethods(visualEffectClass,
33 visualEffectMethods.data(), visualEffectMethods.size());
34 if (ret != ANI_OK) {
35 UIEFFECT_LOG_E("Class_BindNativeMethods failed: %{public}d", ret);
36 return ANI_ERROR;
37 };
38 return ret;
39 }
40
BindFilterMethod(ani_env * env)41 ani_status AniEffect::BindFilterMethod(ani_env* env)
42 {
43 static const char* filterClassName = "L@ohos/graphics/uiEffect/uiEffect/FilterInternal;";
44 ani_class filterClass;
45 if (env->FindClass(filterClassName, &filterClass) != ANI_OK) {
46 UIEFFECT_LOG_E("Not found %{public}s", filterClassName);
47 return ANI_NOT_FOUND;
48 };
49 std::array filterMethods = {
50 ani_native_function { "pixelStretchNative", nullptr,
51 reinterpret_cast<void*>(OHOS::Rosen::AniEffect::PixelStretch) },
52 ani_native_function { "blurNative", nullptr,
53 reinterpret_cast<void*>(OHOS::Rosen::AniEffect::Blur) },
54 };
55 ani_status ret = env->Class_BindNativeMethods(filterClass, filterMethods.data(), filterMethods.size());
56 if (ret != ANI_OK) {
57 UIEFFECT_LOG_E("Class_BindNativeMethods failed: %{public}d", ret);
58 return ANI_ERROR;
59 };
60 return ret;
61 }
62
CreateAniObject(ani_env * env,std::string name,const char * signature,ani_long addr)63 ani_object AniEffect::CreateAniObject(ani_env* env, std::string name, const char* signature, ani_long addr)
64 {
65 ani_class cls;
66 if (env->FindClass(name.c_str(), &cls) != ANI_OK) {
67 UIEFFECT_LOG_E("not found '%{public}s'", name.c_str());
68 return {};
69 };
70 ani_method ctor;
71 if (env->Class_FindMethod(cls, "<ctor>", signature, &ctor) != ANI_OK) {
72 UIEFFECT_LOG_E("get ctor failed '%{public}s'", name.c_str());
73 return {};
74 };
75 ani_object obj = {};
76 if (env->Object_New(cls, ctor, &obj, addr) != ANI_OK) {
77 UIEFFECT_LOG_E("create object failed '%{public}s'", name.c_str());
78 return obj;
79 };
80 UIEFFECT_LOG_I("create object success '%{public}s'", name.c_str());
81 return obj;
82 }
83
CheckCreateBrightnessBlender(ani_env * env,ani_object para_obj,ani_object & blender_obj)84 bool CheckCreateBrightnessBlender(ani_env* env, ani_object para_obj, ani_object& blender_obj)
85 {
86 ani_double cubicRateAni;
87 ani_double quadraticRateAni;
88 ani_double linearRateAni;
89 ani_double degreeAni;
90 ani_double saturationAni;
91 ani_double fractionAni;
92 ani_ref positiveCoefficientAni;
93 ani_ref negativeCoefficientAni;
94 if ((env->Object_GetPropertyByName_Double(para_obj, "cubicRate", &cubicRateAni) != ANI_OK) ||
95 (env->Object_GetPropertyByName_Double(para_obj, "quadraticRate", &quadraticRateAni) != ANI_OK) ||
96 (env->Object_GetPropertyByName_Double(para_obj, "linearRate", &linearRateAni) != ANI_OK) ||
97 (env->Object_GetPropertyByName_Double(para_obj, "degree", °reeAni) != ANI_OK) ||
98 (env->Object_GetPropertyByName_Double(para_obj, "saturation", &saturationAni) != ANI_OK) ||
99 (env->Object_GetPropertyByName_Double(para_obj, "fraction", &fractionAni) != ANI_OK) ||
100 (env->Object_GetPropertyByName_Ref(para_obj, "positiveCoefficient", &positiveCoefficientAni) != ANI_OK) ||
101 (env->Object_GetPropertyByName_Ref(para_obj, "negativeCoefficient", &negativeCoefficientAni) != ANI_OK)) {
102 UIEFFECT_LOG_E("Input para is not BrightnessBlenderParam, some property cannot be found");
103 return false;
104 };
105 if ((env->Object_SetPropertyByName_Double(blender_obj, "cubicRate", cubicRateAni) != ANI_OK) ||
106 (env->Object_SetPropertyByName_Double(blender_obj, "quadraticRate", quadraticRateAni) != ANI_OK) ||
107 (env->Object_SetPropertyByName_Double(blender_obj, "linearRate", linearRateAni) != ANI_OK) ||
108 (env->Object_SetPropertyByName_Double(blender_obj, "degree", degreeAni) != ANI_OK) ||
109 (env->Object_SetPropertyByName_Double(blender_obj, "saturation", saturationAni) != ANI_OK) ||
110 (env->Object_SetPropertyByName_Double(blender_obj, "fraction", fractionAni) != ANI_OK) ||
111 (env->Object_SetPropertyByName_Ref(blender_obj, "positiveCoefficient", positiveCoefficientAni) != ANI_OK) ||
112 (env->Object_SetPropertyByName_Ref(blender_obj, "negativeCoefficient", negativeCoefficientAni) != ANI_OK)) {
113 UIEFFECT_LOG_E("Cannot set all property for BrightnessBlender, some property cannot be found");
114 return false;
115 };
116 return true;
117 }
118
ParseBrightnessBlender(ani_env * env,ani_object para_obj,std::unique_ptr<BrightnessBlender> & blender)119 void AniEffect::ParseBrightnessBlender(ani_env* env, ani_object para_obj, std::unique_ptr<BrightnessBlender>& blender)
120 {
121 ani_double cubicRateAni;
122 ani_double quadraticRateAni;
123 ani_double linearRateAni;
124 ani_double degreeAni;
125 ani_double saturationAni;
126 ani_double fractionAni;
127 ani_ref positiveCoefficientAni;
128 ani_ref negativeCoefficientAni;
129 env->Object_GetPropertyByName_Double(para_obj, "cubicRate", &cubicRateAni);
130 env->Object_GetPropertyByName_Double(para_obj, "quadraticRate", &quadraticRateAni);
131 env->Object_GetPropertyByName_Double(para_obj, "linearRate", &linearRateAni);
132 env->Object_GetPropertyByName_Double(para_obj, "degree", °reeAni);
133 env->Object_GetPropertyByName_Double(para_obj, "saturation", &saturationAni);
134 env->Object_GetPropertyByName_Double(para_obj, "fraction", &fractionAni);
135 env->Object_GetPropertyByName_Ref(para_obj, "positiveCoefficient", &positiveCoefficientAni);
136 env->Object_GetPropertyByName_Ref(para_obj, "negativeCoefficient", &negativeCoefficientAni);
137 const auto positiveCoefficientAniArray = reinterpret_cast<ani_array_double>(positiveCoefficientAni);
138 const auto negativeCoefficientAniArray = reinterpret_cast<ani_array_double>(negativeCoefficientAni);
139 ani_double posCoefNativeBuffer[3U] = { 0.0 };
140 ani_double negCoefNativeBuffer[3U] = { 0.0 };
141 const ani_size offset = 0;
142 const ani_size len = 3;
143 env->Array_GetRegion_Double(positiveCoefficientAniArray, offset, len, posCoefNativeBuffer);
144 env->Array_GetRegion_Double(negativeCoefficientAniArray, offset, len, negCoefNativeBuffer);
145 const int xIndex = 0;
146 const int yIndex = 1;
147 const int zIndex = 2;
148 Vector3f posCoefNative(posCoefNativeBuffer[xIndex], posCoefNativeBuffer[yIndex], posCoefNativeBuffer[zIndex]);
149 Vector3f negCoefNative(negCoefNativeBuffer[xIndex], negCoefNativeBuffer[yIndex], negCoefNativeBuffer[zIndex]);
150 blender->SetCubicRate(static_cast<float>(cubicRateAni));
151 blender->SetQuadRate(static_cast<float>(quadraticRateAni));
152 blender->SetLinearRate(static_cast<float>(linearRateAni));
153 blender->SetDegree(static_cast<float>(degreeAni));
154 blender->SetSaturation(static_cast<float>(saturationAni));
155 blender->SetFraction(static_cast<float>(fractionAni));
156 blender->SetPositiveCoeff(posCoefNative);
157 blender->SetNegativeCoeff(negCoefNative);
158 }
159
CreateEffect(ani_env * env)160 ani_object AniEffect::CreateEffect(ani_env* env)
161 {
162 auto effectObj = std::make_unique<VisualEffect>();
163 auto retVal = CreateAniObject(env, ANI_UIEFFECT_VISUAL_EFFECT, nullptr,
164 reinterpret_cast<ani_long>(effectObj.release()));
165 return retVal;
166 }
167
CreateBrightnessBlender(ani_env * env,ani_object para)168 ani_object AniEffect::CreateBrightnessBlender(ani_env* env, ani_object para)
169 {
170 ani_object retVal {};
171 ani_class cls;
172 if (env->FindClass(ANI_UIEFFECT_BRIGHTNESS_BLENDER.c_str(), &cls) != ANI_OK) {
173 UIEFFECT_LOG_E("not found '%{public}s'", ANI_UIEFFECT_BRIGHTNESS_BLENDER.c_str());
174 return {};
175 }
176 ani_method ctor;
177 if (env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor) != ANI_OK) {
178 UIEFFECT_LOG_E("get ctor failed '%{public}s'", ANI_UIEFFECT_BRIGHTNESS_BLENDER.c_str());
179 return {};
180 }
181 if (env->Object_New(cls, ctor, &retVal) != ANI_OK) {
182 UIEFFECT_LOG_E("create object failed '%{public}s'", ANI_UIEFFECT_BRIGHTNESS_BLENDER.c_str());
183 return {};
184 }
185 auto brightnessObj = std::make_unique<BrightnessBlender>();
186 retVal = CreateAniObject(env, ANI_UIEFFECT_BRIGHTNESS_BLENDER, nullptr,
187 reinterpret_cast<ani_long>(brightnessObj.release()));
188 if (!CheckCreateBrightnessBlender(env, para, retVal)) {
189 UIEFFECT_LOG_E("EffectNapi CheckCreateBrightnessBlender failed.");
190 return {};
191 }
192 return retVal;
193 }
194
CreateHdrBrightnessBlender(ani_env * env,ani_object para)195 ani_object AniEffect::CreateHdrBrightnessBlender(ani_env* env, ani_object para)
196 {
197 ani_object retVal {};
198 ani_class cls;
199 if (env->FindClass(ANI_UIEFFECT_HDRBRIGHTNESS_BLENDER.c_str(), &cls) != ANI_OK) {
200 UIEFFECT_LOG_E("not found '%{public}s'", ANI_UIEFFECT_HDRBRIGHTNESS_BLENDER.c_str());
201 return {};
202 };
203 ani_method ctor;
204 if (env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor) != ANI_OK) {
205 UIEFFECT_LOG_E("get ctor failed '%{public}s'", ANI_UIEFFECT_HDRBRIGHTNESS_BLENDER.c_str());
206 return {};
207 };
208 if (env->Object_New(cls, ctor, &retVal) != ANI_OK) {
209 UIEFFECT_LOG_E("create object failed '%{public}s'", ANI_UIEFFECT_HDRBRIGHTNESS_BLENDER.c_str());
210 return {};
211 };
212 auto brightnessObj = std::make_unique<BrightnessBlender>();
213 brightnessObj->SetHdr(true);
214 retVal = CreateAniObject(env, ANI_UIEFFECT_HDRBRIGHTNESS_BLENDER, nullptr,
215 reinterpret_cast<ani_long>(brightnessObj.release()));
216 if (!CheckCreateBrightnessBlender(env, para, retVal)) {
217 UIEFFECT_LOG_E("EffectNapi CheckCreateBrightnessBlender failed.");
218 return {};
219 };
220 return retVal;
221 }
222
BackgroundColorBlender(ani_env * env,ani_object obj,ani_object para)223 ani_object AniEffect::BackgroundColorBlender(ani_env* env, ani_object obj, ani_object para)
224 {
225 ani_object retVal {};
226 auto uniqueBlender = std::make_unique<BrightnessBlender>();
227 ParseBrightnessBlender(env, para, uniqueBlender);
228 auto bgColorEffectPara = std::make_shared<BackgroundColorEffectPara>();
229 std::shared_ptr<BrightnessBlender> sharedBlender = std::move(uniqueBlender);
230 bgColorEffectPara->SetBlender(sharedBlender);
231 ani_long nativeObj;
232 if (env->Object_GetFieldByName_Long(obj, "visualEffectNativeObj", &nativeObj) != ANI_OK) {
233 UIEFFECT_LOG_E("get generator visualEffectNativeObj failed");
234 return retVal;
235 }
236 VisualEffect* effectObj = reinterpret_cast<VisualEffect*>(nativeObj);
237 if (effectObj == nullptr) {
238 UIEFFECT_LOG_E("effectObj reinterpret_cast to VisualEffect failed");
239 return retVal;
240 }
241 effectObj->AddPara(bgColorEffectPara);
242 retVal = CreateAniObject(env, ANI_UIEFFECT_VISUAL_EFFECT, nullptr, reinterpret_cast<ani_long>(effectObj));
243 return retVal;
244 }
245
CreateFilter(ani_env * env)246 ani_object AniEffect::CreateFilter(ani_env* env)
247 {
248 ani_object retVal {};
249 auto filterObj = std::make_unique<Filter>();
250 retVal = CreateAniObject(env, ANI_UIEFFECT_FILTER, nullptr, reinterpret_cast<ani_long>(filterObj.release()));
251 return retVal;
252 }
253
PixelStretch(ani_env * env,ani_object obj,ani_object arrayObj,ani_enum_item enumItem)254 ani_object AniEffect::PixelStretch(ani_env* env, ani_object obj, ani_object arrayObj, ani_enum_item enumItem)
255 {
256 ani_object retVal {};
257
258 ani_size enumIndex;
259 env->EnumItem_GetIndex(enumItem, &enumIndex);
260 Drawing::TileMode tileMode = static_cast<Drawing::TileMode>(enumIndex);
261
262 auto pixelStretchPara = std::make_shared<PixelStretchPara>();
263 pixelStretchPara->SetTileMode(tileMode);
264
265 ani_double length;
266 if (ANI_OK != env->Object_GetPropertyByName_Double(arrayObj, "length", &length)) {
267 UIEFFECT_LOG_E("get stretchSizes length failed");
268 return retVal;
269 }
270
271 Vector4f stretchPercent;
272 // 4 mean Vector4f length
273 int vectorLen = 4;
274 for (int i = 0; i < int(length) && i < vectorLen; i++) {
275 ani_double val;
276 ani_ref ref;
277 if (ANI_OK != env->Object_CallMethodByName_Ref(arrayObj, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i) ||
278 ANI_OK != env->Object_CallMethodByName_Double(static_cast<ani_object>(ref), "unboxed", ":D", &val)) {
279 UIEFFECT_LOG_E("Object_CallMethodByName_Ref or Object_CallMethodByName_Double Failed");
280 return retVal;
281 }
282 stretchPercent[i] = static_cast<float>(val);
283 }
284 pixelStretchPara->SetStretchPercent(stretchPercent);
285
286 ani_long nativeObj;
287 if (ANI_OK != env->Object_GetFieldByName_Long(obj, "filterNativeObj", &nativeObj)) {
288 UIEFFECT_LOG_E("get generator filterNativeObj failed");
289 return retVal;
290 }
291
292 Filter* filterObj = reinterpret_cast<Filter*>(nativeObj);
293 filterObj->AddPara(pixelStretchPara);
294 retVal = CreateAniObject(env, ANI_UIEFFECT_FILTER, nullptr, reinterpret_cast<ani_long>(filterObj));
295
296 return retVal;
297 }
298
Blur(ani_env * env,ani_object obj,ani_double radius)299 ani_object AniEffect::Blur(ani_env* env, ani_object obj, ani_double radius)
300 {
301 ani_object retVal {};
302 auto filterBlurPara = std::make_shared<FilterBlurPara>();
303 filterBlurPara->SetRadius(static_cast<float>(radius));
304
305 ani_long nativeObj;
306 if (ANI_OK != env->Object_GetFieldByName_Long(obj, "filterNativeObj", &nativeObj)) {
307 UIEFFECT_LOG_E("get generator filterNativeObj failed");
308 return retVal;
309 }
310
311 Filter* filterObj = reinterpret_cast<Filter*>(nativeObj);
312 filterObj->AddPara(filterBlurPara);
313 retVal = CreateAniObject(env, ANI_UIEFFECT_FILTER, nullptr, reinterpret_cast<ani_long>(filterObj));
314
315 return retVal;
316 }
317 } // namespace Rosen
318 } // namespace OHOS
319
320 extern "C" {
ANI_Constructor(ani_vm * vm,uint32_t * result)321 ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
322 {
323 ani_env* env;
324 if (vm->GetEnv(ANI_VERSION_1, &env) != ANI_OK) {
325 UIEFFECT_LOG_E("[ANI_Constructor] Unsupported ANI_VERSION_1");
326 return ANI_ERROR;
327 };
328 static const char* staticClassName = "L@ohos/graphics/uiEffect/uiEffect;";
329 ani_namespace uiEffectNamespace;
330 if (env->FindNamespace(staticClassName, &uiEffectNamespace) != ANI_OK) {
331 UIEFFECT_LOG_E("[ANI_Constructor] FindNamespace failed");
332 return ANI_ERROR;
333 };
334 std::array staticMethods = {
335 ani_native_function { "createEffect", nullptr, reinterpret_cast<void*>(OHOS::Rosen::AniEffect::CreateEffect) },
336 ani_native_function { "createBrightnessBlender", nullptr,
337 reinterpret_cast<void*>(OHOS::Rosen::AniEffect::CreateBrightnessBlender) },
338 ani_native_function { "createHdrBrightnessBlender", nullptr,
339 reinterpret_cast<void*>(OHOS::Rosen::AniEffect::CreateHdrBrightnessBlender) },
340 ani_native_function { "createFilter", nullptr, reinterpret_cast<void*>(OHOS::Rosen::AniEffect::CreateFilter) }
341 };
342 if (env->Namespace_BindNativeFunctions(uiEffectNamespace, staticMethods.data(), staticMethods.size()) != ANI_OK) {
343 UIEFFECT_LOG_E("[ANI_Constructor] Namespace_BindNativeFunctions failed");
344 return ANI_ERROR;
345 }
346 ani_status status = OHOS::Rosen::AniEffect::BindVisualEffectMethod(env);
347 if (status != ANI_OK) {
348 return status;
349 }
350 status = OHOS::Rosen::AniEffect::BindFilterMethod(env);
351 if (status != ANI_OK) {
352 return status;
353 }
354 *result = ANI_VERSION_1;
355 return ANI_OK;
356 }
357 }