1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 59ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h" 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/thumbnails/simple_thumbnail_crop.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/test/test_browser_thread.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/canvas.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/scrollbar_size.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace thumbnails { 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)typedef testing::Test ContentBasedThumbnailingAlgorithmTest; 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class ConsumerCallbackCatcher { 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public: 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ConsumerCallbackCatcher() 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : called_back_(false), clip_result_(CLIP_RESULT_UNPROCESSED) { 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void UiThreadCallback(const ThumbnailingContext& context, 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const SkBitmap& bitmap) { 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) called_back_ = true; 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) captured_bitmap_ = bitmap; 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) clip_result_ = context.clip_result; 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) score_ = context.score; 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool called_back() const { 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return called_back_; 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const SkBitmap& captured_bitmap() const { 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return captured_bitmap_; 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ClipResult clip_result() const { 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return clip_result_; 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const ThumbnailScore& score() const { 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return score_; 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private: 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SkBitmap captured_bitmap_; 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool called_back_; 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ClipResult clip_result_; 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ThumbnailScore score_; 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ConsumerCallbackCatcher); 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(ContentBasedThumbnailingAlgorithmTest, GetCanvasCopyInfo) { 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // We will want to use the entirety of the image as the source. Usually, 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // an image in its original size should be requested, except for reakky large 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // canvas. In that case, image will be shrunk but wit aspect ratio preserved. 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size thumbnail_size(312, 165); 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_refptr<ThumbnailingAlgorithm> algorithm( 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) new ContentBasedThumbnailingAlgorithm(thumbnail_size)); 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Rect clipping_rect; 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Size target_size; 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Size source_size(1000, 600); 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ClipResult clip_result = algorithm->GetCanvasCopyInfo( 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) source_size, ui::SCALE_FACTOR_100P, &clipping_rect, &target_size); 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(CLIP_RESULT_SOURCE_SAME_AS_TARGET, clip_result); 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(source_size.ToString(), clipping_rect.size().ToString()); 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(gfx::Point(0, 0).ToString(), clipping_rect.origin().ToString()); 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(source_size, target_size); 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) source_size.SetSize(6000, 3000); 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) clip_result = algorithm->GetCanvasCopyInfo( 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) source_size, ui::SCALE_FACTOR_100P, &clipping_rect, &target_size); 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(CLIP_RESULT_NOT_CLIPPED, clip_result); 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(source_size.ToString(), clipping_rect.size().ToString()); 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(gfx::Point(0, 0).ToString(), clipping_rect.origin().ToString()); 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(target_size.width(), source_size.width()); 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(target_size.height(), source_size.height()); 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR(static_cast<float>(target_size.width()) / target_size.height(), 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(source_size.width()) / source_size.height(), 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.1f); 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) source_size.SetSize(300, 200); 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) clip_result = algorithm->GetCanvasCopyInfo( 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) source_size, ui::SCALE_FACTOR_100P, &clipping_rect, &target_size); 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(CLIP_RESULT_SOURCE_IS_SMALLER, clip_result); 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(clipping_rect.size().ToString(), 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SimpleThumbnailCrop::GetCopySizeForThumbnail( 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ui::SCALE_FACTOR_100P, thumbnail_size).ToString()); 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(gfx::Point(0, 0).ToString(), clipping_rect.origin().ToString()); 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(ContentBasedThumbnailingAlgorithmTest, PrepareSourceBitmap) { 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size thumbnail_size(312, 165); 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size copy_size(400, 200); 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_refptr<ThumbnailingContext> context( 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ThumbnailingContext::CreateThumbnailingContextForTest()); 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) context->requested_copy_size = copy_size; 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This calls for exercising two distinct paths: with prior clipping and 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // without. 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SkBitmap source; 108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch source.allocN32Pixels(800, 600); 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source.eraseARGB(255, 50, 150, 200); 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SkBitmap result = ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap( 1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) source, thumbnail_size, context.get()); 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(CLIP_RESULT_SOURCE_SAME_AS_TARGET, context->clip_result); 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(result.width(), copy_size.width()); 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(result.height(), copy_size.height()); 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(result.width(), source.width()); 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(result.height(), source.height()); 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The check below is a bit of a side effect: since the image was clipped 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // by scrollbar_size, it cannot be shrunk and thus what we get below is 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // true. 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR(result.width(), source.width(), gfx::scrollbar_size()); 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR(result.height(), source.height(), gfx::scrollbar_size()); 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) result = ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap( 1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) source, thumbnail_size, context.get()); 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(CLIP_RESULT_SOURCE_SAME_AS_TARGET, context->clip_result); 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(result.width(), copy_size.width()); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(result.height(), copy_size.height()); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(result.width(), source.width()); 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(result.height(), source.height()); 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(ContentBasedThumbnailingAlgorithmTest, CreateRetargetedThumbnail) { 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This tests the invocation of the main thumbnail-making apparatus. 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The actual content is not really of concern here, just check the plumbing. 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size image_size(1200, 800); 13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(image_size, 1.0f, true); 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The image consists of vertical non-overlapping stripes 150 pixels wide. 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) canvas.FillRect(gfx::Rect(200, 200, 800, 400), SkColorSetRGB(255, 255, 255)); 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SkBitmap source = 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ConsumerCallbackCatcher catcher; 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size thumbnail_size(432, 284); 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_refptr<ThumbnailingContext> context( 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ThumbnailingContext::CreateThumbnailingContextForTest()); 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) context->requested_copy_size = image_size; 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) context->clip_result = CLIP_RESULT_SOURCE_SAME_AS_TARGET; 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::MessageLoopForUI message_loop; 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) content::TestBrowserThread ui_thread(content::BrowserThread::UI, 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &message_loop); 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail( 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) source, 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) thumbnail_size, 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) context, 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&ConsumerCallbackCatcher::UiThreadCallback, 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Unretained(&catcher))); 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) message_loop.RunUntilIdle(); 160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ASSERT_TRUE(catcher.called_back()); 161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_TRUE(catcher.score().good_clipping); 162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_FALSE(catcher.captured_bitmap().empty()); 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(catcher.captured_bitmap().width(), source.width()); 164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(catcher.captured_bitmap().height(), source.height()); 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace thumbnails 168