18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "animation_state.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
198bf80f4bSopenharmony_ci#include <meta/api/util.h>
208bf80f4bSopenharmony_ci#include <meta/interface/animation/intf_animation_modifier.h>
218bf80f4bSopenharmony_ci#include <meta/interface/builtin_objects.h>
228bf80f4bSopenharmony_ci#include <meta/interface/interface_macros.h>
238bf80f4bSopenharmony_ci#include <meta/interface/intf_attachment_container.h>
248bf80f4bSopenharmony_ci#include <meta/interface/property/property_events.h>
258bf80f4bSopenharmony_ci
268bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_cinamespace Internal {
298bf80f4bSopenharmony_ci
308bf80f4bSopenharmony_cibool AnimationState::Initialize(AnimationStateParams&& params)
318bf80f4bSopenharmony_ci{
328bf80f4bSopenharmony_ci    params_ = BASE_NS::move(params);
338bf80f4bSopenharmony_ci    auto owner = GetOwner();
348bf80f4bSopenharmony_ci    if (!owner) {
358bf80f4bSopenharmony_ci        CORE_LOG_F("AnimationState: Invalid target animation");
368bf80f4bSopenharmony_ci        return false;
378bf80f4bSopenharmony_ci    }
388bf80f4bSopenharmony_ci    auto controllerProp = owner->Controller();
398bf80f4bSopenharmony_ci    if (!controllerProp) {
408bf80f4bSopenharmony_ci        return false;
418bf80f4bSopenharmony_ci    }
428bf80f4bSopenharmony_ci    if (!controllerProp->GetValue().lock()) {
438bf80f4bSopenharmony_ci        // No controller set, init to default
448bf80f4bSopenharmony_ci        controllerProp->SetValue(META_NS::GetAnimationController());
458bf80f4bSopenharmony_ci    }
468bf80f4bSopenharmony_ci
478bf80f4bSopenharmony_ci    updateTotalDuration_ = MakeCallback<IOnChanged>(this, &AnimationState::UpdateTotalDuration);
488bf80f4bSopenharmony_ci    if (auto timed = interface_cast<ITimedAnimation>(owner)) {
498bf80f4bSopenharmony_ci        timed->Duration()->OnChanged()->AddHandler(updateTotalDuration_, uintptr_t(this));
508bf80f4bSopenharmony_ci    }
518bf80f4bSopenharmony_ci
528bf80f4bSopenharmony_ci    auto updateController = MakeCallback<IOnChanged>(this, &AnimationState::UpdateController);
538bf80f4bSopenharmony_ci    controllerProp->OnChanged()->AddHandler(updateController);
548bf80f4bSopenharmony_ci    state_.clock_ = META_NS::GetObjectRegistry().Create<META_NS::IManualClock>(META_NS::ClassId::ManualClock);
558bf80f4bSopenharmony_ci    CORE_ASSERT(state_.clock_);
568bf80f4bSopenharmony_ci    UpdateTotalDuration();
578bf80f4bSopenharmony_ci    UpdateController();
588bf80f4bSopenharmony_ci    return true;
598bf80f4bSopenharmony_ci}
608bf80f4bSopenharmony_ci
618bf80f4bSopenharmony_civoid AnimationState::Uninitialize()
628bf80f4bSopenharmony_ci{
638bf80f4bSopenharmony_ci    if (auto timed = interface_pointer_cast<ITimedAnimation>(GetOwner())) {
648bf80f4bSopenharmony_ci        timed->Duration()->OnChanged()->RemoveHandler(uintptr_t(this));
658bf80f4bSopenharmony_ci    }
668bf80f4bSopenharmony_ci}
678bf80f4bSopenharmony_ci
688bf80f4bSopenharmony_civoid AnimationState::NotifyEvaluationNeeded() const
698bf80f4bSopenharmony_ci{
708bf80f4bSopenharmony_ci    if (auto internal = interface_pointer_cast<IAnimationInternal>(GetOwner())) {
718bf80f4bSopenharmony_ci        internal->OnEvaluationNeeded();
728bf80f4bSopenharmony_ci    }
738bf80f4bSopenharmony_ci}
748bf80f4bSopenharmony_ci
758bf80f4bSopenharmony_civoid AnimationState::NotifyStateChanged(const IAnimationInternal::AnimationStateChangedInfo& info) const
768bf80f4bSopenharmony_ci{
778bf80f4bSopenharmony_ci    if (auto internal = interface_pointer_cast<IAnimationInternal>(GetOwner())) {
788bf80f4bSopenharmony_ci        internal->OnAnimationStateChanged(info);
798bf80f4bSopenharmony_ci        // Need also evaluation
808bf80f4bSopenharmony_ci        internal->OnEvaluationNeeded();
818bf80f4bSopenharmony_ci    }
828bf80f4bSopenharmony_ci}
838bf80f4bSopenharmony_ci
848bf80f4bSopenharmony_civoid AnimationState::UpdateController()
858bf80f4bSopenharmony_ci{
868bf80f4bSopenharmony_ci    IAnimation::Ptr animation = GetOwner();
878bf80f4bSopenharmony_ci    if (!animation) {
888bf80f4bSopenharmony_ci        CORE_LOG_E("Invalid target animation");
898bf80f4bSopenharmony_ci        return;
908bf80f4bSopenharmony_ci    }
918bf80f4bSopenharmony_ci    auto oldController = controller_.lock();
928bf80f4bSopenharmony_ci    auto newController = animation->Controller()->GetValue().lock();
938bf80f4bSopenharmony_ci
948bf80f4bSopenharmony_ci    if (oldController != newController) {
958bf80f4bSopenharmony_ci        if (oldController) {
968bf80f4bSopenharmony_ci            oldController->RemoveAnimation(animation);
978bf80f4bSopenharmony_ci        }
988bf80f4bSopenharmony_ci        if (newController) {
998bf80f4bSopenharmony_ci            newController->AddAnimation(animation);
1008bf80f4bSopenharmony_ci        }
1018bf80f4bSopenharmony_ci        controller_ = newController;
1028bf80f4bSopenharmony_ci    }
1038bf80f4bSopenharmony_ci}
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_civoid AnimationState::ResetClock()
1068bf80f4bSopenharmony_ci{
1078bf80f4bSopenharmony_ci    state_.ResetLastTick();
1088bf80f4bSopenharmony_ci    state_.SetTime(TimeSpan::Zero());
1098bf80f4bSopenharmony_ci}
1108bf80f4bSopenharmony_ci
1118bf80f4bSopenharmony_ciAnimationState::StepStatus AnimationState::Step(const IClock::ConstPtr& clock)
1128bf80f4bSopenharmony_ci{
1138bf80f4bSopenharmony_ci    if (!IsRunning()) {
1148bf80f4bSopenharmony_ci        return {};
1158bf80f4bSopenharmony_ci    }
1168bf80f4bSopenharmony_ci
1178bf80f4bSopenharmony_ci    const auto time = clock ? clock->GetTime() : TimeSpan::Zero();
1188bf80f4bSopenharmony_ci    float progress = static_cast<float>(state_.Tick(time).ToMilliseconds()) /
1198bf80f4bSopenharmony_ci                     static_cast<float>(state_.GetBaseDuration().ToMilliseconds());
1208bf80f4bSopenharmony_ci
1218bf80f4bSopenharmony_ci    return Move(IAnimationInternal::MoveParams::FromProgress(progress));
1228bf80f4bSopenharmony_ci}
1238bf80f4bSopenharmony_ci
1248bf80f4bSopenharmony_ciconstexpr IAnimationInternal::AnimationTargetState GetTargetState(const IAnimationInternal::MoveParams& move) noexcept
1258bf80f4bSopenharmony_ci{
1268bf80f4bSopenharmony_ci    using AnimationTargetState = IAnimationInternal::AnimationTargetState;
1278bf80f4bSopenharmony_ci    const auto& step = move.step;
1288bf80f4bSopenharmony_ci    const auto& state = move.state;
1298bf80f4bSopenharmony_ci    if (state == AnimationTargetState::UNDEFINED) {
1308bf80f4bSopenharmony_ci        // Figure out target state based on step data automatically
1318bf80f4bSopenharmony_ci        const float progress = step.progress;
1328bf80f4bSopenharmony_ci        const bool reverse = step.reverse;
1338bf80f4bSopenharmony_ci        if (progress >= 1.f) {
1348bf80f4bSopenharmony_ci            return reverse ? AnimationTargetState::RUNNING : AnimationTargetState::FINISHED;
1358bf80f4bSopenharmony_ci        }
1368bf80f4bSopenharmony_ci        if (progress <= 0.f) {
1378bf80f4bSopenharmony_ci            return reverse ? AnimationTargetState::FINISHED : AnimationTargetState::RUNNING;
1388bf80f4bSopenharmony_ci        }
1398bf80f4bSopenharmony_ci        return AnimationTargetState::RUNNING;
1408bf80f4bSopenharmony_ci    }
1418bf80f4bSopenharmony_ci
1428bf80f4bSopenharmony_ci    // Just go to the state defined by the caller
1438bf80f4bSopenharmony_ci    return state;
1448bf80f4bSopenharmony_ci}
1458bf80f4bSopenharmony_ci
1468bf80f4bSopenharmony_ciAnimationState::StepStatus AnimationState::Move(const IAnimationInternal::MoveParams& move)
1478bf80f4bSopenharmony_ci{
1488bf80f4bSopenharmony_ci    using AnimationTargetState = IAnimationInternal::AnimationTargetState;
1498bf80f4bSopenharmony_ci    auto animationState = GetTargetState(move);
1508bf80f4bSopenharmony_ci    const auto& step = move.step;
1518bf80f4bSopenharmony_ci    float progress = step.progress;
1528bf80f4bSopenharmony_ci
1538bf80f4bSopenharmony_ci    if (state_.shouldInit_) {
1548bf80f4bSopenharmony_ci        state_.loops = state_.duration.loopCount;
1558bf80f4bSopenharmony_ci        state_.shouldInit_ = false;
1568bf80f4bSopenharmony_ci    }
1578bf80f4bSopenharmony_ci
1588bf80f4bSopenharmony_ci    if (animationState == AnimationTargetState::FINISHED) {
1598bf80f4bSopenharmony_ci        // Check if we need to loop
1608bf80f4bSopenharmony_ci        if (state_.loops && (state_.loops < 0 || --state_.loops)) {
1618bf80f4bSopenharmony_ci            animationState = AnimationTargetState::RUNNING;
1628bf80f4bSopenharmony_ci            const auto overflow = progress - BASE_NS::Math::floor(progress);
1638bf80f4bSopenharmony_ci            state_.SetTime(overflow * state_.GetBaseDuration());
1648bf80f4bSopenharmony_ci            if (overflow > 0.f) {
1658bf80f4bSopenharmony_ci                // If progress based on clock would be e.g. 1.2, jump to 0.2 to not jank the animation
1668bf80f4bSopenharmony_ci                progress = overflow;
1678bf80f4bSopenharmony_ci            }
1688bf80f4bSopenharmony_ci        }
1698bf80f4bSopenharmony_ci    }
1708bf80f4bSopenharmony_ci
1718bf80f4bSopenharmony_ci    AnimationState::StepStatus status;
1728bf80f4bSopenharmony_ci    if (progress = BASE_NS::Math::clamp01(progress); progress != GetProgress()) {
1738bf80f4bSopenharmony_ci        SetProgress(progress);
1748bf80f4bSopenharmony_ci        status.changed = true;
1758bf80f4bSopenharmony_ci    }
1768bf80f4bSopenharmony_ci
1778bf80f4bSopenharmony_ci    status.changed |= SetState(animationState);
1788bf80f4bSopenharmony_ci    status.state = state_.animationState_;
1798bf80f4bSopenharmony_ci    status.progress = GetProgress();
1808bf80f4bSopenharmony_ci    if (status.changed) {
1818bf80f4bSopenharmony_ci        NotifyEvaluationNeeded();
1828bf80f4bSopenharmony_ci    }
1838bf80f4bSopenharmony_ci    return status;
1848bf80f4bSopenharmony_ci}
1858bf80f4bSopenharmony_ci
1868bf80f4bSopenharmony_civoid AnimationState::Seek(float position)
1878bf80f4bSopenharmony_ci{
1888bf80f4bSopenharmony_ci    auto animation = GetOwner();
1898bf80f4bSopenharmony_ci    if (!animation) {
1908bf80f4bSopenharmony_ci        CORE_LOG_E("Invalid target animation");
1918bf80f4bSopenharmony_ci        return;
1928bf80f4bSopenharmony_ci    }
1938bf80f4bSopenharmony_ci
1948bf80f4bSopenharmony_ci    position = BASE_NS::Math::clamp01(position);
1958bf80f4bSopenharmony_ci    state_.ResetLastTick();
1968bf80f4bSopenharmony_ci    const auto seekedTime = state_.GetBaseDuration().ToSecondsFloat() * position;
1978bf80f4bSopenharmony_ci    state_.SetTime(TimeSpan::Seconds(seekedTime));
1988bf80f4bSopenharmony_ci    auto state = state_.animationState_;
1998bf80f4bSopenharmony_ci    if (position >= 1.f) {
2008bf80f4bSopenharmony_ci        state = IAnimationInternal::AnimationTargetState::FINISHED;
2018bf80f4bSopenharmony_ci    }
2028bf80f4bSopenharmony_ci    Move(IAnimationInternal::MoveParams::FromProgress(position, state));
2038bf80f4bSopenharmony_ci}
2048bf80f4bSopenharmony_ci
2058bf80f4bSopenharmony_cibool AnimationState::Pause()
2068bf80f4bSopenharmony_ci{
2078bf80f4bSopenharmony_ci    return SetState(IAnimationInternal::AnimationTargetState::PAUSED);
2088bf80f4bSopenharmony_ci}
2098bf80f4bSopenharmony_ci
2108bf80f4bSopenharmony_cibool AnimationState::Start()
2118bf80f4bSopenharmony_ci{
2128bf80f4bSopenharmony_ci    return SetState(IAnimationInternal::AnimationTargetState::RUNNING);
2138bf80f4bSopenharmony_ci}
2148bf80f4bSopenharmony_ci
2158bf80f4bSopenharmony_cibool AnimationState::Stop()
2168bf80f4bSopenharmony_ci{
2178bf80f4bSopenharmony_ci    return Move(IAnimationInternal::MoveParams::FromProgress(0.f, IAnimationInternal::AnimationTargetState::STOPPED))
2188bf80f4bSopenharmony_ci        .StatusChanged();
2198bf80f4bSopenharmony_ci}
2208bf80f4bSopenharmony_ci
2218bf80f4bSopenharmony_cibool AnimationState::Finish()
2228bf80f4bSopenharmony_ci{
2238bf80f4bSopenharmony_ci    return Move(IAnimationInternal::MoveParams::FromProgress(1.f, IAnimationInternal::AnimationTargetState::FINISHED))
2248bf80f4bSopenharmony_ci        .StatusChanged();
2258bf80f4bSopenharmony_ci}
2268bf80f4bSopenharmony_ci
2278bf80f4bSopenharmony_cibool AnimationState::Restart()
2288bf80f4bSopenharmony_ci{
2298bf80f4bSopenharmony_ci    if (Stop()) {
2308bf80f4bSopenharmony_ci        return Start();
2318bf80f4bSopenharmony_ci    }
2328bf80f4bSopenharmony_ci    return false;
2338bf80f4bSopenharmony_ci}
2348bf80f4bSopenharmony_ci
2358bf80f4bSopenharmony_ciIAnimation::Ptr AnimationState::GetOwner() const noexcept
2368bf80f4bSopenharmony_ci{
2378bf80f4bSopenharmony_ci    return params_.owner.lock();
2388bf80f4bSopenharmony_ci}
2398bf80f4bSopenharmony_ci
2408bf80f4bSopenharmony_cibool AnimationState::IsRunning() const noexcept
2418bf80f4bSopenharmony_ci{
2428bf80f4bSopenharmony_ci    return GetValue(params_.runningProperty, false);
2438bf80f4bSopenharmony_ci}
2448bf80f4bSopenharmony_ci
2458bf80f4bSopenharmony_cibool AnimationState::IsPaused() const noexcept
2468bf80f4bSopenharmony_ci{
2478bf80f4bSopenharmony_ci    return state_.animationState_ == IAnimationInternal::AnimationTargetState::PAUSED;
2488bf80f4bSopenharmony_ci}
2498bf80f4bSopenharmony_ci
2508bf80f4bSopenharmony_civoid AnimationState::SetRunning(bool running) noexcept
2518bf80f4bSopenharmony_ci{
2528bf80f4bSopenharmony_ci    SetValue(params_.runningProperty, running);
2538bf80f4bSopenharmony_ci}
2548bf80f4bSopenharmony_ci
2558bf80f4bSopenharmony_cifloat AnimationState::GetProgress() const noexcept
2568bf80f4bSopenharmony_ci{
2578bf80f4bSopenharmony_ci    return GetValue(params_.progressProperty, 0.f);
2588bf80f4bSopenharmony_ci}
2598bf80f4bSopenharmony_ci
2608bf80f4bSopenharmony_civoid AnimationState::SetProgress(float progress) noexcept
2618bf80f4bSopenharmony_ci{
2628bf80f4bSopenharmony_ci    SetValue(params_.progressProperty, progress);
2638bf80f4bSopenharmony_ci}
2648bf80f4bSopenharmony_ci
2658bf80f4bSopenharmony_cibool AnimationState::SetState(IAnimationInternal::AnimationTargetState state)
2668bf80f4bSopenharmony_ci{
2678bf80f4bSopenharmony_ci    using AnimationTargetState = IAnimationInternal::AnimationTargetState;
2688bf80f4bSopenharmony_ci    const auto previous = state_.animationState_;
2698bf80f4bSopenharmony_ci    if (previous == state) {
2708bf80f4bSopenharmony_ci        return false;
2718bf80f4bSopenharmony_ci    }
2728bf80f4bSopenharmony_ci    if (const auto owner = GetOwner()) {
2738bf80f4bSopenharmony_ci        bool notifyStarted = false;
2748bf80f4bSopenharmony_ci        switch (state) {
2758bf80f4bSopenharmony_ci            case AnimationTargetState::RUNNING:
2768bf80f4bSopenharmony_ci                if (previous != AnimationTargetState::PAUSED) {
2778bf80f4bSopenharmony_ci                    state_.shouldInit_ = true;
2788bf80f4bSopenharmony_ci                    notifyStarted = true;
2798bf80f4bSopenharmony_ci                    if (previous == AnimationTargetState::FINISHED) {
2808bf80f4bSopenharmony_ci                        SetProgress(0.f);
2818bf80f4bSopenharmony_ci                        ResetClock();
2828bf80f4bSopenharmony_ci                    }
2838bf80f4bSopenharmony_ci                }
2848bf80f4bSopenharmony_ci                break;
2858bf80f4bSopenharmony_ci            case AnimationTargetState::PAUSED:
2868bf80f4bSopenharmony_ci                state_.ResetLastTick();
2878bf80f4bSopenharmony_ci                break;
2888bf80f4bSopenharmony_ci            case AnimationTargetState::FINISHED:
2898bf80f4bSopenharmony_ci                [[fallthrough]];
2908bf80f4bSopenharmony_ci            case AnimationTargetState::STOPPED:
2918bf80f4bSopenharmony_ci                ResetClock();
2928bf80f4bSopenharmony_ci                break;
2938bf80f4bSopenharmony_ci            default:
2948bf80f4bSopenharmony_ci                CORE_LOG_E("Invalid target state for animation: AnimationTargetState::UNDEFINED");
2958bf80f4bSopenharmony_ci                ResetClock();
2968bf80f4bSopenharmony_ci                break;
2978bf80f4bSopenharmony_ci        }
2988bf80f4bSopenharmony_ci        SetRunning(state == AnimationTargetState::RUNNING);
2998bf80f4bSopenharmony_ci
3008bf80f4bSopenharmony_ci        state_.animationState_ = state;
3018bf80f4bSopenharmony_ci        IAnimationInternal::AnimationStateChangedInfo info;
3028bf80f4bSopenharmony_ci        info.source = GetOwner();
3038bf80f4bSopenharmony_ci        info.state = state;
3048bf80f4bSopenharmony_ci        info.previous = previous;
3058bf80f4bSopenharmony_ci        NotifyStateChanged(info);
3068bf80f4bSopenharmony_ci
3078bf80f4bSopenharmony_ci        if (state == AnimationTargetState::FINISHED) {
3088bf80f4bSopenharmony_ci            Invoke<IOnChanged>(owner->OnFinished());
3098bf80f4bSopenharmony_ci        }
3108bf80f4bSopenharmony_ci        if (notifyStarted) {
3118bf80f4bSopenharmony_ci            Invoke<IOnChanged>(owner->OnStarted());
3128bf80f4bSopenharmony_ci        }
3138bf80f4bSopenharmony_ci        return true;
3148bf80f4bSopenharmony_ci    }
3158bf80f4bSopenharmony_ci    return false;
3168bf80f4bSopenharmony_ci}
3178bf80f4bSopenharmony_ci
3188bf80f4bSopenharmony_ciBASE_NS::vector<IAnimationModifier::Ptr> AnimationState::GetModifiers() const
3198bf80f4bSopenharmony_ci{
3208bf80f4bSopenharmony_ci    if (!modifierCache_.HasTarget()) {
3218bf80f4bSopenharmony_ci        // Do not create an attachment container unless one has already been created by someone
3228bf80f4bSopenharmony_ci        if (const auto attach = interface_pointer_cast<IAttach>(params_.owner)) {
3238bf80f4bSopenharmony_ci            if (const auto container = attach->GetAttachmentContainer(false)) {
3248bf80f4bSopenharmony_ci                modifierCache_.SetTarget(
3258bf80f4bSopenharmony_ci                    container, { "", TraversalType::NO_HIERARCHY, { IAnimationModifier::UID }, true });
3268bf80f4bSopenharmony_ci            }
3278bf80f4bSopenharmony_ci        }
3288bf80f4bSopenharmony_ci    }
3298bf80f4bSopenharmony_ci
3308bf80f4bSopenharmony_ci    return modifierCache_.FindAll();
3318bf80f4bSopenharmony_ci}
3328bf80f4bSopenharmony_ci
3338bf80f4bSopenharmony_ciIAnimationModifier::StepData AnimationState::ApplyStepModifiers(float progress) const
3348bf80f4bSopenharmony_ci{
3358bf80f4bSopenharmony_ci    IAnimationModifier::StepData step(progress);
3368bf80f4bSopenharmony_ci    for (auto&& mod : GetModifiers()) {
3378bf80f4bSopenharmony_ci        mod->ProcessOnStep(step);
3388bf80f4bSopenharmony_ci    }
3398bf80f4bSopenharmony_ci    return step;
3408bf80f4bSopenharmony_ci}
3418bf80f4bSopenharmony_ci
3428bf80f4bSopenharmony_ciIAnimationModifier::DurationData AnimationState::ApplyDurationModifiers(TimeSpan duration) const
3438bf80f4bSopenharmony_ci{
3448bf80f4bSopenharmony_ci    using DurationData = IAnimationModifier::DurationData;
3458bf80f4bSopenharmony_ci    DurationData durationData;
3468bf80f4bSopenharmony_ci    durationData.duration = duration;
3478bf80f4bSopenharmony_ci    for (auto&& mod : GetModifiers()) {
3488bf80f4bSopenharmony_ci        DurationData data = durationData;
3498bf80f4bSopenharmony_ci        if (mod->ProcessOnGetDuration(data)) {
3508bf80f4bSopenharmony_ci            durationData = data;
3518bf80f4bSopenharmony_ci        }
3528bf80f4bSopenharmony_ci    }
3538bf80f4bSopenharmony_ci    return durationData;
3548bf80f4bSopenharmony_ci}
3558bf80f4bSopenharmony_ci
3568bf80f4bSopenharmony_ciTimeSpan AnimationState::GetAnimationBaseDuration() const
3578bf80f4bSopenharmony_ci{
3588bf80f4bSopenharmony_ci    if (auto timed = interface_cast<ITimedAnimation>(GetOwner())) {
3598bf80f4bSopenharmony_ci        return GetValue(timed->Duration());
3608bf80f4bSopenharmony_ci    }
3618bf80f4bSopenharmony_ci    CORE_LOG_W("Cannot update total duration of an animation that does not implement ITimedAnimation");
3628bf80f4bSopenharmony_ci    return TimeSpan::Zero();
3638bf80f4bSopenharmony_ci}
3648bf80f4bSopenharmony_ci
3658bf80f4bSopenharmony_civoid AnimationState::UpdateTotalDuration()
3668bf80f4bSopenharmony_ci{
3678bf80f4bSopenharmony_ci    if (!params_.totalDuration) {
3688bf80f4bSopenharmony_ci        return;
3698bf80f4bSopenharmony_ci    }
3708bf80f4bSopenharmony_ci    auto durationData = ApplyDurationModifiers(GetAnimationBaseDuration());
3718bf80f4bSopenharmony_ci    state_.duration = durationData;
3728bf80f4bSopenharmony_ci    state_.totalDuration =
3738bf80f4bSopenharmony_ci        durationData.loopCount > 0 ? durationData.duration * durationData.loopCount : TimeSpan::Infinite();
3748bf80f4bSopenharmony_ci    SetValue(params_.totalDuration, state_.totalDuration);
3758bf80f4bSopenharmony_ci}
3768bf80f4bSopenharmony_ci
3778bf80f4bSopenharmony_cibool AnimationState::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
3788bf80f4bSopenharmony_ci{
3798bf80f4bSopenharmony_ci    bool success = false;
3808bf80f4bSopenharmony_ci    if (auto attach = interface_pointer_cast<IAttach>(params_.owner)) {
3818bf80f4bSopenharmony_ci        if (const auto attachments = interface_cast<IAttachmentContainer>(attach->GetAttachmentContainer(true))) {
3828bf80f4bSopenharmony_ci            if (const auto modifier = interface_cast<IAnimationModifier>(attachment)) {
3838bf80f4bSopenharmony_ci                if (success = attachments->Attach(attachment, dataContext); success) {
3848bf80f4bSopenharmony_ci                    if (auto notifyChanged = interface_cast<INotifyOnChange>(modifier)) {
3858bf80f4bSopenharmony_ci                        notifyChanged->OnChanged()->AddHandler(updateTotalDuration_, uintptr_t(this));
3868bf80f4bSopenharmony_ci                    }
3878bf80f4bSopenharmony_ci                }
3888bf80f4bSopenharmony_ci                UpdateTotalDuration();
3898bf80f4bSopenharmony_ci            } else {
3908bf80f4bSopenharmony_ci                // Attaching something else than a modifier
3918bf80f4bSopenharmony_ci                return attachments->Attach(attachment, dataContext);
3928bf80f4bSopenharmony_ci            }
3938bf80f4bSopenharmony_ci        }
3948bf80f4bSopenharmony_ci    }
3958bf80f4bSopenharmony_ci    return success;
3968bf80f4bSopenharmony_ci}
3978bf80f4bSopenharmony_ci
3988bf80f4bSopenharmony_cibool AnimationState::Detach(const IObject::Ptr& attachment)
3998bf80f4bSopenharmony_ci{
4008bf80f4bSopenharmony_ci    bool success = false;
4018bf80f4bSopenharmony_ci    if (auto attach = interface_pointer_cast<IAttach>(params_.owner)) {
4028bf80f4bSopenharmony_ci        success = attach->Detach(attachment);
4038bf80f4bSopenharmony_ci        if (const auto modifier = interface_cast<IAnimationModifier>(attachment)) {
4048bf80f4bSopenharmony_ci            if (auto notifyChanged = interface_cast<INotifyOnChange>(modifier)) {
4058bf80f4bSopenharmony_ci                notifyChanged->OnChanged()->RemoveHandler(uintptr_t(this));
4068bf80f4bSopenharmony_ci            }
4078bf80f4bSopenharmony_ci        }
4088bf80f4bSopenharmony_ci        UpdateTotalDuration();
4098bf80f4bSopenharmony_ci    }
4108bf80f4bSopenharmony_ci    return success;
4118bf80f4bSopenharmony_ci}
4128bf80f4bSopenharmony_ci
4138bf80f4bSopenharmony_ci// PropertyAnimationState
4148bf80f4bSopenharmony_ci
4158bf80f4bSopenharmony_ciIInterpolator::Ptr PropertyAnimationState::GetInterpolator() const
4168bf80f4bSopenharmony_ci{
4178bf80f4bSopenharmony_ci    return interpolator_;
4188bf80f4bSopenharmony_ci}
4198bf80f4bSopenharmony_ci
4208bf80f4bSopenharmony_cibool PropertyAnimationState::SetInterpolator(const TypeId& id)
4218bf80f4bSopenharmony_ci{
4228bf80f4bSopenharmony_ci    interpolator_ = id != TypeId {} ? GetObjectRegistry().CreateInterpolator(id) : nullptr;
4238bf80f4bSopenharmony_ci    return interpolator_ != nullptr;
4248bf80f4bSopenharmony_ci}
4258bf80f4bSopenharmony_ci
4268bf80f4bSopenharmony_ciAnyReturnValue PropertyAnimationState::EvaluateValue(const EvaluationData& data) const
4278bf80f4bSopenharmony_ci{
4288bf80f4bSopenharmony_ci    if (!data.IsValid()) {
4298bf80f4bSopenharmony_ci        return AnyReturn::FAIL;
4308bf80f4bSopenharmony_ci    }
4318bf80f4bSopenharmony_ci
4328bf80f4bSopenharmony_ci    auto step = ApplyStepModifiers(data.progress);
4338bf80f4bSopenharmony_ci    auto progress = step.progress;
4348bf80f4bSopenharmony_ci
4358bf80f4bSopenharmony_ci    if (progress <= 0.f) {
4368bf80f4bSopenharmony_ci        return data.target->CopyFrom(*data.from);
4378bf80f4bSopenharmony_ci    }
4388bf80f4bSopenharmony_ci    if (progress >= 1.f) {
4398bf80f4bSopenharmony_ci        return data.target->CopyFrom(*data.to);
4408bf80f4bSopenharmony_ci    }
4418bf80f4bSopenharmony_ci    if (data.curve) {
4428bf80f4bSopenharmony_ci        progress = data.curve->Transform(progress);
4438bf80f4bSopenharmony_ci    }
4448bf80f4bSopenharmony_ci    if (interpolator_) {
4458bf80f4bSopenharmony_ci        return interpolator_->Interpolate(*data.target, *data.from, *data.to, progress);
4468bf80f4bSopenharmony_ci    }
4478bf80f4bSopenharmony_ci    CORE_LOG_W("No interpolator set for animation state");
4488bf80f4bSopenharmony_ci    return AnyReturn::FAIL;
4498bf80f4bSopenharmony_ci}
4508bf80f4bSopenharmony_ci
4518bf80f4bSopenharmony_ci} // namespace Internal
4528bf80f4bSopenharmony_ci
4538bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
454