OLD | NEW |
---|---|
1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 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/scheduler/begin_frame_source.h" | 5 #include "cc/scheduler/begin_frame_source.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
10 #include "base/test/test_simple_task_runner.h" | 10 #include "base/test/test_simple_task_runner.h" |
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
575 now_src_->Advance(base::TimeDelta::FromInternalValue(5000)); | 575 now_src_->Advance(base::TimeDelta::FromInternalValue(5000)); |
576 EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false); | 576 EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false); |
577 // Sequence number is incremented again, because the missed frame has | 577 // Sequence number is incremented again, because the missed frame has |
578 // different time/interval. | 578 // different time/interval. |
579 EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 3, 10000, 20000, | 579 EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 3, 10000, 20000, |
580 10000); | 580 10000); |
581 source_->AddObserver(&obs); | 581 source_->AddObserver(&obs); |
582 source_->RemoveObserver(&obs); | 582 source_->RemoveObserver(&obs); |
583 } | 583 } |
584 | 584 |
585 // BeginFrameObserverAckTracker testing ---------------------------------------- | |
586 class TestBeginFrameConsumer : public BeginFrameObserverBase { | |
587 public: | |
588 void SetDiscardNextBeginFrame() { discard_next_begin_frame_ = true; } | |
589 | |
590 private: | |
591 bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override { | |
592 // Consume the args and indicate whether we used them. | |
593 bool discard_this_begin_frame = discard_next_begin_frame_; | |
594 discard_next_begin_frame_ = false; | |
595 return !discard_this_begin_frame; | |
596 } | |
597 void OnBeginFrameSourcePausedChanged(bool paused) override {} | |
598 | |
599 bool discard_next_begin_frame_ = false; | |
600 }; | |
601 | |
602 // Use EXPECT_TRUE instead of EXPECT_EQ for |finished| and |damage| as gcc 4.7 | |
603 // issues the following warning on EXPECT_EQ(false, x), which is turned into an | |
604 // error with -Werror=conversion-null: | |
605 // | |
606 // converting 'false' to pointer type for argument 1 of | |
607 // 'char testing::internal::IsNullLiteralHelper(testing::internal::Secret*)' | |
608 #define EXPECT_ACK_TRACKER_STATE(finished, damage, latest_confirmed) \ | |
609 EXPECT_TRUE(finished == tracker_->AllObserversFinishedFrame()) \ | |
610 << "expected: " << finished; \ | |
611 EXPECT_TRUE(damage == tracker_->AnyObserversHadDamage()) << "expected: " \ | |
612 << damage; \ | |
613 EXPECT_EQ(latest_confirmed, tracker_->LatestConfirmedSequenceNumber()) | |
614 | |
615 class BeginFrameObserverAckTrackerTest : public ::testing::Test { | |
616 public: | |
617 BeginFrameArgs current_args_; | |
618 std::unique_ptr<BeginFrameObserverAckTracker> tracker_; | |
619 std::unique_ptr<TestBeginFrameConsumer> obs1_; | |
620 std::unique_ptr<TestBeginFrameConsumer> obs2_; | |
brianderson
2017/02/17 21:26:09
Do these need to be unique_ptrs?
Eric Seckler
2017/02/21 12:10:57
Since I now no longer need to recreate the TestBeg
| |
621 | |
622 void SetUp() override { | |
623 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
624 tracker_.reset(new BeginFrameObserverAckTracker()); | |
625 obs1_.reset(new TestBeginFrameConsumer); | |
626 obs2_.reset(new TestBeginFrameConsumer); | |
627 } | |
628 }; | |
629 | |
630 TEST_F(BeginFrameObserverAckTrackerTest, CorrectnessWithoutObservers) { | |
631 // Check initial state. | |
632 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
633 | |
634 // A new BeginFrame is immediately finished and confirmed. | |
635 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2); | |
636 tracker_->OnBeginFrame(current_args_); | |
637 EXPECT_ACK_TRACKER_STATE(true, false, 2u); | |
638 } | |
639 | |
640 TEST_F(BeginFrameObserverAckTrackerTest, CorrectnessWith1Observer) { | |
641 // Check initial state. | |
642 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
643 | |
644 // After adding an observer, the BeginFrame is not finished or confirmed. | |
645 tracker_->OnObserverAdded(obs1_.get()); | |
646 EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame. | |
647 | |
648 // On removing it, the BeginFrame is back to original state. | |
649 tracker_->OnObserverRemoved(obs1_.get()); | |
650 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
651 | |
652 // After adding it back, the BeginFrame is again not finished or confirmed. | |
653 tracker_->OnObserverAdded(obs1_.get()); | |
654 EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame. | |
655 | |
656 // When the observer finishes and confirms, the BeginFrame is finished | |
657 // and confirmed. | |
658 obs1_->OnBeginFrame(current_args_); | |
659 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
660 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
661 BeginFrameAck(0, 1, 1, 0, false)); | |
662 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
663 | |
664 // A new BeginFrame is initially not finished or confirmed. | |
665 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2); | |
666 tracker_->OnBeginFrame(current_args_); | |
667 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
668 | |
669 // Stray ACK for an old BeginFrame is ignored. | |
670 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
671 BeginFrameAck(0, 1, 1, 0, false)); | |
672 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
673 | |
674 // When the observer finishes but doesn't confirm, the BeginFrame is finished | |
675 // but not confirmed. | |
676 obs1_->OnBeginFrame(current_args_); | |
677 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
678 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
679 BeginFrameAck(0, 2, 1, 0, false)); | |
680 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
681 | |
682 // Damage from ACK propagates. | |
683 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 3); | |
684 tracker_->OnBeginFrame(current_args_); | |
685 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
686 obs1_->OnBeginFrame(current_args_); | |
687 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
688 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
689 BeginFrameAck(0, 3, 3, 0, true)); | |
690 EXPECT_ACK_TRACKER_STATE(true, true, 3u); | |
691 | |
692 // Observer discarding frame during OnBeginFrame also finishes BeginFrame, but | |
693 // doesn't confirm it. | |
694 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 4); | |
695 tracker_->OnBeginFrame(current_args_); | |
696 EXPECT_ACK_TRACKER_STATE(false, false, 3u); | |
697 obs1_->SetDiscardNextBeginFrame(); | |
698 obs1_->OnBeginFrame(current_args_); | |
699 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
700 EXPECT_ACK_TRACKER_STATE(true, false, 3u); | |
701 | |
702 // Removing the observer confirms the latest BeginFrame. | |
703 tracker_->OnObserverRemoved(obs1_.get()); | |
704 EXPECT_ACK_TRACKER_STATE(true, false, 4u); | |
705 } | |
706 | |
707 TEST_F(BeginFrameObserverAckTrackerTest, CorrectnessWith2Observers) { | |
708 // Check initial state. | |
709 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
710 | |
711 // After adding observers, the BeginFrame is not finished or confirmed. | |
712 tracker_->OnObserverAdded(obs1_.get()); | |
713 EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame. | |
714 tracker_->OnObserverAdded(obs2_.get()); | |
715 EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame. | |
716 | |
717 // Removing one of them changes nothing. Same for adding back. | |
718 tracker_->OnObserverRemoved(obs1_.get()); | |
719 EXPECT_ACK_TRACKER_STATE(false, false, 0u); | |
720 tracker_->OnObserverAdded(obs1_.get()); | |
721 EXPECT_ACK_TRACKER_STATE(false, false, 0u); | |
722 | |
723 // When one observer finishes and confirms, nothing changes. | |
724 obs1_->OnBeginFrame(current_args_); | |
725 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
726 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
727 BeginFrameAck(0, 1, 1, 0, false)); | |
728 EXPECT_ACK_TRACKER_STATE(false, false, 0u); | |
729 // When both finish and confirm, the BeginFrame is finished and confirmed. | |
730 obs2_->OnBeginFrame(current_args_); | |
731 tracker_->OnObserverBeginFrame(obs2_.get(), current_args_); | |
732 tracker_->OnObserverFinishedFrame(obs2_.get(), | |
733 BeginFrameAck(0, 1, 1, 0, false)); | |
734 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
735 | |
736 // A new BeginFrame is not finished or confirmed. | |
737 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2); | |
738 tracker_->OnBeginFrame(current_args_); | |
739 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
740 | |
741 // When both observers finish but only one confirms, the BeginFrame is | |
742 // finished but not confirmed. | |
743 obs1_->OnBeginFrame(current_args_); | |
744 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
745 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
746 BeginFrameAck(0, 2, 2, 0, false)); | |
747 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
748 obs2_->OnBeginFrame(current_args_); | |
749 tracker_->OnObserverBeginFrame(obs2_.get(), current_args_); | |
750 tracker_->OnObserverFinishedFrame(obs2_.get(), | |
751 BeginFrameAck(0, 2, 1, 0, false)); | |
752 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
753 | |
754 // With reversed confirmations in the next ACKs, the latest confirmed frame | |
755 // increases but the latest BeginFrame remains unconfirmed. | |
756 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 3); | |
757 tracker_->OnBeginFrame(current_args_); | |
758 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
759 obs1_->OnBeginFrame(current_args_); | |
760 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
761 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
762 BeginFrameAck(0, 3, 2, 0, false)); | |
763 EXPECT_ACK_TRACKER_STATE(false, false, 1u); | |
764 obs2_->OnBeginFrame(current_args_); | |
765 tracker_->OnObserverBeginFrame(obs2_.get(), current_args_); | |
766 tracker_->OnObserverFinishedFrame(obs2_.get(), | |
767 BeginFrameAck(0, 3, 3, 0, false)); | |
768 EXPECT_ACK_TRACKER_STATE(true, false, 2u); | |
769 | |
770 // Only a single ACK with damage suffices. | |
771 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 4); | |
772 tracker_->OnBeginFrame(current_args_); | |
773 EXPECT_ACK_TRACKER_STATE(false, false, 2u); | |
774 obs1_->OnBeginFrame(current_args_); | |
775 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
776 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
777 BeginFrameAck(0, 4, 4, 0, true)); | |
778 EXPECT_ACK_TRACKER_STATE(false, true, 3u); | |
779 obs2_->OnBeginFrame(current_args_); | |
780 tracker_->OnObserverBeginFrame(obs2_.get(), current_args_); | |
781 tracker_->OnObserverFinishedFrame(obs2_.get(), | |
782 BeginFrameAck(0, 4, 4, 0, false)); | |
783 EXPECT_ACK_TRACKER_STATE(true, true, 4u); | |
784 | |
785 // Removing the damaging observer makes no difference in this case. | |
786 tracker_->OnObserverRemoved(obs1_.get()); | |
787 EXPECT_ACK_TRACKER_STATE(true, true, 4u); | |
788 | |
789 // Adding the observer back considers it up to date up to the current | |
790 // BeginFrame, because it is the last used one. Thus, the current BeginFrame | |
791 // is still finished, too. | |
792 tracker_->OnObserverAdded(obs1_.get()); | |
793 EXPECT_ACK_TRACKER_STATE(true, true, 4u); | |
794 | |
795 // Adding the observer back after the next BeginFrame considers it up to date | |
796 // up to last BeginFrame only. | |
797 tracker_->OnObserverRemoved(obs1_.get()); | |
798 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 5); | |
799 tracker_->OnBeginFrame(current_args_); | |
800 tracker_->OnObserverAdded(obs1_.get()); | |
801 EXPECT_ACK_TRACKER_STATE(false, false, 4u); | |
802 // Both observers need to finish for the BeginFrame to be finished. | |
803 obs1_->OnBeginFrame(current_args_); | |
804 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
805 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
806 BeginFrameAck(0, 5, 5, 0, false)); | |
807 EXPECT_ACK_TRACKER_STATE(false, false, 4u); | |
808 obs2_->OnBeginFrame(current_args_); | |
809 tracker_->OnObserverBeginFrame(obs2_.get(), current_args_); | |
810 tracker_->OnObserverFinishedFrame(obs2_.get(), | |
811 BeginFrameAck(0, 5, 5, 0, false)); | |
812 EXPECT_ACK_TRACKER_STATE(true, false, 5u); | |
813 } | |
814 | |
815 TEST_F(BeginFrameObserverAckTrackerTest, ChangingSourceIdOnBeginFrame) { | |
816 // Check initial state. | |
817 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
818 | |
819 // Changing source id without observer updates confirmed BeginFrame. | |
820 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 10); | |
821 tracker_->OnBeginFrame(current_args_); | |
822 EXPECT_ACK_TRACKER_STATE(true, false, 10u); | |
823 | |
824 // Setup an observer for current BeginFrame. | |
825 tracker_->OnObserverAdded(obs1_.get()); | |
826 EXPECT_ACK_TRACKER_STATE(false, false, 9u); // up to date to previous frame. | |
827 obs1_->OnBeginFrame(current_args_); | |
828 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
829 tracker_->OnObserverFinishedFrame(obs1_.get(), | |
830 BeginFrameAck(1, 10, 10, 0, true)); | |
831 EXPECT_ACK_TRACKER_STATE(true, true, 10u); | |
832 | |
833 // Changing source id with an observer sets confirmed BeginFrame to invalid. | |
834 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 2, 20); | |
835 tracker_->OnBeginFrame(current_args_); | |
836 EXPECT_ACK_TRACKER_STATE(false, false, BeginFrameArgs::kInvalidFrameNumber); | |
837 } | |
838 | |
839 TEST_F(BeginFrameObserverAckTrackerTest, ChangingSourceIdOnObserverBeginFrame) { | |
840 // Check initial state. | |
841 EXPECT_ACK_TRACKER_STATE(true, false, 1u); | |
842 | |
843 // Advance to a sequence number that isn't kInvalidFrameNumber+1. | |
844 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 5); | |
845 tracker_->OnBeginFrame(current_args_); | |
846 EXPECT_ACK_TRACKER_STATE(true, false, 5u); | |
847 | |
848 // Assume that source has changed. When an observer is added before the next | |
849 // OnBeginFrame() from the new source, the tracker may see a call to | |
850 // OnObserverBeginFrame() with a new source_id. In this case, the confirmed | |
851 // BeginFrame should be set to invalid. | |
852 tracker_->OnObserverAdded(obs1_.get()); | |
853 EXPECT_ACK_TRACKER_STATE(false, false, 4u); // up to date to previous frame. | |
854 current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 10); | |
855 obs1_->OnBeginFrame(current_args_); | |
856 tracker_->OnObserverBeginFrame(obs1_.get(), current_args_); | |
857 EXPECT_ACK_TRACKER_STATE(false, false, BeginFrameArgs::kInvalidFrameNumber); | |
858 } | |
859 | |
860 // ExternalBeginFrameSource testing -------------------------------------------- | |
861 class MockExternalBeginFrameSourceClient | |
862 : public ExternalBeginFrameSourceClient { | |
863 public: | |
864 MOCK_METHOD1(OnNeedsBeginFrames, void(bool)); | |
865 MOCK_METHOD1(OnDidFinishFrame, void(const BeginFrameAck&)); | |
866 }; | |
867 | |
868 class ExternalBeginFrameSourceTest : public ::testing::Test { | |
869 public: | |
870 std::unique_ptr<MockExternalBeginFrameSourceClient> client_; | |
871 std::unique_ptr<ExternalBeginFrameSource> source_; | |
872 std::unique_ptr<MockBeginFrameObserver> obs_; | |
brianderson
2017/02/17 21:26:09
Do these need to be unique_ptrs?
Eric Seckler
2017/02/21 12:10:57
At the very least, obs_ and client_ should stay on
| |
873 | |
874 void SetUp() override { | |
875 client_.reset(new MockExternalBeginFrameSourceClient); | |
876 source_.reset(new ExternalBeginFrameSource(client_.get())); | |
877 obs_.reset(new MockBeginFrameObserver); | |
878 } | |
879 }; | |
880 | |
881 TEST_F(ExternalBeginFrameSourceTest, CallsOnDidFinishFrameWithoutObservers) { | |
882 EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 2, 0, false))) | |
883 .Times(1); | |
884 source_->OnBeginFrame(CreateBeginFrameArgsForTesting( | |
885 BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000))); | |
886 } | |
887 | |
888 TEST_F(ExternalBeginFrameSourceTest, | |
889 CallsOnDidFinishFrameWhenObserverFinishes) { | |
890 EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false); | |
891 EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1); | |
892 source_->AddObserver(obs_.get()); | |
893 | |
894 BeginFrameArgs args = CreateBeginFrameArgsForTesting( | |
895 BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000)); | |
896 EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args); | |
897 source_->OnBeginFrame(args); | |
898 | |
899 EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 2, 0, true))) | |
900 .Times(1); | |
901 source_->DidFinishFrame(obs_.get(), BeginFrameAck(0, 2, 2, 0, true)); | |
902 | |
903 args = CreateBeginFrameArgsForTesting( | |
904 BEGINFRAME_FROM_HERE, 0, 3, base::TimeTicks::FromInternalValue(20000)); | |
905 EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args); | |
906 source_->OnBeginFrame(args); | |
907 | |
908 EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 3, 2, 0, false))) | |
909 .Times(1); | |
910 source_->DidFinishFrame(obs_.get(), BeginFrameAck(0, 3, 2, 0, false)); | |
911 } | |
912 | |
913 TEST_F(ExternalBeginFrameSourceTest, | |
914 CallsOnDidFinishFrameWhenObserverDropsBeginFrame) { | |
915 EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false); | |
916 EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1); | |
917 source_->AddObserver(obs_.get()); | |
918 | |
919 BeginFrameArgs args = CreateBeginFrameArgsForTesting( | |
920 BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000)); | |
921 EXPECT_BEGIN_FRAME_ARGS_DROP(*obs_, args); | |
922 EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 0, 0, false))) | |
923 .Times(1); | |
924 source_->OnBeginFrame(args); | |
925 } | |
926 | |
927 TEST_F(ExternalBeginFrameSourceTest, CallsOnDidFinishFrameWhenObserverRemoved) { | |
928 EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false); | |
929 EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1); | |
930 source_->AddObserver(obs_.get()); | |
931 | |
932 BeginFrameArgs args = CreateBeginFrameArgsForTesting( | |
933 BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000)); | |
934 EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args); | |
935 source_->OnBeginFrame(args); | |
936 | |
937 EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 2, 0, false))) | |
938 .Times(1); | |
939 EXPECT_CALL((*client_), OnNeedsBeginFrames(false)).Times(1); | |
940 source_->RemoveObserver(obs_.get()); | |
941 } | |
942 | |
585 } // namespace | 943 } // namespace |
586 } // namespace cc | 944 } // namespace cc |
OLD | NEW |