• 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 <cmath>
17 
18 #include "animation/rs_keyframe_animation.h"
19 #include "animation/rs_symbol_animation.h"
20 #include "draw/paint.h"
21 #include "modifier_ng/appearance/rs_alpha_modifier.h"
22 #include "modifier_ng/appearance/rs_foreground_filter_modifier.h"
23 #include "modifier_ng/geometry/rs_bounds_modifier.h"
24 #include "modifier_ng/geometry/rs_frame_modifier.h"
25 #include "modifier_ng/geometry/rs_transform_modifier.h"
26 #include "platform/common/rs_log.h"
27 #include "rs_trace.h"
28 #include "skia_txt/default_symbol_config.h"
29 #include "utils/point.h"
30 
31 namespace OHOS {
32 namespace Rosen {
33 using SymnolBaseFunc = std::function<void(const Drawing::DrawingPiecewiseParameter& parameter)>;
34 using SymbolBaseFuncMap = std::unordered_map<std::string, SymnolBaseFunc>;
35 
36 static const Vector2f CENTER_NODE_COORDINATE = { 0.5f, 0.5f }; // scale center node
37 static const std::string SCALE_PROP_X = "sx";
38 static const std::string SCALE_PROP_Y = "sy";
39 static const std::string ALPHA_PROP = "alpha";
40 static const std::string BLUR_PROP = "blur";
41 static const std::string TRANSLATE_PROP_X = "tx";
42 static const std::string TRANSLATE_PROP_Y = "ty";
43 static const std::string TRANSLATE_RATIO = "tr";
44 static const std::string CLIP_PROP = "clip";
45 static const size_t PROPERTIES = 2; // symbol animation property contains two values, change from one to the other
46 static const unsigned int PROP_START = 0; // symbol animation property contains two values, change from START to the END
47 static const unsigned int PROP_END = 1; // symbol animation property contains two values, change from START to the END
48 static const unsigned int NODE_WIDTH = 2;
49 static const unsigned int NODE_HEIGHT = 3;
50 static const unsigned int INVALID_STATUS = 0; // invalid status label
51 static const unsigned int APPEAR_STATUS = 1 ; // appear status label
52 static const float EXPANSION_RATIO = 0.1f; // the proportion than needs to be expanded
53 
54 namespace SymbolAnimation {
55 template<typename T>
CreateOrSetModifierValue(std::shared_ptr<RSAnimatableProperty<T>> & property,const T & value)56 bool CreateOrSetModifierValue(std::shared_ptr<RSAnimatableProperty<T>>& property, const T& value)
57 {
58     if (property == nullptr) {
59         property = std::make_shared<RSAnimatableProperty<T>>(value);
60         return true;
61     }
62     property->Set(value);
63     return false;
64 }
65 
66 template<typename T>
ElementInMap(const std::string & curElement,const std::map<std::string,T> & curMap)67 bool ElementInMap(const std::string& curElement, const std::map<std::string, T>& curMap)
68 {
69     auto element = curMap.find(curElement);
70     return (element != curMap.end());
71 }
72 
CurveArgsInMap(const std::string & curElement,const std::map<std::string,float> & curMap)73 float CurveArgsInMap(const std::string& curElement, const std::map<std::string, float>& curMap)
74 {
75     auto element = curMap.find(curElement);
76     if (element == curMap.end()) {
77         return 0.0f;
78     }
79     return element->second;
80 }
81 
CreateAnimationTimingCurve(const OHOS::Rosen::Drawing::DrawingCurveType type,const std::map<std::string,float> & curveArgs,RSAnimationTimingCurve & curve)82 void CreateAnimationTimingCurve(const OHOS::Rosen::Drawing::DrawingCurveType type,
83     const std::map<std::string, float>& curveArgs, RSAnimationTimingCurve& curve)
84 {
85     curve = RSAnimationTimingCurve();
86     if (type == OHOS::Rosen::Drawing::DrawingCurveType::LINEAR) {
87         curve = RSAnimationTimingCurve::LINEAR;
88     } else if (type == OHOS::Rosen::Drawing::DrawingCurveType::SPRING) {
89         float scaleVelocity = CurveArgsInMap("velocity", curveArgs);
90         float scaleMass = CurveArgsInMap("mass", curveArgs);
91         float scaleStiffness = CurveArgsInMap("stiffness", curveArgs);
92         float scaleDamping = CurveArgsInMap("damping", curveArgs);
93         curve = RSAnimationTimingCurve::CreateInterpolatingSpring(scaleMass, scaleStiffness, scaleDamping,
94                                                                   scaleVelocity);
95     } else if (type == OHOS::Rosen::Drawing::DrawingCurveType::FRICTION ||
96         type == OHOS::Rosen::Drawing::DrawingCurveType::SHARP) {
97         float ctrlX1 = CurveArgsInMap("ctrlX1", curveArgs);
98         float ctrlY1 = CurveArgsInMap("ctrlY1", curveArgs);
99         float ctrlX2 = CurveArgsInMap("ctrlX2", curveArgs);
100         float ctrlY2 = CurveArgsInMap("ctrlY2", curveArgs);
101         curve = RSAnimationTimingCurve::CreateCubicCurve(ctrlX1, ctrlY1, ctrlX2, ctrlY2);
102     }
103 }
104 
CalcOneTimePercent(std::vector<float> & timePercents,const uint32_t totalDuration,const uint32_t duration)105 void CalcOneTimePercent(std::vector<float>& timePercents, const uint32_t totalDuration, const uint32_t duration)
106 {
107     if (totalDuration == 0) {
108         return;
109     }
110     float timePercent = static_cast<float>(duration) / static_cast<float>(totalDuration);
111     timePercent = timePercent > 1 ? 1.0 : timePercent;
112     timePercents.push_back(timePercent);
113 }
114 } // namespace SymbolAnimation
115 
RSSymbolAnimation()116 RSSymbolAnimation::RSSymbolAnimation() {}
117 
~RSSymbolAnimation()118 RSSymbolAnimation::~RSSymbolAnimation() {}
119 
120 /**
121  * @brief SymbolAnimation interface for arkui
122  * @param symbolAnimationConfig indicates all the information about a symbol
123  * @return true if set animation success
124  */
SetSymbolAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)125 bool RSSymbolAnimation::SetSymbolAnimation(
126     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
127 {
128     RS_TRACE_FUNC();
129     if (rsNode_ == nullptr || symbolAnimationConfig == nullptr) {
130         ROSEN_LOGD("HmSymbol RSSymbolAnimation::getNode or get symbolAnimationConfig:failed");
131         return false;
132     }
133 
134     if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::NONE) {
135         std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
136         rsNode_->replaceNodesSwapArr_[INVALID_STATUS].clear();
137         rsNode_->replaceNodesSwapArr_[APPEAR_STATUS].clear();
138         rsNode_->canvasNodesListMap_.erase(symbolAnimationConfig->symbolSpanId);
139         return true; // pre code already clear nodes.
140     }
141 
142     if (!symbolAnimationConfig->currentAnimationHasPlayed) {
143         switch (symbolAnimationConfig->effectStrategy) {
144             case Drawing::DrawingEffectStrategy::REPLACE_APPEAR:
145             case Drawing::DrawingEffectStrategy::QUICK_REPLACE_APPEAR:
146                 PopNodeFromReplaceList(symbolAnimationConfig->symbolSpanId);
147                 break;
148             case Drawing::DrawingEffectStrategy::TEXT_FLIP:
149                 PopNodeFromFlipList(symbolAnimationConfig->symbolSpanId);
150                 break;
151             default:
152                 NodeProcessBeforeAnimation(symbolAnimationConfig);
153                 break;
154         }
155     }
156 
157     InitSupportAnimationTable(symbolAnimationConfig);
158 
159     switch (symbolAnimationConfig->effectStrategy) {
160         case Drawing::DrawingEffectStrategy::REPLACE_APPEAR:
161         case Drawing::DrawingEffectStrategy::QUICK_REPLACE_APPEAR:
162             return SetReplaceAnimation(symbolAnimationConfig);
163         case Drawing::DrawingEffectStrategy::TEXT_FLIP:
164             return SetTextFlipAnimation(symbolAnimationConfig);
165         case Drawing::DrawingEffectStrategy::DISABLE:
166             return SetDisableAnimation(symbolAnimationConfig);
167         default:
168             return SetPublicAnimation(symbolAnimationConfig);
169     }
170 }
171 
NodeProcessBeforeAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)172 void RSSymbolAnimation::NodeProcessBeforeAnimation(
173     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
174 {
175     std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
176     rsNode_->canvasNodesListMap_.erase(symbolAnimationConfig->symbolSpanId);
177 }
178 
PopNodeFromReplaceList(uint64_t symbolSpanId)179 void RSSymbolAnimation::PopNodeFromReplaceList(uint64_t symbolSpanId)
180 {
181     PopNodeFromReplaceList(symbolSpanId, rsNode_);
182     std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
183     if (rsNode_->canvasNodesListMap_[symbolSpanId].find(symbolSpanId) !=
184         rsNode_->canvasNodesListMap_[symbolSpanId].end()) {
185         PopNodeFromReplaceList(symbolSpanId, rsNode_->canvasNodesListMap_[symbolSpanId][symbolSpanId]);
186     }
187 }
188 
PopNodeFromReplaceList(uint64_t symbolSpanId,const std::shared_ptr<RSNode> & rsNode)189 void RSSymbolAnimation::PopNodeFromReplaceList(uint64_t symbolSpanId,
190     const std::shared_ptr<RSNode>& rsNode)
191 {
192     std::lock_guard<std::mutex> lock(rsNode->childrenNodeLock_);
193     if (rsNode->canvasNodesListMap_.count(symbolSpanId) == 0) {
194         rsNode->canvasNodesListMap_[symbolSpanId] = {};
195     }
196 
197     for (const auto& config : rsNode->replaceNodesSwapArr_[INVALID_STATUS]) {
198         rsNode->canvasNodesListMap_[symbolSpanId].erase(config.nodeId);
199     }
200     rsNode->replaceNodesSwapArr_[INVALID_STATUS].clear();
201 }
202 
PopNodeFromFlipList(uint64_t symbolSpanId)203 void RSSymbolAnimation::PopNodeFromFlipList(uint64_t symbolSpanId)
204 {
205     std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
206     auto it = rsNode_->canvasNodesListMap_.find(symbolSpanId);
207     if (it == rsNode_->canvasNodesListMap_.end()) {
208         it = rsNode_->canvasNodesListMap_.insert({symbolSpanId,
209             std::unordered_map<NodeId, std::shared_ptr<RSNode>>()}).first;
210     }
211     it->second.erase(INVALID_STATUS);
212 }
213 
214 /**
215  * @brief Set Disappear config of replace animation
216  * @param symbolAnimationConfig is the symbol animation config of new symbol
217  * @param disappearConfig set the symbol animation config of old symbol
218  */
SetDisappearConfig(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::shared_ptr<TextEngine::SymbolAnimationConfig> & disappearConfig,const std::shared_ptr<RSNode> & rsNode)219 bool RSSymbolAnimation::SetDisappearConfig(
220     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
221     std::shared_ptr<TextEngine::SymbolAnimationConfig>& disappearConfig,
222     const std::shared_ptr<RSNode>& rsNode)
223 {
224     if (symbolAnimationConfig == nullptr || disappearConfig == nullptr) {
225         ROSEN_LOGD("[%{public}s]: symbolAnimationConfig or disappearConfig is nullptr", __func__);
226         return false;
227     }
228 
229     disappearConfig->repeatCount = symbolAnimationConfig->repeatCount;
230     disappearConfig->animationMode = symbolAnimationConfig->animationMode;
231     disappearConfig->animationStart = symbolAnimationConfig->animationStart;
232     disappearConfig->symbolSpanId = symbolAnimationConfig->symbolSpanId;
233     disappearConfig->commonSubType = symbolAnimationConfig->commonSubType;
234     disappearConfig->effectStrategy = symbolAnimationConfig->effectStrategy;
235 
236     // count node levels and animation levels
237     uint32_t numNodes = 0;
238     int animationLevelNum = -1; // -1 is initial value, that is no animation levels
239     const auto& disappearNodes = rsNode->replaceNodesSwapArr_[APPEAR_STATUS];
240     for (const auto& config : disappearNodes) {
241         TextEngine::SymbolNode symbolNode;
242         symbolNode.animationIndex = config.symbolNode.animationIndex;
243         disappearConfig->symbolNodes.push_back(symbolNode);
244         animationLevelNum =
245             animationLevelNum < symbolNode.animationIndex ? symbolNode.animationIndex : animationLevelNum;
246         numNodes++;
247     }
248     disappearConfig->numNodes = numNodes;
249     // 0 is the byLayer effect and 1 is the wholeSymbol effect
250     disappearConfig->animationMode = animationLevelNum > 0 ? 0 : 1;
251     return numNodes > 0;
252 }
253 
SetReplaceAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)254 bool RSSymbolAnimation::SetReplaceAnimation(
255     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
256 {
257     std::shared_ptr<RSNode> rsNode = nullptr;
258     CreateSameNode(symbolAnimationConfig->symbolSpanId, rsNode, rsNode_);
259     if (rsNode == nullptr) {
260         ROSEN_LOGE("Failed to create rsNode");
261         return false;
262     }
263     // if there is mask layer, set the blendmode on the original node rsNode_
264     if (isMaskSymbol_) {
265         rsNode_->SetColorBlendMode(RSColorBlendMode::SRC_OVER);
266         rsNode_->SetColorBlendApplyType(RSColorBlendApplyType::SAVE_LAYER_ALPHA);
267     }
268     // set shadow
269     if (symbolAnimationConfig->symbolShadow.has_value()) {
270         auto symbolShadow = symbolAnimationConfig->symbolShadow.value();
271         SetSymbolShadow(symbolShadow, rsNode);
272     }
273 
274     if (!symbolAnimationConfig->currentAnimationHasPlayed) {
275         auto disappearConfig = std::make_shared<TextEngine::SymbolAnimationConfig>();
276         if (SetDisappearConfig(symbolAnimationConfig, disappearConfig, rsNode)) {
277             SetReplaceDisappear(disappearConfig, rsNode);
278         }
279     }
280     SetReplaceAppear(symbolAnimationConfig, rsNode,
281         !rsNode->replaceNodesSwapArr_[INVALID_STATUS].empty());
282     return true;
283 }
284 
SetReplaceDisappear(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,const std::shared_ptr<RSNode> & rsNode)285 bool RSSymbolAnimation::SetReplaceDisappear(
286     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
287     const std::shared_ptr<RSNode>& rsNode)
288 {
289     if (symbolAnimationConfig->numNodes == 0) {
290         ROSEN_LOGD("[%{public}s] numNodes in symbolAnimationConfig is 0", __func__);
291         return false;
292     }
293 
294     auto& disappearNodes = rsNode->replaceNodesSwapArr_[APPEAR_STATUS];
295     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
296     Drawing::DrawingEffectStrategy effectStrategy;
297     if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::REPLACE_APPEAR) {
298         effectStrategy = Drawing::DrawingEffectStrategy::REPLACE_DISAPPEAR;
299     } else if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::QUICK_REPLACE_APPEAR) {
300         effectStrategy = Drawing::DrawingEffectStrategy::QUICK_REPLACE_DISAPPEAR;
301     }
302 
303     bool res = GetAnimationGroupParameters(symbolAnimationConfig, parameters, effectStrategy);
304     for (const auto& config : disappearNodes) {
305         if (!res || (config.symbolNode.animationIndex < 0)) {
306             ROSEN_LOGD("[%{public}s] invalid initial parameter", __func__);
307             continue;
308         }
309         if (parameters.size() <= static_cast<size_t>(config.symbolNode.animationIndex) ||
310             parameters[config.symbolNode.animationIndex].empty()) {
311             ROSEN_LOGD("[%{public}s] invalid parameter", __func__);
312             continue;
313         }
314         auto canvasNode = rsNode->canvasNodesListMap_[symbolAnimationConfig->symbolSpanId][config.nodeId];
315         SpliceAnimation(canvasNode, parameters[config.symbolNode.animationIndex]);
316     }
317     {
318         std::lock_guard<std::mutex> lock(rsNode->childrenNodeLock_);
319         swap(rsNode->replaceNodesSwapArr_[INVALID_STATUS], rsNode->replaceNodesSwapArr_[APPEAR_STATUS]);
320     }
321     return true;
322 }
323 
SetReplaceAppear(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,const std::shared_ptr<RSNode> & rsNode,bool isStartAnimation)324 bool RSSymbolAnimation::SetReplaceAppear(
325     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
326     const std::shared_ptr<RSNode>& rsNode,
327     bool isStartAnimation)
328 {
329     if (symbolAnimationConfig->symbolNodes.empty()) {
330         ROSEN_LOGD("[%{public}s] symbol nodes is empty", __func__);
331         return false;
332     }
333     const auto& symbolFirstNode = symbolAnimationConfig->symbolNodes[0]; // calculate offset by the first node
334     Vector4f offsets = CalculateOffset(symbolFirstNode.symbolData.path_,
335         symbolFirstNode.nodeBoundary[0], symbolFirstNode.nodeBoundary[1]); // index 0 offsetX and 1 offsetY of layout
336     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
337     bool res = GetAnimationGroupParameters(symbolAnimationConfig, parameters, symbolAnimationConfig->effectStrategy);
338     uint32_t nodeNum = symbolAnimationConfig->numNodes;
339     rsNode->replaceNodesSwapArr_[APPEAR_STATUS].resize(nodeNum);
340     for (uint32_t n = 0; n < nodeNum; n++) {
341         auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
342         auto bounds = Vector4f(offsets[0], offsets[1], symbolNode.nodeBoundary[NODE_WIDTH],
343             symbolNode.nodeBoundary[NODE_HEIGHT]);
344         std::shared_ptr<RSCanvasNode> canvasNode = nullptr;
345         bool createNewNode = CreateSymbolReplaceNode(symbolAnimationConfig, bounds, n, rsNode, canvasNode);
346         if (canvasNode == nullptr) {
347             return false;
348         }
349         GroupDrawing(canvasNode, symbolNode, offsets);
350         bool isInValid = !res || !isStartAnimation || symbolNode.animationIndex < 0 ||
351                          parameters.size() <= static_cast<size_t>(symbolNode.animationIndex);
352         if (isInValid) {
353             ROSEN_LOGD("[%{public}s] invalid animationIndex or parameter", __func__);
354             continue;
355         }
356 
357         if (createNewNode) {
358             SpliceAnimation(canvasNode, parameters[symbolNode.animationIndex]);
359         }
360     }
361     return true;
362 }
363 
CreateSymbolNode(const Vector4f & bounds,uint64_t symbolSpanId,uint32_t index,const std::shared_ptr<RSNode> & rsNode,std::shared_ptr<RSCanvasNode> & canvasNode)364 bool RSSymbolAnimation::CreateSymbolNode(const Vector4f& bounds, uint64_t symbolSpanId, uint32_t index,
365     const std::shared_ptr<RSNode>& rsNode, std::shared_ptr<RSCanvasNode>& canvasNode)
366 {
367     if (rsNode == nullptr) {
368         return false;
369     }
370     std::lock_guard<std::mutex> lock(rsNode->childrenNodeLock_);
371     bool createNewNode = false;
372     auto outerIter = rsNode->canvasNodesListMap_.find(symbolSpanId);
373     if (outerIter == rsNode->canvasNodesListMap_.end()) {
374         outerIter = rsNode->canvasNodesListMap_.insert({symbolSpanId,
375                     std::unordered_map<NodeId, std::shared_ptr<RSNode>>()}).first;
376         createNewNode = true;
377     }
378 
379     NodeId nodeId = static_cast<NodeId>(index);
380     createNewNode = createNewNode || outerIter->second.find(nodeId) == outerIter->second.end();
381     if (!createNewNode) {
382         UpdateSymbolGeometry(rsNode->canvasNodesListMap_[symbolSpanId][nodeId], bounds);
383         canvasNode = std::static_pointer_cast<RSCanvasNode>(rsNode->canvasNodesListMap_[symbolSpanId][nodeId]);
384         return false;
385     }
386     canvasNode = RSCanvasNode::Create(false, false, rsNode->GetRSUIContext());
387     outerIter->second.insert({nodeId, canvasNode});
388     SetSymbolGeometry(canvasNode, bounds);
389     rsNode->AddChild(canvasNode, -1);
390     return true;
391 }
392 
CreateSymbolReplaceNode(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,const Vector4f & bounds,uint32_t index,const std::shared_ptr<RSNode> & rsNode,std::shared_ptr<RSCanvasNode> & canvasNode)393 bool RSSymbolAnimation::CreateSymbolReplaceNode(
394     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
395     const Vector4f& bounds, uint32_t index, const std::shared_ptr<RSNode>& rsNode,
396     std::shared_ptr<RSCanvasNode>& canvasNode)
397 {
398     if (rsNode == nullptr) {
399         return false;
400     }
401     std::lock_guard<std::mutex> lock(rsNode->childrenNodeLock_);
402 
403     bool createNewNode = false;
404     auto symbolSpanId = symbolAnimationConfig->symbolSpanId;
405     auto outerIter = rsNode->canvasNodesListMap_.find(symbolSpanId);
406     if (outerIter == rsNode->canvasNodesListMap_.end()) {
407         outerIter = rsNode->canvasNodesListMap_.insert({symbolSpanId,
408                     std::unordered_map<NodeId, std::shared_ptr<RSNode>>()}).first;
409         createNewNode = true;
410     }
411     NodeId nodeId = rsNode->replaceNodesSwapArr_[APPEAR_STATUS][index].nodeId;
412     createNewNode = createNewNode || outerIter->second.find(nodeId) == outerIter->second.end() ||
413                     rsNode->replaceNodesSwapArr_[APPEAR_STATUS][index].animationIndex < 0;
414     if (!createNewNode) {
415         UpdateSymbolGeometry(rsNode->canvasNodesListMap_[symbolSpanId][nodeId], bounds);
416         canvasNode = std::static_pointer_cast<RSCanvasNode>(rsNode->canvasNodesListMap_[symbolSpanId][nodeId]);
417         return false;
418     }
419 
420     canvasNode = RSCanvasNode::Create(false, false, rsNode->GetRSUIContext());
421     nodeId = canvasNode->GetId();
422     outerIter->second.insert({nodeId, canvasNode});
423     SetSymbolGeometry(canvasNode, bounds);
424     rsNode->AddChild(canvasNode, -1);
425     auto& symbolNode = symbolAnimationConfig->symbolNodes[index];
426     AnimationNodeConfig appearNodeConfig = {.symbolNode = symbolNode,
427                                             .nodeId = nodeId,
428                                             .animationIndex = symbolNode.animationIndex};
429     rsNode->replaceNodesSwapArr_[APPEAR_STATUS][index] = appearNodeConfig;
430     return true;
431 }
432 
InitSupportAnimationTable(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)433 void RSSymbolAnimation::InitSupportAnimationTable(
434     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
435 {
436     // Init public animation list
437     if (publicSupportAnimations_.empty()) {
438         publicSupportAnimations_ = {Drawing::DrawingEffectStrategy::BOUNCE,
439                                     Drawing::DrawingEffectStrategy::APPEAR,
440                                     Drawing::DrawingEffectStrategy::DISAPPEAR,
441                                     Drawing::DrawingEffectStrategy::SCALE};
442     }
443     if (upAndDownSupportAnimations_.empty()) {
444         upAndDownSupportAnimations_ = {Drawing::DrawingEffectStrategy::BOUNCE,
445                                        Drawing::DrawingEffectStrategy::SCALE,
446                                        Drawing::DrawingEffectStrategy::DISABLE};
447     }
448 
449     range_ = std::nullopt;
450     Vector4f bounds = rsNode_->GetStagingProperties().GetBounds();
451     symbolBounds_ = Vector4f(0.0f, 0.0f, bounds.z_, bounds.w_);
452     isMaskSymbol_ = false;
453     for (const auto& symbolNode: symbolAnimationConfig->symbolNodes) {
454         if (symbolNode.isMask) {
455             isMaskSymbol_ = true;
456             return;
457         }
458     }
459 }
460 
GetAnimationGroupParameters(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> & parameters,Drawing::DrawingEffectStrategy & effectStrategy)461 bool RSSymbolAnimation::GetAnimationGroupParameters(
462     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
463     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>>& parameters,
464     Drawing::DrawingEffectStrategy& effectStrategy)
465 {
466     // count animation levels
467     int animationLevelNum = -1;
468     auto nodeNum = symbolAnimationConfig->numNodes;
469     for (uint32_t n = 0; n < nodeNum; n++) {
470         const auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
471         animationLevelNum =
472             animationLevelNum < symbolNode.animationIndex ? symbolNode.animationIndex : animationLevelNum;
473     }
474 
475     if (animationLevelNum < 0) {
476         ROSEN_LOGD("[%{public}s] HmSymbol: this symbol does not have an animated layer", __func__);
477         return false;
478     }
479     animationLevelNum = animationLevelNum + 1;
480 
481     // get animation group paramaters
482     auto it = std::find(upAndDownSupportAnimations_.begin(), upAndDownSupportAnimations_.end(), effectStrategy);
483     if (it != upAndDownSupportAnimations_.end()) {
484         parameters = OHOS::Rosen::Symbol::DefaultSymbolConfig::GetInstance()->GetGroupParameters(
485             Drawing::DrawingAnimationType(effectStrategy), static_cast<uint16_t>(animationLevelNum),
486             symbolAnimationConfig->animationMode, symbolAnimationConfig->commonSubType);
487     } else {
488         parameters = OHOS::Rosen::Symbol::DefaultSymbolConfig::GetInstance()->GetGroupParameters(
489             Drawing::DrawingAnimationType(effectStrategy), static_cast<uint16_t>(animationLevelNum),
490             symbolAnimationConfig->animationMode);
491     }
492     if (parameters.empty()) {
493         ROSEN_LOGD("[%{public}s] HmSymbol: GetGroupParameters failed", __func__);
494         return false;
495     }
496     return true;
497 }
498 
ChooseAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)499 bool RSSymbolAnimation::ChooseAnimation(const std::shared_ptr<RSNode>& rsNode,
500     std::vector<Drawing::DrawingPiecewiseParameter>& parameters,
501     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
502 {
503     if (std::count(publicSupportAnimations_.begin(),
504         publicSupportAnimations_.end(), symbolAnimationConfig->effectStrategy) != 0) {
505         SpliceAnimation(rsNode, parameters);
506         return true;
507     }
508 
509     switch (symbolAnimationConfig->effectStrategy) {
510         case Drawing::DrawingEffectStrategy::VARIABLE_COLOR:
511             return SetKeyframeAlphaAnimation(rsNode, parameters, symbolAnimationConfig);
512         case Drawing::DrawingEffectStrategy::PULSE:
513             return SetKeyframeAlphaAnimation(rsNode, parameters, symbolAnimationConfig);
514         default:
515             ROSEN_LOGD("[%{public}s] not support input animation type", __func__);
516             return false;
517     }
518 }
519 
SetSymbolShadow(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::shared_ptr<RSNode> & rsNode,const std::shared_ptr<RSNode> & rsNodeRoot)520 void RSSymbolAnimation::SetSymbolShadow(
521     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
522     std::shared_ptr<RSNode>& rsNode,
523     const std::shared_ptr<RSNode>& rsNodeRoot)
524 {
525     if (!symbolAnimationConfig->symbolShadow.has_value()) {
526         return;
527     }
528     if (rsNodeRoot == nullptr) {
529         return;
530     }
531     // update bounds
532     auto symbolBounds = symbolBounds_;
533     if (std::count(upAndDownSupportAnimations_.begin(), upAndDownSupportAnimations_.end(),
534         symbolAnimationConfig->effectStrategy) != 0) {
535         float x = symbolAnimationConfig->symbolNodes[0].nodeBoundary[NODE_WIDTH] * EXPANSION_RATIO;
536         float y = symbolAnimationConfig->symbolNodes[0].nodeBoundary[NODE_HEIGHT] * EXPANSION_RATIO;
537         float two = 2; // 2 is two
538         symbolBounds = Vector4f(-x, -y, symbolBounds_.z_ + y * two, symbolBounds_.w_ + x * two);
539     }
540 
541     std::shared_ptr<RSCanvasNode> canvasNode;
542     CreateSymbolNode(symbolBounds, symbolAnimationConfig->symbolSpanId,
543         symbolAnimationConfig->symbolSpanId, rsNodeRoot, canvasNode);
544     if (canvasNode == nullptr) {
545         ROSEN_LOGE("Failed to create rsNode");
546         return;
547     }
548     rsNode = canvasNode;
549     rsNode->SetClipToBounds(false);
550     rsNode->SetClipToFrame(false);
551     for (auto& symbolNode: symbolAnimationConfig->symbolNodes) {
552         symbolNode.nodeBoundary[0] -= symbolBounds[0];
553         symbolNode.nodeBoundary[1] -= symbolBounds[1];
554     }
555     symbolBounds_.z_ = symbolBounds.z_;
556     symbolBounds_.w_ = symbolBounds.w_;
557 
558     // set symbolShadow
559     auto symbolShadow = symbolAnimationConfig->symbolShadow.value();
560     SetSymbolShadow(symbolShadow, rsNode);
561     return;
562 }
563 
SetSymbolShadow(const SymbolShadow & symbolShadow,std::shared_ptr<RSNode> & rsNode)564 void RSSymbolAnimation::SetSymbolShadow(const SymbolShadow& symbolShadow, std::shared_ptr<RSNode>& rsNode)
565 {
566     rsNode->SetShadowColor(symbolShadow.color.CastToColorQuad());
567     rsNode->SetShadowOffset(symbolShadow.offset.GetX(), symbolShadow.offset.GetY());
568     rsNode->SetShadowRadius(symbolShadow.blurRadius);
569     rsNode->SetShadowMaskStrategy(SHADOW_MASK_STRATEGY::MASK_COLOR_BLUR);
570 }
571 
SetPublicAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)572 bool RSSymbolAnimation::SetPublicAnimation(
573     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
574 {
575     if (symbolAnimationConfig->symbolNodes.empty()) {
576         ROSEN_LOGD("[%{public}s] symbol nodes is empty", __func__);
577         return false;
578     }
579     auto symbolSpanId = symbolAnimationConfig->symbolSpanId;
580     std::shared_ptr<RSNode> rsNode = rsNode_;
581     SetSymbolShadow(symbolAnimationConfig, rsNode, rsNode_);
582     if (isMaskSymbol_) {
583         std::shared_ptr<RSNode> rsNodeMask = nullptr;
584         CreateSameNode(symbolSpanId, rsNodeMask, rsNode);
585         if (rsNodeMask == nullptr) {
586             ROSEN_LOGE("Failed to create rsNode");
587             return false;
588         }
589         rsNodeMask->SetColorBlendMode(RSColorBlendMode::SRC_OVER);
590         rsNodeMask->SetColorBlendApplyType(RSColorBlendApplyType::SAVE_LAYER_ALPHA);
591         rsNode = rsNodeMask;
592     }
593 
594     const auto& symbolFirstNode = symbolAnimationConfig->symbolNodes[0]; // calculate offset by the first node
595     Vector4f offsets = CalculateOffset(symbolFirstNode.symbolData.path_, symbolFirstNode.nodeBoundary[0],
596         symbolFirstNode.nodeBoundary[1]); // index 0 offsetX and 1 offsetY of layout
597     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
598     bool res = GetAnimationGroupParameters(symbolAnimationConfig, parameters, symbolAnimationConfig->effectStrategy);
599     uint32_t nodeNum = symbolAnimationConfig->numNodes;
600     for (uint32_t n = 0; n < nodeNum; n++) {
601         auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
602         auto bounds = Vector4f(offsets[0], offsets[1], symbolNode.nodeBoundary[NODE_WIDTH],
603             symbolNode.nodeBoundary[NODE_HEIGHT]);
604         std::shared_ptr<RSCanvasNode> canvasNode = nullptr;
605         bool createNewNode = CreateSymbolNode(bounds, symbolSpanId, n, rsNode, canvasNode);
606         if (canvasNode == nullptr) {
607             return false;
608         }
609         GroupDrawing(canvasNode, symbolNode, offsets);
610 
611         bool isInValid = !res || symbolNode.animationIndex < 0 ||
612                          parameters.size() <= static_cast<size_t>(symbolNode.animationIndex);
613         if (isInValid) {
614             ROSEN_LOGD("[%{public}s] invalid animationIndex or parameter", __func__);
615             continue;
616         }
617 
618         if (createNewNode) {
619             ChooseAnimation(canvasNode, parameters[symbolNode.animationIndex], symbolAnimationConfig);
620         }
621     }
622     return true;
623 }
624 
625 // set text flip animation
SetTextFlipAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)626 bool RSSymbolAnimation::SetTextFlipAnimation(
627     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
628 {
629     if (!symbolAnimationConfig->animationStart) {
630         ROSEN_LOGD("Clear all text animation");
631         std::lock_guard<std::mutex> lock(rsNode_->childrenNodeLock_);
632         rsNode_->canvasNodesListMap_.clear();
633         return true;
634     }
635     if (symbolAnimationConfig->parameters.size() < PROPERTIES) {
636         ROSEN_LOGE("Invalid animation parameters of text flip, parameters.size: %{public}zu ",
637             symbolAnimationConfig->parameters.size());
638         return false;
639     }
640 
641     FrameRateRange range = {60, 60, 60}; // The fixed frame rate is 60 of text flip animation
642     range_ = range;
643     if (!symbolAnimationConfig->currentAnimationHasPlayed) {
644         SetFlipDisappear(symbolAnimationConfig, rsNode_);
645     }
646     return SetFlipAppear(symbolAnimationConfig, rsNode_,
647         !symbolAnimationConfig->currentAnimationHasPlayed);
648 }
649 
SetFlipDisappear(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::shared_ptr<RSNode> & rsNode)650 void RSSymbolAnimation::SetFlipDisappear(
651     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
652     std::shared_ptr<RSNode>& rsNode)
653 {
654     const auto& symbolId = symbolAnimationConfig->symbolSpanId;
655     if (rsNode->canvasNodesListMap_.find(symbolId) == rsNode->canvasNodesListMap_.end()) {
656         return ;
657     }
658     if (rsNode->canvasNodesListMap_[symbolId].find(APPEAR_STATUS) == rsNode->canvasNodesListMap_[symbolId].end()) {
659         return;
660     }
661     auto& canvasNode = rsNode->canvasNodesListMap_[symbolId][APPEAR_STATUS];
662     auto parameter = UpdateParametersDelay(symbolAnimationConfig->parameters[0],
663         symbolAnimationConfig->effectElement.delay);
664     SpliceAnimation(canvasNode, parameter);
665     {
666         std::lock_guard<std::mutex> lock(rsNode->childrenNodeLock_);
667         rsNode->canvasNodesListMap_[symbolId].insert({INVALID_STATUS, canvasNode});
668         rsNode->canvasNodesListMap_[symbolId].erase(APPEAR_STATUS);
669     }
670 }
671 
SetFlipAppear(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::shared_ptr<RSNode> & rsNode,bool isStartAnimation)672 bool RSSymbolAnimation::SetFlipAppear(
673     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
674     std::shared_ptr<RSNode>& rsNode, bool isStartAnimation)
675 {
676     auto symbolSpanId = symbolAnimationConfig->symbolSpanId;
677     TextEngine::SymbolNode symbolNode;
678     const auto& effectNode = symbolAnimationConfig->effectElement;
679     if (!effectNode.path.IsValid()) {
680         return true;
681     }
682     // creat childNode
683     Vector4f offsets = CalculateOffset(effectNode.path, effectNode.offset.GetX(),
684         effectNode.offset.GetY());
685     // 0: offsetX, 1: offsetY of childNode
686     auto bounds = Vector4f(offsets[0], offsets[1], effectNode.width, effectNode.height);
687     std::shared_ptr<RSCanvasNode> canvasNode = nullptr;
688     isStartAnimation = CreateSymbolNode(bounds, symbolSpanId, APPEAR_STATUS, rsNode, canvasNode);
689     if (canvasNode == nullptr) {
690         ROSEN_LOGE("Failed to get canvasNode of TextFilp");
691         return false;
692     }
693     // draw path
694     auto recordingCanvas = canvasNode->BeginRecording(effectNode.width, effectNode.height);
695     DrawPathOnCanvas(recordingCanvas, effectNode, symbolAnimationConfig->color, {offsets[0], offsets[1]});
696     canvasNode->FinishRecording();
697     if (isStartAnimation) {
698         auto parameter = UpdateParametersDelay(symbolAnimationConfig->parameters[1], effectNode.delay);
699         SpliceAnimation(canvasNode, parameter);
700     }
701     return true;
702 }
703 
UpdateParametersDelay(const std::vector<Drawing::DrawingPiecewiseParameter> & parameters,int delay)704 std::vector<Drawing::DrawingPiecewiseParameter> RSSymbolAnimation::UpdateParametersDelay(
705     const std::vector<Drawing::DrawingPiecewiseParameter>& parameters, int delay)
706 {
707     std::vector<Drawing::DrawingPiecewiseParameter> outParameters = parameters;
708     for (auto& parameter : outParameters) {
709         parameter.delay += delay;
710     }
711     return outParameters;
712 }
713 
DrawPathOnCanvas(ExtendRecordingCanvas * recordingCanvas,const TextEngine::TextEffectElement & effectNode,const Drawing::Color & color,const Drawing::Point & offset)714 void RSSymbolAnimation::DrawPathOnCanvas(ExtendRecordingCanvas* recordingCanvas,
715     const TextEngine::TextEffectElement& effectNode,
716     const Drawing::Color& color, const Drawing::Point& offset)
717 {
718     if (recordingCanvas == nullptr) {
719         return;
720     }
721 
722     Drawing::Brush brush;
723     brush.SetAntiAlias(true);
724     brush.SetColor(color.CastToColorQuad());
725     auto path = effectNode.path;
726     path.Offset(effectNode.offset.GetX() - offset.GetX(), effectNode.offset.GetY() - offset.GetY());
727     recordingCanvas->AttachBrush(brush);
728     recordingCanvas->DrawPath(path);
729     recordingCanvas->DetachBrush();
730 }
731 
GroupAnimationStart(const std::shared_ptr<RSNode> & rsNode,std::vector<std::shared_ptr<RSAnimation>> & animations)732 void RSSymbolAnimation::GroupAnimationStart(
733     const std::shared_ptr<RSNode>& rsNode, std::vector<std::shared_ptr<RSAnimation>>& animations)
734 {
735     if (rsNode == nullptr || animations.empty()) {
736         ROSEN_LOGD("[%{public}s] : invalid input", __func__);
737         return;
738     }
739 
740     for (int i = 0; i < static_cast<int>(animations.size()); i++) {
741         if (animations[i]) {
742             animations[i]->Start(rsNode);
743         }
744     }
745 }
746 
SetNodePivot(const std::shared_ptr<RSNode> & rsNode)747 void RSSymbolAnimation::SetNodePivot(const std::shared_ptr<RSNode>& rsNode)
748 {
749     if (rsNode == nullptr) {
750         ROSEN_LOGD("Interpolator is null, return FRACTION_MIN.");
751         return;
752     }
753     // Set Node Center Offset
754     Vector2f curNodePivot = rsNode->GetStagingProperties().GetPivot();
755     pivotProperty_ = nullptr; // reset
756     if (!(curNodePivot.x_ == CENTER_NODE_COORDINATE.x_ && curNodePivot.y_ == CENTER_NODE_COORDINATE.y_)) {
757         SymbolAnimation::CreateOrSetModifierValue(pivotProperty_, CENTER_NODE_COORDINATE);
758         auto modifier = std::make_shared<ModifierNG::RSTransformModifier>();
759         modifier->AttachProperty(ModifierNG::RSPropertyType::PIVOT, pivotProperty_);
760         rsNode->AddModifier(modifier);
761     }
762 }
763 
CreateSameNode(uint64_t symbolId,std::shared_ptr<RSNode> & rsNode,const std::shared_ptr<RSNode> & rsNodeRoot)764 void RSSymbolAnimation::CreateSameNode(uint64_t symbolId, std::shared_ptr<RSNode>& rsNode,
765     const std::shared_ptr<RSNode>& rsNodeRoot)
766 {
767     if (rsNodeRoot == nullptr) {
768         return;
769     }
770 
771     const auto& symbolBounds = symbolBounds_;
772     std::lock_guard<std::mutex> lock(rsNodeRoot->childrenNodeLock_);
773     auto outerIter = rsNodeRoot->canvasNodesListMap_.find(symbolId);
774     if (outerIter == rsNodeRoot->canvasNodesListMap_.end()) {
775         outerIter = rsNodeRoot->canvasNodesListMap_.insert({symbolId,
776             std::unordered_map<NodeId, std::shared_ptr<RSNode>>()}).first;
777     }
778     if (outerIter->second.find(symbolId) == outerIter->second.end()) {
779         auto childNode = RSCanvasNode::Create(false, false, rsNodeRoot->GetRSUIContext());
780         SetSymbolGeometry(childNode, symbolBounds);
781         outerIter->second.insert({symbolId, childNode});
782         rsNodeRoot->AddChild(childNode, -1);
783     } else {
784         UpdateSymbolGeometry(outerIter->second[symbolId], symbolBounds);
785     }
786     rsNode = outerIter->second[symbolId];
787 }
788 
789 // set Disable Animation
SetDisableAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)790 bool RSSymbolAnimation::SetDisableAnimation(
791     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
792 {
793     if (symbolAnimationConfig->symbolNodes.size() < 1) { // 1: symbol nodes must be >= 1
794         ROSEN_LOGE("HmSymbol Failed to set disable animation, symbol size: %{public}zu",
795             symbolAnimationConfig->symbolNodes.size());
796         return false;
797     }
798 
799     // get the disable animation paramters
800     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> parameters;
801     GetAnimationGroupParameters(symbolAnimationConfig, parameters, symbolAnimationConfig->effectStrategy);
802     std::shared_ptr<RSNode> rsNode = rsNode_;
803     SetSymbolShadow(symbolAnimationConfig, rsNode, rsNode_);
804     return SetDisableAnimation(symbolAnimationConfig, parameters, rsNode);
805 }
806 
SetDisableAnimation(const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> & parameters,const std::shared_ptr<RSNode> & rsNodeRoot)807 bool RSSymbolAnimation::SetDisableAnimation(
808     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
809     std::vector<std::vector<Drawing::DrawingPiecewiseParameter>>& parameters,
810     const std::shared_ptr<RSNode>& rsNodeRoot)
811 {
812     if (parameters.empty()) {
813         ROSEN_LOGE("HmSymbol Failed to get disable parameters");
814         return false;
815     }
816     SetDisableParameter(parameters[parameters.size() - 1], symbolAnimationConfig);
817 
818     // Create a child node the same as the rsNode_
819     std::shared_ptr<RSNode> rsNode = nullptr;
820     CreateSameNode(symbolAnimationConfig->symbolSpanId, rsNode, rsNodeRoot);
821     if (rsNode == nullptr) {
822         ROSEN_LOGE("HmSymbol Failed to create rsNode");
823         return false;
824     }
825     rsNode->SetColorBlendMode(RSColorBlendMode::SRC_OVER);
826     rsNode->SetColorBlendApplyType(RSColorBlendApplyType::SAVE_LAYER_ALPHA);
827 
828     // calculate offset by the first symbol node config
829     const auto& symbolFirstNode = symbolAnimationConfig->symbolNodes[0];
830     Vector4f offsets = CalculateOffset(symbolFirstNode.symbolData.path_, symbolFirstNode.nodeBoundary[0],
831         symbolFirstNode.nodeBoundary[1]); // index 0 offsetX, 1 offsety of layout
832     // set animation base layers
833     if (!SetDisableBaseLayer(rsNode, symbolAnimationConfig, parameters, offsets)) {
834         return false;
835     }
836 
837     // set animation clip layer
838     uint32_t n = symbolAnimationConfig->symbolNodes.size() -1;
839     const auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
840     bool isInValid = symbolNode.animationIndex < 0 || symbolNode.isMask ||
841         parameters.size() <= static_cast<size_t>(symbolNode.animationIndex);
842     if (isInValid) {
843         ROSEN_LOGE("Invalid parameter of clip layer in HmSymbol");
844         return false;
845     }
846     return SetClipAnimation(rsNodeRoot, symbolAnimationConfig, parameters[symbolNode.animationIndex], n, offsets);
847 }
848 
849 // set disable parameter with slope of symbol
SetDisableParameter(std::vector<Drawing::DrawingPiecewiseParameter> & parameter,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)850 void RSSymbolAnimation::SetDisableParameter(std::vector<Drawing::DrawingPiecewiseParameter>& parameter,
851     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
852 {
853     if (parameter.empty()) {
854         return;
855     }
856     uint32_t n = symbolAnimationConfig->symbolNodes.size();
857     const auto& symbolNode = symbolAnimationConfig->symbolNodes[n - 1];
858     if (symbolNode.pathsInfo.empty()) {
859         return;
860     }
861 
862     auto slope = symbolAnimationConfig->slope;
863     auto rect = symbolNode.pathsInfo[0].path.GetBounds();
864     float w = rect.GetWidth();
865     float h = rect.GetHeight();
866     float distance = std::sqrt(w * w + h * h);
867     float angle = std::atan(slope);
868     float x = std::cos(angle) * distance;
869     float y = std::sin(angle) * distance;
870     x = slope > 0 ? x * -1 : x; // -1: The direction of the x-axis needs to be reversed
871     y = slope < 0 ? y * -1 : y; // -1: The direction of the Y-axis needs to be reversed
872 
873     for (auto& param: parameter) {
874         std::vector<float> ratio;
875         if (param.properties.count(TRANSLATE_RATIO)) {
876             ratio = param.properties[TRANSLATE_RATIO];
877         }
878         if (param.properties.count(CLIP_PROP)) {
879             ratio = param.properties[CLIP_PROP];
880         }
881         if (ratio.size() < PROPERTIES) {
882             continue;
883         }
884         param.properties.insert({TRANSLATE_PROP_X, {x * ratio[PROP_START], x * ratio[PROP_END]}});
885         param.properties.insert({TRANSLATE_PROP_Y, {y * ratio[PROP_START], y * ratio[PROP_END]}});
886     }
887 }
888 
SetDisableBaseLayer(const std::shared_ptr<RSNode> & rsNode,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,const std::vector<std::vector<Drawing::DrawingPiecewiseParameter>> & parameters,const Vector4f & offsets)889 bool RSSymbolAnimation::SetDisableBaseLayer(const std::shared_ptr<RSNode>& rsNode,
890     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
891     const std::vector<std::vector<Drawing::DrawingPiecewiseParameter>>& parameters,
892     const Vector4f& offsets)
893 {
894     auto symbolId = symbolAnimationConfig->symbolSpanId;
895     for (uint32_t n = 0; n < symbolAnimationConfig->symbolNodes.size() -1; n++) {
896         auto& symbolNode = symbolAnimationConfig->symbolNodes[n];
897         auto bounds = Vector4f(offsets[0], offsets[1], symbolNode.nodeBoundary[NODE_WIDTH],
898             symbolNode.nodeBoundary[NODE_HEIGHT]);
899         std::shared_ptr<RSCanvasNode> canvasNode = nullptr;
900         bool createNewNode = CreateSymbolNode(bounds, symbolId, n, rsNode, canvasNode);
901         if (canvasNode == nullptr) {
902             ROSEN_LOGE("HmSymbol canvasNode is nullptr");
903             return false;
904         }
905         auto recordingCanvas = canvasNode->BeginRecording(symbolNode.nodeBoundary[NODE_WIDTH],
906             symbolNode.nodeBoundary[NODE_HEIGHT]);
907         DrawPathOnCanvas(recordingCanvas, symbolNode, offsets);
908         canvasNode->FinishRecording();
909 
910         bool isInValid = symbolNode.animationIndex < 0 ||
911             parameters.size() <= static_cast<size_t>(symbolNode.animationIndex);
912         if (isInValid) {
913             continue;
914         }
915         if (createNewNode) {
916             SpliceAnimation(canvasNode, parameters[symbolNode.animationIndex]);
917         }
918     }
919     return true;
920 }
921 
SetClipAnimation(const std::shared_ptr<RSNode> & rsNode,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig,const std::vector<Drawing::DrawingPiecewiseParameter> & parameters,uint32_t index,const Vector4f & offsets)922 bool RSSymbolAnimation::SetClipAnimation(const std::shared_ptr<RSNode>& rsNode,
923     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig,
924     const std::vector<Drawing::DrawingPiecewiseParameter>& parameters,
925     uint32_t index, const Vector4f& offsets)
926 {
927     if (parameters.size() < 3) { // 3: the size of parameters for the disable animation must be >= 3
928         ROSEN_LOGD("Invalid clip parameter in HmSymbol");
929         return false;
930     }
931     // create clip layer node
932     auto symbolId = symbolAnimationConfig->symbolSpanId;
933     auto& symbolNode = symbolAnimationConfig->symbolNodes[index];
934     auto bounds = Vector4f(offsets[0], offsets[1], symbolNode.nodeBoundary[NODE_WIDTH],
935         symbolNode.nodeBoundary[NODE_HEIGHT]);
936     std::shared_ptr<RSCanvasNode> canvasNode = nullptr;
937     bool createNewNode = CreateSymbolNode(bounds, symbolId, index, rsNode, canvasNode);
938     if (canvasNode == nullptr) {
939         ROSEN_LOGE("HmSymbol canvasNode is nullptr");
940         return false;
941     }
942     GroupDrawing(canvasNode, symbolNode, offsets, true);
943 
944     // create a node that displays slashes
945     auto symbolBounds = Vector4f(0.0f, 0.0f, symbolNode.nodeBoundary[NODE_WIDTH],
946         symbolNode.nodeBoundary[NODE_HEIGHT]);
947     std::shared_ptr<RSCanvasNode> canvasNodeLine = nullptr;
948     createNewNode = CreateSymbolNode(symbolBounds, symbolId, index, canvasNode, canvasNodeLine);
949     if (canvasNodeLine == nullptr) {
950         ROSEN_LOGE("HmSymbol canvasNode is nullptr");
951         return false;
952     }
953     GroupDrawing(canvasNodeLine, symbolNode, offsets, false);
954     // set animation to clip layer
955     if (createNewNode) {
956         std::vector<Drawing::DrawingPiecewiseParameter> firstParameters;
957         uint32_t n = parameters.size() - 1; // the max index of parameters
958         for (uint32_t i = 0; i < n; i++) {
959             firstParameters.push_back(parameters[i]);
960         }
961         SpliceAnimation(canvasNode, firstParameters);
962         std::vector<Drawing::DrawingPiecewiseParameter> secondParameters = { parameters[n] };
963         SpliceAnimation(canvasNodeLine, secondParameters);
964     }
965     return true;
966 }
967 
SpliceAnimation(const std::shared_ptr<RSNode> & rsNode,const std::vector<Drawing::DrawingPiecewiseParameter> & parameters)968 void RSSymbolAnimation::SpliceAnimation(const std::shared_ptr<RSNode>& rsNode,
969     const std::vector<Drawing::DrawingPiecewiseParameter>& parameters)
970 {
971     if (rsNode == nullptr) {
972         ROSEN_LOGD("RsNode is null, failed to SpliceAnimation.");
973         return;
974     }
975     std::shared_ptr<RSAnimatableProperty<Vector2f>> scaleProperty = nullptr;
976     std::shared_ptr<RSAnimatableProperty<float>> alphaProperty = nullptr;
977     std::shared_ptr<RSAnimatableProperty<Vector2f>> translateProperty = nullptr;
978     std::shared_ptr<RSAnimatableProperty<float>> blurProperty = nullptr;
979     std::shared_ptr<RSAnimatableProperty<Vector2f>> clipProperty = nullptr;
980     std::vector<std::shared_ptr<RSAnimation>> groupAnimation = {};
981     SymbolBaseFuncMap funcMap = {
982         {SCALE_PROP_X, [&, this](const Drawing::DrawingPiecewiseParameter& parameter)
983             {
984                 ScaleAnimationBase(rsNode, scaleProperty, parameter, groupAnimation);
985             }
986         },
987         {ALPHA_PROP, [&, this](const Drawing::DrawingPiecewiseParameter& parameter)
988             {
989                 AlphaAnimationBase(rsNode, alphaProperty, parameter, groupAnimation);
990             }
991         },
992         {TRANSLATE_PROP_X, [&, this](const Drawing::DrawingPiecewiseParameter& parameter)
993             {
994                 TranslateAnimationBase(rsNode, translateProperty, parameter, groupAnimation);
995             }
996         },
997         {BLUR_PROP, [&, this](const Drawing::DrawingPiecewiseParameter& parameter)
998             {
999                 BlurAnimationBase(rsNode, blurProperty, parameter, groupAnimation);
1000             }
1001         },
1002         {CLIP_PROP, [&, this](const Drawing::DrawingPiecewiseParameter& parameter)
1003             {
1004                 TranslateAnimationBase(rsNode, clipProperty, parameter, groupAnimation);
1005             }
1006         }
1007     };
1008 
1009     for (const auto& parameter : parameters) {
1010         for (const auto& pair : parameter.properties) {
1011             if (funcMap.count(pair.first) > 0) {
1012                 funcMap[pair.first](parameter);
1013                 break;
1014             }
1015         }
1016     }
1017     GroupAnimationStart(rsNode, groupAnimation);
1018 }
1019 
CalculateOffset(const Drawing::Path & path,const float offsetX,const float offsetY)1020 Vector4f RSSymbolAnimation::CalculateOffset(const Drawing::Path& path, const float offsetX, const float offsetY)
1021 {
1022     auto rect = path.GetBounds();
1023     float left = rect.GetLeft();
1024     float top = rect.GetTop();
1025     // the nodeTranslation is offset of new node to the father node;
1026     // the newOffset is offset of path on new node;
1027     Vector2f nodeTranslation = { offsetX + left, offsetY + top };
1028     Vector2f newOffset = { -left, -top };
1029     return Vector4f(nodeTranslation[0], nodeTranslation[1], newOffset[0], newOffset[1]);
1030 }
1031 
UpdateSymbolGeometry(const std::shared_ptr<RSNode> & rsNode,const Vector4f & bounds)1032 void RSSymbolAnimation::UpdateSymbolGeometry(const std::shared_ptr<RSNode>& rsNode, const Vector4f& bounds)
1033 {
1034     if (rsNode == nullptr) {
1035         return;
1036     }
1037     rsNode->SetBounds(bounds);
1038     rsNode->SetFrame(bounds);
1039 }
1040 
GroupDrawing(const std::shared_ptr<RSCanvasNode> & canvasNode,TextEngine::SymbolNode & symbolNode,const Vector4f & offsets,bool isClip)1041 void RSSymbolAnimation::GroupDrawing(const std::shared_ptr<RSCanvasNode>& canvasNode,
1042     TextEngine::SymbolNode& symbolNode, const Vector4f& offsets, bool isClip)
1043 {
1044     // drawing a symbol or a path group
1045     auto recordingCanvas = canvasNode->BeginRecording(symbolNode.nodeBoundary[NODE_WIDTH],
1046                                                       symbolNode.nodeBoundary[NODE_HEIGHT]);
1047     if (isClip) {
1048         DrawClipOnCanvas(recordingCanvas, symbolNode, offsets);
1049     } else {
1050         DrawPathOnCanvas(recordingCanvas, symbolNode, offsets);
1051     }
1052     canvasNode->FinishRecording();
1053 }
1054 
DrawPathOnCanvas(ExtendRecordingCanvas * recordingCanvas,TextEngine::SymbolNode & symbolNode,const Vector4f & offsets)1055 void RSSymbolAnimation::DrawPathOnCanvas(
1056     ExtendRecordingCanvas* recordingCanvas, TextEngine::SymbolNode& symbolNode, const Vector4f& offsets)
1057 {
1058     if (recordingCanvas == nullptr) {
1059         return;
1060     }
1061     Drawing::Brush brush;
1062     Drawing::Pen pen;
1063     brush.SetAntiAlias(true);
1064     pen.SetAntiAlias(true);
1065     Drawing::Point offset = Drawing::Point(offsets[2], offsets[3]); // index 2 offsetX 3 offsetY
1066     if (symbolNode.isMask) {
1067         brush.SetBlendMode(Drawing::BlendMode::CLEAR);
1068         pen.SetBlendMode(Drawing::BlendMode::CLEAR);
1069         recordingCanvas->AttachBrush(brush);
1070         recordingCanvas->AttachPen(pen);
1071         for (auto pathInfo: symbolNode.pathsInfo) {
1072             pathInfo.path.Offset(offset.GetX(), offset.GetY());
1073             recordingCanvas->DrawPath(pathInfo.path);
1074         }
1075         recordingCanvas->DetachBrush();
1076         recordingCanvas->DetachPen();
1077         return;
1078     }
1079 
1080     for (auto pathInfo: symbolNode.pathsInfo) {
1081         if (pathInfo.color == nullptr) {
1082             continue;
1083         }
1084         brush = pathInfo.color->CreateGradientBrush(offset);
1085         pen = pathInfo.color->CreateGradientPen(offset);
1086         pathInfo.path.Offset(offset.GetX(), offset.GetY());
1087         recordingCanvas->AttachBrush(brush);
1088         recordingCanvas->AttachPen(pen);
1089         recordingCanvas->DrawPath(pathInfo.path);
1090         recordingCanvas->DetachBrush();
1091         recordingCanvas->DetachPen();
1092     }
1093 }
1094 
DrawClipOnCanvas(ExtendRecordingCanvas * recordingCanvas,TextEngine::SymbolNode & symbolNode,const Vector4f & offsets)1095 void RSSymbolAnimation::DrawClipOnCanvas(
1096     ExtendRecordingCanvas* recordingCanvas, TextEngine::SymbolNode& symbolNode, const Vector4f& offsets)
1097 {
1098     if (recordingCanvas == nullptr) {
1099         return;
1100     }
1101     Drawing::Brush brush;
1102     Drawing::Pen pen;
1103     brush.SetAntiAlias(true);
1104     pen.SetAntiAlias(true);
1105     recordingCanvas->AttachBrush(brush);
1106     recordingCanvas->AttachPen(pen);
1107 
1108     for (auto pathInfo: symbolNode.pathsInfo) {
1109         pathInfo.path.Offset(offsets[2], offsets[3]); // index 2 offsetX 3 offsetY
1110         recordingCanvas->ClipPath(pathInfo.path, Drawing::ClipOp::INTERSECT, true);
1111     }
1112     recordingCanvas->DetachBrush();
1113     recordingCanvas->DetachPen();
1114 }
1115 
SetSymbolGeometry(const std::shared_ptr<RSNode> & rsNode,const Vector4f & bounds)1116 bool RSSymbolAnimation::SetSymbolGeometry(const std::shared_ptr<RSNode>& rsNode, const Vector4f& bounds)
1117 {
1118     if (rsNode == nullptr) {
1119         return false;
1120     }
1121     auto frameModifier = std::make_shared<ModifierNG::RSFrameModifier>();
1122     frameModifier->SetFrame(bounds);
1123     rsNode->AddModifier(frameModifier);
1124     auto boundsModifier = std::make_shared<ModifierNG::RSBoundsModifier>();
1125     boundsModifier->SetBounds(bounds);
1126     rsNode->AddModifier(boundsModifier);
1127     rsNode_->SetClipToBounds(false);
1128     rsNode_->SetClipToFrame(false);
1129     return true;
1130 }
1131 
SetKeyframeAlphaAnimation(const std::shared_ptr<RSNode> & rsNode,std::vector<Drawing::DrawingPiecewiseParameter> & parameters,const std::shared_ptr<TextEngine::SymbolAnimationConfig> & symbolAnimationConfig)1132 bool RSSymbolAnimation::SetKeyframeAlphaAnimation(const std::shared_ptr<RSNode>& rsNode,
1133     std::vector<Drawing::DrawingPiecewiseParameter>& parameters,
1134     const std::shared_ptr<TextEngine::SymbolAnimationConfig>& symbolAnimationConfig)
1135 {
1136     if (rsNode == nullptr || symbolAnimationConfig == nullptr) {
1137         ROSEN_LOGD("HmSymbol SetVariableColorAnimation::getNode or get symbolAnimationConfig:failed");
1138         return false;
1139     }
1140     alphaPropertyStages_.clear();
1141     uint32_t duration = 0;
1142     std::vector<float> timePercents;
1143     if (!GetKeyframeAlphaAnimationParas(parameters, duration, timePercents)) {
1144         return false;
1145     }
1146     auto alphaModifier = std::make_shared<ModifierNG::RSAlphaModifier>();
1147     // 0 means the first stage of a node
1148     alphaModifier->AttachProperty(ModifierNG::RSPropertyType::ALPHA, alphaPropertyStages_[0]);
1149     rsNode->AddModifier(alphaModifier);
1150     std::shared_ptr<RSAnimation> animation = nullptr;
1151     animation = KeyframeAlphaSymbolAnimation(rsNode, parameters[0], duration, timePercents);
1152     if (animation == nullptr) {
1153         return false;
1154     }
1155 
1156     if (symbolAnimationConfig->effectStrategy == Drawing::DrawingEffectStrategy::VARIABLE_COLOR &&
1157         symbolAnimationConfig->animationMode == 0) {
1158         animation->SetRepeatCount(1);
1159     } else {
1160         animation->SetRepeatCount(-1); // -1 means loop playback
1161     }
1162     animation->Start(rsNode);
1163     return true;
1164 }
1165 
GetKeyframeAlphaAnimationParas(std::vector<Drawing::DrawingPiecewiseParameter> & oneGroupParas,uint32_t & totalDuration,std::vector<float> & timePercents)1166 bool RSSymbolAnimation::GetKeyframeAlphaAnimationParas(
1167     std::vector<Drawing::DrawingPiecewiseParameter>& oneGroupParas,
1168     uint32_t& totalDuration, std::vector<float>& timePercents)
1169 {
1170     if (oneGroupParas.empty()) {
1171         return false;
1172     }
1173     totalDuration = 0;
1174     // traverse all time stages
1175     for (size_t i = 0; i < oneGroupParas.size(); i++) {
1176         int interval = 0;
1177         if (i + 1 < oneGroupParas.size()) {
1178             interval = oneGroupParas[i + 1].delay -
1179                        (static_cast<int>(oneGroupParas[i].duration) + oneGroupParas[i].delay);
1180         } else {
1181             interval = 0;
1182         }
1183         if (interval < 0) {
1184             return false;
1185         }
1186         totalDuration = oneGroupParas[i].duration + totalDuration + static_cast<uint32_t>(interval);
1187         if (!SymbolAnimation::ElementInMap(ALPHA_PROP, oneGroupParas[i].properties) ||
1188             oneGroupParas[i].properties[ALPHA_PROP].size() != PROPERTIES) {
1189             return false;
1190         }
1191         // the value of the key frame needs
1192         float alphaValueStart = oneGroupParas[i].properties[ALPHA_PROP][PROP_START];
1193         std::shared_ptr<RSAnimatableProperty<float>> alphaPropertyStart = nullptr;
1194         SymbolAnimation::CreateOrSetModifierValue(alphaPropertyStart, alphaValueStart);
1195         alphaPropertyStages_.push_back(alphaPropertyStart);
1196 
1197         float alphaValueEnd = oneGroupParas[i].properties[ALPHA_PROP][PROP_END];
1198         std::shared_ptr<RSAnimatableProperty<float>> alphaPropertyEnd = nullptr;
1199         SymbolAnimation::CreateOrSetModifierValue(alphaPropertyEnd, alphaValueEnd);
1200         alphaPropertyStages_.push_back(alphaPropertyEnd);
1201     }
1202     return CalcTimePercents(timePercents, totalDuration, oneGroupParas);
1203 }
1204 
CalcTimePercents(std::vector<float> & timePercents,const uint32_t totalDuration,const std::vector<Drawing::DrawingPiecewiseParameter> & oneGroupParas)1205 bool RSSymbolAnimation::CalcTimePercents(std::vector<float>& timePercents, const uint32_t totalDuration,
1206     const std::vector<Drawing::DrawingPiecewiseParameter>& oneGroupParas)
1207 {
1208     if (totalDuration == 0) {
1209         return false;
1210     }
1211     uint32_t duration = 0;
1212     timePercents.push_back(0); // the first property of timePercent
1213     for (int i = 0; i < static_cast<int>(oneGroupParas.size()) - 1; i++) {
1214         int interval = 0; // Interval between two animations
1215         duration = duration + oneGroupParas[i].duration;
1216         SymbolAnimation::CalcOneTimePercent(timePercents, totalDuration, duration);
1217         interval = oneGroupParas[i + 1].delay -
1218                    (static_cast<int>(oneGroupParas[i].duration) + oneGroupParas[i].delay);
1219         if (interval < 0) {
1220             return false;
1221         }
1222         duration = duration + static_cast<uint32_t>(interval);
1223         SymbolAnimation::CalcOneTimePercent(timePercents, totalDuration, duration);
1224     }
1225     duration = duration + oneGroupParas.back().duration;
1226     SymbolAnimation::CalcOneTimePercent(timePercents, totalDuration, duration);
1227     return true;
1228 }
1229 
SetIconProperty(Drawing::Brush & brush,Drawing::Pen & pen,Drawing::DrawingSColor & color)1230 void RSSymbolAnimation::SetIconProperty(Drawing::Brush& brush, Drawing::Pen& pen, Drawing::DrawingSColor& color)
1231 {
1232     brush.SetColor(Drawing::Color::ColorQuadSetARGB(0xFF, color.r, color.g, color.b));
1233     brush.SetAlphaF(color.a);
1234     brush.SetAntiAlias(true);
1235 
1236     pen.SetColor(Drawing::Color::ColorQuadSetARGB(0xFF, color.r, color.g, color.b));
1237     pen.SetAlphaF(color.a);
1238     pen.SetAntiAlias(true);
1239     return;
1240 }
1241 
KeyframeAlphaSymbolAnimation(const std::shared_ptr<RSNode> & rsNode,const Drawing::DrawingPiecewiseParameter & oneStageParas,const uint32_t duration,const std::vector<float> & timePercents)1242 std::shared_ptr<RSAnimation> RSSymbolAnimation::KeyframeAlphaSymbolAnimation(const std::shared_ptr<RSNode>& rsNode,
1243     const Drawing::DrawingPiecewiseParameter& oneStageParas, const uint32_t duration,
1244     const std::vector<float>& timePercents)
1245 {
1246     if (alphaPropertyStages_.size() == 0 || timePercents.size() != alphaPropertyStages_.size()) {
1247         return nullptr;
1248     }
1249     auto keyframeAnimation = std::make_shared<RSKeyframeAnimation>(alphaPropertyStages_[0]); // initial the alpha status
1250     if (keyframeAnimation == nullptr || rsNode == nullptr) {
1251         return nullptr;
1252     }
1253     keyframeAnimation->SetStartDelay(oneStageParas.delay);
1254     keyframeAnimation->SetDuration(duration);
1255     RSAnimationTimingCurve timingCurve;
1256     SymbolAnimation::CreateAnimationTimingCurve(oneStageParas.curveType, oneStageParas.curveArgs, timingCurve);
1257     std::vector<std::tuple<float, std::shared_ptr<RSPropertyBase>, RSAnimationTimingCurve>> keyframes;
1258     for (unsigned int i = 1; i < alphaPropertyStages_.size(); i++) {
1259         keyframes.push_back(std::make_tuple(timePercents[i], alphaPropertyStages_[i], timingCurve));
1260     }
1261     keyframeAnimation->AddKeyFrames(keyframes);
1262     return keyframeAnimation;
1263 }
1264 
1265 // base atomizated animation
ScaleAnimationBase(const std::shared_ptr<RSNode> & rsNode,std::shared_ptr<RSAnimatableProperty<Vector2f>> & scaleProperty,const Drawing::DrawingPiecewiseParameter & scaleParameter,std::vector<std::shared_ptr<RSAnimation>> & animations)1266 void RSSymbolAnimation::ScaleAnimationBase(const std::shared_ptr<RSNode>& rsNode,
1267     std::shared_ptr<RSAnimatableProperty<Vector2f>>& scaleProperty,
1268     const Drawing::DrawingPiecewiseParameter& scaleParameter, std::vector<std::shared_ptr<RSAnimation>>& animations)
1269 {
1270     const auto& properties = scaleParameter.properties;
1271     if (properties.count(SCALE_PROP_X) <= 0 || properties.count(SCALE_PROP_Y) <= 0 ||
1272         properties.at(SCALE_PROP_X).size() < PROPERTIES ||
1273         properties.at(SCALE_PROP_Y).size() < PROPERTIES) {
1274         ROSEN_LOGD("Invalid parameter input of scale.");
1275         return;
1276     }
1277 
1278     if (scaleProperty == nullptr) {
1279         SetNodePivot(rsNode);
1280         const Vector2f scaleValueBegin = { properties.at(SCALE_PROP_X).at(0), properties.at(SCALE_PROP_Y).at(0) };
1281         SymbolAnimation::CreateOrSetModifierValue(scaleProperty, scaleValueBegin);
1282         auto modifier = std::make_shared<ModifierNG::RSTransformModifier>();
1283         modifier->AttachProperty(ModifierNG::RSPropertyType::SCALE, scaleProperty);
1284         rsNode->AddModifier(modifier);
1285     }
1286 
1287     const Vector2f scaleValueEnd = {properties.at(SCALE_PROP_X).at(PROP_END), properties.at(SCALE_PROP_Y).at(PROP_END)};
1288 
1289     // set animation curve and protocol
1290     RSAnimationTimingCurve scaleCurve;
1291     SymbolAnimation::CreateAnimationTimingCurve(scaleParameter.curveType, scaleParameter.curveArgs, scaleCurve);
1292 
1293     RSAnimationTimingProtocol scaleprotocol;
1294     if (range_.has_value()) {
1295         scaleprotocol.SetFrameRateRange(range_.value());
1296     }
1297     scaleprotocol.SetStartDelay(scaleParameter.delay);
1298     if (scaleParameter.duration > 0) {
1299         scaleprotocol.SetDuration(scaleParameter.duration);
1300     }
1301 
1302     // set animation
1303     std::vector<std::shared_ptr<RSAnimation>> animations1 = RSNode::Animate(rsNode->GetRSUIContext(),
1304         scaleprotocol, scaleCurve, [&scaleProperty, &scaleValueEnd]() { scaleProperty->Set(scaleValueEnd); });
1305 
1306     if (animations1.size() > 0 && animations1[0] != nullptr) {
1307         animations.emplace_back(animations1[0]);
1308     }
1309 }
1310 
AlphaAnimationBase(const std::shared_ptr<RSNode> & rsNode,std::shared_ptr<RSAnimatableProperty<float>> & alphaProperty,const Drawing::DrawingPiecewiseParameter & alphaParameter,std::vector<std::shared_ptr<RSAnimation>> & animations)1311 void RSSymbolAnimation::AlphaAnimationBase(const std::shared_ptr<RSNode>& rsNode,
1312     std::shared_ptr<RSAnimatableProperty<float>>& alphaProperty,
1313     const Drawing::DrawingPiecewiseParameter& alphaParameter, std::vector<std::shared_ptr<RSAnimation>>& animations)
1314 {
1315     // validation input
1316     if (rsNode == nullptr) {
1317         ROSEN_LOGD("[%{public}s] : invalid input", __func__);
1318         return;
1319     }
1320     const auto& properties = alphaParameter.properties;
1321     if (properties.count(ALPHA_PROP) <= 0 || properties.at(ALPHA_PROP).size() < PROPERTIES) {
1322         ROSEN_LOGD("Invalid parameter input of alpha.");
1323         return;
1324     }
1325 
1326     if (alphaProperty == nullptr) {
1327         float alphaValueBegin = static_cast<float>(properties.at(ALPHA_PROP).at(PROP_START));
1328         SymbolAnimation::CreateOrSetModifierValue(alphaProperty, alphaValueBegin);
1329         auto alphaModifier = std::make_shared<ModifierNG::RSAlphaModifier>();
1330         alphaModifier->AttachProperty(ModifierNG::RSPropertyType::ALPHA, alphaProperty);
1331         rsNode->AddModifier(alphaModifier);
1332     }
1333     float alphaValueEnd = static_cast<float>(properties.at(ALPHA_PROP).at(PROP_END));
1334 
1335     // set animation protocol and curve
1336     RSAnimationTimingProtocol alphaProtocol;
1337     if (range_.has_value()) {
1338         alphaProtocol.SetFrameRateRange(range_.value());
1339     }
1340     alphaProtocol.SetStartDelay(alphaParameter.delay);
1341     if (alphaParameter.duration > 0) {
1342         alphaProtocol.SetDuration(alphaParameter.duration);
1343     }
1344     RSAnimationTimingCurve alphaCurve;
1345     SymbolAnimation::CreateAnimationTimingCurve(alphaParameter.curveType, alphaParameter.curveArgs, alphaCurve);
1346 
1347     std::vector<std::shared_ptr<RSAnimation>> animations1 = RSNode::Animate(rsNode->GetRSUIContext(),
1348         alphaProtocol, alphaCurve, [&alphaProperty, &alphaValueEnd]() { alphaProperty->Set(alphaValueEnd); });
1349 
1350     if (animations1.size() > 0 && animations1[0] != nullptr) {
1351         animations.emplace_back(animations1[0]);
1352     }
1353 }
1354 
TranslateAnimationBase(const std::shared_ptr<RSNode> & rsNode,std::shared_ptr<RSAnimatableProperty<Vector2f>> & property,const Drawing::DrawingPiecewiseParameter & parameter,std::vector<std::shared_ptr<RSAnimation>> & animations)1355 void RSSymbolAnimation::TranslateAnimationBase(const std::shared_ptr<RSNode>& rsNode,
1356     std::shared_ptr<RSAnimatableProperty<Vector2f>>& property,
1357     const Drawing::DrawingPiecewiseParameter& parameter,
1358     std::vector<std::shared_ptr<RSAnimation>>& animations)
1359 {
1360     const auto& properties = parameter.properties;
1361     bool isInvalid = !properties.count(TRANSLATE_PROP_X) || !properties.count(TRANSLATE_PROP_Y) ||
1362         properties.at(TRANSLATE_PROP_X).size() < PROPERTIES ||
1363         properties.at(TRANSLATE_PROP_Y).size() < PROPERTIES;
1364     if (isInvalid) {
1365         ROSEN_LOGD("Invalid parameter input of translate.");
1366         return;
1367     }
1368 
1369     if (property == nullptr) {
1370         const Vector2f valueBegin = { properties.at(TRANSLATE_PROP_X).at(0), properties.at(TRANSLATE_PROP_Y).at(0) };
1371         SymbolAnimation::CreateOrSetModifierValue(property, valueBegin);
1372         auto modifier = std::make_shared<ModifierNG::RSTransformModifier>();
1373         modifier->AttachProperty(ModifierNG::RSPropertyType::TRANSLATE, property);
1374         rsNode->AddModifier(modifier);
1375     }
1376 
1377     const Vector2f valueEnd = {properties.at(TRANSLATE_PROP_X).at(PROP_END),
1378         properties.at(TRANSLATE_PROP_Y).at(PROP_END)};
1379 
1380     // set animation curve and protocol
1381     RSAnimationTimingCurve timeCurve;
1382     SymbolAnimation::CreateAnimationTimingCurve(parameter.curveType, parameter.curveArgs, timeCurve);
1383 
1384     RSAnimationTimingProtocol protocol;
1385     if (range_.has_value()) {
1386         protocol.SetFrameRateRange(range_.value());
1387     }
1388     protocol.SetStartDelay(parameter.delay);
1389     if (parameter.duration > 0) {
1390         protocol.SetDuration(parameter.duration);
1391     }
1392 
1393     // set animation
1394     std::vector<std::shared_ptr<RSAnimation>> animations1 = RSNode::Animate(rsNode->GetRSUIContext(),
1395         protocol, timeCurve, [&property, &valueEnd]() { property->Set(valueEnd); });
1396 
1397     if (animations1.size() > 0 && animations1[0] != nullptr) {
1398         animations.emplace_back(animations1[0]);
1399     }
1400 }
1401 
BlurAnimationBase(const std::shared_ptr<RSNode> & rsNode,std::shared_ptr<RSAnimatableProperty<float>> & property,const Drawing::DrawingPiecewiseParameter & parameter,std::vector<std::shared_ptr<RSAnimation>> & animations)1402 void RSSymbolAnimation::BlurAnimationBase(const std::shared_ptr<RSNode>& rsNode,
1403     std::shared_ptr<RSAnimatableProperty<float>>& property,
1404     const Drawing::DrawingPiecewiseParameter& parameter,
1405     std::vector<std::shared_ptr<RSAnimation>>& animations)
1406 {
1407     const auto& properties = parameter.properties;
1408     bool isInValid = !properties.count(BLUR_PROP) || properties.at(BLUR_PROP).size() < PROPERTIES;
1409     if (isInValid) {
1410         ROSEN_LOGD("Invalid parameter input of blur.");
1411         return;
1412     }
1413 
1414     if (property == nullptr) {
1415         float valueBegin = properties.at(BLUR_PROP).at(PROP_START);
1416         SymbolAnimation::CreateOrSetModifierValue(property, valueBegin);
1417         auto modifier = std::make_shared<ModifierNG::RSForegroundFilterModifier>();
1418         modifier->AttachProperty(ModifierNG::RSPropertyType::FOREGROUND_EFFECT_RADIUS, property);
1419         rsNode->AddModifier(modifier);
1420     }
1421 
1422     float valueEnd = properties.at(BLUR_PROP).at(PROP_END);
1423 
1424     // set animation curve and protocol
1425     RSAnimationTimingCurve timeCurve;
1426     SymbolAnimation::CreateAnimationTimingCurve(parameter.curveType, parameter.curveArgs, timeCurve);
1427 
1428     RSAnimationTimingProtocol protocol;
1429     if (range_.has_value()) {
1430         protocol.SetFrameRateRange(range_.value());
1431     }
1432     protocol.SetStartDelay(parameter.delay);
1433     if (parameter.duration > 0) {
1434         protocol.SetDuration(parameter.duration);
1435     }
1436 
1437     // set animation
1438     std::vector<std::shared_ptr<RSAnimation>> animations1 = RSNode::Animate(rsNode->GetRSUIContext(),
1439         protocol, timeCurve, [&property, &valueEnd]() { property->Set(valueEnd); });
1440 
1441     if (animations1.size() > 0 && animations1[0] != nullptr) {
1442         animations.emplace_back(animations1[0]);
1443     }
1444 }
1445 } // namespace Rosen
1446 } // namespace OHOS