diff options
-rw-r--r-- | base/scoped_handle.h | 8 | ||||
-rw-r--r-- | chrome/common/plugin_messages_internal.h | 16 | ||||
-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 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 211 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.h | 36 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 156 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_host.h | 22 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.cc | 1 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.h | 9 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.cc | 5 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 1 | ||||
-rw-r--r-- | webkit/glue/webplugin_delegate.h | 4 |
15 files changed, 343 insertions, 303 deletions
diff --git a/base/scoped_handle.h b/base/scoped_handle.h index 5f12af1..654d6fd 100644 --- a/base/scoped_handle.h +++ b/base/scoped_handle.h @@ -112,6 +112,10 @@ class ScopedHDC { Close(); } + HDC Get() { + return hdc_; + } + void Set(HDC h) { Close(); hdc_ = h; @@ -139,6 +143,10 @@ class ScopedBitmap { Close(); } + HBITMAP Get() { + return hbitmap_; + } + void Set(HBITMAP h) { Close(); hbitmap_ = h; diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index 36cb1cd..146cd9c 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -102,6 +102,14 @@ IPC_BEGIN_MESSAGES(Plugin, 5) PluginMsg_Init_Params, bool /* result */) + // Used to synchronously request a paint for windowless plugins. + IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_Paint, + gfx::Rect /* damaged_rect */) + + // Sent by the renderer after it paints from its backing store so that the + // plugin knows it can send more invalidates. + IPC_MESSAGE_ROUTED0(PluginMsg_DidPaint) + IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_Print, PluginMsg_PrintResponse_Params /* params */) @@ -112,12 +120,16 @@ IPC_BEGIN_MESSAGES(Plugin, 5) IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_DidFinishLoadWithReason, int /* reason */) + // Updates the plugin location. For windowless plugins, windowless_buffer + // contains a buffer that the plugin draws into. background_buffer is used + // for transparent windowless plugins, and holds the background of the plugin + // rectangle. IPC_MESSAGE_ROUTED5(PluginMsg_UpdateGeometry, gfx::Rect /* window_rect */, gfx::Rect /* clip_rect */, bool /* visible */, SharedMemoryHandle /* windowless_buffer */, - SharedMemoryLock /* windowless_buffer_lock */) + SharedMemoryHandle /* background_buffer */) IPC_SYNC_MESSAGE_ROUTED0_0(PluginMsg_SetFocus) @@ -197,8 +209,6 @@ IPC_BEGIN_MESSAGES(PluginHost, 6) IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_CancelResource, int /* id */) - IPC_MESSAGE_ROUTED0(PluginHostMsg_Invalidate) - IPC_MESSAGE_ROUTED1(PluginHostMsg_InvalidateRect, gfx::Rect /* rect */) 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__ diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 5670bf7..1d6e8d21 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -143,7 +143,9 @@ WebPluginDelegateProxy::WebPluginDelegateProxy(const std::string& mime_type, send_deferred_update_geometry_(false), visible_(false), sad_plugin_(NULL), - window_script_object_(NULL) { + window_script_object_(NULL), + transparent_(false), + invalidate_pending_(false) { } WebPluginDelegateProxy::~WebPluginDelegateProxy() { @@ -222,6 +224,11 @@ bool WebPluginDelegateProxy::Initialize(const GURL& url, char** argn, for (int i = 0; i < argc; ++i) { params.arg_names.push_back(argn[i]); params.arg_values.push_back(argv[i]); + + if (LowerCaseEqualsASCII(params.arg_names.back(), "wmode") && + LowerCaseEqualsASCII(params.arg_values.back(), "transparent")) { + transparent_ = true; + } } params.load_manually = load_manually; params.modal_dialog_event = render_view_->modal_dialog_event(); @@ -299,7 +306,6 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy, msg) IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow, OnSetWindow) IPC_MESSAGE_HANDLER(PluginHostMsg_CancelResource, OnCancelResource) - IPC_MESSAGE_HANDLER(PluginHostMsg_Invalidate, OnInvalidate) IPC_MESSAGE_HANDLER(PluginHostMsg_InvalidateRect, OnInvalidateRect) IPC_MESSAGE_HANDLER(PluginHostMsg_GetWindowScriptNPObject, OnGetWindowScriptNPObject) @@ -322,21 +328,14 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { } void WebPluginDelegateProxy::OnChannelError() { - OnInvalidate(); + if (plugin_) + plugin_->Invalidate(); 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) { - bool moved = plugin_rect_.x() != window_rect.x() || - plugin_rect_.y() != window_rect.y(); plugin_rect_ = window_rect; if (!windowless_) { deferred_clip_rect_ = clip_rect; @@ -345,43 +344,65 @@ void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect, return; } - HANDLE windowless_buffer_handle = NULL; - 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; + HANDLE transport_store_handle = NULL; + HANDLE background_store_handle = NULL; + if (!backing_store_canvas_.get() || + (window_rect.width() != backing_store_canvas_->getDevice()->width() || + window_rect.height() != backing_store_canvas_->getDevice()->height())) { + // Create a shared memory section that the plugin paints into + // asynchronously. + ResetWindowlessBitmaps(); + if (!window_rect.IsEmpty()) { + if (!CreateBitmap(&backing_store_, &backing_store_canvas_) || + !CreateBitmap(&transport_store_, &transport_store_canvas_) || + (transparent_ && + !CreateBitmap(&background_store_, &background_store_canvas_))) { + DCHECK(false); + ResetWindowlessBitmaps(); + return; + } + + transport_store_handle = transport_store_->handle(); + if (background_store_.get()) + background_store_handle = background_store_->handle(); } - - 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_); + instance_id_, window_rect, clip_rect, visible, transport_store_handle, + background_store_handle); msg->set_unblock(true); Send(msg); } +// 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::ResetWindowlessBitmaps() { + backing_store_.reset(); + transport_store_.reset(); + backing_store_canvas_.reset(); + transport_store_canvas_.reset(); + background_store_.reset(); + background_store_canvas_.release(); +} + +bool WebPluginDelegateProxy::CreateBitmap( + scoped_ptr<SharedMemory>* memory, + scoped_ptr<gfx::PlatformCanvasWin>* canvas) { + size_t size = GetPaintBufSize(plugin_rect_); + memory->reset(new SharedMemory()); + if (!(*memory)->Create(L"", false, true, size)) + return false; + + canvas->reset(new gfx::PlatformCanvasWin( + plugin_rect_.width(), plugin_rect_.height(), true, (*memory)->handle())); + return true; +} + void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) { // If the plugin is no longer connected (channel crashed) draw a crashed // plugin bitmap @@ -398,32 +419,84 @@ void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) { // We shall use PrintWindow() to draw the window. return; } - first_paint_ = false; // We got a paint before the plugin's coordinates, so there's no buffer to // copy from. - if (!windowless_buffer_.get()) + if (!backing_store_canvas_.get()) 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_); - DWORD wait_result = WaitForSingleObject(windowless_buffer_lock_, INFINITE); - DCHECK(wait_result == WAIT_OBJECT_0); + bool background_changed = false; + if (background_store_canvas_.get() && BackgroundChanged(hdc, rect)) { + background_changed = true; + HDC background_hdc = + background_store_canvas_->getTopPlatformDevice().getBitmapDC(); + BitBlt(background_hdc, rect.x()-plugin_rect_.x(), rect.y()-plugin_rect_.y(), + rect.width(), rect.height(), hdc, rect.x(), rect.y(), SRCCOPY); + } + + if (first_paint_ || background_changed) { + gfx::Rect offset_rect = rect; + offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y()); + Send(new PluginMsg_Paint(instance_id_, offset_rect)); + CopyFromTransportToBacking(offset_rect); + } + + first_paint_ = false; + HDC backing_hdc = backing_store_canvas_->getTopPlatformDevice().getBitmapDC(); + BitBlt(hdc, rect.x(), rect.y(), rect.width(), rect.height(), backing_hdc, + rect.x()-plugin_rect_.x(), rect.y()-plugin_rect_.y(), SRCCOPY); + + if (invalidate_pending_) { + // Only send the PaintAck message if this paint is in response to an + // invalidate from the plugin, since this message acts as an access token + // to ensure only one process is using the transport dib at a time. + invalidate_pending_ = false; + Send(new PluginMsg_DidPaint(instance_id_)); + } +} + +bool WebPluginDelegateProxy::BackgroundChanged( + HDC hdc, + const gfx::Rect& rect) { + HBITMAP hbitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + if (hbitmap == NULL) { + NOTREACHED(); + return true; + } + + BITMAP bitmap = { 0 }; + int result = GetObject(hbitmap, sizeof(bitmap), &bitmap); + if (!result) { + NOTREACHED(); + return true; + } - BLENDFUNCTION m_bf; - m_bf.BlendOp = AC_SRC_OVER; - m_bf.BlendFlags = 0; - m_bf.SourceConstantAlpha = 255; - m_bf.AlphaFormat = AC_SRC_ALPHA; + XFORM xf; + if (!GetWorldTransform(hdc, &xf)) { + NOTREACHED(); + return true; + } - 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); + int row_byte_size = rect.width() * (bitmap.bmBitsPixel / 8); + for (int y = rect.y(); y < rect.bottom(); y++) { + char* hdc_row_start = static_cast<char*>(bitmap.bmBits) + + (y + static_cast<int>(xf.eDy)) * bitmap.bmWidthBytes + + (rect.x() + static_cast<int>(xf.eDx)) * (bitmap.bmBitsPixel / 8); + + // getAddr32 doesn't use the translation units, so we have to subtract + // the plugin origin from the coordinates. + uint32_t* canvas_row_start = + background_store_canvas_->getDevice()->accessBitmap(true).getAddr32( + rect.x() - plugin_rect_.x(), y - plugin_rect_.y()); + if (memcmp(hdc_row_start, canvas_row_start, row_byte_size) != 0) + return true; + } - BOOL result = ReleaseMutex(windowless_buffer_lock_); - DCHECK(result); + return false; } void WebPluginDelegateProxy::Print(HDC hdc) { @@ -488,11 +561,6 @@ int WebPluginDelegateProxy::GetProcessId() { return channel_host_->peer_pid(); } -HWND WebPluginDelegateProxy::GetWindowHandle() { - NOTREACHED() << "GetWindowHandle can't be called on the proxy."; - return NULL; -} - void WebPluginDelegateProxy::OnSetWindow( HWND window, HANDLE modal_loop_pump_messages_event) { windowless_ = window == NULL; @@ -508,14 +576,13 @@ void WebPluginDelegateProxy::OnCancelResource(int id) { plugin_->CancelResource(id); } -void WebPluginDelegateProxy::OnInvalidate() { - if (plugin_) - plugin_->Invalidate(); -} - void WebPluginDelegateProxy::OnInvalidateRect(const gfx::Rect& rect) { - if (plugin_) - plugin_->InvalidateRect(rect); + if (!plugin_) + return; + + invalidate_pending_ = true; + CopyFromTransportToBacking(rect); + plugin_->InvalidateRect(rect); } void WebPluginDelegateProxy::OnGetWindowScriptNPObject( @@ -616,6 +683,18 @@ void WebPluginDelegateProxy::PaintSadPlugin(HDC hdc, const gfx::Rect& rect) { return; } +void WebPluginDelegateProxy::CopyFromTransportToBacking(const gfx::Rect& rect) { + if (!backing_store_canvas_.get()) + return; + + // Copy the damaged rect from the transport bitmap to the backing store. + HDC backing = backing_store_canvas_->getTopPlatformDevice().getBitmapDC(); + HDC transport = transport_store_canvas_->getTopPlatformDevice().getBitmapDC(); + + BitBlt(backing, rect.x(), rect.y(), rect.width(), rect.height(), + transport, rect.x(), rect.y(), SRCCOPY); +} + void WebPluginDelegateProxy::OnHandleURLRequest( const PluginHostMsg_URLRequest_Params& params) { const char* data = NULL; diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index c457f90..7a7da77 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -60,7 +60,6 @@ class WebPluginDelegateProxy : public WebPluginDelegate, virtual void SetFocus(); virtual bool HandleEvent(NPEvent* event, WebCursor* cursor); virtual int GetProcessId(); - virtual HWND GetWindowHandle(); // IPC::Channel::Listener implementation: virtual void OnMessageReceived(const IPC::Message& msg); @@ -110,7 +109,6 @@ class WebPluginDelegateProxy : public WebPluginDelegate, bool* result); void OnHandleURLRequest(const PluginHostMsg_URLRequest_Params& params); void OnCancelResource(int id); - void OnInvalidate(); void OnInvalidateRect(const gfx::Rect& rect); void OnGetWindowScriptNPObject(int route_id, bool* success, void** npobject_ptr); void OnGetPluginElement(int route_id, bool* success, void** npobject_ptr); @@ -133,6 +131,20 @@ class WebPluginDelegateProxy : public WebPluginDelegate, // Draw a graphic indicating a crashed plugin. void PaintSadPlugin(HDC hdc, const gfx::Rect& rect); + // Returns true if the given rectangle is different in the hdc and the + // current background bitmap. + bool BackgroundChanged(HDC hdc, const gfx::Rect& rect); + + // Copies the given rectangle from the transport bitmap to the backing store. + void CopyFromTransportToBacking(const gfx::Rect& rect); + + // Clears the shared memory section and canvases used for windowless plugins. + void ResetWindowlessBitmaps(); + + // Creates a shared memory section and canvas. + bool CreateBitmap(scoped_ptr<SharedMemory>* memory, + scoped_ptr<gfx::PlatformCanvasWin>* canvas); + RenderView* render_view_; WebPlugin* plugin_; bool windowless_; @@ -158,11 +170,21 @@ class WebPluginDelegateProxy : public WebPluginDelegate, // 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_; + // True if we got an invalidate from the plugin and are waiting for a paint. + bool invalidate_pending_; + + // Used to desynchronize windowless painting. When WebKit paints, we bitblt + // from our backing store of what the plugin rectangle looks like. The + // plugin paints into the transport store, and we copy that to our backing + // store when we get an invalidate from it. The background bitmap is used + // for transparent plugins, as they need the backgroud data during painting. + bool transparent_; + scoped_ptr<SharedMemory> backing_store_; + scoped_ptr<gfx::PlatformCanvasWin> backing_store_canvas_; + scoped_ptr<SharedMemory> transport_store_; + scoped_ptr<gfx::PlatformCanvasWin> transport_store_canvas_; + scoped_ptr<SharedMemory> background_store_; + scoped_ptr<gfx::PlatformCanvasWin> background_store_canvas_; DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateProxy); }; diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index 7993048..b793032 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -5,7 +5,6 @@ #include "webkit/glue/plugins/plugin_host.h" #include "base/logging.h" -#include "base/message_loop.h" #include "base/string_util.h" #include "webkit/default_plugin/default_plugin_shared.h" #include "webkit/glue/glue_util.h" @@ -17,29 +16,12 @@ #include "webkit/glue/plugins/plugin_stream_url.h" #include "third_party/npapi/bindings/npruntime.h" -extern "C" { - -// FindInstance() -// Finds a PluginInstance from an NPP. -// The caller must take a reference if needed. -NPAPI::PluginInstance* FindInstance(NPP id) { - if (id == NULL) { - NOTREACHED(); - return NULL; - } - - return (NPAPI::PluginInstance *)id->ndata; -} namespace NPAPI { scoped_refptr<PluginHost> PluginHost::singleton_; -static const int kFlashMessageThrottleDelayMs = 10; - -PluginHost::PluginHost() -#pragma warning(suppress: 4355) // can use this - : throttle_factory_(this) { +PluginHost::PluginHost() { InitializeHostFuncs(); } @@ -151,78 +133,6 @@ void PluginHost::PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides) { host_funcs_.enumerate = overrides->enumerate; } -void PluginHost::InvalidateRect(NPP id, NPRect* invalidRect) { - if (!invalidRect) { - NOTREACHED(); - return; - } - - // Invalidates specified drawing area prior to repainting or refreshing a - // windowless plugin - - // Before a windowless plugin can refresh part of its drawing area, it must - // first invalidate it. This function causes the NPP_HandleEvent method to - // pass an update event or a paint message to the plug-in. After calling - // this method, the plug-in recieves a paint message asynchronously. - - // The browser redraws invalid areas of the document and any windowless - // plug-ins at regularly timed intervals. To force a paint message, the - // plug-in can call NPN_ForceRedraw after calling this method. - - scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id); - DCHECK(plugin.get() != NULL); - - if (plugin.get() && plugin->webplugin()) { - if (!plugin->windowless()) { - RECT rect = {0}; - rect.left = invalidRect->left; - rect.right = invalidRect->right; - rect.top = invalidRect->top; - rect.bottom = invalidRect->bottom; - ::InvalidateRect(plugin->window_handle(), &rect, FALSE); - return; - } - - if (plugin->throttle_invalidate()) { - // We need to track plugin invalidates on a per instance basis. - ThrottledInvalidates plugin_instance_invalidates; - InstanceThrottledInvalidatesMap::iterator invalidate_index = - instance_throttled_invalidates_.find(id); - if (invalidate_index != instance_throttled_invalidates_.end()) { - plugin_instance_invalidates = (*invalidate_index).second; - } - - bool throttle_active = - (plugin_instance_invalidates.throttled_invalidates.size() > 0); - - gfx::Rect rect(invalidRect->left, - invalidRect->top, - invalidRect->right - invalidRect->left, - invalidRect->bottom - invalidRect->top); - - plugin_instance_invalidates.throttled_invalidates.push_back(rect); - - if (!throttle_active) { - // We hold a reference to the plugin instance to avoid race conditions - // due to the instance being released before the OnInvalidateRect - // function is invoked. - plugin->AddRef(); - MessageLoop::current()->PostDelayedTask(FROM_HERE, - throttle_factory_.NewRunnableMethod(&PluginHost::OnInvalidateRect, - id, plugin.get()), - kFlashMessageThrottleDelayMs); - } - instance_throttled_invalidates_[id] = plugin_instance_invalidates; - } else { - gfx::Rect rect(invalidRect->left, - invalidRect->top, - invalidRect->right - invalidRect->left, - invalidRect->bottom - invalidRect->top); - plugin->webplugin()->InvalidateRect(rect); - } - } -} - bool PluginHost::SetPostData(const char *buf, uint32 length, std::vector<std::string>* names, @@ -325,39 +235,22 @@ bool PluginHost::SetPostData(const char *buf, return !err; } -void PluginHost::OnInvalidateRect(NPP id, PluginInstance* instance) { - if (!instance) { - NOTREACHED(); - return; - } - - InstanceThrottledInvalidatesMap::iterator invalidate_index = - instance_throttled_invalidates_.find(id); - if (invalidate_index == instance_throttled_invalidates_.end()) { - NOTREACHED(); - instance->Release(); - return; - } +} // namespace NPAPI - ThrottledInvalidates plugin_instance_invalidates = - (*invalidate_index).second; +extern "C" { - if (instance->webplugin()) { - for (unsigned int throttle_index = 0; - throttle_index < - plugin_instance_invalidates.throttled_invalidates.size(); - throttle_index++) { - instance->webplugin()->InvalidateRect( - plugin_instance_invalidates.throttled_invalidates[throttle_index]); - } +// FindInstance() +// Finds a PluginInstance from an NPP. +// The caller must take a reference if needed. +NPAPI::PluginInstance* FindInstance(NPP id) { + if (id == NULL) { + NOTREACHED(); + return NULL; } - instance->Release(); - instance_throttled_invalidates_.erase(invalidate_index); + return (NPAPI::PluginInstance *)id->ndata; } -} // namespace NPAPI - // Allocates memory from the host's memory space. void* NPN_MemAlloc(uint32 size) { scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton(); @@ -646,9 +539,30 @@ void NPN_Status(NPP id, const char* message) { } void NPN_InvalidateRect(NPP id, NPRect *invalidRect) { - scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton(); - if (host != NULL) { - host->InvalidateRect(id, invalidRect); + // Invalidates specified drawing area prior to repainting or refreshing a + // windowless plugin + + // Before a windowless plugin can refresh part of its drawing area, it must + // first invalidate it. This function causes the NPP_HandleEvent method to + // pass an update event or a paint message to the plug-in. After calling + // this method, the plug-in recieves a paint message asynchronously. + + // The browser redraws invalid areas of the document and any windowless + // plug-ins at regularly timed intervals. To force a paint message, the + // plug-in can call NPN_ForceRedraw after calling this method. + + scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id); + DCHECK(plugin.get() != NULL); + if (plugin.get() && plugin->webplugin()) { + if (invalidRect) { + gfx::Rect rect(invalidRect->left, + invalidRect->top, + invalidRect->right - invalidRect->left, + invalidRect->bottom - invalidRect->top); + plugin->webplugin()->InvalidateRect(rect); + } else { + plugin->webplugin()->Invalidate(); + } } } diff --git a/webkit/glue/plugins/plugin_host.h b/webkit/glue/plugins/plugin_host.h index 0a90f29..be12d5e 100644 --- a/webkit/glue/plugins/plugin_host.h +++ b/webkit/glue/plugins/plugin_host.h @@ -9,11 +9,8 @@ #include <string> #include <vector> -#include <map> #include "base/ref_counted.h" -#include "base/gfx/rect.h" -#include "base/task.h" #include "webkit/glue/plugins/nphostapi.h" #include "third_party/npapi/bindings/npapi.h" @@ -50,31 +47,12 @@ class PluginHost : public base::RefCounted<PluginHost> { void PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides); - // Handles invalidateRect requests for windowless plugins. - void InvalidateRect(NPP id, NPRect* invalidRect); - private: PluginHost(); void InitializeHostFuncs(); - // For certain plugins like flash we need to throttle invalidateRect - // requests as they are made at a high frequency. - void OnInvalidateRect(NPP id, PluginInstance* instance); - static scoped_refptr<PluginHost> singleton_; NPNetscapeFuncs host_funcs_; DISALLOW_EVIL_CONSTRUCTORS(PluginHost); - - // This structure keeps track of individual plugin instance invalidates. - struct ThrottledInvalidates { - std::vector<gfx::Rect> throttled_invalidates; - }; - - // We need to track throttled invalidate rects on a per plugin instance - // basis. - typedef std::map<NPP, ThrottledInvalidates> InstanceThrottledInvalidatesMap; - InstanceThrottledInvalidatesMap instance_throttled_invalidates_; - - ScopedRunnableMethodFactory<PluginHost> throttle_factory_; }; } // namespace NPAPI diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc index 0f81412..e6d5087 100644 --- a/webkit/glue/plugins/plugin_instance.cc +++ b/webkit/glue/plugins/plugin_instance.cc @@ -36,7 +36,6 @@ PluginInstance::PluginInstance(PluginLib *plugin, const std::string &mime_type) use_mozilla_user_agent_(false), message_loop_(MessageLoop::current()), load_manually_(false), - throttle_invalidate_(false), get_notify_data_(NULL), in_close_streams_(false) { npp_ = new NPP_t(); diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h index b6b1465..9765fef 100644 --- a/webkit/glue/plugins/plugin_instance.h +++ b/webkit/glue/plugins/plugin_instance.h @@ -142,11 +142,6 @@ class PluginInstance : public base::RefCounted<PluginInstance> { bool use_mozilla_user_agent() { return use_mozilla_user_agent_; } void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; } - bool throttle_invalidate() const { return throttle_invalidate_; } - void set_throttle_invalidate(bool throttle_invalidate) { - throttle_invalidate_ = throttle_invalidate; - } - // Helper that implements NPN_PluginThreadAsyncCall semantics void PluginThreadAsyncCall(void (*func)(void *), void *userData); @@ -248,10 +243,6 @@ class PluginInstance : public base::RefCounted<PluginInstance> { // webkit. if false indicates that the plugin should download the data. bool load_manually_; - // This flag indicates if the NPN_InvalidateRect calls made by the - // plugin need to be throttled. - bool throttle_invalidate_; - // Stack indicating if popups are to be enabled for the outgoing // NPN_GetURL/NPN_GetURLNotify calls. std::stack<bool> popups_enabled_stack_; diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc index 29c69a87..4e1c713 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl.cc @@ -144,7 +144,6 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( // Flash only requests windowless plugins if we return a Mozilla user // agent. instance_->set_use_mozilla_user_agent(); - instance_->set_throttle_invalidate(true); quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE; } else if (plugin_info.name.find(L"Windows Media Player") != std::wstring::npos) { @@ -304,10 +303,6 @@ int WebPluginDelegateImpl::GetProcessId() { return ::GetCurrentProcessId(); } -HWND WebPluginDelegateImpl::GetWindowHandle() { - return instance()->window_handle(); -} - void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url, const std::wstring& result, bool success, diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index dc7374a..fe4743c 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -51,7 +51,6 @@ class WebPluginDelegateImpl : public WebPluginDelegate { virtual NPObject* GetPluginScriptableObject(); virtual void DidFinishLoadWithReason(NPReason reason); virtual int GetProcessId(); - virtual HWND GetWindowHandle(); virtual void FlushGeometryUpdates() { } diff --git a/webkit/glue/webplugin_delegate.h b/webkit/glue/webplugin_delegate.h index 2300986..40419bd 100644 --- a/webkit/glue/webplugin_delegate.h +++ b/webkit/glue/webplugin_delegate.h @@ -73,10 +73,6 @@ class WebPluginDelegate { // Returns the process id of the process that is running the plugin. virtual int GetProcessId() = 0; - // Returns the window handle for this plugin if it's a windowed plugin, - // or NULL otherwise. - virtual gfx::ViewHandle GetWindowHandle() = 0; - virtual void FlushGeometryUpdates() = 0; // The result of the script execution is returned via this function. |