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/renderer/webplugin_delegate_proxy.cc | |
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/renderer/webplugin_delegate_proxy.cc')
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 211 |
1 files changed, 145 insertions, 66 deletions
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; |