diff options
55 files changed, 2067 insertions, 551 deletions
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc index 8ef4314..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 @@ int ChromeMain(int argc, char** argv) { 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 NaClBrokerMain(const MainFunctionParams& parameters) { 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 @@ bool CaptureVisibleTabFunction::RunImpl() { // 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..1856182 --- /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..afaedea 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 @@ gboolean DraggedTabGtk::OnExposeEvent(GtkWidget* widget, 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..a60adc2 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" - -#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 +#include "chrome/common/transport_dib.h" +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..3d9e793 --- /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(RenderWidgetHost* widget, const gfx::Size& size) } } -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 @@ void BackingStore::PaintRect(base::ProcessHandle process, 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()))); - - 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); + for (size_t i = 0; i < copy_rects.size(); i++) { + const gfx::Rect& copy_rect = copy_rects[i]; + + // 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 @@ void BackingStore::ScrollRect(int dx, int dy, // 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 @@ void BackingStore::ScrollRect(int dx, int dy, 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 @@ void BackingStore::ScrollRect(int dx, int dy, 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 @@ void BackingStore::ScrollRect(int dx, int dy, } } -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 @@ CGLayerRef BackingStore::CreateCGLayer() { 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 4e21d04..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 @@ BackingStore* BackingStoreManager::GetBackingStore( } // 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 @@ BackingStore* BackingStoreManager::PrepareBackingStore( *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 847d8a1..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 @@ class BackingStoreManager { 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 @@ class BackingStoreManager { // 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..b39eebd --- /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..f82d948 --- /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 @@ HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) { 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 @@ void CallStretchDIBits(HDC hdc, int dest_x, int dest_y, int dest_w, int dest_h, } // 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 @@ BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size) ReleaseDC(NULL, screen_dc); } -BackingStore::~BackingStore() { +BackingStoreWin::~BackingStoreWin() { DCHECK(hdc_); if (original_bitmap_) { SelectObject(hdc_, original_bitmap_); @@ -97,12 +96,8 @@ BackingStore::~BackingStore() { 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 @@ bool BackingStore::ColorManagementEnabled() { 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 @@ void BackingStore::PaintRect(base::ProcessHandle process, 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); - - 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)); + 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)); + } +} + +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 BackingStore::ScrollRect(int dx, int dy, - const gfx::Rect& clip_rect, - const gfx::Size& view_size) { +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..af334fa 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 @@ static void DestroySharedImage(Display* display, 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 @@ BackingStore::BackingStore(RenderWidgetHost* widget, 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 @@ BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size) root_window_(0) { } -BackingStore::~BackingStore() { +BackingStoreX::~BackingStoreX() { // In unit tests, display_ may be NULL. if (!display_) return; @@ -97,16 +98,17 @@ BackingStore::~BackingStore() { 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 @@ void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap, << " 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 @@ void BackingStore::PaintRect(base::ProcessHandle process, 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 @@ void BackingStore::PaintRect(base::ProcessHandle process, 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 @@ void BackingStore::PaintRect(base::ProcessHandle process, 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 @@ void BackingStore::PaintRect(base::ProcessHandle process, } 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 @@ void BackingStore::PaintRect(base::ProcessHandle process, 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::ScrollRect(int dx, int dy, } } -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 @@ void BackingStore::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) { 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 eac566b..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 @@ bool BrowserRenderProcessHost::Send(IPC::Message* msg) { 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 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { 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..52fae31 --- /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..a995fa0 --- /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 @@ class RenderProcessHost : public IPC::Channel::Sender, // 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 @@ BackingStore* RenderWidgetHost::AllocBackingStore(const gfx::Size& size) { 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 @@ void RenderWidgetHost::OnMsgUpdateRect( 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 @@ void RenderWidgetHost::OnMsgUpdateRect( // 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 @@ void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, #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 @@ void RenderWidgetHost::PaintBackingStoreRect( } 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 @@ void RenderWidgetHost::ScrollBackingStoreRect(int dx, int dy, 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 d59fc4e..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 @@ class RenderWidgetHost : public IPC::Channel::Listener, // (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 @@ class RenderWidgetHost : public IPC::Channel::Listener, #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 aee6b5f..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 @@ void RenderWidgetHostViewGtk::DidScrollBackingStoreRect(const gfx::Rect& rect, 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 @@ void RenderWidgetHostViewGtk::ShowingContextMenu(bool showing) { 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 @@ void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) { 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 @@ void RenderWidgetHostViewMac::SetTooltipText(const std::wstring& tooltip_text) { 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 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) { 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 @@ RenderWidgetHostViewWin::~RenderWidgetHostViewWin() { 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 @@ void RenderWidgetHostViewWin::SetTooltipText(const std::wstring& tooltip_text) { 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 @@ void RenderWidgetHostViewWin::OnDestroy() { 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 @@ void RenderWidgetHostViewWin::OnPaint(HDC dc) { 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 Message; class BackingStore; class RenderWidgetHost; +class GpuViewHostWin; typedef CWinTraits<WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0> RenderWidgetHostHWNDTraits; @@ -59,6 +61,8 @@ class RenderWidgetHostViewWin 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 @@ class RenderWidgetHostViewWin 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 @@ class RenderWidgetHostViewWin // 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 720f51e..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 @@ TestRenderWidgetHostView::TestRenderWidgetHostView(RenderWidgetHost* rwh) 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 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, 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 1a5c5c4..ccd781e 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 @@ WidgetThumbnail* GetDataForHost(RenderWidgetHost* host) { 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 GetThumbnailForBackingStore(BackingStore* backing_store) { SkBitmap result; - // TODO(brettw) write this for other platforms. If you enable this, be sure - // to also enable the unit tests for the same platform in - // thumbnail_generator_unittest.cc -#if defined(OS_WIN) // Get the bitmap as a Skia object so we can resample it. This is a large // allocation and we can tolerate failure here, so give up if the allocation // fails. 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 b46290b..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 @@ RenderWidgetHostView* TabContentsViewWin::CreateViewForWidget( 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..3e280a9 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 d567984..2625ca9 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 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver, }; 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 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver, }; 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..5726675 100644 --- a/chrome/common/child_process_info.h +++ b/chrome/common/child_process_info.h @@ -24,7 +24,8 @@ class ChildProcessInfo { 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 kEnableFastback[] = "enable-fastback"; 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 @@ const char kFirstRun[] = "first-run"; // 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 @@ const char kInternalNaCl[] = "internal-nacl"; // 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 @@ const char kKioskMode[] = "kiosk"; #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 kExtensionsUpdateFrequency[]; 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 kInProcessPlugins[]; 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 @@ extern const char kKioskMode[]; #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..e60cffa --- /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..92c73a6 --- /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..e94c695 --- /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_ diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h index 4f1a6f32..0bffce9 100644 --- a/ipc/ipc_message_utils.h +++ b/ipc/ipc_message_utils.h @@ -48,6 +48,8 @@ enum IPCMessageStart { CommandBufferMsgStart, UtilityMsgStart, UtilityHostMsgStart, + GpuMsgStart, + GpuHostMsgStart, // NOTE: When you add a new message class, also update // IPCStatusView::IPCStatusView to ensure logging works. LastMsgIndex |