chromeos: dbus: add Bluetooth properties support
[chromium-blink-merge.git] / content / renderer / webplugin_delegate_proxy.cc
blobca04b6665309c7c92c7be652b72e343d11cc48c6
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/webplugin_delegate_proxy.h"
7 #if defined(TOOLKIT_USES_GTK)
8 #include <gtk/gtk.h>
9 #elif defined(USE_X11)
10 #include <cairo/cairo.h>
11 #endif
13 #include <algorithm>
15 #include "base/basictypes.h"
16 #include "base/command_line.h"
17 #include "base/file_util.h"
18 #include "base/logging.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/string_split.h"
22 #include "base/string_util.h"
23 #include "base/utf_string_conversions.h"
24 #include "base/version.h"
25 #include "content/common/child_process.h"
26 #include "content/common/npobject_proxy.h"
27 #include "content/common/npobject_stub.h"
28 #include "content/common/npobject_util.h"
29 #include "content/common/plugin_messages.h"
30 #include "content/common/view_messages.h"
31 #include "content/public/renderer/content_renderer_client.h"
32 #include "content/renderer/plugin_channel_host.h"
33 #include "content/renderer/render_thread_impl.h"
34 #include "content/renderer/render_view_impl.h"
35 #include "ipc/ipc_channel_handle.h"
36 #include "net/base/mime_util.h"
37 #include "skia/ext/platform_canvas.h"
38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
40 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
41 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebDragData.h"
42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
43 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
45 #include "ui/gfx/blit.h"
46 #include "ui/gfx/canvas_skia.h"
47 #include "ui/gfx/native_widget_types.h"
48 #include "ui/gfx/size.h"
49 #include "webkit/plugins/npapi/plugin_group.h"
50 #include "webkit/plugins/npapi/webplugin.h"
51 #include "webkit/plugins/sad_plugin.h"
52 #include "webkit/glue/webkit_glue.h"
54 #if defined(OS_POSIX)
55 #include "ipc/ipc_channel_posix.h"
56 #endif
58 #if defined(OS_MACOSX)
59 #include "base/mac/mac_util.h"
60 #endif
62 using WebKit::WebBindings;
63 using WebKit::WebCursorInfo;
64 using WebKit::WebDragData;
65 using WebKit::WebInputEvent;
66 using WebKit::WebString;
67 using WebKit::WebView;
69 // Proxy for WebPluginResourceClient. The object owns itself after creation,
70 // deleting itself after its callback has been called.
71 class ResourceClientProxy : public webkit::npapi::WebPluginResourceClient {
72 public:
73 ResourceClientProxy(PluginChannelHost* channel, int instance_id)
74 : channel_(channel), instance_id_(instance_id), resource_id_(0),
75 multibyte_response_expected_(false) {
78 ~ResourceClientProxy() {
81 void Initialize(unsigned long resource_id, const GURL& url, int notify_id) {
82 resource_id_ = resource_id;
83 channel_->Send(new PluginMsg_HandleURLRequestReply(
84 instance_id_, resource_id, url, notify_id));
87 void InitializeForSeekableStream(unsigned long resource_id,
88 int range_request_id) {
89 resource_id_ = resource_id;
90 multibyte_response_expected_ = true;
91 channel_->Send(new PluginMsg_HTTPRangeRequestReply(
92 instance_id_, resource_id, range_request_id));
95 // PluginResourceClient implementation:
96 void WillSendRequest(const GURL& url, int http_status_code) {
97 DCHECK(channel_ != NULL);
98 channel_->Send(new PluginMsg_WillSendRequest(instance_id_, resource_id_,
99 url, http_status_code));
102 void DidReceiveResponse(const std::string& mime_type,
103 const std::string& headers,
104 uint32 expected_length,
105 uint32 last_modified,
106 bool request_is_seekable) {
107 DCHECK(channel_ != NULL);
108 PluginMsg_DidReceiveResponseParams params;
109 params.id = resource_id_;
110 params.mime_type = mime_type;
111 params.headers = headers;
112 params.expected_length = expected_length;
113 params.last_modified = last_modified;
114 params.request_is_seekable = request_is_seekable;
115 // Grab a reference on the underlying channel so it does not get
116 // deleted from under us.
117 scoped_refptr<PluginChannelHost> channel_ref(channel_);
118 channel_->Send(new PluginMsg_DidReceiveResponse(instance_id_, params));
121 void DidReceiveData(const char* buffer, int length, int data_offset) {
122 DCHECK(channel_ != NULL);
123 DCHECK_GT(length, 0);
124 std::vector<char> data;
125 data.resize(static_cast<size_t>(length));
126 memcpy(&data.front(), buffer, length);
127 // Grab a reference on the underlying channel so it does not get
128 // deleted from under us.
129 scoped_refptr<PluginChannelHost> channel_ref(channel_);
130 channel_->Send(new PluginMsg_DidReceiveData(instance_id_, resource_id_,
131 data, data_offset));
134 void DidFinishLoading() {
135 DCHECK(channel_ != NULL);
136 channel_->Send(new PluginMsg_DidFinishLoading(instance_id_, resource_id_));
137 channel_ = NULL;
138 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
141 void DidFail() {
142 DCHECK(channel_ != NULL);
143 channel_->Send(new PluginMsg_DidFail(instance_id_, resource_id_));
144 channel_ = NULL;
145 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
148 bool IsMultiByteResponseExpected() {
149 return multibyte_response_expected_;
152 int ResourceId() {
153 return resource_id_;
156 private:
157 scoped_refptr<PluginChannelHost> channel_;
158 int instance_id_;
159 unsigned long resource_id_;
160 // Set to true if the response expected is a multibyte response.
161 // For e.g. response for a HTTP byte range request.
162 bool multibyte_response_expected_;
165 WebPluginDelegateProxy::WebPluginDelegateProxy(
166 const std::string& mime_type,
167 const base::WeakPtr<RenderViewImpl>& render_view)
168 : render_view_(render_view),
169 plugin_(NULL),
170 uses_shared_bitmaps_(false),
171 #if defined(OS_MACOSX)
172 uses_compositor_(false),
173 #endif
174 window_(gfx::kNullPluginWindow),
175 mime_type_(mime_type),
176 instance_id_(MSG_ROUTING_NONE),
177 npobject_(NULL),
178 sad_plugin_(NULL),
179 invalidate_pending_(false),
180 transparent_(false),
181 front_buffer_index_(0),
182 page_url_(render_view_->webview()->mainFrame()->document().url()) {
185 WebPluginDelegateProxy::~WebPluginDelegateProxy() {
186 if (npobject_)
187 WebBindings::releaseObject(npobject_);
190 WebPluginDelegateProxy::SharedBitmap::SharedBitmap() {}
192 WebPluginDelegateProxy::SharedBitmap::~SharedBitmap() {}
194 void WebPluginDelegateProxy::PluginDestroyed() {
195 #if defined(OS_MACOSX) || defined(OS_WIN)
196 // Ensure that the renderer doesn't think the plugin still has focus.
197 if (render_view_)
198 render_view_->PluginFocusChanged(false, instance_id_);
199 #endif
201 if (window_)
202 WillDestroyWindow();
204 if (render_view_)
205 render_view_->UnregisterPluginDelegate(this);
207 if (channel_host_) {
208 Send(new PluginMsg_DestroyInstance(instance_id_));
210 // Must remove the route after sending the destroy message, since
211 // RemoveRoute can lead to all the outstanding NPObjects being told the
212 // channel went away if this was the last instance.
213 channel_host_->RemoveRoute(instance_id_);
215 // Release the channel host now. If we are is the last reference to the
216 // channel, this avoids a race where this renderer asks a new connection to
217 // the same plugin between now and the time 'this' is actually deleted.
218 // Destroying the channel host is what releases the channel name -> FD
219 // association on POSIX, and if we ask for a new connection before it is
220 // released, the plugin will give us a new FD, and we'll assert when trying
221 // to associate it with the channel name.
222 channel_host_ = NULL;
225 if (window_script_object_) {
226 // Release the window script object, if the plugin didn't already.
227 // If we don't do this then it will linger until the last plugin instance is
228 // destroyed. In the meantime, though, the frame that it refers to may have
229 // been destroyed by WebKit, at which point WebKit will forcibly deallocate
230 // the window script object. The window script object stub is unique to the
231 // plugin instance, so this won't affect other instances.
232 window_script_object_->DeleteSoon();
235 plugin_ = NULL;
237 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
240 // Returns true if the given Silverlight 'background' value corresponds to
241 // one that should make the plugin transparent. See:
242 // http://msdn.microsoft.com/en-us/library/cc838148(VS.95).aspx
243 // for possible values.
244 static bool SilverlightColorIsTransparent(const std::string& color) {
245 if (StartsWithASCII(color, "#", false)) {
246 // If it's #ARGB or #AARRGGBB check the alpha; if not it's an RGB form and
247 // it's not transparent.
248 if ((color.length() == 5 && !StartsWithASCII(color, "#F", false)) ||
249 (color.length() == 9 && !StartsWithASCII(color, "#FF", false)))
250 return true;
251 } else if (StartsWithASCII(color, "sc#", false)) {
252 // It's either sc#A,R,G,B or sc#R,G,B; if the former, check the alpha.
253 if (color.length() < 4)
254 return false;
255 std::string value_string = color.substr(3, std::string::npos);
256 std::vector<std::string> components;
257 base::SplitString(value_string, ',', &components);
258 if (components.size() == 4 && !StartsWithASCII(components[0], "1", false))
259 return true;
260 } else if (LowerCaseEqualsASCII(color, "transparent")) {
261 return true;
263 // Anything else is a named, opaque color or an RGB form with no alpha.
264 return false;
267 bool WebPluginDelegateProxy::Initialize(
268 const GURL& url,
269 const std::vector<std::string>& arg_names,
270 const std::vector<std::string>& arg_values,
271 webkit::npapi::WebPlugin* plugin,
272 bool load_manually) {
273 IPC::ChannelHandle channel_handle;
274 if (!RenderThreadImpl::current()->Send(new ViewHostMsg_OpenChannelToPlugin(
275 render_view_->routing_id(), url, page_url_, mime_type_,
276 &channel_handle, &info_))) {
277 return false;
280 if (channel_handle.name.empty()) {
281 // We got an invalid handle. Either the plugin couldn't be found (which
282 // shouldn't happen, since if we got here the plugin should exist) or the
283 // plugin crashed on initialization.
284 if (!info_.path.empty()) {
285 render_view_->PluginCrashed(info_.path);
286 LOG(ERROR) << "Plug-in crashed on start";
288 // Return true so that the plugin widget is created and we can paint the
289 // crashed plugin there.
290 return true;
292 LOG(ERROR) << "Plug-in couldn't be found";
293 return false;
296 scoped_refptr<PluginChannelHost> channel_host(
297 PluginChannelHost::GetPluginChannelHost(
298 channel_handle, ChildProcess::current()->io_message_loop_proxy()));
299 if (!channel_host.get()) {
300 LOG(ERROR) << "Couldn't get PluginChannelHost";
301 return false;
304 int instance_id;
305 bool result = channel_host->Send(new PluginMsg_CreateInstance(
306 mime_type_, &instance_id));
307 if (!result) {
308 LOG(ERROR) << "Couldn't send PluginMsg_CreateInstance";
309 return false;
312 channel_host_ = channel_host;
313 instance_id_ = instance_id;
315 channel_host_->AddRoute(instance_id_, this, NULL);
317 // Now tell the PluginInstance in the plugin process to initialize.
318 PluginMsg_Init_Params params;
319 params.containing_window = render_view_->host_window();
320 params.url = url;
321 params.page_url = page_url_;
322 params.arg_names = arg_names;
323 params.arg_values = arg_values;
324 params.host_render_view_routing_id = render_view_->routing_id();
326 bool flash =
327 LowerCaseEqualsASCII(mime_type_, "application/x-shockwave-flash");
328 bool silverlight =
329 StartsWithASCII(mime_type_, "application/x-silverlight", false);
330 for (size_t i = 0; i < arg_names.size(); ++i) {
331 if ((flash && LowerCaseEqualsASCII(arg_names[i], "wmode") &&
332 LowerCaseEqualsASCII(arg_values[i], "transparent")) ||
333 (silverlight && LowerCaseEqualsASCII(arg_names[i], "background") &&
334 SilverlightColorIsTransparent(arg_values[i]))) {
335 transparent_ = true;
338 params.load_manually = load_manually;
340 plugin_ = plugin;
342 result = false;
343 IPC::Message* msg = new PluginMsg_Init(instance_id_, params, &result);
344 Send(msg);
346 if (!result)
347 LOG(ERROR) << "PluginMsg_Init returned false";
349 render_view_->RegisterPluginDelegate(this);
351 return result;
354 bool WebPluginDelegateProxy::Send(IPC::Message* msg) {
355 if (!channel_host_) {
356 DLOG(WARNING) << "dropping message because channel host is null";
357 delete msg;
358 return false;
361 return channel_host_->Send(msg);
364 void WebPluginDelegateProxy::SendJavaScriptStream(const GURL& url,
365 const std::string& result,
366 bool success,
367 int notify_id) {
368 Send(new PluginMsg_SendJavaScriptStream(
369 instance_id_, url, result, success, notify_id));
372 void WebPluginDelegateProxy::DidReceiveManualResponse(
373 const GURL& url, const std::string& mime_type,
374 const std::string& headers, uint32 expected_length,
375 uint32 last_modified) {
376 PluginMsg_DidReceiveResponseParams params;
377 params.id = 0;
378 params.mime_type = mime_type;
379 params.headers = headers;
380 params.expected_length = expected_length;
381 params.last_modified = last_modified;
382 Send(new PluginMsg_DidReceiveManualResponse(instance_id_, url, params));
385 void WebPluginDelegateProxy::DidReceiveManualData(const char* buffer,
386 int length) {
387 DCHECK_GT(length, 0);
388 std::vector<char> data;
389 data.resize(static_cast<size_t>(length));
390 memcpy(&data.front(), buffer, length);
391 Send(new PluginMsg_DidReceiveManualData(instance_id_, data));
394 void WebPluginDelegateProxy::DidFinishManualLoading() {
395 Send(new PluginMsg_DidFinishManualLoading(instance_id_));
398 void WebPluginDelegateProxy::DidManualLoadFail() {
399 Send(new PluginMsg_DidManualLoadFail(instance_id_));
402 bool WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) {
403 content::GetContentClient()->SetActiveURL(page_url_);
405 bool handled = true;
406 IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy, msg)
407 IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow, OnSetWindow)
408 #if defined(OS_WIN)
409 IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindowlessPumpEvent,
410 OnSetWindowlessPumpEvent)
411 IPC_MESSAGE_HANDLER(PluginHostMsg_NotifyIMEStatus,
412 OnNotifyIMEStatus)
413 #endif
414 IPC_MESSAGE_HANDLER(PluginHostMsg_CancelResource, OnCancelResource)
415 IPC_MESSAGE_HANDLER(PluginHostMsg_InvalidateRect, OnInvalidateRect)
416 IPC_MESSAGE_HANDLER(PluginHostMsg_GetWindowScriptNPObject,
417 OnGetWindowScriptNPObject)
418 IPC_MESSAGE_HANDLER(PluginHostMsg_GetPluginElement,
419 OnGetPluginElement)
420 IPC_MESSAGE_HANDLER(PluginHostMsg_ResolveProxy, OnResolveProxy)
421 IPC_MESSAGE_HANDLER(PluginHostMsg_SetCookie, OnSetCookie)
422 IPC_MESSAGE_HANDLER(PluginHostMsg_GetCookies, OnGetCookies)
423 IPC_MESSAGE_HANDLER(PluginHostMsg_URLRequest, OnHandleURLRequest)
424 IPC_MESSAGE_HANDLER(PluginHostMsg_CancelDocumentLoad, OnCancelDocumentLoad)
425 IPC_MESSAGE_HANDLER(PluginHostMsg_InitiateHTTPRangeRequest,
426 OnInitiateHTTPRangeRequest)
427 IPC_MESSAGE_HANDLER(PluginHostMsg_DeferResourceLoading,
428 OnDeferResourceLoading)
430 #if defined(OS_MACOSX)
431 IPC_MESSAGE_HANDLER(PluginHostMsg_FocusChanged,
432 OnFocusChanged);
433 IPC_MESSAGE_HANDLER(PluginHostMsg_StartIme,
434 OnStartIme);
435 IPC_MESSAGE_HANDLER(PluginHostMsg_BindFakePluginWindowHandle,
436 OnBindFakePluginWindowHandle);
437 // Used only on 10.6 and later.
438 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedSurfaceSetIOSurface,
439 OnAcceleratedSurfaceSetIOSurface)
440 // Used on 10.5 and earlier.
441 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedSurfaceSetTransportDIB,
442 OnAcceleratedSurfaceSetTransportDIB)
443 IPC_MESSAGE_HANDLER(PluginHostMsg_AllocTransportDIB,
444 OnAcceleratedSurfaceAllocTransportDIB)
445 IPC_MESSAGE_HANDLER(PluginHostMsg_FreeTransportDIB,
446 OnAcceleratedSurfaceFreeTransportDIB)
447 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedSurfaceBuffersSwapped,
448 OnAcceleratedSurfaceBuffersSwapped)
449 // Used only on 10.6 and later.
450 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedPluginEnabledRendering,
451 OnAcceleratedPluginEnabledRendering)
452 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedPluginAllocatedIOSurface,
453 OnAcceleratedPluginAllocatedIOSurface)
454 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedPluginSwappedIOSurface,
455 OnAcceleratedPluginSwappedIOSurface)
456 #endif
457 IPC_MESSAGE_HANDLER(PluginHostMsg_URLRedirectResponse,
458 OnURLRedirectResponse)
459 IPC_MESSAGE_UNHANDLED(handled = false)
460 IPC_END_MESSAGE_MAP()
461 DCHECK(handled);
462 return handled;
465 void WebPluginDelegateProxy::OnChannelError() {
466 if (plugin_) {
467 if (window_) {
468 // The actual WebPluginDelegate never got a chance to tell the WebPlugin
469 // its window was going away. Do it on its behalf.
470 WillDestroyWindow();
472 plugin_->Invalidate();
474 if (!channel_host_->expecting_shutdown())
475 render_view_->PluginCrashed(info_.path);
477 #if defined(OS_MACOSX) || defined(OS_WIN)
478 // Ensure that the renderer doesn't think the plugin still has focus.
479 if (render_view_)
480 render_view_->PluginFocusChanged(false, instance_id_);
481 #endif
484 static void CopyTransportDIBHandleForMessage(
485 const TransportDIB::Handle& handle_in,
486 TransportDIB::Handle* handle_out) {
487 #if defined(OS_MACOSX)
488 // On Mac, TransportDIB::Handle is typedef'ed to FileDescriptor, and
489 // FileDescriptor message fields needs to remain valid until the message is
490 // sent or else the sendmsg() call will fail.
491 if ((handle_out->fd = HANDLE_EINTR(dup(handle_in.fd))) < 0) {
492 PLOG(ERROR) << "dup()";
493 return;
495 handle_out->auto_close = true;
496 #else
497 // Don't need to do anything special for other platforms.
498 *handle_out = handle_in;
499 #endif
502 void WebPluginDelegateProxy::SendUpdateGeometry(
503 bool bitmaps_changed) {
504 PluginMsg_UpdateGeometry_Param param;
505 param.window_rect = plugin_rect_;
506 param.clip_rect = clip_rect_;
507 param.windowless_buffer0 = TransportDIB::DefaultHandleValue();
508 param.windowless_buffer1 = TransportDIB::DefaultHandleValue();
509 param.windowless_buffer_index = back_buffer_index();
510 param.background_buffer = TransportDIB::DefaultHandleValue();
511 param.transparent = transparent_;
513 #if defined(OS_POSIX)
514 // If we're using POSIX mmap'd TransportDIBs, sending the handle across
515 // IPC establishes a new mapping rather than just sending a window ID,
516 // so only do so if we've actually changed the shared memory bitmaps.
517 if (bitmaps_changed)
518 #endif
520 if (transport_stores_[0].dib.get())
521 CopyTransportDIBHandleForMessage(transport_stores_[0].dib->handle(),
522 &param.windowless_buffer0);
524 if (transport_stores_[1].dib.get())
525 CopyTransportDIBHandleForMessage(transport_stores_[1].dib->handle(),
526 &param.windowless_buffer1);
528 if (background_store_.dib.get())
529 CopyTransportDIBHandleForMessage(background_store_.dib->handle(),
530 &param.background_buffer);
533 IPC::Message* msg;
534 #if defined(OS_WIN)
535 if (UseSynchronousGeometryUpdates()) {
536 msg = new PluginMsg_UpdateGeometrySync(instance_id_, param);
537 } else // NOLINT
538 #endif
540 msg = new PluginMsg_UpdateGeometry(instance_id_, param);
541 msg->set_unblock(true);
544 Send(msg);
547 void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
548 const gfx::Rect& clip_rect) {
549 // window_rect becomes either a window in native windowing system
550 // coords, or a backing buffer. In either case things will go bad
551 // if the rectangle is very large.
552 if (window_rect.width() < 0 || window_rect.width() > (1<<15) ||
553 window_rect.height() < 0 || window_rect.height() > (1<<15) ||
554 // Clip to 8m pixels; we know this won't overflow due to above checks.
555 window_rect.width() * window_rect.height() > (8<<20)) {
556 return;
559 plugin_rect_ = window_rect;
560 clip_rect_ = clip_rect;
562 bool bitmaps_changed = false;
564 if (uses_shared_bitmaps_) {
565 if (!front_buffer_canvas() ||
566 (window_rect.width() != front_buffer_canvas()->getDevice()->width() ||
567 window_rect.height() != front_buffer_canvas()->getDevice()->height()))
569 bitmaps_changed = true;
571 bool needs_background_store = transparent_;
572 #if defined(OS_MACOSX)
573 // We don't support transparency under QuickDraw, and CoreGraphics
574 // preserves transparency information (and does the compositing itself)
575 // so plugins don't need access to the page background.
576 needs_background_store = false;
577 #endif
579 // Create a shared memory section that the plugin paints into
580 // asynchronously.
581 ResetWindowlessBitmaps();
582 if (!window_rect.IsEmpty()) {
583 if (!CreateSharedBitmap(&transport_stores_[0].dib,
584 &transport_stores_[0].canvas) ||
585 !CreateSharedBitmap(&transport_stores_[1].dib,
586 &transport_stores_[1].canvas) ||
587 (needs_background_store &&
588 !CreateSharedBitmap(&background_store_.dib,
589 &background_store_.canvas))) {
590 DCHECK(false);
591 ResetWindowlessBitmaps();
592 return;
598 SendUpdateGeometry(bitmaps_changed);
601 void WebPluginDelegateProxy::ResetWindowlessBitmaps() {
602 transport_stores_[0].dib.reset();
603 transport_stores_[1].dib.reset();
604 background_store_.dib.reset();
606 transport_stores_[0].canvas.reset();
607 transport_stores_[1].canvas.reset();
608 background_store_.canvas.reset();
609 transport_store_painted_ = gfx::Rect();
610 front_buffer_diff_ = gfx::Rect();
613 static size_t BitmapSizeForPluginRect(const gfx::Rect& plugin_rect) {
614 const size_t stride =
615 skia::PlatformCanvas::StrideForWidth(plugin_rect.width());
616 return stride * plugin_rect.height();
619 #if !defined(OS_WIN)
620 bool WebPluginDelegateProxy::CreateLocalBitmap(
621 std::vector<uint8>* memory,
622 scoped_ptr<skia::PlatformCanvas>* canvas) {
623 const size_t size = BitmapSizeForPluginRect(plugin_rect_);
624 memory->resize(size);
625 if (memory->size() != size)
626 return false;
627 canvas->reset(new skia::PlatformCanvas(
628 plugin_rect_.width(), plugin_rect_.height(), true, &((*memory)[0])));
629 return true;
631 #endif
633 bool WebPluginDelegateProxy::CreateSharedBitmap(
634 scoped_ptr<TransportDIB>* memory,
635 scoped_ptr<skia::PlatformCanvas>* canvas) {
636 const size_t size = BitmapSizeForPluginRect(plugin_rect_);
637 #if defined(OS_POSIX) && !defined(OS_MACOSX)
638 memory->reset(TransportDIB::Create(size, 0));
639 if (!memory->get())
640 return false;
641 #endif
642 #if defined(OS_MACOSX)
643 TransportDIB::Handle handle;
644 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, false, &handle);
645 if (!RenderThreadImpl::current()->Send(msg))
646 return false;
647 if (handle.fd < 0)
648 return false;
649 memory->reset(TransportDIB::Map(handle));
650 #else
651 static uint32 sequence_number = 0;
652 memory->reset(TransportDIB::Create(size, sequence_number++));
653 #endif
654 canvas->reset((*memory)->GetPlatformCanvas(plugin_rect_.width(),
655 plugin_rect_.height()));
656 return !!canvas->get();
659 #if defined(OS_MACOSX)
660 // Flips |rect| vertically within an enclosing rect with height |height|.
661 // Intended for converting rects between flipped and non-flipped contexts.
662 static void FlipRectVerticallyWithHeight(gfx::Rect* rect, int height) {
663 rect->set_y(height - rect->bottom());
665 #endif
667 void WebPluginDelegateProxy::Paint(WebKit::WebCanvas* canvas,
668 const gfx::Rect& damaged_rect) {
669 // Limit the damaged rectangle to whatever is contained inside the plugin
670 // rectangle, as that's the rectangle that we'll actually draw.
671 gfx::Rect rect = damaged_rect.Intersect(plugin_rect_);
673 // If the plugin is no longer connected (channel crashed) draw a crashed
674 // plugin bitmap
675 if (!channel_host_ || !channel_host_->channel_valid()) {
676 PaintSadPlugin(canvas, rect);
677 return;
680 if (!uses_shared_bitmaps_)
681 return;
683 // We got a paint before the plugin's coordinates, so there's no buffer to
684 // copy from.
685 if (!front_buffer_canvas())
686 return;
688 // We're using the native OS APIs from here on out.
689 #if WEBKIT_USING_SKIA
690 if (!skia::SupportsPlatformPaint(canvas)) {
691 // TODO(alokp): Implement this path.
692 // This block will only get hit with --enable-accelerated-drawing flag.
693 // With accelerated canvas, we do not have a bitmap that can be provided
694 // to the plugin for compositing. We may have to implement a solution
695 // described in crbug.com/12586.
696 DLOG(WARNING) << "Could not paint plugin";
697 return;
699 skia::ScopedPlatformPaint scoped_platform_paint(canvas);
700 gfx::NativeDrawingContext context =
701 scoped_platform_paint.GetPlatformSurface();
702 #elif WEBKIT_USING_CG
703 gfx::NativeDrawingContext context = canvas;
704 #endif
706 gfx::Rect offset_rect = rect;
707 offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y());
708 gfx::Rect canvas_rect = offset_rect;
709 #if defined(OS_MACOSX)
710 // The canvases are flipped relative to the context, so flip the rect too.
711 FlipRectVerticallyWithHeight(&canvas_rect, plugin_rect_.height());
712 #endif
714 bool background_changed = false;
715 if (background_store_.canvas.get() && BackgroundChanged(context, rect)) {
716 background_changed = true;
717 BlitContextToCanvas(background_store_.canvas.get(), canvas_rect,
718 context, rect.origin());
721 // transport_store_painted_ is really a bounding box, so in principle this
722 // check could falsely indicate that we don't need to paint offset_rect, but
723 // in practice it works fine.
724 if (background_changed ||
725 !transport_store_painted_.Contains(offset_rect)) {
726 Send(new PluginMsg_Paint(instance_id_, offset_rect));
727 // Since the plugin is not blocked on the renderer in this context, there is
728 // a chance that it will begin repainting the back-buffer before we complete
729 // capturing the data. Buffer flipping would increase that risk because
730 // geometry update is asynchronous, so we don't want to use buffer flipping
731 // here.
732 UpdateFrontBuffer(offset_rect, false);
735 #if defined(OS_MACOSX)
736 // The canvases are flipped relative to the context, so flip the context's
737 // coordinate space so that the blit unflips the content.
738 CGContextSaveGState(context);
739 CGContextScaleCTM(context, 1, -1);
740 rect.set_y(-rect.bottom());
741 #endif
742 BlitCanvasToContext(context,
743 rect,
744 front_buffer_canvas(),
745 offset_rect.origin());
746 #if defined(OS_MACOSX)
747 CGContextRestoreGState(context);
748 #endif
750 if (invalidate_pending_) {
751 // Only send the PaintAck message if this paint is in response to an
752 // invalidate from the plugin, since this message acts as an access token
753 // to ensure only one process is using the transport dib at a time.
754 invalidate_pending_ = false;
755 Send(new PluginMsg_DidPaint(instance_id_));
759 bool WebPluginDelegateProxy::BackgroundChanged(
760 gfx::NativeDrawingContext context,
761 const gfx::Rect& rect) {
762 #if defined(OS_ANDROID)
763 NOTIMPLEMENTED();
764 #else
765 #if defined(OS_WIN)
766 HBITMAP hbitmap = static_cast<HBITMAP>(GetCurrentObject(context, OBJ_BITMAP));
767 if (hbitmap == NULL) {
768 NOTREACHED();
769 return true;
772 BITMAP bitmap = { 0 };
773 int result = GetObject(hbitmap, sizeof(bitmap), &bitmap);
774 if (!result) {
775 NOTREACHED();
776 return true;
779 XFORM xf;
780 if (!GetWorldTransform(context, &xf)) {
781 NOTREACHED();
782 return true;
785 // The damaged rect that we're given can be larger than the bitmap, so
786 // intersect their rects first.
787 gfx::Rect bitmap_rect(static_cast<int>(-xf.eDx), static_cast<int>(-xf.eDy),
788 bitmap.bmWidth, bitmap.bmHeight);
789 gfx::Rect check_rect = rect.Intersect(bitmap_rect);
790 int row_byte_size = check_rect.width() * (bitmap.bmBitsPixel / 8);
791 for (int y = check_rect.y(); y < check_rect.bottom(); y++) {
792 char* hdc_row_start = static_cast<char*>(bitmap.bmBits) +
793 (y + static_cast<int>(xf.eDy)) * bitmap.bmWidthBytes +
794 (check_rect.x() + static_cast<int>(xf.eDx)) * (bitmap.bmBitsPixel / 8);
796 // getAddr32 doesn't use the translation units, so we have to subtract
797 // the plugin origin from the coordinates.
798 uint32_t* canvas_row_start =
799 background_store_.canvas->getDevice()->accessBitmap(true).getAddr32(
800 check_rect.x() - plugin_rect_.x(), y - plugin_rect_.y());
801 if (memcmp(hdc_row_start, canvas_row_start, row_byte_size) != 0)
802 return true;
804 #else
805 #if defined(OS_MACOSX)
806 // If there is a translation on the content area context, we need to account
807 // for it; the context may be a subset of the full content area with a
808 // transform that makes the coordinates work out.
809 CGAffineTransform transform = CGContextGetCTM(context);
810 bool flipped = fabs(transform.d + 1) < 0.0001;
811 CGFloat context_offset_x = -transform.tx;
812 CGFloat context_offset_y = flipped ? transform.ty -
813 CGBitmapContextGetHeight(context)
814 : -transform.ty;
815 gfx::Rect full_content_rect(context_offset_x, context_offset_y,
816 CGBitmapContextGetWidth(context),
817 CGBitmapContextGetHeight(context));
818 #else
819 cairo_surface_t* page_surface = cairo_get_target(context);
820 DCHECK_EQ(cairo_surface_get_type(page_surface), CAIRO_SURFACE_TYPE_IMAGE);
821 DCHECK_EQ(cairo_image_surface_get_format(page_surface), CAIRO_FORMAT_ARGB32);
823 // Transform context coordinates into surface coordinates.
824 double page_x_double = rect.x();
825 double page_y_double = rect.y();
826 cairo_user_to_device(context, &page_x_double, &page_y_double);
827 gfx::Rect full_content_rect(0, 0,
828 cairo_image_surface_get_width(page_surface),
829 cairo_image_surface_get_height(page_surface));
830 #endif
831 // According to comments in the Windows code, the damage rect that we're given
832 // may project outside the image, so intersect their rects.
833 gfx::Rect content_rect = rect.Intersect(full_content_rect);
835 #if defined(OS_MACOSX)
836 const unsigned char* page_bytes = static_cast<const unsigned char*>(
837 CGBitmapContextGetData(context));
838 int page_stride = CGBitmapContextGetBytesPerRow(context);
839 int page_start_x = content_rect.x() - context_offset_x;
840 int page_start_y = content_rect.y() - context_offset_y;
842 skia::ScopedPlatformPaint scoped_platform_paint(
843 background_store_.canvas.get());
844 CGContextRef bg_context = scoped_platform_paint.GetPlatformSurface();
846 DCHECK_EQ(CGBitmapContextGetBitsPerPixel(context),
847 CGBitmapContextGetBitsPerPixel(bg_context));
848 const unsigned char* bg_bytes = static_cast<const unsigned char*>(
849 CGBitmapContextGetData(bg_context));
850 int full_bg_width = CGBitmapContextGetWidth(bg_context);
851 int full_bg_height = CGBitmapContextGetHeight(bg_context);
852 int bg_stride = CGBitmapContextGetBytesPerRow(bg_context);
853 int bg_last_row = CGBitmapContextGetHeight(bg_context) - 1;
855 int bytes_per_pixel = CGBitmapContextGetBitsPerPixel(context) / 8;
856 #else
857 cairo_surface_flush(page_surface);
858 const unsigned char* page_bytes = cairo_image_surface_get_data(page_surface);
859 int page_stride = cairo_image_surface_get_stride(page_surface);
860 int page_start_x = static_cast<int>(page_x_double);
861 int page_start_y = static_cast<int>(page_y_double);
863 skia::ScopedPlatformPaint scoped_platform_paint(
864 background_store_.canvas.get());
865 cairo_surface_t* bg_surface =cairo_get_target(
866 scoped_platform_paint.GetPlatformSurface());
867 DCHECK_EQ(cairo_surface_get_type(bg_surface), CAIRO_SURFACE_TYPE_IMAGE);
868 DCHECK_EQ(cairo_image_surface_get_format(bg_surface), CAIRO_FORMAT_ARGB32);
869 cairo_surface_flush(bg_surface);
870 const unsigned char* bg_bytes = cairo_image_surface_get_data(bg_surface);
871 int full_bg_width = cairo_image_surface_get_width(bg_surface);
872 int full_bg_height = cairo_image_surface_get_height(bg_surface);
873 int bg_stride = cairo_image_surface_get_stride(bg_surface);
875 int bytes_per_pixel = 4; // ARGB32 = 4 bytes per pixel.
876 #endif
878 int damage_width = content_rect.width();
879 int damage_height = content_rect.height();
881 int bg_start_x = rect.x() - plugin_rect_.x();
882 int bg_start_y = rect.y() - plugin_rect_.y();
883 // The damage rect is supposed to have been intersected with the plugin rect;
884 // double-check, since if it hasn't we'll walk off the end of the buffer.
885 DCHECK_LE(bg_start_x + damage_width, full_bg_width);
886 DCHECK_LE(bg_start_y + damage_height, full_bg_height);
888 int bg_x_byte_offset = bg_start_x * bytes_per_pixel;
889 int page_x_byte_offset = page_start_x * bytes_per_pixel;
890 for (int row = 0; row < damage_height; ++row) {
891 int page_offset = page_stride * (page_start_y + row) + page_x_byte_offset;
892 int bg_y = bg_start_y + row;
893 #if defined(OS_MACOSX)
894 // The background buffer is upside down relative to the content.
895 bg_y = bg_last_row - bg_y;
896 #endif
897 int bg_offset = bg_stride * bg_y + bg_x_byte_offset;
898 if (memcmp(page_bytes + page_offset,
899 bg_bytes + bg_offset,
900 damage_width * bytes_per_pixel) != 0)
901 return true;
903 #endif
904 #endif // OS_ANDROID
906 return false;
909 NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() {
910 if (npobject_)
911 return WebBindings::retainObject(npobject_);
913 int route_id = MSG_ROUTING_NONE;
914 Send(new PluginMsg_GetPluginScriptableObject(instance_id_, &route_id));
915 if (route_id == MSG_ROUTING_NONE)
916 return NULL;
918 npobject_ = NPObjectProxy::Create(
919 channel_host_.get(), route_id, 0, page_url_);
921 return WebBindings::retainObject(npobject_);
924 bool WebPluginDelegateProxy::GetFormValue(string16* value) {
925 bool success = false;
926 Send(new PluginMsg_GetFormValue(instance_id_, value, &success));
927 return success;
930 void WebPluginDelegateProxy::DidFinishLoadWithReason(
931 const GURL& url, NPReason reason, int notify_id) {
932 Send(new PluginMsg_DidFinishLoadWithReason(
933 instance_id_, url, reason, notify_id));
936 void WebPluginDelegateProxy::SetFocus(bool focused) {
937 Send(new PluginMsg_SetFocus(instance_id_, focused));
938 #if defined(OS_WIN)
939 if (render_view_)
940 render_view_->PluginFocusChanged(focused, instance_id_);
941 #endif
944 bool WebPluginDelegateProxy::HandleInputEvent(
945 const WebInputEvent& event,
946 WebCursorInfo* cursor_info) {
947 bool handled;
948 WebCursor cursor;
949 // A windowless plugin can enter a modal loop in the context of a
950 // NPP_HandleEvent call, in which case we need to pump messages to
951 // the plugin. We pass of the corresponding event handle to the
952 // plugin process, which is set if the plugin does enter a modal loop.
953 IPC::SyncMessage* message = new PluginMsg_HandleInputEvent(
954 instance_id_, &event, &handled, &cursor);
955 message->set_pump_messages_event(modal_loop_pump_messages_event_.get());
956 Send(message);
957 cursor.GetCursorInfo(cursor_info);
958 return handled;
961 int WebPluginDelegateProxy::GetProcessId() {
962 return channel_host_->peer_pid();
965 void WebPluginDelegateProxy::SetContentAreaFocus(bool has_focus) {
966 IPC::Message* msg = new PluginMsg_SetContentAreaFocus(instance_id_,
967 has_focus);
968 // Make sure focus events are delivered in the right order relative to
969 // sync messages they might interact with (Paint, HandleEvent, etc.).
970 msg->set_unblock(true);
971 Send(msg);
974 #if defined(OS_WIN)
975 void WebPluginDelegateProxy::ImeCompositionUpdated(
976 const string16& text,
977 const std::vector<int>& clauses,
978 const std::vector<int>& target,
979 int cursor_position,
980 int plugin_id) {
981 // Dispatch the raw IME data if this plug-in is the focused one.
982 if (instance_id_ != plugin_id)
983 return;
985 IPC::Message* msg = new PluginMsg_ImeCompositionUpdated(instance_id_,
986 text, clauses, target, cursor_position);
987 msg->set_unblock(true);
988 Send(msg);
991 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16& text,
992 int plugin_id) {
993 // Dispatch the IME text if this plug-in is the focused one.
994 if (instance_id_ != plugin_id)
995 return;
997 IPC::Message* msg = new PluginMsg_ImeCompositionCompleted(instance_id_, text);
998 msg->set_unblock(true);
999 Send(msg);
1001 #endif
1003 #if defined(OS_MACOSX)
1004 void WebPluginDelegateProxy::SetWindowFocus(bool window_has_focus) {
1005 IPC::Message* msg = new PluginMsg_SetWindowFocus(instance_id_,
1006 window_has_focus);
1007 // Make sure focus events are delivered in the right order relative to
1008 // sync messages they might interact with (Paint, HandleEvent, etc.).
1009 msg->set_unblock(true);
1010 Send(msg);
1013 void WebPluginDelegateProxy::SetContainerVisibility(bool is_visible) {
1014 IPC::Message* msg;
1015 if (is_visible) {
1016 gfx::Rect window_frame = render_view_->rootWindowRect();
1017 gfx::Rect view_frame = render_view_->windowRect();
1018 WebKit::WebView* webview = render_view_->webview();
1019 msg = new PluginMsg_ContainerShown(instance_id_, window_frame, view_frame,
1020 webview && webview->isActive());
1021 } else {
1022 msg = new PluginMsg_ContainerHidden(instance_id_);
1024 // Make sure visibility events are delivered in the right order relative to
1025 // sync messages they might interact with (Paint, HandleEvent, etc.).
1026 msg->set_unblock(true);
1027 Send(msg);
1030 void WebPluginDelegateProxy::WindowFrameChanged(gfx::Rect window_frame,
1031 gfx::Rect view_frame) {
1032 IPC::Message* msg = new PluginMsg_WindowFrameChanged(instance_id_,
1033 window_frame,
1034 view_frame);
1035 // Make sure frame events are delivered in the right order relative to
1036 // sync messages they might interact with (e.g., HandleEvent).
1037 msg->set_unblock(true);
1038 Send(msg);
1040 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16& text,
1041 int plugin_id) {
1042 // If the message isn't intended for this plugin, there's nothing to do.
1043 if (instance_id_ != plugin_id)
1044 return;
1046 IPC::Message* msg = new PluginMsg_ImeCompositionCompleted(instance_id_,
1047 text);
1048 // Order relative to other key events is important.
1049 msg->set_unblock(true);
1050 Send(msg);
1052 #endif // OS_MACOSX
1054 void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window) {
1055 #if defined(OS_MACOSX)
1056 uses_shared_bitmaps_ = !window && !uses_compositor_;
1057 #else
1058 uses_shared_bitmaps_ = !window;
1059 #endif
1060 window_ = window;
1061 if (plugin_)
1062 plugin_->SetWindow(window);
1065 void WebPluginDelegateProxy::WillDestroyWindow() {
1066 DCHECK(window_);
1067 plugin_->WillDestroyWindow(window_);
1068 #if defined(OS_MACOSX)
1069 if (window_) {
1070 // This is actually a "fake" window handle only for the GPU
1071 // plugin. Deallocate it on the browser side.
1072 if (render_view_)
1073 render_view_->DestroyFakePluginWindowHandle(window_);
1075 #endif
1076 window_ = gfx::kNullPluginWindow;
1079 #if defined(OS_WIN)
1080 void WebPluginDelegateProxy::OnSetWindowlessPumpEvent(
1081 HANDLE modal_loop_pump_messages_event) {
1082 DCHECK(modal_loop_pump_messages_event_ == NULL);
1084 // Bug 25583: this can be null because some "virus scanners" block the
1085 // DuplicateHandle call in the plugin process.
1086 if (!modal_loop_pump_messages_event)
1087 return;
1089 modal_loop_pump_messages_event_.reset(
1090 new base::WaitableEvent(modal_loop_pump_messages_event));
1093 void WebPluginDelegateProxy::OnNotifyIMEStatus(int input_type,
1094 const gfx::Rect& caret_rect) {
1095 if (!render_view_)
1096 return;
1098 render_view_->Send(new ViewHostMsg_TextInputStateChanged(
1099 render_view_->routing_id(),
1100 static_cast<ui::TextInputType>(input_type),
1101 true));
1103 render_view_->Send(new ViewHostMsg_SelectionBoundsChanged(
1104 render_view_->routing_id(), caret_rect, caret_rect));
1106 #endif
1108 void WebPluginDelegateProxy::OnCancelResource(int id) {
1109 if (plugin_)
1110 plugin_->CancelResource(id);
1113 void WebPluginDelegateProxy::OnInvalidateRect(const gfx::Rect& rect,
1114 bool allow_buffer_flipping) {
1115 if (!plugin_)
1116 return;
1118 // Clip the invalidation rect to the plugin bounds; the plugin may have been
1119 // resized since the invalidate message was sent.
1120 const gfx::Rect clipped_rect(rect.Intersect(gfx::Rect(plugin_rect_.size())));
1122 invalidate_pending_ = true;
1123 // The plugin is blocked on the renderer because the invalidate message it has
1124 // sent us is synchronous, so we can use buffer flipping here if the caller
1125 // allows it.
1126 UpdateFrontBuffer(clipped_rect, allow_buffer_flipping);
1127 plugin_->InvalidateRect(clipped_rect);
1130 void WebPluginDelegateProxy::OnGetWindowScriptNPObject(
1131 int route_id, bool* success) {
1132 *success = false;
1133 NPObject* npobject = NULL;
1134 if (plugin_)
1135 npobject = plugin_->GetWindowScriptNPObject();
1137 if (!npobject)
1138 return;
1140 // The stub will delete itself when the proxy tells it that it's released, or
1141 // otherwise when the channel is closed.
1142 window_script_object_ = (new NPObjectStub(
1143 npobject, channel_host_.get(), route_id, 0, page_url_))->AsWeakPtr();
1144 *success = true;
1147 void WebPluginDelegateProxy::OnResolveProxy(const GURL& url,
1148 bool* result,
1149 std::string* proxy_list) {
1150 *result = false;
1151 RenderThreadImpl::current()->Send(
1152 new ViewHostMsg_ResolveProxy(url, result, proxy_list));
1155 void WebPluginDelegateProxy::OnGetPluginElement(int route_id, bool* success) {
1156 *success = false;
1157 NPObject* npobject = NULL;
1158 if (plugin_)
1159 npobject = plugin_->GetPluginElement();
1160 if (!npobject)
1161 return;
1163 // The stub will delete itself when the proxy tells it that it's released, or
1164 // otherwise when the channel is closed.
1165 new NPObjectStub(
1166 npobject, channel_host_.get(), route_id, 0, page_url_);
1167 *success = true;
1170 void WebPluginDelegateProxy::OnSetCookie(const GURL& url,
1171 const GURL& first_party_for_cookies,
1172 const std::string& cookie) {
1173 if (plugin_)
1174 plugin_->SetCookie(url, first_party_for_cookies, cookie);
1177 void WebPluginDelegateProxy::OnGetCookies(const GURL& url,
1178 const GURL& first_party_for_cookies,
1179 std::string* cookies) {
1180 DCHECK(cookies);
1181 if (plugin_)
1182 *cookies = plugin_->GetCookies(url, first_party_for_cookies);
1185 void WebPluginDelegateProxy::PaintSadPlugin(WebKit::WebCanvas* native_context,
1186 const gfx::Rect& rect) {
1187 // Lazily load the sad plugin image.
1188 if (!sad_plugin_)
1189 sad_plugin_ = content::GetContentClient()->renderer()->GetSadPluginBitmap();
1190 if (sad_plugin_)
1191 webkit::PaintSadPlugin(native_context, plugin_rect_, *sad_plugin_);
1194 void WebPluginDelegateProxy::CopyFromBackBufferToFrontBuffer(
1195 const gfx::Rect& rect) {
1196 #if defined(OS_MACOSX)
1197 // Blitting the bits directly is much faster than going through CG, and since
1198 // the goal is just to move the raw pixels between two bitmaps with the same
1199 // pixel format (no compositing, color correction, etc.), it's safe.
1200 const size_t stride =
1201 skia::PlatformCanvas::StrideForWidth(plugin_rect_.width());
1202 const size_t chunk_size = 4 * rect.width();
1203 DCHECK(back_buffer_dib() != NULL);
1204 uint8* source_data = static_cast<uint8*>(back_buffer_dib()->memory()) +
1205 rect.y() * stride + 4 * rect.x();
1206 DCHECK(front_buffer_dib() != NULL);
1207 uint8* target_data = static_cast<uint8*>(front_buffer_dib()->memory()) +
1208 rect.y() * stride + 4 * rect.x();
1209 for (int row = 0; row < rect.height(); ++row) {
1210 memcpy(target_data, source_data, chunk_size);
1211 source_data += stride;
1212 target_data += stride;
1214 #else
1215 BlitCanvasToCanvas(front_buffer_canvas(),
1216 rect,
1217 back_buffer_canvas(),
1218 rect.origin());
1219 #endif
1222 void WebPluginDelegateProxy::UpdateFrontBuffer(
1223 const gfx::Rect& rect,
1224 bool allow_buffer_flipping) {
1225 if (!front_buffer_canvas()) {
1226 return;
1229 #if defined(OS_WIN)
1230 // If SendUpdateGeometry() would block on the plugin process then we don't
1231 // want to use buffer flipping at all since it would add extra locking.
1232 // (Alternatively we could probably safely use async updates for buffer
1233 // flipping all the time since the size is not changing.)
1234 if (UseSynchronousGeometryUpdates()) {
1235 allow_buffer_flipping = false;
1237 #endif
1239 // Plugin has just painted "rect" into the back-buffer, so the front-buffer
1240 // no longer holds the latest content for that rectangle.
1241 front_buffer_diff_ = front_buffer_diff_.Subtract(rect);
1242 if (allow_buffer_flipping && front_buffer_diff_.IsEmpty()) {
1243 // Back-buffer contains the latest content for all areas; simply flip
1244 // the buffers.
1245 front_buffer_index_ = back_buffer_index();
1246 SendUpdateGeometry(false);
1247 // The front-buffer now holds newer content for this region than the
1248 // back-buffer.
1249 front_buffer_diff_ = rect;
1250 } else {
1251 // Back-buffer contains the latest content for "rect" but the front-buffer
1252 // contains the latest content for some other areas (or buffer flipping not
1253 // allowed); fall back to copying the data.
1254 CopyFromBackBufferToFrontBuffer(rect);
1256 transport_store_painted_ = transport_store_painted_.Union(rect);
1259 void WebPluginDelegateProxy::OnHandleURLRequest(
1260 const PluginHostMsg_URLRequest_Params& params) {
1261 const char* data = NULL;
1262 if (params.buffer.size())
1263 data = &params.buffer[0];
1265 const char* target = NULL;
1266 if (params.target.length())
1267 target = params.target.c_str();
1269 plugin_->HandleURLRequest(
1270 params.url.c_str(), params.method.c_str(), target, data,
1271 static_cast<unsigned int>(params.buffer.size()), params.notify_id,
1272 params.popups_allowed, params.notify_redirects);
1275 webkit::npapi::WebPluginResourceClient*
1276 WebPluginDelegateProxy::CreateResourceClient(
1277 unsigned long resource_id, const GURL& url, int notify_id) {
1278 if (!channel_host_)
1279 return NULL;
1281 ResourceClientProxy* proxy = new ResourceClientProxy(channel_host_,
1282 instance_id_);
1283 proxy->Initialize(resource_id, url, notify_id);
1284 return proxy;
1287 webkit::npapi::WebPluginResourceClient*
1288 WebPluginDelegateProxy::CreateSeekableResourceClient(
1289 unsigned long resource_id, int range_request_id) {
1290 if (!channel_host_)
1291 return NULL;
1293 ResourceClientProxy* proxy = new ResourceClientProxy(channel_host_,
1294 instance_id_);
1295 proxy->InitializeForSeekableStream(resource_id, range_request_id);
1296 return proxy;
1299 #if defined(OS_MACOSX)
1300 void WebPluginDelegateProxy::OnFocusChanged(bool focused) {
1301 if (render_view_)
1302 render_view_->PluginFocusChanged(focused, instance_id_);
1305 void WebPluginDelegateProxy::OnStartIme() {
1306 if (render_view_)
1307 render_view_->StartPluginIme();
1310 void WebPluginDelegateProxy::OnBindFakePluginWindowHandle(bool opaque) {
1311 BindFakePluginWindowHandle(opaque);
1314 // Synthesize a fake window handle for the plug-in to identify the instance
1315 // to the browser, allowing mapping to a surface for hardware acceleration
1316 // of plug-in content. The browser generates the handle which is then set on
1317 // the plug-in. Returns true if it successfully sets the window handle on the
1318 // plug-in.
1319 bool WebPluginDelegateProxy::BindFakePluginWindowHandle(bool opaque) {
1320 gfx::PluginWindowHandle fake_window = NULL;
1321 if (render_view_)
1322 fake_window = render_view_->AllocateFakePluginWindowHandle(opaque, false);
1323 // If we aren't running on 10.6, this allocation will fail.
1324 if (!fake_window)
1325 return false;
1326 OnSetWindow(fake_window);
1327 if (!Send(new PluginMsg_SetFakeAcceleratedSurfaceWindowHandle(instance_id_,
1328 fake_window))) {
1329 return false;
1332 // Since this isn't a real window, it doesn't get initial size and location
1333 // information the way a real windowed plugin would, so we need to feed it its
1334 // starting geometry.
1335 webkit::npapi::WebPluginGeometry geom;
1336 geom.window = fake_window;
1337 geom.window_rect = plugin_rect_;
1338 geom.clip_rect = clip_rect_;
1339 geom.rects_valid = true;
1340 geom.visible = true;
1341 render_view_->DidMovePlugin(geom);
1342 // Invalidate the plugin region to ensure that the move event actually gets
1343 // dispatched (for a plugin on an otherwise static page).
1344 render_view_->didInvalidateRect(WebKit::WebRect(plugin_rect_.x(),
1345 plugin_rect_.y(),
1346 plugin_rect_.width(),
1347 plugin_rect_.height()));
1349 return true;
1351 #endif
1353 gfx::PluginWindowHandle WebPluginDelegateProxy::GetPluginWindowHandle() {
1354 return window_;
1357 void WebPluginDelegateProxy::OnCancelDocumentLoad() {
1358 plugin_->CancelDocumentLoad();
1361 void WebPluginDelegateProxy::OnInitiateHTTPRangeRequest(
1362 const std::string& url,
1363 const std::string& range_info,
1364 int range_request_id) {
1365 plugin_->InitiateHTTPRangeRequest(
1366 url.c_str(), range_info.c_str(), range_request_id);
1369 void WebPluginDelegateProxy::OnDeferResourceLoading(unsigned long resource_id,
1370 bool defer) {
1371 plugin_->SetDeferResourceLoading(resource_id, defer);
1374 #if defined(OS_MACOSX)
1375 void WebPluginDelegateProxy::OnAcceleratedSurfaceSetIOSurface(
1376 gfx::PluginWindowHandle window,
1377 int32 width,
1378 int32 height,
1379 uint64 io_surface_identifier) {
1380 if (render_view_)
1381 render_view_->AcceleratedSurfaceSetIOSurface(window, width, height,
1382 io_surface_identifier);
1385 void WebPluginDelegateProxy::OnAcceleratedSurfaceSetTransportDIB(
1386 gfx::PluginWindowHandle window,
1387 int32 width,
1388 int32 height,
1389 TransportDIB::Handle transport_dib) {
1390 if (render_view_)
1391 render_view_->AcceleratedSurfaceSetTransportDIB(window, width, height,
1392 transport_dib);
1395 void WebPluginDelegateProxy::OnAcceleratedSurfaceAllocTransportDIB(
1396 size_t size,
1397 TransportDIB::Handle* dib_handle) {
1398 if (render_view_)
1399 *dib_handle = render_view_->AcceleratedSurfaceAllocTransportDIB(size);
1400 else
1401 *dib_handle = TransportDIB::DefaultHandleValue();
1404 void WebPluginDelegateProxy::OnAcceleratedSurfaceFreeTransportDIB(
1405 TransportDIB::Id dib_id) {
1406 if (render_view_)
1407 render_view_->AcceleratedSurfaceFreeTransportDIB(dib_id);
1410 void WebPluginDelegateProxy::OnAcceleratedSurfaceBuffersSwapped(
1411 gfx::PluginWindowHandle window, uint64 surface_id) {
1412 if (render_view_)
1413 render_view_->AcceleratedSurfaceBuffersSwapped(window, surface_id);
1416 void WebPluginDelegateProxy::OnAcceleratedPluginEnabledRendering() {
1417 uses_compositor_ = true;
1418 OnSetWindow(NULL);
1421 void WebPluginDelegateProxy::OnAcceleratedPluginAllocatedIOSurface(
1422 int32 width,
1423 int32 height,
1424 uint32 surface_id) {
1425 if (plugin_)
1426 plugin_->AcceleratedPluginAllocatedIOSurface(width, height, surface_id);
1429 void WebPluginDelegateProxy::OnAcceleratedPluginSwappedIOSurface() {
1430 if (plugin_)
1431 plugin_->AcceleratedPluginSwappedIOSurface();
1433 #endif
1435 #if defined(OS_WIN)
1436 bool WebPluginDelegateProxy::UseSynchronousGeometryUpdates() {
1437 // Need to update geometry synchronously with WMP, otherwise if a site
1438 // scripts the plugin to start playing while it's in the middle of handling
1439 // an update geometry message, videos don't play. See urls in bug 20260.
1440 if (info_.name.find(ASCIIToUTF16("Windows Media Player")) != string16::npos)
1441 return true;
1443 // The move networks plugin needs to be informed of geometry updates
1444 // synchronously.
1445 std::vector<webkit::WebPluginMimeType>::iterator index;
1446 for (index = info_.mime_types.begin(); index != info_.mime_types.end();
1447 index++) {
1448 if (index->mime_type == "application/x-vnd.moveplayer.qm" ||
1449 index->mime_type == "application/x-vnd.moveplay2.qm" ||
1450 index->mime_type == "application/x-vnd.movenetworks.qm" ||
1451 index->mime_type == "application/x-vnd.mnplayer.qm") {
1452 return true;
1455 return false;
1457 #endif
1459 void WebPluginDelegateProxy::OnURLRedirectResponse(bool allow,
1460 int resource_id) {
1461 if (!plugin_)
1462 return;
1464 plugin_->URLRedirectResponse(allow, resource_id);