summaryrefslogtreecommitdiffstats
path: root/chrome/plugin
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/plugin
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/plugin')
-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
4 files changed, 166 insertions, 167 deletions
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__