• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025-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 "js_window_animation_utils.h"
17 #include "window_manager_hilog.h"
18 namespace {
19     #define NAPI_CALL_NO_THROW(theCall, retVal)      \
20     do {                                         \
21         if ((theCall) != napi_ok) {              \
22             return retVal;                       \
23         }                                        \
24     } while (0)
25 
26 template <typename T>
CreateJsNumber(napi_env env,T value)27 napi_value CreateJsNumber(napi_env env, T value)
28 {
29     napi_value result = nullptr;
30     if constexpr (std::is_same_v<T, int32_t>) {
31         napi_create_int32(env, value, &result);
32     } else if constexpr (std::is_same_v<T, uint32_t>) {
33         napi_create_uint32(env, value, &result);
34     } else if constexpr (std::is_same_v<T, int64_t>) {
35         napi_create_int64(env, value, &result);
36     } else if constexpr (std::is_same_v<T, double>) {
37         napi_create_double(env, value, &result);
38     }
39     return result;
40 }
41 
42 template<class T>
CreateJsValue(napi_env env,const T & value)43 napi_value CreateJsValue(napi_env env, const T& value)
44 {
45     using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
46     napi_value result = nullptr;
47     if constexpr (std::is_same_v<ValueType, bool>) {
48         napi_get_boolean(env, value, &result);
49         return result;
50     } else if constexpr (std::is_arithmetic_v<ValueType>) {
51         return CreateJsNumber(env, value);
52     } else if constexpr (std::is_same_v<ValueType, std::string>) {
53         napi_create_string_utf8(env, value.c_str(), value.length(), &result);
54         return result;
55     } else if constexpr (std::is_enum_v<ValueType>) {
56         return CreateJsNumber(env, static_cast<std::make_signed_t<std::underlying_type_t<ValueType>>>(value));
57     } else if constexpr (std::is_same_v<ValueType, const char*>) {
58         (value != nullptr) ? napi_create_string_utf8(env, value, strlen(value), &result) :
59             napi_get_undefined(env, &result);
60         return result;
61     }
62 }
63 
64 template <typename T>
ConvertFromJsNumber(napi_env env,napi_value jsValue,T & outValue)65 bool ConvertFromJsNumber(napi_env env, napi_value jsValue, T& outValue)
66 {
67     if constexpr (std::is_same_v<T, int32_t>) {
68         NAPI_CALL_NO_THROW(napi_get_value_int32(env, jsValue, &outValue), false);
69     } else if constexpr (std::is_same_v<T, uint32_t>) {
70         NAPI_CALL_NO_THROW(napi_get_value_uint32(env, jsValue, &outValue), false);
71     } else if constexpr (std::is_same_v<T, int64_t>) {
72         NAPI_CALL_NO_THROW(napi_get_value_int64(env, jsValue, &outValue), false);
73     } else if constexpr (std::is_same_v<T, double>) {
74         NAPI_CALL_NO_THROW(napi_get_value_double(env, jsValue, &outValue), false);
75     }
76     return true;
77 }
78 
79 template<class T>
ConvertFromJsValue(napi_env env,napi_value jsValue,T & value)80 bool ConvertFromJsValue(napi_env env, napi_value jsValue, T& value)
81 {
82     if (jsValue == nullptr) {
83         return false;
84     }
85 
86     using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
87     if constexpr (std::is_same_v<ValueType, bool>) {
88         NAPI_CALL_NO_THROW(napi_get_value_bool(env, jsValue, &value), false);
89         return true;
90     } else if constexpr (std::is_arithmetic_v<ValueType>) {
91         return ConvertFromJsNumber(env, jsValue, value);
92     } else if constexpr (std::is_same_v<ValueType, std::string>) {
93         size_t len = 0;
94         NAPI_CALL_NO_THROW(napi_get_value_string_utf8(env, jsValue, nullptr, 0, &len), false);
95         auto buffer = std::make_unique<char[]>(len + 1);
96         size_t strLength = 0;
97         NAPI_CALL_NO_THROW(napi_get_value_string_utf8(env, jsValue, buffer.get(), len + 1, &strLength), false);
98         value = buffer.get();
99         return true;
100     } else if constexpr (std::is_enum_v<ValueType>) {
101         std::make_signed_t<ValueType> numberValue = 0;
102         if (!ConvertFromJsNumber(env, jsValue, numberValue)) {
103             return false;
104         }
105         value = static_cast<ValueType>(numberValue);
106         return true;
107     }
108 }
109 
110 template<class T>
ParseJsValue(napi_value jsObject,napi_env env,const std::string & name,T & data)111 bool ParseJsValue(napi_value jsObject, napi_env env, const std::string& name, T& data)
112 {
113     napi_value value = nullptr;
114     napi_get_named_property(env, jsObject, name.c_str(), &value);
115     napi_valuetype type = napi_undefined;
116     napi_typeof(env, value, &type);
117     if (type != napi_undefined) {
118         if (!ConvertFromJsValue(env, value, data)) {
119             return false;
120         }
121     } else {
122         return false;
123     }
124     return true;
125 }
126 }
127 namespace OHOS {
128 namespace Rosen {
ConvertTransitionAnimationToJsValue(napi_env env,std::shared_ptr<TransitionAnimation> transitionAnimation)129 napi_value ConvertTransitionAnimationToJsValue(napi_env env, std::shared_ptr<TransitionAnimation> transitionAnimation)
130 {
131     napi_value objValue = nullptr;
132     if (!transitionAnimation) {
133         return objValue;
134     }
135     CHECK_NAPI_CREATE_OBJECT_RETURN_IF_NULL(env, objValue);
136     napi_value configJsValue = ConvertWindowAnimationOptionToJsValue(env, transitionAnimation->config);
137     if (!configJsValue) {
138         return nullptr;
139     }
140     napi_set_named_property(env, objValue, "config", configJsValue);
141     napi_set_named_property(env, objValue, "opacity", CreateJsValue(env, transitionAnimation->opacity));
142 
143     return objValue;
144 }
145 
ConvertStartAnimationOptionsToJsValue(napi_env env,std::shared_ptr<StartAnimationOptions> startAnimationOptions)146 napi_value ConvertStartAnimationOptionsToJsValue(napi_env env,
147     std::shared_ptr<StartAnimationOptions> startAnimationOptions)
148 {
149     napi_value objValue = nullptr;
150     if (!startAnimationOptions) {
151         return objValue;
152     }
153     CHECK_NAPI_CREATE_OBJECT_RETURN_IF_NULL(env, objValue);
154     NAPI_CHECK_RETURN_IF_NULL(napi_set_named_property(env, objValue, "type",
155         CreateJsValue(env, startAnimationOptions->animationType)),
156         "ConvertStartAnimationOptionsToJsValue failed");
157     return objValue;
158 }
159 
ConvertStartAnimationSystemOptionsToJsValue(napi_env env,std::shared_ptr<StartAnimationSystemOptions> startAnimationSystemOptions)160 napi_value ConvertStartAnimationSystemOptionsToJsValue(napi_env env,
161     std::shared_ptr<StartAnimationSystemOptions> startAnimationSystemOptions)
162 {
163     napi_value objValue = nullptr;
164     if (!startAnimationSystemOptions) {
165         return objValue;
166     }
167     CHECK_NAPI_CREATE_OBJECT_RETURN_IF_NULL(env, objValue);
168     NAPI_CHECK_RETURN_IF_NULL(napi_set_named_property(env, objValue, "type",
169         CreateJsValue(env, startAnimationSystemOptions->animationType)),
170         "ConvertStartAnimationSystemOptionsToJsValue failed");
171     if (startAnimationSystemOptions->animationConfig != nullptr) {
172         napi_value configJsValue = ConvertWindowAnimationOptionToJsValue(env,
173             *(startAnimationSystemOptions->animationConfig));
174         if (configJsValue != nullptr) {
175             NAPI_CHECK_RETURN_IF_NULL(napi_set_named_property(env, objValue, "animationConfig", configJsValue),
176                 "Set animationConfig failed");
177         } else {
178             TLOGE(WmsLogTag::WMS_ANIMATION, "ConvertWindowAnimationOptionToJsValue failed");
179         }
180     }
181     return objValue;
182 }
183 
ConvertWindowAnimationOptionToJsValue(napi_env env,const WindowAnimationOption & animationConfig)184 napi_value ConvertWindowAnimationOptionToJsValue(napi_env env,
185     const WindowAnimationOption& animationConfig)
186 {
187     napi_value configJsValue = nullptr;
188     CHECK_NAPI_CREATE_OBJECT_RETURN_IF_NULL(env, configJsValue);
189     napi_set_named_property(env, configJsValue, "curve", CreateJsValue(env, animationConfig.curve));
190     switch (animationConfig.curve) {
191         case WindowAnimationCurve::LINEAR: {
192             napi_set_named_property(env, configJsValue, "duration", CreateJsValue(env, animationConfig.duration));
193             break;
194         }
195         case WindowAnimationCurve::CUBIC_BEZIER: {
196             napi_set_named_property(env, configJsValue, "duration", CreateJsValue(env, animationConfig.duration));
197             [[fallthrough]];
198         }
199         case WindowAnimationCurve::INTERPOLATION_SPRING: {
200             napi_value params = nullptr;
201             napi_create_array(env, &params);
202             for (uint32_t i = 0; i < ANIMATION_PARAM_SIZE; ++i) {
203                 napi_value element;
204                 napi_create_double(env, static_cast<double>(animationConfig.params[i]), &element);
205                 napi_set_element(env, params, i, element);
206             }
207             napi_set_named_property(env, configJsValue, "param", params);
208             break;
209         }
210         default:
211             break;
212     }
213     return configJsValue;
214 }
215 
ConvertTransitionAnimationFromJsValue(napi_env env,napi_value jsObject,TransitionAnimation & transitionAnimation,WmErrorCode & result)216 bool ConvertTransitionAnimationFromJsValue(napi_env env, napi_value jsObject, TransitionAnimation& transitionAnimation,
217     WmErrorCode& result)
218 {
219     napi_value jsAnimationConfig = nullptr;
220     napi_get_named_property(env, jsObject, "config", &jsAnimationConfig);
221     if (!ConvertWindowAnimationOptionFromJsValue(env, jsAnimationConfig, transitionAnimation.config, result) ||
222         !CheckWindowAnimationOption(env, transitionAnimation.config, result)) {
223         return false;
224     }
225     double opacity = 1.0f;
226     napi_value jsOpacityValue = nullptr;
227     napi_get_named_property(env, jsObject, "opacity", &jsOpacityValue);
228     napi_valuetype type = napi_undefined;
229     napi_typeof(env, jsOpacityValue, &type);
230     if (type != napi_undefined) {
231         if (!ConvertFromJsValue(env, jsOpacityValue, opacity)) {
232             result = WmErrorCode::WM_ERROR_INVALID_PARAM;
233             return false;
234         } else if (opacity < 0.0 || opacity > 1.0) {
235             result = WmErrorCode::WM_ERROR_ILLEGAL_PARAM;
236             return false;
237         }
238     }
239     transitionAnimation.opacity = static_cast<float>(opacity);
240     return true;
241 }
242 
ConvertStartAnimationOptionsFromJsValue(napi_env env,napi_value jsObject,StartAnimationOptions & startAnimationOptions)243 bool ConvertStartAnimationOptionsFromJsValue(napi_env env, napi_value jsObject,
244     StartAnimationOptions& startAnimationOptions)
245 {
246     uint32_t animationType = 0;
247     if (!ParseJsValue(jsObject, env, "type", animationType)) {
248         return false;
249     }
250     if (animationType >= static_cast<uint32_t>(AnimationType::END)) {
251         return false;
252     }
253     startAnimationOptions.animationType = static_cast<AnimationType>(animationType);
254     return true;
255 }
256 
ConvertStartAnimationSystemOptionsFromJsValue(napi_env env,napi_value jsObject,StartAnimationSystemOptions & startAnimationSystemOptions)257 bool ConvertStartAnimationSystemOptionsFromJsValue(napi_env env, napi_value jsObject,
258     StartAnimationSystemOptions& startAnimationSystemOptions)
259 {
260     WmErrorCode result = WmErrorCode::WM_OK;
261     uint32_t animationType = 0;
262     if (!ParseJsValue(jsObject, env, "type", animationType)) {
263         return false;
264     }
265     if (animationType >= static_cast<uint32_t>(AnimationType::END)) {
266         return false;
267     }
268     startAnimationSystemOptions.animationType = static_cast<AnimationType>(animationType);
269     bool hasAnimationConfig = false;
270     napi_has_named_property(env, jsObject, "animationConfig", &hasAnimationConfig);
271     if (!hasAnimationConfig) {
272         return true;
273     }
274     napi_value jsAnimationConfig = nullptr;
275     napi_get_named_property(env, jsObject, "animationConfig", &jsAnimationConfig);
276     startAnimationSystemOptions.animationConfig = std::make_shared<WindowAnimationOption>();
277     if (!ConvertWindowAnimationOptionFromJsValue(env, jsAnimationConfig, *(startAnimationSystemOptions.animationConfig),
278         result) || !CheckWindowAnimationOption(env, *(startAnimationSystemOptions.animationConfig), result)) {
279         startAnimationSystemOptions.animationConfig = nullptr;
280     }
281     return true;
282 }
283 
ConvertWindowCreateParamsFromJsValue(napi_env env,napi_value jsObject,WindowCreateParams & windowCreateParams)284 bool ConvertWindowCreateParamsFromJsValue(napi_env env, napi_value jsObject,
285     WindowCreateParams& windowCreateParams)
286 {
287     bool hasAnimationParams = false;
288     napi_has_named_property(env, jsObject, "animationParams", &hasAnimationParams);
289     if (hasAnimationParams) {
290         napi_value jsAnimationParams = nullptr;
291         napi_get_named_property(env, jsObject, "animationParams", &jsAnimationParams);
292         windowCreateParams.animationParams = std::make_shared<StartAnimationOptions>();
293         if (!ConvertStartAnimationOptionsFromJsValue(env, jsAnimationParams, *(windowCreateParams.animationParams))) {
294             windowCreateParams.animationParams = nullptr;
295         }
296     }
297     bool hasAnimationSystemParams = false;
298     napi_has_named_property(env, jsObject, "systemAnimationParams", &hasAnimationSystemParams);
299     if (hasAnimationSystemParams) {
300         napi_value jsAnimationSystemParams = nullptr;
301         napi_get_named_property(env, jsObject, "systemAnimationParams", &jsAnimationSystemParams);
302         windowCreateParams.animationSystemParams = std::make_shared<StartAnimationSystemOptions>();
303         if (!ConvertStartAnimationSystemOptionsFromJsValue(env, jsAnimationSystemParams,
304             *(windowCreateParams.animationSystemParams))) {
305             windowCreateParams.animationSystemParams = nullptr;
306         }
307     }
308     return true;
309 }
310 
CheckWindowAnimationOption(napi_env env,WindowAnimationOption & animationConfig,WmErrorCode & result)311 bool CheckWindowAnimationOption(napi_env env, WindowAnimationOption& animationConfig, WmErrorCode& result)
312 {
313     switch (animationConfig.curve) {
314         case WindowAnimationCurve::LINEAR: {
315             if (animationConfig.duration > ANIMATION_MAX_DURATION) {
316                 TLOGE(WmsLogTag::WMS_ANIMATION, "Duration is invalid: %{public}u", animationConfig.duration);
317                 result = WmErrorCode::WM_ERROR_ILLEGAL_PARAM;
318                 return false;
319             }
320             break;
321         }
322         case WindowAnimationCurve::INTERPOLATION_SPRING: {
323             for (uint32_t i = 1; i < ANIMATION_PARAM_SIZE; ++i) {
324                 if (animationConfig.params[i] <= 0.0) {
325                     TLOGI(WmsLogTag::WMS_ANIMATION, "Interpolation spring param %{public}u is invalid: %{public}f",
326                         i, animationConfig.params[i]);
327                     animationConfig.params[i] = 1.0;
328                 }
329             }
330             break;
331         }
332         case WindowAnimationCurve::CUBIC_BEZIER: {
333             if (animationConfig.duration > ANIMATION_MAX_DURATION) {
334                 TLOGE(WmsLogTag::WMS_ANIMATION, "Duration is invalid: %{public}u", animationConfig.duration);
335                 result = WmErrorCode::WM_ERROR_ILLEGAL_PARAM;
336                 return false;
337             }
338             break;
339         }
340         default:
341             result = WmErrorCode::WM_ERROR_ILLEGAL_PARAM;
342             return false;
343     }
344     return true;
345 }
346 
ConvertWindowAnimationOptionFromJsValue(napi_env env,napi_value jsAnimationConfig,WindowAnimationOption & animationConfig,WmErrorCode & result)347 bool ConvertWindowAnimationOptionFromJsValue(napi_env env, napi_value jsAnimationConfig,
348     WindowAnimationOption& animationConfig, WmErrorCode& result)
349 {
350     if (jsAnimationConfig == nullptr) {
351         result = WmErrorCode::WM_ERROR_INVALID_PARAM;
352         return false;
353     }
354     uint32_t curve = 0;
355     if (!ParseJsValue(jsAnimationConfig, env, "curve", curve)) {
356         result = WmErrorCode::WM_ERROR_INVALID_PARAM;
357         return false;
358     }
359     animationConfig.curve = static_cast<WindowAnimationCurve>(curve);
360     uint32_t duration = 0;
361     std::array<double, ANIMATION_PARAM_SIZE> params;
362     switch (curve) {
363         case static_cast<uint32_t>(WindowAnimationCurve::LINEAR): {
364             if (!ParseJsValue(jsAnimationConfig, env, "duration", duration)) {
365                 result = WmErrorCode::WM_ERROR_INVALID_PARAM;
366                 return false;
367             }
368             animationConfig.duration = duration;
369             break;
370         }
371         case static_cast<uint32_t>(WindowAnimationCurve::CUBIC_BEZIER): {
372             if (!ParseJsValue(jsAnimationConfig, env, "duration", duration)) {
373                 result = WmErrorCode::WM_ERROR_INVALID_PARAM;
374                 return false;
375             }
376             animationConfig.duration = duration;
377             [[fallthrough]];
378         }
379         case static_cast<uint32_t>(WindowAnimationCurve::INTERPOLATION_SPRING): {
380             napi_value paramsValue = nullptr;
381             napi_get_named_property(env, jsAnimationConfig, "param", &paramsValue);
382             for (uint32_t i = 0; i < ANIMATION_PARAM_SIZE; ++i) {
383                 napi_value element;
384                 napi_get_element(env, paramsValue, i, &element);
385                 if (!ConvertFromJsValue(env, element, params[i])) {
386                     result = WmErrorCode::WM_ERROR_INVALID_PARAM;
387                     return false;
388                 }
389                 animationConfig.params[i] = static_cast<float>(params[i]);
390             }
391             break;
392         }
393         default:
394             result = WmErrorCode::WM_ERROR_ILLEGAL_PARAM;
395             return false;
396     }
397     return true;
398 }
399 } // namespace Rosen
400 } // namespace OHOS
401