| Index: chrome/browser/tab_contents/thumbnail_generator_unittest.cc
|
| ===================================================================
|
| --- chrome/browser/tab_contents/thumbnail_generator_unittest.cc (revision 0)
|
| +++ chrome/browser/tab_contents/thumbnail_generator_unittest.cc (revision 0)
|
| @@ -0,0 +1,168 @@
|
| +// Copyright (c) 2009 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 "base/basictypes.h"
|
| +#include "chrome/browser/renderer_host/backing_store_manager.h"
|
| +#include "chrome/browser/renderer_host/mock_render_process_host.h"
|
| +#include "chrome/browser/renderer_host/test_render_view_host.h"
|
| +#include "chrome/browser/tab_contents/thumbnail_generator.h"
|
| +#include "chrome/common/notification_service.h"
|
| +#include "chrome/common/render_messages.h"
|
| +#include "chrome/common/transport_dib.h"
|
| +#include "chrome/test/testing_profile.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/skia/include/core/SkColorPriv.h"
|
| +
|
| +static const int kBitmapWidth = 100;
|
| +static const int kBitmapHeight = 100;
|
| +
|
| +class ThumbnailGeneratorTest : public testing::Test {
|
| + public:
|
| + ThumbnailGeneratorTest()
|
| + : profile_(),
|
| + process_(new MockRenderProcessHost(&profile_)),
|
| + widget_(process_, 1),
|
| + view_(&widget_) {
|
| + // Paiting will be skipped if there's no view.
|
| + widget_.set_view(&view_);
|
| +
|
| + // Need to send out a create notification for the RWH to get hooked. This is
|
| + // a little scary in that we don't have a RenderView, but the only listener
|
| + // will want a RenderWidget, so it works out OK.
|
| + NotificationService::current()->Notify(
|
| + NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
|
| + Source<RenderViewHostManager>(NULL),
|
| + Details<RenderViewHost>(reinterpret_cast<RenderViewHost*>(&widget_)));
|
| +
|
| + transport_dib_.reset(TransportDIB::Create(kBitmapWidth * kBitmapHeight * 4,
|
| + 1));
|
| +
|
| + // We don't want to be sensitive to timing.
|
| + generator_.set_no_timeout(true);
|
| + }
|
| +
|
| + protected:
|
| + // Indicates what bitmap should be sent with the paint message. _OTHER will
|
| + // only be retrned by CheckFirstPixel if the pixel is none of the others.
|
| + enum TransportType { TRANSPORT_BLACK, TRANSPORT_WHITE, TRANSPORT_OTHER };
|
| +
|
| + void SendPaint(TransportType type) {
|
| + ViewHostMsg_PaintRect_Params params;
|
| + params.bitmap_rect = gfx::Rect(0, 0, kBitmapWidth, kBitmapHeight);
|
| + params.view_size = params.bitmap_rect.size();
|
| + params.flags = 0;
|
| +
|
| + scoped_ptr<skia::PlatformCanvas> canvas(
|
| + transport_dib_->GetPlatformCanvas(kBitmapWidth, kBitmapHeight));
|
| + switch (type) {
|
| + case TRANSPORT_BLACK:
|
| + canvas->getTopPlatformDevice().accessBitmap(true).eraseARGB(
|
| + 0xFF, 0, 0, 0);
|
| + break;
|
| + case TRANSPORT_WHITE:
|
| + canvas->getTopPlatformDevice().accessBitmap(true).eraseARGB(
|
| + 0xFF, 0xFF, 0xFF, 0xFF);
|
| + break;
|
| + case TRANSPORT_OTHER:
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +
|
| + params.bitmap = transport_dib_->id();
|
| +
|
| + ViewHostMsg_PaintRect msg(1, params);
|
| + widget_.OnMessageReceived(msg);
|
| + }
|
| +
|
| + TransportType ClassifyFirstPixel(const SkBitmap& bitmap) {
|
| + // Returns the color of the first pixel of the bitmap. The bitmap must be
|
| + // non-empty.
|
| + SkAutoLockPixels lock(bitmap);
|
| + uint32 pixel = *bitmap.getAddr32(0, 0);
|
| +
|
| + if (SkGetPackedA32(pixel) != 0xFF)
|
| + return TRANSPORT_OTHER; // All values expect an opqaue alpha channel
|
| +
|
| + if (SkGetPackedR32(pixel) == 0 &&
|
| + SkGetPackedG32(pixel) == 0 &&
|
| + SkGetPackedB32(pixel) == 0)
|
| + return TRANSPORT_BLACK;
|
| +
|
| + if (SkGetPackedR32(pixel) == 0xFF &&
|
| + SkGetPackedG32(pixel) == 0xFF &&
|
| + SkGetPackedB32(pixel) == 0xFF)
|
| + return TRANSPORT_WHITE;
|
| +
|
| + return TRANSPORT_OTHER;
|
| + }
|
| +
|
| + MessageLoopForUI message_loop_;
|
| +
|
| + TestingProfile profile_;
|
| +
|
| + // This will get deleted when the last RHWH associated with it is destroyed.
|
| + MockRenderProcessHost* process_;
|
| +
|
| + RenderWidgetHost widget_;
|
| + TestRenderWidgetHostView view_;
|
| + ThumbnailGenerator generator_;
|
| +
|
| + scoped_ptr<TransportDIB> transport_dib_;
|
| +
|
| + private:
|
| + // testing::Test implementation.
|
| + void SetUp() {
|
| + }
|
| + void TearDown() {
|
| + }
|
| +};
|
| +
|
| +TEST_F(ThumbnailGeneratorTest, NoThumbnail) {
|
| + // This is the case where there is no thumbnail available on the tab and
|
| + // there is no backing store. There should be no image returned.
|
| + SkBitmap result = generator_.GetThumbnailForRenderer(&widget_);
|
| + EXPECT_TRUE(result.isNull());
|
| +}
|
| +
|
| +// Tests basic thumbnail generation when a backing store is discarded.
|
| +TEST_F(ThumbnailGeneratorTest, DiscardBackingStore) {
|
| + // First set up a backing store and then discard it.
|
| + SendPaint(TRANSPORT_BLACK);
|
| + widget_.WasHidden();
|
| + ASSERT_TRUE(BackingStoreManager::ExpireBackingStoreForTest(&widget_));
|
| + ASSERT_FALSE(widget_.GetBackingStore(false));
|
| +
|
| + // The thumbnail generator should have stashed a thumbnail of the page.
|
| + SkBitmap result = generator_.GetThumbnailForRenderer(&widget_);
|
| + ASSERT_FALSE(result.isNull());
|
| + EXPECT_EQ(TRANSPORT_BLACK, ClassifyFirstPixel(result));
|
| +}
|
| +
|
| +TEST_F(ThumbnailGeneratorTest, QuickShow) {
|
| + // Set up a hidden widget with a black cached thumbnail and an expired
|
| + // backing store.
|
| + SendPaint(TRANSPORT_BLACK);
|
| + widget_.WasHidden();
|
| + ASSERT_TRUE(BackingStoreManager::ExpireBackingStoreForTest(&widget_));
|
| + ASSERT_FALSE(widget_.GetBackingStore(false));
|
| +
|
| + // Now show the widget and paint white.
|
| + widget_.WasRestored();
|
| + SendPaint(TRANSPORT_WHITE);
|
| +
|
| + // The black thumbnail should still be cached because it hasn't processed the
|
| + // timer message yet.
|
| + SkBitmap result = generator_.GetThumbnailForRenderer(&widget_);
|
| + ASSERT_FALSE(result.isNull());
|
| + EXPECT_EQ(TRANSPORT_BLACK, ClassifyFirstPixel(result));
|
| +
|
| + // Running the message loop will process the timer, which should expire the
|
| + // cached thumbnail. Asking again should give us a new one computed from the
|
| + // backing store.
|
| + message_loop_.RunAllPending();
|
| + result = generator_.GetThumbnailForRenderer(&widget_);
|
| + ASSERT_FALSE(result.isNull());
|
| + EXPECT_EQ(TRANSPORT_WHITE, ClassifyFirstPixel(result));
|
| +}
|
|
|