| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "platform/graphics/OffscreenCanvasFrameDispatcherImpl.h" |
| |
| #include "platform/wtf/PtrUtil.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkSurface.h" |
| |
| using ::testing::_; |
| using ::testing::Mock; |
| |
| namespace blink { |
| |
| class MockOffscreenCanvasFrameDispatcherImpl |
| : public OffscreenCanvasFrameDispatcherImpl { |
| public: |
| MockOffscreenCanvasFrameDispatcherImpl() |
| : OffscreenCanvasFrameDispatcherImpl(nullptr, 0, 0, 0, 10, 10) {} |
| |
| MOCK_METHOD2(PostImageToPlaceholder, |
| void(RefPtr<StaticBitmapImage>, unsigned resource_id)); |
| }; |
| |
| class OffscreenCanvasFrameDispatcherImplTest : public ::testing::Test { |
| public: |
| void DispatchOneFrame(); |
| OffscreenCanvasResourceProvider* GetResourceProvider() { |
| return dispatcher_->offscreen_canvas_resource_provider_.get(); |
| } |
| |
| unsigned GetNumUnreclaimedFramesPosted() { |
| return dispatcher_->num_unreclaimed_frames_posted_; |
| } |
| |
| StaticBitmapImage* GetLatestUnpostedImage() { |
| return dispatcher_->latest_unposted_image_.get(); |
| } |
| |
| unsigned GetLatestUnpostedResourceId() { |
| return dispatcher_->latest_unposted_resource_id_; |
| } |
| |
| protected: |
| OffscreenCanvasFrameDispatcherImplTest() { |
| dispatcher_ = WTF::WrapUnique(new MockOffscreenCanvasFrameDispatcherImpl()); |
| } |
| |
| MockOffscreenCanvasFrameDispatcherImpl* Dispatcher() { |
| return dispatcher_.get(); |
| } |
| |
| private: |
| RefPtr<StaticBitmapImage> PrepareStaticBitmapImage(); |
| std::unique_ptr<MockOffscreenCanvasFrameDispatcherImpl> dispatcher_; |
| }; |
| |
| void OffscreenCanvasFrameDispatcherImplTest::DispatchOneFrame() { |
| sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(10, 10); |
| dispatcher_->DispatchFrame( |
| StaticBitmapImage::Create(surface->makeImageSnapshot()), 0.0, |
| SkIRect::MakeEmpty(), false); |
| } |
| |
| TEST_F(OffscreenCanvasFrameDispatcherImplTest, PlaceholderRunsNormally) { |
| /* We allow OffscreenCanvas to post up to 3 frames without hearing a response |
| * from placeholder. */ |
| // Post first frame |
| unsigned post_resource_id = 1u; |
| EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id)); |
| DispatchOneFrame(); |
| EXPECT_EQ(1u, GetNumUnreclaimedFramesPosted()); |
| EXPECT_EQ(1u, GetResourceProvider()->GetNextResourceId()); |
| Mock::VerifyAndClearExpectations(Dispatcher()); |
| |
| // Post second frame |
| post_resource_id++; |
| EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id)); |
| DispatchOneFrame(); |
| EXPECT_EQ(2u, GetNumUnreclaimedFramesPosted()); |
| EXPECT_EQ(2u, GetResourceProvider()->GetNextResourceId()); |
| Mock::VerifyAndClearExpectations(Dispatcher()); |
| |
| // Post third frame |
| post_resource_id++; |
| EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id)); |
| DispatchOneFrame(); |
| EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted()); |
| EXPECT_EQ(3u, GetResourceProvider()->GetNextResourceId()); |
| EXPECT_EQ(nullptr, GetLatestUnpostedImage()); |
| Mock::VerifyAndClearExpectations(Dispatcher()); |
| |
| /* We mock the behavior of placeholder on main thread here, by reclaiming |
| * the resources in order. */ |
| // Reclaim first frame |
| unsigned reclaim_resource_id = 1u; |
| Dispatcher()->ReclaimResource(reclaim_resource_id); |
| EXPECT_EQ(2u, GetNumUnreclaimedFramesPosted()); |
| |
| // Reclaim second frame |
| reclaim_resource_id++; |
| Dispatcher()->ReclaimResource(reclaim_resource_id); |
| EXPECT_EQ(1u, GetNumUnreclaimedFramesPosted()); |
| |
| // Reclaim third frame |
| reclaim_resource_id++; |
| Dispatcher()->ReclaimResource(reclaim_resource_id); |
| EXPECT_EQ(0u, GetNumUnreclaimedFramesPosted()); |
| } |
| |
| TEST_F(OffscreenCanvasFrameDispatcherImplTest, PlaceholderBeingBlocked) { |
| /* When main thread is blocked, attempting to post more than 3 frames will |
| * result in only 3 PostImageToPlaceholder. The latest unposted image will |
| * be saved. */ |
| EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, _)).Times(3); |
| |
| // Attempt to post 4 times |
| DispatchOneFrame(); |
| DispatchOneFrame(); |
| DispatchOneFrame(); |
| DispatchOneFrame(); |
| unsigned post_resource_id = 4u; |
| EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted()); |
| EXPECT_EQ(post_resource_id, GetResourceProvider()->GetNextResourceId()); |
| EXPECT_TRUE(GetLatestUnpostedImage()); |
| EXPECT_EQ(post_resource_id, GetLatestUnpostedResourceId()); |
| |
| // Attempt to post the 5th time. The latest unposted image will be replaced. |
| post_resource_id++; |
| DispatchOneFrame(); |
| EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted()); |
| EXPECT_EQ(post_resource_id, GetResourceProvider()->GetNextResourceId()); |
| EXPECT_TRUE(GetLatestUnpostedImage()); |
| EXPECT_EQ(post_resource_id, GetLatestUnpostedResourceId()); |
| |
| Mock::VerifyAndClearExpectations(Dispatcher()); |
| |
| /* When main thread becomes unblocked, the first reclaim called by placeholder |
| * will trigger OffscreenCanvasFrameDispatcher to post the last saved image. |
| * Resource reclaim happens in the same order as frame posting. */ |
| unsigned reclaim_resource_id = 1u; |
| EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id)); |
| Dispatcher()->ReclaimResource(reclaim_resource_id); |
| // Reclaim 1 frame and post 1 frame, so numPostImagesUnresponded remains as 3 |
| EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted()); |
| // Not generating new resource Id |
| EXPECT_EQ(post_resource_id, GetResourceProvider()->GetNextResourceId()); |
| EXPECT_FALSE(GetLatestUnpostedImage()); |
| EXPECT_EQ(0u, GetLatestUnpostedResourceId()); |
| Mock::VerifyAndClearExpectations(Dispatcher()); |
| |
| reclaim_resource_id++; |
| Dispatcher()->ReclaimResource(reclaim_resource_id); |
| EXPECT_EQ(2u, GetNumUnreclaimedFramesPosted()); |
| } |
| |
| } // namespace blink |