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)
10 #include <cairo/cairo.h>
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"
55 #include "ipc/ipc_channel_posix.h"
58 #if defined(OS_MACOSX)
59 #include "base/mac/mac_util.h"
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
{
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_
,
134 void DidFinishLoading() {
135 DCHECK(channel_
!= NULL
);
136 channel_
->Send(new PluginMsg_DidFinishLoading(instance_id_
, resource_id_
));
138 MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
142 DCHECK(channel_
!= NULL
);
143 channel_
->Send(new PluginMsg_DidFail(instance_id_
, resource_id_
));
145 MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
148 bool IsMultiByteResponseExpected() {
149 return multibyte_response_expected_
;
157 scoped_refptr
<PluginChannelHost
> channel_
;
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
),
170 uses_shared_bitmaps_(false),
171 #if defined(OS_MACOSX)
172 uses_compositor_(false),
174 window_(gfx::kNullPluginWindow
),
175 mime_type_(mime_type
),
176 instance_id_(MSG_ROUTING_NONE
),
179 invalidate_pending_(false),
181 front_buffer_index_(0),
182 page_url_(render_view_
->webview()->mainFrame()->document().url()) {
185 WebPluginDelegateProxy::~WebPluginDelegateProxy() {
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.
198 render_view_
->PluginFocusChanged(false, instance_id_
);
205 render_view_
->UnregisterPluginDelegate(this);
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();
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)))
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)
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))
260 } else if (LowerCaseEqualsASCII(color
, "transparent")) {
263 // Anything else is a named, opaque color or an RGB form with no alpha.
267 bool WebPluginDelegateProxy::Initialize(
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_
))) {
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.
292 LOG(ERROR
) << "Plug-in couldn't be found";
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";
305 bool result
= channel_host
->Send(new PluginMsg_CreateInstance(
306 mime_type_
, &instance_id
));
308 LOG(ERROR
) << "Couldn't send PluginMsg_CreateInstance";
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();
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();
327 LowerCaseEqualsASCII(mime_type_
, "application/x-shockwave-flash");
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
]))) {
338 params
.load_manually
= load_manually
;
343 IPC::Message
* msg
= new PluginMsg_Init(instance_id_
, params
, &result
);
347 LOG(ERROR
) << "PluginMsg_Init returned false";
349 render_view_
->RegisterPluginDelegate(this);
354 bool WebPluginDelegateProxy::Send(IPC::Message
* msg
) {
355 if (!channel_host_
) {
356 DLOG(WARNING
) << "dropping message because channel host is null";
361 return channel_host_
->Send(msg
);
364 void WebPluginDelegateProxy::SendJavaScriptStream(const GURL
& url
,
365 const std::string
& result
,
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
;
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
,
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_
);
406 IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy
, msg
)
407 IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow
, OnSetWindow
)
409 IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindowlessPumpEvent
,
410 OnSetWindowlessPumpEvent
)
411 IPC_MESSAGE_HANDLER(PluginHostMsg_NotifyIMEStatus
,
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
,
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
,
433 IPC_MESSAGE_HANDLER(PluginHostMsg_StartIme
,
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
)
457 IPC_MESSAGE_HANDLER(PluginHostMsg_URLRedirectResponse
,
458 OnURLRedirectResponse
)
459 IPC_MESSAGE_UNHANDLED(handled
= false)
460 IPC_END_MESSAGE_MAP()
465 void WebPluginDelegateProxy::OnChannelError() {
468 // The actual WebPluginDelegate never got a chance to tell the WebPlugin
469 // its window was going away. Do it on its behalf.
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.
480 render_view_
->PluginFocusChanged(false, instance_id_
);
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()";
495 handle_out
->auto_close
= true;
497 // Don't need to do anything special for other platforms.
498 *handle_out
= handle_in
;
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.
520 if (transport_stores_
[0].dib
.get())
521 CopyTransportDIBHandleForMessage(transport_stores_
[0].dib
->handle(),
522 ¶m
.windowless_buffer0
);
524 if (transport_stores_
[1].dib
.get())
525 CopyTransportDIBHandleForMessage(transport_stores_
[1].dib
->handle(),
526 ¶m
.windowless_buffer1
);
528 if (background_store_
.dib
.get())
529 CopyTransportDIBHandleForMessage(background_store_
.dib
->handle(),
530 ¶m
.background_buffer
);
535 if (UseSynchronousGeometryUpdates()) {
536 msg
= new PluginMsg_UpdateGeometrySync(instance_id_
, param
);
540 msg
= new PluginMsg_UpdateGeometry(instance_id_
, param
);
541 msg
->set_unblock(true);
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)) {
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;
579 // Create a shared memory section that the plugin paints into
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
))) {
591 ResetWindowlessBitmaps();
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();
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
)
627 canvas
->reset(new skia::PlatformCanvas(
628 plugin_rect_
.width(), plugin_rect_
.height(), true, &((*memory
)[0])));
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));
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
))
649 memory
->reset(TransportDIB::Map(handle
));
651 static uint32 sequence_number
= 0;
652 memory
->reset(TransportDIB::Create(size
, sequence_number
++));
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());
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
675 if (!channel_host_
|| !channel_host_
->channel_valid()) {
676 PaintSadPlugin(canvas
, rect
);
680 if (!uses_shared_bitmaps_
)
683 // We got a paint before the plugin's coordinates, so there's no buffer to
685 if (!front_buffer_canvas())
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";
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
;
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());
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
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());
742 BlitCanvasToContext(context
,
744 front_buffer_canvas(),
745 offset_rect
.origin());
746 #if defined(OS_MACOSX)
747 CGContextRestoreGState(context
);
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)
766 HBITMAP hbitmap
= static_cast<HBITMAP
>(GetCurrentObject(context
, OBJ_BITMAP
));
767 if (hbitmap
== NULL
) {
772 BITMAP bitmap
= { 0 };
773 int result
= GetObject(hbitmap
, sizeof(bitmap
), &bitmap
);
780 if (!GetWorldTransform(context
, &xf
)) {
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)
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
)
815 gfx::Rect
full_content_rect(context_offset_x
, context_offset_y
,
816 CGBitmapContextGetWidth(context
),
817 CGBitmapContextGetHeight(context
));
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
));
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;
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.
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
;
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)
909 NPObject
* WebPluginDelegateProxy::GetPluginScriptableObject() {
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
)
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
));
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
));
940 render_view_
->PluginFocusChanged(focused
, instance_id_
);
944 bool WebPluginDelegateProxy::HandleInputEvent(
945 const WebInputEvent
& event
,
946 WebCursorInfo
* cursor_info
) {
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());
957 cursor
.GetCursorInfo(cursor_info
);
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_
,
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);
975 void WebPluginDelegateProxy::ImeCompositionUpdated(
976 const string16
& text
,
977 const std::vector
<int>& clauses
,
978 const std::vector
<int>& target
,
981 // Dispatch the raw IME data if this plug-in is the focused one.
982 if (instance_id_
!= plugin_id
)
985 IPC::Message
* msg
= new PluginMsg_ImeCompositionUpdated(instance_id_
,
986 text
, clauses
, target
, cursor_position
);
987 msg
->set_unblock(true);
991 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16
& text
,
993 // Dispatch the IME text if this plug-in is the focused one.
994 if (instance_id_
!= plugin_id
)
997 IPC::Message
* msg
= new PluginMsg_ImeCompositionCompleted(instance_id_
, text
);
998 msg
->set_unblock(true);
1003 #if defined(OS_MACOSX)
1004 void WebPluginDelegateProxy::SetWindowFocus(bool window_has_focus
) {
1005 IPC::Message
* msg
= new PluginMsg_SetWindowFocus(instance_id_
,
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);
1013 void WebPluginDelegateProxy::SetContainerVisibility(bool 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());
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);
1030 void WebPluginDelegateProxy::WindowFrameChanged(gfx::Rect window_frame
,
1031 gfx::Rect view_frame
) {
1032 IPC::Message
* msg
= new PluginMsg_WindowFrameChanged(instance_id_
,
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);
1040 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16
& text
,
1042 // If the message isn't intended for this plugin, there's nothing to do.
1043 if (instance_id_
!= plugin_id
)
1046 IPC::Message
* msg
= new PluginMsg_ImeCompositionCompleted(instance_id_
,
1048 // Order relative to other key events is important.
1049 msg
->set_unblock(true);
1054 void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window
) {
1055 #if defined(OS_MACOSX)
1056 uses_shared_bitmaps_
= !window
&& !uses_compositor_
;
1058 uses_shared_bitmaps_
= !window
;
1062 plugin_
->SetWindow(window
);
1065 void WebPluginDelegateProxy::WillDestroyWindow() {
1067 plugin_
->WillDestroyWindow(window_
);
1068 #if defined(OS_MACOSX)
1070 // This is actually a "fake" window handle only for the GPU
1071 // plugin. Deallocate it on the browser side.
1073 render_view_
->DestroyFakePluginWindowHandle(window_
);
1076 window_
= gfx::kNullPluginWindow
;
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
)
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
) {
1098 render_view_
->Send(new ViewHostMsg_TextInputStateChanged(
1099 render_view_
->routing_id(),
1100 static_cast<ui::TextInputType
>(input_type
),
1103 render_view_
->Send(new ViewHostMsg_SelectionBoundsChanged(
1104 render_view_
->routing_id(), caret_rect
, caret_rect
));
1108 void WebPluginDelegateProxy::OnCancelResource(int id
) {
1110 plugin_
->CancelResource(id
);
1113 void WebPluginDelegateProxy::OnInvalidateRect(const gfx::Rect
& rect
,
1114 bool allow_buffer_flipping
) {
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
1126 UpdateFrontBuffer(clipped_rect
, allow_buffer_flipping
);
1127 plugin_
->InvalidateRect(clipped_rect
);
1130 void WebPluginDelegateProxy::OnGetWindowScriptNPObject(
1131 int route_id
, bool* success
) {
1133 NPObject
* npobject
= NULL
;
1135 npobject
= plugin_
->GetWindowScriptNPObject();
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();
1147 void WebPluginDelegateProxy::OnResolveProxy(const GURL
& url
,
1149 std::string
* proxy_list
) {
1151 RenderThreadImpl::current()->Send(
1152 new ViewHostMsg_ResolveProxy(url
, result
, proxy_list
));
1155 void WebPluginDelegateProxy::OnGetPluginElement(int route_id
, bool* success
) {
1157 NPObject
* npobject
= NULL
;
1159 npobject
= plugin_
->GetPluginElement();
1163 // The stub will delete itself when the proxy tells it that it's released, or
1164 // otherwise when the channel is closed.
1166 npobject
, channel_host_
.get(), route_id
, 0, page_url_
);
1170 void WebPluginDelegateProxy::OnSetCookie(const GURL
& url
,
1171 const GURL
& first_party_for_cookies
,
1172 const std::string
& cookie
) {
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
) {
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.
1189 sad_plugin_
= content::GetContentClient()->renderer()->GetSadPluginBitmap();
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
;
1215 BlitCanvasToCanvas(front_buffer_canvas(),
1217 back_buffer_canvas(),
1222 void WebPluginDelegateProxy::UpdateFrontBuffer(
1223 const gfx::Rect
& rect
,
1224 bool allow_buffer_flipping
) {
1225 if (!front_buffer_canvas()) {
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;
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
1245 front_buffer_index_
= back_buffer_index();
1246 SendUpdateGeometry(false);
1247 // The front-buffer now holds newer content for this region than the
1249 front_buffer_diff_
= rect
;
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
= ¶ms
.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
) {
1281 ResourceClientProxy
* proxy
= new ResourceClientProxy(channel_host_
,
1283 proxy
->Initialize(resource_id
, url
, notify_id
);
1287 webkit::npapi::WebPluginResourceClient
*
1288 WebPluginDelegateProxy::CreateSeekableResourceClient(
1289 unsigned long resource_id
, int range_request_id
) {
1293 ResourceClientProxy
* proxy
= new ResourceClientProxy(channel_host_
,
1295 proxy
->InitializeForSeekableStream(resource_id
, range_request_id
);
1299 #if defined(OS_MACOSX)
1300 void WebPluginDelegateProxy::OnFocusChanged(bool focused
) {
1302 render_view_
->PluginFocusChanged(focused
, instance_id_
);
1305 void WebPluginDelegateProxy::OnStartIme() {
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
1319 bool WebPluginDelegateProxy::BindFakePluginWindowHandle(bool opaque
) {
1320 gfx::PluginWindowHandle fake_window
= NULL
;
1322 fake_window
= render_view_
->AllocateFakePluginWindowHandle(opaque
, false);
1323 // If we aren't running on 10.6, this allocation will fail.
1326 OnSetWindow(fake_window
);
1327 if (!Send(new PluginMsg_SetFakeAcceleratedSurfaceWindowHandle(instance_id_
,
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(),
1346 plugin_rect_
.width(),
1347 plugin_rect_
.height()));
1353 gfx::PluginWindowHandle
WebPluginDelegateProxy::GetPluginWindowHandle() {
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
,
1371 plugin_
->SetDeferResourceLoading(resource_id
, defer
);
1374 #if defined(OS_MACOSX)
1375 void WebPluginDelegateProxy::OnAcceleratedSurfaceSetIOSurface(
1376 gfx::PluginWindowHandle window
,
1379 uint64 io_surface_identifier
) {
1381 render_view_
->AcceleratedSurfaceSetIOSurface(window
, width
, height
,
1382 io_surface_identifier
);
1385 void WebPluginDelegateProxy::OnAcceleratedSurfaceSetTransportDIB(
1386 gfx::PluginWindowHandle window
,
1389 TransportDIB::Handle transport_dib
) {
1391 render_view_
->AcceleratedSurfaceSetTransportDIB(window
, width
, height
,
1395 void WebPluginDelegateProxy::OnAcceleratedSurfaceAllocTransportDIB(
1397 TransportDIB::Handle
* dib_handle
) {
1399 *dib_handle
= render_view_
->AcceleratedSurfaceAllocTransportDIB(size
);
1401 *dib_handle
= TransportDIB::DefaultHandleValue();
1404 void WebPluginDelegateProxy::OnAcceleratedSurfaceFreeTransportDIB(
1405 TransportDIB::Id dib_id
) {
1407 render_view_
->AcceleratedSurfaceFreeTransportDIB(dib_id
);
1410 void WebPluginDelegateProxy::OnAcceleratedSurfaceBuffersSwapped(
1411 gfx::PluginWindowHandle window
, uint64 surface_id
) {
1413 render_view_
->AcceleratedSurfaceBuffersSwapped(window
, surface_id
);
1416 void WebPluginDelegateProxy::OnAcceleratedPluginEnabledRendering() {
1417 uses_compositor_
= true;
1421 void WebPluginDelegateProxy::OnAcceleratedPluginAllocatedIOSurface(
1424 uint32 surface_id
) {
1426 plugin_
->AcceleratedPluginAllocatedIOSurface(width
, height
, surface_id
);
1429 void WebPluginDelegateProxy::OnAcceleratedPluginSwappedIOSurface() {
1431 plugin_
->AcceleratedPluginSwappedIOSurface();
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
)
1443 // The move networks plugin needs to be informed of geometry updates
1445 std::vector
<webkit::WebPluginMimeType
>::iterator index
;
1446 for (index
= info_
.mime_types
.begin(); index
!= info_
.mime_types
.end();
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") {
1459 void WebPluginDelegateProxy::OnURLRedirectResponse(bool allow
,
1464 plugin_
->URLRedirectResponse(allow
, resource_id
);