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