summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rwxr-xr-x[-rw-r--r--]chrome/DEPS4
-rwxr-xr-x[-rw-r--r--]chrome/browser/DEPS1
-rw-r--r--chrome/browser/browser_process_impl.h11
-rw-r--r--chrome/browser/profile.cc2
-rw-r--r--chrome/browser/renderer_host/backing_store.h30
-rw-r--r--chrome/browser/renderer_host/backing_store_mac.cc5
-rw-r--r--chrome/browser/renderer_host/backing_store_manager.cc51
-rw-r--r--chrome/browser/renderer_host/backing_store_manager.h5
-rw-r--r--chrome/browser/renderer_host/backing_store_win.cc5
-rw-r--r--chrome/browser/renderer_host/backing_store_x.cc38
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc35
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h33
-rwxr-xr-xchrome/browser/renderer_host/render_widget_host_painting_observer.h24
-rw-r--r--chrome/browser/renderer_host/render_widget_host_unittest.cc16
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc22
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h62
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm4
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc4
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.cc9
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.h3
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.cc8
-rwxr-xr-xchrome/browser/tab_contents/thumbnail_generator.cc321
-rwxr-xr-xchrome/browser/tab_contents/thumbnail_generator.h75
-rwxr-xr-xchrome/browser/tab_contents/thumbnail_generator_unittest.cc179
-rw-r--r--chrome/chrome.gyp3
-rw-r--r--chrome/common/notification_type.h11
-rw-r--r--chrome/common/property_bag.h2
-rwxr-xr-x[-rw-r--r--]chrome/common/transport_dib.h8
-rwxr-xr-x[-rw-r--r--]chrome/common/transport_dib_linux.cc6
-rwxr-xr-x[-rw-r--r--]chrome/common/transport_dib_mac.cc6
-rwxr-xr-x[-rw-r--r--]chrome/common/transport_dib_win.cc5
-rwxr-xr-x[-rw-r--r--]chrome/renderer/DEPS1
-rw-r--r--chrome/renderer/render_process.cc17
-rw-r--r--chrome/test/unit/unittests.vcproj4
34 files changed, 872 insertions, 138 deletions
diff --git a/chrome/DEPS b/chrome/DEPS
index 3c413c6..bb61606 100644..100755
--- a/chrome/DEPS
+++ b/chrome/DEPS
@@ -24,8 +24,8 @@ include_rules = [
# Allow usage of Google Toolbox for Mac.
"+third_party/GTM",
- # Brett's test. Contact him for questions.
- "+frame_window",
+ # Our Skia extensions.
+ "+skia/ext",
# On Linux, we include some breakpad headers
"+breakpad/linux",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 90a473f..a18a7a56 100644..100755
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -8,7 +8,6 @@ include_rules = [
"+grit", # For generated headers
"+sandbox/src",
"+skia/include",
- "+skia/ext",
"+webkit/default_plugin",
"+webkit/glue", # Defines some types that are marshalled over IPC.
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index f056476..27ce62acd 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -18,6 +18,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/tab_contents/thumbnail_generator.h"
#if defined(OS_WIN)
#include "sandbox/src/sandbox.h"
@@ -270,6 +271,16 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
bool checked_for_new_frames_;
bool using_new_frames_;
+#if defined(LINUX2)
+ // TODO(brettw) enable this for all builds when we have a need for it. This
+ // component has some overhead, so we don't want to have it running without
+ // any consumers. Since it integrates by listening to notifications, it's
+ // sufficient to just not instatiate it to make it disabled.
+
+ // This service just sits around and makes thumanails for tabs.
+ ThumbnailGenerator thumbnail_generator_;
+#endif
+
// An event that notifies when we are shutting-down.
scoped_ptr<base::WaitableEvent> shutdown_event_;
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index b19fb2d7..3e8b196 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extensions_service.h"
@@ -29,7 +30,6 @@
#include "chrome/browser/spellchecker.h"
#include "chrome/browser/ssl/ssl_host_state.h"
#include "chrome/browser/thumbnail_store.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/visitedlink_master.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 5d817d0..0fb47ab 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -21,6 +21,7 @@
#endif
class RenderWidgetHost;
+class SkBitmap;
class TransportDIB;
// BackingStore ----------------------------------------------------------------
@@ -29,31 +30,31 @@ class TransportDIB;
class BackingStore {
public:
#if defined(OS_WIN) || defined(OS_MACOSX)
- explicit BackingStore(const gfx::Size& size);
+ BackingStore(RenderWidgetHost* widget, const gfx::Size& size);
#elif defined(OS_LINUX)
- // Create a backing store on the X server.
- // size: the size of the server-side pixmap
- // x_connection: the display to target
- // depth: the depth of the X window which will be drawn into
- // visual: An Xlib Visual describing the format of the target window
- // root_window: The X id of the root window
- // use_render: if true, the X server supports Xrender
- // use_shared_memory: if true, the X server is local
- BackingStore(const gfx::Size& size, Display* x_connection, int depth,
- void* visual, XID root_window, bool use_render,
- bool use_shared_memory);
+ // Create a backing store on the X server. The visual is an Xlib Visual
+ // describing the format of the target window and the depth is the color
+ // depth of the X window which will be drawn into.
+ BackingStore(RenderWidgetHost* widget,
+ const gfx::Size& size,
+ void* visual,
+ int depth);
+
// This is for unittesting only. An object constructed using this constructor
// will silently ignore all paints
- explicit BackingStore(const gfx::Size& size);
+ BackingStore(RenderWidgetHost* widget, const gfx::Size& size);
#endif
~BackingStore();
+ RenderWidgetHost* render_widget_host() const { return render_widget_host_; }
const gfx::Size& size() { return size_; }
#if defined(OS_WIN)
HDC hdc() { return hdc_; }
+
#elif defined(OS_MACOSX)
skia::PlatformCanvas* canvas() { return &canvas_; }
+
#elif defined(OS_LINUX)
// Copy from the server-side backing store to the target window
// display: the display of the backing store and target window
@@ -77,6 +78,9 @@ class BackingStore {
const gfx::Size& view_size);
private:
+ // The owner of this backing store.
+ RenderWidgetHost* render_widget_host_;
+
// The size of the backing store.
gfx::Size size_;
diff --git a/chrome/browser/renderer_host/backing_store_mac.cc b/chrome/browser/renderer_host/backing_store_mac.cc
index 569e3f6..2395a6c 100644
--- a/chrome/browser/renderer_host/backing_store_mac.cc
+++ b/chrome/browser/renderer_host/backing_store_mac.cc
@@ -10,8 +10,9 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
-BackingStore::BackingStore(const gfx::Size& size)
- : size_(size) {
+BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
+ : render_widget_host_(widget),
+ size_(size) {
if (!canvas_.initialize(size.width(), size.height(), true))
SK_CRASH();
}
diff --git a/chrome/browser/renderer_host/backing_store_manager.cc b/chrome/browser/renderer_host/backing_store_manager.cc
index 3ff2e76..7b16a43 100644
--- a/chrome/browser/renderer_host/backing_store_manager.cc
+++ b/chrome/browser/renderer_host/backing_store_manager.cc
@@ -7,6 +7,7 @@
#include "base/sys_info.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
#include "chrome/common/chrome_constants.h"
namespace {
@@ -15,35 +16,59 @@ typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache;
static BackingStoreCache* cache = NULL;
// Returns the size of the backing store cache.
-static int GetBackingStoreCacheSize() {
+static size_t GetBackingStoreCacheSize() {
// This uses a similar approach to GetMaxRendererProcessCount. The goal
// is to reduce memory pressure and swapping on low-resource machines.
- static const int kMaxDibCountByRamTier[] = {
+ static const size_t kMaxDibCountByRamTier[] = {
2, // less than 256MB
3, // 256MB
4, // 512MB
5 // 768MB and above
};
- static int max_size = kMaxDibCountByRamTier[
+ static size_t max_size = kMaxDibCountByRamTier[
std::min(base::SysInfo::AmountOfPhysicalMemoryMB() / 256,
static_cast<int>(arraysize(kMaxDibCountByRamTier)) - 1)];
return max_size;
}
+// Expires the given backing store from the cache.
+void ExpireBackingStoreAt(BackingStoreCache::iterator backing_store) {
+ RenderWidgetHost* rwh = backing_store->second->render_widget_host();
+ if (rwh->painting_observer()) {
+ rwh->painting_observer()->WidgetWillDestroyBackingStore(
+ backing_store->first,
+ backing_store->second);
+ }
+ cache->Erase(backing_store);
+}
+
// Creates the backing store for the host based on the dimensions passed in.
// Removes the existing backing store if there is one.
BackingStore* CreateBackingStore(RenderWidgetHost* host,
const gfx::Size& backing_store_size) {
+ // Remove any existing backing store in case we're replacing it.
BackingStoreManager::RemoveBackingStore(host);
+ size_t max_cache_size = GetBackingStoreCacheSize();
+ if (max_cache_size > 0 && !cache)
+ cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
+
+ if (cache->size() >= max_cache_size) {
+ // Need to remove an old backing store to make room for the new one. We
+ // don't want to do this when the backing store is being replace by a new
+ // one for the same tab, but this case won't get called then: we'll have
+ // removed the onld one in the RemoveBackingStore above, and the cache
+ // won't be over-sized.
+ //
+ // Crazy C++ alert: rbegin.base() is a forward iterator pointing to end(),
+ // so we need to do -- to move one back to the actual last item.
+ ExpireBackingStoreAt(--cache->rbegin().base());
+ }
+
BackingStore* backing_store = host->AllocBackingStore(backing_store_size);
- int backing_store_cache_size = GetBackingStoreCacheSize();
- if (backing_store_cache_size > 0) {
- if (!cache)
- cache = new BackingStoreCache(backing_store_cache_size);
+ if (max_cache_size > 0)
cache->Put(host, backing_store);
- }
return backing_store;
}
@@ -110,7 +135,6 @@ void BackingStoreManager::RemoveBackingStore(RenderWidgetHost* host) {
BackingStoreCache::iterator it = cache->Peek(host);
if (it == cache->end())
return;
-
cache->Erase(it);
if (cache->empty()) {
@@ -118,3 +142,12 @@ void BackingStoreManager::RemoveBackingStore(RenderWidgetHost* host) {
cache = NULL;
}
}
+
+// static
+bool BackingStoreManager::ExpireBackingStoreForTest(RenderWidgetHost* host) {
+ BackingStoreCache::iterator it = cache->Peek(host);
+ if (it == cache->end())
+ return false;
+ ExpireBackingStoreAt(it);
+ return true;
+}
diff --git a/chrome/browser/renderer_host/backing_store_manager.h b/chrome/browser/renderer_host/backing_store_manager.h
index 5b929f6..3078a93 100644
--- a/chrome/browser/renderer_host/backing_store_manager.h
+++ b/chrome/browser/renderer_host/backing_store_manager.h
@@ -58,6 +58,11 @@ class BackingStoreManager {
// Removes the backing store for the host.
static void RemoveBackingStore(RenderWidgetHost* host);
+ // Expires the given backing store. This emulates something getting evicted
+ // from the cache for the purpose of testing. Returns true if the host was
+ // removed, false if it wasn't found.
+ static bool ExpireBackingStoreForTest(RenderWidgetHost* host);
+
private:
// Not intended for instantiation.
BackingStoreManager() {}
diff --git a/chrome/browser/renderer_host/backing_store_win.cc b/chrome/browser/renderer_host/backing_store_win.cc
index 1241e42..b3a1839 100644
--- a/chrome/browser/renderer_host/backing_store_win.cc
+++ b/chrome/browser/renderer_host/backing_store_win.cc
@@ -25,8 +25,9 @@ HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) {
// BackingStore (Windows) ------------------------------------------------------
-BackingStore::BackingStore(const gfx::Size& size)
- : size_(size),
+BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
+ : render_widget_host_(widget),
+ size_(size),
backing_store_dib_(NULL),
original_bitmap_(NULL) {
HDC screen_dc = ::GetDC(NULL);
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
index 6cb7c91..52fd7dc 100644
--- a/chrome/browser/renderer_host/backing_store_x.cc
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -24,41 +24,39 @@
// shared memory or over the wire, and XRENDER is used to convert them to the
// correct format for the backing store.
-BackingStore::BackingStore(const gfx::Size& size,
- Display* display,
- int depth,
+BackingStore::BackingStore(RenderWidgetHost* widget,
+ const gfx::Size& size,
void* visual,
- Drawable root_window,
- bool use_render,
- bool use_shared_memory)
- : size_(size),
- display_(display),
- use_shared_memory_(use_shared_memory),
- use_render_(use_render),
+ int depth)
+ : render_widget_host_(widget),
+ size_(size),
+ display_(x11_util::GetXDisplay()),
+ use_shared_memory_(x11_util::QuerySharedMemorySupport(display_)),
+ use_render_(x11_util::QueryRenderSupport(display_)),
visual_depth_(depth),
- root_window_(root_window) {
- const int width = size.width();
- const int height = size.height();
-
+ root_window_(x11_util::GetX11RootWindow()) {
COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
- pixmap_ = XCreatePixmap(display_, root_window, width, height, depth);
+ pixmap_ = XCreatePixmap(display_, root_window_,
+ size.width(), size.height(), depth);
if (use_render_) {
picture_ = XRenderCreatePicture(
display_, pixmap_,
- x11_util::GetRenderVisualFormat(display_, static_cast<Visual*>(visual)),
- 0, NULL);
+ x11_util::GetRenderVisualFormat(display_,
+ static_cast<Visual*>(visual)),
+ 0, NULL);
} else {
picture_ = 0;
- pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display, depth);
+ pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display_, depth);
}
pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
}
-BackingStore::BackingStore(const gfx::Size& size)
- : size_(size),
+BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
+ : render_widget_host_(widget),
+ size_(size),
display_(NULL),
use_shared_memory_(false),
use_render_(false),
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index fccd45d..51d2b3b 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/renderer_host/backing_store_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_helper.h"
+#include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
@@ -49,6 +50,7 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process,
: renderer_initialized_(false),
view_(NULL),
process_(process),
+ painting_observer_(NULL),
routing_id_(routing_id),
is_loading_(false),
is_hidden_(false),
@@ -142,6 +144,12 @@ void RenderWidgetHost::WasHidden() {
// Tell the RenderProcessHost we were hidden.
process_->WidgetHidden();
+
+ bool is_visible = false;
+ NotificationService::current()->Notify(
+ NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED,
+ Source<RenderWidgetHost>(this),
+ Details<bool>(&is_visible));
}
void RenderWidgetHost::WasRestored() {
@@ -163,6 +171,12 @@ void RenderWidgetHost::WasRestored() {
Send(new ViewMsg_WasRestored(routing_id_, needs_repainting));
process_->WidgetRestored();
+
+ bool is_visible = true;
+ NotificationService::current()->Notify(
+ NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED,
+ Source<RenderWidgetHost>(this),
+ Details<bool>(&is_visible));
}
void RenderWidgetHost::WasResized() {
@@ -217,10 +231,13 @@ void RenderWidgetHost::SetIsLoading(bool is_loading) {
view_->SetIsLoading(is_loading);
}
-BackingStore* RenderWidgetHost::GetBackingStore() {
+BackingStore* RenderWidgetHost::GetBackingStore(bool force_create) {
// We should not be asked to paint while we are hidden. If we are hidden,
- // then it means that our consumer failed to call WasRestored.
- DCHECK(!is_hidden_) << "GetBackingStore called while hidden!";
+ // then it means that our consumer failed to call WasRestored. If we're not
+ // force creating the backing store, it's OK since we can feel free to give
+ // out our cached one if we have it.
+ DCHECK(!is_hidden_ || !force_create) <<
+ "GetBackingStore called while hidden!";
// We should never be called recursively; this can theoretically lead to
// infinite recursion and almost certainly leads to lower performance.
@@ -230,6 +247,11 @@ BackingStore* RenderWidgetHost::GetBackingStore() {
// We might have a cached backing store that we can reuse!
BackingStore* backing_store =
BackingStoreManager::GetBackingStore(this, current_size_);
+ if (!force_create) {
+ in_get_backing_store_ = false;
+ return backing_store;
+ }
+
// If we fail to find a backing store in the cache, send out a request
// to the renderer to paint the view if required.
if (!backing_store && !repaint_ack_pending_ && !resize_ack_pending_ &&
@@ -259,7 +281,6 @@ BackingStore* RenderWidgetHost::GetBackingStore() {
BackingStore* RenderWidgetHost::AllocBackingStore(const gfx::Size& size) {
if (!view_)
return NULL;
-
return view_->AllocBackingStore(size);
}
@@ -549,6 +570,9 @@ void RenderWidgetHost::OnMsgPaintRect(
}
}
+ if (painting_observer_)
+ painting_observer_->WidgetDidUpdateBackingStore(this);
+
// Log the time delta for processing a paint message.
TimeDelta delta = TimeTicks::Now() - paint_start;
UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgPaintRect", delta);
@@ -595,6 +619,9 @@ void RenderWidgetHost::OnMsgScrollRect(
view_being_painted_ = false;
}
+ if (painting_observer_)
+ painting_observer_->WidgetDidUpdateBackingStore(this);
+
// Log the time delta for processing a scroll message.
TimeDelta delta = TimeTicks::Now() - scroll_start;
UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgScrollRect", delta);
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index 0645496..c5913ef 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -14,6 +14,7 @@
#include "base/timer.h"
#include "chrome/common/ipc_channel.h"
#include "chrome/common/native_web_keyboard_event.h"
+#include "chrome/common/property_bag.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "webkit/glue/webtextdirection.h"
@@ -31,6 +32,7 @@ class BackingStore;
class PaintObserver;
class RenderProcessHost;
class RenderWidgetHostView;
+class RenderWidgetHostPaintingObserver;
class TransportDIB;
class WebCursor;
struct ViewHostMsg_PaintRect_Params;
@@ -140,6 +142,22 @@ class RenderWidgetHost : public IPC::Channel::Listener {
paint_observer_.reset(paint_observer);
}
+ // Returns the property bag for this widget, where callers can add extra data
+ // they may wish to associate with it. Returns a pointer rather than a
+ // reference since the PropertyAccessors expect this.
+ const PropertyBag* property_bag() const { return &property_bag_; }
+ PropertyBag* property_bag() { return &property_bag_; }
+
+ // The painting observer that will be called for paint events. This
+ // pointer's ownership will remain with the caller and must remain valid
+ // until this class is destroyed or the observer is replaced.
+ RenderWidgetHostPaintingObserver* painting_observer() const {
+ return painting_observer_;
+ }
+ void set_painting_observer(RenderWidgetHostPaintingObserver* observer) {
+ painting_observer_ = observer;
+ }
+
// Called when a renderer object already been created for this host, and we
// just need to be attached to it. Used for window.open, <select> dropdown
// menus, and other times when the renderer initiates creating an object.
@@ -182,9 +200,11 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// Get access to the widget's backing store. If a resize is in progress,
// then the current size of the backing store may be less than the size of
- // the widget's view. This method returns NULL if the backing store could
- // not be created.
- BackingStore* GetBackingStore();
+ // the widget's view. If you pass |force_create| as true, then the backing
+ // store will be created if it doesn't exist. Otherwise, NULL will be returned
+ // if the backing store doesn't already exist. It will also return NULL if the
+ // backing store could not be created.
+ BackingStore* GetBackingStore(bool force_create);
// Allocate a new backing store of the given size. Returns NULL on failure
// (for example, if we don't currently have a RenderWidgetHostView.)
@@ -358,6 +378,13 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// renderer crashed, so you must always check that.
RenderProcessHost* process_;
+ // Stores random bits of data for others to associate with this object.
+ PropertyBag property_bag_;
+
+ // Observer that will be called for paint events. This may be NULL. The
+ // pointer is not owned by this class.
+ RenderWidgetHostPaintingObserver* painting_observer_;
+
// The ID of the corresponding object in the Renderer Instance.
int routing_id_;
diff --git a/chrome/browser/renderer_host/render_widget_host_painting_observer.h b/chrome/browser/renderer_host/render_widget_host_painting_observer.h
new file mode 100755
index 0000000..d24b61a
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host_painting_observer.h
@@ -0,0 +1,24 @@
+// 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.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_PAINTING_OBSERVER_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_PAINTING_OBSERVER_H_
+
+class BackingStore;
+class RenderWidgetHost;
+
+// This class can be used to observe painting events for a RenderWidgetHost.
+// Its primary goal in Chrome is to allow thumbnails to be generated.
+class RenderWidgetHostPaintingObserver {
+ public:
+ // Indicates the RenderWidgetHost is about to destroy the backing store. The
+ // backing store will still be valid when this call is made.
+ virtual void WidgetWillDestroyBackingStore(RenderWidgetHost* widget,
+ BackingStore* backing_store) = 0;
+
+ // Indicates that the RenderWidgetHost just updated the backing store.
+ virtual void WidgetDidUpdateBackingStore(RenderWidgetHost* widget) = 0;
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_PAINTING_OBSERVER_H_
diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc
index 083434d..f41aa29 100644
--- a/chrome/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc
@@ -100,7 +100,7 @@ bool RenderWidgetHostProcess::WaitForPaintMsg(int render_widget_id,
// This test view allows us to specify the size.
class TestView : public TestRenderWidgetHostView {
public:
- TestView() {}
+ TestView(RenderWidgetHost* rwh) : TestRenderWidgetHostView(rwh) {}
// Sets the bounds returned by GetViewBounds.
void set_bounds(const gfx::Rect& bounds) {
@@ -112,10 +112,6 @@ class TestView : public TestRenderWidgetHostView {
return bounds_;
}
- BackingStore* AllocBackingStore(const gfx::Size& size) {
- return new BackingStore(size);
- }
-
protected:
gfx::Rect bounds_;
DISALLOW_COPY_AND_ASSIGN(TestView);
@@ -160,7 +156,7 @@ class RenderWidgetHostTest : public testing::Test {
profile_.reset(new TestingProfile());
process_ = new RenderWidgetHostProcess(profile_.get());
host_.reset(new MockRenderWidgetHost(process_, 1));
- view_.reset(new TestView);
+ view_.reset(new TestView(host_.get()));
host_->set_view(view_.get());
host_->Init();
}
@@ -303,7 +299,7 @@ TEST_F(RenderWidgetHostTest, GetBackingStore_NoRepaintAck) {
// We don't currently have a backing store, and if the renderer doesn't send
// one in time, we should get nothing.
process_->set_paint_msg_should_reply(false);
- BackingStore* backing = host_->GetBackingStore();
+ BackingStore* backing = host_->GetBackingStore(true);
EXPECT_FALSE(backing);
// The widget host should have sent a request for a repaint, and there should
// be no paint ACK.
@@ -315,7 +311,7 @@ TEST_F(RenderWidgetHostTest, GetBackingStore_NoRepaintAck) {
process_->sink().ClearMessages();
process_->set_paint_msg_should_reply(true);
process_->set_paint_msg_reply_flags(0);
- backing = host_->GetBackingStore();
+ backing = host_->GetBackingStore(true);
EXPECT_TRUE(backing);
// The widget host should NOT have sent a request for a repaint, since there
// was an ACK already pending.
@@ -331,7 +327,7 @@ TEST_F(RenderWidgetHostTest, GetBackingStore_RepaintAck) {
process_->set_paint_msg_should_reply(true);
process_->set_paint_msg_reply_flags(
ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK);
- BackingStore* backing = host_->GetBackingStore();
+ BackingStore* backing = host_->GetBackingStore(true);
EXPECT_TRUE(backing);
// We still should not have sent out a repaint request since the last flags
// didn't have the repaint ack set, and the pending flag will still be set.
@@ -342,7 +338,7 @@ TEST_F(RenderWidgetHostTest, GetBackingStore_RepaintAck) {
// Asking again for the backing store should just re-use the existing one
// and not send any messagse.
process_->sink().ClearMessages();
- backing = host_->GetBackingStore();
+ backing = host_->GetBackingStore(true);
EXPECT_TRUE(backing);
EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Repaint::ID));
EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index 4570d40..192ab0b 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -446,19 +446,6 @@ void RenderWidgetHostViewGtk::SelectionChanged(const std::string& text) {
gtk_clipboard_set_text(x_clipboard, text.c_str(), text.length());
}
-BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
- const gfx::Size& size) {
- Display* display = x11_util::GetXDisplay();
- void* visual = x11_util::GetVisualFromGtkWidget(view_.get());
- XID root_window = x11_util::GetX11RootWindow();
- bool use_render = x11_util::QueryRenderSupport(display);
- bool use_shared_memory = x11_util::QuerySharedMemorySupport(display);
- int depth = gtk_widget_get_visual(view_.get())->depth;
-
- return new BackingStore(size, display, depth, visual, root_window,
- use_render, use_shared_memory);
-}
-
void RenderWidgetHostViewGtk::PasteFromSelectionClipboard() {
GtkClipboard* x_clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
gtk_clipboard_request_text(x_clipboard, ReceivedSelectionText, this);
@@ -472,12 +459,19 @@ void RenderWidgetHostViewGtk::ShowingContextMenu(bool showing) {
GetRenderWidgetHost()->Blur();
}
+BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
+ const gfx::Size& size) {
+ return new BackingStore(host_, size,
+ x11_util::GetVisualFromGtkWidget(view_.get()),
+ gtk_widget_get_visual(view_.get())->depth);
+}
+
void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
DCHECK(!about_to_validate_and_paint_);
invalid_rect_ = damage_rect;
about_to_validate_and_paint_ = true;
- BackingStore* backing_store = host_->GetBackingStore();
+ BackingStore* backing_store = host_->GetBackingStore(true);
// Calling GetBackingStore maybe have changed |invalid_rect_|...
about_to_validate_and_paint_ = false;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
index 0bed0c5..af0ac47 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
@@ -30,38 +30,34 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// Initialize this object for use as a drawing area.
void InitAsChild();
- // ---------------------------------------------------------------------------
- // Implementation of RenderWidgetHostView...
-
- void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos);
- RenderWidgetHost* GetRenderWidgetHost() const { return host_; }
- void DidBecomeSelected();
- void WasHidden();
- void SetSize(const gfx::Size& size);
- gfx::NativeView GetNativeView();
- void MovePluginWindows(
+ // RenderWidgetHostView implementation.
+ virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& pos);
+ virtual RenderWidgetHost* GetRenderWidgetHost() const { return host_; }
+ virtual void DidBecomeSelected();
+ virtual void WasHidden();
+ virtual void SetSize(const gfx::Size& size);
+ virtual gfx::NativeView GetNativeView();
+ virtual void MovePluginWindows(
const std::vector<WebPluginGeometry>& plugin_window_moves);
- void Focus();
- void Blur();
- bool HasFocus();
- void Show();
- void Hide();
- gfx::Rect GetViewBounds() const;
- void UpdateCursor(const WebCursor& cursor);
- void SetIsLoading(bool is_loading);
- void IMEUpdateStatus(int control, const gfx::Rect& caret_rect);
- void DidPaintRect(const gfx::Rect& rect);
- void DidScrollRect(
- const gfx::Rect& rect, int dx, int dy);
- void RenderViewGone();
- void Destroy();
- void SetTooltipText(const std::wstring& tooltip_text);
- void SelectionChanged(const std::string& text);
- void PasteFromSelectionClipboard();
- void ShowingContextMenu(bool showing);
- BackingStore* AllocBackingStore(const gfx::Size& size);
- // ---------------------------------------------------------------------------
+ virtual void Focus();
+ virtual void Blur();
+ virtual bool HasFocus();
+ virtual void Show();
+ virtual void Hide();
+ virtual gfx::Rect GetViewBounds() const;
+ virtual void UpdateCursor(const WebCursor& cursor);
+ virtual void SetIsLoading(bool is_loading);
+ virtual void IMEUpdateStatus(int control, const gfx::Rect& caret_rect);
+ virtual void DidPaintRect(const gfx::Rect& rect);
+ virtual void DidScrollRect(const gfx::Rect& rect, int dx, int dy);
+ virtual void RenderViewGone();
+ virtual void Destroy();
+ virtual void SetTooltipText(const std::wstring& tooltip_text);
+ virtual void SelectionChanged(const std::string& text);
+ virtual void PasteFromSelectionClipboard();
+ virtual void ShowingContextMenu(bool showing);
+ virtual BackingStore* AllocBackingStore(const gfx::Size& size);
gfx::NativeView native_view() const { return view_.get(); }
@@ -80,7 +76,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
gpointer userdata);
// The model object.
- RenderWidgetHost *const host_;
+ RenderWidgetHost* const host_;
+
// The native UI widget.
OwnedWidgetGtk view_;
@@ -88,6 +85,7 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// paint requests by expanding the invalid rect rather than actually
// painting.
bool about_to_validate_and_paint_;
+
// This is the rectangle which we'll paint.
gfx::Rect invalid_rect_;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index 4580c2f..a18dd08 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -297,7 +297,7 @@ void RenderWidgetHostViewMac::SetTooltipText(const std::wstring& tooltip_text) {
BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
const gfx::Size& size) {
- return new BackingStore(size);
+ return new BackingStore(render_widget_host_, size);
}
// Display a popup menu for WebKit using Cocoa widgets.
@@ -415,7 +415,7 @@ void RenderWidgetHostViewMac::ShutdownHost() {
renderWidgetHostView_->invalid_rect_ = dirtyRect;
renderWidgetHostView_->about_to_validate_and_paint_ = true;
BackingStore* backing_store =
- renderWidgetHostView_->render_widget_host_->GetBackingStore();
+ renderWidgetHostView_->render_widget_host_->GetBackingStore(true);
skia::PlatformCanvas* canvas = backing_store->canvas();
renderWidgetHostView_->about_to_validate_and_paint_ = false;
dirtyRect = renderWidgetHostView_->invalid_rect_;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
index 9c33865..15bee47 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -650,7 +650,7 @@ void RenderWidgetHostViewWin::SetTooltipText(const std::wstring& tooltip_text) {
BackingStore* RenderWidgetHostViewWin::AllocBackingStore(
const gfx::Size& size) {
- return new BackingStore(size);
+ return new BackingStore(render_widget_host_, size);
}
void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) {
@@ -692,7 +692,7 @@ void RenderWidgetHostViewWin::OnPaint(HDC dc) {
DCHECK(render_widget_host_->process()->channel());
about_to_validate_and_paint_ = true;
- BackingStore* backing_store = render_widget_host_->GetBackingStore();
+ BackingStore* backing_store = render_widget_host_->GetBackingStore(true);
// We initialize |paint_dc| (and thus call BeginPaint()) after calling
// GetBackingStore(), so that if it updates the invalid rect we'll catch the
diff --git a/chrome/browser/renderer_host/test_render_view_host.cc b/chrome/browser/renderer_host/test_render_view_host.cc
index 65dd323..982beb6 100644
--- a/chrome/browser/renderer_host/test_render_view_host.cc
+++ b/chrome/browser/renderer_host/test_render_view_host.cc
@@ -17,7 +17,7 @@ TestRenderViewHost::TestRenderViewHost(SiteInstance* instance,
: RenderViewHost(instance, delegate, routing_id, modal_dialog_event),
render_view_created_(false),
delete_counter_(NULL) {
- set_view(new TestRenderWidgetHostView());
+ set_view(new TestRenderWidgetHostView(this));
}
TestRenderViewHost::~TestRenderViewHost() {
@@ -66,9 +66,14 @@ void TestRenderViewHost::SendNavigate(int page_id, const GURL& url) {
OnMsgNavigate(msg);
}
+TestRenderWidgetHostView::TestRenderWidgetHostView(RenderWidgetHost* rwh)
+ : rwh_(rwh),
+ is_showing_(false) {
+}
+
BackingStore* TestRenderWidgetHostView::AllocBackingStore(
const gfx::Size& size) {
- return new BackingStore(size);
+ return new BackingStore(rwh_, size);
}
void RenderViewHostTestHarness::NavigateAndCommit(const GURL& url) {
diff --git a/chrome/browser/renderer_host/test_render_view_host.h b/chrome/browser/renderer_host/test_render_view_host.h
index ac80096..37b100a 100644
--- a/chrome/browser/renderer_host/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test_render_view_host.h
@@ -38,7 +38,7 @@ class TestTabContents;
// without having side-effects.
class TestRenderWidgetHostView : public RenderWidgetHostView {
public:
- TestRenderWidgetHostView() : is_showing_(false) {}
+ explicit TestRenderWidgetHostView(RenderWidgetHost* rwh);
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) {}
@@ -82,6 +82,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
bool is_showing() const { return is_showing_; }
private:
+ RenderWidgetHost* rwh_;
bool is_showing_;
};
diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc
index 710723f..68421a7 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager.cc
@@ -58,6 +58,10 @@ void RenderViewHostManager::Init(Profile* profile,
site_instance = SiteInstance::CreateSiteInstance(profile);
render_view_host_ = RenderViewHostFactory::Create(
site_instance, render_view_delegate_, routing_id, modal_dialog_event);
+ NotificationService::current()->Notify(
+ NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
+ Source<RenderViewHostManager>(this),
+ Details<RenderViewHost>(render_view_host_));
}
RenderViewHost* RenderViewHostManager::Navigate(const NavigationEntry& entry) {
@@ -407,6 +411,10 @@ bool RenderViewHostManager::CreatePendingRenderView(SiteInstance* instance) {
pending_render_view_host_ = RenderViewHostFactory::Create(
instance, render_view_delegate_, MSG_ROUTING_NONE, NULL);
+ NotificationService::current()->Notify(
+ NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
+ Source<RenderViewHostManager>(this),
+ Details<RenderViewHost>(pending_render_view_host_));
bool success = delegate_->CreateRenderViewForRenderManager(
pending_render_view_host_);
diff --git a/chrome/browser/tab_contents/thumbnail_generator.cc b/chrome/browser/tab_contents/thumbnail_generator.cc
new file mode 100755
index 0000000..4654b14
--- /dev/null
+++ b/chrome/browser/tab_contents/thumbnail_generator.cc
@@ -0,0 +1,321 @@
+// 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 "chrome/browser/tab_contents/thumbnail_generator.h"
+
+#include <algorithm>
+
+#include "base/histogram.h"
+#include "base/time.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/property_bag.h"
+#include "skia/ext/image_operations.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+// Overview
+// --------
+// This class provides current thumbnails for tabs. The simplest operation is
+// when a request for a thumbnail comes in, to grab the backing store and make
+// a smaller version of that.
+//
+// A complication happens because we don't always have nice backing stores for
+// all tabs (there is a cache of several tabs we'll keep backing stores for).
+// To get thumbnails for tabs with expired backing stores, we listen for
+// backing stores that are being thrown out, and generate thumbnails before
+// that happens. We attach them to the RenderWidgetHost via the property bag
+// so we can retrieve them later. When a tab has a live backing store again,
+// we throw away the thumbnail since it's now out-of-date.
+//
+// Another complication is performance. If the user brings up a tab switcher, we
+// don't want to get all 5 cached backing stores since it is a very large amount
+// of data. As a result, we generate thumbnails for tabs that are hidden even
+// if the backing store is still valid. This means we'll have to do a maximum
+// of generating thumbnails for the visible tabs at any point.
+//
+// The last performance consideration is when the user switches tabs quickly.
+// This can happen by doing Control-PageUp/Down or juct clicking quickly on
+// many different tabs (like when you're looking for one). We don't want to
+// slow this down by making thumbnails for each tab as it's hidden. Therefore,
+// we have a timer so that we don't invalidate thumbnails for tabs that are
+// only shown briefly (which would cause the thumbnail to be regenerated when
+// the tab is hidden).
+
+namespace {
+
+static const int kThumbnailWidth = 294;
+static const int kThumbnailHeight = 204;
+
+// Indicates the time that the RWH must be visible for us to update the
+// thumbnail on it. If the user holds down control enter, there will be a lot
+// of backing stores created and destroyed. WE don't want to interfere with
+// that.
+//
+// Any operation that happens within this time of being shown is ignored.
+// This means we won't throw the thumbnail away when the backing store is
+// painted in this time.
+static const int kVisibilitySlopMS = 3000;
+
+struct WidgetThumbnail {
+ SkBitmap thumbnail;
+
+ // Indicates the last time the RWH was shown and hidden.
+ base::TimeTicks last_shown;
+ base::TimeTicks last_hidden;
+};
+
+PropertyAccessor<WidgetThumbnail>* GetThumbnailAccessor() {
+ static PropertyAccessor<WidgetThumbnail> accessor;
+ return &accessor;
+}
+
+// Returns the existing WidgetThumbnail for a RVH, or creates a new one and
+// returns that if none exists.
+WidgetThumbnail* GetDataForHost(RenderWidgetHost* host) {
+ WidgetThumbnail* wt = GetThumbnailAccessor()->GetProperty(
+ host->property_bag());
+ if (wt)
+ return wt;
+
+ GetThumbnailAccessor()->SetProperty(host->property_bag(),
+ WidgetThumbnail());
+ return GetThumbnailAccessor()->GetProperty(host->property_bag());
+}
+
+// Creates a downsampled thumbnail for the given backing store. The returned
+// bitmap will be isNull if there was an error creating it.
+SkBitmap GetThumbnailForBackingStore(BackingStore* backing_store) {
+ SkBitmap result;
+
+ // TODO(brettw) write this for other platforms. If you enable this, be sure
+ // to also enable the unit tests for the same platform in
+ // thumbnail_generator_unittest.cc
+#if defined(OS_WIN)
+ // Get the bitmap as a Skia object so we can resample it. This is a large
+ // allocation and we can tolerate failure here, so give up if the allocation
+ // fails.
+ base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
+
+ skia::PlatformCanvas temp_canvas;
+ if (!temp_canvas.initialize(backing_store->size().width(),
+ backing_store->size().height(), true))
+ return SkBitmap();
+ HDC temp_dc = temp_canvas.beginPlatformPaint();
+ BitBlt(temp_dc,
+ 0, 0, backing_store->size().width(), backing_store->size().height(),
+ backing_store->hdc(), 0, 0, SRCCOPY);
+ temp_canvas.endPlatformPaint();
+
+ // Get the bitmap out of the canvas and resample it.
+ const SkBitmap& bmp = temp_canvas.getTopPlatformDevice().accessBitmap(false);
+ result = skia::ImageOperations::DownsampleByTwoUntilSize(
+ bmp,
+ kThumbnailWidth, kThumbnailHeight);
+ if (bmp.width() == result.width() && bmp.height() == result.height()) {
+ // This is a bit subtle. SkBitmaps are refcounted, but the magic ones in
+ // PlatformCanvas can't be ssigned 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.
+ bmp.copyTo(&result, SkBitmap::kARGB_8888_Config);
+ }
+
+ HISTOGRAM_TIMES("Thumbnail.ComputeOnDestroyMS",
+ base::TimeTicks::Now() - begin_compute_thumbnail);
+#endif
+
+ return result;
+}
+
+} // namespace
+
+ThumbnailGenerator::ThumbnailGenerator()
+ : no_timeout_(false) {
+ // Even though we deal in RenderWidgetHosts, we only care about its subclass,
+ // RenderViewHost when it is in a tab. We don't make thumbnails for
+ // RenderViewHosts that aren't in tabs, or RenderWidgetHosts that aren't
+ // views like select popups.
+ registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
+ NotificationService::AllSources());
+
+ registrar_.Add(this, NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DESTROYED,
+ NotificationService::AllSources());
+}
+
+ThumbnailGenerator::~ThumbnailGenerator() {
+}
+
+SkBitmap ThumbnailGenerator::GetThumbnailForRenderer(
+ RenderWidgetHost* renderer) const {
+ // Return a cached one if we have it and it's still valid. This will only be
+ // valid when there used to be a backing store, but there isn't now.
+ WidgetThumbnail* wt = GetThumbnailAccessor()->GetProperty(
+ renderer->property_bag());
+ if (wt && !wt->thumbnail.isNull() &&
+ (no_timeout_ ||
+ base::TimeTicks::Now() -
+ base::TimeDelta::FromMilliseconds(kVisibilitySlopMS) < wt->last_shown))
+ return wt->thumbnail;
+
+ BackingStore* backing_store = renderer->GetBackingStore(false);
+ if (!backing_store)
+ return SkBitmap();
+
+ // Save this thumbnail in case we need to use it again soon. It will be
+ // invalidated on the next paint.
+ wt->thumbnail = GetThumbnailForBackingStore(backing_store);
+ return wt->thumbnail;
+}
+
+void ThumbnailGenerator::WidgetWillDestroyBackingStore(
+ RenderWidgetHost* widget,
+ BackingStore* backing_store) {
+ // Since the backing store is going away, we need to save it as a thumbnail.
+ WidgetThumbnail* wt = GetDataForHost(widget);
+
+ // If there is already a thumbnail on the RWH that's visible, it means that
+ // not enough time has elapsed since being shown, and we can ignore generating
+ // a new one.
+ if (!wt->thumbnail.isNull())
+ return;
+
+ // Save a scaled-down image of the page in case we're asked for the thumbnail
+ // when there is no RenderViewHost. If this fails, we don't want to overwrite
+ // an existing thumbnail.
+ SkBitmap new_thumbnail = GetThumbnailForBackingStore(backing_store);
+ if (!new_thumbnail.isNull())
+ wt->thumbnail = new_thumbnail;
+}
+
+void ThumbnailGenerator::WidgetDidUpdateBackingStore(
+ RenderWidgetHost* widget) {
+ // Clear the current thumbnail since it's no longer valid.
+ WidgetThumbnail* wt = GetThumbnailAccessor()->GetProperty(
+ widget->property_bag());
+ if (!wt)
+ return; // Nothing to do.
+
+ // If this operation is within the time slop after being shown, keep the
+ // existing thumbnail.
+ if (no_timeout_ ||
+ base::TimeTicks::Now() -
+ base::TimeDelta::FromMilliseconds(kVisibilitySlopMS) < wt->last_shown)
+ return; // TODO(brettw) schedule thumbnail generation for this renderer in
+ // case we don't get a paint for it after the time slop, but it's
+ // still visible.
+
+ // Clear the thumbnail, since it's now out of date.
+ wt->thumbnail = SkBitmap();
+}
+
+void ThumbnailGenerator::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB: {
+ // Install our observer for all new RVHs.
+ RenderViewHost* renderer = Details<RenderViewHost>(details).ptr();
+ renderer->set_painting_observer(this);
+ break;
+ }
+
+ case NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED:
+ if (*Details<bool>(details).ptr())
+ WidgetShown(Source<RenderWidgetHost>(source).ptr());
+ else
+ WidgetHidden(Source<RenderWidgetHost>(source).ptr());
+ break;
+
+ case NotificationType::RENDER_WIDGET_HOST_DESTROYED:
+ WidgetDestroyed(Source<RenderWidgetHost>(source).ptr());
+ break;
+
+ default:
+ NOTREACHED();
+ }
+}
+
+void ThumbnailGenerator::WidgetShown(RenderWidgetHost* widget) {
+ WidgetThumbnail* wt = GetDataForHost(widget);
+ wt->last_shown = base::TimeTicks::Now();
+
+ // If there is no thumbnail (like we're displaying a background tab for the
+ // first time), then we don't have do to invalidate the existing one.
+ if (wt->thumbnail.isNull())
+ return;
+
+ std::vector<RenderWidgetHost*>::iterator found =
+ std::find(shown_hosts_.begin(), shown_hosts_.end(), widget);
+ if (found != shown_hosts_.end()) {
+ NOTREACHED() << "Showing a RWH we already think is shown";
+ shown_hosts_.erase(found);
+ }
+ shown_hosts_.push_back(widget);
+
+ // Keep the old thumbnail for a small amount of time after the tab has been
+ // shown. This is so in case it's hidden quickly again, we don't waste any
+ // work regenerating it.
+ if (timer_.IsRunning())
+ return;
+ timer_.Start(base::TimeDelta::FromMilliseconds(
+ no_timeout_ ? 0 : kVisibilitySlopMS),
+ this, &ThumbnailGenerator::ShownDelayHandler);
+}
+
+void ThumbnailGenerator::WidgetHidden(RenderWidgetHost* widget) {
+ WidgetThumbnail* wt = GetDataForHost(widget);
+ wt->last_hidden = base::TimeTicks::Now();
+
+ // If the tab is on the list of ones to invalidate the thumbnail, we need to
+ // remove it.
+ EraseHostFromShownList(widget);
+
+ // There may still be a valid cached thumbnail on the RWH, so we don't need to
+ // make a new one.
+ if (!wt->thumbnail.isNull())
+ return;
+ wt->thumbnail = GetThumbnailForRenderer(widget);
+}
+
+void ThumbnailGenerator::WidgetDestroyed(RenderWidgetHost* widget) {
+ EraseHostFromShownList(widget);
+}
+
+void ThumbnailGenerator::ShownDelayHandler() {
+ base::TimeTicks threshold = base::TimeTicks::Now() -
+ base::TimeDelta::FromMilliseconds(kVisibilitySlopMS);
+
+ // Check the list of all pending RWHs (normally only one) to see if any of
+ // their times have expired.
+ for (size_t i = 0; i < shown_hosts_.size(); i++) {
+ WidgetThumbnail* wt = GetDataForHost(shown_hosts_[i]);
+ if (no_timeout_ || wt->last_shown <= threshold) {
+ // This thumbnail has expired, delete it.
+ wt->thumbnail = SkBitmap();
+ shown_hosts_.erase(shown_hosts_.begin() + i);
+ i--;
+ }
+ }
+
+ // We need to schedule another run if there are still items in the list to
+ // process. We use half the timeout for these re-runs to catch the items
+ // that were added since the timer was run the first time.
+ if (!shown_hosts_.empty()) {
+ DCHECK(!no_timeout_);
+ timer_.Start(base::TimeDelta::FromMilliseconds(kVisibilitySlopMS) / 2, this,
+ &ThumbnailGenerator::ShownDelayHandler);
+ }
+}
+
+void ThumbnailGenerator::EraseHostFromShownList(RenderWidgetHost* widget) {
+ std::vector<RenderWidgetHost*>::iterator found =
+ std::find(shown_hosts_.begin(), shown_hosts_.end(), widget);
+ if (found != shown_hosts_.end())
+ shown_hosts_.erase(found);
+}
diff --git a/chrome/browser/tab_contents/thumbnail_generator.h b/chrome/browser/tab_contents/thumbnail_generator.h
new file mode 100755
index 0000000..76afb3c
--- /dev/null
+++ b/chrome/browser/tab_contents/thumbnail_generator.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef CHROME_BROWSER_TAB_CONTENTS_THUMBNAIL_GENERATOR_H_
+#define CHROME_BROWSER_TAB_CONTENTS_THUMBNAIL_GENERATOR_H_
+
+#include "base/basictypes.h"
+#include "base/timer.h"
+#include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class RenderWidgetHost;
+class SkBitmap;
+
+// This class MUST be destroyed after the RenderWidgetHosts, since it installs
+// a painting observer that is not removed.
+class ThumbnailGenerator : public RenderWidgetHostPaintingObserver,
+ public NotificationObserver {
+ public:
+ ThumbnailGenerator();
+ ~ThumbnailGenerator();
+
+ SkBitmap GetThumbnailForRenderer(RenderWidgetHost* renderer) const;
+
+#ifdef UNIT_TEST
+ // When true, the class will not use a timeout to do the expiration. This
+ // will cause expiration to happen on the next run of the message loop.
+ // Unit tests case use this to test expiration by choosing when the message
+ // loop runs.
+ void set_no_timeout(bool no_timeout) { no_timeout_ = no_timeout; }
+#endif
+
+ private:
+ // RenderWidgetHostPaintingObserver implementation.
+ virtual void WidgetWillDestroyBackingStore(RenderWidgetHost* widget,
+ BackingStore* backing_store);
+ virtual void WidgetDidUpdateBackingStore(RenderWidgetHost* widget);
+
+ // NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Indicates that the given widget has changed is visibility.
+ void WidgetShown(RenderWidgetHost* widget);
+ void WidgetHidden(RenderWidgetHost* widget);
+
+ // Called when the given widget is destroyed.
+ void WidgetDestroyed(RenderWidgetHost* widget);
+
+ // Timer function called on a delay after a tab has been shown. It will
+ // invalidate the thumbnail for hosts with expired thumbnails in shown_hosts_.
+ void ShownDelayHandler();
+
+ // Removes the given host from the shown_hosts_ list, if it is there.
+ void EraseHostFromShownList(RenderWidgetHost* host);
+
+ NotificationRegistrar registrar_;
+
+ base::OneShotTimer<ThumbnailGenerator> timer_;
+
+ // A list of all RWHs that have been shown and need to have their thumbnail
+ // expired at some time in the future with the "slop" time has elapsed. This
+ // list will normally have 0 or 1 items in it.
+ std::vector<RenderWidgetHost*> shown_hosts_;
+
+ // See the setter above.
+ bool no_timeout_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThumbnailGenerator);
+};
+
+#endif // CHROME_BROWSER_TAB_CONTENTS_THUMBNAIL_GENERATOR_H_
diff --git a/chrome/browser/tab_contents/thumbnail_generator_unittest.cc b/chrome/browser/tab_contents/thumbnail_generator_unittest.cc
new file mode 100755
index 0000000..53a17fc
--- /dev/null
+++ b/chrome/browser/tab_contents/thumbnail_generator_unittest.cc
@@ -0,0 +1,179 @@
+// 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 "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkColorPriv.h"
+
+static const int kBitmapWidth = 100;
+static const int kBitmapHeight = 100;
+
+// TODO(brettw) enable this when GetThumbnailForBackingStore is implemented
+// for other platforms in thumbnail_generator.cc
+//#if defined(OS_WIN)
+// TODO(brettw) enable this on Windows after we clobber a build to see if the
+// failures of this on the buildbot can be resolved.
+#if 0
+
+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;
+
+ EXPECT_TRUE(false) << "Got weird color: " << pixel;
+ 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));
+}
+
+#endif
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 39e3de6..c5184bb 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1396,6 +1396,8 @@
'browser/tab_contents/tab_contents_view_mac.mm',
'browser/tab_contents/tab_util.cc',
'browser/tab_contents/tab_util.h',
+ 'browser/tab_contents/thumbnail_generator.cc',
+ 'browser/tab_contents/thumbnail_generator.h',
'browser/tab_contents/web_drag_source.cc',
'browser/tab_contents/web_drag_source.h',
'browser/tab_contents/web_drop_target.cc',
@@ -3416,6 +3418,7 @@
'browser/tab_contents/navigation_entry_unittest.cc',
'browser/tab_contents/render_view_host_manager_unittest.cc',
'browser/tab_contents/site_instance_unittest.cc',
+ 'browser/tab_contents/thumbnail_generator_unittest.cc',
'browser/tab_contents/web_contents_unittest.cc',
'browser/tabs/tab_strip_model_unittest.cc',
'browser/task_manager_unittest.cc',
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index 3c8b26a..678c942 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -286,6 +286,12 @@ class NotificationType {
// Source<TabContents>.
TAB_CONTENTS_DESTROYED,
+ // A RenderViewHost was created for a TabContents. The source is the
+ // RenderViewHostManager who owns it, and the details is the RenderViewHost
+ // pointer. Note that the source will be NULL in some cases for testing,
+ // when there is no RVHManager.
+ RENDER_VIEW_HOST_CREATED_FOR_TAB,
+
// Stuff inside the tabs ---------------------------------------------------
// This message is sent after a constrained window has been closed. The
@@ -326,6 +332,11 @@ class NotificationType {
// the RenderWidgetHost, the details are not used.
RENDER_WIDGET_HOST_DESTROYED,
+ // Indicates a RenderWidgetHost has been hidden or restored. The source is
+ // the RWH whose visibility changed, the details is a bool set to true if
+ // the new state is "visible."
+ RENDER_WIDGET_VISIBILITY_CHANGED,
+
// Notification from TabContents that we have received a response from the
// renderer after using the dom inspector.
DOM_INSPECT_ELEMENT_RESPONSE,
diff --git a/chrome/common/property_bag.h b/chrome/common/property_bag.h
index d2f3559..afc7bd3 100644
--- a/chrome/common/property_bag.h
+++ b/chrome/common/property_bag.h
@@ -131,7 +131,7 @@ class PropertyAccessor : public PropertyAccessorBase {
PropertyAccessor() : PropertyAccessorBase() {}
virtual ~PropertyAccessor() {}
- // Takes ownership of the |prop| pointer.
+ // Makes a copy of the |prop| object for storage.
void SetProperty(PropertyBag* bag, const T& prop) {
SetPropertyInternal(bag, new Container(prop));
}
diff --git a/chrome/common/transport_dib.h b/chrome/common/transport_dib.h
index 33c0649..5712827 100644..100755
--- a/chrome/common/transport_dib.h
+++ b/chrome/common/transport_dib.h
@@ -20,6 +20,9 @@
namespace gfx {
class Size;
}
+namespace skia {
+class PlatformCanvas;
+}
// -----------------------------------------------------------------------------
// A TransportDIB is a block of memory that is used to transport pixels
@@ -84,6 +87,11 @@ class TransportDIB {
// Map the referenced transport DIB. Returns NULL on failure.
static TransportDIB* Map(Handle transport_dib);
+ // Returns a canvas using the memory of this TransportDIB. The returned
+ // pointer will be owned by the caller. The bitmap will be of the given size,
+ // which should fit inside this memory.
+ skia::PlatformCanvas* GetPlatformCanvas(int w, int h);
+
// Return a pointer to the shared memory
void* memory() const;
diff --git a/chrome/common/transport_dib_linux.cc b/chrome/common/transport_dib_linux.cc
index be673d9..1037341 100644..100755
--- a/chrome/common/transport_dib_linux.cc
+++ b/chrome/common/transport_dib_linux.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "chrome/common/transport_dib.h"
#include "chrome/common/x11_util.h"
+#include "skia/ext/platform_canvas.h"
// The shmat system call uses this as it's invalid return address
static void *const kInvalidAddress = (void*) -1;
@@ -80,6 +81,11 @@ TransportDIB* TransportDIB::Map(Handle shmkey) {
return dib;
}
+skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
+ return new skia::PlatformCanvas(w, h, true,
+ reinterpret_cast<uint8_t*>(memory()));
+}
+
void* TransportDIB::memory() const {
DCHECK_NE(address_, kInvalidAddress);
return address_;
diff --git a/chrome/common/transport_dib_mac.cc b/chrome/common/transport_dib_mac.cc
index b4c7a2a7..638866c 100644..100755
--- a/chrome/common/transport_dib_mac.cc
+++ b/chrome/common/transport_dib_mac.cc
@@ -9,6 +9,7 @@
#include "base/eintr_wrapper.h"
#include "base/shared_memory.h"
+#include "skia/ext/platform_canvas.h"
TransportDIB::TransportDIB()
: size_(0) {
@@ -52,6 +53,11 @@ TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
return dib;
}
+skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
+ return new skia::PlatformCanvas(w, h, true,
+ reinterpret_cast<uint8_t*>(dib->memory()));
+}
+
void* TransportDIB::memory() const {
return shared_memory_.memory();
}
diff --git a/chrome/common/transport_dib_win.cc b/chrome/common/transport_dib_win.cc
index 49cb755..41fe925 100644..100755
--- a/chrome/common/transport_dib_win.cc
+++ b/chrome/common/transport_dib_win.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/sys_info.h"
#include "chrome/common/transport_dib.h"
+#include "skia/ext/platform_canvas.h"
TransportDIB::TransportDIB() {
}
@@ -59,6 +60,10 @@ TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
return dib;
}
+skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
+ return new skia::PlatformCanvas(w, h, true, handle());
+}
+
void* TransportDIB::memory() const {
return shared_memory_.memory();
}
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS
index cb1f386..d5673d2 100644..100755
--- a/chrome/renderer/DEPS
+++ b/chrome/renderer/DEPS
@@ -6,7 +6,6 @@ include_rules = [
"+media/base",
"+media/filters",
"+sandbox/src",
- "+skia/ext",
"+skia/include",
"+webkit/default_plugin",
"+webkit/extensions",
diff --git a/chrome/renderer/render_process.cc b/chrome/renderer/render_process.cc
index 6cfb56d..027b209 100644
--- a/chrome/renderer/render_process.cc
+++ b/chrome/renderer/render_process.cc
@@ -136,21 +136,6 @@ bool RenderProcess::InProcessPlugins() {
// -----------------------------------------------------------------------------
// Platform specific code for dealing with bitmap transport...
-// -----------------------------------------------------------------------------
-// Create a platform canvas object which renders into the given transport
-// memory.
-// -----------------------------------------------------------------------------
-static skia::PlatformCanvas* CanvasFromTransportDIB(
- TransportDIB* dib, const gfx::Rect& rect) {
-#if defined(OS_WIN)
- return new skia::PlatformCanvas(rect.width(), rect.height(), true,
- dib->handle());
-#elif defined(OS_LINUX) || defined(OS_MACOSX)
- return new skia::PlatformCanvas(rect.width(), rect.height(), true,
- reinterpret_cast<uint8_t*>(dib->memory()));
-#endif
-}
-
TransportDIB* RenderProcess::CreateTransportDIB(size_t size) {
#if defined(OS_WIN) || defined(OS_LINUX)
// Windows and Linux create transport DIBs inside the renderer
@@ -196,7 +181,7 @@ skia::PlatformCanvas* RenderProcess::GetDrawingCanvas(
return false;
}
- return CanvasFromTransportDIB(*memory, rect);
+ return (*memory)->GetPlatformCanvas(rect.width(), rect.height());
}
void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) {
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index 2e35b33..3a9cda1 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -810,6 +810,10 @@
>
</File>
<File
+ RelativePath="..\..\browser\tab_contents\thumbnail_generator_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\browser\thumbnail_store_unittest.cc"
>
</File>