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