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