Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: chrome/renderer/webplugin_delegate_proxy.cc

Issue 3133: Desynchronize windowless plugin painting. This greatly improves the painting... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/renderer/webplugin_delegate_proxy.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/webplugin_delegate_proxy.h" 5 #include "chrome/renderer/webplugin_delegate_proxy.h"
6 6
7 #include <atlbase.h> 7 #include <atlbase.h>
8 8
9 #include "generated_resources.h" 9 #include "generated_resources.h"
10 10
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 : render_view_(render_view), 135 : render_view_(render_view),
136 mime_type_(mime_type), 136 mime_type_(mime_type),
137 clsid_(clsid), 137 clsid_(clsid),
138 plugin_(NULL), 138 plugin_(NULL),
139 windowless_(false), 139 windowless_(false),
140 first_paint_(true), 140 first_paint_(true),
141 npobject_(NULL), 141 npobject_(NULL),
142 send_deferred_update_geometry_(false), 142 send_deferred_update_geometry_(false),
143 visible_(false), 143 visible_(false),
144 sad_plugin_(NULL), 144 sad_plugin_(NULL),
145 window_script_object_(NULL), 145 window_script_object_(NULL) {
146 modal_loop_pump_messages_event_(NULL) {
147 } 146 }
148 147
149 WebPluginDelegateProxy::~WebPluginDelegateProxy() { 148 WebPluginDelegateProxy::~WebPluginDelegateProxy() {
150 if (npobject_) 149 if (npobject_)
151 NPN_ReleaseObject(npobject_); 150 NPN_ReleaseObject(npobject_);
152 151
153 if (window_script_object_) { 152 if (window_script_object_) {
154 window_script_object_->set_proxy(NULL); 153 window_script_object_->set_proxy(NULL);
155 window_script_object_->set_invalid(); 154 window_script_object_->set_invalid();
156 } 155 }
157
158 if (modal_loop_pump_messages_event_) {
159 CloseHandle(modal_loop_pump_messages_event_);
160 }
161 } 156 }
162 157
163 void WebPluginDelegateProxy::PluginDestroyed() { 158 void WebPluginDelegateProxy::PluginDestroyed() {
164 plugin_ = NULL; 159 plugin_ = NULL;
165 160
166 if (channel_host_) { 161 if (channel_host_) {
167 if (npobject_) { 162 if (npobject_) {
168 // When we destroy the plugin instance, the NPObjectStub NULLs out its 163 // When we destroy the plugin instance, the NPObjectStub NULLs out its
169 // pointer to the npobject (see NPObjectStub::OnChannelError). Therefore, 164 // pointer to the npobject (see NPObjectStub::OnChannelError). Therefore,
170 // we release the object before destroying the instance to avoid leaking. 165 // we release the object before destroying the instance to avoid leaking.
171 NPN_ReleaseObject(npobject_); 166 NPN_ReleaseObject(npobject_);
172 npobject_ = NULL; 167 npobject_ = NULL;
173 } 168 }
174 169
175 channel_host_->RemoveRoute(instance_id_); 170 channel_host_->RemoveRoute(instance_id_);
176 Send(new PluginMsg_DestroyInstance(instance_id_)); 171 Send(new PluginMsg_DestroyInstance(instance_id_));
177 } 172 }
178 render_view_->PluginDestroyed(this); 173 render_view_->PluginDestroyed(this);
179 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 174 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
180 } 175 }
181 176
182 void WebPluginDelegateProxy::FlushGeometryUpdates() { 177 void WebPluginDelegateProxy::FlushGeometryUpdates() {
183 if (send_deferred_update_geometry_) { 178 if (send_deferred_update_geometry_) {
184 send_deferred_update_geometry_ = false; 179 send_deferred_update_geometry_ = false;
185 Send(new PluginMsg_UpdateGeometry(instance_id_, 180 Send(new PluginMsg_UpdateGeometry(instance_id_,
186 plugin_rect_, 181 plugin_rect_,
187 deferred_clip_rect_, 182 deferred_clip_rect_,
188 visible_)); 183 visible_,
184 NULL,
185 NULL));
189 } 186 }
190 } 187 }
191 188
192 bool WebPluginDelegateProxy::Initialize(const GURL& url, char** argn, 189 bool WebPluginDelegateProxy::Initialize(const GURL& url, char** argn,
193 char** argv, int argc, 190 char** argv, int argc,
194 WebPlugin* plugin, 191 WebPlugin* plugin,
195 bool load_manually) { 192 bool load_manually) {
196 std::wstring channel_name, plugin_path; 193 std::wstring channel_name, plugin_path;
197 if (!RenderThread::current()->Send(new ViewHostMsg_OpenChannelToPlugin( 194 if (!RenderThread::current()->Send(new ViewHostMsg_OpenChannelToPlugin(
198 url, mime_type_, clsid_, webkit_glue::GetWebKitLocale(), 195 url, mime_type_, clsid_, webkit_glue::GetWebKitLocale(),
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 OnGetCPBrowsingContext) 315 OnGetCPBrowsingContext)
319 IPC_MESSAGE_UNHANDLED_ERROR() 316 IPC_MESSAGE_UNHANDLED_ERROR()
320 IPC_END_MESSAGE_MAP() 317 IPC_END_MESSAGE_MAP()
321 } 318 }
322 319
323 void WebPluginDelegateProxy::OnChannelError() { 320 void WebPluginDelegateProxy::OnChannelError() {
324 OnInvalidate(); 321 OnInvalidate();
325 render_view_->PluginCrashed(plugin_path_); 322 render_view_->PluginCrashed(plugin_path_);
326 } 323 }
327 324
325 // Copied from render_widget.cc
326 static size_t GetPaintBufSize(const gfx::Rect& rect) {
327 // TODO(darin): protect against overflow
328 return 4 * rect.width() * rect.height();
329 }
330
328 void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect, 331 void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
329 const gfx::Rect& clip_rect, 332 const gfx::Rect& clip_rect,
330 bool visible) { 333 bool visible) {
331 plugin_rect_ = window_rect; 334 if (!windowless_) {
332
333 if (windowless_) {
334 IPC::Message* msg = new PluginMsg_UpdateGeometry(
335 instance_id_, window_rect, clip_rect, visible);
336 msg->set_unblock(true);
337 Send(msg);
338 } else {
339 deferred_clip_rect_ = clip_rect; 335 deferred_clip_rect_ = clip_rect;
340 visible_ = visible; 336 visible_ = visible;
341 send_deferred_update_geometry_ = true; 337 send_deferred_update_geometry_ = true;
338 return;
342 } 339 }
340
341 HANDLE windowless_buffer_handle = NULL;
342 bool moved = plugin_rect_.x() != window_rect.x() ||
343 plugin_rect_.y() != window_rect.y();
344 plugin_rect_ = window_rect;
345 if (!windowless_canvas_.get() ||
346 (window_rect.width() != windowless_canvas_->getDevice()->width() ||
347 window_rect.height() != windowless_canvas_->getDevice()->height())) {
348 // Create a shared memory section that the plugin paints asynchronously.
349 windowless_canvas_.reset();
350 if (!windowless_buffer_lock_)
351 windowless_buffer_lock_.Set(CreateMutex(NULL, FALSE, NULL));
352 windowless_buffer_.reset(new SharedMemory());
353 size_t size = GetPaintBufSize(plugin_rect_);
354 if (!windowless_buffer_->Create(L"", false, true, size)) {
355 DCHECK(false);
356 windowless_buffer_.reset();
357 return;
358 }
359
360 windowless_canvas_.reset(new gfx::PlatformCanvasWin(
361 plugin_rect_.width(), plugin_rect_.height(), false,
362 windowless_buffer_->handle()));
363 windowless_canvas_->translate(static_cast<SkScalar>(-plugin_rect_.x()),
364 static_cast<SkScalar>(-plugin_rect_.y()));
365 windowless_canvas_->getTopPlatformDevice().accessBitmap(true).
366 eraseARGB(0, 0, 0, 0);
367 windowless_buffer_handle = windowless_buffer_->handle();
368 } else if (moved) {
369 windowless_canvas_->resetMatrix();
370 windowless_canvas_->translate(static_cast<SkScalar>(-plugin_rect_.x()),
371 static_cast<SkScalar>(-plugin_rect_.y()));
372 }
373
374 IPC::Message* msg = new PluginMsg_UpdateGeometry(
375 instance_id_, window_rect, clip_rect, visible, windowless_buffer_handle,
376 windowless_buffer_lock_);
377 msg->set_unblock(true);
378 Send(msg);
343 } 379 }
344 380
345 void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) { 381 void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) {
346 // If the plugin is no longer connected (channel crashed) draw a crashed 382 // If the plugin is no longer connected (channel crashed) draw a crashed
347 // plugin bitmap 383 // plugin bitmap
348 if (!channel_host_->channel_valid()) { 384 if (!channel_host_->channel_valid()) {
349 PaintSadPlugin(hdc, damaged_rect); 385 PaintSadPlugin(hdc, damaged_rect);
350 return; 386 return;
351 } 387 }
352 388
353 // Can't duplicate an HDC handle, so get all the parameters we need in 389 // No paint events for windowed plugins. However, if it is the first paint
354 // order to recreate the same HDC in the plugin process. 390 // we don't know yet whether the plugin is windowless or not, so we have to
355 PluginMsg_Paint_Params params; 391 // send the event.
356 HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); 392 if (!windowless_ && !first_paint_) {
357 if (bitmap == NULL) { 393 // TODO(maruel): That's not true for printing and thumbnail capture.
358 NOTREACHED(); 394 // We shall use PrintWindow() to draw the window.
359 return; 395 return;
360 } 396 }
397 first_paint_ = false;
361 398
362 DIBSECTION dibsection = { 0 }; 399 // We got a paint before the plugin's coordinates, so there's no buffer to
363 int result = GetObject(bitmap, sizeof(dibsection), &dibsection); 400 // copy from.
364 if (!result) { 401 if (!windowless_buffer_.get())
365 NOTREACHED();
366 return;
367 }
368
369 win_util::ScopedHRGN hrgn(CreateRectRgn(0, 0, 0, 0));
370 result = GetClipRgn(hdc, hrgn);
371 if (result == -1) {
372 NOTREACHED();
373 return;
374 }
375
376 params.size.SetSize(dibsection.dsBmih.biWidth, dibsection.dsBmih.biHeight);
377 if (result == 0) {
378 // No clipping region.
379 params.clip_rect.set_width(params.size.width());
380 params.clip_rect.set_height(params.size.height());
381 } else {
382 RECT clip_rect;
383 result = GetRgnBox(hrgn, &clip_rect);
384 DCHECK_NE(result, 0);
385 params.clip_rect = clip_rect;
386 }
387
388 if (!GetWorldTransform(hdc, &params.xf)) {
389 NOTREACHED();
390 return;
391 }
392
393 params.damaged_rect = damaged_rect;
394 params.shared_memory = dibsection.dshSection;
395
396 // Normal painting code path.
397 if (dibsection.dshSection) {
398 // No paint events for windowed plugins. However, if it is the first paint
399 // we don't know yet whether the plugin is windowless or not, so we have to
400 // send the event.
401 if (!windowless_ && !first_paint_) {
402 // TODO(maruel): That's not true for printing and thumbnail capture.
403 // We shall use PrintWindow() to draw the window.
404 return;
405 }
406 first_paint_ = false;
407
408 DCHECK(params.size.width());
409 DCHECK(params.size.height());
410 Send(new PluginMsg_Paint(instance_id_, params));
411 return;
412 }
413
414 params.size.SetSize(damaged_rect.width(), damaged_rect.height());
415 // Pass the window size instead.
416 if (!windowless_)
417 params.damaged_rect = plugin_rect_;
418
419 // When the thumbnail is painted or during printing, a shared memory handle
420 // isn't given to CreateDIBSection so we don't get one now.
421 size_t bytes = 0;
422 SharedMemoryHandle emf_buffer = NULL;
423 PluginMsg_PaintIntoSharedMemory* msg =
424 new PluginMsg_PaintIntoSharedMemory(instance_id_, params, &emf_buffer,
425 &bytes);
426 if (!Send(msg))
427 return; 402 return;
428 403
429 if (!emf_buffer) { 404 // Limit the damaged rectangle to whatever is contained inside the plugin
430 NOTREACHED(); 405 // rectangle, as that's the rectangle that we'll bitblt to the hdc.
431 return; 406 gfx::Rect rect = damaged_rect.Intersect(plugin_rect_);
432 }
433 407
434 // memory's destructor will automatically close emf_buffer. 408 DWORD wait_result = WaitForSingleObject(windowless_buffer_lock_, INFINITE);
435 SharedMemory memory(emf_buffer, true); 409 DCHECK(wait_result == WAIT_OBJECT_0);
436 if (!memory.Map(bytes)) {
437 NOTREACHED();
438 return;
439 }
440 410
441 gfx::Emf emf; 411 BLENDFUNCTION m_bf;
442 if (!emf.CreateFromData(memory.memory(), bytes)) { 412 m_bf.BlendOp = AC_SRC_OVER;
443 NOTREACHED(); 413 m_bf.BlendFlags = 0;
444 return; 414 m_bf.SourceConstantAlpha = 255;
445 } 415 m_bf.AlphaFormat = AC_SRC_ALPHA;
446 emf.Playback(hdc, NULL); 416
417 HDC new_hdc = windowless_canvas_->getTopPlatformDevice().getBitmapDC();
418 AlphaBlend(hdc, rect.x(), rect.y(), rect.width(), rect.height(),
419 new_hdc, rect.x(), rect.y(), rect.width(), rect.height(), m_bf);
420
421 BOOL result = ReleaseMutex(windowless_buffer_lock_);
422 DCHECK(result);
447 } 423 }
448 424
449 void WebPluginDelegateProxy::Print(HDC hdc) { 425 void WebPluginDelegateProxy::Print(HDC hdc) {
450 PluginMsg_PrintResponse_Params params = { 0 }; 426 PluginMsg_PrintResponse_Params params = { 0 };
451 Send(new PluginMsg_Print(instance_id_, &params)); 427 Send(new PluginMsg_Print(instance_id_, &params));
452 428
453 SharedMemory memory(params.shared_memory, true); 429 SharedMemory memory(params.shared_memory, true);
454 if (!memory.Map(params.size)) { 430 if (!memory.Map(params.size)) {
455 NOTREACHED(); 431 NOTREACHED();
456 return; 432 return;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 NOTREACHED() << "GetWindowHandle can't be called on the proxy."; 488 NOTREACHED() << "GetWindowHandle can't be called on the proxy.";
513 return NULL; 489 return NULL;
514 } 490 }
515 491
516 void WebPluginDelegateProxy::OnSetWindow( 492 void WebPluginDelegateProxy::OnSetWindow(
517 HWND window, HANDLE modal_loop_pump_messages_event) { 493 HWND window, HANDLE modal_loop_pump_messages_event) {
518 windowless_ = window == NULL; 494 windowless_ = window == NULL;
519 if (plugin_) 495 if (plugin_)
520 plugin_->SetWindow(window, modal_loop_pump_messages_event); 496 plugin_->SetWindow(window, modal_loop_pump_messages_event);
521 497
522 modal_loop_pump_messages_event_ = modal_loop_pump_messages_event; 498 DCHECK(modal_loop_pump_messages_event_ == NULL);
499 modal_loop_pump_messages_event_.Set(modal_loop_pump_messages_event);
523 } 500 }
524 501
525 void WebPluginDelegateProxy::OnCancelResource(int id) { 502 void WebPluginDelegateProxy::OnCancelResource(int id) {
526 if (plugin_) 503 if (plugin_)
527 plugin_->CancelResource(id); 504 plugin_->CancelResource(id);
528 } 505 }
529 506
530 void WebPluginDelegateProxy::OnInvalidate() { 507 void WebPluginDelegateProxy::OnInvalidate() {
531 if (plugin_) 508 if (plugin_)
532 plugin_->Invalidate(); 509 plugin_->Invalidate();
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
662 return proxy; 639 return proxy;
663 } 640 }
664 641
665 void WebPluginDelegateProxy::URLRequestRouted(const std::string& url, 642 void WebPluginDelegateProxy::URLRequestRouted(const std::string& url,
666 bool notify_needed, 643 bool notify_needed,
667 void* notify_data) { 644 void* notify_data) {
668 Send(new PluginMsg_URLRequestRouted(instance_id_, url, notify_needed, 645 Send(new PluginMsg_URLRequestRouted(instance_id_, url, notify_needed,
669 notify_data)); 646 notify_data));
670 } 647 }
671 648
OLDNEW
« no previous file with comments | « chrome/renderer/webplugin_delegate_proxy.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698