• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "frameworks/bridge/js_frontend/engine/common/base_animation_bridge.h"
17 
18 #include <functional>
19 #include <unordered_map>
20 #include <utility>
21 
22 #include "base/json/json_util.h"
23 #include "base/utils/linear_map.h"
24 #include "base/utils/string_utils.h"
25 #include "base/utils/utils.h"
26 #include "core/animation/keyframe_animation.h"
27 #include "frameworks/bridge/common/dom/dom_type.h"
28 #include "frameworks/bridge/common/utils/transform_convertor.h"
29 #include "frameworks/bridge/common/utils/utils.h"
30 
31 namespace OHOS::Ace::Framework {
32 namespace {
33 
34 constexpr int32_t MIN_SIZE = 2;
35 constexpr Dimension HALF = 0.5_pct;
36 constexpr Dimension FULL = 1.0_pct;
37 constexpr Dimension ZERO = 0.0_pct;
38 
JsParseAnimationFramesInternal(const std::unique_ptr<JsonValue> & argsPtrAnimation,std::unordered_map<std::string,std::string> & animationFrames)39 void JsParseAnimationFramesInternal(
40     const std::unique_ptr<JsonValue>& argsPtrAnimation, std::unordered_map<std::string, std::string>& animationFrames)
41 {
42     if (!argsPtrAnimation || argsPtrAnimation->IsNull()) {
43         LOGE("args is null");
44         return;
45     }
46 
47     for (auto i = 0; i < argsPtrAnimation->GetArraySize(); i++) {
48         auto item = argsPtrAnimation->GetArrayItem(i);
49         if (!item || item->IsNull()) {
50             continue;
51         }
52         auto key = item->GetKey();
53         auto value = item->IsString() ? item->GetString() : item->ToString();
54 
55         if (!key.empty() && !value.empty()) {
56             // in js api offset in range in [0, 1], but keyframe time range in range [0, 100]
57             if (key == DOM_ANIMATION_OFFSET) {
58                 auto time = StringUtils::StringToDouble(value);
59                 value = std::to_string(time * 100.0);
60             }
61             animationFrames[key] = value;
62         }
63     }
64 }
65 
JsParseIterations(const std::unique_ptr<JsonValue> & argsPtrIterations)66 int32_t JsParseIterations(const std::unique_ptr<JsonValue>& argsPtrIterations)
67 {
68     if (!argsPtrIterations) {
69         LOGE("Parse animation iterations failed, argsPtrIterations is null");
70         return 0;
71     }
72     int32_t iterations = 0;
73     if (argsPtrIterations->IsString()) {
74         std::string iterationsString = argsPtrIterations->GetString();
75         if (iterationsString == BaseAnimationBridgeUtils::ITERATIONS_INFINITY) {
76             iterations = ANIMATION_REPEAT_INFINITE;
77         } else {
78             iterations = StringToInt(iterationsString);
79         }
80     } else if (argsPtrIterations->IsNumber()) {
81         iterations = argsPtrIterations->GetInt();
82     } else {
83         iterations = 1;
84     }
85     return iterations;
86 }
87 
JsParseDoubleParams(const std::unique_ptr<JsonValue> & argsPtrDuration,const std::unique_ptr<JsonValue> & argsPtrDelay,std::unordered_map<std::string,double> & animationDoubleParams)88 void JsParseDoubleParams(const std::unique_ptr<JsonValue>& argsPtrDuration,
89     const std::unique_ptr<JsonValue>& argsPtrDelay, std::unordered_map<std::string, double>& animationDoubleParams)
90 {
91     if (argsPtrDelay) {
92         double delay = 0.0;
93         if (argsPtrDelay->IsString()) {
94             delay = StringToDouble(argsPtrDelay->GetString());
95         } else {
96             delay = argsPtrDelay->GetDouble();
97         }
98         animationDoubleParams[DOM_ANIMATION_DELAY_API] = delay;
99     }
100     if (argsPtrDuration) {
101         double duration = 0.0;
102         if (argsPtrDuration->IsString()) {
103             duration = StringToDouble(argsPtrDuration->GetString());
104         } else {
105             duration = argsPtrDuration->GetDouble();
106         }
107         animationDoubleParams[DOM_ANIMATION_DURATION_API] = duration;
108     }
109 }
110 
111 } // namespace
112 
HandleTransformOrigin(const std::vector<std::unordered_map<std::string,std::string>> & animationFrames)113 std::vector<Dimension> BaseAnimationBridgeUtils::HandleTransformOrigin(
114     const std::vector<std::unordered_map<std::string, std::string>>& animationFrames)
115 {
116     std::string transformOrigin;
117     if (animationFrames.size() >= MIN_SIZE) {
118         auto iterFrom = animationFrames.front().find(DOM_TRANSFORM_ORIGIN);
119         if (iterFrom != animationFrames.front().end()) {
120             transformOrigin = iterFrom->second;
121         }
122         if (transformOrigin.empty()) {
123             auto iterTo = animationFrames.back().find(DOM_TRANSFORM_ORIGIN);
124             if (iterTo != animationFrames.back().end()) {
125                 transformOrigin = iterTo->second;
126             }
127         }
128     }
129 
130     std::vector<Dimension> transformOriginValue;
131     if (transformOrigin.empty()) {
132         return transformOriginValue;
133     }
134 
135     static const LinearMapNode<std::vector<Dimension>> transformOriginMap[] = {
136         { DOM_TRANSFORM_ORIGIN_CENTER_BOTTOM, { HALF, FULL } },
137         { DOM_TRANSFORM_ORIGIN_CENTER_CENTER, { HALF, HALF } },
138         { DOM_TRANSFORM_ORIGIN_CENTER_TOP, { HALF, ZERO } },
139         { DOM_TRANSFORM_ORIGIN_LEFT_BOTTOM, { ZERO, FULL } },
140         { DOM_TRANSFORM_ORIGIN_LEFT_CENTER, { ZERO, HALF } },
141         { DOM_TRANSFORM_ORIGIN_LEFT_TOP, { ZERO, ZERO } },
142         { DOM_TRANSFORM_ORIGIN_RIGHT_BOTTOM, { FULL, FULL } },
143         { DOM_TRANSFORM_ORIGIN_RIGHT_CENTER, { FULL, HALF } },
144         { DOM_TRANSFORM_ORIGIN_RIGHT_TOP, { FULL, ZERO } },
145     };
146 
147     int64_t idx = BinarySearchFindIndex(transformOriginMap, ArraySize(transformOriginMap), transformOrigin.c_str());
148     if (idx < 0) {
149         auto pos = transformOrigin.find(' ', 0);
150         if (pos != std::string::npos) {
151             transformOriginValue.emplace_back(StringToDimension(transformOrigin.substr(0, pos)));
152             transformOriginValue.emplace_back(StringToDimension(transformOrigin.substr(pos + 1)));
153         }
154     } else {
155         transformOriginValue = transformOriginMap[idx].value;
156     }
157     return transformOriginValue;
158 }
159 
SetTweenComponentParams(const RefPtr<Curve> & curve,const std::vector<std::unordered_map<std::string,std::string>> & animationFrames,RefPtr<TweenComponent> & tweenComponent,TweenOption & tweenOption)160 void BaseAnimationBridgeUtils::SetTweenComponentParams(const RefPtr<Curve>& curve,
161     const std::vector<std::unordered_map<std::string, std::string>>& animationFrames,
162     RefPtr<TweenComponent>& tweenComponent, TweenOption& tweenOption)
163 {
164     tweenComponent->SetCustomTweenOption(tweenOption);
165     tweenComponent->SetCustomAnimationOperation(AnimationOperation::NONE);
166 }
167 
JsParseAnimationFrames(const std::string & content,std::vector<std::unordered_map<std::string,std::string>> & animationFrames)168 void BaseAnimationBridgeUtils::JsParseAnimationFrames(
169     const std::string& content, std::vector<std::unordered_map<std::string, std::string>>& animationFrames)
170 {
171     auto argsPtr = JsonUtil::ParseJsonString(content);
172     if (!argsPtr) {
173         return;
174     }
175     auto argsPtrItem = argsPtr->GetArrayItem(0);
176     if (!argsPtrItem) {
177         LOGE("Animation frames are null.");
178         return;
179     }
180     // Parse the arguments to each item in the frame
181     auto size = argsPtrItem->GetArraySize();
182     for (int32_t idx = 0; idx < size; ++idx) {
183         auto argsPtrAnimation = argsPtrItem->GetArrayItem(idx);
184         if (!argsPtrAnimation) {
185             continue;
186         }
187         std::unordered_map<std::string, std::string> animationFrame;
188         JsParseAnimationFramesInternal(argsPtrAnimation, animationFrame);
189         if (idx == 0) {
190             animationFrame[DOM_ANIMATION_OFFSET] = ANIMATION_FROM;
191         } else if (idx == size - 1) {
192             animationFrame[DOM_ANIMATION_OFFSET] = ANIMATION_TO;
193         }
194         animationFrames.emplace_back(animationFrame);
195     }
196 }
197 
JsParseAnimationOptions(const std::string & content,int32_t & iterations,std::unordered_map<std::string,double> & animationDoubleOptions,std::unordered_map<std::string,std::string> & animationStringOptions)198 void BaseAnimationBridgeUtils::JsParseAnimationOptions(const std::string& content, int32_t& iterations,
199     std::unordered_map<std::string, double>& animationDoubleOptions,
200     std::unordered_map<std::string, std::string>& animationStringOptions)
201 {
202     auto argsPtr = JsonUtil::ParseJsonString(content);
203     if (!argsPtr) {
204         LOGE("Js Parse AnimationOption failed. argsPtr is null.");
205         return;
206     }
207 
208     auto argsPtrItem = argsPtr->GetArrayItem(1);
209     if (!argsPtrItem) {
210         LOGE("Js Parse AnimationOption failed. argsPtrItem is null.");
211         return;
212     }
213 
214     auto argsPtrItemIterations = argsPtrItem->GetValue(DOM_ANIMATION_ITERATIONS);
215     auto argsPtrItemDelay = argsPtrItem->GetValue(DOM_ANIMATION_DELAY_API);
216     auto argsPtrItemDuration = argsPtrItem->GetValue(DOM_ANIMATION_DURATION_API);
217     auto argsPtrItemEasing = argsPtrItem->GetValue(DOM_ANIMATION_EASING);
218     auto argsPtrItemFill = argsPtrItem->GetValue(DOM_ANIMATION_FILL);
219     auto argsPtrItemDirection = argsPtrItem->GetValue(DOM_ANIMATION_DIRECTION_API);
220 
221     iterations = JsParseIterations(argsPtrItemIterations);
222     JsParseDoubleParams(argsPtrItemDuration, argsPtrItemDelay, animationDoubleOptions);
223     if (argsPtrItemEasing) {
224         animationStringOptions[DOM_ANIMATION_EASING] = argsPtrItemEasing->GetString();
225     }
226     if (argsPtrItemFill) {
227         animationStringOptions[DOM_ANIMATION_FILL] = argsPtrItemFill->GetString();
228     }
229     if (argsPtrItemDirection) {
230         animationStringOptions[DOM_ANIMATION_DIRECTION_API] = argsPtrItemDirection->GetString();
231     }
232 }
233 
JsParseAnimatorParams(const std::string & content,int32_t & iterations,std::unordered_map<std::string,double> & animationDoubleParams,std::unordered_map<std::string,std::string> & animationStringParams)234 void BaseAnimationBridgeUtils::JsParseAnimatorParams(const std::string& content, int32_t& iterations,
235     std::unordered_map<std::string, double>& animationDoubleParams,
236     std::unordered_map<std::string, std::string>& animationStringParams)
237 {
238     auto argsPtr = JsonUtil::ParseJsonString(content);
239     if (!argsPtr) {
240         LOGE("Js Parse animator params failed. argsPtr is null.");
241         return;
242     }
243 
244     auto argsPtrIterations = argsPtr->GetValue(DOM_ANIMATION_ITERATIONS);
245     auto argsPtrDelay = argsPtr->GetValue(DOM_ANIMATION_DELAY_API);
246     auto argsPtrDuration = argsPtr->GetValue(DOM_ANIMATION_DURATION_API);
247     auto argsPtrEasing = argsPtr->GetValue(DOM_ANIMATION_EASING);
248     auto argsPtrFill = argsPtr->GetValue(DOM_ANIMATION_FILL);
249     auto argsPtrFrom = argsPtr->GetValue(DOM_ANIMATION_BEGIN);
250     auto argsPtrTo = argsPtr->GetValue(DOM_ANIMATION_END);
251     auto argsPtrDirection = argsPtr->GetValue(DOM_ANIMATION_DIRECTION_API);
252 
253     iterations = JsParseIterations(argsPtrIterations);
254     JsParseDoubleParams(argsPtrDuration, argsPtrDelay, animationDoubleParams);
255     if (argsPtrEasing) {
256         animationStringParams[DOM_ANIMATION_EASING] = argsPtrEasing->GetString();
257     }
258     if (argsPtrFill) {
259         animationStringParams[DOM_ANIMATION_FILL] = argsPtrFill->GetString();
260     }
261     if (argsPtrDirection) {
262         animationStringParams[DOM_ANIMATION_DIRECTION_API] = argsPtrDirection->GetString();
263     }
264     if (argsPtrFrom) {
265         double from = 0.0;
266         from = argsPtrFrom->GetDouble();
267         animationDoubleParams[DOM_ANIMATION_BEGIN] = from;
268     }
269     if (argsPtrTo) {
270         double to = 1.0;
271         to = argsPtrTo->GetDouble();
272         animationDoubleParams[DOM_ANIMATION_END] = to;
273     }
274 }
275 } // namespace OHOS::Ace::Framework
276