Add the ability for the GPU process to be used to paint the backing store of a
tab. This is the first pass and is currently a bit buggy and incomplete.

This patch refactors the backing store to make it a virtual interface which is
then implemented by the platform-specific backing stores. This cleans up the
multi-platform aspects of the old code, and also makes it possible to create
different backing stores (such as ones in another process).

This renames the BackingStore::PaintRect function to PaintToBackingStore which
clears up what it does. I would often get confused and think that it paints
the backing store to the screen.

This makes a common way to capture backing store information and adds it to the
backing store API. This removed a bunch of ugly ifdefs.

This adds the ability for a backing store to specify that the TransportDIB
should not be freed by RenderWidgetHost when painting is complete. This is
necessary since the out-of-process version needs to use it after the
RenderWidget paint function has returned.

This pushes up the vector of copy_rect from RenderWidgetHost to the actual
BackingStores. This prevents us from sending duplicate data over IPC. It also
makes the common non-IPC case more efficient, since we end up setting up various
surfaces only once when there are multiple update rects.

BUG=none
TEST=none
Review URL: http://codereview.chromium.org/523028

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36075 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc
index 8ef4314b..b15e044 100644
--- a/chrome/app/chrome_dll_main.cc
+++ b/chrome/app/chrome_dll_main.cc
@@ -86,6 +86,7 @@
 
 extern int BrowserMain(const MainFunctionParams&);
 extern int RendererMain(const MainFunctionParams&);
+extern int GpuMain(const MainFunctionParams&);
 extern int PluginMain(const MainFunctionParams&);
 extern int WorkerMain(const MainFunctionParams&);
 extern int NaClMain(const MainFunctionParams&);
@@ -671,6 +672,8 @@
     rv = PluginMain(main_params);
   } else if (process_type == switches::kUtilityProcess) {
     rv = UtilityMain(main_params);
+  } else if (process_type == switches::kGpuProcess) {
+    rv = GpuMain(main_params);
   } else if (process_type == switches::kProfileImportProcess) {
 #if defined(OS_MACOSX)
     rv = ProfileImportMain(main_params);
diff --git a/chrome/app/dummy_main_functions.cc b/chrome/app/dummy_main_functions.cc
index fa066ca..192720e 100644
--- a/chrome/app/dummy_main_functions.cc
+++ b/chrome/app/dummy_main_functions.cc
@@ -42,3 +42,7 @@
 int DiagnosticsMain(const CommandLine& command_line) {
   return 1;
 }
+
+int GpuMain(const MainFunctionParams&) {
+  return ResultCodes::BAD_PROCESS_TYPE;
+}
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index edfd5f5..aac6081 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -765,55 +765,18 @@
 // Build the image of a tab's contents out of a backing store.
 void CaptureVisibleTabFunction::CaptureSnapshotFromBackingStore(
     BackingStore* backing_store) {
-  SkBitmap screen_capture;
 
-#if defined(OS_WIN)
   skia::PlatformCanvas temp_canvas;
-  if (!temp_canvas.initialize(backing_store->size().width(),
-                              backing_store->size().height(), true)) {
+  if (!backing_store->CopyFromBackingStore(gfx::Rect(gfx::Point(0, 0),
+                                                     backing_store->size()),
+                                           &temp_canvas)) {
     error_ = ExtensionErrorUtils::FormatErrorMessage(
         keys::kInternalVisibleTabCaptureError, "");
     SendResponse(false);
     return;
   }
-  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();
-
-  screen_capture = temp_canvas.getTopPlatformDevice().accessBitmap(false);
-#elif defined(OS_MACOSX)
-  skia::PlatformCanvas temp_canvas;
-  if (!temp_canvas.initialize(backing_store->size().width(),
-                              backing_store->size().height(), true)) {
-    error_ = ExtensionErrorUtils::FormatErrorMessage(
-        keys::kInternalVisibleTabCaptureError, "");
-    SendResponse(false);
-    return;
-  }
-  CGContextRef temp_context = temp_canvas.beginPlatformPaint();
-  CGContextSaveGState(temp_context);
-  CGContextTranslateCTM(temp_context, 0.0, backing_store->size().height());
-  CGContextScaleCTM(temp_context, 1.0, -1.0);
-  CGContextDrawLayerAtPoint(temp_context, CGPointMake(0.0, 0.0),
-                            backing_store->cg_layer());
-  CGContextRestoreGState(temp_context);
-  temp_canvas.endPlatformPaint();
-
-  screen_capture = temp_canvas.getTopPlatformDevice().accessBitmap(false);
-#elif defined(OS_LINUX)
-  screen_capture = backing_store->PaintRectToBitmap(
-      gfx::Rect(0, 0, backing_store->size().width(),
-                backing_store->size().height()));
-#else
-  // TODO(port)
-  error_ = keys::kNotImplementedError;
-  SendResponse(false);
-  return;
-#endif
-
-  SendResultFromBitmap(screen_capture);
+  SendResultFromBitmap(
+      temp_canvas.getTopPlatformDevice().accessBitmap(false));
 }
 
 // If a backing store was not available in CaptureVisibleTabFunction::RunImpl,
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc
new file mode 100644
index 0000000..905f5c7
--- /dev/null
+++ b/chrome/browser/gpu_process_host.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2010 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/gpu_process_host.h"
+
+#include "base/command_line.h"
+#include "base/singleton.h"
+#include "base/thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/child_process_launcher.h"
+#include "chrome/common/child_process_host.h"
+#include "chrome/common/child_process_info.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/gpu_messages.h"
+#include "ipc/ipc_switches.h"
+
+GpuProcessHost::GpuProcessHost() : last_routing_id_(1) {
+  FilePath exe_path = ChildProcessHost::GetChildPath();
+  if (exe_path.empty())
+    return;
+
+  std::string channel_id = ChildProcessInfo::GenerateRandomChannelID(this);
+  channel_.reset(new IPC::ChannelProxy(
+      channel_id,
+      IPC::Channel::MODE_SERVER,
+      this,
+      NULL,  // No filter (for now).
+      g_browser_process->io_thread()->message_loop()));
+
+  CommandLine* cmd_line = new CommandLine(exe_path);
+  cmd_line->AppendSwitchWithValue(switches::kProcessType,
+                                  switches::kGpuProcess);
+  cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+                                  ASCIIToWide(channel_id));
+
+  // Spawn the child process asynchronously to avoid blocking the UI thread.
+  child_process_.reset(new ChildProcessLauncher(
+#if defined(OS_WIN)
+      FilePath(),
+#elif defined(POSIX)
+      base::environment_vector(),
+      channel_->GetClientFileDescriptor(),
+#endif
+      cmd_line,
+      this));
+}
+
+GpuProcessHost::~GpuProcessHost() {
+}
+
+// static
+GpuProcessHost* GpuProcessHost::Get() {
+  GpuProcessHost* host = Singleton<GpuProcessHost>::get();
+  if (!host->child_process_.get())
+    return NULL;  // Failed to init.
+  return host;
+}
+
+int32 GpuProcessHost::GetNextRoutingId() {
+  return ++last_routing_id_;
+}
+
+int32 GpuProcessHost::NewRenderWidgetHostView(gfx::NativeViewId parent) {
+  int32 routing_id = GetNextRoutingId();
+  Send(new GpuMsg_NewRenderWidgetHostView(parent, routing_id));
+  return routing_id;
+}
+
+bool GpuProcessHost::Send(IPC::Message* msg) {
+  if (!channel_.get()) {
+    delete msg;
+    return false;
+  }
+
+  if (child_process_.get() && child_process_->IsStarting()) {
+    queued_messages_.push(msg);
+    return true;
+  }
+
+  return channel_->Send(msg);
+}
+
+void GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
+  if (message.routing_id() == MSG_ROUTING_CONTROL) {
+    // We don't currently have any control messages.
+    // OnControlMessageReceived(message);
+  } else {
+    router_.OnMessageReceived(message);
+  }
+}
+
+void GpuProcessHost::OnChannelConnected(int32 peer_pid) {
+}
+
+void GpuProcessHost::OnChannelError() {
+}
+
+void GpuProcessHost::OnProcessLaunched() {
+  while (!queued_messages_.empty()) {
+    Send(queued_messages_.front());
+    queued_messages_.pop();
+  }
+}
+
+void GpuProcessHost::AddRoute(int32 routing_id,
+                              IPC::Channel::Listener* listener) {
+  router_.AddRoute(routing_id, listener);
+}
+
+void GpuProcessHost::RemoveRoute(int32 routing_id) {
+  router_.RemoveRoute(routing_id);
+}
diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h
new file mode 100644
index 0000000..18561829
--- /dev/null
+++ b/chrome/browser/gpu_process_host.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2010 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_GPU_PROCESS_HOST_H_
+#define CHROME_BROWSER_GPU_PROCESS_HOST_H_
+
+#include <queue>
+
+#include "app/gfx/native_widget_types.h"
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/singleton.h"
+#include "chrome/browser/child_process_launcher.h"
+#include "chrome/common/message_router.h"
+#include "ipc/ipc_channel_proxy.h"
+
+class ChildProcessLauncher;
+
+class GpuProcessHost : public IPC::Channel::Sender,
+                       public IPC::Channel::Listener,
+                       public ChildProcessLauncher::Client {
+ public:
+  // Getter for the singleton. This will return NULL on failure.
+  static GpuProcessHost* Get();
+
+  int32 GetNextRoutingId();
+
+  // Creates the new remote view and returns the routing ID for the view, or 0
+  // on failure.
+  int32 NewRenderWidgetHostView(gfx::NativeViewId parent);
+
+  // IPC::Channel::Sender implementation.
+  virtual bool Send(IPC::Message* msg);
+
+  // IPC::Channel::Listener implementation.
+  virtual void OnMessageReceived(const IPC::Message& message);
+  virtual void OnChannelConnected(int32 peer_pid);
+  virtual void OnChannelError();
+
+  // ChildProcessLauncher::Client implementation.
+  virtual void OnProcessLaunched();
+
+  // See documentation on MessageRouter for AddRoute and RemoveRoute
+  void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
+  void RemoveRoute(int32 routing_id);
+
+ private:
+  friend struct DefaultSingletonTraits<GpuProcessHost>;
+
+  GpuProcessHost();
+  virtual ~GpuProcessHost();
+
+  scoped_ptr<ChildProcessLauncher> child_process_;
+
+  // A proxy for our IPC::Channel that lives on the IO thread (see
+  // browser_process.h). This will be NULL if the class failed to initialize.
+  scoped_ptr<IPC::ChannelProxy> channel_;
+
+  int last_routing_id_;
+
+  MessageRouter router_;
+
+  // Messages we queue while waiting for the process handle.  We queue them here
+  // instead of in the channel so that we ensure they're sent after init related
+  // messages that are sent once the process handle is available.  This is
+  // because the queued messages may have dependencies on the init messages.
+  std::queue<IPC::Message*> queued_messages_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuProcessHost);
+};
+
+#endif  // CHROME_BROWSER_GPU_PROCESS_HOST_H_
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
index fce118d..afaedea6 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
@@ -13,7 +13,7 @@
 #include "app/l10n_util.h"
 #include "chrome/browser/browser_theme_provider.h"
 #include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/backing_store_x.h"
 #include "chrome/browser/tab_contents/tab_contents.h"
 #include "chrome/browser/tabs/tab_strip_model.h"
 #include "chrome/browser/gtk/tabs/tab_renderer_gtk.h"
@@ -301,7 +301,7 @@
       dragged_tab->data_source_->render_view_host()->GetBackingStore(false);
   if (backing_store && !dragged_tab->attached_) {
     // This leaves room for the border.
-    backing_store->PaintToRect(
+    static_cast<BackingStoreX*>(backing_store)->PaintToRect(
         gfx::Rect(kDragFrameBorderSize, tab_height,
                   widget->allocation.width - kTwiceDragFrameBorderSize,
                   widget->allocation.height - tab_height -
diff --git a/chrome/browser/renderer_host/backing_store.cc b/chrome/browser/renderer_host/backing_store.cc
new file mode 100644
index 0000000..feebac3
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2010 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/renderer_host/backing_store.h"
+
+BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
+    : render_widget_host_(widget),
+      size_(size) {
+}
+
+BackingStore::~BackingStore() {
+}
+
+size_t BackingStore::MemorySize() {
+  return size_.GetArea() * 4;
+}
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 28640ba..a60adc2b 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -1,185 +1,81 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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_BACKING_STORE_H_
 #define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_H_
 
+#include <vector>
+
 #include "base/basictypes.h"
-#include "base/gfx/rect.h"
 #include "base/gfx/size.h"
 #include "base/process.h"
-#include "build/build_config.h"
+#include "chrome/common/transport_dib.h"
 
-#if defined(OS_WIN)
-#include <windows.h>
-#elif defined(OS_MACOSX)
-#include "base/scoped_cftyperef.h"
-#include "skia/ext/platform_canvas.h"
-#elif defined(OS_LINUX)
-#include "chrome/common/x11_util.h"
-#endif
-
+class RenderProcessHost;
 class RenderWidgetHost;
-class SkBitmap;
-class TransportDIB;
-typedef struct _GdkDrawable GdkDrawable;
 
-// BackingStore ----------------------------------------------------------------
+namespace gfx {
+class Rect;
+}
+
+namespace skia {
+class PlatformCanvas;
+}
 
 // Represents a backing store for the pixels in a RenderWidgetHost.
 class BackingStore {
  public:
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  BackingStore(RenderWidgetHost* widget, const gfx::Size& size);
-#elif defined(OS_LINUX)
-  // 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
-  BackingStore(RenderWidgetHost* widget, const gfx::Size& size);
-#endif
-  ~BackingStore();
+  virtual ~BackingStore();
 
   RenderWidgetHost* render_widget_host() const { return render_widget_host_; }
   const gfx::Size& size() { return size_; }
 
-  // The number of bytes that this backing store consumes.  This should roughly
-  // be size_.GetArea() * bytes per pixel.
-  size_t MemorySize();
-
-#if defined(OS_WIN)
-  HDC hdc() { return hdc_; }
-
-  // Returns true if we should convert to the monitor profile when painting.
-  static bool ColorManagementEnabled();
-#elif defined(OS_MACOSX)
-  // A CGLayer that stores the contents of the backing store, cached in GPU
-  // memory if possible.
-  CGLayerRef cg_layer() { return cg_layer_; }
-  // A CGBitmapContext that stores the contents of the backing store if the
-  // corresponding Cocoa view has not been inserted into an NSWindow yet.
-  CGContextRef cg_bitmap() { return cg_bitmap_; }
-
-  // Paint the layer into a graphics context--if the target is a window,
-  // this should be a GPU->GPU copy (and therefore very fast).
-  void PaintToRect(const gfx::Rect& dest_rect, CGContextRef target);
-#elif defined(OS_LINUX)
-  Display* display() const { return display_; }
-  XID root_window() const { return root_window_; }
-
-  // Copy from the server-side backing store to the target window
-  //   display: the display of the backing store and target window
-  //   damage: the area to copy
-  //   target: the X id of the target window
-  void ShowRect(const gfx::Rect& damage, XID target);
-
-  // Paints the server-side backing store data to a SkBitmap. On failure, the
-  // return bitmap will be isNull().
-  SkBitmap PaintRectToBitmap(const gfx::Rect& rect);
-#endif
-
-#if defined(TOOLKIT_GTK)
-  // Paint the backing store into the target's |dest_rect|.
-  void PaintToRect(const gfx::Rect& dest_rect, GdkDrawable* target);
-#endif
+  // The number of bytes that this backing store consumes. The default
+  // implementation just assumes there's 32 bits per pixel over the current
+  // size of the screen. Implementations may override this if they have more
+  // information about the color depth.
+  virtual size_t MemorySize();
 
   // Paints the bitmap from the renderer onto the backing store.  bitmap_rect
-  // gives the location of bitmap, and copy_rect specifies the subregion of
+  // gives the location of bitmap, and copy_rects specifies the subregion(s) of
   // the backingstore to be painted from the bitmap.
-  void PaintRect(base::ProcessHandle process,
-                 TransportDIB* bitmap,
-                 const gfx::Rect& bitmap_rect,
-                 const gfx::Rect& copy_rect);
+  //
+  // The value placed into |*painted_synchronously| indicates if the paint was
+  // completed synchronously and the TransportDIB can be freed. False means that
+  // the backing store may still be using the transport DIB and it will manage
+  // notifying the RenderWidgetHost that it's done with it via
+  // DonePaintingToBackingStore().
+  virtual void PaintToBackingStore(
+      RenderProcessHost* process,
+      TransportDIB::Id bitmap,
+      const gfx::Rect& bitmap_rect,
+      const std::vector<gfx::Rect>& copy_rects,
+      bool* painted_synchronously) = 0;
+
+  // Extracts the gives subset of the backing store and copies it to the given
+  // PlatformCanvas. The PlatformCanvas should not be initialized. This function
+  // will call initialize() with the correct size. The return value indicates
+  // success.
+  virtual bool CopyFromBackingStore(const gfx::Rect& rect,
+                                    skia::PlatformCanvas* output) = 0;
 
   // Scrolls the contents of clip_rect in the backing store by dx or dy (but dx
   // and dy cannot both be non-zero).
-  void ScrollRect(int dx, int dy,
-                  const gfx::Rect& clip_rect,
-                  const gfx::Size& view_size);
+  virtual void ScrollBackingStore(int dx, int dy,
+                                  const gfx::Rect& clip_rect,
+                                  const gfx::Size& view_size) = 0;
+ protected:
+  // Can only be constructed via subclasses.
+  BackingStore(RenderWidgetHost* widget, const gfx::Size& size);
 
  private:
-#if defined(OS_MACOSX)
-  // Creates a CGLayer associated with its owner view's window's graphics
-  // context, sized properly for the backing store.  Returns NULL if the owner
-  // is not in a window with a CGContext.  cg_layer_ is assigned this method's
-  // result.
-  CGLayerRef CreateCGLayer();
-
-  // Creates a CGBitmapContext sized properly for the backing store.  The
-  // owner view need not be in a window.  cg_bitmap_ is assigned this method's
-  // result.
-  CGContextRef CreateCGBitmapContext();
-#endif
-
   // The owner of this backing store.
   RenderWidgetHost* render_widget_host_;
 
   // The size of the backing store.
   gfx::Size size_;
 
-#if defined(OS_WIN)
-  // The backing store dc.
-  HDC hdc_;
-  // Handle to the backing store dib.
-  HANDLE backing_store_dib_;
-  // Handle to the original bitmap in the dc.
-  HANDLE original_bitmap_;
-  // Number of bits per pixel of the screen.
-  int color_depth_;
-#elif defined(OS_MACOSX)
-  scoped_cftyperef<CGContextRef> cg_bitmap_;
-  scoped_cftyperef<CGLayerRef> cg_layer_;
-#elif defined(OS_LINUX) && defined(USE_GL)
-  Display* const display_;
-
-  // The parent window for this backing store.
-  const XID root_window_;
-
-  unsigned int texture_id_;  // 0 when uninitialized.
-
-  // The size of the texture loaded into GL. This is 0x0 when there is no
-  // texture loaded. This may be different than the size of the backing store
-  // because we could have been resized without yet getting the updated
-  // bitmap.
-  gfx::Size texture_size_;
-
-#elif defined(OS_LINUX) && !defined(USE_GL)
-  // Paints the bitmap from the renderer onto the backing store without
-  // using Xrender to composite the pixmaps.
-  void PaintRectWithoutXrender(TransportDIB* bitmap,
-                               const gfx::Rect& bitmap_rect,
-                               const gfx::Rect& copy_rect);
-
-  // This is the connection to the X server where this backing store will be
-  // displayed.
-  Display* const display_;
-  // What flavor, if any, MIT-SHM (X shared memory) support we have.
-  const x11_util::SharedMemorySupport shared_memory_support_;
-  // If this is true, then we can use Xrender to composite our pixmaps.
-  const bool use_render_;
-  // If |use_render_| is false, this is the number of bits-per-pixel for |depth|
-  int pixmap_bpp_;
-  // if |use_render_| is false, we need the Visual to get the RGB masks.
-  void* const visual_;
-  // This is the depth of the target window.
-  const int visual_depth_;
-  // The parent window (probably a GtkDrawingArea) for this backing store.
-  const XID root_window_;
-  // This is a handle to the server side pixmap which is our backing store.
-  XID pixmap_;
-  // This is the RENDER picture pointing at |pixmap_|.
-  XID picture_;
-  // This is a default graphic context, used in XCopyArea
-  void* pixmap_gc_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(BackingStore);
 };
 
diff --git a/chrome/browser/renderer_host/backing_store_glx.h b/chrome/browser/renderer_host/backing_store_glx.h
new file mode 100644
index 0000000..534c052
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_glx.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2010 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_BACKING_STORE_GLX_H_
+#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_GLX_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/common/x11_util.h"
+
+class BackingStoreGLX : public BackingStore {
+ public:
+  // 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.
+  BackingStoreGLX(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
+  BackingStoreGLX(RenderWidgetHost* widget, const gfx::Size& size);
+
+  virtual ~BackingStoreGLX();
+
+  Display* display() const { return display_; }
+  XID root_window() const { return root_window_; }
+
+  // Copy from the server-side backing store to the target window
+  //   display: the display of the backing store and target window
+  //   damage: the area to copy
+  //   target: the X id of the target window
+  void ShowRect(const gfx::Rect& damage, XID target);
+
+  // Paints the server-side backing store data to a SkBitmap. On failure, the
+  // return bitmap will be isNull().
+  SkBitmap PaintRectToBitmap(const gfx::Rect& rect);
+
+#if defined(TOOLKIT_GTK)
+  // Paint the backing store into the target's |dest_rect|.
+  void PaintToRect(const gfx::Rect& dest_rect, GdkDrawable* target);
+#endif
+
+  // BackingStore implementation.
+  virtual size_t MemorySize();
+  virtual void PaintRect(base::ProcessHandle process,
+                         TransportDIB* bitmap,
+                         const gfx::Rect& bitmap_rect,
+                         const gfx::Rect& copy_rect);
+  virtual void ScrollRect(int dx, int dy,
+                          const gfx::Rect& clip_rect,
+                          const gfx::Size& view_size);
+
+ private:
+  Display* const display_;
+
+  // The parent window for this backing store.
+  const XID root_window_;
+
+  unsigned int texture_id_;  // 0 when uninitialized.
+
+  // The size of the texture loaded into GL. This is 0x0 when there is no
+  // texture loaded. This may be different than the size of the backing store
+  // because we could have been resized without yet getting the updated
+  // bitmap.
+  gfx::Size texture_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackingStoreGLX);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_GLX_H_
diff --git a/chrome/browser/renderer_host/backing_store_mac.h b/chrome/browser/renderer_host/backing_store_mac.h
new file mode 100644
index 0000000..3d9e7938
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_mac.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2010 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_BACKING_STORE_MAC_H_
+#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MAC_H_
+
+#include "base/basictypes.h"
+#include "base/scoped_cftyperef.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+
+class BackingStoreMac : public BackingStore {
+ public:
+  BackingStoreMac(RenderWidgetHost* widget, const gfx::Size& size);
+  virtual ~BackingStoreMac();
+
+  // A CGLayer that stores the contents of the backing store, cached in GPU
+  // memory if possible.
+  CGLayerRef cg_layer() { return cg_layer_; }
+
+  // A CGBitmapContext that stores the contents of the backing store if the
+  // corresponding Cocoa view has not been inserted into an NSWindow yet.
+  CGContextRef cg_bitmap() { return cg_bitmap_; }
+
+  // BackingStore implementation.
+  virtual void PaintToBackingStore(
+      RenderProcessHost* process,
+      TransportDIB::Id bitmap,
+      const gfx::Rect& bitmap_rect,
+      const std::vector<gfx::Rect>& copy_rects,
+      bool* painted_synchronously);
+  virtual bool CopyFromBackingStore(const gfx::Rect& rect,
+                                    skia::PlatformCanvas* output);
+  virtual void ScrollBackingStore(int dx, int dy,
+                                  const gfx::Rect& clip_rect,
+                                  const gfx::Size& view_size);
+
+ private:
+  // Creates a CGLayer associated with its owner view's window's graphics
+  // context, sized properly for the backing store.  Returns NULL if the owner
+  // is not in a window with a CGContext.  cg_layer_ is assigned this method's
+  // result.
+  CGLayerRef CreateCGLayer();
+
+  // Creates a CGBitmapContext sized properly for the backing store.  The
+  // owner view need not be in a window.  cg_bitmap_ is assigned this method's
+  // result.
+  CGContextRef CreateCGBitmapContext();
+
+  scoped_cftyperef<CGContextRef> cg_bitmap_;
+  scoped_cftyperef<CGLayerRef> cg_layer_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackingStoreMac);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MAC_H_
diff --git a/chrome/browser/renderer_host/backing_store_mac.mm b/chrome/browser/renderer_host/backing_store_mac.mm
index 0b8fa6e..1324593 100644
--- a/chrome/browser/renderer_host/backing_store_mac.mm
+++ b/chrome/browser/renderer_host/backing_store_mac.mm
@@ -1,15 +1,16 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
 #import <Cocoa/Cocoa.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_view.h"
+#include "chrome/browser/renderer_host/backing_store_mac.h"
 
 #include "base/logging.h"
 #include "base/mac_util.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
 #include "chrome/common/transport_dib.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -22,9 +23,9 @@
 // allows acclerated drawing into the layer and lets scrolling and such happen
 // all or mostly on the GPU, which is good for performance.
 
-BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
-    : render_widget_host_(widget),
-      size_(size) {
+BackingStoreMac::BackingStoreMac(RenderWidgetHost* widget,
+                                 const gfx::Size& size)
+    : BackingStore(widget, size) {
   cg_layer_.reset(CreateCGLayer());
   if (!cg_layer_) {
     // The view isn't in a window yet.  Use a CGBitmapContext for now.
@@ -32,23 +33,27 @@
   }
 }
 
-BackingStore::~BackingStore() {
+BackingStoreMac::~BackingStoreMac() {
 }
 
-size_t BackingStore::MemorySize() {
-  // Estimate memory usage as 4 bytes per pixel.
-  return size_.GetArea() * 4;
-}
+void BackingStoreMac::PaintToBackingStore(
+    RenderProcessHost* process,
+    TransportDIB::Id bitmap,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects,
+    bool* painted_synchronously) {
+  // Our paints are always synchronous and the caller can free the TransportDIB,
+  // even on failure.
+  *painted_synchronously = true;
 
-// Paint the contents of a TransportDIB into a rectangle of our CGLayer
-void BackingStore::PaintRect(base::ProcessHandle process,
-                             TransportDIB* bitmap,
-                             const gfx::Rect& bitmap_rect,
-                             const gfx::Rect& copy_rect) {
   DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
 
+  TransportDIB* dib = process->GetTransportDIB(bitmap);
+  if (!dib)
+    return;
+
   scoped_cftyperef<CGDataProviderRef> data_provider(
-      CGDataProviderCreateWithData(NULL, bitmap->memory(),
+      CGDataProviderCreateWithData(NULL, dib->memory(),
       bitmap_rect.width() * bitmap_rect.height() * 4, NULL));
 
   scoped_cftyperef<CGImageRef> bitmap_image(
@@ -57,51 +62,71 @@
           kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
           data_provider, NULL, false, kCGRenderingIntentDefault));
 
-  // Only the subpixels given by copy_rect have pixels to copy.
-  scoped_cftyperef<CGImageRef> image(
-      CGImageCreateWithImageInRect(bitmap_image, CGRectMake(
-          copy_rect.x() - bitmap_rect.x(),
-          copy_rect.y() - bitmap_rect.y(),
-          copy_rect.width(),
-          copy_rect.height())));
+  for (size_t i = 0; i < copy_rects.size(); i++) {
+    const gfx::Rect& copy_rect = copy_rects[i];
 
-  if (!cg_layer()) {
-    // The view may have moved to a window.  Try to get a CGLayer.
-    cg_layer_.reset(CreateCGLayer());
-    if (cg_layer()) {
-      // now that we have a layer, copy the cached image into it
-      scoped_cftyperef<CGImageRef> bitmap_image(
-          CGBitmapContextCreateImage(cg_bitmap_));
-      CGContextDrawImage(CGLayerGetContext(cg_layer()),
-                         CGRectMake(0, 0, size().width(), size().height()),
-                         bitmap_image);
-      // Discard the cache bitmap, since we no longer need it.
-      cg_bitmap_.reset(NULL);
+    // Only the subpixels given by copy_rect have pixels to copy.
+    scoped_cftyperef<CGImageRef> image(
+        CGImageCreateWithImageInRect(bitmap_image, CGRectMake(
+            copy_rect.x() - bitmap_rect.x(),
+            copy_rect.y() - bitmap_rect.y(),
+            copy_rect.width(),
+            copy_rect.height())));
+
+    if (!cg_layer()) {
+      // The view may have moved to a window.  Try to get a CGLayer.
+      cg_layer_.reset(CreateCGLayer());
+      if (cg_layer()) {
+        // now that we have a layer, copy the cached image into it
+        scoped_cftyperef<CGImageRef> bitmap_image(
+            CGBitmapContextCreateImage(cg_bitmap_));
+        CGContextDrawImage(CGLayerGetContext(cg_layer()),
+                           CGRectMake(0, 0, size().width(), size().height()),
+                           bitmap_image);
+        // Discard the cache bitmap, since we no longer need it.
+        cg_bitmap_.reset(NULL);
+      }
     }
-  }
 
-  DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
+    DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
 
-  if (cg_layer()) {
-    // The CGLayer's origin is in the lower left, but flipping the CTM would
-    // cause the image to get drawn upside down.  So we move the rectangle
-    // to the right position before drawing the image.
-    CGContextRef layer = CGLayerGetContext(cg_layer());
-    gfx::Rect paint_rect = copy_rect;
-    paint_rect.set_y(size_.height() - copy_rect.bottom());
-    CGContextDrawImage(layer, paint_rect.ToCGRect(), image);
-  } else {
-    // The layer hasn't been created yet, so draw into the cache bitmap.
-    gfx::Rect paint_rect = copy_rect;
-    paint_rect.set_y(size_.height() - copy_rect.bottom());
-    CGContextDrawImage(cg_bitmap_, paint_rect.ToCGRect(), image);
+    if (cg_layer()) {
+      // The CGLayer's origin is in the lower left, but flipping the CTM would
+      // cause the image to get drawn upside down.  So we move the rectangle
+      // to the right position before drawing the image.
+      CGContextRef layer = CGLayerGetContext(cg_layer());
+      gfx::Rect paint_rect = copy_rect;
+      paint_rect.set_y(size().height() - copy_rect.bottom());
+      CGContextDrawImage(layer, paint_rect.ToCGRect(), image);
+    } else {
+      // The layer hasn't been created yet, so draw into the cache bitmap.
+      gfx::Rect paint_rect = copy_rect;
+      paint_rect.set_y(size().height() - copy_rect.bottom());
+      CGContextDrawImage(cg_bitmap_, paint_rect.ToCGRect(), image);
+    }
   }
 }
 
+bool BackingStoreMac::CopyFromBackingStore(const gfx::Rect& rect,
+                                           skia::PlatformCanvas* output) {
+  if (!output->initialize(rect.width(), rect.height(), true))
+    return false;
+
+  CGContextRef temp_context = output->beginPlatformPaint();
+  CGContextSaveGState(temp_context);
+  CGContextTranslateCTM(temp_context, 0.0, size().height());
+  CGContextScaleCTM(temp_context, 1.0, -1.0);
+  CGContextDrawLayerAtPoint(temp_context, CGPointMake(rect.x(), rect.y()),
+                            cg_layer());
+  CGContextRestoreGState(temp_context);
+  output->endPlatformPaint();
+  return true;
+}
+
 // Scroll the contents of our CGLayer
-void BackingStore::ScrollRect(int dx, int dy,
-                              const gfx::Rect& clip_rect,
-                              const gfx::Size& view_size) {
+void BackingStoreMac::ScrollBackingStore(int dx, int dy,
+                                         const gfx::Rect& clip_rect,
+                                         const gfx::Size& view_size) {
   DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
 
   // "Scroll" the contents of the layer by creating a new CGLayer,
@@ -114,10 +139,10 @@
   // translated by the scroll.)
 
   // We assume |clip_rect| is contained within the backing store.
-  DCHECK(clip_rect.bottom() <= size_.height());
-  DCHECK(clip_rect.right() <= size_.width());
+  DCHECK(clip_rect.bottom() <= size().height());
+  DCHECK(clip_rect.right() <= size().width());
 
-  if ((dx || dy) && abs(dx) < size_.width() && abs(dy) < size_.height()) {
+  if ((dx || dy) && abs(dx) < size().width() && abs(dy) < size().height()) {
     if (cg_layer()) {
       scoped_cftyperef<CGLayerRef> new_layer(CreateCGLayer());
 
@@ -127,10 +152,11 @@
       CGContextRef layer = CGLayerGetContext(new_layer);
       CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer());
       CGContextSaveGState(layer);
-      CGContextClipToRect(layer, CGRectMake(clip_rect.x(),
-                                            size_.height() - clip_rect.bottom(),
-                                            clip_rect.width(),
-                                            clip_rect.height()));
+      CGContextClipToRect(layer,
+                          CGRectMake(clip_rect.x(),
+                                     size().height() - clip_rect.bottom(),
+                                     clip_rect.width(),
+                                     clip_rect.height()));
       CGContextDrawLayerAtPoint(layer, CGPointMake(dx, -dy), cg_layer());
       CGContextRestoreGState(layer);
       cg_layer_.swap(new_layer);
@@ -140,16 +166,16 @@
       scoped_cftyperef<CGImageRef> bitmap_image(
           CGBitmapContextCreateImage(cg_bitmap_));
       CGContextDrawImage(new_bitmap,
-                         CGRectMake(0, 0, size_.width(), size_.height()),
+                         CGRectMake(0, 0, size().width(), size().height()),
                          bitmap_image);
       CGContextSaveGState(new_bitmap);
       CGContextClipToRect(new_bitmap,
                           CGRectMake(clip_rect.x(),
-                                     size_.height() - clip_rect.bottom(),
+                                     size().height() - clip_rect.bottom(),
                                      clip_rect.width(),
                                      clip_rect.height()));
       CGContextDrawImage(new_bitmap,
-                         CGRectMake(dx, -dy, size_.width(), size_.height()),
+                         CGRectMake(dx, -dy, size().width(), size().height()),
                          bitmap_image);
       CGContextRestoreGState(new_bitmap);
       cg_bitmap_.swap(new_bitmap);
@@ -157,7 +183,7 @@
   }
 }
 
-CGLayerRef BackingStore::CreateCGLayer() {
+CGLayerRef BackingStoreMac::CreateCGLayer() {
   // The CGLayer should be optimized for drawing into the containing window,
   // so extract a CGContext corresponding to the window to be passed to
   // CGLayerCreateWithContext.
@@ -176,19 +202,19 @@
   DCHECK(cg_context);
 
   CGLayerRef layer = CGLayerCreateWithContext(cg_context,
-                                              size_.ToCGSize(),
+                                              size().ToCGSize(),
                                               NULL);
   DCHECK(layer);
 
   return layer;
 }
 
-CGContextRef BackingStore::CreateCGBitmapContext() {
+CGContextRef BackingStoreMac::CreateCGBitmapContext() {
   // A CGBitmapContext serves as a stand-in for the layer before the view is
   // in a containing window.
   CGContextRef context = CGBitmapContextCreate(NULL,
-                                               size_.width(), size_.height(),
-                                               8, size_.width() * 4,
+                                               size().width(), size().height(),
+                                               8, size().width() * 4,
                                                mac_util::GetSystemColorSpace(),
                                                kCGImageAlphaPremultipliedFirst |
                                                    kCGBitmapByteOrder32Host);
diff --git a/chrome/browser/renderer_host/backing_store_manager.cc b/chrome/browser/renderer_host/backing_store_manager.cc
index 4e21d04a..39149f2 100644
--- a/chrome/browser/renderer_host/backing_store_manager.cc
+++ b/chrome/browser/renderer_host/backing_store_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -175,14 +175,17 @@
 }
 
 // static
-BackingStore* BackingStoreManager::PrepareBackingStore(
+void BackingStoreManager::PrepareBackingStore(
     RenderWidgetHost* host,
     const gfx::Size& backing_store_size,
-    base::ProcessHandle process_handle,
-    TransportDIB* bitmap,
+    TransportDIB::Id bitmap,
     const gfx::Rect& bitmap_rect,
     const std::vector<gfx::Rect>& copy_rects,
-    bool* needs_full_paint) {
+    bool* needs_full_paint,
+    bool* painted_synchronously) {
+  // Default to declaring we're done using the transport DIB so it can be freed.
+  *painted_synchronously = true;
+
   BackingStore* backing_store = GetBackingStore(host, backing_store_size);
   if (!backing_store) {
     // We need to get Webkit to generate a new paint here, as we
@@ -194,19 +197,14 @@
       *needs_full_paint = true;
       // Makes no sense to paint the transport dib if we are going
       // to request a full paint.
-      return NULL;
+      return;
     }
     backing_store = CreateBackingStore(host, backing_store_size);
   }
 
-  DCHECK(backing_store != NULL);
-
-  for (size_t i = 0; i < copy_rects.size(); ++i) {
-    backing_store->PaintRect(process_handle, bitmap, bitmap_rect,
-                             copy_rects[i]);
-  }
-
-  return backing_store;
+  backing_store->PaintToBackingStore(host->process(), bitmap,
+                                     bitmap_rect, copy_rects,
+                                     painted_synchronously);
 }
 
 // static
diff --git a/chrome/browser/renderer_host/backing_store_manager.h b/chrome/browser/renderer_host/backing_store_manager.h
index 847d8a1c..96edd93 100644
--- a/chrome/browser/renderer_host/backing_store_manager.h
+++ b/chrome/browser/renderer_host/backing_store_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -11,10 +11,10 @@
 #include "base/gfx/rect.h"
 #include "base/gfx/size.h"
 #include "base/process.h"
+#include "chrome/common/transport_dib.h"
 
 class BackingStore;
 class RenderWidgetHost;
-class TransportDIB;
 
 // This class manages backing stores in the browsr. Every RenderWidgetHost is
 // associated with a backing store which it requests from this class.  The
@@ -30,14 +30,11 @@
   static BackingStore* GetBackingStore(RenderWidgetHost* host,
                                        const gfx::Size& desired_size);
 
-  // Returns a backing store which is fully ready for consumption, i.e. the
-  // bitmap from the renderer has been copied into the backing store dc, or the
-  // bitmap in the backing store dc references the renderer bitmap.
+  // Makes a backing store which is fully ready for consumption, i.e. the
+  // bitmap from the renderer has been copied into the backing store.
   //
   // backing_store_size
   //   The desired backing store dimensions.
-  // process_handle
-  //   The renderer process handle.
   // bitmap_section
   //   The bitmap section from the renderer.
   // bitmap_rect
@@ -45,14 +42,19 @@
   // needs_full_paint
   //   Set if we need to send out a request to paint the view
   //   to the renderer.
-  static BackingStore* PrepareBackingStore(
+  // painted_synchronously
+  //   Will be set by the function if the request was processed synchronously,
+  //   and the bitmap is done being used. False means that the backing store
+  //   will paint the bitmap at a later time and that the TransportDIB can't be
+  //   freed (it will be the backing store's job to free it later).
+  static void PrepareBackingStore(
       RenderWidgetHost* host,
       const gfx::Size& backing_store_size,
-      base::ProcessHandle process_handle,
-      TransportDIB* bitmap,
+      TransportDIB::Id bitmap,
       const gfx::Rect& bitmap_rect,
       const std::vector<gfx::Rect>& copy_rects,
-      bool* needs_full_paint);
+      bool* needs_full_paint,
+      bool* painted_synchronously);
 
   // Returns a matching backing store for the host.
   // Returns NULL if we fail to find one.
diff --git a/chrome/browser/renderer_host/backing_store_proxy.cc b/chrome/browser/renderer_host/backing_store_proxy.cc
new file mode 100644
index 0000000..b39eebd1
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_proxy.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2010 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/renderer_host/backing_store_proxy.h"
+
+#include "base/gfx/rect.h"
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/common/gpu_messages.h"
+#include "chrome/common/render_messages.h"
+
+BackingStoreProxy::BackingStoreProxy(RenderWidgetHost* widget,
+                                     const gfx::Size& size,
+                                     GpuProcessHost* process,
+                                     int32 routing_id)
+    : BackingStore(widget, size),
+      process_(process),
+      routing_id_(routing_id),
+      waiting_for_paint_ack_(false) {
+  process_->AddRoute(routing_id_, this);
+}
+
+BackingStoreProxy::~BackingStoreProxy() {
+  process_->RemoveRoute(routing_id_);
+}
+
+void BackingStoreProxy::PaintToBackingStore(
+    RenderProcessHost* process,
+    TransportDIB::Id bitmap,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects,
+    bool* painted_synchronously) {
+  DCHECK(!waiting_for_paint_ack_);
+
+  if (process_->Send(new GpuMsg_PaintToBackingStore(
+         routing_id_, ::GetProcessId(process->GetHandle()),
+         bitmap, bitmap_rect, copy_rects))) {
+    // Message sent successfully, so the caller can not destroy the
+    // TransportDIB. OnDonePaintingToBackingStore will free it later.
+    *painted_synchronously = false;
+    waiting_for_paint_ack_ = true;
+  } else {
+    // On error, we're done with the TransportDIB and the caller can free it.
+    *painted_synchronously = true;
+  }
+}
+
+bool BackingStoreProxy::CopyFromBackingStore(const gfx::Rect& rect,
+                                             skia::PlatformCanvas* output) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void BackingStoreProxy::ScrollBackingStore(int dx, int dy,
+                                           const gfx::Rect& clip_rect,
+                                           const gfx::Size& view_size) {
+  process_->Send(new GpuMsg_ScrollBackingStore(routing_id_, dx, dy,
+                                               clip_rect, view_size));
+}
+
+void BackingStoreProxy::OnMessageReceived(const IPC::Message& msg) {
+  IPC_BEGIN_MESSAGE_MAP(BackingStoreProxy, msg)
+    IPC_MESSAGE_HANDLER(GpuHostMsg_PaintToBackingStore_ACK,
+                        OnPaintToBackingStoreACK)
+  IPC_END_MESSAGE_MAP_EX()
+}
+
+void BackingStoreProxy::OnChannelConnected(int32 peer_pid) {
+}
+
+void BackingStoreProxy::OnChannelError() {
+  if (waiting_for_paint_ack_) {
+    // If the GPU process dies while painting, the renderer will be waiting for
+    // the paint ACK before painting any more. Since no ack is coming, we
+    // manually declare that we're done with the transport DIB here so it can
+    // continue.
+    OnPaintToBackingStoreACK();
+  }
+
+  // FIXME(brettw) does this mean we aren't getting any more messages and we
+  // should delete outselves?
+}
+
+void BackingStoreProxy::OnPaintToBackingStoreACK() {
+  DCHECK(waiting_for_paint_ack_);
+  render_widget_host()->DonePaintingToBackingStore();
+  waiting_for_paint_ack_ = false;
+}
diff --git a/chrome/browser/renderer_host/backing_store_proxy.h b/chrome/browser/renderer_host/backing_store_proxy.h
new file mode 100644
index 0000000..f82d9488
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_proxy.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 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_BACKING_STORE_PROXY_H_
+#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_PROXY_H_
+
+#include "base/basictypes.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+#include "ipc/ipc_channel.h"
+
+#include <windows.h>
+
+class GpuProcessHost;
+
+class BackingStoreProxy : public BackingStore,
+                          public IPC::Channel::Listener {
+ public:
+  BackingStoreProxy(RenderWidgetHost* widget, const gfx::Size& size,
+                    GpuProcessHost* process, int32 routing_id);
+  virtual ~BackingStoreProxy();
+
+  // BackingStore implementation.
+  virtual void PaintToBackingStore(RenderProcessHost* process,
+                                   TransportDIB::Id bitmap,
+                                   const gfx::Rect& bitmap_rect,
+                                   const std::vector<gfx::Rect>& copy_rects,
+                                   bool* painted_synchronously);
+  virtual bool CopyFromBackingStore(const gfx::Rect& rect,
+                                    skia::PlatformCanvas* output);
+  virtual void ScrollBackingStore(int dx, int dy,
+                                  const gfx::Rect& clip_rect,
+                                  const gfx::Size& view_size);
+
+  // IPC::Channel::Listener implementation.
+  virtual void OnMessageReceived(const IPC::Message& message);
+  virtual void OnChannelConnected(int32 peer_pid);
+  virtual void OnChannelError();
+
+ private:
+  // Message handlers.
+  void OnPaintToBackingStoreACK();
+
+  GpuProcessHost* process_;
+  int32 routing_id_;
+
+  // Set to true when we're waiting for the GPU process to do a paint and send
+  // back a "done" message. In this case, the renderer will be waiting for our
+  // message that we're done using the backing store.
+  bool waiting_for_paint_ack_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackingStoreProxy);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_PROXY_H_
diff --git a/chrome/browser/renderer_host/backing_store_win.cc b/chrome/browser/renderer_host/backing_store_win.cc
index ae772dc..ede1c40 100644
--- a/chrome/browser/renderer_host/backing_store_win.cc
+++ b/chrome/browser/renderer_host/backing_store_win.cc
@@ -1,14 +1,16 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/backing_store_win.h"
 
 #include "app/gfx/gdi_util.h"
 #include "base/command_line.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
 #include "chrome/browser/renderer_host/render_widget_host.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/transport_dib.h"
+#include "skia/ext/platform_canvas.h"
 
 namespace {
 
@@ -30,7 +32,7 @@
   hdr.bV5ClrUsed = 0;
   hdr.bV5ClrImportant = 0;
 
-  if (BackingStore::ColorManagementEnabled()) {
+  if (BackingStoreWin::ColorManagementEnabled()) {
     hdr.bV5CSType = LCS_sRGB;
     hdr.bV5Intent = LCS_GM_IMAGES;
   }
@@ -67,11 +69,8 @@
 
 }  // namespace
 
-// BackingStore (Windows) ------------------------------------------------------
-
-BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
-    : render_widget_host_(widget),
-      size_(size),
+BackingStoreWin::BackingStoreWin(RenderWidgetHost* widget, const gfx::Size& size)
+    : BackingStore(widget, size),
       backing_store_dib_(NULL),
       original_bitmap_(NULL) {
   HDC screen_dc = ::GetDC(NULL);
@@ -85,7 +84,7 @@
   ReleaseDC(NULL, screen_dc);
 }
 
-BackingStore::~BackingStore() {
+BackingStoreWin::~BackingStoreWin() {
   DCHECK(hdc_);
   if (original_bitmap_) {
     SelectObject(hdc_, original_bitmap_);
@@ -97,12 +96,8 @@
   DeleteDC(hdc_);
 }
 
-size_t BackingStore::MemorySize() {
-  return size_.GetArea() * (color_depth_ / 8);
-}
-
 // static
-bool BackingStore::ColorManagementEnabled() {
+bool BackingStoreWin::ColorManagementEnabled() {
   static bool enabled = false;
   static bool checked = false;
   if (!checked) {
@@ -113,13 +108,23 @@
   return enabled;
 }
 
-void BackingStore::PaintRect(base::ProcessHandle process,
-                             TransportDIB* bitmap,
-                             const gfx::Rect& bitmap_rect,
-                             const gfx::Rect& copy_rect) {
+size_t BackingStoreWin::MemorySize() {
+  return size().GetArea() * (color_depth_ / 8);
+}
+
+void BackingStoreWin::PaintToBackingStore(
+    RenderProcessHost* process,
+    TransportDIB::Id bitmap,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects,
+    bool* painted_synchronously) {
+  // Our paints are always synchronous and the TransportDIB can be freed when
+  // we're done (even on error).
+  *painted_synchronously = true;
+
   if (!backing_store_dib_) {
-    backing_store_dib_ = CreateDIB(hdc_, size_.width(),
-                                   size_.height(), color_depth_);
+    backing_store_dib_ = CreateDIB(hdc_, size().width(),
+                                   size().height(), color_depth_);
     if (!backing_store_dib_) {
       NOTREACHED();
       return;
@@ -127,28 +132,46 @@
     original_bitmap_ = SelectObject(hdc_, backing_store_dib_);
   }
 
+  TransportDIB* dib = process->GetTransportDIB(bitmap);
+  if (!dib)
+    return;
+
   BITMAPINFOHEADER hdr;
   gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr);
   // Account for a bitmap_rect that exceeds the bounds of our view
-  gfx::Rect view_rect(0, 0, size_.width(), size_.height());
-  gfx::Rect paint_rect = view_rect.Intersect(copy_rect);
+  gfx::Rect view_rect(0, 0, size().width(), size().height());
 
-  CallStretchDIBits(hdc_,
-                    paint_rect.x(),
-                    paint_rect.y(),
-                    paint_rect.width(),
-                    paint_rect.height(),
-                    paint_rect.x() - bitmap_rect.x(),
-                    paint_rect.y() - bitmap_rect.y(),
-                    paint_rect.width(),
-                    paint_rect.height(),
-                    bitmap->memory(),
-                    reinterpret_cast<BITMAPINFO*>(&hdr));
+  for (size_t i = 0; i < copy_rects.size(); i++) {
+    gfx::Rect paint_rect = view_rect.Intersect(copy_rects[i]);
+    CallStretchDIBits(hdc_,
+                      paint_rect.x(),
+                      paint_rect.y(),
+                      paint_rect.width(),
+                      paint_rect.height(),
+                      paint_rect.x() - bitmap_rect.x(),
+                      paint_rect.y() - bitmap_rect.y(),
+                      paint_rect.width(),
+                      paint_rect.height(),
+                      dib->memory(),
+                      reinterpret_cast<BITMAPINFO*>(&hdr));
+  }
 }
 
-void BackingStore::ScrollRect(int dx, int dy,
-                              const gfx::Rect& clip_rect,
-                              const gfx::Size& view_size) {
+bool BackingStoreWin::CopyFromBackingStore(const gfx::Rect& rect,
+                                           skia::PlatformCanvas* output) {
+  if (!output->initialize(rect.width(), rect.height(), true))
+    return false;
+
+  HDC temp_dc = output->beginPlatformPaint();
+  BitBlt(temp_dc, 0, 0, rect.width(), rect.height(),
+         hdc(), rect.x(), rect.y(), SRCCOPY);
+  output->endPlatformPaint();
+  return true;
+}
+
+void BackingStoreWin::ScrollBackingStore(int dx, int dy,
+                                         const gfx::Rect& clip_rect,
+                                         const gfx::Size& view_size) {
   RECT damaged_rect, r = clip_rect.ToRECT();
   ScrollDC(hdc_, dx, dy, NULL, &r, NULL, &damaged_rect);
 
diff --git a/chrome/browser/renderer_host/backing_store_win.h b/chrome/browser/renderer_host/backing_store_win.h
new file mode 100644
index 0000000..f280bca
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_win.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 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_BACKING_STORE_WIN_H_
+#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_WIN_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+
+class BackingStoreWin : public BackingStore {
+ public:
+  BackingStoreWin(RenderWidgetHost* widget, const gfx::Size& size);
+  virtual ~BackingStoreWin();
+
+  HDC hdc() { return hdc_; }
+
+  // Returns true if we should convert to the monitor profile when painting.
+  static bool ColorManagementEnabled();
+
+  // BackingStore implementation.
+  virtual size_t MemorySize();
+  virtual void PaintToBackingStore(RenderProcessHost* process,
+                                   TransportDIB::Id bitmap,
+                                   const gfx::Rect& bitmap_rect,
+                                   const std::vector<gfx::Rect>& copy_rects,
+                                   bool* painted_synchronously);
+  virtual bool CopyFromBackingStore(const gfx::Rect& rect,
+                                    skia::PlatformCanvas* output);
+  virtual void ScrollBackingStore(int dx, int dy,
+                                  const gfx::Rect& clip_rect,
+                                  const gfx::Size& view_size);
+
+ private:
+  // The backing store dc.
+  HDC hdc_;
+
+  // Handle to the backing store dib.
+  HANDLE backing_store_dib_;
+
+  // Handle to the original bitmap in the dc.
+  HANDLE original_bitmap_;
+
+  // Number of bits per pixel of the screen.
+  int color_depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackingStoreWin);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_WIN_H_
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
index 1cf4620..af334fa4 100644
--- a/chrome/browser/renderer_host/backing_store_x.cc
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/backing_store_x.h"
 
 #include <stdlib.h>
 #include <sys/ipc.h>
@@ -16,12 +16,15 @@
 #include <utility>
 
 #include "base/compiler_specific.h"
+#include "base/gfx/rect.h"
 #include "base/histogram.h"
 #include "base/logging.h"
 #include "base/time.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
 #include "chrome/common/transport_dib.h"
 #include "chrome/common/x11_util.h"
 #include "chrome/common/x11_util_internal.h"
+#include "skia/ext/platform_canvas.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 // X Backing Stores:
@@ -45,12 +48,11 @@
   shmdt(shminfo->shmaddr);
 }
 
-BackingStore::BackingStore(RenderWidgetHost* widget,
-                           const gfx::Size& size,
-                           void* visual,
-                           int depth)
-    : render_widget_host_(widget),
-      size_(size),
+BackingStoreX::BackingStoreX(RenderWidgetHost* widget,
+                            const gfx::Size& size,
+                            void* visual,
+                            int depth)
+    : BackingStore(widget, size),
       display_(x11_util::GetXDisplay()),
       shared_memory_support_(x11_util::QuerySharedMemorySupport(display_)),
       use_render_(x11_util::QueryRenderSupport(display_)),
@@ -76,9 +78,8 @@
   pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
 }
 
-BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
-    : render_widget_host_(widget),
-      size_(size),
+BackingStoreX::BackingStoreX(RenderWidgetHost* widget, const gfx::Size& size)
+    : BackingStore(widget, size),
       display_(NULL),
       shared_memory_support_(x11_util::SHARED_MEMORY_NONE),
       use_render_(false),
@@ -87,7 +88,7 @@
       root_window_(0) {
 }
 
-BackingStore::~BackingStore() {
+BackingStoreX::~BackingStoreX() {
   // In unit tests, display_ may be NULL.
   if (!display_)
     return;
@@ -97,16 +98,17 @@
   XFreeGC(display_, static_cast<GC>(pixmap_gc_));
 }
 
-size_t BackingStore::MemorySize() {
+size_t BackingStoreX::MemorySize() {
   if (!use_render_)
-    return size_.GetArea() * (pixmap_bpp_ / 8);
+    return size().GetArea() * (pixmap_bpp_ / 8);
   else
-    return size_.GetArea() * 4;
+    return size().GetArea() * 4;
 }
 
-void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap,
-                                           const gfx::Rect& bitmap_rect,
-                                           const gfx::Rect& copy_rect) {
+void BackingStoreX::PaintRectWithoutXrender(
+    TransportDIB* bitmap,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects) {
   const int width = bitmap_rect.width();
   const int height = bitmap_rect.height();
   Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height,
@@ -203,28 +205,37 @@
                  << " bpp:" << pixmap_bpp_ << ")";
   }
 
-  XCopyArea(display_,
-            pixmap,                           // src
-            pixmap_,                          // dest
-            static_cast<GC>(pixmap_gc_),      // gc
-            copy_rect.x() - bitmap_rect.x(),  // src_x
-            copy_rect.y() - bitmap_rect.y(),  // src_y
-            copy_rect.width(),                // width
-            copy_rect.height(),               // height
-            copy_rect.x(),                    // dest_x
-            copy_rect.y());                   // dest_y
+  for (size_t i = 0; i < copy_rects.size(); i++) {
+    const gfx::Rect& copy_rect = copy_rects[i];
+    XCopyArea(display_,
+              pixmap,                           // src
+              pixmap_,                          // dest
+              static_cast<GC>(pixmap_gc_),      // gc
+              copy_rect.x() - bitmap_rect.x(),  // src_x
+              copy_rect.y() - bitmap_rect.y(),  // src_y
+              copy_rect.width(),                // width
+              copy_rect.height(),               // height
+              copy_rect.x(),                    // dest_x
+              copy_rect.y());                   // dest_y
+  }
 
   XFreePixmap(display_, pixmap);
 }
 
-void BackingStore::PaintRect(base::ProcessHandle process,
-                             TransportDIB* bitmap,
-                             const gfx::Rect& bitmap_rect,
-                             const gfx::Rect& copy_rect) {
+void BackingStoreX::PaintToBackingStore(
+    RenderProcessHost* process,
+    TransportDIB::Id bitmap,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects,
+    bool* painted_synchronously) {
+  // Our paints are always synchronous and the caller can free the TransportDIB
+  // when we're done, even on error.
+  *painted_synchronously = true;
+
   if (!display_)
     return;
 
-  if (bitmap_rect.IsEmpty() || copy_rect.IsEmpty())
+  if (bitmap_rect.IsEmpty())
     return;
 
   const int width = bitmap_rect.width();
@@ -235,15 +246,19 @@
   if (width > 23170 || height > 23170)
     return;
 
+  TransportDIB* dib = process->GetTransportDIB(bitmap);
+  if (!dib)
+    return;
+
   if (!use_render_)
-    return PaintRectWithoutXrender(bitmap, bitmap_rect, copy_rect);
+    return PaintRectWithoutXrender(dib, bitmap_rect, copy_rects);
 
   Picture picture;
   Pixmap pixmap;
 
   if (shared_memory_support_ == x11_util::SHARED_MEMORY_PIXMAP) {
     XShmSegmentInfo shminfo = {0};
-    shminfo.shmseg = bitmap->MapToX(display_);
+    shminfo.shmseg = dib->MapToX(display_);
 
     // The NULL in the following is the |data| pointer: this is an artifact of
     // Xlib trying to be helpful, rather than just exposing the X protocol. It
@@ -261,12 +276,12 @@
     GC gc = XCreateGC(display_, pixmap, 0, NULL);
 
     if (shared_memory_support_ == x11_util::SHARED_MEMORY_PUTIMAGE) {
-      const XID shmseg = bitmap->MapToX(display_);
+      const XID shmseg = dib->MapToX(display_);
 
       XShmSegmentInfo shminfo;
       memset(&shminfo, 0, sizeof(shminfo));
       shminfo.shmseg = shmseg;
-      shminfo.shmaddr = static_cast<char*>(bitmap->memory());
+      shminfo.shmaddr = static_cast<char*>(dib->memory());
 
       // TODO(evanm): verify that Xlib isn't doing any conversions here.
       XImage* image = XShmCreateImage(display_, static_cast<Visual*>(visual_),
@@ -298,7 +313,7 @@
       image.red_mask = 0xff;
       image.green_mask = 0xff00;
       image.blue_mask = 0xff0000;
-      image.data = static_cast<char*>(bitmap->memory());
+      image.data = static_cast<char*>(dib->memory());
 
       XPutImage(display_, pixmap, gc, &image,
                 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
@@ -308,19 +323,23 @@
   }
 
   picture = x11_util::CreatePictureFromSkiaPixmap(display_, pixmap);
-  XRenderComposite(display_,
-                   PictOpSrc,                        // op
-                   picture,                          // src
-                   0,                                // mask
-                   picture_,                         // dest
-                   copy_rect.x() - bitmap_rect.x(),  // src_x
-                   copy_rect.y() - bitmap_rect.y(),  // src_y
-                   0,                                // mask_x
-                   0,                                // mask_y
-                   copy_rect.x(),                    // dest_x
-                   copy_rect.y(),                    // dest_y
-                   copy_rect.width(),                // width
-                   copy_rect.height());              // height
+
+  for (size_t i = 0; i < copy_rects.size(); i++) {
+    const gfx::Rect& copy_rect = copy_rects[i];
+    XRenderComposite(display_,
+                     PictOpSrc,                        // op
+                     picture,                          // src
+                     0,                                // mask
+                     picture_,                         // dest
+                     copy_rect.x() - bitmap_rect.x(),  // src_x
+                     copy_rect.y() - bitmap_rect.y(),  // src_y
+                     0,                                // mask_x
+                     0,                                // mask_y
+                     copy_rect.x(),                    // dest_x
+                     copy_rect.y(),                    // dest_y
+                     copy_rect.width(),                // width
+                     copy_rect.height());              // height
+  }
 
   // In the case of shared memory, we wait for the composite to complete so that
   // we are sure that the X server has finished reading from the shared memory
@@ -332,9 +351,83 @@
   XFreePixmap(display_, pixmap);
 }
 
-void BackingStore::ScrollRect(int dx, int dy,
-                              const gfx::Rect& clip_rect,
-                              const gfx::Size& view_size) {
+bool BackingStoreX::CopyFromBackingStore(const gfx::Rect& rect,
+                                         skia::PlatformCanvas* output) {
+  base::TimeTicks begin_time = base::TimeTicks::Now();
+  const int width = std::min(size().width(), rect.width());
+  const int height = std::min(size().height(), rect.height());
+
+  XImage* image;
+  XShmSegmentInfo shminfo;  // Used only when shared memory is enabled.
+  if (shared_memory_support_ != x11_util::SHARED_MEMORY_NONE) {
+    // Use shared memory for faster copies when it's available.
+    Visual* visual = static_cast<Visual*>(visual_);
+    memset(&shminfo, 0, sizeof(shminfo));
+    image = XShmCreateImage(display_, visual, 32,
+                            ZPixmap, NULL, &shminfo, width, height);
+
+    // Create the shared memory segment for the image and map it.
+    shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
+                           IPC_CREAT|0666);
+    if (shminfo.shmid == -1) {
+      XDestroyImage(image);
+      return false;
+    }
+
+    void* mapped_memory = shmat(shminfo.shmid, NULL, SHM_RDONLY);
+    shmctl(shminfo.shmid, IPC_RMID, 0);
+    if (mapped_memory == (void*)-1) {
+      XDestroyImage(image);
+      return false;
+    }
+    shminfo.shmaddr = image->data = static_cast<char*>(mapped_memory);
+
+    if (!XShmAttach(display_, &shminfo) ||
+        !XShmGetImage(display_, pixmap_, image, rect.x(), rect.y(),
+                      AllPlanes)) {
+      DestroySharedImage(display_, image, &shminfo);
+      return false;
+    }
+  } else {
+    // Non-shared memory case just copy the image from the server.
+    image = XGetImage(display_, pixmap_,
+                      rect.x(), rect.y(), width, height,
+                      AllPlanes, ZPixmap);
+  }
+
+  // TODO(jhawkins): Need to convert the image data if the image bits per pixel
+  // is not 32.
+  if (!output->initialize(width, height, true) ||
+      image->bits_per_pixel != 32) {
+    if (shared_memory_support_ != x11_util::SHARED_MEMORY_NONE)
+      DestroySharedImage(display_, image, &shminfo);
+    else
+      XDestroyImage(image);
+    return false;
+  }
+
+  // The X image might have a different row stride, so iterate through it and
+  // copy each row out, only up to the pixels we're actually using.
+  SkBitmap bitmap = output->getTopPlatformDevice().accessBitmap(true);
+  for (int y = 0; y < height; y++) {
+    uint32* dest_row = bitmap.getAddr32(0, y);
+    const char* src_row = &image->data[image->bytes_per_line * y];
+    memcpy(dest_row, src_row, width * 4);
+  }
+
+  if (shared_memory_support_ != x11_util::SHARED_MEMORY_NONE)
+    DestroySharedImage(display_, image, &shminfo);
+  else
+    XDestroyImage(image);
+
+  HISTOGRAM_TIMES("BackingStore.RetrievalFromX",
+                  base::TimeTicks::Now() - begin_time);
+  return true;
+}
+
+void BackingStoreX::ScrollBackingStore(int dx, int dy,
+                                       const gfx::Rect& clip_rect,
+                                       const gfx::Size& view_size) {
   if (!display_)
     return;
 
@@ -366,22 +459,22 @@
   }
 }
 
-void BackingStore::ShowRect(const gfx::Rect& rect, XID target) {
+void BackingStoreX::ShowRect(const gfx::Rect& rect, XID target) {
   XCopyArea(display_, pixmap_, target, static_cast<GC>(pixmap_gc_),
             rect.x(), rect.y(), rect.width(), rect.height(),
             rect.x(), rect.y());
 }
 
 #if defined(TOOLKIT_GTK)
-void BackingStore::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) {
+void BackingStoreX::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) {
   cairo_surface_t* surface = cairo_xlib_surface_create(
       display_, pixmap_, static_cast<Visual*>(visual_),
-      size_.width(), size_.height());
+      size().width(), size().height());
   cairo_t* cr = gdk_cairo_create(target);
 
   cairo_translate(cr, rect.x(), rect.y());
-  double x_scale = static_cast<double>(rect.width()) / size_.width();
-  double y_scale = static_cast<double>(rect.height()) / size_.height();
+  double x_scale = static_cast<double>(rect.width()) / size().width();
+  double y_scale = static_cast<double>(rect.height()) / size().height();
   cairo_scale(cr, x_scale, y_scale);
 
   cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
@@ -396,76 +489,3 @@
   cairo_destroy(cr);
 }
 #endif
-
-SkBitmap BackingStore::PaintRectToBitmap(const gfx::Rect& rect) {
-  base::TimeTicks begin_time = base::TimeTicks::Now();
-  const int width = std::min(size_.width(), rect.width());
-  const int height = std::min(size_.height(), rect.height());
-
-  XImage* image;
-  XShmSegmentInfo shminfo;  // Used only when shared memory is enabled.
-  if (shared_memory_support_ != x11_util::SHARED_MEMORY_NONE) {
-    // Use shared memory for faster copies when it's available.
-    Visual* visual = static_cast<Visual*>(visual_);
-    memset(&shminfo, 0, sizeof(shminfo));
-    image = XShmCreateImage(display_, visual, 32,
-                            ZPixmap, NULL, &shminfo, width, height);
-
-    // Create the shared memory segment for the image and map it.
-    shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
-                           IPC_CREAT|0666);
-    if (shminfo.shmid == -1) {
-      XDestroyImage(image);
-      return SkBitmap();
-    }
-
-    void* mapped_memory = shmat(shminfo.shmid, NULL, SHM_RDONLY);
-    shmctl(shminfo.shmid, IPC_RMID, 0);
-    if (mapped_memory == (void*)-1) {
-      XDestroyImage(image);
-      return SkBitmap();
-    }
-    shminfo.shmaddr = image->data = static_cast<char*>(mapped_memory);
-
-    if (!XShmAttach(display_, &shminfo) ||
-        !XShmGetImage(display_, pixmap_, image, rect.x(), rect.y(),
-                      AllPlanes)) {
-      DestroySharedImage(display_, image, &shminfo);
-      return SkBitmap();
-    }
-  } else {
-    // Non-shared memory case just copy the image from the server.
-    image = XGetImage(display_, pixmap_,
-                      rect.x(), rect.y(), width, height,
-                      AllPlanes, ZPixmap);
-  }
-
-  // TODO(jhawkins): Need to convert the image data if the image bits per pixel
-  // is not 32.
-  if (image->bits_per_pixel != 32) {
-    if (shared_memory_support_ != x11_util::SHARED_MEMORY_NONE)
-      DestroySharedImage(display_, image, &shminfo);
-    else
-      XDestroyImage(image);
-    return SkBitmap();
-  }
-
-  // Create a bitmap to put the results into, being careful to use the stride
-  // from the image rather than the width for the size.
-  SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height,
-                   image->bytes_per_line);
-  bitmap.allocPixels();
-  unsigned char* bitmap_data =
-      reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0));
-  memcpy(bitmap_data, image->data, image->bytes_per_line * height);
-
-  if (shared_memory_support_ != x11_util::SHARED_MEMORY_NONE)
-    DestroySharedImage(display_, image, &shminfo);
-  else
-    XDestroyImage(image);
-
-  HISTOGRAM_TIMES("BackingStore.RetrievalFromX",
-                  base::TimeTicks::Now() - begin_time);
-  return bitmap;
-}
diff --git a/chrome/browser/renderer_host/backing_store_x.h b/chrome/browser/renderer_host/backing_store_x.h
new file mode 100644
index 0000000..39c5fe9
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_x.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2010 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_BACKING_STORE_X_H_
+#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_X_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/common/x11_util.h"
+
+typedef struct _GdkDrawable GdkDrawable;
+class SkBitmap;
+
+class BackingStoreX : public BackingStore {
+ public:
+  // 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.
+  BackingStoreX(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
+  BackingStoreX(RenderWidgetHost* widget, const gfx::Size& size);
+
+  virtual ~BackingStoreX();
+
+  Display* display() const { return display_; }
+  XID root_window() const { return root_window_; }
+
+  // Copy from the server-side backing store to the target window
+  //   display: the display of the backing store and target window
+  //   damage: the area to copy
+  //   target: the X id of the target window
+  void ShowRect(const gfx::Rect& damage, XID target);
+
+#if defined(TOOLKIT_GTK)
+  // Paint the backing store into the target's |dest_rect|.
+  void PaintToRect(const gfx::Rect& dest_rect, GdkDrawable* target);
+#endif
+
+  // BackingStore implementation.
+  virtual size_t MemorySize();
+  virtual void PaintToBackingStore(
+      RenderProcessHost* process,
+      TransportDIB::Id bitmap,
+      const gfx::Rect& bitmap_rect,
+      const std::vector<gfx::Rect>& copy_rects,
+      bool* painted_synchronously);
+  virtual bool CopyFromBackingStore(const gfx::Rect& rect,
+                                    skia::PlatformCanvas* output);
+  virtual void ScrollBackingStore(int dx, int dy,
+                                  const gfx::Rect& clip_rect,
+                                  const gfx::Size& view_size);
+
+ private:
+  // Paints the bitmap from the renderer onto the backing store without
+  // using Xrender to composite the pixmaps.
+  void PaintRectWithoutXrender(TransportDIB* bitmap,
+                               const gfx::Rect& bitmap_rect,
+                               const std::vector<gfx::Rect>& copy_rects);
+
+  // This is the connection to the X server where this backing store will be
+  // displayed.
+  Display* const display_;
+  // What flavor, if any, MIT-SHM (X shared memory) support we have.
+  const x11_util::SharedMemorySupport shared_memory_support_;
+  // If this is true, then we can use Xrender to composite our pixmaps.
+  const bool use_render_;
+  // If |use_render_| is false, this is the number of bits-per-pixel for |depth|
+  int pixmap_bpp_;
+  // if |use_render_| is false, we need the Visual to get the RGB masks.
+  void* const visual_;
+  // This is the depth of the target window.
+  const int visual_depth_;
+  // The parent window (probably a GtkDrawingArea) for this backing store.
+  const XID root_window_;
+  // This is a handle to the server side pixmap which is our backing store.
+  XID pixmap_;
+  // This is the RENDER picture pointing at |pixmap_|.
+  XID picture_;
+  // This is a default graphic context, used in XCopyArea
+  void* pixmap_gc_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackingStoreX);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_X_H_
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index eac566bd..32c141c 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -735,7 +735,7 @@
 void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
   mark_child_process_activity_time();
   if (msg.routing_id() == MSG_ROUTING_CONTROL) {
-    // dispatch control messages
+    // Dispatch control messages.
     bool msg_is_ok = true;
     IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost, msg, msg_is_ok)
       IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
@@ -762,7 +762,7 @@
     return;
   }
 
-  // dispatch incoming messages to the appropriate TabContents
+  // Dispatch incoming messages to the appropriate RenderView/WidgetHost.
   IPC::Channel::Listener* listener = GetListenerByID(msg.routing_id());
   if (!listener) {
     if (msg.is_sync()) {
diff --git a/chrome/browser/renderer_host/gpu_view_host_win.cc b/chrome/browser/renderer_host/gpu_view_host_win.cc
new file mode 100644
index 0000000..52fae314
--- /dev/null
+++ b/chrome/browser/renderer_host/gpu_view_host_win.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2010 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/renderer_host/gpu_view_host_win.h"
+
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/renderer_host/backing_store_proxy.h"
+#include "chrome/common/gpu_messages.h"
+
+GpuViewHostWin::GpuViewHostWin(RenderWidgetHostViewWin* view,
+                               HWND parent)
+    : view_(view),
+      process_(GpuProcessHost::Get()),
+      routing_id_(0) {
+  if (!process_) {
+    // TODO(brettw) handle error.
+    return;
+  }
+  routing_id_ = process_->NewRenderWidgetHostView(
+      gfx::IdFromNativeView(parent));
+}
+
+GpuViewHostWin::~GpuViewHostWin() {
+}
+
+BackingStore* GpuViewHostWin::CreateBackingStore(
+    RenderWidgetHost* widget,
+    const gfx::Size& size) {
+  int32 backing_store_routing_id = process_->GetNextRoutingId();
+  process_->Send(new GpuMsg_NewBackingStore(routing_id_,
+                                            backing_store_routing_id,
+                                            size));
+  return new BackingStoreProxy(widget, size,
+                               process_, backing_store_routing_id);
+}
diff --git a/chrome/browser/renderer_host/gpu_view_host_win.h b/chrome/browser/renderer_host/gpu_view_host_win.h
new file mode 100644
index 0000000..a995fa09
--- /dev/null
+++ b/chrome/browser/renderer_host/gpu_view_host_win.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2010 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_GPU_VIEW_HOST_WIN_H_
+#define CHROME_BROWSER_RENDERER_HOST_GPU_VIEW_HOST_WIN_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+class BackingStore;
+class GpuProcessHost;
+class RenderWidgetHost;
+class RenderWidgetHostViewWin;
+
+namespace gfx {
+class Size;
+}
+
+// A proxy for the GPU process' window for rendering pages.
+class GpuViewHostWin {
+ public:
+  GpuViewHostWin(RenderWidgetHostViewWin* view, HWND parent);
+  ~GpuViewHostWin();
+
+  BackingStore* CreateBackingStore(RenderWidgetHost* widget,
+                                   const gfx::Size& size);
+
+ private:
+  RenderWidgetHostViewWin* view_;
+
+  GpuProcessHost* process_;
+  int32 routing_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuViewHostWin);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_GPU_VIEW_HOST_WIN_H_
diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h
index 7979d24..9d4855c 100644
--- a/chrome/browser/renderer_host/render_process_host.h
+++ b/chrome/browser/renderer_host/render_process_host.h
@@ -208,8 +208,10 @@
   // Returns the process object associated with the child process.  In certain
   // tests or single-process mode, this will actually represent the current
   // process.
-  // NOTE: this is not valid after calling Init, as it starts the process
-  // asynchronously.  It's guaranteed to be valid after the first IPC arrives.
+  //
+  // NOTE: this is not necessarily valid immediately after calling Init, as
+  // Init starts the process asynchronously.  It's guaranteed to be valid after
+  // the first IPC arrives.
   virtual base::ProcessHandle GetHandle() = 0;
 
   // Transport DIB functions ---------------------------------------------------
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index ad94aa6..4798516 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -314,6 +314,10 @@
   return view_->AllocBackingStore(size);
 }
 
+void RenderWidgetHost::DonePaintingToBackingStore() {
+  Send(new ViewMsg_UpdateRect_ACK(routing_id()));
+}
+
 void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) {
   time_when_considered_hung_ = Time::Now() + delay;
 
@@ -649,6 +653,7 @@
   const size_t size = params.bitmap_rect.height() *
                       params.bitmap_rect.width() * 4;
   TransportDIB* dib = process_->GetTransportDIB(params.bitmap);
+  bool painted_synchronously = true;  // Default to sending a paint ACK below.
   if (dib) {
     if (dib->size() < size) {
       DLOG(WARNING) << "Transport DIB too small for given rectangle";
@@ -664,16 +669,19 @@
       // Paint the backing store. This will update it with the renderer-supplied
       // bits. The view will read out of the backing store later to actually
       // draw to the screen.
-      PaintBackingStoreRect(dib, params.bitmap_rect, params.copy_rects,
-                            params.view_size);
+      PaintBackingStoreRect(params.bitmap, params.bitmap_rect,
+                            params.copy_rects, params.view_size,
+                            &painted_synchronously);
     }
   }
 
   // ACK early so we can prefetch the next PaintRect if there is a next one.
   // This must be done AFTER we're done painting with the bitmap supplied by the
   // renderer. This ACK is a signal to the renderer that the backing store can
-  // be re-used, so the bitmap may be invalid after this call.
-  Send(new ViewMsg_UpdateRect_ACK(routing_id_));
+  // be re-used, so the bitmap may be invalid after this call. If the backing
+  // store is painting asynchronously, it will manage issuing this IPC.
+  if (painted_synchronously)
+    Send(new ViewMsg_UpdateRect_ACK(routing_id_));
 
   // We don't need to update the view if the view is hidden. We must do this
   // early return after the ACK is sent, however, or the renderer will not send
@@ -825,10 +833,15 @@
 #endif
 
 void RenderWidgetHost::PaintBackingStoreRect(
-    TransportDIB* bitmap,
+    TransportDIB::Id bitmap,
     const gfx::Rect& bitmap_rect,
     const std::vector<gfx::Rect>& copy_rects,
-    const gfx::Size& view_size) {
+    const gfx::Size& view_size,
+    bool* painted_synchronously) {
+  // On failure, we need to be sure our caller knows we're done with the
+  // backing store.
+  *painted_synchronously = true;
+
   // The view may be destroyed already.
   if (!view_)
     return;
@@ -842,10 +855,9 @@
   }
 
   bool needs_full_paint = false;
-  BackingStoreManager::PrepareBackingStore(this, view_size,
-                                           process_->GetHandle(),
-                                           bitmap, bitmap_rect, copy_rects,
-                                           &needs_full_paint);
+  BackingStoreManager::PrepareBackingStore(this, view_size, bitmap, bitmap_rect,
+                                           copy_rects, &needs_full_paint,
+                                           painted_synchronously);
   if (needs_full_paint) {
     repaint_start_time_ = TimeTicks::Now();
     repaint_ack_pending_ = true;
@@ -870,7 +882,7 @@
   BackingStore* backing_store = BackingStoreManager::Lookup(this);
   if (!backing_store || (backing_store->size() != view_size))
     return;
-  backing_store->ScrollRect(dx, dy, clip_rect, view_size);
+  backing_store->ScrollBackingStore(dx, dy, clip_rect, view_size);
 }
 
 void RenderWidgetHost::ToggleSpellPanel(bool is_currently_visible) {
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index d59fc4e7..ddda002 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -16,6 +16,7 @@
 #include "chrome/common/edit_command.h"
 #include "chrome/common/native_web_keyboard_event.h"
 #include "chrome/common/property_bag.h"
+#include "chrome/common/transport_dib.h"
 #include "ipc/ipc_channel.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 #include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h"
@@ -214,6 +215,11 @@
   // (for example, if we don't currently have a RenderWidgetHostView.)
   BackingStore* AllocBackingStore(const gfx::Size& size);
 
+  // When a backing store does asynchronous painting, it will call this function
+  // when it is done with the DIB. We will then forward a message to the
+  // renderer to send another paint.
+  void DonePaintingToBackingStore();
+
   // Checks to see if we can give up focus to this widget through a JS call.
   virtual bool CanBlur() const { return true; }
 
@@ -434,10 +440,15 @@
 #endif
 
   // Paints the given bitmap to the current backing store at the given location.
-  void PaintBackingStoreRect(TransportDIB* dib,
+  // |*painted_synchronously| will be true if the message was processed
+  // synchronously, and the bitmap is done being used. False means that the
+  // backing store will paint the bitmap at a later time and that the DIB can't
+  // be freed (it will be the backing store's job to free it later).
+  void PaintBackingStoreRect(TransportDIB::Id bitmap,
                              const gfx::Rect& bitmap_rect,
                              const std::vector<gfx::Rect>& copy_rects,
-                             const gfx::Size& view_size);
+                             const gfx::Size& view_size,
+                             bool* painted_synchronously);
 
   // Scrolls the given |clip_rect| in the backing by the given dx/dy amount. The
   // |dib| and its corresponding location |bitmap_rect| in the backing store
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 aee6b5fd..6291574 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -28,7 +28,7 @@
 #include "chrome/common/gtk_util.h"
 #include "chrome/common/native_web_keyboard_event.h"
 #include "chrome/common/x11_util.h"
-#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/backing_store_x.h"
 #include "chrome/browser/renderer_host/gtk_im_context_wrapper.h"
 #include "chrome/browser/renderer_host/gtk_key_bindings_handler.h"
 #include "chrome/browser/renderer_host/render_widget_host.h"
@@ -528,7 +528,8 @@
     return;
 
   // TODO(darin): Implement the equivalent of Win32's ScrollWindowEX.  Can that
-  // be done using XCopyArea?  Perhaps similar to BackingStore::ScrollRect?
+  // be done using XCopyArea?  Perhaps similar to
+  // BackingStore::ScrollBackingStore?
   if (about_to_validate_and_paint_)
     invalid_rect_ = invalid_rect_.Union(rect);
   else
@@ -596,9 +597,9 @@
 
 BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
     const gfx::Size& size) {
-  return new BackingStore(host_, size,
-                          x11_util::GetVisualFromGtkWidget(view_.get()),
-                          gtk_widget_get_visual(view_.get())->depth);
+  return new BackingStoreX(host_, size,
+                           x11_util::GetVisualFromGtkWidget(view_.get()),
+                           gtk_widget_get_visual(view_.get())->depth);
 }
 
 void RenderWidgetHostViewGtk::SetBackground(const SkBitmap& background) {
@@ -611,7 +612,8 @@
 
   invalid_rect_ = damage_rect;
   about_to_validate_and_paint_ = true;
-  BackingStore* backing_store = host_->GetBackingStore(true);
+  BackingStoreX* backing_store = static_cast<BackingStoreX*>(
+      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_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index 55cfaef..5f45aec 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -11,7 +11,7 @@
 #include "chrome/browser/browser_trial.h"
 #import "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
 #include "chrome/browser/plugin_process_host.h"
-#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/backing_store_mac.h"
 #include "chrome/browser/renderer_host/render_process_host.h"
 #include "chrome/browser/renderer_host/render_widget_host.h"
 #include "chrome/browser/spellchecker_platform_engine.h"
@@ -383,7 +383,7 @@
 
 BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
     const gfx::Size& size) {
-  return new BackingStore(render_widget_host_, size);
+  return new BackingStoreMac(render_widget_host_, size);
 }
 
 // Display a popup menu for WebKit using Cocoa widgets.
@@ -758,8 +758,8 @@
 
   renderWidgetHostView_->invalid_rect_ = dirtyRect;
   renderWidgetHostView_->about_to_validate_and_paint_ = true;
-  BackingStore* backing_store =
-      renderWidgetHostView_->render_widget_host_->GetBackingStore(true);
+  BackingStoreMac* backing_store = static_cast<BackingStoreMac*>(
+      renderWidgetHostView_->render_widget_host_->GetBackingStore(true));
   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 8be4df5..d6287ac 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -21,6 +21,8 @@
 #include "chrome/browser/chrome_thread.h"
 #include "chrome/browser/plugin_process_host.h"
 #include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/backing_store_win.h"
+#include "chrome/browser/renderer_host/gpu_view_host_win.h"
 #include "chrome/browser/renderer_host/render_process_host.h"
 #include "chrome/browser/renderer_host/render_widget_host.h"
 #include "chrome/common/chrome_constants.h"
@@ -259,6 +261,13 @@
   ResetTooltip();
 }
 
+void RenderWidgetHostViewWin::CreateWnd(HWND parent) {
+  Create(parent);  // ATL function to create the window.
+  // Uncommenting this will enable experimental out-of-process painting.
+  // Contact brettw for more,
+  // gpu_view_host_.reset(new GpuViewHostWin(this, m_hWnd));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // RenderWidgetHostViewWin, RenderWidgetHostView implementation:
 
@@ -702,7 +711,9 @@
 
 BackingStore* RenderWidgetHostViewWin::AllocBackingStore(
     const gfx::Size& size) {
-  return new BackingStore(render_widget_host_, size);
+  if (gpu_view_host_.get())
+    return gpu_view_host_->CreateBackingStore(render_widget_host_, size);
+  return new BackingStoreWin(render_widget_host_, size);
 }
 
 void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) {
@@ -758,11 +769,22 @@
   TrackMouseLeave(false);
 }
 
-void RenderWidgetHostViewWin::OnPaint(HDC dc) {
+void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) {
   DCHECK(render_widget_host_->process()->HasConnection());
 
+  if (gpu_view_host_.get()) {
+    // When we're proxying painting, we don't actually display the web page
+    // ourselves. We clear it white in case the proxy window isn't visible
+    // yet we won't show gibberish.
+    CPaintDC paint_dc(m_hWnd);
+    FillRect(paint_dc.m_hDC, &paint_dc.m_ps.rcPaint,
+             static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
+    return;
+  }
+
   about_to_validate_and_paint_ = true;
-  BackingStore* backing_store = render_widget_host_->GetBackingStore(true);
+  BackingStoreWin* backing_store = static_cast<BackingStoreWin*>(
+      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
@@ -783,7 +805,7 @@
   if (backing_store) {
     gfx::Rect bitmap_rect(gfx::Point(), backing_store->size());
 
-    bool manage_colors = BackingStore::ColorManagementEnabled();
+    bool manage_colors = BackingStoreWin::ColorManagementEnabled();
     if (manage_colors)
       SetICMMode(paint_dc.m_hDC, ICM_ON);
 
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h
index 3b54064..f86d08a 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -11,6 +11,7 @@
 #include <atlmisc.h>
 
 #include "base/scoped_comptr_win.h"
+#include "base/scoped_ptr.h"
 #include "base/task.h"
 #include "chrome/browser/ime_input.h"
 #include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -27,6 +28,7 @@
 
 class BackingStore;
 class RenderWidgetHost;
+class GpuViewHostWin;
 
 typedef CWinTraits<WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0>
     RenderWidgetHostHWNDTraits;
@@ -59,6 +61,8 @@
   explicit RenderWidgetHostViewWin(RenderWidgetHost* widget);
   virtual ~RenderWidgetHostViewWin();
 
+  void CreateWnd(HWND parent);
+
   DECLARE_WND_CLASS_EX(kRenderWidgetHostHWNDClass, CS_DBLCLKS, 0);
 
   BEGIN_MSG_MAP(RenderWidgetHostHWND)
@@ -139,7 +143,7 @@
   LRESULT OnCreate(CREATESTRUCT* create_struct);
   void OnActivate(UINT, BOOL, HWND);
   void OnDestroy();
-  void OnPaint(HDC dc);
+  void OnPaint(HDC unused_dc);
   void OnNCPaint(HRGN update_region);
   LRESULT OnEraseBkgnd(HDC dc);
   LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT mouse_message_id);
@@ -224,6 +228,10 @@
   // The associated Model.
   RenderWidgetHost* render_widget_host_;
 
+  // If we're doing out-of-process painting, this member will be non-NULL,
+  // indicating the gpu view we're using for the painting.
+  scoped_ptr<GpuViewHostWin> gpu_view_host_;
+
   // The cursor for the page. This is passed up from the renderer.
   WebCursor current_cursor_;
 
diff --git a/chrome/browser/renderer_host/test/test_backing_store.cc b/chrome/browser/renderer_host/test/test_backing_store.cc
new file mode 100644
index 0000000..d90c7fd
--- /dev/null
+++ b/chrome/browser/renderer_host/test/test_backing_store.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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/renderer_host/test/test_backing_store.h"
+
+TestBackingStore::TestBackingStore(RenderWidgetHost* widget,
+                                   const gfx::Size& size)
+    : BackingStore(widget, size) {
+}
+
+TestBackingStore::~TestBackingStore() {
+}
+
+void TestBackingStore::PaintToBackingStore(
+    RenderProcessHost* process,
+    TransportDIB::Id bitmap,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects,
+    bool* painted_synchronously) {
+}
+
+bool TestBackingStore::CopyFromBackingStore(const gfx::Rect& rect,
+                                            skia::PlatformCanvas* output) {
+  return false;
+}
+
+void TestBackingStore::ScrollBackingStore(int dx, int dy,
+                                          const gfx::Rect& clip_rect,
+                                          const gfx::Size& view_size) {
+}
diff --git a/chrome/browser/renderer_host/test/test_backing_store.h b/chrome/browser/renderer_host/test/test_backing_store.h
new file mode 100644
index 0000000..41deb4c
--- /dev/null
+++ b/chrome/browser/renderer_host/test/test_backing_store.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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_TEST_TEST_BACKING_STORE_H_
+#define CHROME_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_
+
+#include "base/basictypes.h"
+#include "chrome/browser/renderer_host/backing_store.h"
+
+class TestBackingStore : public BackingStore {
+ public:
+  TestBackingStore(RenderWidgetHost* widget, const gfx::Size& size);
+  virtual ~TestBackingStore();
+
+  // BackingStore implementation.
+  virtual void PaintToBackingStore(RenderProcessHost* process,
+                                   TransportDIB::Id bitmap,
+                                   const gfx::Rect& bitmap_rect,
+                                   const std::vector<gfx::Rect>& copy_rects,
+                                   bool* painted_synchronously);
+  virtual bool CopyFromBackingStore(const gfx::Rect& rect,
+                                    skia::PlatformCanvas* output);
+  virtual void ScrollBackingStore(int dx, int dy,
+                                  const gfx::Rect& clip_rect,
+                                  const gfx::Size& view_size);
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestBackingStore);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_
diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc
index 720f51e8..095c2e1 100644
--- a/chrome/browser/renderer_host/test/test_render_view_host.cc
+++ b/chrome/browser/renderer_host/test/test_render_view_host.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/renderer_host/test/test_render_view_host.h"
 
 #include "base/gfx/rect.h"
-#include "chrome/browser/renderer_host/backing_store.h"
+#include "chrome/browser/renderer_host/test/test_backing_store.h"
 #include "chrome/browser/tab_contents/test_tab_contents.h"
 #include "chrome/common/render_messages.h"
 
@@ -74,7 +74,7 @@
 
 BackingStore* TestRenderWidgetHostView::AllocBackingStore(
     const gfx::Size& size) {
-  return new BackingStore(rwh_, size);
+  return new TestBackingStore(rwh_, size);
 }
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/sandbox_policy.cc b/chrome/browser/sandbox_policy.cc
index 4af55a6..ce137e0 100644
--- a/chrome/browser/sandbox_policy.cc
+++ b/chrome/browser/sandbox_policy.cc
@@ -350,6 +350,8 @@
     type = ChildProcessInfo::NACL_PROCESS;
   } else if (type_str == switches::kUtilityProcess) {
     type = ChildProcessInfo::UTILITY_PROCESS;
+  } else if (type_str == switches::kGpuProcess) {
+    type = ChildProcessInfo::GPU_PROCESS;
   } else {
     NOTREACHED();
     return 0;
diff --git a/chrome/browser/tab_contents/thumbnail_generator.cc b/chrome/browser/tab_contents/thumbnail_generator.cc
index 1a5c5c45..ccd781e24 100644
--- a/chrome/browser/tab_contents/thumbnail_generator.cc
+++ b/chrome/browser/tab_contents/thumbnail_generator.cc
@@ -7,8 +7,10 @@
 #include <algorithm>
 
 #include "app/gfx/skbitmap_operations.h"
+#include "base/gfx/rect.h"
 #include "base/histogram.h"
 #include "base/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/renderer_host/backing_store.h"
 #include "chrome/browser/renderer_host/render_view_host.h"
 #include "chrome/common/notification_service.h"
@@ -87,22 +89,6 @@
   return GetThumbnailAccessor()->GetProperty(host->property_bag());
 }
 
-#if defined(OS_WIN)
-
-// PlatformDevices/Canvases can't be copied like a regular SkBitmap (at least
-// on Windows). So the second parameter is the canvas to draw into. It should
-// be sized to the size of the backing store.
-void GetBitmapForBackingStore(BackingStore* backing_store,
-                              skia::PlatformCanvas* canvas) {
-  HDC dc = canvas->beginPlatformPaint();
-  BitBlt(dc, 0, 0,
-         backing_store->size().width(), backing_store->size().height(),
-         backing_store->hdc(), 0, 0, SRCCOPY);
-  canvas->endPlatformPaint();
-}
-
-#endif
-
 // 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) {
@@ -110,48 +96,26 @@
 
   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.
   skia::PlatformCanvas temp_canvas;
-  if (!temp_canvas.initialize(backing_store->size().width(),
-                              backing_store->size().height(), true))
+  if (!backing_store->CopyFromBackingStore(gfx::Rect(gfx::Point(0, 0),
+                                                     backing_store->size()),
+                                           &temp_canvas))
     return result;
-  GetBitmapForBackingStore(backing_store, &temp_canvas);
-
-  // Get the bitmap out of the canvas and resample it. It would be nice if this
-  // whole Windows-specific block could be put into a function, but the memory
-  // management wouldn't work out because the bitmap is a PlatformDevice which
-  // can't actually be copied.
   const SkBitmap& bmp = temp_canvas.getTopPlatformDevice().accessBitmap(false);
-
-#elif defined(OS_LINUX)
-  SkBitmap bmp = backing_store->PaintRectToBitmap(
-      gfx::Rect(0, 0,
-                backing_store->size().width(), backing_store->size().height()));
-
-#elif defined(OS_MACOSX)
-  SkBitmap bmp;
-  NOTIMPLEMENTED();
-#endif
-
   result = SkBitmapOperations::DownsampleByTwoUntilSize(bmp, kThumbnailWidth,
                                                         kThumbnailHeight);
 
-#if defined(OS_WIN)
   // This is a bit subtle. SkBitmaps are refcounted, but the magic ones in
-  // PlatformCanvas on Windows can't be ssigned to SkBitmap with proper
+  // 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.
   if (bmp.width() == result.width() && bmp.height() == result.height())
     bmp.copyTo(&result, SkBitmap::kARGB_8888_Config);
-#endif
 
   HISTOGRAM_TIMES(kThumbnailHistogramName,
                   base::TimeTicks::Now() - begin_compute_thumbnail);
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_win.cc b/chrome/browser/views/tab_contents/tab_contents_view_win.cc
index b46290b8..a6f8b3e 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_win.cc
+++ b/chrome/browser/views/tab_contents/tab_contents_view_win.cc
@@ -107,7 +107,7 @@
 
   RenderWidgetHostViewWin* view =
       new RenderWidgetHostViewWin(render_widget_host);
-  view->Create(GetNativeView());
+  view->CreateWnd(GetNativeView());
   view->ShowWindow(SW_SHOW);
   return view;
 }
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 49003b4..3e280a90 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Copyright (c) 2010 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.
 
@@ -25,6 +25,7 @@
       'common',
       'browser',
       'debugger',
+      'chrome_gpu',
       'renderer',
       'syncapi',
       'utility',
@@ -513,6 +514,38 @@
       ],
     },
     {
+      'target_name': 'chrome_gpu',
+      'type': '<(library)',
+      'msvs_guid': 'F10F1ECD-D84D-4C33-8468-9DDFE19F4D8A',
+      'dependencies': [
+        '../base/base.gyp:base',
+        'common',
+      ],
+      'conditions': [
+        ['OS=="win"', {
+          'include_dirs': [
+            'third_party/wtl/include',
+          ],
+          'sources': [
+            'gpu/gpu_backing_store.cc',
+            'gpu/gpu_backing_store.h',
+            'gpu/gpu_view_win.cc',
+            'gpu/gpu_view_win.h',
+          ],
+        }]
+      ],
+      'sources': [
+        'gpu/gpu_main.cc',
+        'gpu/gpu_process.cc',
+        'gpu/gpu_process.h',
+        'gpu/gpu_thread.cc',
+        'gpu/gpu_thread.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
       'target_name': 'worker',
       'type': '<(library)',
       'msvs_guid': 'C78D02D0-A366-4EC6-A248-AA8E64C4BA18',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d567984e..2625ca9e 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -813,6 +813,8 @@
         'browser/google_url_tracker.h',
         'browser/google_util.cc',
         'browser/google_util.h',
+        'browser/gpu_process_host.cc',
+        'browser/gpu_process_host.h',
         'browser/gtk/about_chrome_dialog.cc',
         'browser/gtk/about_chrome_dialog.h',
         'browser/gtk/back_forward_button_gtk.cc',
@@ -1327,12 +1329,18 @@
         'browser/renderer_host/async_resource_handler.h',
         'browser/renderer_host/audio_renderer_host.cc',
         'browser/renderer_host/audio_renderer_host.h',
+        'browser/renderer_host/backing_store.cc',
         'browser/renderer_host/backing_store.h',
         'browser/renderer_host/backing_store_manager.cc',
         'browser/renderer_host/backing_store_manager.h',
+        'browser/renderer_host/backing_store_mac.h',
         'browser/renderer_host/backing_store_mac.mm',
+        'browser/renderer_host/backing_store_proxy.cc',
+        'browser/renderer_host/backing_store_proxy.h',
         'browser/renderer_host/backing_store_win.cc',
+        'browser/renderer_host/backing_store_win.h',
         'browser/renderer_host/backing_store_x.cc',
+        'browser/renderer_host/backing_store_x.h',
         'browser/renderer_host/browser_render_process_host.cc',
         'browser/renderer_host/browser_render_process_host.h',
         'browser/renderer_host/buffered_resource_handler.cc',
@@ -1346,6 +1354,8 @@
         'browser/renderer_host/download_throttling_resource_handler.cc',
         'browser/renderer_host/download_throttling_resource_handler.h',
         'browser/renderer_host/global_request_id.h',
+        'browser/renderer_host/gpu_view_host_win.cc',
+        'browser/renderer_host/gpu_view_host_win.h',
         'browser/renderer_host/gtk_im_context_wrapper.cc',
         'browser/renderer_host/gtk_im_context_wrapper.h',
         'browser/renderer_host/gtk_key_bindings_handler.cc',
@@ -1921,6 +1931,8 @@
              # Windows-specific files.
             'browser/password_manager/password_store_win.cc',
             'browser/password_manager/password_store_win.h',
+            'browser/renderer_host/backing_store_proxy.cc',
+            'browser/renderer_host/backing_store_proxy.h',
           ],
           'sources': [
             'browser/crash_handler_host_linux.h',
@@ -1972,6 +1984,8 @@
             'browser/password_manager/password_store_kwallet.cc',
             'browser/password_manager/password_store_win.cc',
             'browser/password_manager/password_store_win.h',
+            'browser/renderer_host/backing_store_proxy.cc',
+            'browser/renderer_host/backing_store_proxy.h',
             'browser/views/extensions/extension_shelf.cc',
             'browser/views/extensions/extension_shelf.h',
             'browser/views/extensions/extension_view.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 0624d4a..adfa960b 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -53,6 +53,8 @@
           'common/debug_flags.h',
           'common/devtools_messages.h',
           'common/devtools_messages_internal.h',
+          'common/gpu_messages.h',
+          'common/gpu_messages_internal.h',
           'common/logging_chrome.cc',
           'common/logging_chrome.h',
           'common/main_function_params.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index ea66614..d00af61 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -73,6 +73,8 @@
         'browser/net/url_request_mock_net_error_job.h',
         'browser/renderer_host/mock_render_process_host.cc',
         'browser/renderer_host/mock_render_process_host.h',
+        'browser/renderer_host/test/test_backing_store.cc',
+        'browser/renderer_host/test/test_backing_store.h',
         'browser/renderer_host/test/test_render_view_host.cc',
         'browser/renderer_host/test/test_render_view_host.h',
         'browser/tab_contents/test_tab_contents.cc',
diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h
index 94bdafd..1ca547b 100644
--- a/chrome/common/child_process_host.h
+++ b/chrome/common/child_process_host.h
@@ -69,6 +69,8 @@
   };
 
  protected:
+  // The resource_dispatcher_host may be NULL to indicate none is needed for
+  // this process type.
   ChildProcessHost(ProcessType type,
                    ResourceDispatcherHost* resource_dispatcher_host);
 
@@ -127,7 +129,10 @@
   };
 
   ListenerHook listener_;
+
+  // May be NULL if this current process has no resource dispatcher host.
   ResourceDispatcherHost* resource_dispatcher_host_;
+
   bool opening_channel_;  // True while we're waiting the channel to be opened.
   scoped_ptr<IPC::Channel> channel_;
   std::string channel_id_;
diff --git a/chrome/common/child_process_info.h b/chrome/common/child_process_info.h
index 50d1d0d..57266753 100644
--- a/chrome/common/child_process_info.h
+++ b/chrome/common/child_process_info.h
@@ -24,7 +24,8 @@
     UTILITY_PROCESS,
     PROFILE_IMPORT_PROCESS,
     ZYGOTE_PROCESS,
-    SANDBOX_HELPER_PROCESS
+    SANDBOX_HELPER_PROCESS,
+    GPU_PROCESS
   };
 
   ChildProcessInfo(const ChildProcessInfo& original);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index af88125..251b382 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -205,7 +205,7 @@
 const char kEnableFileCookies[]             = "enable-file-cookies";
 
 // Enable Geolocation support.
-const char kEnableGeolocation[]       = "enable-geolocation";
+const char kEnableGeolocation[]             = "enable-geolocation";
 
 // Enable the GPU plugin and Pepper 3D rendering.
 const char kEnableGPUPlugin[]               = "enable-gpu-plugin";
@@ -298,6 +298,9 @@
 // current details.
 const char kForceFieldTestNameAndValue[]    = "force-fieldtest";
 
+// Makes this process a GPU sub-process.
+const char kGpuProcess[]                    = "gpu-process";
+
 // Make Windows happy by allowing it to show "Enable access to this program"
 // checkbox in Add/Remove Programs->Set Program Access and Defaults. This
 // only shows an error box because the only way to hide Chrome is by
@@ -325,12 +328,6 @@
 // Runs a trusted Pepper plugin inside the renderer process.
 const char kInternalPepper[]                = "internal-pepper";
 
-#ifndef NDEBUG
-// Makes sure any sync login attempt will fail with an error.  (Only
-// used for testing.)
-const char kInvalidateSyncLogin[]           = "invalidate-sync-login";
-#endif
-
 // Specifies the flags passed to JS engine
 const char kJavaScriptFlags[]               = "js-flags";
 
@@ -733,6 +730,10 @@
 #ifndef NDEBUG
 // Debug only switch to specify which gears plugin dll to load.
 const char kGearsPluginPathOverride[]       = "gears-plugin-path";
+
+// Makes sure any sync login attempt will fail with an error.  (Only
+// used for testing.)
+const char kInvalidateSyncLogin[]           = "invalidate-sync-login";
 #endif
 
 // -----------------------------------------------------------------------------
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 7e3deaf..15b1975 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -96,6 +96,7 @@
 extern const char kFileDescriptorLimit[];
 extern const char kFirstRun[];
 extern const char kForceFieldTestNameAndValue[];
+extern const char kGpuProcess[];
 extern const char kHideIcons[];
 extern const char kHomePage[];
 extern const char kImport[];
@@ -103,9 +104,6 @@
 extern const char kIncognito[];
 extern const char kInternalNaCl[];
 extern const char kInternalPepper[];
-#ifndef NDEBUG
-extern const char kInvalidateSyncLogin[];
-#endif
 extern const char kJavaScriptFlags[];
 extern const char kLoadExtension[];
 extern const char kLoadPlugin[];
@@ -221,6 +219,7 @@
 
 #ifndef NDEBUG
 extern const char kGearsPluginPathOverride[];
+extern const char kInvalidateSyncLogin[];
 #endif
 
 // DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
diff --git a/chrome/common/gpu_messages.h b/chrome/common/gpu_messages.h
new file mode 100644
index 0000000..52e3d6f
--- /dev/null
+++ b/chrome/common/gpu_messages.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2010 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_COMMON_GPU_MESSAGES_H_
+#define CHROME_COMMON_GPU_MESSAGES_H_
+
+#include <vector>
+
+#include "app/gfx/native_widget_types.h"
+#include "base/basictypes.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "chrome/common/common_param_traits.h"
+#include "chrome/common/transport_dib.h"
+
+namespace IPC {
+
+// Potential new structures for messages go here.
+
+}  // namespace IPC
+
+#define MESSAGES_INTERNAL_FILE \
+    "chrome/common/gpu_messages_internal.h"
+#include "ipc/ipc_message_macros.h"
+
+#endif  // CHROME_COMMON_GPU_MESSAGES_H_
+
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
new file mode 100644
index 0000000..73a82f1
--- /dev/null
+++ b/chrome/common/gpu_messages_internal.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 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.
+
+// This header is meant to be included in multiple passes, hence no traditional
+// header guard. It is included by backing_store_messages_internal.h
+// See ipc_message_macros.h for explanation of the macros and passes.
+
+// This file needs to be included again, even though we're actually included
+// from it via utility_messages.h.
+#include "ipc/ipc_message_macros.h"
+
+//------------------------------------------------------------------------------
+// Backing Store Messages
+// These are messages from the browser to the GPU process.
+IPC_BEGIN_MESSAGES(Gpu)
+
+  IPC_MESSAGE_CONTROL2(GpuMsg_NewRenderWidgetHostView,
+                       gfx::NativeViewId, /* parent window */
+                       int32 /* view_id */)
+
+  // Creates a new backing store.
+  IPC_MESSAGE_ROUTED2(GpuMsg_NewBackingStore,
+                      int32, /* backing_store_id */
+                      gfx::Size /* size */)
+
+  // Updates the backing store with the given bitmap. The GPU process will send
+  // back a GpuHostMsg_PaintToBackingStore_ACK after the paint is complete to
+  // let the caller know the TransportDIB can be freed or reused.
+  IPC_MESSAGE_ROUTED4(GpuMsg_PaintToBackingStore,
+                      base::ProcessId, /* process */
+                      TransportDIB::Id, /* bitmap */
+                      gfx::Rect, /* bitmap_rect */
+                      std::vector<gfx::Rect>) /* copy_rects */
+
+
+  IPC_MESSAGE_ROUTED4(GpuMsg_ScrollBackingStore,
+                      int, /* dx */
+                      int, /* dy */
+                      gfx::Rect, /* clip_rect */
+                      gfx::Size) /* view_size */
+
+IPC_END_MESSAGES(Gpu)
+
+//------------------------------------------------------------------------------
+// Backing Store Host Messagse
+// These are messages from the GPU process to the browser.
+IPC_BEGIN_MESSAGES(GpuHost)
+
+  // This message is sent in response to BackingStoreMsg_New to tell the host
+  // about the child window that was just created.
+  IPC_MESSAGE_ROUTED1(GpuHostMsg_CreatedRenderWidgetHostView,
+                      gfx::NativeViewId)
+
+  // Send in response to GpuMsg_PaintToBackingStore, see that for more.
+  IPC_MESSAGE_ROUTED0(GpuHostMsg_PaintToBackingStore_ACK)
+
+IPC_END_MESSAGES(GpuHost)
+
diff --git a/chrome/gpu/gpu_backing_store.cc b/chrome/gpu/gpu_backing_store.cc
new file mode 100644
index 0000000..a5fafe2
--- /dev/null
+++ b/chrome/gpu/gpu_backing_store.cc
@@ -0,0 +1,185 @@
+// Copyright (c) 2010 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/gpu/gpu_backing_store.h"
+
+#include "app/gfx/gdi_util.h"
+#include "app/win_util.h"
+#include "base/logging.h"
+#include "chrome/common/gpu_messages.h"
+#include "chrome/gpu/gpu_view_win.h"
+#include "chrome/gpu/gpu_thread.h"
+
+namespace {
+
+// Creates a dib conforming to the height/width/section parameters passed in.
+HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) {
+  BITMAPV5HEADER hdr = {0};
+  ZeroMemory(&hdr, sizeof(BITMAPV5HEADER));
+
+  // These values are shared with gfx::PlatformDevice
+  hdr.bV5Size = sizeof(BITMAPINFOHEADER);
+  hdr.bV5Width = width;
+  hdr.bV5Height = -height;  // minus means top-down bitmap
+  hdr.bV5Planes = 1;
+  hdr.bV5BitCount = color_depth;
+  hdr.bV5Compression = BI_RGB;  // no compression
+  hdr.bV5SizeImage = 0;
+  hdr.bV5XPelsPerMeter = 1;
+  hdr.bV5YPelsPerMeter = 1;
+  hdr.bV5ClrUsed = 0;
+  hdr.bV5ClrImportant = 0;
+
+
+  void* data = NULL;
+  HANDLE dib = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO*>(&hdr),
+                                0, &data, NULL, 0);
+  DCHECK(data);
+  return dib;
+}
+
+void CallStretchDIBits(HDC hdc, int dest_x, int dest_y, int dest_w, int dest_h,
+                       int src_x, int src_y, int src_w, int src_h, void* pixels,
+                       const BITMAPINFO* bitmap_info) {
+  // When blitting a rectangle that touches the bottom, left corner of the
+  // bitmap, StretchDIBits looks at it top-down!  For more details, see
+  // http://wiki.allegro.cc/index.php?title=StretchDIBits.
+  int rv;
+  int bitmap_h = -bitmap_info->bmiHeader.biHeight;
+  int bottom_up_src_y = bitmap_h - src_y - src_h;
+  if (bottom_up_src_y == 0 && src_x == 0 && src_h != bitmap_h) {
+    rv = StretchDIBits(hdc,
+                       dest_x, dest_h + dest_y - 1, dest_w, -dest_h,
+                       src_x, bitmap_h - src_y + 1, src_w, -src_h,
+                       pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY);
+  } else {
+    rv = StretchDIBits(hdc,
+                       dest_x, dest_y, dest_w, dest_h,
+                       src_x, bottom_up_src_y, src_w, src_h,
+                       pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY);
+  }
+  DCHECK(rv != GDI_ERROR);
+}
+
+}  // namespace
+
+
+GpuBackingStore::GpuBackingStore(GpuViewWin* view,
+                                 GpuThread* gpu_thread,
+                                 int32 routing_id,
+                                 const gfx::Size& size)
+    : view_(view),
+      gpu_thread_(gpu_thread),
+      routing_id_(routing_id),
+      size_(size) {
+  gpu_thread_->AddRoute(routing_id_, this);
+
+  HDC screen_dc = ::GetDC(NULL);
+  color_depth_ = ::GetDeviceCaps(screen_dc, BITSPIXEL);
+  // Color depths less than 16 bpp require a palette to be specified. Instead,
+  // we specify the desired color depth as 16 which lets the OS to come up
+  // with an approximation.
+  if (color_depth_ < 16)
+    color_depth_ = 16;
+  hdc_ = CreateCompatibleDC(screen_dc);
+  ReleaseDC(NULL, screen_dc);
+}
+
+GpuBackingStore::~GpuBackingStore() {
+  gpu_thread_->RemoveRoute(routing_id_);
+
+  DCHECK(hdc_);
+  if (original_bitmap_) {
+    SelectObject(hdc_, original_bitmap_);
+  }
+  if (backing_store_dib_) {
+    DeleteObject(backing_store_dib_);
+    backing_store_dib_ = NULL;
+  }
+  DeleteDC(hdc_);
+}
+
+void GpuBackingStore::OnMessageReceived(const IPC::Message& msg) {
+  IPC_BEGIN_MESSAGE_MAP(GpuBackingStore, msg)
+    IPC_MESSAGE_HANDLER(GpuMsg_PaintToBackingStore, OnPaintToBackingStore)
+    IPC_MESSAGE_HANDLER(GpuMsg_ScrollBackingStore, OnScrollBackingStore)
+  IPC_END_MESSAGE_MAP_EX()
+}
+
+void GpuBackingStore::OnChannelConnected(int32 peer_pid) {
+}
+
+void GpuBackingStore::OnChannelError() {
+  // FIXME(brettw) does this mean we aren't getting any more messages and we
+  // should delete outselves?
+}
+
+void GpuBackingStore::OnPaintToBackingStore(
+    base::ProcessId source_process_id,
+    TransportDIB::Id id,
+    const gfx::Rect& bitmap_rect,
+    const std::vector<gfx::Rect>& copy_rects) {
+  HANDLE source_process_handle = OpenProcess(PROCESS_ALL_ACCESS,
+                                             FALSE, source_process_id);
+  CHECK(source_process_handle);
+
+  // On Windows we need to duplicate the handle from the remote process.
+  // See BrowserRenderProcessHost::MapTransportDIB for how to do this on other
+  // platforms.
+  HANDLE section = win_util::GetSectionFromProcess(
+      id.handle, source_process_handle, false /* read write */);
+  CHECK(section);
+  TransportDIB* dib = TransportDIB::Map(section);
+  CHECK(dib);
+
+  if (!backing_store_dib_) {
+    backing_store_dib_ = CreateDIB(hdc_, size_.width(),
+                                   size_.height(), color_depth_);
+    if (!backing_store_dib_) {
+      NOTREACHED();
+
+      // TODO(brettw): do this in such a way that we can't forget to
+      // send the ACK.
+      gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_));
+      return;
+    }
+    original_bitmap_ = SelectObject(hdc_, backing_store_dib_);
+  }
+
+  BITMAPINFOHEADER hdr;
+  gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr);
+  // Account for a bitmap_rect that exceeds the bounds of our view
+  gfx::Rect view_rect(0, 0, size_.width(), size_.height());
+
+  for (size_t i = 0; i < copy_rects.size(); i++) {
+    gfx::Rect paint_rect = view_rect.Intersect(copy_rects[i]);
+    CallStretchDIBits(hdc_,
+                      paint_rect.x(),
+                      paint_rect.y(),
+                      paint_rect.width(),
+                      paint_rect.height(),
+                      paint_rect.x() - bitmap_rect.x(),
+                      paint_rect.y() - bitmap_rect.y(),
+                      paint_rect.width(),
+                      paint_rect.height(),
+                      dib->memory(),
+                      reinterpret_cast<BITMAPINFO*>(&hdr));
+    view_->InvalidateRect(&paint_rect.ToRECT());
+  }
+
+  CloseHandle(source_process_handle);
+  gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_));
+}
+
+void GpuBackingStore::OnScrollBackingStore(int dx, int dy,
+                                           const gfx::Rect& clip_rect,
+                                           const gfx::Size& view_size) {
+  RECT damaged_rect, r = clip_rect.ToRECT();
+  ScrollDC(hdc_, dx, dy, NULL, &r, NULL, &damaged_rect);
+
+  // TODO(darin): this doesn't work if dx and dy are both non-zero!
+  DCHECK(dx == 0 || dy == 0);
+
+  view_->DidScrollBackingStoreRect(dx, dy, clip_rect);
+}
diff --git a/chrome/gpu/gpu_backing_store.h b/chrome/gpu/gpu_backing_store.h
new file mode 100644
index 0000000..bfe9941
--- /dev/null
+++ b/chrome/gpu/gpu_backing_store.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2010 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_GPU_GPU_BACKING_STORE_H_
+#define CHROME_GPU_GPU_BACKING_STORE_H_
+
+#include <windows.h>
+
+#include <vector>
+
+#include "app/gfx/native_widget_types.h"
+#include "base/basictypes.h"
+#include "base/gfx/size.h"
+#include "chrome/common/transport_dib.h"
+#include "ipc/ipc_channel.h"
+
+class GpuThread;
+class GpuViewWin;
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+class GpuBackingStore : public IPC::Channel::Listener {
+ public:
+  GpuBackingStore(GpuViewWin* view,
+                  GpuThread* gpu_thread,
+                  int32 routing_id,
+                  const gfx::Size& size);
+  ~GpuBackingStore();
+
+  gfx::Size size() const { return size_; }
+  HDC hdc() const { return hdc_; }
+
+  // IPC::Channel::Listener implementation.
+  virtual void OnMessageReceived(const IPC::Message& message);
+  virtual void OnChannelConnected(int32 peer_pid);
+  virtual void OnChannelError();
+
+ private:
+  // Message handlers.
+  void OnPaintToBackingStore(base::ProcessId source_process_id,
+                             TransportDIB::Id id,
+                             const gfx::Rect& bitmap_rect,
+                             const std::vector<gfx::Rect>& copy_rects);
+  void OnScrollBackingStore(int dx, int dy,
+                            const gfx::Rect& clip_rect,
+                            const gfx::Size& view_size);
+
+  GpuViewWin* view_;
+
+  GpuThread* gpu_thread_;
+  int32 routing_id_;
+
+  gfx::Size size_;
+
+  // The backing store dc.
+  HDC hdc_;
+
+  // Handle to the backing store dib.
+  HANDLE backing_store_dib_;
+
+  // Handle to the original bitmap in the dc.
+  HANDLE original_bitmap_;
+
+  // Number of bits per pixel of the screen.
+  int color_depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuBackingStore);
+};
+
+#endif  // CHROME_GPU_GPU_BACKING_STORE_H_
diff --git a/chrome/gpu/gpu_main.cc b/chrome/gpu/gpu_main.cc
new file mode 100644
index 0000000..e60cffab
--- /dev/null
+++ b/chrome/gpu/gpu_main.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2010 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/message_loop.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/main_function_params.h"
+#include "chrome/gpu/gpu_process.h"
+#include "chrome/gpu/gpu_thread.h"
+
+#if defined(OS_WIN)
+#include "app/win_util.h"
+#endif
+
+// Main function for starting the Gpu process.
+int GpuMain(const MainFunctionParams& parameters) {
+#if defined(USE_LINUX_BREAKPAD)
+  // Needs to be called after we have chrome::DIR_USER_DATA.
+  InitCrashReporter();
+#endif
+
+  MessageLoop main_message_loop(MessageLoop::TYPE_UI);
+  std::wstring app_name = chrome::kBrowserAppName;
+  PlatformThread::SetName(WideToASCII(app_name + L"_GpuMain").c_str());
+
+#if defined(OS_WIN)
+  win_util::ScopedCOMInitializer com_initializer;
+#endif
+
+  GpuProcess gpu_process;
+  gpu_process.set_main_thread(new GpuThread());
+
+  main_message_loop.Run();
+
+  return 0;
+}
+
diff --git a/chrome/gpu/gpu_process.cc b/chrome/gpu/gpu_process.cc
new file mode 100644
index 0000000..ada83c8
--- /dev/null
+++ b/chrome/gpu/gpu_process.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2010 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/gpu/gpu_process.h"
+
+GpuProcess::GpuProcess() {
+}
+
+GpuProcess::~GpuProcess() {
+}
diff --git a/chrome/gpu/gpu_process.h b/chrome/gpu/gpu_process.h
new file mode 100644
index 0000000..92c73a67
--- /dev/null
+++ b/chrome/gpu/gpu_process.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2010 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_GPU_GPU_PROCESS_H_
+#define CHROME_GPU_GPU_PROCESS_H_
+
+#include "chrome/common/child_process.h"
+
+class GpuProcess : public ChildProcess {
+ public:
+  GpuProcess();
+  ~GpuProcess();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GpuProcess);
+};
+
+#endif  // CHROME_GPU_GPU_PROCESS_H_
diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc
new file mode 100644
index 0000000..d143cbc
--- /dev/null
+++ b/chrome/gpu/gpu_thread.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2010 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/gpu/gpu_thread.h"
+
+#include "build/build_config.h"
+#include "chrome/common/gpu_messages.h"
+
+#if defined(OS_WIN)
+#include "chrome/gpu/gpu_view_win.h"
+#endif
+
+GpuThread::GpuThread() {
+}
+
+GpuThread::~GpuThread() {
+}
+
+void GpuThread::OnControlMessageReceived(const IPC::Message& msg) {
+  bool msg_is_ok = true;
+  IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok)
+    IPC_MESSAGE_HANDLER(GpuMsg_NewRenderWidgetHostView,
+                        OnNewRenderWidgetHostView)
+  IPC_END_MESSAGE_MAP_EX()
+}
+
+void GpuThread::OnNewRenderWidgetHostView(gfx::NativeViewId parent_window,
+                                          int32 routing_id) {
+#if defined(OS_WIN)
+  // The class' lifetime is controlled by the host, which will send a message to
+  // destroy the GpuRWHView when necessary. So we don't manage the lifetime
+  // of this object.
+  new GpuViewWin(this, parent_window, routing_id);
+#else
+  NOTIMPLEMENTED();
+#endif
+}
diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h
new file mode 100644
index 0000000..3f25b00
--- /dev/null
+++ b/chrome/gpu/gpu_thread.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2010 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_GPU_GPU_THREAD_H_
+#define CHROME_GPU_GPU_THREAD_H_
+
+#include "app/gfx/native_widget_types.h"
+#include "base/basictypes.h"
+#include "chrome/common/child_thread.h"
+
+class GpuThread : public ChildThread {
+ public:
+  GpuThread();
+  ~GpuThread();
+
+ private:
+  // ChildThread overrides.
+  virtual void OnControlMessageReceived(const IPC::Message& msg);
+
+  // Message handlers.
+  void OnNewRenderWidgetHostView(gfx::NativeViewId parent_window,
+                                 int32 routing_id);
+
+  DISALLOW_COPY_AND_ASSIGN(GpuThread);
+};
+
+#endif  // CHROME_GPU_GPU_THREAD_H_
diff --git a/chrome/gpu/gpu_view_win.cc b/chrome/gpu/gpu_view_win.cc
new file mode 100644
index 0000000..e94c6950
--- /dev/null
+++ b/chrome/gpu/gpu_view_win.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2010 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/gpu/gpu_view_win.h"
+
+#include "chrome/common/gpu_messages.h"
+#include "chrome/gpu/gpu_backing_store.h"
+#include "chrome/gpu/gpu_thread.h"
+
+namespace {
+
+void DrawBackground(const RECT& dirty_rect, CPaintDC* dc) {
+  HBRUSH white_brush = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
+  dc->FillRect(&dirty_rect, white_brush);
+}
+
+void DrawResizeCorner(const RECT& dirty_rect, HDC dc) {
+  // TODO(brettw): implement this.
+}
+
+}  // namespace
+
+GpuViewWin::GpuViewWin(GpuThread* gpu_thread,
+                       gfx::NativeViewId parent_window,
+                       int32 routing_id)
+    : gpu_thread_(gpu_thread),
+      routing_id_(routing_id),
+      parent_window_(gfx::NativeViewFromId(parent_window)) {
+  gpu_thread_->AddRoute(routing_id_, this);
+  Create(gfx::NativeViewFromId(parent_window));
+  SetWindowText(L"GPU window");
+  ShowWindow(SW_SHOW);
+}
+
+GpuViewWin::~GpuViewWin() {
+  gpu_thread_->RemoveRoute(routing_id_);
+  // TODO(brettw) may want to delete any dangling backing stores, or perhaps
+  // assert if one still exists.
+}
+
+void GpuViewWin::OnMessageReceived(const IPC::Message& msg) {
+  IPC_BEGIN_MESSAGE_MAP(GpuViewWin, msg)
+    IPC_MESSAGE_HANDLER(GpuMsg_NewBackingStore, OnNewBackingStore)
+  IPC_END_MESSAGE_MAP_EX()
+}
+
+void GpuViewWin::OnChannelConnected(int32 peer_pid) {
+}
+
+void GpuViewWin::OnChannelError() {
+  // TODO(brettw) do we need to delete ourselves now?
+}
+
+void GpuViewWin::DidScrollBackingStoreRect(int dx, int dy,
+                                           const gfx::Rect& rect) {
+  // We need to pass in SW_INVALIDATE to ScrollWindowEx.  The documentation on
+  // MSDN states that it only applies to the HRGN argument, which is wrong.
+  // Not passing in this flag does not invalidate the region which was scrolled
+  // from, thus causing painting issues.
+  RECT clip_rect = rect.ToRECT();
+  ScrollWindowEx(dx, dy, NULL, &clip_rect, NULL, NULL, SW_INVALIDATE);
+}
+
+void GpuViewWin::OnNewBackingStore(int32 routing_id, const gfx::Size& size) {
+  backing_store_.reset(
+      new GpuBackingStore(this, gpu_thread_, routing_id, size));
+  MoveWindow(0, 0, size.width(), size.height(), TRUE);
+}
+
+void GpuViewWin::OnPaint(HDC unused_dc) {
+  // Grab the region to paint before creation of paint_dc since it clears the
+  // damage region.
+  ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
+  GetUpdateRgn(damage_region, FALSE);
+
+  CPaintDC paint_dc(m_hWnd);
+
+  gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint);
+  if (damaged_rect.IsEmpty())
+    return;
+
+  if (backing_store_.get()) {
+    gfx::Rect bitmap_rect(gfx::Point(), backing_store_->size());
+
+    // Blit only the damaged regions from the backing store.
+    DWORD data_size = GetRegionData(damage_region, 0, NULL);
+    // TODO(brettw) why is the "+1" necessary here? When I remove it, the
+    // page paints black, but according to the documentation, its not needed.
+    scoped_array<char> region_data_buf(new char[data_size + 1]);
+    RGNDATA* region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get());
+    GetRegionData(damage_region, data_size, region_data);
+
+    RECT* region_rects = reinterpret_cast<RECT*>(region_data->Buffer);
+    for (DWORD i = 0; i < region_data->rdh.nCount; ++i) {
+      gfx::Rect paint_rect = bitmap_rect.Intersect(gfx::Rect(region_rects[i]));
+      if (!paint_rect.IsEmpty()) {
+        DrawResizeCorner(paint_rect.ToRECT(), backing_store_->hdc());
+        BitBlt(paint_dc.m_hDC,
+               paint_rect.x(),
+               paint_rect.y(),
+               paint_rect.width(),
+               paint_rect.height(),
+               backing_store_->hdc(),
+               paint_rect.x(),
+               paint_rect.y(),
+               SRCCOPY);
+      }
+    }
+
+    // Fill the remaining portion of the damaged_rect with the background
+    if (damaged_rect.right() > bitmap_rect.right()) {
+      RECT r;
+      r.left = std::max(bitmap_rect.right(), damaged_rect.x());
+      r.right = damaged_rect.right();
+      r.top = damaged_rect.y();
+      r.bottom = std::min(bitmap_rect.bottom(), damaged_rect.bottom());
+      DrawBackground(r, &paint_dc);
+    }
+    if (damaged_rect.bottom() > bitmap_rect.bottom()) {
+      RECT r;
+      r.left = damaged_rect.x();
+      r.right = damaged_rect.right();
+      r.top = std::max(bitmap_rect.bottom(), damaged_rect.y());
+      r.bottom = damaged_rect.bottom();
+      DrawBackground(r, &paint_dc);
+    }
+  } else {
+    DrawBackground(paint_dc.m_ps.rcPaint, &paint_dc);
+  }
+}
+
+LRESULT GpuViewWin::OnMouseEvent(UINT message,
+                                 WPARAM wparam,
+                                 LPARAM lparam,
+                                 BOOL& handled) {
+  handled = true;
+  ::PostMessage(GetParent(), message, wparam, lparam);
+  return 0;
+}
+
+LRESULT GpuViewWin::OnKeyEvent(UINT message,
+                               WPARAM wparam,
+                               LPARAM lparam,
+                               BOOL& handled) {
+  handled = true;
+  ::PostMessage(GetParent(), message, wparam, lparam);
+  return 0;
+}
+
+LRESULT GpuViewWin::OnWheelEvent(UINT message,
+                                 WPARAM wparam,
+                                 LPARAM lparam,
+                                 BOOL& handled) {
+  handled = true;
+  ::PostMessage(GetParent(), message, wparam, lparam);
+  return 0;
+}
diff --git a/chrome/gpu/gpu_view_win.h b/chrome/gpu/gpu_view_win.h
new file mode 100644
index 0000000..30efeac8
--- /dev/null
+++ b/chrome/gpu/gpu_view_win.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2010 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_GPU_GPU_VIEW_WIN_H_
+#define CHROME_GPU_GPU_VIEW_WIN_H_
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcrack.h>
+#include <atlmisc.h>
+
+#include "app/gfx/native_widget_types.h"
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "ipc/ipc_channel.h"
+
+class GpuBackingStore;
+class GpuThread;
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+typedef CWinTraits<WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0>
+    GpuRenderWidgetHostViewWinTraits;
+
+class GpuViewWin
+    : public IPC::Channel::Listener,
+      public CWindowImpl<GpuViewWin,
+                         CWindow,
+                         GpuRenderWidgetHostViewWinTraits> {
+ public:
+  GpuViewWin(GpuThread* gpu_thread,
+                             gfx::NativeViewId parent_window,
+                             int32 routing_id);
+  ~GpuViewWin();
+
+  // IPC::Channel::Listener implementation.
+  virtual void OnMessageReceived(const IPC::Message& message);
+  virtual void OnChannelConnected(int32 peer_pid);
+  virtual void OnChannelError();
+
+  void DidScrollBackingStoreRect(int dx, int dy, const gfx::Rect& rect);
+
+  BEGIN_MSG_MAP(GpuViewWin)
+    MSG_WM_PAINT(OnPaint)
+    MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseEvent)
+    MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseEvent)
+    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnMouseEvent)
+    MESSAGE_HANDLER(WM_MBUTTONDOWN, OnMouseEvent)
+    MESSAGE_HANDLER(WM_RBUTTONDOWN, OnMouseEvent)
+    MESSAGE_HANDLER(WM_LBUTTONUP, OnMouseEvent)
+    MESSAGE_HANDLER(WM_MBUTTONUP, OnMouseEvent)
+    MESSAGE_HANDLER(WM_RBUTTONUP, OnMouseEvent)
+    MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnMouseEvent)
+    MESSAGE_HANDLER(WM_MBUTTONDBLCLK, OnMouseEvent)
+    MESSAGE_HANDLER(WM_RBUTTONDBLCLK, OnMouseEvent)
+    MESSAGE_HANDLER(WM_SYSKEYDOWN, OnKeyEvent)
+    MESSAGE_HANDLER(WM_SYSKEYUP, OnKeyEvent)
+    MESSAGE_HANDLER(WM_KEYDOWN, OnKeyEvent)
+    MESSAGE_HANDLER(WM_KEYUP, OnKeyEvent)
+    MESSAGE_HANDLER(WM_MOUSEWHEEL, OnWheelEvent)
+    MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnWheelEvent)
+    MESSAGE_HANDLER(WM_HSCROLL, OnWheelEvent)
+    MESSAGE_HANDLER(WM_VSCROLL, OnWheelEvent)
+    MESSAGE_HANDLER(WM_CHAR, OnKeyEvent)
+    MESSAGE_HANDLER(WM_SYSCHAR, OnKeyEvent)
+    MESSAGE_HANDLER(WM_IME_CHAR, OnKeyEvent)
+  END_MSG_MAP()
+
+ private:
+  // IPC message handlers.
+  void OnNewBackingStore(int32 routing_id, const gfx::Size& size);
+
+  // Windows message handlers.
+  void OnPaint(HDC unused_dc);
+  LRESULT OnMouseEvent(UINT message,
+                       WPARAM wparam,
+                       LPARAM lparam,
+                       BOOL& handled);
+  LRESULT OnKeyEvent(UINT message,
+                     WPARAM wparam,
+                     LPARAM lparam,
+                     BOOL& handled);
+  LRESULT OnWheelEvent(UINT message,
+                       WPARAM wparam,
+                       LPARAM lparam,
+                       BOOL& handled);
+
+  GpuThread* gpu_thread_;
+  int32 routing_id_;
+
+  HWND parent_window_;
+
+  scoped_ptr<GpuBackingStore> backing_store_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuViewWin);
+};
+
+#endif  // CHROME_GPU_GPU_VIEW_WIN_H_