1 /*
2  * Copyright (c) 2023-2024 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 "animation/rs_symbol_animation.h"
17 #include "animation/rs_keyframe_animation.h"
18 #include "draw/paint.h"
19 #include "platform/common/rs_log.h"
20 #include "utils/point.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 static const Vector2f CENTER_NODE_COORDINATE = { 0.5f, 0.5f }; // scale center node
25 static const std::string SCALE_PROP_X = "sx";
26 static const std::string SCALE_PROP_Y = "sy";
27 static const std::string ALPHA_PROP = "alpha";
28 static const size_t PROPERTIES = 2; // symbol animation property contains two values, change from one to the other
29 static const unsigned int PROP_START = 0; // symbol animation property contains two values, change from START to the END
30 static const unsigned int PROP_END = 1; // symbol animation property contains two values, change from START to the END
31 static const unsigned int NODE_WIDTH = 2;
32 static const unsigned int NODE_HEIGHT = 3;
33 static const int INVALID_STATUS = -1; // invalid status label
34 static const int APPEAR_STATUS = 1 ; // appear status label
35 
36 namespace SymbolAnimation {
37 template<typename T>
CreateOrSetModifierValue(std::shared_ptr<RSAnimatableProperty<T>> & property,const T & value)38 bool CreateOrSetModifierValue(std::shared_ptr<RSAnimatableProperty<T>>& property, const T& value)
39 {
40     if (property == nullptr) {
41         property = std::make_shared<RSAnimatableProperty<T>>(value);
42         return true;
43     }
44     property->Set(value);
45     return false;
46 }
47 
48 template<typename T>
ElementInMap(const std::string & curElement,const std::map<std::string,T> & curMap)49 bool ElementInMap(const std::string& curElement, const std::map<std::string, T>& curMap)
50 {
51     auto element = curMap.find(curElement);
52     return (element != curMap.end());
53 }
54 
CurveArgsInMap(const std::string & curElement,const std::map<std::string,float> & curMap)55 float CurveArgsInMap(const std::string& curElement, const std::map<std::string, float>& curMap)
56 {
57     auto element = curMap.find(curElement);
58     if (element == curMap.end()) {
59         return 0.0f;
60     }
61     return element->second;
62 }
63 
CreateAnimationTimingCurve(const OHOS::Rosen::Drawing::DrawingCurveType type,const std::map<std::string,float> & curveArgs,RSAnimationTimingCurve & curve)64 void CreateAnimationTimingCurve(const OHOS::Rosen::Drawing::DrawingCurveType type,
65     const std::map<std::string, float>& curveArgs, RSAnimationTimingCurve& curve)
66 {
67     curve = RSAnimationTimingCurve();
68     if (type == OHOS::Rosen::Drawing::DrawingCurveType::LINEAR) {
69         curve = RSAnimationTimingCurve::LINEAR;
70     } else if (type == OHOS::Rosen::Drawing::DrawingCurveType::SPRING) {
71         float scaleVelocity = CurveArgsInMap("velocity", curveArgs);
72         float scaleMass = CurveArgsInMap("mass", curveArgs);
73         float scaleStiffness = CurveArgsInMap("stiffness", curveArgs);
74         float scaleDamping = CurveArgsInMap("damping", curveArgs);
75         curve = RSAnimationTimingCurve::CreateInterpolatingSpring(scaleMass, scaleStiffness, scaleDamping,
76                                                                   scaleVelocity);
77     } else if (type == OHOS::Rosen::Drawing::DrawingCurveType::FRICTION ||
78         type == OHOS::Rosen::Drawing::DrawingCurveType::SHARP) {
79         float ctrlX1 = CurveArgsInMap("ctrlX1", curveArgs);
80         float ctrlY1 = CurveArgsInMap("ctrlY1", curveArgs);
81         float ctrlX2 = CurveArgsInMap("ctrlX2", curveArgs);
82         float ctrlY2 = CurveArgsInMap("ctrlY2", curveArgs);
83         curve = RSAnimationTimingCurve::CreateCubicCurve(ctrlX1, ctrlY1, ctrlX2, ctrlY2);
84     }
85 }
86 
CalcOneTimePercent(std::vector<float> & timePercents,const uint32_t totalDuration,const uint32_t duration)87 void CalcOneTimePercent(std::vector<float>& timePercents, const uint32_t totalDuration, const uint32_t duration)
88 {
89     if (totalDuration == 0) {
90         return;
91     }
92     float timePercent = static_cast<float>(duration) / static_cast<float>(totalDuration);
93     timePercent = timePercent > 1 ? 1.0 : timePercent;
94     timePercents.push_back(timePercent);
95 }
96 } // namespace SymbolAnimation
97 
RSSymbolAnimation()98 RSSymbolAnimation::RSSymbolAnimation() {}
99 
~RSSymbolAnimation()100 RSSymbolAnimation::~RSSymbolAnimation() {}
101 
102 /**
103  * @brief SymbolAnimation interface for arkui
104  * @param symbolAnimationConfig indicates all the information about a symbol
105  * @return true if set animation success
106  */
SetSymbolAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)107 bool RSSymbolAnimation::SetSymbolAnimation(
108     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
109 {
110     if (rsNode_ == nullptr || symbolAnimationConfig == nullptr) {
111         ROSEN_LOGD("HmSymbol RSSymbolAnimation::getNode or get symbolAnimationConfig:failed");
112         return false;
113     }
114 
115     NodeProcessBeforeAnimation(symbolAnimationConfig);
116     if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::NONE) {
117         return true; // pre code already clear nodes.
118     }
119     InitSupportAnimationTable();
120 
121     if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::REPLACE_APPEAR) {
122         return SetReplaceAnimation(symbolAnimationConfig);
123     }
124 
125     return SetPublicAnimation(symbolAnimationConfig);
126 }
127 
NodeProcessBeforeAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)128 void RSSymbolAnimation::NodeProcessBeforeAnimation(
129     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
130 {
131     if (symbolAnimationConfig->effectStrategy ==
132         Drawing::DrawingEffectStrategy::REPLACE_APPEAR) {
133         PopNodeFromReplaceList(symbolAnimationConfig->symbolSpanId);
134         return;
135     }
136 
137     {
138         std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
139         rsNode_->canvasNodesListMap.erase(symbolAnimationConfig->symbolSpanId);
140     }
141     return;
142 }
143 
PopNodeFromReplaceList(uint64_t symbolSpanId)144 void RSSymbolAnimation::PopNodeFromReplaceList(uint64_t symbolSpanId)
145 {
146     std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
147     if (rsNode_->canvasNodesListMap.count(symbolSpanId) == 0) {
148         rsNode_->canvasNodesListMap[symbolSpanId] = {};
149     }
150 
151     if (rsNode_->replaceNodesSwapMap.find(INVALID_STATUS) == rsNode_->replaceNodesSwapMap.end()) {
152         rsNode_->replaceNodesSwapMap[INVALID_STATUS] = {};
153     } else {
154         const auto& invalidNodes = rsNode_->replaceNodesSwapMap[INVALID_STATUS];
155         for (const auto& [id, config] : invalidNodes) {
156             rsNode_->canvasNodesListMap[symbolSpanId].erase(id);
157         }
158         rsNode_->replaceNodesSwapMap[INVALID_STATUS].clear();
159     }
160 
161     if (rsNode_->replaceNodesSwapMap.find(APPEAR_STATUS) == rsNode_->replaceNodesSwapMap.end()) {
162         rsNode_->replaceNodesSwapMap[APPEAR_STATUS] = {};
163     }
164 }
165 
166 /**
167  * @brief Set Disappear config of replace animation
168  * @param symbolAnimationConfig is the symbol animation config of new symbol
169  * @param disappearConfig set the symbol animation config of old symbol
170  */
SetDisappearConfig(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::shared_ptr<TextEngine::SymbolAnimationConfig> & disappearConfig)171 bool RSSymbolAnimation::SetDisappearConfig(
172     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
173     std::shared_ptr<TextEngine::SymbolAnimationConfig>& disappearConfig)
174 {
175     if (symbolAnimationConfig == nullptr || disappearConfig == nullptr) {
176         ROSEN_LOGD("[%{public}s]: symbolAnimationConfig or disappearConfig is nullptr \n", __func__);
177         return false;
178     }
179 
180     auto disappearNodes = rsNode_->replaceNodesSwapMap[APPEAR_STATUS];
181     disappearConfig->repeatCount = symbolAnimationConfig->repeatCount;
182     disappearConfig->animationMode = symbolAnimationConfig->animationMode;
183     disappearConfig->animationStart = symbolAnimationConfig->animationStart;
184     disappearConfig->symbolSpanId = symbolAnimationConfig->symbolSpanId;
185     disappearConfig->commonSubType = symbolAnimationConfig->commonSubType;
186     disappearConfig->effectStrategy = symbolAnimationConfig->effectStrategy;
187 
188     // count node levels and animation levels
189     uint32_t numNodes = 0;
190     int animationLevelNum = -1; // -1 is initial value, that is no animation levels
191     for (const auto& [id, config] : disappearNodes) {
192         TextEngine::SymbolNode symbolNode;
193         symbolNode.animationIndex = config.symbolNode.animationIndex;
194         disappearConfig->symbolNodes.push_back(symbolNode);
195         animationLevelNum =
196             animationLevelNum < symbolNode.animationIndex ? symbolNode.animationIndex : animationLevelNum;
197         numNodes++;
198     }
199     disappearConfig->numNodes = numNodes;
200     // 0 is the byLayer effect and 1 is the wholeSymbol effect
201     disappearConfig->animationMode = animationLevelNum > 0 ? 0 : 1;
202     return true;
203 }
204 
SetReplaceAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)205 bool RSSymbolAnimation::SetReplaceAnimation(
206     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
207 {
208     auto disappearConfig = std::make_shared<TextEngine::SymbolAnimationConfig>();
209     if (SetDisappearConfig(symbolAnimationConfig, disappearConfig)) {
210         SetReplaceDisappear(disappearConfig);
211     }
212     SetReplaceAppear(symbolAnimationConfig,
213         !rsNode_->replaceNodesSwapMap[INVALID_STATUS].empty());
214     return true;
215 }
216 
SetReplaceDisappear(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)217 bool RSSymbolAnimation::SetReplaceDisappear(
218     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
219 {
220     if (symbolAnimationConfig->numNodes == 0) {
221         ROSEN_LOGD("[%{public}s] numNodes in symbolAnimationConfig is 0 \n", __func__);
222         return false;
223     }
224 
225     auto& disappearNodes = rsNode_->replaceNodesSwapMap[APPEAR_STATUS];
226     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
227     Drawing::DrawingEffectStrategy effectStrategy = Drawing::DrawingEffectStrategy::REPLACE_DISAPPEAR;
228     bool res = GetAnimationGroupParameters(symbolAnimationConfig, parameters, effectStrategy);
229     for (const auto& [id, config] : disappearNodes) {
230         if (!res || (config.symbolNode.animationIndex < 0)) {
231             ROSEN_LOGD("[%{public}s] invalid initial parameter \n", __func__);
232             continue;
233         }
234         if (static_cast<int>(parameters.size()) <= config.symbolNode.animationIndex ||
235             parameters.at(config.symbolNode.animationIndex).empty()) {
236             ROSEN_LOGD("[%{public}s] invalid parameter \n", __func__);
237             continue;
238         }
239         auto canvasNode = rsNode_->canvasNodesListMap[symbolAnimationConfig->symbolSpanId][id];
240         SpliceAnimation(canvasNode, parameters[config.symbolNode.animationIndex],
241             Drawing::DrawingEffectStrategy::DISAPPEAR);
242     }
243     {
244         std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
245         rsNode_->replaceNodesSwapMap[INVALID_STATUS].swap(rsNode_->replaceNodesSwapMap[APPEAR_STATUS]);
246     }
247     return true;
248 }
249 
250 
SetReplaceAppear(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,bool isStartAnimation)251 bool RSSymbolAnimation::SetReplaceAppear(
252     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
253     bool isStartAnimation)
254 {
255     auto nodeNum = symbolAnimationConfig->numNodes;
256     if (nodeNum <= 0) {
257         return false;
258     }
259     auto symbolSpanId = symbolAnimationConfig->symbolSpanId;
260     const auto& symbolFirstNode = symbolAnimationConfig->symbolNodes[0]; // calculate offset by the first node
261     Vector4f offsets = CalculateOffset(symbolFirstNode.symbolData.path_,
262         symbolFirstNode.nodeBoundary[0], symbolFirstNode.nodeBoundary[1]); // index 0 offsetX and 1 offsetY of layout
263     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
264     Drawing::DrawingEffectStrategy effectStrategy = Drawing::DrawingEffectStrategy::REPLACE_APPEAR;
265     bool res = GetAnimationGroupParameters(symbolAnimationConfig, parameters,
266         effectStrategy);
267     for (uint32_t n = 0; n < nodeNum; n++) {
268         auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
269         auto canvasNode = RSCanvasNode::Create();
270         {
271             std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
272             if (rsNode_->canvasNodesListMap.count(symbolSpanId) == 0) {
273                 rsNode_->canvasNodesListMap.insert({symbolSpanId, {}});
274             }
275             rsNode_->canvasNodesListMap[symbolSpanId].insert((std::make_pair(canvasNode->GetId(), canvasNode)));
276             AnimationNodeConfig appearNodeConfig = {.symbolNode = symbolNode,
277                                                     .animationIndex = symbolNode.animationIndex};
278             rsNode_->replaceNodesSwapMap[APPEAR_STATUS].insert((std::make_pair(canvasNode->GetId(), appearNodeConfig)));
279         }
280         if (!SetSymbolGeometry(canvasNode, Vector4f(offsets[0], offsets[1], // 0: offsetX of newNode 1: offsetY
281             symbolNode.nodeBoundary[NODE_WIDTH], symbolNode.nodeBoundary[NODE_HEIGHT]))) {
282             continue;
283         }
284         rsNode_->AddChild(canvasNode, -1);
285         GroupDrawing(canvasNode, symbolNode, offsets, nodeNum > 1);
286         if (!isStartAnimation || !res || (symbolNode.animationIndex < 0)) {
287             continue;
288         }
289         if (static_cast<int>(parameters.size()) <= symbolNode.animationIndex ||
290             parameters[symbolNode.animationIndex].empty()) {
291             ROSEN_LOGD("[%{public}s] invalid parameter \n", __func__);
292             continue;
293         }
294         SpliceAnimation(canvasNode, parameters[symbolNode.animationIndex], Drawing::DrawingEffectStrategy::APPEAR);
295     }
296     return true;
297 }
298 
InitSupportAnimationTable()299 void RSSymbolAnimation::InitSupportAnimationTable()
300 {
301     // Init public animation list
302     if (publicSupportAnimations_.empty()) {
303         publicSupportAnimations_ = {Drawing::DrawingEffectStrategy::BOUNCE,
304                                     Drawing::DrawingEffectStrategy::APPEAR,
305                                     Drawing::DrawingEffectStrategy::DISAPPEAR,
306                                     Drawing::DrawingEffectStrategy::SCALE};
307     }
308     if (upAndDownSupportAnimations_.empty()) {
309         upAndDownSupportAnimations_ = {Drawing::DrawingEffectStrategy::BOUNCE,
310                                        Drawing::DrawingEffectStrategy::SCALE};
311     }
312 }
313 
GetAnimationGroupParameters(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> & parameters,Drawing::DrawingEffectStrategy & effectStrategy)314 bool RSSymbolAnimation::GetAnimationGroupParameters(
315     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
316     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>>& parameters,
317     Drawing::DrawingEffectStrategy& effectStrategy)
318 {
319     // count animation levels
320     int animationLevelNum = -1;
321     auto nodeNum = symbolAnimationConfig->numNodes;
322     for (uint32_t n = 0; n < nodeNum; n++) {
323         const auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
324         animationLevelNum =
325             animationLevelNum < symbolNode.animationIndex ? symbolNode.animationIndex : animationLevelNum;
326     }
327 
328     if (animationLevelNum < 0) {
329         ROSEN_LOGD("[%{public}s] HmSymbol: this symbol does not have an animated layer\n", __func__);
330         return false;
331     }
332     animationLevelNum = animationLevelNum + 1;
333 
334     // get animation group paramaters
335     if (std::count(upAndDownSupportAnimations_.begin(), upAndDownSupportAnimations_.end(),
336         effectStrategy) != 0) {
337         parameters = Drawing::HmSymbolConfigOhos::GetGroupParameters(
338             Drawing::DrawingAnimationType(effectStrategy),
339             static_cast<uint16_t>(animationLevelNum),
340             symbolAnimationConfig->animationMode, symbolAnimationConfig->commonSubType);
341     } else {
342         parameters = Drawing::HmSymbolConfigOhos::GetGroupParameters(
343             Drawing::DrawingAnimationType(effectStrategy),
344             static_cast<uint16_t>(animationLevelNum),
345             symbolAnimationConfig->animationMode);
346     }
347     if (parameters.empty()) {
348         ROSEN_LOGD("[%{public}s] HmSymbol: GetGroupParameters failed\n", __func__);
349         return false;
350     }
351     return true;
352 }
353 
ChooseAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)354 bool RSSymbolAnimation::ChooseAnimation(const std::shared_ptr<RSNode>& rsNode,
355     std::vector<Drawing::DrawingPiecewiseParameter>& parameters,
356     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
357 {
358     if (std::count(publicSupportAnimations_.begin(),
359         publicSupportAnimations_.end(), symbolAnimationConfig->effectStrategy) != 0) {
360         SpliceAnimation(rsNode, parameters, symbolAnimationConfig->effectStrategy);
361         return true;
362     }
363 
364     switch (symbolAnimationConfig->effectStrategy) {
365         case Drawing::DrawingEffectStrategy::VARIABLE_COLOR:
366             return SetKeyframeAlphaAnimation(rsNode, parameters, symbolAnimationConfig);
367         case Drawing::DrawingEffectStrategy::PULSE:
368             return SetKeyframeAlphaAnimation(rsNode, parameters, symbolAnimationConfig);
369         default:
370             ROSEN_LOGD("[%{public}s] not support input animation type \n", __func__);
371             return false;
372     }
373 }
374 
SetPublicAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)375 bool RSSymbolAnimation::SetPublicAnimation(
376     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
377 {
378     uint32_t nodeNum = symbolAnimationConfig->numNodes;
379     if (nodeNum <= 0) {
380         ROSEN_LOGD("HmSymbol SetDisappearAnimation::getNode or get symbolAnimationConfig:failed");
381         return false;
382     }
383 
384     auto symbolSpanId = symbolAnimationConfig->symbolSpanId;
385     const auto& symbolFirstNode = symbolAnimationConfig->symbolNodes[0]; // calculate offset by the first node
386 
387     Vector4f offsets = CalculateOffset(symbolFirstNode.symbolData.path_, symbolFirstNode.nodeBoundary[0],
388         symbolFirstNode.nodeBoundary[1]); // index 0 offsetX and 1 offsetY of layout
389 
390     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
391     bool res = GetAnimationGroupParameters(symbolAnimationConfig, parameters, symbolAnimationConfig->effectStrategy);
392 
393     for (uint32_t n = 0; n < nodeNum; n++) {
394         auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
395         auto canvasNode = RSCanvasNode::Create();
396         {
397             std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
398             if (!rsNode_->canvasNodesListMap.count(symbolSpanId)) {
399                 rsNode_->canvasNodesListMap[symbolSpanId] = {};
400             }
401             rsNode_->canvasNodesListMap[symbolSpanId][canvasNode->GetId()] = canvasNode;
402         }
403         if (!SetSymbolGeometry(canvasNode, Vector4f(offsets[0], offsets[1], // 0: offsetX of newNode 1: offsetY
404             symbolNode.nodeBoundary[NODE_WIDTH], symbolNode.nodeBoundary[NODE_HEIGHT]))) {
405             return false;
406         }
407         rsNode_->AddChild(canvasNode, -1);
408 
409         GroupDrawing(canvasNode, symbolNode, offsets, nodeNum > 1);
410 
411         if (!res || (symbolNode.animationIndex < 0)) {
412             continue;
413         }
414 
415         if (static_cast<int>(parameters.size()) <= symbolNode.animationIndex ||
416             parameters[symbolNode.animationIndex].empty()) {
417             ROSEN_LOGD("[%{public}s] invalid parameter \n", __func__);
418             continue;
419         }
420         ChooseAnimation(canvasNode, parameters[symbolNode.animationIndex], symbolAnimationConfig);
421     }
422     return true;
423 }
424 
GroupAnimationStart(const std::shared_ptr<RSNode> & rsNode,std::vector<std::shared_ptr<RSAnimation>> & animations)425 void RSSymbolAnimation::GroupAnimationStart(
426     const std::shared_ptr<RSNode>& rsNode, std::vector<std::shared_ptr<RSAnimation>>& animations)
427 {
428     if (rsNode == nullptr || animations.empty()) {
429         ROSEN_LOGD("[%{public}s] : invalid input \n", __func__);
430         return;
431     }
432 
433     for (int i = 0; i < static_cast<int>(animations.size()); i++) {
434         if (animations[i]) {
435             animations[i]->Start(rsNode);
436         }
437     }
438 }
439 
SetNodePivot(const std::shared_ptr<RSNode> & rsNode)440 void RSSymbolAnimation::SetNodePivot(const std::shared_ptr<RSNode>& rsNode)
441 {
442     if (rsNode == nullptr) {
443         ROSEN_LOGD("Interpolator is null, return FRACTION_MIN.");
444         return;
445     }
446     // Set Node Center Offset
447     Vector2f curNodePivot = rsNode->GetStagingProperties().GetPivot();
448     pivotProperty_ = nullptr; // reset
449     if (!(curNodePivot.x_ == CENTER_NODE_COORDINATE.x_ && curNodePivot.y_ == CENTER_NODE_COORDINATE.y_)) {
450         bool isCreate = SymbolAnimation::CreateOrSetModifierValue(pivotProperty_, CENTER_NODE_COORDINATE);
451         if (isCreate) {
452             auto pivotModifier = std::make_shared<RSPivotModifier>(pivotProperty_);
453             rsNode->AddModifier(pivotModifier);
454         }
455     }
456 }
457 
SpliceAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters,const Drawing::DrawingEffectStrategy & effectStrategy)458 void RSSymbolAnimation::SpliceAnimation(const std::shared_ptr<RSNode>& rsNode,
459     std::vector<Drawing::DrawingPiecewiseParameter>& parameters,
460     const Drawing::DrawingEffectStrategy& effectStrategy)
461 {
462     if (rsNode == nullptr) {
463         ROSEN_LOGD("RsNode is null, failed to SpliceAnimation.");
464         return;
465     }
466     if (effectStrategy == Drawing::DrawingEffectStrategy::DISAPPEAR ||
467         effectStrategy == Drawing::DrawingEffectStrategy::APPEAR) {
468         AppearAnimation(rsNode, parameters);
469     } else if (effectStrategy == Drawing::DrawingEffectStrategy::BOUNCE ||
470         effectStrategy == Drawing::DrawingEffectStrategy::SCALE) {
471         BounceAnimation(rsNode, parameters);
472     } else {
473         return;
474     }
475 }
476 
BounceAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters)477 void RSSymbolAnimation::BounceAnimation(
478     const std::shared_ptr<RSNode>& rsNode, std::vector<Drawing::DrawingPiecewiseParameter>& parameters)
479 {
480     constexpr unsigned int animationStageNum = 2; // the count of atomizated animations
481     if (rsNode == nullptr || parameters.size() < animationStageNum) {
482         ROSEN_LOGD("[%{public}s] : invalid input\n", __func__);
483         return;
484     }
485 
486     std::shared_ptr<RSAnimatableProperty<Vector2f>> scaleProperty = nullptr;
487     bool isAdd = AddScaleBaseModifier(rsNode, parameters[0], scaleProperty);
488     if (!isAdd) {
489         ROSEN_LOGD("[%{public}s] : add scale modifier failed\n", __func__);
490         return;
491     }
492 
493     std::vector<std::shared_ptr<RSAnimation>> groupAnimation = {};
494     ScaleAnimationBase(scaleProperty, parameters[0], groupAnimation);
495     ScaleAnimationBase(scaleProperty, parameters[1], groupAnimation);
496     GroupAnimationStart(rsNode, groupAnimation);
497 }
498 
AppearAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters)499 void RSSymbolAnimation::AppearAnimation(
500     const std::shared_ptr<RSNode>& rsNode, std::vector<Drawing::DrawingPiecewiseParameter>& parameters)
501 {
502     constexpr unsigned int animationStageNum = 2; // the count of atomizated animations
503     if (rsNode == nullptr || parameters.size() < animationStageNum) {
504         ROSEN_LOGD("[%{public}s] : invalid input\n", __func__);
505         return;
506     }
507 
508     std::shared_ptr<RSAnimatableProperty<Vector2f>> scaleProperty = nullptr;
509     bool isAdd = AddScaleBaseModifier(rsNode, parameters[0], scaleProperty);
510     if (!isAdd) {
511         ROSEN_LOGD("[%{public}s] : add scale modifier failed\n", __func__);
512         return;
513     }
514 
515     std::vector<std::shared_ptr<RSAnimation>> groupAnimation = {};
516     ScaleAnimationBase(scaleProperty, parameters[0], groupAnimation);
517     AlphaAnimationBase(rsNode, parameters[1], groupAnimation);
518     GroupAnimationStart(rsNode, groupAnimation);
519 }
520 
CalculateOffset(const Drawing::Path & path,const float offsetX,const float offsetY)521 Vector4f RSSymbolAnimation::CalculateOffset(const Drawing::Path& path, const float offsetX, const float offsetY)
522 {
523     auto rect = path.GetBounds();
524     float left = rect.GetLeft();
525     float top = rect.GetTop();
526     // the nodeTranslation is offset of new node to the father node;
527     // the newOffset is offset of path on new node;
528     Vector2f nodeTranslation = { offsetX + left, offsetY + top };
529     Vector2f newOffset = { -left, -top };
530     return Vector4f(nodeTranslation[0], nodeTranslation[1], newOffset[0], newOffset[1]);
531 }
532 
GroupDrawing(const std::shared_ptr<RSCanvasNode> & canvasNode,TextEngine::SymbolNode & symbolNode,const Vector4f & offsets,bool isMultiLayer)533 void RSSymbolAnimation::GroupDrawing(const std::shared_ptr<RSCanvasNode>& canvasNode,
534     TextEngine::SymbolNode& symbolNode, const Vector4f& offsets, bool isMultiLayer)
535 {
536     // if there is mask layer, set the blendmode on the original node rsNode_
537     if (symbolNode.isMask) {
538         rsNode_->SetColorBlendMode(RSColorBlendMode::SRC_OVER);
539         rsNode_->SetColorBlendApplyType(RSColorBlendApplyType::SAVE_LAYER);
540     }
541 
542     // drawing a symbol or a path group
543     auto recordingCanvas = canvasNode->BeginRecording(symbolNode.nodeBoundary[NODE_WIDTH],
544                                                       symbolNode.nodeBoundary[NODE_HEIGHT]);
545     if (isMultiLayer) {
546         DrawPathOnCanvas(recordingCanvas, symbolNode, offsets);
547     } else {
548         DrawSymbolOnCanvas(recordingCanvas, symbolNode, offsets);
549     }
550     canvasNode->FinishRecording();
551 }
552 
DrawSymbolOnCanvas(ExtendRecordingCanvas * recordingCanvas,TextEngine::SymbolNode & symbolNode,const Vector4f & offsets)553 void RSSymbolAnimation::DrawSymbolOnCanvas(
554     ExtendRecordingCanvas* recordingCanvas, TextEngine::SymbolNode& symbolNode, const Vector4f& offsets)
555 {
556     if (recordingCanvas == nullptr) {
557         return;
558     }
559     Drawing::Brush brush;
560     Drawing::Pen pen;
561     Drawing::Point offsetLocal = Drawing::Point { offsets[2], offsets[3] }; // index 2 offsetX 3 offsetY
562     recordingCanvas->AttachBrush(brush);
563     recordingCanvas->AttachPen(pen);
564     recordingCanvas->DrawSymbol(symbolNode.symbolData, offsetLocal);
565     recordingCanvas->DetachBrush();
566     recordingCanvas->DetachPen();
567 }
568 
DrawPathOnCanvas(ExtendRecordingCanvas * recordingCanvas,TextEngine::SymbolNode & symbolNode,const Vector4f & offsets)569 void RSSymbolAnimation::DrawPathOnCanvas(
570     ExtendRecordingCanvas* recordingCanvas, TextEngine::SymbolNode& symbolNode, const Vector4f& offsets)
571 {
572     if (recordingCanvas == nullptr) {
573         return;
574     }
575     Drawing::Brush brush;
576     Drawing::Pen pen;
577     brush.SetAntiAlias(true);
578     pen.SetAntiAlias(true);
579     if (symbolNode.isMask) {
580         brush.SetBlendMode(Drawing::BlendMode::CLEAR);
581         pen.SetBlendMode(Drawing::BlendMode::CLEAR);
582     }
583     for (auto& pathInfo: symbolNode.pathsInfo) {
584         SetIconProperty(brush, pen, pathInfo.color);
585         pathInfo.path.Offset(offsets[2], offsets[3]); // index 2 offsetX 3 offsetY
586         recordingCanvas->AttachBrush(brush);
587         recordingCanvas->AttachPen(pen);
588         recordingCanvas->DrawPath(pathInfo.path);
589         recordingCanvas->DetachBrush();
590         recordingCanvas->DetachPen();
591     }
592 }
593 
SetSymbolGeometry(const std::shared_ptr<RSNode> & rsNode,const Vector4f & bounds)594 bool RSSymbolAnimation::SetSymbolGeometry(const std::shared_ptr<RSNode>& rsNode, const Vector4f& bounds)
595 {
596     if (rsNode == nullptr) {
597         return false;
598     }
599     std::shared_ptr<RSAnimatableProperty<Vector4f>> frameProperty = nullptr;
600     std::shared_ptr<RSAnimatableProperty<Vector4f>> boundsProperty = nullptr;
601 
602     bool isFrameCreate = SymbolAnimation::CreateOrSetModifierValue(frameProperty, bounds);
603     if (isFrameCreate) {
604         auto frameModifier = std::make_shared<RSFrameModifier>(frameProperty);
605         rsNode->AddModifier(frameModifier);
606     }
607     bool isBoundsCreate = SymbolAnimation::CreateOrSetModifierValue(boundsProperty, bounds);
608     if (isBoundsCreate) {
609         auto boundsModifier = std::make_shared<RSBoundsModifier>(boundsProperty);
610         rsNode->AddModifier(boundsModifier);
611     }
612     rsNode_->SetClipToBounds(false);
613     rsNode_->SetClipToFrame(false);
614     return true;
615 }
616 
SetKeyframeAlphaAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)617 bool RSSymbolAnimation::SetKeyframeAlphaAnimation(const std::shared_ptr<RSNode>& rsNode,
618     std::vector<Drawing::DrawingPiecewiseParameter>& parameters,
619     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
620 {
621     if (rsNode == nullptr || symbolAnimationConfig == nullptr) {
622         ROSEN_LOGD("HmSymbol SetVariableColorAnimation::getNode or get symbolAnimationConfig:failed");
623         return false;
624     }
625     alphaPropertyStages_.clear();
626     uint32_t duration = 0;
627     std::vector<float> timePercents;
628     if (!GetKeyframeAlphaAnimationParas(parameters, duration, timePercents)) {
629         return false;
630     }
631 
632     // 0 means the first stage of a node
633     auto alphaModifier = std::make_shared<RSAlphaModifier>(alphaPropertyStages_[0]);
634     rsNode->AddModifier(alphaModifier);
635     std::shared_ptr<RSAnimation> animation = nullptr;
636     animation = KeyframeAlphaSymbolAnimation(rsNode, parameters[0], duration, timePercents);
637     if (animation == nullptr) {
638         return false;
639     }
640 
641     if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::VARIABLE_COLOR &&
642         symbolAnimationConfig->animationMode == 0) {
643         animation->SetRepeatCount(1);
644     } else {
645         animation->SetRepeatCount(-1); // -1 means loop playback
646     }
647     animation->Start(rsNode);
648     return true;
649 }
650 
GetKeyframeAlphaAnimationParas(std::vector<Drawing::DrawingPiecewiseParameter> & oneGroupParas,uint32_t & totalDuration,std::vector<float> & timePercents)651 bool RSSymbolAnimation::GetKeyframeAlphaAnimationParas(
652     std::vector<Drawing::DrawingPiecewiseParameter>& oneGroupParas,
653     uint32_t& totalDuration, std::vector<float>& timePercents)
654 {
655     if (oneGroupParas.empty()) {
656         return false;
657     }
658     totalDuration = 0;
659     // traverse all time stages
660     for (size_t i = 0; i < oneGroupParas.size(); i++) {
661         int interval = 0;
662         if (i + 1 < oneGroupParas.size()) {
663             interval = oneGroupParas[i + 1].delay -
664                        (static_cast<int>(oneGroupParas[i].duration) + oneGroupParas[i].delay);
665         } else {
666             interval = 0;
667         }
668         if (interval < 0) {
669             return false;
670         }
671         totalDuration = oneGroupParas[i].duration + totalDuration + static_cast<uint32_t>(interval);
672         if (!SymbolAnimation::ElementInMap(ALPHA_PROP, oneGroupParas[i].properties) ||
673             oneGroupParas[i].properties[ALPHA_PROP].size() != PROPERTIES) {
674             return false;
675         }
676         // the value of the key frame needs
677         float alphaValueStart = oneGroupParas[i].properties[ALPHA_PROP][PROP_START];
678         std::shared_ptr<RSAnimatableProperty<float>> alphaPropertyStart = nullptr;
679         SymbolAnimation::CreateOrSetModifierValue(alphaPropertyStart, alphaValueStart);
680         alphaPropertyStages_.push_back(alphaPropertyStart);
681 
682         float alphaValueEnd = oneGroupParas[i].properties[ALPHA_PROP][PROP_END];
683         std::shared_ptr<RSAnimatableProperty<float>> alphaPropertyEnd = nullptr;
684         SymbolAnimation::CreateOrSetModifierValue(alphaPropertyEnd, alphaValueEnd);
685         alphaPropertyStages_.push_back(alphaPropertyEnd);
686     }
687     return CalcTimePercents(timePercents, totalDuration, oneGroupParas);
688 }
689 
CalcTimePercents(std::vector<float> & timePercents,const uint32_t totalDuration,const std::vector<Drawing::DrawingPiecewiseParameter> & oneGroupParas)690 bool RSSymbolAnimation::CalcTimePercents(std::vector<float>& timePercents, const uint32_t totalDuration,
691     const std::vector<Drawing::DrawingPiecewiseParameter>& oneGroupParas)
692 {
693     if (totalDuration == 0) {
694         return false;
695     }
696     uint32_t duration = 0;
697     timePercents.push_back(0); // the first property of timePercent
698     for (int i = 0; i < static_cast<int>(oneGroupParas.size()) - 1; i++) {
699         int interval = 0; // Interval between two animations
700         duration = duration + oneGroupParas[i].duration;
701         SymbolAnimation::CalcOneTimePercent(timePercents, totalDuration, duration);
702         interval = oneGroupParas[i + 1].delay -
703                    (static_cast<int>(oneGroupParas[i].duration) + oneGroupParas[i].delay);
704         if (interval < 0) {
705             return false;
706         }
707         duration = duration + static_cast<uint32_t>(interval);
708         SymbolAnimation::CalcOneTimePercent(timePercents, totalDuration, duration);
709     }
710     duration = duration + oneGroupParas.back().duration;
711     SymbolAnimation::CalcOneTimePercent(timePercents, totalDuration, duration);
712     return true;
713 }
714 
SetIconProperty(Drawing::Brush & brush,Drawing::Pen & pen,Drawing::DrawingSColor & color)715 void RSSymbolAnimation::SetIconProperty(Drawing::Brush& brush, Drawing::Pen& pen, Drawing::DrawingSColor& color)
716 {
717     brush.SetColor(Drawing::Color::ColorQuadSetARGB(0xFF, color.r, color.g, color.b));
718     brush.SetAlphaF(color.a);
719     brush.SetAntiAlias(true);
720 
721     pen.SetColor(Drawing::Color::ColorQuadSetARGB(0xFF, color.r, color.g, color.b));
722     pen.SetAlphaF(color.a);
723     pen.SetAntiAlias(true);
724     return;
725 }
726 
KeyframeAlphaSymbolAnimation(const std::shared_ptr<RSNode> & rsNode,const Drawing::DrawingPiecewiseParameter & oneStageParas,const uint32_t duration,const std::vector<float> & timePercents)727 std::shared_ptr<RSAnimation> RSSymbolAnimation::KeyframeAlphaSymbolAnimation(const std::shared_ptr<RSNode>& rsNode,
728     const Drawing::DrawingPiecewiseParameter& oneStageParas, const uint32_t duration,
729     const std::vector<float>& timePercents)
730 {
731     if (alphaPropertyStages_.size() == 0 || timePercents.size() != alphaPropertyStages_.size()) {
732         return nullptr;
733     }
734     auto keyframeAnimation = std::make_shared<RSKeyframeAnimation>(alphaPropertyStages_[0]); // initial the alpha status
735     if (keyframeAnimation == nullptr || rsNode == nullptr) {
736         return nullptr;
737     }
738     keyframeAnimation->SetStartDelay(oneStageParas.delay);
739     keyframeAnimation->SetDuration(duration);
740     RSAnimationTimingCurve timingCurve;
741     SymbolAnimation::CreateAnimationTimingCurve(oneStageParas.curveType, oneStageParas.curveArgs, timingCurve);
742     std::vector<std::tuple<float, std::shared_ptr<RSPropertyBase>, RSAnimationTimingCurve>> keyframes;
743     for (unsigned int i = 1; i < alphaPropertyStages_.size(); i++) {
744         keyframes.push_back(std::make_tuple(timePercents[i], alphaPropertyStages_[i], timingCurve));
745     }
746     keyframeAnimation->AddKeyFrames(keyframes);
747     return keyframeAnimation;
748 }
749 
750 /**
751  * @brief creates a scaleModifier by scaleParamter and adds it to rsNode
752  * @param rsNode is the node of symbol animation
753  * @param scaleParamter is the parameter of the scale effect
754  * @param scaleProperty property of the scale effect
755  * @return true if add scale modifer success
756  */
AddScaleBaseModifier(const std::shared_ptr<RSNode> & rsNode,Drawing::DrawingPiecewiseParameter & scaleParameter,std::shared_ptr<RSAnimatableProperty<Vector2f>> & scaleProperty)757 bool RSSymbolAnimation::AddScaleBaseModifier(const std::shared_ptr<RSNode>& rsNode,
758     Drawing::DrawingPiecewiseParameter& scaleParameter,
759     std::shared_ptr<RSAnimatableProperty<Vector2f>>& scaleProperty)
760 {
761     // validation input
762     if (rsNode == nullptr) {
763         ROSEN_LOGD("[%{public}s] : invalid input \n", __func__);
764         return false;
765     }
766     if (scaleParameter.properties.count(SCALE_PROP_X) <= 0 || scaleParameter.properties.count(SCALE_PROP_Y) <= 0 ||
767         scaleParameter.properties[SCALE_PROP_X].size() < PROPERTIES ||
768         scaleParameter.properties[SCALE_PROP_Y].size() < PROPERTIES) {
769         ROSEN_LOGD("[%{public}s] : invalid input \n", __func__);
770         return false;
771     }
772 
773     SetNodePivot(rsNode);
774 
775     const Vector2f scaleValueBegin = {scaleParameter.properties[SCALE_PROP_X][0],
776         scaleParameter.properties[SCALE_PROP_Y][0]};
777 
778     bool isCreate = SymbolAnimation::CreateOrSetModifierValue(scaleProperty, scaleValueBegin);
779     if (!isCreate) {
780         ROSEN_LOGD("[%{public}s] : invalid parameter \n", __func__);
781         return false;
782     }
783 
784     auto scaleModifier = std::make_shared<Rosen::RSScaleModifier>(scaleProperty);
785     rsNode->AddModifier(scaleModifier);
786     return true;
787 }
788 
789 // base atomizated animation
ScaleAnimationBase(std::shared_ptr<RSAnimatableProperty<Vector2f>> & scaleProperty,Drawing::DrawingPiecewiseParameter & scaleParameter,std::vector<std::shared_ptr<RSAnimation>> & animations)790 void RSSymbolAnimation::ScaleAnimationBase(std::shared_ptr<RSAnimatableProperty<Vector2f>>& scaleProperty,
791     Drawing::DrawingPiecewiseParameter& scaleParameter, std::vector<std::shared_ptr<RSAnimation>>& animations)
792 {
793     if (scaleProperty == nullptr) {
794         ROSEN_LOGD("[%{public}s] : scaleProperty is nullptr \n", __func__);
795         return;
796     }
797 
798     if (scaleParameter.properties.count(SCALE_PROP_X) <= 0 || scaleParameter.properties.count(SCALE_PROP_Y) <= 0 ||
799         scaleParameter.properties[SCALE_PROP_X].size() < PROPERTIES ||
800         scaleParameter.properties[SCALE_PROP_Y].size() < PROPERTIES) {
801         ROSEN_LOGD("[%{public}s] : invalid input \n", __func__);
802         return;
803     }
804 
805     const Vector2f scaleValueEnd = {scaleParameter.properties[SCALE_PROP_X][PROP_END],
806         scaleParameter.properties[SCALE_PROP_Y][PROP_END]};
807 
808     // set animation curve and protocol
809     RSAnimationTimingCurve scaleCurve;
810     SymbolAnimation::CreateAnimationTimingCurve(scaleParameter.curveType, scaleParameter.curveArgs, scaleCurve);
811 
812     RSAnimationTimingProtocol scaleprotocol;
813     scaleprotocol.SetStartDelay(scaleParameter.delay);
814     if (scaleParameter.duration > 0) {
815         scaleprotocol.SetDuration(scaleParameter.duration);
816     }
817 
818     // set animation
819     std::vector<std::shared_ptr<RSAnimation>> animations1 = RSNode::Animate(
820         scaleprotocol, scaleCurve, [&scaleProperty, &scaleValueEnd]() { scaleProperty->Set(scaleValueEnd); });
821 
822     if (animations1.size() > 0 && animations1[0] != nullptr) {
823         animations.emplace_back(animations1[0]);
824     }
825 }
826 
AlphaAnimationBase(const std::shared_ptr<RSNode> & rsNode,Drawing::DrawingPiecewiseParameter & alphaParameter,std::vector<std::shared_ptr<RSAnimation>> & animations)827 void RSSymbolAnimation::AlphaAnimationBase(const std::shared_ptr<RSNode>& rsNode,
828     Drawing::DrawingPiecewiseParameter& alphaParameter, std::vector<std::shared_ptr<RSAnimation>>& animations)
829 {
830     // validation input
831     if (rsNode == nullptr) {
832         ROSEN_LOGD("[%{public}s] : invalid input \n", __func__);
833         return;
834     }
835     if (alphaParameter.properties.count("alpha") <= 0 || alphaParameter.properties["alpha"].size() < PROPERTIES) {
836         ROSEN_LOGD("[%{public}s] : invalid input \n", __func__);
837         return;
838     }
839 
840     float alphaBegin = static_cast<float>(alphaParameter.properties["alpha"][PROP_START]);
841     float alphaValueEnd = static_cast<float>(alphaParameter.properties["alpha"][PROP_END]);
842 
843     std::shared_ptr<RSAnimatableProperty<float>> alphaProperty;
844 
845     if (!SymbolAnimation::CreateOrSetModifierValue(alphaProperty, alphaBegin)) {
846         return;
847     }
848     auto alphaModifier = std::make_shared<Rosen::RSAlphaModifier>(alphaProperty);
849 
850     rsNode->AddModifier(alphaModifier);
851 
852     RSAnimationTimingProtocol alphaProtocol;
853     alphaProtocol.SetStartDelay(alphaParameter.delay);
854     alphaProtocol.SetDuration(alphaParameter.duration);
855     RSAnimationTimingCurve alphaCurve;
856     SymbolAnimation::CreateAnimationTimingCurve(alphaParameter.curveType, alphaParameter.curveArgs, alphaCurve);
857 
858     std::vector<std::shared_ptr<RSAnimation>> animations1 = RSNode::Animate(
859         alphaProtocol, alphaCurve, [&alphaProperty, &alphaValueEnd]() { alphaProperty->Set(alphaValueEnd); });
860 
861     if (animations1.size() > 0 && animations1[0] != nullptr) {
862         animations.emplace_back(animations1[0]);
863     }
864 }
865 } // namespace Rosen
866 } // namespace OHOS