diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-22 22:26:59 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-22 22:26:59 +0000 |
commit | 22c54fdc29f5c5952175ec4a5d0f954139f2fb75 (patch) | |
tree | 66ee6c27c6bf2eb75e3a4c3ec6cee7b7463aa4db /chrome | |
parent | 20ea3526d1b851a5594d7d05a472e83757df034d (diff) | |
download | chromium_src-22c54fdc29f5c5952175ec4a5d0f954139f2fb75.zip chromium_src-22c54fdc29f5c5952175ec4a5d0f954139f2fb75.tar.gz chromium_src-22c54fdc29f5c5952175ec4a5d0f954139f2fb75.tar.bz2 |
Desynchronize windowless plugin painting. This greatly improves the painting
performance when there are multiple plugins, or when scrolling.
Review URL: http://codereview.chromium.org/3133
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2459 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/common/plugin_messages.h | 45 | ||||
-rw-r--r-- | chrome/common/plugin_messages_internal.h | 15 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.cc | 127 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.h | 19 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.cc | 145 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.h | 42 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 179 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.h | 13 |
8 files changed, 260 insertions, 325 deletions
diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h index cbe0b31..6ebead6 100644 --- a/chrome/common/plugin_messages.h +++ b/chrome/common/plugin_messages.h @@ -58,18 +58,6 @@ struct PluginMsg_URLRequestReply_Params { HANDLE stream; }; -struct PluginMsg_Paint_Params { - gfx::Size size; - gfx::Rect clip_rect; - gfx::Rect damaged_rect; - - // Bitmap's bits. - HANDLE shared_memory; - - // Information about the world transform (see GetWorldTransform). - XFORM xf; -}; - struct PluginMsg_PrintResponse_Params { HANDLE shared_memory; size_t size; @@ -254,39 +242,6 @@ struct ParamTraits<PluginMsg_URLRequestReply_Params> { }; template <> -struct ParamTraits<PluginMsg_Paint_Params> { - typedef PluginMsg_Paint_Params param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.size); - WriteParam(m, p.clip_rect); - WriteParam(m, p.damaged_rect); - WriteParam(m, p.shared_memory); - WriteParam(m, p.xf); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return - ReadParam(m, iter, &r->size) && - ReadParam(m, iter, &r->clip_rect) && - ReadParam(m, iter, &r->damaged_rect) && - ReadParam(m, iter, &r->shared_memory) && - ReadParam(m, iter, &r->xf); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(L"("); - LogParam(p.size, l); - l->append(L", "); - LogParam(p.clip_rect, l); - l->append(L", "); - LogParam(p.damaged_rect, l); - l->append(L", "); - LogParam(p.shared_memory, l); - l->append(L", "); - LogParam(p.xf, l); - l->append(L")"); - } -}; - -template <> struct ParamTraits<PluginMsg_PrintResponse_Params> { typedef PluginMsg_PrintResponse_Params param_type; static void Write(Message* m, const param_type& p) { diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index b0df3b3..36cb1cd 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -102,18 +102,9 @@ IPC_BEGIN_MESSAGES(Plugin, 5) PluginMsg_Init_Params, bool /* result */) - IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_Paint, - PluginMsg_Paint_Params /* params */) - IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_Print, PluginMsg_PrintResponse_Params /* params */) - // Returns a shared memory handle to a EMF buffer. - IPC_SYNC_MESSAGE_ROUTED1_2(PluginMsg_PaintIntoSharedMemory, - PluginMsg_Paint_Params /* params */, - SharedMemoryHandle /* emf_buffer */, - size_t /* bytes */) - IPC_SYNC_MESSAGE_ROUTED0_2(PluginMsg_GetPluginScriptableObject, int /* route_id */, void* /* npobject_ptr */) @@ -121,10 +112,12 @@ IPC_BEGIN_MESSAGES(Plugin, 5) IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_DidFinishLoadWithReason, int /* reason */) - IPC_MESSAGE_ROUTED3(PluginMsg_UpdateGeometry, + IPC_MESSAGE_ROUTED5(PluginMsg_UpdateGeometry, gfx::Rect /* window_rect */, gfx::Rect /* clip_rect */, - bool /* visible */) + bool /* visible */, + SharedMemoryHandle /* windowless_buffer */, + SharedMemoryLock /* windowless_buffer_lock */) IPC_SYNC_MESSAGE_ROUTED0_0(PluginMsg_SetFocus) diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 047afce..e2129f2 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -6,7 +6,6 @@ #include "base/command_line.h" #include "base/time.h" -#include "base/gfx/bitmap_header.h" #include "base/gfx/platform_device_win.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/gfx/emf.h" @@ -81,10 +80,7 @@ void WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { OnDidFinishLoadWithReason) IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus) IPC_MESSAGE_HANDLER(PluginMsg_HandleEvent, OnHandleEvent) - IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint) IPC_MESSAGE_HANDLER(PluginMsg_Print, OnPrint) - IPC_MESSAGE_HANDLER(PluginMsg_PaintIntoSharedMemory, - OnPaintIntoSharedMemory) IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject, OnGetPluginScriptableObject) IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry) @@ -203,47 +199,6 @@ void WebPluginDelegateStub::OnHandleEvent(const NPEvent& event, *handled = delegate_->HandleEvent(const_cast<NPEvent*>(&event), cursor); } -void WebPluginDelegateStub::OnPaint(const PluginMsg_Paint_Params& params) { - // Convert the shared memory handle to a handle that works in our process, - // and then use that to create an HDC. - win_util::ScopedHandle shared_section(win_util::GetSectionFromProcess( - params.shared_memory, channel_->renderer_handle(), false)); - - if (shared_section == NULL) { - NOTREACHED(); - return; - } - - void* data = NULL; - HDC screen_dc = GetDC(NULL); - BITMAPINFOHEADER bitmap_header; - gfx::CreateBitmapHeader(params.size.width(), params.size.height(), - &bitmap_header); - win_util::ScopedBitmap hbitmap(CreateDIBSection( - screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header), - DIB_RGB_COLORS, &data, - shared_section, 0)); - ReleaseDC(NULL, screen_dc); - if (hbitmap == NULL) { - NOTREACHED(); - return; - } - - win_util::ScopedHDC hdc(CreateCompatibleDC(NULL)); - if (hdc == NULL) { - NOTREACHED(); - return; - } - gfx::PlatformDeviceWin::InitializeDC(hdc); - SelectObject(hdc, hbitmap); - SetWorldTransform(hdc, ¶ms.xf); - - win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(¶ms.clip_rect.ToRECT())); - SelectClipRgn(hdc, hrgn); - webplugin_->WillPaint(); - delegate_->Paint(hdc, params.damaged_rect); -} - void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) { gfx::Emf emf; if (!emf.CreateDc(NULL, NULL)) { @@ -269,80 +224,14 @@ void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) { DCHECK(success); } -void WebPluginDelegateStub::OnPaintIntoSharedMemory( - const PluginMsg_Paint_Params& params, - SharedMemoryHandle* emf_buffer, - size_t* bytes) { - *emf_buffer = NULL; - *bytes = 0; - - gfx::Emf emf; - if (!emf.CreateDc(NULL, NULL)) { - NOTREACHED(); - return; - } - HDC hdc = emf.hdc(); - gfx::PlatformDeviceWin::InitializeDC(hdc); - - if (delegate_->windowless()) { - WindowlessPaint(hdc, params); - } else { - WindowedPaint(hdc, params.damaged_rect); - } - - // Need to send back the data as shared memory. - if (!emf.CloseDc()) { - NOTREACHED(); - return; - } - - size_t size = emf.GetDataSize(); - DCHECK(size); - *bytes = size; - SharedMemory shared_buf; - CreateSharedBuffer(size, &shared_buf, emf_buffer); - - // Retrieve a copy of the data. - bool success = emf.GetData(shared_buf.memory(), size); - DCHECK(success); -} - -void WebPluginDelegateStub::WindowedPaint(HDC hdc, - const gfx::Rect& window_rect) { - // Use the NPAPI print() function to render the plugin. - delegate_->Print(hdc); -} - -void WebPluginDelegateStub::WindowlessPaint( - HDC hdc, - const PluginMsg_Paint_Params& params) { - void* data = NULL; - HDC screen_dc = GetDC(NULL); - BITMAPINFOHEADER bitmap_header; - gfx::CreateBitmapHeader(params.size.width(), params.size.height(), - &bitmap_header); - win_util::ScopedBitmap hbitmap(CreateDIBSection( - screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header), - DIB_RGB_COLORS, &data, NULL, 0)); - ReleaseDC(NULL, screen_dc); - if (hbitmap == NULL) { - NOTREACHED(); - return; - } - SelectObject(hdc, hbitmap); - - // Apply transform and clipping. - SetWorldTransform(hdc, ¶ms.xf); - win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(¶ms.clip_rect.ToRECT())); - SelectClipRgn(hdc, hrgn); - webplugin_->WillPaint(); - delegate_->Paint(hdc, params.damaged_rect); -} - -void WebPluginDelegateStub::OnUpdateGeometry(const gfx::Rect& window_rect, - const gfx::Rect& clip_rect, - bool visible) { - delegate_->UpdateGeometry(window_rect, clip_rect, visible); +void WebPluginDelegateStub::OnUpdateGeometry( + const gfx::Rect& window_rect, + const gfx::Rect& clip_rect, + bool visible, + const SharedMemoryHandle& windowless_buffer, + const SharedMemoryLock& lock) { + webplugin_->UpdateGeometry( + window_rect, clip_rect, visible, windowless_buffer, lock); } void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id, diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index f113cb8..cb242b4 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -19,7 +19,6 @@ class PluginChannel; class WebPluginProxy; class WebPluginDelegateImpl; struct PluginMsg_Init_Params; -struct PluginMsg_Paint_Params; struct PluginMsg_DidReceiveResponseParams; class WebCursor; @@ -58,23 +57,11 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, void OnSetFocus(); void OnHandleEvent(const NPEvent& event, bool* handled, WebCursor* cursor); - - void OnPaint(const PluginMsg_Paint_Params& params); - void OnPrint(PluginMsg_PrintResponse_Params* params); - - // Paints the plugin into a buffer. It roughly does the same as OnPaint (i.e. - // painting a plugin) except that the plugin window is always renderered into - // an EMF buffer and that it is effective for windowed plugins too. - void OnPaintIntoSharedMemory(const PluginMsg_Paint_Params& params, - SharedMemoryHandle* emf_buffer, size_t* bytes); - // Paints a windowed plugin into a device context. - void WindowedPaint(HDC hdc, const gfx::Rect& window_rect); - // Paints a windowless plugin into a device context. - void WindowlessPaint(HDC hdc, - const PluginMsg_Paint_Params& params); void OnUpdateGeometry(const gfx::Rect& window_rect, - const gfx::Rect& clip_rect, bool visible); + const gfx::Rect& clip_rect, bool visible, + const SharedMemoryHandle& windowless_buffer, + const SharedMemoryLock& lock); void OnGetPluginScriptableObject(int* route_id, void** npobject_ptr); void OnSendJavaScriptStream(const std::string& url, const std::wstring& result, diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index 6f68c2d..cc091a2 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -4,14 +4,22 @@ #include "chrome/plugin/webplugin_proxy.h" +#include "base/gfx/bitmap_header.h" +#include "base/gfx/platform_device_win.h" #include "base/scoped_handle.h" +#include "base/shared_memory.h" #include "base/singleton.h" +#include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/plugin_messages.h" +#include "chrome/common/win_util.h" #include "chrome/plugin/plugin_channel.h" #include "chrome/plugin/webplugin_delegate_stub.h" #include "chrome/plugin/npobject_proxy.h" #include "chrome/plugin/npobject_util.h" -#include "webkit/glue/webplugin_delegate.h" +#include "webkit/glue/plugins/webplugin_delegate_impl.h" + +// How many times per second we draw windowless plugins. +static const int kWindowlessPaintFPS = 30; typedef std::map<CPBrowsingContext, WebPluginProxy*> ContextMap; static ContextMap& GetContextMap() { @@ -21,15 +29,14 @@ static ContextMap& GetContextMap() { WebPluginProxy::WebPluginProxy( PluginChannel* channel, int route_id, - WebPluginDelegate* delegate, + WebPluginDelegateImpl* delegate, HANDLE modal_dialog_event) : channel_(channel), route_id_(route_id), cp_browsing_context_(0), window_npobject_(NULL), plugin_element_(NULL), - delegate_(delegate), - waiting_for_paint_(false) { + delegate_(delegate) { HANDLE event; BOOL result = DuplicateHandle(channel->renderer_handle(), @@ -78,17 +85,10 @@ void WebPluginProxy::Invalidate() { } void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) { - // Ignore NPN_InvalidateRect calls with empty rects. - if (rect.IsEmpty()) { - return; - } - // Only send a single InvalidateRect message at a time. From WillPaint we - // will dispatch an additional InvalidateRect message if necessary. - if (waiting_for_paint_) { - damaged_rect_ = damaged_rect_.Union(rect); - } else { - waiting_for_paint_ = true; - Send(new PluginHostMsg_InvalidateRect(route_id_, rect)); + damaged_rect_ = damaged_rect_.Union(rect); + if (!paint_timer_.IsRunning()) { + paint_timer_.Start(TimeDelta::FromMilliseconds(1000 / kWindowlessPaintFPS), + this, &WebPluginProxy::OnPaintTimerFired); } } @@ -190,16 +190,6 @@ WebPluginResourceClient* WebPluginProxy::GetResourceClient(int id) { return iterator->second; } -void WebPluginProxy::WillPaint() { - // If we have an accumulated damaged rect, then check to see if we need to - // send out another InvalidateRect message. - waiting_for_paint_ = false; - if (!damaged_rect_.IsEmpty()) { - InvalidateRect(damaged_rect_); - damaged_rect_ = gfx::Rect(); - } -} - void WebPluginProxy::OnResourceCreated(int resource_id, HANDLE cookie) { WebPluginResourceClient* resource_client = reinterpret_cast<WebPluginResourceClient*>(cookie); @@ -243,6 +233,111 @@ void WebPluginProxy::HandleURLRequest(const char *method, Send(new PluginHostMsg_URLRequest(route_id_, params)); } +void WebPluginProxy::OnPaintTimerFired() { + if (!windowless_hdc_) + return; + + if (damaged_rect_.IsEmpty()) { + paint_timer_.Stop(); + return; + } + + DWORD wait_result = WaitForSingleObject(windowless_buffer_lock_, INFINITE); + DCHECK(wait_result == WAIT_OBJECT_0); + + // Clear the damaged area so that if the plugin doesn't paint there we won't + // end up with the old values. + gfx::Rect offset_rect = damaged_rect_; + offset_rect.Offset(delegate_->rect().x(), delegate_->rect().y()); + FillRect(windowless_hdc_, &offset_rect.ToRECT(), + static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); + + // Before we send the invalidate, paint so that renderer uses the updated + // bitmap. + delegate_->Paint(windowless_hdc_, damaged_rect_); + BOOL result = ReleaseMutex(windowless_buffer_lock_); + DCHECK(result); + + Send(new PluginHostMsg_InvalidateRect(route_id_, damaged_rect_)); + damaged_rect_ = gfx::Rect(); +} + +void WebPluginProxy::UpdateGeometry( + const gfx::Rect& window_rect, + const gfx::Rect& clip_rect, + bool visible, + const SharedMemoryHandle& windowless_buffer, + const SharedMemoryLock& lock) { + bool moved = delegate_->rect().x() != window_rect.x() || + delegate_->rect().y() != window_rect.y(); + delegate_->UpdateGeometry(window_rect, clip_rect, visible); + if (windowless_buffer) { + // The plugin's rect changed, so now we have a new buffer to draw into. + SetWindowlessBuffer(windowless_buffer, lock); + } else if (moved) { + // The plugin moved, so update our world transform. + UpdateTransform(); + } +} + +void WebPluginProxy::SetWindowlessBuffer(const SharedMemoryHandle& handle, + const SharedMemoryLock& lock) { + // Convert the shared memory handle to a handle that works in our process, + // and then use that to create an HDC. + windowless_shared_section_.Set(win_util::GetSectionFromProcess( + handle, channel_->renderer_handle(), false)); + if (!windowless_buffer_lock_) { + HANDLE dup_handle = NULL; + DuplicateHandle(channel_->renderer_handle(), lock, GetCurrentProcess(), + &dup_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); + windowless_buffer_lock_.Set(dup_handle); + } + + if (windowless_shared_section_ == NULL || windowless_buffer_lock_ == NULL) { + NOTREACHED(); + return; + } + + void* data = NULL; + HDC screen_dc = GetDC(NULL); + BITMAPINFOHEADER bitmap_header; + gfx::CreateBitmapHeader(delegate_->rect().width(), + delegate_->rect().height(), + &bitmap_header); + windowless_bitmap_.Set(CreateDIBSection( + screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header), + DIB_RGB_COLORS, &data, windowless_shared_section_, 0)); + ReleaseDC(NULL, screen_dc); + if (windowless_bitmap_ == NULL) { + NOTREACHED(); + return; + } + + windowless_hdc_.Set(CreateCompatibleDC(NULL)); + if (windowless_hdc_ == NULL) { + NOTREACHED(); + return; + } + + gfx::PlatformDeviceWin::InitializeDC(windowless_hdc_); + SelectObject(windowless_hdc_, windowless_bitmap_); + UpdateTransform(); +} + +void WebPluginProxy::UpdateTransform() { + if (!windowless_hdc_) + return; + + XFORM xf; + xf.eDx = static_cast<FLOAT>(-delegate_->rect().x()); + xf.eDy = static_cast<FLOAT>(-delegate_->rect().y()); + xf.eM11 = 1; + xf.eM21 = 0; + xf.eM12 = 0; + xf.eM22 = 1; + SetWorldTransform(windowless_hdc_, &xf); +} + void WebPluginProxy::CancelDocumentLoad() { Send(new PluginHostMsg_CancelDocumentLoad(route_id_)); } diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 092bf32..9e1a051 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -8,12 +8,14 @@ #include "base/hash_tables.h" #include "base/ref_counted.h" #include "base/scoped_handle.h" +#include "base/shared_memory.h" +#include "base/timer.h" #include "chrome/common/ipc_message.h" #include "chrome/common/chrome_plugin_api.h" #include "webkit/glue/webplugin.h" class PluginChannel; -class WebPluginDelegate; +class WebPluginDelegateImpl; // This is an implementation of WebPlugin that proxies all calls to the // renderer. @@ -23,7 +25,7 @@ class WebPluginProxy : public WebPlugin { // marshalled WebPlugin calls. WebPluginProxy(PluginChannel* channel, int route_id, - WebPluginDelegate* delegate, + WebPluginDelegateImpl* delegate, HANDLE modal_dialog_event); ~WebPluginProxy(); @@ -60,8 +62,6 @@ class WebPluginProxy : public WebPlugin { // object with that id exists. WebPluginResourceClient* GetResourceClient(int id); - void WillPaint(); - // Notification received on a plugin issued resource request // creation. void OnResourceCreated(int resource_id, HANDLE cookie); @@ -73,6 +73,12 @@ class WebPluginProxy : public WebPlugin { bool notify, const char* url, void* notify_data, bool popups_allowed); + void UpdateGeometry(const gfx::Rect& window_rect, + const gfx::Rect& clip_rect, + bool visible, + const SharedMemoryHandle& windowless_buffer, + const SharedMemoryLock& lock); + void CancelDocumentLoad(); void InitiateHTTPRangeRequest(const char* url, @@ -80,9 +86,21 @@ class WebPluginProxy : public WebPlugin { void* existing_stream, bool notify_needed, HANDLE notify_data); + private: bool Send(IPC::Message* msg); + // Called periodically so that we can paint windowless plugins. + void OnPaintTimerFired(); + + // Updates the shared memory section where windowless plugins paint. + void SetWindowlessBuffer(const SharedMemoryHandle& handle, + const SharedMemoryLock& lock); + + // Called when a plugin's origin moves, so that we can update the world + // transform of the local HDC. + void UpdateTransform(); + typedef base::hash_map<int, WebPluginResourceClient*> ResourceClientMap; ResourceClientMap resource_clients_; @@ -90,11 +108,21 @@ class WebPluginProxy : public WebPlugin { int route_id_; NPObject* window_npobject_; NPObject* plugin_element_; - WebPluginDelegate* delegate_; - gfx::Rect damaged_rect_; - bool waiting_for_paint_; + WebPluginDelegateImpl* delegate_; uint32 cp_browsing_context_; ScopedHandle modal_dialog_event_; + + // Used to desynchronize windowless painting. We accumulate invalidates and + // paint into a shared buffer when our repeating timer fires. After painting + // we tell the renderer asynchronously and it paints from the buffer. This + // allows the renderer to paint without a blocking call, which improves + // performance, and lets us control the frame rate at which we paint. + gfx::Rect damaged_rect_; + base::RepeatingTimer<WebPluginProxy> paint_timer_; + ScopedHandle windowless_shared_section_; + ScopedBitmap windowless_bitmap_; + ScopedHDC windowless_hdc_; + ScopedHandle windowless_buffer_lock_; }; #endif // CHROME_PLUGIN_PLUGIN_WEBPLUGIN_PROXY_H__ diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 225608e..1c5924c 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -143,8 +143,7 @@ WebPluginDelegateProxy::WebPluginDelegateProxy(const std::string& mime_type, send_deferred_update_geometry_(false), visible_(false), sad_plugin_(NULL), - window_script_object_(NULL), - modal_loop_pump_messages_event_(NULL) { + window_script_object_(NULL) { } WebPluginDelegateProxy::~WebPluginDelegateProxy() { @@ -155,10 +154,6 @@ WebPluginDelegateProxy::~WebPluginDelegateProxy() { window_script_object_->set_proxy(NULL); window_script_object_->set_invalid(); } - - if (modal_loop_pump_messages_event_) { - CloseHandle(modal_loop_pump_messages_event_); - } } void WebPluginDelegateProxy::PluginDestroyed() { @@ -186,7 +181,9 @@ void WebPluginDelegateProxy::FlushGeometryUpdates() { Send(new PluginMsg_UpdateGeometry(instance_id_, plugin_rect_, deferred_clip_rect_, - visible_)); + visible_, + NULL, + NULL)); } } @@ -329,21 +326,60 @@ void WebPluginDelegateProxy::OnChannelError() { render_view_->PluginCrashed(plugin_path_); } +// Copied from render_widget.cc +static size_t GetPaintBufSize(const gfx::Rect& rect) { + // TODO(darin): protect against overflow + return 4 * rect.width() * rect.height(); +} + void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect, const gfx::Rect& clip_rect, bool visible) { - plugin_rect_ = window_rect; - - if (windowless_) { - IPC::Message* msg = new PluginMsg_UpdateGeometry( - instance_id_, window_rect, clip_rect, visible); - msg->set_unblock(true); - Send(msg); - } else { + if (!windowless_) { deferred_clip_rect_ = clip_rect; visible_ = visible; send_deferred_update_geometry_ = true; + return; } + + HANDLE windowless_buffer_handle = NULL; + bool moved = plugin_rect_.x() != window_rect.x() || + plugin_rect_.y() != window_rect.y(); + plugin_rect_ = window_rect; + if (!windowless_canvas_.get() || + (window_rect.width() != windowless_canvas_->getDevice()->width() || + window_rect.height() != windowless_canvas_->getDevice()->height())) { + // Create a shared memory section that the plugin paints asynchronously. + windowless_canvas_.reset(); + if (!windowless_buffer_lock_) + windowless_buffer_lock_.Set(CreateMutex(NULL, FALSE, NULL)); + windowless_buffer_.reset(new SharedMemory()); + size_t size = GetPaintBufSize(plugin_rect_); + if (!windowless_buffer_->Create(L"", false, true, size)) { + DCHECK(false); + windowless_buffer_.reset(); + return; + } + + windowless_canvas_.reset(new gfx::PlatformCanvasWin( + plugin_rect_.width(), plugin_rect_.height(), false, + windowless_buffer_->handle())); + windowless_canvas_->translate(static_cast<SkScalar>(-plugin_rect_.x()), + static_cast<SkScalar>(-plugin_rect_.y())); + windowless_canvas_->getTopPlatformDevice().accessBitmap(true). + eraseARGB(0, 0, 0, 0); + windowless_buffer_handle = windowless_buffer_->handle(); + } else if (moved) { + windowless_canvas_->resetMatrix(); + windowless_canvas_->translate(static_cast<SkScalar>(-plugin_rect_.x()), + static_cast<SkScalar>(-plugin_rect_.y())); + } + + IPC::Message* msg = new PluginMsg_UpdateGeometry( + instance_id_, window_rect, clip_rect, visible, windowless_buffer_handle, + windowless_buffer_lock_); + msg->set_unblock(true); + Send(msg); } void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) { @@ -354,100 +390,40 @@ void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) { return; } - // Can't duplicate an HDC handle, so get all the parameters we need in - // order to recreate the same HDC in the plugin process. - PluginMsg_Paint_Params params; - HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); - if (bitmap == NULL) { - NOTREACHED(); + // No paint events for windowed plugins. However, if it is the first paint + // we don't know yet whether the plugin is windowless or not, so we have to + // send the event. + if (!windowless_ && !first_paint_) { + // TODO(maruel): That's not true for printing and thumbnail capture. + // We shall use PrintWindow() to draw the window. return; } + first_paint_ = false; - DIBSECTION dibsection = { 0 }; - int result = GetObject(bitmap, sizeof(dibsection), &dibsection); - if (!result) { - NOTREACHED(); + // We got a paint before the plugin's coordinates, so there's no buffer to + // copy from. + if (!windowless_buffer_.get()) return; - } - win_util::ScopedHRGN hrgn(CreateRectRgn(0, 0, 0, 0)); - result = GetClipRgn(hdc, hrgn); - if (result == -1) { - NOTREACHED(); - return; - } + // Limit the damaged rectangle to whatever is contained inside the plugin + // rectangle, as that's the rectangle that we'll bitblt to the hdc. + gfx::Rect rect = damaged_rect.Intersect(plugin_rect_); - params.size.SetSize(dibsection.dsBmih.biWidth, dibsection.dsBmih.biHeight); - if (result == 0) { - // No clipping region. - params.clip_rect.set_width(params.size.width()); - params.clip_rect.set_height(params.size.height()); - } else { - RECT clip_rect; - result = GetRgnBox(hrgn, &clip_rect); - DCHECK_NE(result, 0); - params.clip_rect = clip_rect; - } + DWORD wait_result = WaitForSingleObject(windowless_buffer_lock_, INFINITE); + DCHECK(wait_result == WAIT_OBJECT_0); - if (!GetWorldTransform(hdc, ¶ms.xf)) { - NOTREACHED(); - return; - } - - params.damaged_rect = damaged_rect; - params.shared_memory = dibsection.dshSection; - - // Normal painting code path. - if (dibsection.dshSection) { - // No paint events for windowed plugins. However, if it is the first paint - // we don't know yet whether the plugin is windowless or not, so we have to - // send the event. - if (!windowless_ && !first_paint_) { - // TODO(maruel): That's not true for printing and thumbnail capture. - // We shall use PrintWindow() to draw the window. - return; - } - first_paint_ = false; - - DCHECK(params.size.width()); - DCHECK(params.size.height()); - Send(new PluginMsg_Paint(instance_id_, params)); - return; - } - - params.size.SetSize(damaged_rect.width(), damaged_rect.height()); - // Pass the window size instead. - if (!windowless_) - params.damaged_rect = plugin_rect_; - - // When the thumbnail is painted or during printing, a shared memory handle - // isn't given to CreateDIBSection so we don't get one now. - size_t bytes = 0; - SharedMemoryHandle emf_buffer = NULL; - PluginMsg_PaintIntoSharedMemory* msg = - new PluginMsg_PaintIntoSharedMemory(instance_id_, params, &emf_buffer, - &bytes); - if (!Send(msg)) - return; - - if (!emf_buffer) { - NOTREACHED(); - return; - } + BLENDFUNCTION m_bf; + m_bf.BlendOp = AC_SRC_OVER; + m_bf.BlendFlags = 0; + m_bf.SourceConstantAlpha = 255; + m_bf.AlphaFormat = AC_SRC_ALPHA; - // memory's destructor will automatically close emf_buffer. - SharedMemory memory(emf_buffer, true); - if (!memory.Map(bytes)) { - NOTREACHED(); - return; - } + HDC new_hdc = windowless_canvas_->getTopPlatformDevice().getBitmapDC(); + AlphaBlend(hdc, rect.x(), rect.y(), rect.width(), rect.height(), + new_hdc, rect.x(), rect.y(), rect.width(), rect.height(), m_bf); - gfx::Emf emf; - if (!emf.CreateFromData(memory.memory(), bytes)) { - NOTREACHED(); - return; - } - emf.Playback(hdc, NULL); + BOOL result = ReleaseMutex(windowless_buffer_lock_); + DCHECK(result); } void WebPluginDelegateProxy::Print(HDC hdc) { @@ -523,7 +499,8 @@ void WebPluginDelegateProxy::OnSetWindow( if (plugin_) plugin_->SetWindow(window, modal_loop_pump_messages_event); - modal_loop_pump_messages_event_ = modal_loop_pump_messages_event; + DCHECK(modal_loop_pump_messages_event_ == NULL); + modal_loop_pump_messages_event_.Set(modal_loop_pump_messages_event); } void WebPluginDelegateProxy::OnCancelResource(int id) { diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index 5ce612a..c457f90 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -10,6 +10,7 @@ #include "base/gfx/rect.h" #include "base/ref_counted.h" +#include "base/scoped_handle.h" #include "chrome/common/ipc_message.h" #include "chrome/common/plugin_messages.h" #include "chrome/plugin/npobject_stub.h" @@ -21,6 +22,10 @@ class GURL; struct PluginHostMsg_RouteToFrame_Params; class RenderView; class SkBitmap; +namespace gfx { +class PlatformCanvasWin; +} + // An implementation of WebPluginDelegate that proxies all calls to // the plugin process. @@ -148,11 +153,17 @@ class WebPluginDelegateProxy : public WebPluginDelegate, // Event passed in by the plugin process and is used to decide if // messages need to be pumped in the NPP_HandleEvent sync call. - HANDLE modal_loop_pump_messages_event_; + ScopedHandle modal_loop_pump_messages_event_; // Bitmap for crashed plugin SkBitmap* sad_plugin_; + // Used for desynchronized windowless painting. See the comment in + // webplugin_proxy.h for information about how this works. + scoped_ptr<SharedMemory> windowless_buffer_; + scoped_ptr<gfx::PlatformCanvasWin> windowless_canvas_; + ScopedHandle windowless_buffer_lock_; + DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateProxy); }; |