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