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