summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-22 22:26:59 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-22 22:26:59 +0000
commit22c54fdc29f5c5952175ec4a5d0f954139f2fb75 (patch)
tree66ee6c27c6bf2eb75e3a4c3ec6cee7b7463aa4db /chrome
parent20ea3526d1b851a5594d7d05a472e83757df034d (diff)
downloadchromium_src-22c54fdc29f5c5952175ec4a5d0f954139f2fb75.zip
chromium_src-22c54fdc29f5c5952175ec4a5d0f954139f2fb75.tar.gz
chromium_src-22c54fdc29f5c5952175ec4a5d0f954139f2fb75.tar.bz2
Desynchronize windowless plugin painting. This greatly improves the painting
performance when there are multiple plugins, or when scrolling. Review URL: http://codereview.chromium.org/3133 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2459 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/common/plugin_messages.h45
-rw-r--r--chrome/common/plugin_messages_internal.h15
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc127
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h19
-rw-r--r--chrome/plugin/webplugin_proxy.cc145
-rw-r--r--chrome/plugin/webplugin_proxy.h42
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc179
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h13
8 files changed, 260 insertions, 325 deletions
diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h
index cbe0b31..6ebead6 100644
--- a/chrome/common/plugin_messages.h
+++ b/chrome/common/plugin_messages.h
@@ -58,18 +58,6 @@ struct PluginMsg_URLRequestReply_Params {
HANDLE stream;
};
-struct PluginMsg_Paint_Params {
- gfx::Size size;
- gfx::Rect clip_rect;
- gfx::Rect damaged_rect;
-
- // Bitmap's bits.
- HANDLE shared_memory;
-
- // Information about the world transform (see GetWorldTransform).
- XFORM xf;
-};
-
struct PluginMsg_PrintResponse_Params {
HANDLE shared_memory;
size_t size;
@@ -254,39 +242,6 @@ struct ParamTraits<PluginMsg_URLRequestReply_Params> {
};
template <>
-struct ParamTraits<PluginMsg_Paint_Params> {
- typedef PluginMsg_Paint_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.size);
- WriteParam(m, p.clip_rect);
- WriteParam(m, p.damaged_rect);
- WriteParam(m, p.shared_memory);
- WriteParam(m, p.xf);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- return
- ReadParam(m, iter, &r->size) &&
- ReadParam(m, iter, &r->clip_rect) &&
- ReadParam(m, iter, &r->damaged_rect) &&
- ReadParam(m, iter, &r->shared_memory) &&
- ReadParam(m, iter, &r->xf);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.size, l);
- l->append(L", ");
- LogParam(p.clip_rect, l);
- l->append(L", ");
- LogParam(p.damaged_rect, l);
- l->append(L", ");
- LogParam(p.shared_memory, l);
- l->append(L", ");
- LogParam(p.xf, l);
- l->append(L")");
- }
-};
-
-template <>
struct ParamTraits<PluginMsg_PrintResponse_Params> {
typedef PluginMsg_PrintResponse_Params param_type;
static void Write(Message* m, const param_type& p) {
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index b0df3b3..36cb1cd 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -102,18 +102,9 @@ IPC_BEGIN_MESSAGES(Plugin, 5)
PluginMsg_Init_Params,
bool /* result */)
- IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_Paint,
- PluginMsg_Paint_Params /* params */)
-
IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_Print,
PluginMsg_PrintResponse_Params /* params */)
- // Returns a shared memory handle to a EMF buffer.
- IPC_SYNC_MESSAGE_ROUTED1_2(PluginMsg_PaintIntoSharedMemory,
- PluginMsg_Paint_Params /* params */,
- SharedMemoryHandle /* emf_buffer */,
- size_t /* bytes */)
-
IPC_SYNC_MESSAGE_ROUTED0_2(PluginMsg_GetPluginScriptableObject,
int /* route_id */,
void* /* npobject_ptr */)
@@ -121,10 +112,12 @@ IPC_BEGIN_MESSAGES(Plugin, 5)
IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_DidFinishLoadWithReason,
int /* reason */)
- IPC_MESSAGE_ROUTED3(PluginMsg_UpdateGeometry,
+ IPC_MESSAGE_ROUTED5(PluginMsg_UpdateGeometry,
gfx::Rect /* window_rect */,
gfx::Rect /* clip_rect */,
- bool /* visible */)
+ bool /* visible */,
+ SharedMemoryHandle /* windowless_buffer */,
+ SharedMemoryLock /* windowless_buffer_lock */)
IPC_SYNC_MESSAGE_ROUTED0_0(PluginMsg_SetFocus)
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc
index 047afce..e2129f2 100644
--- a/chrome/plugin/webplugin_delegate_stub.cc
+++ b/chrome/plugin/webplugin_delegate_stub.cc
@@ -6,7 +6,6 @@
#include "base/command_line.h"
#include "base/time.h"
-#include "base/gfx/bitmap_header.h"
#include "base/gfx/platform_device_win.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gfx/emf.h"
@@ -81,10 +80,7 @@ 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_Print, OnPrint)
- IPC_MESSAGE_HANDLER(PluginMsg_PaintIntoSharedMemory,
- OnPaintIntoSharedMemory)
IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject,
OnGetPluginScriptableObject)
IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry)
@@ -203,47 +199,6 @@ void WebPluginDelegateStub::OnHandleEvent(const NPEvent& event,
*handled = delegate_->HandleEvent(const_cast<NPEvent*>(&event), cursor);
}
-void WebPluginDelegateStub::OnPaint(const PluginMsg_Paint_Params& params) {
- // Convert the shared memory handle to a handle that works in our process,
- // and then use that to create an HDC.
- win_util::ScopedHandle shared_section(win_util::GetSectionFromProcess(
- params.shared_memory, channel_->renderer_handle(), false));
-
- if (shared_section == NULL) {
- NOTREACHED();
- return;
- }
-
- void* data = NULL;
- HDC screen_dc = GetDC(NULL);
- BITMAPINFOHEADER bitmap_header;
- gfx::CreateBitmapHeader(params.size.width(), params.size.height(),
- &bitmap_header);
- win_util::ScopedBitmap hbitmap(CreateDIBSection(
- screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header),
- DIB_RGB_COLORS, &data,
- shared_section, 0));
- ReleaseDC(NULL, screen_dc);
- if (hbitmap == NULL) {
- NOTREACHED();
- return;
- }
-
- win_util::ScopedHDC hdc(CreateCompatibleDC(NULL));
- if (hdc == NULL) {
- NOTREACHED();
- return;
- }
- gfx::PlatformDeviceWin::InitializeDC(hdc);
- SelectObject(hdc, hbitmap);
- SetWorldTransform(hdc, &params.xf);
-
- win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(&params.clip_rect.ToRECT()));
- SelectClipRgn(hdc, hrgn);
- webplugin_->WillPaint();
- delegate_->Paint(hdc, params.damaged_rect);
-}
-
void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) {
gfx::Emf emf;
if (!emf.CreateDc(NULL, NULL)) {
@@ -269,80 +224,14 @@ void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) {
DCHECK(success);
}
-void WebPluginDelegateStub::OnPaintIntoSharedMemory(
- const PluginMsg_Paint_Params& params,
- SharedMemoryHandle* emf_buffer,
- size_t* bytes) {
- *emf_buffer = NULL;
- *bytes = 0;
-
- gfx::Emf emf;
- if (!emf.CreateDc(NULL, NULL)) {
- NOTREACHED();
- return;
- }
- HDC hdc = emf.hdc();
- gfx::PlatformDeviceWin::InitializeDC(hdc);
-
- if (delegate_->windowless()) {
- WindowlessPaint(hdc, params);
- } else {
- WindowedPaint(hdc, params.damaged_rect);
- }
-
- // Need to send back the data as shared memory.
- if (!emf.CloseDc()) {
- NOTREACHED();
- return;
- }
-
- size_t size = emf.GetDataSize();
- DCHECK(size);
- *bytes = size;
- SharedMemory shared_buf;
- CreateSharedBuffer(size, &shared_buf, emf_buffer);
-
- // Retrieve a copy of the data.
- bool success = emf.GetData(shared_buf.memory(), size);
- DCHECK(success);
-}
-
-void WebPluginDelegateStub::WindowedPaint(HDC hdc,
- const gfx::Rect& window_rect) {
- // Use the NPAPI print() function to render the plugin.
- delegate_->Print(hdc);
-}
-
-void WebPluginDelegateStub::WindowlessPaint(
- HDC hdc,
- const PluginMsg_Paint_Params& params) {
- void* data = NULL;
- HDC screen_dc = GetDC(NULL);
- BITMAPINFOHEADER bitmap_header;
- gfx::CreateBitmapHeader(params.size.width(), params.size.height(),
- &bitmap_header);
- win_util::ScopedBitmap hbitmap(CreateDIBSection(
- screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header),
- DIB_RGB_COLORS, &data, NULL, 0));
- ReleaseDC(NULL, screen_dc);
- if (hbitmap == NULL) {
- NOTREACHED();
- return;
- }
- SelectObject(hdc, hbitmap);
-
- // Apply transform and clipping.
- SetWorldTransform(hdc, &params.xf);
- win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(&params.clip_rect.ToRECT()));
- SelectClipRgn(hdc, hrgn);
- webplugin_->WillPaint();
- delegate_->Paint(hdc, params.damaged_rect);
-}
-
-void WebPluginDelegateStub::OnUpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect,
- bool visible) {
- delegate_->UpdateGeometry(window_rect, clip_rect, visible);
+void WebPluginDelegateStub::OnUpdateGeometry(
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible,
+ const SharedMemoryHandle& windowless_buffer,
+ const SharedMemoryLock& lock) {
+ webplugin_->UpdateGeometry(
+ window_rect, clip_rect, visible, windowless_buffer, lock);
}
void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id,
diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h
index f113cb8..cb242b4 100644
--- a/chrome/plugin/webplugin_delegate_stub.h
+++ b/chrome/plugin/webplugin_delegate_stub.h
@@ -19,7 +19,6 @@ class PluginChannel;
class WebPluginProxy;
class WebPluginDelegateImpl;
struct PluginMsg_Init_Params;
-struct PluginMsg_Paint_Params;
struct PluginMsg_DidReceiveResponseParams;
class WebCursor;
@@ -58,23 +57,11 @@ class WebPluginDelegateStub : public IPC::Channel::Listener,
void OnSetFocus();
void OnHandleEvent(const NPEvent& event, bool* handled,
WebCursor* cursor);
-
- void OnPaint(const PluginMsg_Paint_Params& params);
-
void OnPrint(PluginMsg_PrintResponse_Params* params);
-
- // Paints the plugin into a buffer. It roughly does the same as OnPaint (i.e.
- // painting a plugin) except that the plugin window is always renderered into
- // an EMF buffer and that it is effective for windowed plugins too.
- void OnPaintIntoSharedMemory(const PluginMsg_Paint_Params& params,
- SharedMemoryHandle* emf_buffer, size_t* bytes);
- // Paints a windowed plugin into a device context.
- void WindowedPaint(HDC hdc, const gfx::Rect& window_rect);
- // Paints a windowless plugin into a device context.
- void WindowlessPaint(HDC hdc,
- const PluginMsg_Paint_Params& params);
void OnUpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect, bool visible);
+ const gfx::Rect& clip_rect, bool visible,
+ const SharedMemoryHandle& windowless_buffer,
+ const SharedMemoryLock& lock);
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 6f68c2d..cc091a2 100644
--- a/chrome/plugin/webplugin_proxy.cc
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -4,14 +4,22 @@
#include "chrome/plugin/webplugin_proxy.h"
+#include "base/gfx/bitmap_header.h"
+#include "base/gfx/platform_device_win.h"
#include "base/scoped_handle.h"
+#include "base/shared_memory.h"
#include "base/singleton.h"
+#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/plugin_messages.h"
+#include "chrome/common/win_util.h"
#include "chrome/plugin/plugin_channel.h"
#include "chrome/plugin/webplugin_delegate_stub.h"
#include "chrome/plugin/npobject_proxy.h"
#include "chrome/plugin/npobject_util.h"
-#include "webkit/glue/webplugin_delegate.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() {
@@ -21,15 +29,14 @@ static ContextMap& GetContextMap() {
WebPluginProxy::WebPluginProxy(
PluginChannel* channel,
int route_id,
- WebPluginDelegate* delegate,
+ WebPluginDelegateImpl* delegate,
HANDLE modal_dialog_event)
: channel_(channel),
route_id_(route_id),
cp_browsing_context_(0),
window_npobject_(NULL),
plugin_element_(NULL),
- delegate_(delegate),
- waiting_for_paint_(false) {
+ delegate_(delegate) {
HANDLE event;
BOOL result = DuplicateHandle(channel->renderer_handle(),
@@ -78,17 +85,10 @@ void WebPluginProxy::Invalidate() {
}
void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) {
- // Ignore NPN_InvalidateRect calls with empty rects.
- if (rect.IsEmpty()) {
- return;
- }
- // Only send a single InvalidateRect message at a time. From WillPaint we
- // will dispatch an additional InvalidateRect message if necessary.
- if (waiting_for_paint_) {
- damaged_rect_ = damaged_rect_.Union(rect);
- } else {
- waiting_for_paint_ = true;
- Send(new PluginHostMsg_InvalidateRect(route_id_, rect));
+ damaged_rect_ = damaged_rect_.Union(rect);
+ if (!paint_timer_.IsRunning()) {
+ paint_timer_.Start(TimeDelta::FromMilliseconds(1000 / kWindowlessPaintFPS),
+ this, &WebPluginProxy::OnPaintTimerFired);
}
}
@@ -190,16 +190,6 @@ WebPluginResourceClient* WebPluginProxy::GetResourceClient(int id) {
return iterator->second;
}
-void WebPluginProxy::WillPaint() {
- // 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_);
- damaged_rect_ = gfx::Rect();
- }
-}
-
void WebPluginProxy::OnResourceCreated(int resource_id, HANDLE cookie) {
WebPluginResourceClient* resource_client =
reinterpret_cast<WebPluginResourceClient*>(cookie);
@@ -243,6 +233,111 @@ void WebPluginProxy::HandleURLRequest(const char *method,
Send(new PluginHostMsg_URLRequest(route_id_, params));
}
+void WebPluginProxy::OnPaintTimerFired() {
+ 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)));
+
+ // 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();
+}
+
+void WebPluginProxy::UpdateGeometry(
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible,
+ const SharedMemoryHandle& windowless_buffer,
+ const SharedMemoryLock& lock) {
+ 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);
+ } else if (moved) {
+ // The plugin moved, so update our world transform.
+ UpdateTransform();
+ }
+}
+
+void WebPluginProxy::SetWindowlessBuffer(const SharedMemoryHandle& handle,
+ const SharedMemoryLock& lock) {
+ // 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);
+ }
+
+ if (windowless_shared_section_ == NULL || windowless_buffer_lock_ == NULL) {
+ NOTREACHED();
+ return;
+ }
+
+ void* data = NULL;
+ HDC screen_dc = GetDC(NULL);
+ BITMAPINFOHEADER bitmap_header;
+ gfx::CreateBitmapHeader(delegate_->rect().width(),
+ delegate_->rect().height(),
+ &bitmap_header);
+ windowless_bitmap_.Set(CreateDIBSection(
+ screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS, &data, windowless_shared_section_, 0));
+ ReleaseDC(NULL, screen_dc);
+ if (windowless_bitmap_ == NULL) {
+ NOTREACHED();
+ return;
+ }
+
+ windowless_hdc_.Set(CreateCompatibleDC(NULL));
+ if (windowless_hdc_ == NULL) {
+ NOTREACHED();
+ return;
+ }
+
+ gfx::PlatformDeviceWin::InitializeDC(windowless_hdc_);
+ SelectObject(windowless_hdc_, windowless_bitmap_);
+ UpdateTransform();
+}
+
+void WebPluginProxy::UpdateTransform() {
+ if (!windowless_hdc_)
+ return;
+
+ XFORM xf;
+ xf.eDx = static_cast<FLOAT>(-delegate_->rect().x());
+ xf.eDy = static_cast<FLOAT>(-delegate_->rect().y());
+ xf.eM11 = 1;
+ xf.eM21 = 0;
+ xf.eM12 = 0;
+ xf.eM22 = 1;
+ SetWorldTransform(windowless_hdc_, &xf);
+}
+
void WebPluginProxy::CancelDocumentLoad() {
Send(new PluginHostMsg_CancelDocumentLoad(route_id_));
}
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
index 092bf32..9e1a051 100644
--- a/chrome/plugin/webplugin_proxy.h
+++ b/chrome/plugin/webplugin_proxy.h
@@ -8,12 +8,14 @@
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/scoped_handle.h"
+#include "base/shared_memory.h"
+#include "base/timer.h"
#include "chrome/common/ipc_message.h"
#include "chrome/common/chrome_plugin_api.h"
#include "webkit/glue/webplugin.h"
class PluginChannel;
-class WebPluginDelegate;
+class WebPluginDelegateImpl;
// This is an implementation of WebPlugin that proxies all calls to the
// renderer.
@@ -23,7 +25,7 @@ class WebPluginProxy : public WebPlugin {
// marshalled WebPlugin calls.
WebPluginProxy(PluginChannel* channel,
int route_id,
- WebPluginDelegate* delegate,
+ WebPluginDelegateImpl* delegate,
HANDLE modal_dialog_event);
~WebPluginProxy();
@@ -60,8 +62,6 @@ class WebPluginProxy : public WebPlugin {
// object with that id exists.
WebPluginResourceClient* GetResourceClient(int id);
- void WillPaint();
-
// Notification received on a plugin issued resource request
// creation.
void OnResourceCreated(int resource_id, HANDLE cookie);
@@ -73,6 +73,12 @@ class WebPluginProxy : public WebPlugin {
bool notify, const char* url,
void* notify_data, bool popups_allowed);
+ void UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible,
+ const SharedMemoryHandle& windowless_buffer,
+ const SharedMemoryLock& lock);
+
void CancelDocumentLoad();
void InitiateHTTPRangeRequest(const char* url,
@@ -80,9 +86,21 @@ class WebPluginProxy : public WebPlugin {
void* existing_stream,
bool notify_needed,
HANDLE notify_data);
+
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);
+
+ // Called when a plugin's origin moves, so that we can update the world
+ // transform of the local HDC.
+ void UpdateTransform();
+
typedef base::hash_map<int, WebPluginResourceClient*> ResourceClientMap;
ResourceClientMap resource_clients_;
@@ -90,11 +108,21 @@ class WebPluginProxy : public WebPlugin {
int route_id_;
NPObject* window_npobject_;
NPObject* plugin_element_;
- WebPluginDelegate* delegate_;
- gfx::Rect damaged_rect_;
- bool waiting_for_paint_;
+ WebPluginDelegateImpl* delegate_;
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_;
+ ScopedHandle windowless_shared_section_;
+ ScopedBitmap windowless_bitmap_;
+ ScopedHDC windowless_hdc_;
+ ScopedHandle windowless_buffer_lock_;
};
#endif // CHROME_PLUGIN_PLUGIN_WEBPLUGIN_PROXY_H__
diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc
index 225608e..1c5924c 100644
--- a/chrome/renderer/webplugin_delegate_proxy.cc
+++ b/chrome/renderer/webplugin_delegate_proxy.cc
@@ -143,8 +143,7 @@ WebPluginDelegateProxy::WebPluginDelegateProxy(const std::string& mime_type,
send_deferred_update_geometry_(false),
visible_(false),
sad_plugin_(NULL),
- window_script_object_(NULL),
- modal_loop_pump_messages_event_(NULL) {
+ window_script_object_(NULL) {
}
WebPluginDelegateProxy::~WebPluginDelegateProxy() {
@@ -155,10 +154,6 @@ WebPluginDelegateProxy::~WebPluginDelegateProxy() {
window_script_object_->set_proxy(NULL);
window_script_object_->set_invalid();
}
-
- if (modal_loop_pump_messages_event_) {
- CloseHandle(modal_loop_pump_messages_event_);
- }
}
void WebPluginDelegateProxy::PluginDestroyed() {
@@ -186,7 +181,9 @@ void WebPluginDelegateProxy::FlushGeometryUpdates() {
Send(new PluginMsg_UpdateGeometry(instance_id_,
plugin_rect_,
deferred_clip_rect_,
- visible_));
+ visible_,
+ NULL,
+ NULL));
}
}
@@ -329,21 +326,60 @@ void WebPluginDelegateProxy::OnChannelError() {
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) {
- plugin_rect_ = window_rect;
-
- if (windowless_) {
- IPC::Message* msg = new PluginMsg_UpdateGeometry(
- instance_id_, window_rect, clip_rect, visible);
- msg->set_unblock(true);
- Send(msg);
- } else {
+ if (!windowless_) {
deferred_clip_rect_ = clip_rect;
visible_ = visible;
send_deferred_update_geometry_ = true;
+ return;
}
+
+ HANDLE windowless_buffer_handle = NULL;
+ bool moved = plugin_rect_.x() != window_rect.x() ||
+ plugin_rect_.y() != window_rect.y();
+ plugin_rect_ = window_rect;
+ 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;
+ }
+
+ 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_);
+ msg->set_unblock(true);
+ Send(msg);
}
void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) {
@@ -354,100 +390,40 @@ void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) {
return;
}
- // Can't duplicate an HDC handle, so get all the parameters we need in
- // order to recreate the same HDC in the plugin process.
- PluginMsg_Paint_Params params;
- HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
- if (bitmap == NULL) {
- NOTREACHED();
+ // No paint events for windowed plugins. However, if it is the first paint
+ // we don't know yet whether the plugin is windowless or not, so we have to
+ // send the event.
+ if (!windowless_ && !first_paint_) {
+ // TODO(maruel): That's not true for printing and thumbnail capture.
+ // We shall use PrintWindow() to draw the window.
return;
}
+ first_paint_ = false;
- DIBSECTION dibsection = { 0 };
- int result = GetObject(bitmap, sizeof(dibsection), &dibsection);
- if (!result) {
- NOTREACHED();
+ // We got a paint before the plugin's coordinates, so there's no buffer to
+ // copy from.
+ if (!windowless_buffer_.get())
return;
- }
- win_util::ScopedHRGN hrgn(CreateRectRgn(0, 0, 0, 0));
- result = GetClipRgn(hdc, hrgn);
- if (result == -1) {
- NOTREACHED();
- 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_);
- params.size.SetSize(dibsection.dsBmih.biWidth, dibsection.dsBmih.biHeight);
- if (result == 0) {
- // No clipping region.
- params.clip_rect.set_width(params.size.width());
- params.clip_rect.set_height(params.size.height());
- } else {
- RECT clip_rect;
- result = GetRgnBox(hrgn, &clip_rect);
- DCHECK_NE(result, 0);
- params.clip_rect = clip_rect;
- }
+ DWORD wait_result = WaitForSingleObject(windowless_buffer_lock_, INFINITE);
+ DCHECK(wait_result == WAIT_OBJECT_0);
- if (!GetWorldTransform(hdc, &params.xf)) {
- NOTREACHED();
- return;
- }
-
- params.damaged_rect = damaged_rect;
- params.shared_memory = dibsection.dshSection;
-
- // Normal painting code path.
- if (dibsection.dshSection) {
- // No paint events for windowed plugins. However, if it is the first paint
- // we don't know yet whether the plugin is windowless or not, so we have to
- // send the event.
- if (!windowless_ && !first_paint_) {
- // TODO(maruel): That's not true for printing and thumbnail capture.
- // We shall use PrintWindow() to draw the window.
- return;
- }
- first_paint_ = false;
-
- DCHECK(params.size.width());
- DCHECK(params.size.height());
- Send(new PluginMsg_Paint(instance_id_, params));
- return;
- }
-
- params.size.SetSize(damaged_rect.width(), damaged_rect.height());
- // Pass the window size instead.
- if (!windowless_)
- params.damaged_rect = plugin_rect_;
-
- // When the thumbnail is painted or during printing, a shared memory handle
- // isn't given to CreateDIBSection so we don't get one now.
- size_t bytes = 0;
- SharedMemoryHandle emf_buffer = NULL;
- PluginMsg_PaintIntoSharedMemory* msg =
- new PluginMsg_PaintIntoSharedMemory(instance_id_, params, &emf_buffer,
- &bytes);
- if (!Send(msg))
- return;
-
- if (!emf_buffer) {
- NOTREACHED();
- return;
- }
+ BLENDFUNCTION m_bf;
+ m_bf.BlendOp = AC_SRC_OVER;
+ m_bf.BlendFlags = 0;
+ m_bf.SourceConstantAlpha = 255;
+ m_bf.AlphaFormat = AC_SRC_ALPHA;
- // memory's destructor will automatically close emf_buffer.
- SharedMemory memory(emf_buffer, true);
- if (!memory.Map(bytes)) {
- NOTREACHED();
- return;
- }
+ 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);
- gfx::Emf emf;
- if (!emf.CreateFromData(memory.memory(), bytes)) {
- NOTREACHED();
- return;
- }
- emf.Playback(hdc, NULL);
+ BOOL result = ReleaseMutex(windowless_buffer_lock_);
+ DCHECK(result);
}
void WebPluginDelegateProxy::Print(HDC hdc) {
@@ -523,7 +499,8 @@ void WebPluginDelegateProxy::OnSetWindow(
if (plugin_)
plugin_->SetWindow(window, modal_loop_pump_messages_event);
- modal_loop_pump_messages_event_ = modal_loop_pump_messages_event;
+ DCHECK(modal_loop_pump_messages_event_ == NULL);
+ modal_loop_pump_messages_event_.Set(modal_loop_pump_messages_event);
}
void WebPluginDelegateProxy::OnCancelResource(int id) {
diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h
index 5ce612a..c457f90 100644
--- a/chrome/renderer/webplugin_delegate_proxy.h
+++ b/chrome/renderer/webplugin_delegate_proxy.h
@@ -10,6 +10,7 @@
#include "base/gfx/rect.h"
#include "base/ref_counted.h"
+#include "base/scoped_handle.h"
#include "chrome/common/ipc_message.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/plugin/npobject_stub.h"
@@ -21,6 +22,10 @@ class GURL;
struct PluginHostMsg_RouteToFrame_Params;
class RenderView;
class SkBitmap;
+namespace gfx {
+class PlatformCanvasWin;
+}
+
// An implementation of WebPluginDelegate that proxies all calls to
// the plugin process.
@@ -148,11 +153,17 @@ class WebPluginDelegateProxy : public WebPluginDelegate,
// Event passed in by the plugin process and is used to decide if
// messages need to be pumped in the NPP_HandleEvent sync call.
- HANDLE modal_loop_pump_messages_event_;
+ ScopedHandle modal_loop_pump_messages_event_;
// 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_;
+
DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateProxy);
};