diff options
Diffstat (limited to 'chrome')
-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 |
7 files changed, 300 insertions, 140 deletions
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); }; |