diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-01 00:38:11 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-01 00:38:11 +0000 |
commit | c20b454f6a44ff119c0683a8228b292ba88d6044 (patch) | |
tree | fa3e0721d2c084d14eb067cdc4b7c7a8bdc7ae17 /chrome/plugin | |
parent | 3deb65daf866945e0a5e211897e0d5382f3c272b (diff) | |
download | chromium_src-c20b454f6a44ff119c0683a8228b292ba88d6044.zip chromium_src-c20b454f6a44ff119c0683a8228b292ba88d6044.tar.gz chromium_src-c20b454f6a44ff119c0683a8228b292ba88d6044.tar.bz2 |
Fix painting problem with transparent plugins because plugins were ignoring the alpha channel sometimes.
This change introduces another buffer which holds the background image for transparent plugins. Before
painting these plugins, their backing store is overwritten with the background data.
This change also uses an ACK from the renderer to figure out when it can paint, similar to how the
renderer does it, which gives us throttling and also doesn't lead to painting when the tab is hidden.
Review URL: http://codereview.chromium.org/5040
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2744 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/plugin')
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.cc | 14 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.h | 7 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.cc | 115 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.h | 41 |
4 files changed, 113 insertions, 64 deletions
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index e2129f2..84bc069 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -80,6 +80,8 @@ 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_DidPaint, OnDidPaint) IPC_MESSAGE_HANDLER(PluginMsg_Print, OnPrint) IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject, OnGetPluginScriptableObject) @@ -199,6 +201,14 @@ void WebPluginDelegateStub::OnHandleEvent(const NPEvent& event, *handled = delegate_->HandleEvent(const_cast<NPEvent*>(&event), cursor); } +void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) { + webplugin_->Paint(damaged_rect); +} + +void WebPluginDelegateStub::OnDidPaint() { + webplugin_->DidPaint(); +} + void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) { gfx::Emf emf; if (!emf.CreateDc(NULL, NULL)) { @@ -229,9 +239,9 @@ void WebPluginDelegateStub::OnUpdateGeometry( const gfx::Rect& clip_rect, bool visible, const SharedMemoryHandle& windowless_buffer, - const SharedMemoryLock& lock) { + const SharedMemoryHandle& background_buffer) { webplugin_->UpdateGeometry( - window_rect, clip_rect, visible, windowless_buffer, lock); + window_rect, clip_rect, visible, windowless_buffer, background_buffer); } void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id, diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index cb242b4..78684bf 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -57,11 +57,16 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, void OnSetFocus(); void OnHandleEvent(const NPEvent& event, bool* handled, WebCursor* cursor); + + void OnPaint(const gfx::Rect& damaged_rect); + void OnDidPaint(); + void OnPrint(PluginMsg_PrintResponse_Params* params); + void OnUpdateGeometry(const gfx::Rect& window_rect, const gfx::Rect& clip_rect, bool visible, const SharedMemoryHandle& windowless_buffer, - const SharedMemoryLock& lock); + const SharedMemoryHandle& background_buffer); 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 cc091a2..2abafb0 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -18,9 +18,6 @@ #include "chrome/plugin/npobject_util.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() { return *Singleton<ContextMap>::get(); @@ -36,7 +33,8 @@ WebPluginProxy::WebPluginProxy( cp_browsing_context_(0), window_npobject_(NULL), plugin_element_(NULL), - delegate_(delegate) { + delegate_(delegate), + waiting_for_paint_(false) { HANDLE event; BOOL result = DuplicateHandle(channel->renderer_handle(), @@ -81,14 +79,25 @@ void WebPluginProxy::CancelResource(int id) { } void WebPluginProxy::Invalidate() { - Send(new PluginHostMsg_Invalidate(route_id_)); + gfx::Rect rect(0, 0, delegate_->rect().width(), delegate_->rect().height()); + InvalidateRect(rect); } void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) { + // Ignore NPN_InvalidateRect calls with empty rects. + if (rect.IsEmpty()) + return; + damaged_rect_ = damaged_rect_.Union(rect); - if (!paint_timer_.IsRunning()) { - paint_timer_.Start(TimeDelta::FromMilliseconds(1000 / kWindowlessPaintFPS), - this, &WebPluginProxy::OnPaintTimerFired); + // Only send a single InvalidateRect message at a time. From DidPaint we + // will dispatch an additional InvalidateRect message if necessary. + if (!waiting_for_paint_) { + waiting_for_paint_ = true; + // Paint to the plugin bitmap and let the renderer know so it can update + // its backing store. + Paint(damaged_rect_); + Send(new PluginHostMsg_InvalidateRect(route_id_, damaged_rect_)); + damaged_rect_ = gfx::Rect(); } } @@ -190,6 +199,14 @@ WebPluginResourceClient* WebPluginProxy::GetResourceClient(int id) { return iterator->second; } +void WebPluginProxy::DidPaint() { + // 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_); +} + void WebPluginProxy::OnResourceCreated(int resource_id, HANDLE cookie) { WebPluginResourceClient* resource_client = reinterpret_cast<WebPluginResourceClient*>(cookie); @@ -233,33 +250,26 @@ void WebPluginProxy::HandleURLRequest(const char *method, Send(new PluginHostMsg_URLRequest(route_id_, params)); } -void WebPluginProxy::OnPaintTimerFired() { +void WebPluginProxy::Paint(const gfx::Rect& rect) { 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))); + gfx::Rect offset_rect = rect; + offset_rect.Offset(delegate_->rect().x(), delegate_->rect().y()); + if (!background_hdc_) { + FillRect(windowless_hdc_, &offset_rect.ToRECT(), + static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); + } else { + BitBlt(windowless_hdc_, offset_rect.x(), offset_rect.y(), + offset_rect.width(), offset_rect.height(), background_hdc_, + rect.x(), rect.y(), SRCCOPY); + } // 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(); + delegate_->Paint(windowless_hdc_, offset_rect); } void WebPluginProxy::UpdateGeometry( @@ -267,33 +277,45 @@ void WebPluginProxy::UpdateGeometry( const gfx::Rect& clip_rect, bool visible, const SharedMemoryHandle& windowless_buffer, - const SharedMemoryLock& lock) { + const SharedMemoryHandle& background_buffer) { + gfx::Rect old = delegate_->rect(); 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); + SetWindowlessBuffer(windowless_buffer, background_buffer); } else if (moved) { // The plugin moved, so update our world transform. UpdateTransform(); } } -void WebPluginProxy::SetWindowlessBuffer(const SharedMemoryHandle& handle, - const SharedMemoryLock& lock) { +void WebPluginProxy::SetWindowlessBuffer( + const SharedMemoryHandle& windowless_buffer, + const SharedMemoryHandle& background_buffer) { // 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); + ConvertBuffer(windowless_buffer, + &windowless_shared_section_, + &windowless_bitmap_, + &windowless_hdc_); + if (background_buffer) { + ConvertBuffer(background_buffer, + &background_shared_section_, + &background_bitmap_, + &background_hdc_); } + UpdateTransform(); +} - if (windowless_shared_section_ == NULL || windowless_buffer_lock_ == NULL) { +void WebPluginProxy::ConvertBuffer(const SharedMemoryHandle& buffer, + ScopedHandle* shared_section, + ScopedBitmap* bitmap, + ScopedHDC* hdc) { + shared_section->Set(win_util::GetSectionFromProcess( + buffer, channel_->renderer_handle(), false)); + if (shared_section->Get() == NULL) { NOTREACHED(); return; } @@ -304,24 +326,23 @@ void WebPluginProxy::SetWindowlessBuffer(const SharedMemoryHandle& handle, gfx::CreateBitmapHeader(delegate_->rect().width(), delegate_->rect().height(), &bitmap_header); - windowless_bitmap_.Set(CreateDIBSection( + bitmap->Set(CreateDIBSection( screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header), - DIB_RGB_COLORS, &data, windowless_shared_section_, 0)); + DIB_RGB_COLORS, &data, shared_section->Get(), 0)); ReleaseDC(NULL, screen_dc); - if (windowless_bitmap_ == NULL) { + if (bitmap->Get() == NULL) { NOTREACHED(); return; } - windowless_hdc_.Set(CreateCompatibleDC(NULL)); - if (windowless_hdc_ == NULL) { + hdc->Set(CreateCompatibleDC(NULL)); + if (hdc->Get() == NULL) { NOTREACHED(); return; } - gfx::PlatformDeviceWin::InitializeDC(windowless_hdc_); - SelectObject(windowless_hdc_, windowless_bitmap_); - UpdateTransform(); + gfx::PlatformDeviceWin::InitializeDC(hdc->Get()); + SelectObject(hdc->Get(), bitmap->Get()); } void WebPluginProxy::UpdateTransform() { diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 9e1a051..ab50933 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -62,6 +62,12 @@ class WebPluginProxy : public WebPlugin { // object with that id exists. WebPluginResourceClient* GetResourceClient(int id); + // For windowless plugins, paints the given rectangle into the local buffer. + void Paint(const gfx::Rect& rect); + + // Callback from the renderer to let us know that a paint occurred. + void DidPaint(); + // Notification received on a plugin issued resource request // creation. void OnResourceCreated(int resource_id, HANDLE cookie); @@ -77,7 +83,7 @@ class WebPluginProxy : public WebPlugin { const gfx::Rect& clip_rect, bool visible, const SharedMemoryHandle& windowless_buffer, - const SharedMemoryLock& lock); + const SharedMemoryHandle& background_buffer); void CancelDocumentLoad(); @@ -90,12 +96,16 @@ class WebPluginProxy : public WebPlugin { 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); + void SetWindowlessBuffer(const SharedMemoryHandle& windowless_buffer, + const SharedMemoryHandle& background_buffer); + + // Converts a shared memory section handle from the renderer process into a + // bitmap and hdc that are mapped to this process. + void ConvertBuffer(const SharedMemoryHandle& buffer, + ScopedHandle* shared_section, + ScopedBitmap* bitmap, + ScopedHDC* hdc); // Called when a plugin's origin moves, so that we can update the world // transform of the local HDC. @@ -109,20 +119,23 @@ class WebPluginProxy : public WebPlugin { NPObject* window_npobject_; NPObject* plugin_element_; WebPluginDelegateImpl* delegate_; + gfx::Rect damaged_rect_; + bool waiting_for_paint_; 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_; + // Variables used for desynchronized windowless plugin painting. See note in + // webplugin_delegate_proxy.h for how this works. + + // These hold the bitmap where the plugin draws. ScopedHandle windowless_shared_section_; ScopedBitmap windowless_bitmap_; ScopedHDC windowless_hdc_; - ScopedHandle windowless_buffer_lock_; + + // These hold the bitmap of the background image. + ScopedHandle background_shared_section_; + ScopedBitmap background_bitmap_; + ScopedHDC background_hdc_; }; #endif // CHROME_PLUGIN_PLUGIN_WEBPLUGIN_PROXY_H__ |