diff options
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 3 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.h | 5 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 7 | ||||
-rw-r--r-- | chrome/browser/tab_contents/thumbnail_generator.cc | 169 | ||||
-rw-r--r-- | chrome/browser/tab_contents/thumbnail_generator.h | 49 | ||||
-rw-r--r-- | chrome/browser/tab_contents/thumbnail_generator_unittest.cc | 100 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 5 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | chrome/common/render_messages_params.cc | 2 | ||||
-rw-r--r-- | chrome/common/render_messages_params.h | 3 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 13 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 1 | ||||
-rw-r--r-- | chrome/renderer/render_widget.cc | 6 | ||||
-rw-r--r-- | chrome/renderer/render_widget.h | 4 |
15 files changed, 348 insertions, 22 deletions
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 26b3f4c..b9918e1 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -729,7 +729,8 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer( switches::kPpapiOutOfProcess, switches::kEnablePrintPreview, switches::kEnableCrxlessWebApps, - switches::kDisable3DAPIs + switches::kDisable3DAPIs, + switches::kEnableInBrowserThumbnailing, }; renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames, arraysize(kSwitchNames)); diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 4dae42f..b97923f 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -815,6 +815,8 @@ void RenderWidgetHost::OnMsgUpdateRect( // Update our knowledge of the RenderWidget's size. current_size_ = params.view_size; + // Update our knowledge of the RenderWidget's scroll offset. + last_scroll_offset_ = params.scroll_offset; bool is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags); diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 2eda8cd..bfefefa 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -393,6 +393,8 @@ class RenderWidgetHost : public IPC::Channel::Listener, // Activate deferred plugin handles. void ActivateDeferredPluginHandles(); + const gfx::Size& last_scroll_offset() const { return last_scroll_offset_; } + protected: // Internal implementation of the public Forward*Event() methods. void ForwardInputEvent(const WebKit::WebInputEvent& input_event, @@ -665,6 +667,9 @@ class RenderWidgetHost : public IPC::Channel::Listener, std::vector<gfx::PluginWindowHandle> deferred_plugin_handles_; + // The last scroll offset of the render widget. + gfx::Size last_scroll_offset_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHost); }; diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 2f975a7d..d852134 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -74,6 +74,7 @@ #include "chrome/browser/tab_contents/tab_contents_delegate.h" #include "chrome/browser/tab_contents/tab_contents_ssl_helper.h" #include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/browser/tab_contents/thumbnail_generator.h" #include "chrome/browser/tab_contents/web_navigation_observer.h" #include "chrome/browser/translate/page_translated_details.h" #include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" @@ -2378,6 +2379,12 @@ void TabContents::OnPageContents(const GURL& url, NotificationType::TAB_LANGUAGE_DETERMINED, Source<TabContents>(this), Details<std::string>(&lang)); + + // Generate the thumbnail here if the in-browser thumbnailing is enabled. + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableInBrowserThumbnailing)) { + ThumbnailGenerator::UpdateThumbnailIfNecessary(this, url); + } } void TabContents::OnPageTranslated(int32 page_id, diff --git a/chrome/browser/tab_contents/thumbnail_generator.cc b/chrome/browser/tab_contents/thumbnail_generator.cc index c370719..39d61f7 100644 --- a/chrome/browser/tab_contents/thumbnail_generator.cc +++ b/chrome/browser/tab_contents/thumbnail_generator.cc @@ -11,14 +11,22 @@ #include "base/scoped_ptr.h" #include "base/time.h" #include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/history/top_sites.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/backing_store.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/notification_service.h" #include "chrome/common/property_bag.h" +#include "chrome/common/thumbnail_score.h" +#include "gfx/color_utils.h" #include "gfx/rect.h" #include "gfx/skbitmap_operations.h" +#include "googleurl/src/gurl.h" +#include "skia/ext/bitmap_platform_device.h" +#include "skia/ext/image_operations.h" #include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -99,9 +107,12 @@ WidgetThumbnail* GetDataForHost(RenderWidgetHost* host) { // Creates a downsampled thumbnail for the given backing store. The returned // bitmap will be isNull if there was an error creating it. -SkBitmap GetBitmapForBackingStore(BackingStore* backing_store, - int desired_width, - int desired_height) { +SkBitmap GetBitmapForBackingStore( + BackingStore* backing_store, + int desired_width, + int desired_height, + int options, + ThumbnailGenerator::ClipResult* clip_result) { base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); SkBitmap result; @@ -115,20 +126,31 @@ SkBitmap GetBitmapForBackingStore(BackingStore* backing_store, return result; const SkBitmap& bmp = temp_canvas.getTopPlatformDevice().accessBitmap(false); - // Need to resize it to the size we want, so downsample until it's - // close, and let the caller make it the exact size if desired. - result = SkBitmapOperations::DownsampleByTwoUntilSize( - bmp, desired_width, desired_height); - - // This is a bit subtle. SkBitmaps are refcounted, but the magic - // ones in PlatformCanvas can't be assigned to SkBitmap with proper - // refcounting. If the bitmap doesn't change, then the downsampler - // will return the input bitmap, which will be the reference to the - // weird PlatformCanvas one insetad of a regular one. To get a - // regular refcounted bitmap, we need to copy it. - if (bmp.width() == result.width() && - bmp.height() == result.height()) - bmp.copyTo(&result, SkBitmap::kARGB_8888_Config); + // Check if a clipped thumbnail is requested. + if (options & ThumbnailGenerator::kClippedThumbnail) { + SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( + bmp, desired_width, desired_height, clip_result); + + // Need to resize it to the size we want, so downsample until it's + // close, and let the caller make it the exact size if desired. + result = SkBitmapOperations::DownsampleByTwoUntilSize( + clipped_bitmap, desired_width, desired_height); + } else { + // Need to resize it to the size we want, so downsample until it's + // close, and let the caller make it the exact size if desired. + result = SkBitmapOperations::DownsampleByTwoUntilSize( + bmp, desired_width, desired_height); + + // This is a bit subtle. SkBitmaps are refcounted, but the magic + // ones in PlatformCanvas can't be assigned to SkBitmap with proper + // refcounting. If the bitmap doesn't change, then the downsampler + // will return the input bitmap, which will be the reference to the + // weird PlatformCanvas one insetad of a regular one. To get a + // regular refcounted bitmap, we need to copy it. + if (bmp.width() == result.width() && + bmp.height() == result.height()) + bmp.copyTo(&result, SkBitmap::kARGB_8888_Config); + } HISTOGRAM_TIMES(kThumbnailHistogramName, base::TimeTicks::Now() - begin_compute_thumbnail); @@ -223,7 +245,9 @@ void ThumbnailGenerator::AskForSnapshot(RenderWidgetHost* renderer, // we'll go with it. SkBitmap first_try = GetBitmapForBackingStore(backing_store, desired_size.width(), - desired_size.height()); + desired_size.height(), + kNoOptions, + NULL); callback->Run(first_try); delete callback; @@ -275,6 +299,13 @@ void ThumbnailGenerator::AskForSnapshot(RenderWidgetHost* renderer, SkBitmap ThumbnailGenerator::GetThumbnailForRenderer( RenderWidgetHost* renderer) const { + return GetThumbnailForRendererWithOptions(renderer, kNoOptions, NULL); +} + +SkBitmap ThumbnailGenerator::GetThumbnailForRendererWithOptions( + RenderWidgetHost* renderer, + int options, + ClipResult* clip_result) const { WidgetThumbnail* wt = GetDataForHost(renderer); BackingStore* backing_store = renderer->GetBackingStore(false); @@ -299,7 +330,9 @@ SkBitmap ThumbnailGenerator::GetThumbnailForRenderer( // invalidated on the next paint. wt->thumbnail = GetBitmapForBackingStore(backing_store, kThumbnailWidth, - kThumbnailHeight); + kThumbnailHeight, + options, + clip_result); return wt->thumbnail; } @@ -320,7 +353,9 @@ void ThumbnailGenerator::WidgetWillDestroyBackingStore( // an existing thumbnail. SkBitmap new_thumbnail = GetBitmapForBackingStore(backing_store, kThumbnailWidth, - kThumbnailHeight); + kThumbnailHeight, + kNoOptions, + NULL); if (!new_thumbnail.isNull()) wt->thumbnail = new_thumbnail; } @@ -534,3 +569,97 @@ void ThumbnailGenerator::EraseHostFromShownList(RenderWidgetHost* widget) { if (found != shown_hosts_.end()) shown_hosts_.erase(found); } + +double ThumbnailGenerator::CalculateBoringScore(SkBitmap* bitmap) { + if (bitmap->isNull() || bitmap->empty()) + return 1.0; + int histogram[256] = {0}; + color_utils::BuildLumaHistogram(bitmap, histogram); + + int color_count = *std::max_element(histogram, histogram + 256); + int pixel_count = bitmap->width() * bitmap->height(); + return static_cast<double>(color_count) / pixel_count; +} + +SkBitmap ThumbnailGenerator::GetClippedBitmap(const SkBitmap& bitmap, + int desired_width, + int desired_height, + ClipResult* clip_result) { + const SkRect dest_rect = { 0, 0, + SkIntToScalar(desired_width), + SkIntToScalar(desired_height) }; + const float dest_aspect = dest_rect.width() / dest_rect.height(); + + // Get the src rect so that we can preserve the aspect ratio while filling + // the destination. + SkIRect src_rect; + if (bitmap.width() < dest_rect.width() || + bitmap.height() < dest_rect.height()) { + // Source image is smaller: we clip the part of source image within the + // dest rect, and then stretch it to fill the dest rect. We don't respect + // the aspect ratio in this case. + src_rect.set(0, 0, static_cast<S16CPU>(dest_rect.width()), + static_cast<S16CPU>(dest_rect.height())); + if (clip_result) + *clip_result = ThumbnailGenerator::kSourceIsSmaller; + } else { + const float src_aspect = + static_cast<float>(bitmap.width()) / bitmap.height(); + if (src_aspect > dest_aspect) { + // Wider than tall, clip horizontally: we center the smaller + // thumbnail in the wider screen. + S16CPU new_width = static_cast<S16CPU>(bitmap.height() * dest_aspect); + S16CPU x_offset = (bitmap.width() - new_width) / 2; + src_rect.set(x_offset, 0, new_width + x_offset, bitmap.height()); + if (clip_result) + *clip_result = ThumbnailGenerator::kWiderThanTall; + } else if (src_aspect < dest_aspect) { + src_rect.set(0, 0, bitmap.width(), + static_cast<S16CPU>(bitmap.width() / dest_aspect)); + if (clip_result) + *clip_result = ThumbnailGenerator::kTallerThanWide; + } else { + src_rect.set(0, 0, bitmap.width(), bitmap.height()); + if (clip_result) + *clip_result = ThumbnailGenerator::kNotClipped; + } + } + + SkBitmap clipped_bitmap; + bitmap.extractSubset(&clipped_bitmap, src_rect); + return clipped_bitmap; +} + +void ThumbnailGenerator::UpdateThumbnailIfNecessary( + TabContents* tab_contents, const GURL& url) { + if (tab_contents->profile()->IsOffTheRecord() || + (url.SchemeIs("chrome") && url.host() == "newtab")) + return; + // TODO(satorux): Add more conditions here to avoid unnecessary + // thumbnail generation. + + ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator(); + const int options = ThumbnailGenerator::kClippedThumbnail; + ThumbnailGenerator::ClipResult clip_result = ThumbnailGenerator::kNotClipped; + SkBitmap thumbnail = generator->GetThumbnailForRendererWithOptions( + tab_contents->render_view_host(), options, &clip_result); + // Failed to generate a thumbnail. Maybe the tab is in the background? + if (thumbnail.isNull()) + return; + + // Compute the thumbnail score. + ThumbnailScore score; + score.at_top = + (tab_contents->render_view_host()->last_scroll_offset().height() == 0); + score.boring_score = ThumbnailGenerator::CalculateBoringScore(&thumbnail); + score.good_clipping = + (clip_result == ThumbnailGenerator::kTallerThanWide || + clip_result == ThumbnailGenerator::kNotClipped); + + history::TopSites* top_sites = tab_contents->profile()->GetTopSites(); + top_sites->SetPageThumbnail(url, thumbnail, score); + VLOG(1) << "Thumbnail taken for " << url + << ", at_top: " << score.at_top + << ", boring_score: " << score.boring_score + << ", good_clipping: " << score.good_clipping; +} diff --git a/chrome/browser/tab_contents/thumbnail_generator.h b/chrome/browser/tab_contents/thumbnail_generator.h index 1952b53..de57c21 100644 --- a/chrome/browser/tab_contents/thumbnail_generator.h +++ b/chrome/browser/tab_contents/thumbnail_generator.h @@ -18,6 +18,7 @@ #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" +class GURL; class RenderWidgetHost; class SkBitmap; class TabContents; @@ -25,6 +26,27 @@ class TabContents; class ThumbnailGenerator : NotificationObserver { public: typedef Callback1<const SkBitmap&>::Type ThumbnailReadyCallback; + // The result of clipping. This can be used to determine if the + // generated thumbnail is good or not. + enum ClipResult { + // The source image is smaller. + kSourceIsSmaller, + // Wider than tall, clip horizontally. + kWiderThanTall, + // Taller than wide, clip vertically. + kTallerThanWide, + // The source and destination aspect ratios are identical. + kNotClipped, + }; + + // Bitmasks of options for generating a thumbnail. + enum ThumbnailOptions { + // No options. + kNoOptions = 0, + // Request a clipped thumbnail with the aspect ratio preserved. + kClippedThumbnail = 1 << 0, + }; + // This class will do nothing until you call StartThumbnailing. ThumbnailGenerator(); ~ThumbnailGenerator(); @@ -60,6 +82,13 @@ class ThumbnailGenerator : NotificationObserver { // renderer. SkBitmap GetThumbnailForRenderer(RenderWidgetHost* renderer) const; + // This returns a thumbnail of a fixed, small size for the given + // renderer. |options| is a bitmask of ThumbnailOptions. If + // |clip_result| is non-NULL, the result of clipping will be written. + SkBitmap GetThumbnailForRendererWithOptions(RenderWidgetHost* renderer, + int options, + ClipResult* clip_result) const; + // Start or stop monitoring notifications for |renderer| based on the value // of |monitor|. void MonitorRenderer(RenderWidgetHost* renderer, bool monitor); @@ -72,6 +101,26 @@ class ThumbnailGenerator : NotificationObserver { void set_no_timeout(bool no_timeout) { no_timeout_ = no_timeout; } #endif + // Calculates how "boring" a thumbnail is. The boring score is the + // 0,1 ranged percentage of pixels that are the most common + // luma. Higher boring scores indicate that a higher percentage of a + // bitmap are all the same brightness. + static double CalculateBoringScore(SkBitmap* bitmap); + + // Gets the clipped bitmap from |bitmap| per the aspect ratio of the + // desired width and the desired height. For instance, if the input + // bitmap is vertically long (ex. 400x900) and the desired size is + // square (ex. 100x100), the clipped bitmap will be the top half of the + // input bitmap (400x400). + static SkBitmap GetClippedBitmap(const SkBitmap& bitmap, + int desired_width, + int desired_height, + ClipResult* clip_result); + + // Update the thumbnail of the given URL if necessary. + static void UpdateThumbnailIfNecessary(TabContents* tab_contents, + const GURL& url); + private: // RenderWidgetHostPaintingObserver implementation. virtual void WidgetWillDestroyBackingStore(RenderWidgetHost* widget, diff --git a/chrome/browser/tab_contents/thumbnail_generator_unittest.cc b/chrome/browser/tab_contents/thumbnail_generator_unittest.cc index 787873c..7c7f601 100644 --- a/chrome/browser/tab_contents/thumbnail_generator_unittest.cc +++ b/chrome/browser/tab_contents/thumbnail_generator_unittest.cc @@ -11,6 +11,7 @@ #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" #include "chrome/test/testing_profile.h" +#include "gfx/canvas_skia.h" #include "skia/ext/platform_canvas.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColorPriv.h" @@ -178,3 +179,102 @@ TEST_F(ThumbnailGeneratorTest, QuickShow) { } #endif + +TEST(ThumbnailGeneratorSimpleTest, CalculateBoringScore_Empty) { + SkBitmap bitmap; + EXPECT_DOUBLE_EQ(1.0, ThumbnailGenerator::CalculateBoringScore(&bitmap)); +} + +TEST(ThumbnailGeneratorSimpleTest, CalculateBoringScore_SingleColor) { + const SkColor kBlack = SkColorSetRGB(0, 0, 0); + const gfx::Size kSize(20, 10); + gfx::CanvasSkia canvas(kSize.width(), kSize.height(), true); + // Fill all pixesl in black. + canvas.FillRectInt(kBlack, 0, 0, kSize.width(), kSize.height()); + + SkBitmap bitmap = canvas.getTopPlatformDevice().accessBitmap(false); + // The thumbnail should deserve the highest boring score. + EXPECT_DOUBLE_EQ(1.0, ThumbnailGenerator::CalculateBoringScore(&bitmap)); +} + +TEST(ThumbnailGeneratorSimpleTest, CalculateBoringScore_TwoColors) { + const SkColor kBlack = SkColorSetRGB(0, 0, 0); + const SkColor kWhite = SkColorSetRGB(0xFF, 0xFF, 0xFF); + const gfx::Size kSize(20, 10); + + gfx::CanvasSkia canvas(kSize.width(), kSize.height(), true); + // Fill all pixesl in black. + canvas.FillRectInt(kBlack, 0, 0, kSize.width(), kSize.height()); + // Fill the left half pixels in white. + canvas.FillRectInt(kWhite, 0, 0, kSize.width() / 2, kSize.height()); + + SkBitmap bitmap = canvas.getTopPlatformDevice().accessBitmap(false); + ASSERT_EQ(kSize.width(), bitmap.width()); + ASSERT_EQ(kSize.height(), bitmap.height()); + // The thumbnail should be less boring because two colors are used. + EXPECT_DOUBLE_EQ(0.5, ThumbnailGenerator::CalculateBoringScore(&bitmap)); +} + +TEST(ThumbnailGeneratorSimpleTest, GetClippedBitmap_TallerThanWide) { + // The input bitmap is vertically long. + gfx::CanvasSkia canvas(40, 90, true); + const SkBitmap bitmap = canvas.getTopPlatformDevice().accessBitmap(false); + + // The desired size is square. + ThumbnailGenerator::ClipResult clip_result = ThumbnailGenerator::kNotClipped; + SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( + bitmap, 10, 10, &clip_result); + // The clipped bitmap should be square. + EXPECT_EQ(40, clipped_bitmap.width()); + EXPECT_EQ(40, clipped_bitmap.height()); + // The input was taller than wide. + EXPECT_EQ(ThumbnailGenerator::kTallerThanWide, clip_result); +} + +TEST(ThumbnailGeneratorSimpleTest, GetClippedBitmap_WiderThanTall) { + // The input bitmap is horizontally long. + gfx::CanvasSkia canvas(90, 40, true); + const SkBitmap bitmap = canvas.getTopPlatformDevice().accessBitmap(false); + + // The desired size is square. + ThumbnailGenerator::ClipResult clip_result = ThumbnailGenerator::kNotClipped; + SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( + bitmap, 10, 10, &clip_result); + // The clipped bitmap should be square. + EXPECT_EQ(40, clipped_bitmap.width()); + EXPECT_EQ(40, clipped_bitmap.height()); + // The input was wider than tall. + EXPECT_EQ(ThumbnailGenerator::kWiderThanTall, clip_result); +} + +TEST(ThumbnailGeneratorSimpleTest, GetClippedBitmap_NotClipped) { + // The input bitmap is square. + gfx::CanvasSkia canvas(40, 40, true); + const SkBitmap bitmap = canvas.getTopPlatformDevice().accessBitmap(false); + + // The desired size is square. + ThumbnailGenerator::ClipResult clip_result = ThumbnailGenerator::kNotClipped; + SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( + bitmap, 10, 10, &clip_result); + // The clipped bitmap should be square. + EXPECT_EQ(40, clipped_bitmap.width()); + EXPECT_EQ(40, clipped_bitmap.height()); + // There was no need to clip. + EXPECT_EQ(ThumbnailGenerator::kNotClipped, clip_result); +} + +TEST(ThumbnailGeneratorSimpleTest, GetClippedBitmap_NonSquareOutput) { + // The input bitmap is square. + gfx::CanvasSkia canvas(40, 40, true); + const SkBitmap bitmap = canvas.getTopPlatformDevice().accessBitmap(false); + + // The desired size is horizontally long. + ThumbnailGenerator::ClipResult clip_result = ThumbnailGenerator::kNotClipped; + SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( + bitmap, 20, 10, &clip_result); + // The clipped bitmap should have the same aspect ratio of the desired size. + EXPECT_EQ(40, clipped_bitmap.width()); + EXPECT_EQ(20, clipped_bitmap.height()); + // The input was taller than wide. + EXPECT_EQ(ThumbnailGenerator::kTallerThanWide, clip_result); +} diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 1a86bcd..f781baf 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -497,6 +497,11 @@ const char kEnableFastback[] = "enable-fastback"; // testing, for example page cycler and layout tests. See bug 1157243. const char kEnableFileCookies[] = "enable-file-cookies"; +// Enable the in-browser thumbnailing, which is more efficient than the +// in-renderer thumbnailing, as we can use more information to determine +// if we need to update thumbnails. +const char kEnableInBrowserThumbnailing[] = "enable-in-browser-thumbnailing"; + // Enable IPv6 support, even if probes suggest that it may not be fully // supported. Some probes may require internet connections, and this flag will // allow support independent of application testing. diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index d23b724..aa9c42d 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -149,6 +149,7 @@ extern const char kEnableExtensionTimelineApi[]; extern const char kEnableFastback[]; extern const char kEnableFileCookies[]; extern const char kEnableGPUPlugin[]; +extern const char kEnableInBrowserThumbnailing[]; extern const char kEnableIPv6[]; extern const char kEnableLogging[]; extern const char kEnableMemoryInfo[]; diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc index 91d7ba7..c93423f 100644 --- a/chrome/common/render_messages_params.cc +++ b/chrome/common/render_messages_params.cc @@ -790,6 +790,7 @@ void ParamTraits<ViewHostMsg_UpdateRect_Params>::Write( WriteParam(m, p.dx); WriteParam(m, p.dy); WriteParam(m, p.scroll_rect); + WriteParam(m, p.scroll_offset); WriteParam(m, p.copy_rects); WriteParam(m, p.view_size); WriteParam(m, p.resizer_rect); @@ -805,6 +806,7 @@ bool ParamTraits<ViewHostMsg_UpdateRect_Params>::Read( ReadParam(m, iter, &p->dx) && ReadParam(m, iter, &p->dy) && ReadParam(m, iter, &p->scroll_rect) && + ReadParam(m, iter, &p->scroll_offset) && ReadParam(m, iter, &p->copy_rects) && ReadParam(m, iter, &p->view_size) && ReadParam(m, iter, &p->resizer_rect) && diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h index 20d8470..11fe638 100644 --- a/chrome/common/render_messages_params.h +++ b/chrome/common/render_messages_params.h @@ -344,6 +344,9 @@ struct ViewHostMsg_UpdateRect_Params { // The rectangular region to scroll. gfx::Rect scroll_rect; + // The scroll offset of the render view. + gfx::Size scroll_offset; + // The regions of the bitmap (in view coords) that contain updated pixels. // In the case of scrolling, this includes the scroll damage rect. std::vector<gfx::Rect> copy_rects; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 151d927..c7df8bf 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1227,7 +1227,13 @@ void RenderView::CapturePageInfo(int load_id, bool preliminary_capture) { TranslateHelper::IsPageTranslatable(&document))); } - OnCaptureThumbnail(); + // Generate the thumbnail here if the in-browser thumbnailing isn't + // enabled. TODO(satorux): Remove this and related code once + // crbug.com/65936 is complete. + if (!CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableInBrowserThumbnailing)) { + OnCaptureThumbnail(); + } if (phishing_delegate_.get()) phishing_delegate_->FinishedLoad(&contents); @@ -5175,6 +5181,11 @@ webkit::ppapi::PluginInstance* RenderView::GetBitmapForOptimizedPluginPaint( paint_bounds, dib, location, clip); } +gfx::Size RenderView::GetScrollOffset() { + WebKit::WebSize scroll_offset = webview()->mainFrame()->scrollOffset(); + return gfx::Size(scroll_offset.width, scroll_offset.height); +} + void RenderView::OnClearFocusedNode() { if (webview()) webview()->clearFocusedNode(); diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 2f4729a..fa357c4 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -665,6 +665,7 @@ class RenderView : public RenderWidget, TransportDIB** dib, gfx::Rect* location, gfx::Rect* clip); + virtual gfx::Size GetScrollOffset(); virtual void DidHandleKeyEvent(); virtual void DidHandleMouseEvent(const WebKit::WebMouseEvent& event); virtual void OnSetFocus(bool enable); diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index 7fb9e4a..ba01020 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -585,6 +585,7 @@ void RenderWidget::DoDeferredUpdate() { params.resizer_rect = resizer_rect_; params.plugin_window_moves.swap(plugin_window_moves_); params.flags = next_paint_flags_; + params.scroll_offset = GetScrollOffset(); update_reply_pending_ = true; Send(new ViewHostMsg_UpdateRect(routing_id_, params)); @@ -920,6 +921,11 @@ webkit::ppapi::PluginInstance* RenderWidget::GetBitmapForOptimizedPluginPaint( return NULL; } +gfx::Size RenderWidget::GetScrollOffset() { + // Bare RenderWidgets don't support scroll offset. + return gfx::Size(0, 0); +} + void RenderWidget::SetHidden(bool hidden) { if (is_hidden_ == hidden) return; diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h index 33d0205..71a065e 100644 --- a/chrome/renderer/render_widget.h +++ b/chrome/renderer/render_widget.h @@ -219,6 +219,10 @@ class RenderWidget : public IPC::Channel::Listener, gfx::Rect* location, gfx::Rect* clip); + // Gets the scroll offset of this widget, if this widget has a notion of + // scroll offset. + virtual gfx::Size GetScrollOffset(); + // Sets the "hidden" state of this widget. All accesses to is_hidden_ should // use this method so that we can properly inform the RenderThread of our // state. |