| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "android_webview/browser/gfx/begin_frame_source_webview.h" |
| |
| #include "components/viz/test/begin_frame_source_test.h" |
| |
| namespace android_webview { |
| namespace { |
| |
| class TestBeginFrameSource : public viz::ExternalBeginFrameSource, |
| public viz::ExternalBeginFrameSourceClient { |
| public: |
| TestBeginFrameSource() : ExternalBeginFrameSource(this) {} |
| ~TestBeginFrameSource() override = default; |
| |
| void OnNeedsBeginFrames(bool needs_begin_frames) override { |
| needs_begin_frames_ = needs_begin_frames; |
| } |
| |
| bool needs_begin_frames() const { return needs_begin_frames_; } |
| |
| private: |
| bool needs_begin_frames_ = false; |
| }; |
| |
| } // namespace |
| |
| class BeginFrameSourceWebViewTest : public ::testing::Test { |
| public: |
| BeginFrameSourceWebViewTest() { |
| root_begin_frame_source_.ObserveBeginFrameSource(&test_begin_frame_source_); |
| } |
| |
| viz::BeginFrameArgs BeginFrameArgsForTesting(uint64_t sequence) { |
| return viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, |
| sequence); |
| } |
| |
| protected: |
| BeginFrameSourceWebView begin_frame_source_; |
| RootBeginFrameSourceWebView root_begin_frame_source_; |
| |
| // Test classes used to issue and observe begin frames. |
| testing::NiceMock<viz::MockBeginFrameObserver> observer_; |
| TestBeginFrameSource test_begin_frame_source_; |
| }; |
| |
| TEST_F(BeginFrameSourceWebViewTest, RootBeginFrame) { |
| EXPECT_FALSE(test_begin_frame_source_.needs_begin_frames()); |
| |
| // Send BeginFrame without observer. |
| auto args1 = BeginFrameArgsForTesting(1); |
| test_begin_frame_source_.OnBeginFrame(args1); |
| |
| root_begin_frame_source_.AddObserver(&observer_); |
| EXPECT_TRUE(test_begin_frame_source_.needs_begin_frames()); |
| |
| // Send BeginFrame with observer, verify it gets it. |
| auto args2 = BeginFrameArgsForTesting(2); |
| EXPECT_BEGIN_FRAME_ARGS_USED(observer_, args2); |
| test_begin_frame_source_.OnBeginFrame(args2); |
| |
| root_begin_frame_source_.RemoveObserver(&observer_); |
| EXPECT_FALSE(test_begin_frame_source_.needs_begin_frames()); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, RootPausedWithObservers) { |
| // External BFS is not paused => observer will be unpaused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| root_begin_frame_source_.AddObserver(&observer_); |
| |
| // External BFS is paused => observer will be paused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(true); |
| |
| // External BFS is unpaused => observer will be unpaused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(false); |
| root_begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, RootPausedWithoutObservers) { |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(true); |
| |
| // External BFS is paused => observer will be paused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| root_begin_frame_source_.AddObserver(&observer_); |
| |
| // External BFS is unpaused => observer will be unpaused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(false); |
| |
| root_begin_frame_source_.RemoveObserver(&observer_); |
| |
| // External BFS is unpaused => observer will be unpaused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| root_begin_frame_source_.AddObserver(&observer_); |
| |
| root_begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, ChildBeginFrame) { |
| begin_frame_source_.SetParentSource(&root_begin_frame_source_); |
| |
| EXPECT_FALSE(test_begin_frame_source_.needs_begin_frames()); |
| |
| // Send BeginFrame without observer. |
| auto args1 = BeginFrameArgsForTesting(1); |
| test_begin_frame_source_.OnBeginFrame(args1); |
| |
| begin_frame_source_.AddObserver(&observer_); |
| EXPECT_TRUE(test_begin_frame_source_.needs_begin_frames()); |
| |
| // Send BeginFrame with observer, verify it gets it. |
| auto args2 = BeginFrameArgsForTesting(2); |
| EXPECT_BEGIN_FRAME_ARGS_USED(observer_, args2); |
| test_begin_frame_source_.OnBeginFrame(args2); |
| |
| begin_frame_source_.RemoveObserver(&observer_); |
| EXPECT_FALSE(test_begin_frame_source_.needs_begin_frames()); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, ChildPausedWithObservers) { |
| begin_frame_source_.SetParentSource(&root_begin_frame_source_); |
| |
| // External BFS is not paused => observer will be not paused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| begin_frame_source_.AddObserver(&observer_); |
| |
| // External BFS paused => observer will be paused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(true); |
| |
| // External BFS unpaused => observer will be unpaused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(false); |
| begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, ChildPausedWithoutObservers) { |
| begin_frame_source_.SetParentSource(&root_begin_frame_source_); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(true); |
| |
| // External BFS is paused => observer will be paused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| begin_frame_source_.AddObserver(&observer_); |
| |
| // External BFS unpaused => observer will be unpaused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(false); |
| |
| begin_frame_source_.RemoveObserver(&observer_); |
| |
| // External BFS is unpaused => observer will be unpaused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| begin_frame_source_.AddObserver(&observer_); |
| |
| begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, ChildPausedNoParent) { |
| // BFS doesn't have parent so it is paused => observer will be paused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| begin_frame_source_.AddObserver(&observer_); |
| |
| // As there is no parent we are always paused, so we don't expect the call. |
| EXPECT_CALL(observer_, OnBeginFrameSourcePausedChanged(testing::_)).Times(0); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(true); |
| |
| // As there is no parent we are always paused, so we don't expect the call. |
| EXPECT_CALL(observer_, OnBeginFrameSourcePausedChanged(testing::_)).Times(0); |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(false); |
| |
| begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, ChildPauseChangeOnSetParent) { |
| // BFS doesn't have parent so it is paused => observer will be paused on Add. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| begin_frame_source_.AddObserver(&observer_); |
| |
| // We set parent and it's unpaused => observer will be unpaused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, false); |
| begin_frame_source_.SetParentSource(&root_begin_frame_source_); |
| |
| // We remove parent so BFS becomes paused => observer will be paused. |
| EXPECT_BEGIN_FRAME_SOURCE_PAUSED(observer_, true); |
| begin_frame_source_.SetParentSource(nullptr); |
| |
| test_begin_frame_source_.OnSetBeginFrameSourcePaused(true); |
| |
| // We set parent and it's paused => observer will be paused. |
| // As it's already paused we don't expect the call. |
| EXPECT_CALL(observer_, OnBeginFrameSourcePausedChanged(testing::_)).Times(0); |
| begin_frame_source_.SetParentSource(&root_begin_frame_source_); |
| |
| begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| TEST_F(BeginFrameSourceWebViewTest, Reentrancy) { |
| begin_frame_source_.SetParentSource(&root_begin_frame_source_); |
| begin_frame_source_.AddObserver(&observer_); |
| |
| // Re-Add observer inside OnBeginFrame so it will trigger missed BeginFrame |
| EXPECT_CALL(observer_, OnBeginFrame(testing::_)) |
| .WillRepeatedly(testing::Invoke([&](const viz::BeginFrameArgs& args) { |
| if (args.type == viz::BeginFrameArgs::MISSED) |
| return; |
| begin_frame_source_.RemoveObserver(&observer_); |
| begin_frame_source_.AddObserver(&observer_); |
| })); |
| |
| test_begin_frame_source_.OnBeginFrame(BeginFrameArgsForTesting(1)); |
| |
| begin_frame_source_.RemoveObserver(&observer_); |
| } |
| |
| } // namespace android_webview |