Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Side by Side Diff: cc/animation/element_animations_unittest.cc

Issue 1987123002: cc : Track transform animation changes on transform tree (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/animation/element_animations.cc ('k') | cc/layers/layer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/animation/element_animations.h" 5 #include "cc/animation/element_animations.h"
6 6
7 #include "cc/animation/animation_delegate.h" 7 #include "cc/animation/animation_delegate.h"
8 #include "cc/animation/animation_host.h" 8 #include "cc/animation/animation_host.h"
9 #include "cc/animation/animation_id_provider.h" 9 #include "cc/animation/animation_id_provider.h"
10 #include "cc/animation/animation_player.h" 10 #include "cc/animation/animation_player.h"
(...skipping 2760 matching lines...) Expand 10 before | Expand all | Expand 10 after
2771 2771
2772 animations_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); 2772 animations_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
2773 2773
2774 // Both elements should have been ticked. 2774 // Both elements should have been ticked.
2775 EXPECT_EQ(0.75f, 2775 EXPECT_EQ(0.75f,
2776 client_impl_.GetOpacity(element_id_, ElementListType::PENDING)); 2776 client_impl_.GetOpacity(element_id_, ElementListType::PENDING));
2777 EXPECT_EQ(0.75f, 2777 EXPECT_EQ(0.75f,
2778 client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE)); 2778 client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE));
2779 } 2779 }
2780 2780
2781 TEST_F(ElementAnimationsTest, 2781 TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) {
2782 ObserverNotifiedWhenTransformIsPotentiallyAnimatingChanges) {
2783 CreateTestLayer(true, true); 2782 CreateTestLayer(true, true);
2784 AttachTimelinePlayerLayer(); 2783 AttachTimelinePlayerLayer();
2785 CreateImplTimelineAndPlayer(); 2784 CreateImplTimelineAndPlayer();
2786 2785
2787 scoped_refptr<ElementAnimations> animations = element_animations(); 2786 scoped_refptr<ElementAnimations> animations = element_animations();
2788 scoped_refptr<ElementAnimations> animations_impl = element_animations_impl(); 2787 scoped_refptr<ElementAnimations> animations_impl = element_animations_impl();
2789 2788
2790 auto events = host_impl_->CreateEvents(); 2789 auto events = host_impl_->CreateEvents();
2791 2790
2792 EXPECT_FALSE( 2791 EXPECT_FALSE(client_.GetHasPotentialTransformAnimation(
2793 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2792 element_id_, ElementListType::ACTIVE));
2794 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2793 EXPECT_FALSE(client_.GetTransformIsCurrentlyAnimating(
2795 ElementListType::PENDING)); 2794 element_id_, ElementListType::ACTIVE));
2796 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2795 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2797 ElementListType::ACTIVE)); 2796 element_id_, ElementListType::PENDING));
2797 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2798 element_id_, ElementListType::PENDING));
2799 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2800 element_id_, ElementListType::ACTIVE));
2801 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2802 element_id_, ElementListType::ACTIVE));
2798 2803
2799 // Case 1: An animation that's allowed to run until its finish point. 2804 // Case 1: An animation that's allowed to run until its finish point.
2800 AddAnimatedTransformToElementAnimations(animations.get(), 1.0, 1, 1); 2805 AddAnimatedTransformToElementAnimations(animations.get(), 1.0, 1, 1);
2801 EXPECT_TRUE( 2806 EXPECT_TRUE(client_.GetHasPotentialTransformAnimation(
2802 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2807 element_id_, ElementListType::ACTIVE));
2808 EXPECT_TRUE(client_.GetTransformIsCurrentlyAnimating(
2809 element_id_, ElementListType::ACTIVE));
2803 2810
2804 animations->PushPropertiesTo(animations_impl.get()); 2811 animations->PushPropertiesTo(animations_impl.get());
2805 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2812 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2806 ElementListType::PENDING)); 2813 element_id_, ElementListType::PENDING));
2807 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2814 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2808 ElementListType::ACTIVE)); 2815 element_id_, ElementListType::PENDING));
2816 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2817 element_id_, ElementListType::ACTIVE));
2818 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2819 element_id_, ElementListType::ACTIVE));
2809 2820
2810 animations_impl->ActivateAnimations(); 2821 animations_impl->ActivateAnimations();
2811 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2822 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2812 ElementListType::PENDING)); 2823 element_id_, ElementListType::PENDING));
2813 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2824 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2814 ElementListType::ACTIVE)); 2825 element_id_, ElementListType::PENDING));
2826 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2827 element_id_, ElementListType::ACTIVE));
2828 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2829 element_id_, ElementListType::ACTIVE));
2815 2830
2816 animations_impl->Animate(kInitialTickTime); 2831 animations_impl->Animate(kInitialTickTime);
2817 animations_impl->UpdateState(true, events.get()); 2832 animations_impl->UpdateState(true, events.get());
2818 2833
2819 animations->NotifyAnimationStarted(events->events_[0]); 2834 animations->NotifyAnimationStarted(events->events_[0]);
2820 events->events_.clear(); 2835 events->events_.clear();
2821 2836
2822 // Finish the animation. 2837 // Finish the animation.
2823 animations->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); 2838 animations->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
2824 animations->UpdateState(true, nullptr); 2839 animations->UpdateState(true, nullptr);
2825 EXPECT_FALSE( 2840 EXPECT_FALSE(client_.GetHasPotentialTransformAnimation(
2826 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2841 element_id_, ElementListType::ACTIVE));
2842 EXPECT_FALSE(client_.GetTransformIsCurrentlyAnimating(
2843 element_id_, ElementListType::ACTIVE));
2827 2844
2828 animations->PushPropertiesTo(animations_impl.get()); 2845 animations->PushPropertiesTo(animations_impl.get());
2829 2846
2830 // animations_impl hasn't yet ticked at/past the end of the animation. 2847 // animations_impl hasn't yet ticked at/past the end of the animation.
2831 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2848 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2832 ElementListType::PENDING)); 2849 element_id_, ElementListType::PENDING));
2833 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2850 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2834 ElementListType::ACTIVE)); 2851 element_id_, ElementListType::PENDING));
2852 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2853 element_id_, ElementListType::ACTIVE));
2854 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2855 element_id_, ElementListType::ACTIVE));
2835 2856
2836 animations_impl->Animate(kInitialTickTime + 2857 animations_impl->Animate(kInitialTickTime +
2837 TimeDelta::FromMilliseconds(1000)); 2858 TimeDelta::FromMilliseconds(1000));
2838 animations_impl->UpdateState(true, events.get()); 2859 animations_impl->UpdateState(true, events.get());
2839 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2860 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2840 ElementListType::PENDING)); 2861 element_id_, ElementListType::PENDING));
2841 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2862 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2842 ElementListType::ACTIVE)); 2863 element_id_, ElementListType::PENDING));
2843 2864 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2844 animations->NotifyAnimationFinished(events->events_[0]); 2865 element_id_, ElementListType::ACTIVE));
2845 events->events_.clear(); 2866 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2867 element_id_, ElementListType::ACTIVE));
2846 2868
2847 // Case 2: An animation that's removed before it finishes. 2869 // Case 2: An animation that's removed before it finishes.
2848 int animation_id = 2870 int animation_id =
2849 AddAnimatedTransformToElementAnimations(animations.get(), 10.0, 2, 2); 2871 AddAnimatedTransformToElementAnimations(animations.get(), 10.0, 2, 2);
2850 EXPECT_TRUE( 2872 EXPECT_TRUE(client_.GetHasPotentialTransformAnimation(
2851 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2873 element_id_, ElementListType::ACTIVE));
2874 EXPECT_TRUE(client_.GetTransformIsCurrentlyAnimating(
2875 element_id_, ElementListType::ACTIVE));
2852 2876
2853 animations->PushPropertiesTo(animations_impl.get()); 2877 animations->PushPropertiesTo(animations_impl.get());
2854 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2878 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2855 ElementListType::PENDING)); 2879 element_id_, ElementListType::PENDING));
2856 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2880 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2857 ElementListType::ACTIVE)); 2881 element_id_, ElementListType::PENDING));
2882 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2883 element_id_, ElementListType::ACTIVE));
2884 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2885 element_id_, ElementListType::ACTIVE));
2858 2886
2859 animations_impl->ActivateAnimations(); 2887 animations_impl->ActivateAnimations();
2860 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2888 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2861 ElementListType::PENDING)); 2889 element_id_, ElementListType::ACTIVE));
2862 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2890 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2863 ElementListType::ACTIVE)); 2891 element_id_, ElementListType::ACTIVE));
2864 2892
2865 animations_impl->Animate(kInitialTickTime + 2893 animations_impl->Animate(kInitialTickTime +
2866 TimeDelta::FromMilliseconds(2000)); 2894 TimeDelta::FromMilliseconds(2000));
2867 animations_impl->UpdateState(true, events.get()); 2895 animations_impl->UpdateState(true, events.get());
2868 2896
2869 animations->NotifyAnimationStarted(events->events_[0]); 2897 animations->NotifyAnimationStarted(events->events_[0]);
2870 events->events_.clear(); 2898 events->events_.clear();
2871 2899
2872 animations->RemoveAnimation(animation_id); 2900 animations->RemoveAnimation(animation_id);
2873 EXPECT_FALSE( 2901 EXPECT_FALSE(client_.GetHasPotentialTransformAnimation(
2874 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2902 element_id_, ElementListType::ACTIVE));
2903 EXPECT_FALSE(client_.GetTransformIsCurrentlyAnimating(
2904 element_id_, ElementListType::ACTIVE));
2875 2905
2876 animations->PushPropertiesTo(animations_impl.get()); 2906 animations->PushPropertiesTo(animations_impl.get());
2877 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2907 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2878 ElementListType::PENDING)); 2908 element_id_, ElementListType::PENDING));
2879 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2909 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2880 ElementListType::ACTIVE)); 2910 element_id_, ElementListType::PENDING));
2911 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2912 element_id_, ElementListType::ACTIVE));
2913 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2914 element_id_, ElementListType::ACTIVE));
2881 2915
2882 animations_impl->ActivateAnimations(); 2916 animations_impl->ActivateAnimations();
2883 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2917 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2884 ElementListType::PENDING)); 2918 element_id_, ElementListType::ACTIVE));
2885 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2919 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2886 ElementListType::ACTIVE)); 2920 element_id_, ElementListType::ACTIVE));
2887 2921
2888 // Case 3: An animation that's aborted before it finishes. 2922 // Case 3: An animation that's aborted before it finishes.
2889 animation_id = 2923 animation_id =
2890 AddAnimatedTransformToElementAnimations(animations.get(), 10.0, 3, 3); 2924 AddAnimatedTransformToElementAnimations(animations.get(), 10.0, 3, 3);
2891 EXPECT_TRUE( 2925 EXPECT_TRUE(client_.GetHasPotentialTransformAnimation(
2892 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2926 element_id_, ElementListType::ACTIVE));
2927 EXPECT_TRUE(client_.GetTransformIsCurrentlyAnimating(
2928 element_id_, ElementListType::ACTIVE));
2893 2929
2894 animations->PushPropertiesTo(animations_impl.get()); 2930 animations->PushPropertiesTo(animations_impl.get());
2895 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2931 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2896 ElementListType::PENDING)); 2932 element_id_, ElementListType::PENDING));
2897 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2933 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2898 ElementListType::ACTIVE)); 2934 element_id_, ElementListType::PENDING));
2935 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2936 element_id_, ElementListType::ACTIVE));
2937 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2938 element_id_, ElementListType::ACTIVE));
2899 2939
2900 animations_impl->ActivateAnimations(); 2940 animations_impl->ActivateAnimations();
2901 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2941 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2902 ElementListType::PENDING)); 2942 element_id_, ElementListType::ACTIVE));
2903 EXPECT_TRUE(client_impl_.GetTransformIsAnimating(element_id_, 2943 EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
2904 ElementListType::ACTIVE)); 2944 element_id_, ElementListType::ACTIVE));
2905 2945
2906 animations_impl->Animate(kInitialTickTime + 2946 animations_impl->Animate(kInitialTickTime +
2907 TimeDelta::FromMilliseconds(3000)); 2947 TimeDelta::FromMilliseconds(2000));
2908 animations_impl->UpdateState(true, events.get()); 2948 animations_impl->UpdateState(true, events.get());
2909 2949
2910 animations->NotifyAnimationStarted(events->events_[0]); 2950 animations->NotifyAnimationStarted(events->events_[0]);
2911 events->events_.clear(); 2951 events->events_.clear();
2912 2952
2913 animations_impl->AbortAnimations(TargetProperty::TRANSFORM); 2953 animations_impl->AbortAnimations(TargetProperty::TRANSFORM);
2914 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2954 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2915 ElementListType::PENDING)); 2955 element_id_, ElementListType::PENDING));
2916 EXPECT_FALSE(client_impl_.GetTransformIsAnimating(element_id_, 2956 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2917 ElementListType::ACTIVE)); 2957 element_id_, ElementListType::PENDING));
2958 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2959 element_id_, ElementListType::ACTIVE));
2960 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2961 element_id_, ElementListType::ACTIVE));
2918 2962
2919 animations_impl->Animate(kInitialTickTime + 2963 animations_impl->Animate(kInitialTickTime +
2920 TimeDelta::FromMilliseconds(4000)); 2964 TimeDelta::FromMilliseconds(4000));
2921 animations_impl->UpdateState(true, events.get()); 2965 animations_impl->UpdateState(true, events.get());
2922 2966
2923 animations->NotifyAnimationAborted(events->events_[0]); 2967 animations->NotifyAnimationAborted(events->events_[0]);
2924 EXPECT_FALSE( 2968 EXPECT_FALSE(client_.GetHasPotentialTransformAnimation(
2925 client_.GetTransformIsAnimating(element_id_, ElementListType::ACTIVE)); 2969 element_id_, ElementListType::ACTIVE));
2970 EXPECT_FALSE(client_.GetTransformIsCurrentlyAnimating(
2971 element_id_, ElementListType::ACTIVE));
2972
2973 // Case 4 : An animation that's not in effect.
2974 animation_id =
2975 AddAnimatedTransformToElementAnimations(animations.get(), 1.0, 1, 6);
2976 animations->GetAnimationById(animation_id)
2977 ->set_time_offset(base::TimeDelta::FromMilliseconds(-10000));
2978 animations->GetAnimationById(animation_id)
2979 ->set_fill_mode(Animation::FillMode::NONE);
2980
2981 animations->PushPropertiesTo(animations_impl.get());
2982 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2983 element_id_, ElementListType::PENDING));
2984 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2985 element_id_, ElementListType::PENDING));
2986 EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
2987 element_id_, ElementListType::ACTIVE));
2988 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2989 element_id_, ElementListType::ACTIVE));
2990
2991 animations_impl->ActivateAnimations();
2992 EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
2993 element_id_, ElementListType::ACTIVE));
2994 EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
2995 element_id_, ElementListType::ACTIVE));
2926 } 2996 }
2927 2997
2928 TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) { 2998 TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) {
2929 CreateTestLayer(true, true); 2999 CreateTestLayer(true, true);
2930 AttachTimelinePlayerLayer(); 3000 AttachTimelinePlayerLayer();
2931 CreateImplTimelineAndPlayer(); 3001 CreateImplTimelineAndPlayer();
2932 3002
2933 scoped_refptr<ElementAnimations> animations = element_animations(); 3003 scoped_refptr<ElementAnimations> animations = element_animations();
2934 scoped_refptr<ElementAnimations> animations_impl = element_animations_impl(); 3004 scoped_refptr<ElementAnimations> animations_impl = element_animations_impl();
2935 3005
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after
3458 EXPECT_FALSE(animations->IsPotentiallyAnimatingProperty( 3528 EXPECT_FALSE(animations->IsPotentiallyAnimatingProperty(
3459 TargetProperty::OPACITY, ElementListType::ACTIVE)); 3529 TargetProperty::OPACITY, ElementListType::ACTIVE));
3460 EXPECT_FALSE(animations->IsCurrentlyAnimatingProperty( 3530 EXPECT_FALSE(animations->IsCurrentlyAnimatingProperty(
3461 TargetProperty::OPACITY, ElementListType::PENDING)); 3531 TargetProperty::OPACITY, ElementListType::PENDING));
3462 EXPECT_FALSE(animations->IsCurrentlyAnimatingProperty( 3532 EXPECT_FALSE(animations->IsCurrentlyAnimatingProperty(
3463 TargetProperty::OPACITY, ElementListType::ACTIVE)); 3533 TargetProperty::OPACITY, ElementListType::ACTIVE));
3464 } 3534 }
3465 3535
3466 } // namespace 3536 } // namespace
3467 } // namespace cc 3537 } // namespace cc
OLDNEW
« no previous file with comments | « cc/animation/element_animations.cc ('k') | cc/layers/layer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698