summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/common/plugin_messages_internal.h16
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc14
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h7
-rw-r--r--chrome/plugin/webplugin_proxy.cc115
-rw-r--r--chrome/plugin/webplugin_proxy.h41
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc211
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h36
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);
};