1 /*
2 * Copyright (c) 2021-2022 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 "core/components/tween/tween_element.h"
17
18 #include "base/geometry/transform_util.h"
19 #include "core/animation/curve_animation.h"
20 #include "core/common/frontend.h"
21 #include "core/components/clip/render_clip.h"
22 #include "core/components/display/display_component.h"
23 #include "core/components/positioned/positioned_element.h"
24 #include "core/components/shared_transition/shared_transition_element.h"
25 #include "core/components/transform/transform_component.h"
26 #include "core/components/tween/tween_component.h"
27 #include "core/pipeline/base/render_element.h"
28
29 namespace OHOS::Ace {
30 namespace {
GetAnimatable(const RefPtr<Element> & contentElement)31 RefPtr<PropertyAnimatable> GetAnimatable(const RefPtr<Element>& contentElement)
32 {
33 if (!contentElement) {
34 LOGE("Get Animatable failed. content element is null.");
35 return nullptr;
36 }
37 return AceType::DynamicCast<PropertyAnimatable>(contentElement->GetRenderNode());
38 }
39
SetTranslateProperties(const RefPtr<Animation<DimensionOffset>> & translateAnimation,TweenOption & option)40 void SetTranslateProperties(const RefPtr<Animation<DimensionOffset>>& translateAnimation, TweenOption& option)
41 {
42 if (option.GetCurve()) {
43 translateAnimation->SetCurve(option.GetCurve());
44 }
45 if (!translateAnimation->HasInitValue()) {
46 DimensionOffset beginPos = DimensionOffset(Dimension(), Dimension());
47 translateAnimation->SetInitValue(beginPos);
48 }
49 }
50
SetScaleProperties(const RefPtr<Animation<float>> & scaleAnimation,TweenOption & option)51 void SetScaleProperties(const RefPtr<Animation<float>>& scaleAnimation, TweenOption& option)
52 {
53 if (option.GetCurve()) {
54 scaleAnimation->SetCurve(option.GetCurve());
55 }
56 if (!scaleAnimation->HasInitValue()) {
57 scaleAnimation->SetInitValue(1.0f);
58 }
59 }
60
SetRotateProperties(const RefPtr<Animation<float>> & rotateAnimation,TweenOption & option)61 void SetRotateProperties(const RefPtr<Animation<float>>& rotateAnimation, TweenOption& option)
62 {
63 if (option.GetCurve()) {
64 rotateAnimation->SetCurve(option.GetCurve());
65 }
66 if (!rotateAnimation->HasInitValue()) {
67 rotateAnimation->SetInitValue(0.0f);
68 }
69 }
70
ResetController(RefPtr<Animator> & controller)71 void ResetController(RefPtr<Animator>& controller)
72 {
73 if (!controller) {
74 LOGE("Reset Controller failed. controller is null.");
75 return;
76 }
77 if (controller->GetStatus() != Animator::Status::IDLE && controller->GetStatus() != Animator::Status::STOPPED) {
78 controller->Finish();
79 }
80 controller->ClearInterpolators();
81 }
82
83 template<class T>
SetAnimationProperties(const RefPtr<Animation<T>> & animation,TweenOption & option)84 void SetAnimationProperties(const RefPtr<Animation<T>>& animation, TweenOption& option)
85 {
86 if (option.GetCurve()) {
87 animation->SetCurve(option.GetCurve());
88 }
89 if (!animation->HasInitValue()) {
90 animation->SetInitValue(T {});
91 }
92 }
93
RenderTransformUpdate(WeakPtr<RenderTransform> & weakPtr,const TransformOperation & value)94 void RenderTransformUpdate(WeakPtr<RenderTransform>& weakPtr, const TransformOperation& value)
95 {
96 auto renderTransformNode = weakPtr.Upgrade();
97 if (renderTransformNode) {
98 switch (value.type_) {
99 case TransformOperationType::TRANSLATE:
100 renderTransformNode->Translate(
101 value.translateOperation_.dx, value.translateOperation_.dy, value.translateOperation_.dz);
102 break;
103 case TransformOperationType::SKEW:
104 renderTransformNode->Skew(value.skewOperation_.skewX, value.skewOperation_.skewY);
105 break;
106 case TransformOperationType::ROTATE:
107 renderTransformNode->Rotate(value.rotateOperation_.angle, value.rotateOperation_.dx,
108 value.rotateOperation_.dy, value.rotateOperation_.dz);
109 break;
110 case TransformOperationType::MATRIX:
111 renderTransformNode->Matrix3D(value.matrix4_);
112 break;
113 case TransformOperationType::SCALE:
114 renderTransformNode->Scale(
115 value.scaleOperation_.scaleX, value.scaleOperation_.scaleY, value.scaleOperation_.scaleZ);
116 break;
117 case TransformOperationType::PERSPECTIVE:
118 renderTransformNode->Perspective(value.perspectiveOperation_.distance);
119 break;
120 case TransformOperationType::UNDEFINED:
121 renderTransformNode->Translate(Dimension {}, Dimension {}, Dimension {});
122 break;
123 default:
124 LOGE("unsupported transform operation");
125 break;
126 }
127 }
128 }
129
TransformComponentUpdate(WeakPtr<TransformComponent> & transform,const TransformOperation & value)130 void TransformComponentUpdate(WeakPtr<TransformComponent>& transform, const TransformOperation& value)
131 {
132 auto transformComponent = transform.Upgrade();
133 if (transformComponent) {
134 transformComponent->ResetTransform();
135 switch (value.type_) {
136 case TransformOperationType::TRANSLATE:
137 transformComponent->Translate(
138 value.translateOperation_.dx, value.translateOperation_.dy, value.translateOperation_.dz);
139 break;
140 case TransformOperationType::SKEW:
141 transformComponent->Skew(value.skewOperation_.skewX, value.skewOperation_.skewY);
142 break;
143 case TransformOperationType::ROTATE:
144 transformComponent->Rotate(value.rotateOperation_.dx, value.rotateOperation_.dy,
145 value.rotateOperation_.dz, value.rotateOperation_.angle);
146 break;
147 case TransformOperationType::MATRIX:
148 transformComponent->Matrix3d(value.matrix4_);
149 break;
150 case TransformOperationType::SCALE:
151 transformComponent->Scale(
152 value.scaleOperation_.scaleX, value.scaleOperation_.scaleY, value.scaleOperation_.scaleZ);
153 break;
154 case TransformOperationType::PERSPECTIVE:
155 transformComponent->Perspective(value.perspectiveOperation_.distance);
156 break;
157 case TransformOperationType::UNDEFINED:
158 transformComponent->Translate(Dimension {}, Dimension {}, Dimension {});
159 break;
160 default:
161 LOGE("unsupported transform operation");
162 break;
163 }
164 }
165 }
166
RenderTransformOriginUpdate(const WeakPtr<RenderTransform> & weakPtr,const DimensionOffset & origin)167 void RenderTransformOriginUpdate(const WeakPtr<RenderTransform>& weakPtr, const DimensionOffset& origin)
168 {
169 auto renderTransformNode = weakPtr.Upgrade();
170 if (renderTransformNode) {
171 renderTransformNode->SetTransformOrigin(origin.GetX(), origin.GetY());
172 renderTransformNode->MarkNeedUpdateOrigin();
173 }
174 }
175
CreateTransformAnimation(const RefPtr<RenderTransform> & renderTransformNode,const WeakPtr<TransformComponent> & transform,TweenOption & option)176 void CreateTransformAnimation(const RefPtr<RenderTransform>& renderTransformNode,
177 const WeakPtr<TransformComponent>& transform, TweenOption& option)
178 {
179 WeakPtr<RenderTransform> weak(renderTransformNode);
180
181 for (const auto& animation : option.GetTransformAnimations()) {
182 if (animation) {
183 SetAnimationProperties(animation, option);
184 animation->AddListener(std::bind(RenderTransformUpdate, weak, std::placeholders::_1));
185 animation->AddListener(std::bind(TransformComponentUpdate, transform, std::placeholders::_1));
186 }
187 }
188 }
189
OpacityAnimationListener(const WeakPtr<RenderDisplay> & weakRender,WeakPtr<DisplayComponent> & display,float value)190 void OpacityAnimationListener(
191 const WeakPtr<RenderDisplay>& weakRender, WeakPtr<DisplayComponent>& display, float value)
192 {
193 auto opacity = static_cast<uint8_t>(Round(value * UINT8_MAX));
194 if (value < 0.0f || value > 1.0f) {
195 opacity = UINT8_MAX;
196 }
197 auto renderDisplayNode = weakRender.Upgrade();
198 auto displayComponent = display.Upgrade();
199 if (renderDisplayNode) {
200 renderDisplayNode->UpdateOpacity(opacity);
201 if (displayComponent) {
202 displayComponent->SetOpacity((double) opacity / UINT8_MAX);
203 }
204 }
205 }
206
CreateOpacityAnimation(const RefPtr<RenderDisplay> & renderDisplayNode,const WeakPtr<DisplayComponent> & display,TweenOption & option)207 void CreateOpacityAnimation(
208 const RefPtr<RenderDisplay>& renderDisplayNode, const WeakPtr<DisplayComponent>& display, TweenOption& option)
209 {
210 auto& opacityAnimation = option.GetOpacityAnimation();
211 if (!opacityAnimation) {
212 return;
213 }
214 if (!opacityAnimation->HasInitValue()) {
215 opacityAnimation->SetInitValue(UINT8_MAX);
216 }
217 WeakPtr<RenderDisplay> weakRender = renderDisplayNode;
218 opacityAnimation->AddListener(std::bind(OpacityAnimationListener, weakRender, display, std::placeholders::_1));
219
220 if (option.GetCurve()) {
221 opacityAnimation->SetCurve(option.GetCurve());
222 }
223 }
224
BindingTransformAnimationToController(RefPtr<Animator> & controller,TweenOption & option)225 bool BindingTransformAnimationToController(RefPtr<Animator>& controller, TweenOption& option)
226 {
227 bool needAnimation = false;
228 const auto& animations = option.GetTransformAnimations();
229 for (auto& animation : animations) {
230 if (animation) {
231 needAnimation = true;
232 controller->AddInterpolator(animation);
233 }
234 }
235 return needAnimation;
236 }
237
238 } // namespace
239
240 const LinearEnumMapNode<AnimationType,
241 void (*)(const RefPtr<Animation<float>>&, WeakPtr<RenderTransform>&, TweenOption&)>
242 TweenElement::transformFloatAnimationAddMap_[] = {
243 { AnimationType::SCALE,
244 [](const RefPtr<Animation<float>>& scaleAnimation, WeakPtr<RenderTransform>& weakRender,
__anonf1ba2b2b0202() 245 TweenOption& option) {
246 SetScaleProperties(scaleAnimation, option);
247 scaleAnimation->AddListener([weakRender, scaleAnimation](float value) {
248 auto renderTransformNode = weakRender.Upgrade();
249 if (renderTransformNode) {
250 renderTransformNode->Scale(value);
251 }
252 });
253 } },
254 { AnimationType::SCALE_X,
255 [](const RefPtr<Animation<float>>& scaleXAnimation, WeakPtr<RenderTransform>& weakRender,
__anonf1ba2b2b0402() 256 TweenOption& option) {
257 SetScaleProperties(scaleXAnimation, option);
258 double maxScaleXY = option.GetMaxScaleXY();
259 auto renderTransformNode = weakRender.Upgrade();
260 if (renderTransformNode) {
261 renderTransformNode->SetMaxScaleXY(maxScaleXY);
262 }
263 scaleXAnimation->AddListener([weakRender, scaleXAnimation](float value) {
264 auto renderTransformNode = weakRender.Upgrade();
265 if (renderTransformNode) {
266 renderTransformNode->Scale(value, 1.0f);
267 }
268 });
269 } },
270 { AnimationType::SCALE_Y,
271 [](const RefPtr<Animation<float>>& scaleYAnimation, WeakPtr<RenderTransform>& weakRender,
__anonf1ba2b2b0602() 272 TweenOption& option) {
273 SetScaleProperties(scaleYAnimation, option);
274 scaleYAnimation->AddListener([weakRender, scaleYAnimation](float value) {
275 auto renderTransformNode = weakRender.Upgrade();
276 if (renderTransformNode) {
277 renderTransformNode->Scale(1.0f, value);
278 }
279 });
280 } },
281 { AnimationType::ROTATE_Z,
282 [](const RefPtr<Animation<float>>& rotateZAnimation, WeakPtr<RenderTransform>& weakRender,
__anonf1ba2b2b0802() 283 TweenOption& option) {
284 SetRotateProperties(rotateZAnimation, option);
285 rotateZAnimation->AddListener([weakRender, rotateZAnimation](float value) {
286 auto renderTransformNode = weakRender.Upgrade();
287 if (renderTransformNode) {
288 renderTransformNode->RotateZ(value);
289 }
290 });
291 } },
292 { AnimationType::ROTATE_X,
293 [](const RefPtr<Animation<float>>& rotateXAnimation, WeakPtr<RenderTransform>& weakRender,
__anonf1ba2b2b0a02() 294 TweenOption& option) {
295 SetRotateProperties(rotateXAnimation, option);
296 rotateXAnimation->AddListener([weakRender, rotateXAnimation](float value) {
297 auto renderTransformNode = weakRender.Upgrade();
298 if (renderTransformNode) {
299 renderTransformNode->RotateX(value);
300 }
301 });
302 } },
303 { AnimationType::ROTATE_Y,
304 [](const RefPtr<Animation<float>>& rotateYAnimation, WeakPtr<RenderTransform>& weakRender,
__anonf1ba2b2b0c02() 305 TweenOption& option) {
306 SetRotateProperties(rotateYAnimation, option);
307 rotateYAnimation->AddListener([weakRender, rotateYAnimation](float value) {
308 auto renderTransformNode = weakRender.Upgrade();
309 if (renderTransformNode) {
310 renderTransformNode->RotateY(value);
311 }
312 });
313 } }
314 };
315
Update()316 void TweenElement::Update()
317 {
318 ComposedElement::Update();
319 if (!component_) {
320 return;
321 }
322 auto tweenComponent = AceType::DynamicCast<TweenComponent>(component_);
323 if (!tweenComponent) {
324 LOGE("Get TweenComponent failed.");
325 return;
326 }
327 shadow_ = tweenComponent->GetShadow();
328 positionParam_ = tweenComponent->GetPositionParam();
329
330 if (tweenComponent->IsAnimationNameUpdated()) {
331 needUpdateKeyframes_ = true;
332 tweenComponent->DisableAnimationNameUpdated();
333 }
334 if (tweenComponent->IsOptionCssChanged()) {
335 needUpdateTweenOption_ = true;
336 option_ = tweenComponent->GetTweenOption();
337 tweenComponent->SetOptionCssChanged(false);
338 }
339 if (tweenComponent->IsOptionCustomChanged()) {
340 needUpdateTweenOptionCustom_ = true;
341 optionCustom_ = tweenComponent->GetCustomTweenOption();
342 tweenComponent->SetOptionCustomChanged(false);
343 }
344 if (tweenComponent->IsOperationCssChanged()) {
345 operation_ = tweenComponent->GetAnimationOperation();
346 tweenComponent->SetOperationCssChanged(false);
347 }
348 if (tweenComponent->IsOperationCustomChanged()) {
349 operationCustom_ = tweenComponent->GetCustomAnimationOperation();
350 tweenComponent->SetOperationCustomChanged(false);
351 }
352 auto pipelineContext = context_.Upgrade();
353 if (pipelineContext) {
354 RefPtr<Animator> controller = tweenComponent->GetAnimator();
355 if (controller) {
356 isComponentController_ = true;
357 if (!controller->HasScheduler()) {
358 controller->AttachScheduler(context_);
359 }
360 controllerCustom_ = controller;
361 tweenComponent->SetAnimator(controllerCustom_);
362 }
363 if (!controller_) {
364 isDelegatedController_ = false;
365 controller_ = CREATE_ANIMATOR(context_);
366 tweenComponent->SetAnimator(controller_);
367 }
368
369 // If transform component exists, it also plays animation. RenderTransform can get correct value from component
370 // when Update(component).
371 if ((operation_ != AnimationOperation::NONE || operationCustom_ != AnimationOperation::NONE) &&
372 !transform_.Upgrade()) {
373 pipelineContext->AddPostAnimationFlushListener(AceType::Claim(this));
374 }
375 pipelineContext->AddPostFlushListener(AceType::Claim(this));
376 }
377 }
378
~TweenElement()379 TweenElement::~TweenElement()
380 {
381 if (isComponentController_ && controllerCustom_) {
382 controllerCustom_->Stop();
383 controllerCustom_->ClearInterpolators();
384 controllerCustom_->ClearAllListeners();
385 }
386 }
387
ApplyOperation(RefPtr<Animator> & controller,AnimationOperation & operation)388 void TweenElement::ApplyOperation(RefPtr<Animator>& controller, AnimationOperation& operation)
389 {
390 switch (operation) {
391 case AnimationOperation::PLAY:
392 controller->Play();
393 break;
394 case AnimationOperation::RUNNING:
395 controller->Play();
396 break;
397 case AnimationOperation::PAUSE:
398 controller->Pause();
399 break;
400 case AnimationOperation::CANCEL:
401 controller->Cancel();
402 break;
403 case AnimationOperation::FINISH:
404 controller->Finish();
405 break;
406 case AnimationOperation::REVERSE:
407 controller->Reverse();
408 break;
409 case AnimationOperation::NONE:
410 default:
411 break;
412 }
413 }
414
OnPostFlush()415 void TweenElement::OnPostFlush()
416 {
417 if (skipPostFlush_) {
418 skipPostFlush_ = false;
419 return;
420 }
421 AddPreFlush();
422 }
423
OnPostAnimationFlush()424 void TweenElement::OnPostAnimationFlush()
425 {
426 if (controller_) {
427 controller_->TriggerFrame(controller_->GetPlayedTime(), true);
428 }
429 if (controllerCustom_) {
430 controllerCustom_->TriggerFrame(controllerCustom_->GetPlayedTime(), true);
431 }
432 }
433
OnPreFlush()434 void TweenElement::OnPreFlush()
435 {
436 if (!controller_ && !controllerCustom_) {
437 return;
438 }
439 SetWrapHidden(false);
440 if (isDelegatedController_ && !isComponentController_) {
441 return;
442 }
443
444 if (needUpdateKeyframes_ || (operation_ == AnimationOperation::PLAY && needUpdateTweenOption_)) {
445 ResetController(controller_);
446 ApplyKeyframes();
447 needUpdateKeyframes_ = false;
448 }
449
450 if (needUpdateTweenOption_) {
451 ApplyOptions(controller_, option_);
452 needUpdateTweenOption_ = false;
453 }
454 if (needUpdateTweenOptionCustom_) {
455 ResetController(controllerCustom_);
456 ApplyKeyframes(controllerCustom_, optionCustom_, prepareIdCustom_);
457 ApplyOptions(controllerCustom_, optionCustom_);
458 needUpdateTweenOptionCustom_ = false;
459 }
460 if (operation_ != AnimationOperation::NONE || operationCustom_ != AnimationOperation::NONE) {
461 auto pipelineContext = context_.Upgrade();
462 if (!pipelineContext) {
463 return;
464 }
465 }
466
467 if (controller_) {
468 ApplyOperation(controller_, operation_);
469 }
470 if (controllerCustom_) {
471 ApplyOperation(controllerCustom_, operationCustom_);
472 }
473
474 // reset operation to none.
475 operation_ = AnimationOperation::NONE;
476 operationCustom_ = AnimationOperation::NONE;
477 }
478
IsNeedAnimation(RefPtr<Animator> & controller,TweenOption & option)479 bool TweenElement::IsNeedAnimation(RefPtr<Animator>& controller, TweenOption& option)
480 {
481 if (!controller) {
482 LOGE("add interpolator failed. controller is null.");
483 return false;
484 }
485 bool needAnimation = false;
486 auto& transformOffsetAnimations = option.GetTranslateAnimations();
487 for (auto&& [translate, animation] : transformOffsetAnimations) {
488 if (animation) {
489 needAnimation = true;
490 controller->AddInterpolator(animation);
491 }
492 }
493 auto& transformFloatAnimations = option.GetTransformFloatAnimation();
494 for (auto&& [transformFloat, animation] : transformFloatAnimations) {
495 if (animation) {
496 needAnimation = true;
497 controller->AddInterpolator(animation);
498 }
499 }
500 if (BindingTransformAnimationToController(controller, option)) {
501 needAnimation = true;
502 }
503 auto& transformOriginAnimation = option.GetTransformOriginAnimation();
504 if (transformOriginAnimation) {
505 controller->AddInterpolator(transformOriginAnimation);
506 // no need enable needAnimation, Transform Origin Animation only work when set transform animation.
507 }
508 auto& opacityAnimation = option.GetOpacityAnimation();
509 if (opacityAnimation) {
510 controller->AddInterpolator(opacityAnimation);
511 needAnimation = true;
512 }
513 auto& colorAnimation = option.GetColorAnimation();
514 if (colorAnimation) {
515 controller->AddInterpolator(colorAnimation);
516 needAnimation = true;
517 }
518 if (AddToAnimator(option.GetFloatPropertyAnimation(), controller, option)) {
519 needAnimation = true;
520 }
521 return needAnimation;
522 }
523
BuildChild()524 RefPtr<Component> TweenElement::BuildChild()
525 {
526 RefPtr<TweenComponent> tween = AceType::DynamicCast<TweenComponent>(component_);
527 if (tween) {
528 RefPtr<DisplayComponent> displayComponent = AceType::DynamicCast<DisplayComponent>(tween->GetChild());
529 RefPtr<TransformComponent> transformComponent;
530 if (displayComponent) {
531 transformComponent = AceType::DynamicCast<TransformComponent>(displayComponent->GetChild());
532 if (!transformComponent) {
533 transformComponent = AceType::MakeRefPtr<TransformComponent>();
534 transformComponent->SetChild(displayComponent->GetChild());
535 displayComponent->SetChild(transformComponent);
536 }
537 } else {
538 transformComponent = AceType::MakeRefPtr<TransformComponent>();
539 displayComponent = AceType::MakeRefPtr<DisplayComponent>(transformComponent);
540 transformComponent->SetChild(ComposedElement::BuildChild());
541 }
542 displayComponent->SetPositionType(positionParam_.type);
543 displayComponent->SetHasLeft(positionParam_.left.second);
544 displayComponent->SetHasRight(positionParam_.right.second);
545 displayComponent->SetHasTop(positionParam_.top.second);
546 displayComponent->SetHasBottom(positionParam_.bottom.second);
547 displayComponent->SetLeft(positionParam_.left.first);
548 displayComponent->SetRight(positionParam_.right.first);
549 displayComponent->SetTop(positionParam_.top.first);
550 displayComponent->SetBottom(positionParam_.bottom.first);
551 displayComponent->DisableLayer(tween->IsLeafNode());
552 transform_ = transformComponent;
553 display_ = displayComponent;
554 return displayComponent;
555 } else {
556 LOGE("no tween component found. return empty child.");
557 return nullptr;
558 }
559 }
560
PerformBuild()561 void TweenElement::PerformBuild()
562 {
563 ComposedElement::PerformBuild();
564 auto tweenComponent = AceType::DynamicCast<TweenComponent>(component_);
565 if (!tweenComponent) {
566 LOGE("Get TweenComponent failed.");
567 return;
568 }
569 if (!tweenComponent->GetIsFirstFrameShow()) {
570 SetWrapHidden(true);
571 }
572 }
573
CanUpdate(const RefPtr<Component> & newComponent)574 bool TweenElement::CanUpdate(const RefPtr<Component>& newComponent)
575 {
576 auto pipelineContext = context_.Upgrade();
577 if (pipelineContext && pipelineContext->GetIsDeclarative()) {
578 return ComposedElement::CanUpdate(newComponent);
579 }
580 // components of the same type are not updated.
581 return Element::CanUpdate(newComponent);
582 }
583
CreateTranslateAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)584 void TweenElement::CreateTranslateAnimation(const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
585 {
586 if (!option.HasTransformOffsetChanged()) {
587 return;
588 }
589 auto& transformOffsetAnimations = option.GetTranslateAnimations();
590 WeakPtr<RenderTransform> weakRender = renderTransformNode;
591 static const LinearEnumMapNode<AnimationType,
592 void (*)(const RefPtr<Animation<DimensionOffset>>&, WeakPtr<RenderTransform>&, TweenOption&)>
593 translateAnimationAddMap[] = {
594 { AnimationType::TRANSLATE,
595 [](const RefPtr<Animation<DimensionOffset>>& translateAnimation,
596 WeakPtr<RenderTransform>& weakRender, TweenOption& option) {
597 SetTranslateProperties(translateAnimation, option);
598 translateAnimation->AddListener([weakRender](const DimensionOffset& value) {
599 auto renderTransformNode = weakRender.Upgrade();
600 if (renderTransformNode) {
601 renderTransformNode->Translate(value.GetX(), value.GetY());
602 }
603 });
604 } },
605 { AnimationType::TRANSLATE_X,
606 [](const RefPtr<Animation<DimensionOffset>>& translateXAnimation, WeakPtr<RenderTransform>& weakRender,
607 TweenOption& option) {
608 SetTranslateProperties(translateXAnimation, option);
609 translateXAnimation->AddListener([weakRender](const DimensionOffset& value) {
610 auto renderTransformNode = weakRender.Upgrade();
611 if (renderTransformNode) {
612 renderTransformNode->Translate(value.GetX(), 0.0_px);
613 }
614 });
615 } },
616 { AnimationType::TRANSLATE_Y,
617 [](const RefPtr<Animation<DimensionOffset>>& translateYAnimation, WeakPtr<RenderTransform>& weakRender,
618 TweenOption& option) {
619 SetTranslateProperties(translateYAnimation, option);
620 translateYAnimation->AddListener([weakRender](const DimensionOffset& value) {
621 auto renderTransformNode = weakRender.Upgrade();
622 if (renderTransformNode) {
623 renderTransformNode->Translate(0.0_px, value.GetY());
624 }
625 });
626 } }
627 };
628 size_t mapSize = ArraySize(translateAnimationAddMap);
629 auto iterTranslateAnimation = transformOffsetAnimations.find(AnimationType::TRANSLATE);
630 if (iterTranslateAnimation != transformOffsetAnimations.end()) {
631 auto translateAnimationIter =
632 BinarySearchFindIndex(translateAnimationAddMap, mapSize, AnimationType::TRANSLATE);
633 if (translateAnimationIter != -1) {
634 auto& translateAnimation = iterTranslateAnimation->second;
635 translateAnimationAddMap[translateAnimationIter].value(translateAnimation, weakRender, option);
636 }
637 }
638
639 auto iterTranslateXAnimation = transformOffsetAnimations.find(AnimationType::TRANSLATE_X);
640 if (iterTranslateXAnimation != transformOffsetAnimations.end()) {
641 auto translateXAnimationIter =
642 BinarySearchFindIndex(translateAnimationAddMap, mapSize, AnimationType::TRANSLATE_X);
643 if (translateXAnimationIter != -1) {
644 auto& translateXAnimation = iterTranslateXAnimation->second;
645 translateAnimationAddMap[translateXAnimationIter].value(translateXAnimation, weakRender, option);
646 }
647 }
648
649 auto iterTranslateYAnimation = transformOffsetAnimations.find(AnimationType::TRANSLATE_Y);
650 if (iterTranslateYAnimation != transformOffsetAnimations.end()) {
651 auto translateYAnimationIter =
652 BinarySearchFindIndex(translateAnimationAddMap, mapSize, AnimationType::TRANSLATE_Y);
653 if (translateYAnimationIter != -1) {
654 auto& translateYAnimation = iterTranslateYAnimation->second;
655 translateAnimationAddMap[translateYAnimationIter].value(translateYAnimation, weakRender, option);
656 }
657 }
658 }
659
CreateScaleAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)660 void TweenElement::CreateScaleAnimation(const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
661 {
662 if (!option.HasTransformFloatChanged()) {
663 return;
664 }
665 auto& transformFloatAnimations = option.GetTransformFloatAnimation();
666 WeakPtr<RenderTransform> weakRender = renderTransformNode;
667 auto iterScaleAnimation = transformFloatAnimations.find(AnimationType::SCALE);
668 size_t mapSize = ArraySize(transformFloatAnimationAddMap_);
669 if (iterScaleAnimation != transformFloatAnimations.end()) {
670 auto scaleAnimationIter = BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::SCALE);
671 if (scaleAnimationIter != -1) {
672 auto& scaleAnimation = iterScaleAnimation->second;
673 transformFloatAnimationAddMap_[scaleAnimationIter].value(scaleAnimation, weakRender, option);
674 }
675 }
676
677 auto iterScaleXAnimation = transformFloatAnimations.find(AnimationType::SCALE_X);
678 if (iterScaleXAnimation != transformFloatAnimations.end()) {
679 auto scaleXAnimationIter =
680 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::SCALE_X);
681 if (scaleXAnimationIter != -1) {
682 auto& scaleXAnimation = iterScaleXAnimation->second;
683 transformFloatAnimationAddMap_[scaleXAnimationIter].value(scaleXAnimation, weakRender, option);
684 }
685 }
686
687 auto iterScaleYAnimation = transformFloatAnimations.find(AnimationType::SCALE_Y);
688 if (iterScaleYAnimation != transformFloatAnimations.end()) {
689 auto scaleYAnimationIter =
690 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::SCALE_Y);
691 if (scaleYAnimationIter != -1) {
692 auto& scaleYAnimation = iterScaleYAnimation->second;
693 transformFloatAnimationAddMap_[scaleYAnimationIter].value(scaleYAnimation, weakRender, option);
694 }
695 }
696 }
697
CreateTransformOriginAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)698 void TweenElement::CreateTransformOriginAnimation(
699 const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
700 {
701 if (option.HasTransformOriginChanged()) {
702 renderTransformNode->SetTransformOrigin(option.GetTransformOriginX(), option.GetTransformOriginY());
703 auto animation = option.GetTransformOriginAnimation();
704 if (animation) {
705 animation->AddListener([weak = AceType::WeakClaim(AceType::RawPtr(renderTransformNode))](
706 const DimensionOffset& value) { RenderTransformOriginUpdate(weak, value); });
707
708 if (option.GetCurve()) {
709 animation->SetCurve(option.GetCurve());
710 }
711 }
712 option.SetTransformOriginChanged(false);
713 } else {
714 renderTransformNode->SetTransformOrigin(HALF_PERCENT, HALF_PERCENT);
715 renderTransformNode->MarkNeedUpdateOrigin();
716 }
717 }
718
CreateRotateAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)719 void TweenElement::CreateRotateAnimation(const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
720 {
721 if (!option.HasTransformFloatChanged()) {
722 return;
723 }
724 auto& transformFloatAnimations = option.GetTransformFloatAnimation();
725 WeakPtr<RenderTransform> weakRender = renderTransformNode;
726 auto iterRotateZAnimation = transformFloatAnimations.find(AnimationType::ROTATE_Z);
727 size_t mapSize = ArraySize(transformFloatAnimationAddMap_);
728 if (iterRotateZAnimation != transformFloatAnimations.end()) {
729 auto rotateZAnimationIter =
730 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::ROTATE_Z);
731 if (rotateZAnimationIter != -1) {
732 auto& rotateZAnimation = iterRotateZAnimation->second;
733 transformFloatAnimationAddMap_[rotateZAnimationIter].value(rotateZAnimation, weakRender, option);
734 }
735 }
736
737 auto iterRotateXAnimation = transformFloatAnimations.find(AnimationType::ROTATE_X);
738 if (iterRotateXAnimation != transformFloatAnimations.end()) {
739 auto rotateXAnimationIter =
740 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::ROTATE_X);
741 if (rotateXAnimationIter != -1) {
742 auto& rotateXAnimation = iterRotateXAnimation->second;
743 transformFloatAnimationAddMap_[rotateXAnimationIter].value(rotateXAnimation, weakRender, option);
744 }
745 }
746
747 auto iterRotateYAnimation = transformFloatAnimations.find(AnimationType::ROTATE_Y);
748 if (iterRotateYAnimation != transformFloatAnimations.end()) {
749 auto rotateYAnimationIter =
750 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::ROTATE_Y);
751 if (rotateYAnimationIter != -1) {
752 auto& rotateYAnimation = iterRotateYAnimation->second;
753 transformFloatAnimationAddMap_[rotateYAnimationIter].value(rotateYAnimation, weakRender, option);
754 }
755 }
756 }
757
CreateColorAnimation(const RefPtr<PropertyAnimatable> & animatable,TweenOption & option)758 void TweenElement::CreateColorAnimation(const RefPtr<PropertyAnimatable>& animatable, TweenOption& option)
759 {
760 if (!animatable) {
761 LOGE("create color animation failed. not a animatable child.");
762 return;
763 }
764 auto& colorAnimation = option.GetColorAnimation();
765 if (!colorAnimation) {
766 return;
767 }
768 PropertyAnimatableType propertyType;
769 if (option.GetIsBackground()) {
770 propertyType = PropertyAnimatableType::PROPERTY_BACK_DECORATION_COLOR;
771 } else {
772 propertyType = PropertyAnimatableType::PROPERTY_FRONT_DECORATION_COLOR;
773 }
774 CreatePropertyAnimation<ColorPropertyAnimatable, Color>(animatable, propertyType, option, colorAnimation);
775 }
776
777 template<class U, class V>
CreatePropertyAnimation(const RefPtr<PropertyAnimatable> & propertyAnimatable,PropertyAnimatableType propertyType,const TweenOption & option,RefPtr<Animation<V>> & animation)778 bool TweenElement::CreatePropertyAnimation(const RefPtr<PropertyAnimatable>& propertyAnimatable,
779 PropertyAnimatableType propertyType, const TweenOption& option, RefPtr<Animation<V>>& animation)
780 {
781 if (!animation) {
782 LOGE("CreatePropertyAnimation failed, animation is null.");
783 return false;
784 }
785 typename U::Type initValue;
786 bool created =
787 PropertyAnimatable::AddPropertyAnimation<U, V>(propertyAnimatable, propertyType, animation, initValue);
788 if (!created) {
789 LOGE("create property animation failed. property: %{public}d", propertyType);
790 return false;
791 }
792 if (option.GetCurve()) {
793 animation->SetCurve(option.GetCurve());
794 }
795 if (!animation->HasInitValue()) {
796 animation->SetInitValue(initValue);
797 }
798 return true;
799 }
800
801 template<class U>
AddToAnimator(const std::map<PropertyAnimatableType,U> & animations,RefPtr<Animator> & controller,TweenOption & option)802 bool TweenElement::AddToAnimator(
803 const std::map<PropertyAnimatableType, U>& animations, RefPtr<Animator>& controller, TweenOption& option)
804 {
805 bool needAnimation = false;
806 for (auto&& [property, animation] : animations) {
807 if (animation) {
808 needAnimation = true;
809 controller->AddInterpolator(animation);
810 }
811 }
812 return needAnimation;
813 }
814
SetController(const RefPtr<Animator> & controller)815 void TweenElement::SetController(const RefPtr<Animator>& controller)
816 {
817 if (!controller) {
818 LOGE("set controller failed. controller is empty.");
819 return;
820 }
821 if (!controller_->IsStopped()) {
822 controller_->Stop();
823 }
824 isDelegatedController_ = true;
825 controller_ = controller;
826 }
827
GetOption() const828 const TweenOption& TweenElement::GetOption() const
829 {
830 return option_;
831 }
832
SetOption(const TweenOption & option)833 void TweenElement::SetOption(const TweenOption& option)
834 {
835 option_ = option;
836 }
837
GetController() const838 const RefPtr<Animator>& TweenElement::GetController() const
839 {
840 return controller_;
841 }
842
SetOpacity(uint8_t opacity)843 void TweenElement::SetOpacity(uint8_t opacity)
844 {
845 if (children_.empty()) {
846 LOGE("no child when set Opacity");
847 return;
848 }
849 const auto& child = children_.front();
850 if (!child) {
851 LOGE("child is null.");
852 return;
853 }
854 auto childElement = AceType::DynamicCast<RenderElement>(child);
855 if (!childElement) {
856 LOGE("child element is null.");
857 return;
858 }
859 const auto& displayRenderNode = AceType::DynamicCast<RenderDisplay>(childElement->GetRenderNode());
860 if (!displayRenderNode) {
861 LOGE("no display render node found.");
862 return;
863 }
864 displayRenderNode->UpdateOpacity(opacity);
865 }
866
SkipPostFlush()867 void TweenElement::SkipPostFlush()
868 {
869 skipPostFlush_ = true;
870 }
871
AddPreFlush()872 void TweenElement::AddPreFlush()
873 {
874 auto pipelineContext = context_.Upgrade();
875 if (!pipelineContext) {
876 return;
877 }
878 pipelineContext->AddPreFlushListener(AceType::Claim(this));
879 }
880
SetWrapHidden(bool hidden)881 void TweenElement::SetWrapHidden(bool hidden)
882 {
883 if (children_.empty()) {
884 LOGE("no child when set visible");
885 return;
886 }
887 const auto& child = children_.front();
888 if (!child) {
889 LOGE("child is null.");
890 return;
891 }
892 auto childElement = AceType::DynamicCast<RenderElement>(child);
893 if (!childElement) {
894 LOGE("child element is null.");
895 return;
896 }
897 const auto& displayRenderNode = AceType::DynamicCast<RenderDisplay>(childElement->GetRenderNode());
898 if (!displayRenderNode) {
899 LOGE("no display render node found.");
900 return;
901 }
902 displayRenderNode->UpdateHidden(hidden);
903 }
904
SetTouchable(bool enable)905 void TweenElement::SetTouchable(bool enable)
906 {
907 if (children_.empty()) {
908 LOGW("get content child failed. no child yet.");
909 return;
910 }
911 const auto& child = children_.front();
912 if (!child || child->GetType() != RENDER_ELEMENT) {
913 LOGW("get content child failed. null child or not render child.");
914 return;
915 }
916 const auto& transformElement = AceType::DynamicCast<RenderElement>(child)->GetFirstChild();
917 if (!transformElement) {
918 LOGE("Get RenderElement failed.");
919 return;
920 }
921 const auto& transformRenderNode = AceType::DynamicCast<RenderTransform>(transformElement->GetRenderNode());
922 if (transformRenderNode) {
923 transformRenderNode->SetTouchable(enable);
924 }
925 }
926
GetContentRender() const927 RefPtr<RenderNode> TweenElement::GetContentRender() const
928 {
929 auto contentElement = GetContentElement();
930 if (!contentElement) {
931 return nullptr;
932 }
933 return contentElement->GetRenderNode();
934 }
935
ApplyKeyframes()936 bool TweenElement::ApplyKeyframes()
937 {
938 return ApplyKeyframes(controller_, option_, prepareId_);
939 }
940
AddPrepareListener(RefPtr<Animator> & controller,const WeakPtr<RenderTransform> & weakTransform,BaseId::IdType & prepareId)941 void TweenElement::AddPrepareListener(
942 RefPtr<Animator>& controller, const WeakPtr<RenderTransform>& weakTransform, BaseId::IdType& prepareId)
943 {
944 if (!controller) {
945 LOGE("Add Prepare Listener failed. controller is null.");
946 return;
947 }
948 controller->RemovePrepareListener(prepareId);
949 prepareId =
950 controller->AddPrepareListener([weakTransform, weakContext = context_,
951 weakTween = AceType::WeakClaim(this),
952 needForceResetTransform =
953 controller->GetAllowRunningAsynchronously()]() {
954 // reset transform matrix at the start of every frame.
955 auto context = weakContext.Upgrade();
956 auto tween = weakTween.Upgrade();
957 auto transform = weakTransform.Upgrade();
958 if (context && tween && transform) {
959 auto currentTimestamp = context->GetTimeFromExternalTimer();
960 if (tween->currentTimestamp_ != currentTimestamp || tween->currentTimestamp_ == 0 ||
961 needForceResetTransform) {
962 transform->ResetTransform();
963 tween->currentTimestamp_ = currentTimestamp;
964 }
965 }
966 });
967 }
968
ApplyKeyframes(RefPtr<Animator> & controller,TweenOption & option,BaseId::IdType & prepareId)969 bool TweenElement::ApplyKeyframes(RefPtr<Animator>& controller, TweenOption& option, BaseId::IdType& prepareId)
970 {
971 if (!controller) {
972 LOGW("controller is null.");
973 return false;
974 }
975 if (children_.empty()) {
976 LOGW("apply option failed. no child yet.");
977 return false;
978 }
979 const auto& child = children_.front();
980 if (!child || child->GetType() != RENDER_ELEMENT) {
981 LOGW("apply option failed. null child or not render child.");
982 return false;
983 }
984 const auto& displayRenderNode =
985 AceType::DynamicCast<RenderDisplay>(AceType::DynamicCast<RenderElement>(child)->GetRenderNode());
986 if (!displayRenderNode) {
987 LOGE("display render node is null.");
988 return false;
989 }
990 const auto& transformElement = AceType::DynamicCast<RenderElement>(child)->GetFirstChild();
991 if (!transformElement) {
992 LOGE("transform element node is null.");
993 return false;
994 }
995 const auto& transformRenderNode = AceType::DynamicCast<RenderTransform>(transformElement->GetRenderNode());
996 if (!transformRenderNode) {
997 LOGE("transform render node is null.");
998 return false;
999 }
1000 if (shadow_.IsValid()) {
1001 displayRenderNode->SetShadow(shadow_);
1002 transformRenderNode->SetShadow(shadow_);
1003 }
1004
1005 const auto& contentElement = AceType::DynamicCast<RenderElement>(transformElement)->GetFirstChild();
1006 auto animatable = GetAnimatable(contentElement);
1007 if (animatable) {
1008 CreateColorAnimation(animatable, option);
1009 CreatePropertyAnimationFloat(animatable, option);
1010 }
1011 CreateTransformAnimation(transformRenderNode, transform_, option);
1012 CreateTranslateAnimation(transformRenderNode, option);
1013 CreateScaleAnimation(transformRenderNode, option);
1014 CreateRotateAnimation(transformRenderNode, option);
1015 CreateTransformOriginAnimation(transformRenderNode, option);
1016 if (option.HasTransformOffsetChanged() || option.HasTransformFloatChanged() || option.HasTransformChanged()) {
1017 AddPrepareListener(controller, transformRenderNode, prepareId);
1018 }
1019 CreateOpacityAnimation(displayRenderNode, display_, option);
1020 return IsNeedAnimation(controller, option);
1021 }
1022
ApplyOptions(RefPtr<Animator> & controller,TweenOption & option)1023 void TweenElement::ApplyOptions(RefPtr<Animator>& controller, TweenOption& option)
1024 {
1025 if (!controller) {
1026 LOGE("Apply Options failed. Controller is null.");
1027 return;
1028 }
1029 controller->SetDuration(option.GetDuration());
1030 controller->SetIteration(option.GetIteration());
1031 controller->SetStartDelay(option.GetDelay());
1032 controller->SetFillMode(option.GetFillMode());
1033 controller->SetTempo(option.GetTempo());
1034 controller->SetAnimationDirection(option.GetAnimationDirection());
1035 controller->SetAllowRunningAsynchronously(option.GetAllowRunningAsynchronously());
1036
1037 for (const auto& [type, animation] : option.GetAnimatables()) {
1038 if (option.GetCurve()) {
1039 animation->SetCurve(option.GetCurve());
1040 }
1041 controller->AddInterpolator(animation);
1042 }
1043 }
1044
ApplyOptions()1045 void TweenElement::ApplyOptions()
1046 {
1047 ApplyOptions(controller_, option_);
1048 }
1049
GetContentElement() const1050 RefPtr<Element> TweenElement::GetContentElement() const
1051 {
1052 const auto& mountParent = GetContentParent();
1053 if (!mountParent) {
1054 LOGE("Get content element failed. content parent is null.");
1055 return nullptr;
1056 }
1057 return mountParent->GetFirstChild();
1058 }
1059
GetContentParent() const1060 RefPtr<Element> TweenElement::GetContentParent() const
1061 {
1062 const auto child = GetFirstChild();
1063 if (!child) {
1064 LOGW("Get transformElement failed. null child.");
1065 return nullptr;
1066 }
1067 const auto& displayRenderNode =
1068 AceType::DynamicCast<RenderDisplay>(AceType::DynamicCast<RenderElement>(child)->GetRenderNode());
1069 if (!displayRenderNode) {
1070 LOGE("display render node is null.");
1071 return nullptr;
1072 }
1073 const auto& transformElement = AceType::DynamicCast<RenderElement>(child)->GetFirstChild();
1074 if (!transformElement) {
1075 LOGE("Get transformElement failed. transform element is null");
1076 return nullptr;
1077 }
1078 const auto& transformRenderNode = AceType::DynamicCast<RenderTransform>(transformElement->GetRenderNode());
1079 if (!transformRenderNode) {
1080 LOGE("Get transformElement failed. transform render node is null.");
1081 return nullptr;
1082 }
1083 return transformElement;
1084 }
1085
CreatePropertyAnimationFloat(const RefPtr<PropertyAnimatable> & animatable,TweenOption & option)1086 void TweenElement::CreatePropertyAnimationFloat(const RefPtr<PropertyAnimatable>& animatable, TweenOption& option)
1087 {
1088 if (!animatable) {
1089 LOGE("Create property animation for float failed. animatable is null.");
1090 return;
1091 }
1092 auto& propertyFloatMap = option.GetFloatPropertyAnimation();
1093 if (propertyFloatMap.empty()) {
1094 return;
1095 }
1096 for (auto&& [property, animation] : propertyFloatMap) {
1097 CreatePropertyAnimation<FloatPropertyAnimatable, float>(animatable, property, option, animation);
1098 }
1099 }
1100
1101 } // namespace OHOS::Ace
1102