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