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

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

Issue 6713005: Move a bunch of gpu/worker/plugin renderer code to content. I temporarily disabled the sad plugi... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/renderer/webplugin_delegate_proxy.h ('k') | chrome/renderer/websharedworker_proxy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 #include "chrome/renderer/webplugin_delegate_proxy.h"
6
7 #if defined(TOOLKIT_USES_GTK)
8 #include <gtk/gtk.h>
9 #endif
10
11 #include <algorithm>
12
13 #include "base/basictypes.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/logging.h"
17 #include "base/ref_counted.h"
18 #include "base/scoped_ptr.h"
19 #include "base/string_split.h"
20 #include "base/string_util.h"
21 #include "base/sys_info.h"
22 #include "base/utf_string_conversions.h"
23 #include "chrome/common/child_process_logging.h"
24 #include "chrome/common/render_messages.h"
25 #include "chrome/renderer/command_buffer_proxy.h"
26 #include "chrome/renderer/plugin_channel_host.h"
27 #include "chrome/renderer/render_thread.h"
28 #include "chrome/renderer/render_view.h"
29 #include "content/common/plugin_messages.h"
30 #include "content/plugin/npobject_proxy.h"
31 #include "content/plugin/npobject_stub.h"
32 #include "content/plugin/npobject_util.h"
33 #include "grit/generated_resources.h"
34 #include "grit/renderer_resources.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/WebDragData.h"
41 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
44 #include "ui/base/resource/resource_bundle.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/webplugin.h"
50 #include "webkit/glue/webkit_glue.h"
51
52 #if defined(OS_POSIX)
53 #include "ipc/ipc_channel_posix.h"
54 #endif
55
56 #if defined(OS_WIN)
57 #include "printing/native_metafile_factory.h"
58 #include "printing/native_metafile.h"
59 #endif
60
61 using WebKit::WebBindings;
62 using WebKit::WebCursorInfo;
63 using WebKit::WebDragData;
64 using WebKit::WebInputEvent;
65 using WebKit::WebString;
66 using WebKit::WebView;
67
68 // Proxy for WebPluginResourceClient. The object owns itself after creation,
69 // deleting itself after its callback has been called.
70 class ResourceClientProxy : public webkit::npapi::WebPluginResourceClient {
71 public:
72 ResourceClientProxy(PluginChannelHost* channel, int instance_id)
73 : channel_(channel), instance_id_(instance_id), resource_id_(0),
74 multibyte_response_expected_(false) {
75 }
76
77 ~ResourceClientProxy() {
78 }
79
80 void Initialize(unsigned long resource_id, const GURL& url, int notify_id) {
81 resource_id_ = resource_id;
82 channel_->Send(new PluginMsg_HandleURLRequestReply(
83 instance_id_, resource_id, url, notify_id));
84 }
85
86 void InitializeForSeekableStream(unsigned long resource_id,
87 int range_request_id) {
88 resource_id_ = resource_id;
89 multibyte_response_expected_ = true;
90 channel_->Send(new PluginMsg_HTTPRangeRequestReply(
91 instance_id_, resource_id, range_request_id));
92 }
93
94 // PluginResourceClient implementation:
95 void WillSendRequest(const GURL& url, int http_status_code) {
96 DCHECK(channel_ != NULL);
97 channel_->Send(new PluginMsg_WillSendRequest(instance_id_, resource_id_,
98 url, http_status_code));
99 }
100
101 void DidReceiveResponse(const std::string& mime_type,
102 const std::string& headers,
103 uint32 expected_length,
104 uint32 last_modified,
105 bool request_is_seekable) {
106 DCHECK(channel_ != NULL);
107 PluginMsg_DidReceiveResponseParams params;
108 params.id = resource_id_;
109 params.mime_type = mime_type;
110 params.headers = headers;
111 params.expected_length = expected_length;
112 params.last_modified = last_modified;
113 params.request_is_seekable = request_is_seekable;
114 // Grab a reference on the underlying channel so it does not get
115 // deleted from under us.
116 scoped_refptr<PluginChannelHost> channel_ref(channel_);
117 channel_->Send(new PluginMsg_DidReceiveResponse(instance_id_, params));
118 }
119
120 void DidReceiveData(const char* buffer, int length, int data_offset) {
121 DCHECK(channel_ != NULL);
122 DCHECK_GT(length, 0);
123 std::vector<char> data;
124 data.resize(static_cast<size_t>(length));
125 memcpy(&data.front(), buffer, length);
126 // Grab a reference on the underlying channel so it does not get
127 // deleted from under us.
128 scoped_refptr<PluginChannelHost> channel_ref(channel_);
129 channel_->Send(new PluginMsg_DidReceiveData(instance_id_, resource_id_,
130 data, data_offset));
131 }
132
133 void DidFinishLoading() {
134 DCHECK(channel_ != NULL);
135 channel_->Send(new PluginMsg_DidFinishLoading(instance_id_, resource_id_));
136 channel_ = NULL;
137 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
138 }
139
140 void DidFail() {
141 DCHECK(channel_ != NULL);
142 channel_->Send(new PluginMsg_DidFail(instance_id_, resource_id_));
143 channel_ = NULL;
144 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
145 }
146
147 bool IsMultiByteResponseExpected() {
148 return multibyte_response_expected_;
149 }
150
151 int ResourceId() {
152 return resource_id_;
153 }
154
155 private:
156 scoped_refptr<PluginChannelHost> channel_;
157 int instance_id_;
158 unsigned long resource_id_;
159 // Set to true if the response expected is a multibyte response.
160 // For e.g. response for a HTTP byte range request.
161 bool multibyte_response_expected_;
162 };
163
164 #if defined(OS_MACOSX)
165 static void ReleaseTransportDIB(TransportDIB* dib) {
166 if (dib) {
167 IPC::Message* message = new ViewHostMsg_FreeTransportDIB(dib->id());
168 RenderThread::current()->Send(message);
169 }
170 }
171 #endif
172
173 WebPluginDelegateProxy::WebPluginDelegateProxy(
174 const std::string& mime_type,
175 const base::WeakPtr<RenderView>& render_view)
176 : render_view_(render_view),
177 plugin_(NULL),
178 uses_shared_bitmaps_(false),
179 window_(gfx::kNullPluginWindow),
180 mime_type_(mime_type),
181 instance_id_(MSG_ROUTING_NONE),
182 npobject_(NULL),
183 sad_plugin_(NULL),
184 invalidate_pending_(false),
185 transparent_(false),
186 page_url_(render_view_->webview()->mainFrame()->url()) {
187 }
188
189 WebPluginDelegateProxy::~WebPluginDelegateProxy() {
190 #if defined(OS_MACOSX)
191 // Ask the browser to release old TransportDIB objects for which no
192 // PluginHostMsg_UpdateGeometry_ACK was ever received from the plugin
193 // process.
194 for (OldTransportDIBMap::iterator iterator = old_transport_dibs_.begin();
195 iterator != old_transport_dibs_.end();
196 ++iterator) {
197 ReleaseTransportDIB(iterator->second.get());
198 }
199
200 // Ask the browser to release the "live" TransportDIB object.
201 ReleaseTransportDIB(transport_store_.get());
202 DCHECK(!background_store_.get());
203 #endif
204 }
205
206 void WebPluginDelegateProxy::PluginDestroyed() {
207 #if defined(OS_MACOSX)
208 // Ensure that the renderer doesn't think the plugin still has focus.
209 if (render_view_)
210 render_view_->PluginFocusChanged(false, instance_id_);
211 #endif
212
213 if (window_)
214 WillDestroyWindow();
215
216 if (render_view_)
217 render_view_->UnregisterPluginDelegate(this);
218
219 if (channel_host_) {
220 Send(new PluginMsg_DestroyInstance(instance_id_));
221
222 // Must remove the route after sending the destroy message, since
223 // RemoveRoute can lead to all the outstanding NPObjects being told the
224 // channel went away if this was the last instance.
225 channel_host_->RemoveRoute(instance_id_);
226
227 // Release the channel host now. If we are is the last reference to the
228 // channel, this avoids a race where this renderer asks a new connection to
229 // the same plugin between now and the time 'this' is actually deleted.
230 // Destroying the channel host is what releases the channel name -> FD
231 // association on POSIX, and if we ask for a new connection before it is
232 // released, the plugin will give us a new FD, and we'll assert when trying
233 // to associate it with the channel name.
234 channel_host_ = NULL;
235 }
236
237 if (window_script_object_) {
238 // The ScriptController deallocates this object independent of its ref count
239 // to avoid leaks if the plugin forgets to release it. So mark the object
240 // invalid to avoid accessing it past this point. Note: only do this after
241 // the DestroyInstance message in case the window object is scripted by the
242 // plugin in NPP_Destroy.
243 window_script_object_->OnPluginDestroyed();
244 }
245
246 plugin_ = NULL;
247
248 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
249 }
250
251 // Returns true if the given Silverlight 'background' value corresponds to
252 // one that should make the plugin transparent. See:
253 // http://msdn.microsoft.com/en-us/library/cc838148(VS.95).aspx
254 // for possible values.
255 static bool SilverlightColorIsTransparent(const std::string& color) {
256 if (StartsWithASCII(color, "#", false)) {
257 // If it's #ARGB or #AARRGGBB check the alpha; if not it's an RGB form and
258 // it's not transparent.
259 if ((color.length() == 5 && !StartsWithASCII(color, "#F", false)) ||
260 (color.length() == 9 && !StartsWithASCII(color, "#FF", false)))
261 return true;
262 } else if (StartsWithASCII(color, "sc#", false)) {
263 // It's either sc#A,R,G,B or sc#R,G,B; if the former, check the alpha.
264 if (color.length() < 4)
265 return false;
266 std::string value_string = color.substr(3, std::string::npos);
267 std::vector<std::string> components;
268 base::SplitString(value_string, ',', &components);
269 if (components.size() == 4 && !StartsWithASCII(components[0], "1", false))
270 return true;
271 } else if (LowerCaseEqualsASCII(color, "transparent")) {
272 return true;
273 }
274 // Anything else is a named, opaque color or an RGB form with no alpha.
275 return false;
276 }
277
278 bool WebPluginDelegateProxy::Initialize(
279 const GURL& url,
280 const std::vector<std::string>& arg_names,
281 const std::vector<std::string>& arg_values,
282 webkit::npapi::WebPlugin* plugin,
283 bool load_manually) {
284 IPC::ChannelHandle channel_handle;
285 if (!RenderThread::current()->Send(new ViewHostMsg_OpenChannelToPlugin(
286 render_view_->routing_id(), url, mime_type_, &channel_handle,
287 &info_))) {
288 return false;
289 }
290
291 if (channel_handle.name.empty()) {
292 // We got an invalid handle. Either the plugin couldn't be found (which
293 // shouldn't happen, since if we got here the plugin should exist) or the
294 // plugin crashed on initialization.
295 if (!info_.path.empty()) {
296 render_view_->PluginCrashed(info_.path);
297
298 // Return true so that the plugin widget is created and we can paint the
299 // crashed plugin there.
300 return true;
301 }
302 return false;
303 }
304
305 scoped_refptr<PluginChannelHost> channel_host(
306 PluginChannelHost::GetPluginChannelHost(
307 channel_handle, ChildProcess::current()->io_message_loop()));
308 if (!channel_host.get())
309 return false;
310
311 int instance_id;
312 bool result = channel_host->Send(new PluginMsg_CreateInstance(
313 mime_type_, &instance_id));
314 if (!result)
315 return false;
316
317 channel_host_ = channel_host;
318 instance_id_ = instance_id;
319
320 channel_host_->AddRoute(instance_id_, this, NULL);
321
322 // Now tell the PluginInstance in the plugin process to initialize.
323 PluginMsg_Init_Params params;
324 params.containing_window = render_view_->host_window();
325 params.url = url;
326 params.page_url = page_url_;
327 params.arg_names = arg_names;
328 params.arg_values = arg_values;
329 params.host_render_view_routing_id = render_view_->routing_id();
330
331 bool flash =
332 LowerCaseEqualsASCII(mime_type_, "application/x-shockwave-flash");
333 bool silverlight =
334 StartsWithASCII(mime_type_, "application/x-silverlight", false);
335 for (size_t i = 0; i < arg_names.size(); ++i) {
336 if ((flash && LowerCaseEqualsASCII(arg_names[i], "wmode") &&
337 LowerCaseEqualsASCII(arg_values[i], "transparent")) ||
338 (silverlight && LowerCaseEqualsASCII(arg_names[i], "background") &&
339 SilverlightColorIsTransparent(arg_values[i]))) {
340 transparent_ = true;
341 }
342 }
343 #if defined(OS_MACOSX)
344 // Unless we have a real way to support accelerated (3D) drawing on Macs
345 // (which for now at least means the Core Animation drawing model), ask
346 // Flash to use windowless mode so that it use CoreGraphics instead of opening
347 // OpenGL contexts overlaying the browser window (which requires a very
348 // expensive extra copy for us).
349 if (!transparent_ && mime_type_ == "application/x-shockwave-flash") {
350 bool force_opaque_mode = false;
351 if (StartsWith(info_.version, ASCIIToUTF16("10.0"), false) ||
352 StartsWith(info_.version, ASCIIToUTF16("9."), false)) {
353 // Older versions of Flash don't support CA (and they assume QuickDraw
354 // support, so we can't rely on negotiation to do the right thing).
355 force_opaque_mode = true;
356 } else {
357 // Flash 10.1 doesn't respect QuickDraw negotiation either, so we still
358 // have to force opaque mode on 10.5 (where it doesn't use CA).
359 int32 major, minor, bugfix;
360 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
361 if (major < 10 || (major == 10 && minor < 6))
362 force_opaque_mode = true;
363 }
364
365 if (force_opaque_mode) {
366 params.arg_names.push_back("wmode");
367 params.arg_values.push_back("opaque");
368 }
369 }
370 #endif
371 params.load_manually = load_manually;
372
373 plugin_ = plugin;
374
375 result = false;
376 IPC::Message* msg = new PluginMsg_Init(instance_id_, params, &result);
377 Send(msg);
378
379 render_view_->RegisterPluginDelegate(this);
380
381 return result;
382 }
383
384 bool WebPluginDelegateProxy::Send(IPC::Message* msg) {
385 if (!channel_host_) {
386 DLOG(WARNING) << "dropping message because channel host is null";
387 delete msg;
388 return false;
389 }
390
391 return channel_host_->Send(msg);
392 }
393
394 void WebPluginDelegateProxy::SendJavaScriptStream(const GURL& url,
395 const std::string& result,
396 bool success,
397 int notify_id) {
398 Send(new PluginMsg_SendJavaScriptStream(
399 instance_id_, url, result, success, notify_id));
400 }
401
402 void WebPluginDelegateProxy::DidReceiveManualResponse(
403 const GURL& url, const std::string& mime_type,
404 const std::string& headers, uint32 expected_length,
405 uint32 last_modified) {
406 PluginMsg_DidReceiveResponseParams params;
407 params.id = 0;
408 params.mime_type = mime_type;
409 params.headers = headers;
410 params.expected_length = expected_length;
411 params.last_modified = last_modified;
412 Send(new PluginMsg_DidReceiveManualResponse(instance_id_, url, params));
413 }
414
415 void WebPluginDelegateProxy::DidReceiveManualData(const char* buffer,
416 int length) {
417 DCHECK_GT(length, 0);
418 std::vector<char> data;
419 data.resize(static_cast<size_t>(length));
420 memcpy(&data.front(), buffer, length);
421 Send(new PluginMsg_DidReceiveManualData(instance_id_, data));
422 }
423
424 void WebPluginDelegateProxy::DidFinishManualLoading() {
425 Send(new PluginMsg_DidFinishManualLoading(instance_id_));
426 }
427
428 void WebPluginDelegateProxy::DidManualLoadFail() {
429 Send(new PluginMsg_DidManualLoadFail(instance_id_));
430 }
431
432 void WebPluginDelegateProxy::InstallMissingPlugin() {
433 Send(new PluginMsg_InstallMissingPlugin(instance_id_));
434 }
435
436 bool WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) {
437 child_process_logging::SetActiveURL(page_url_);
438
439 bool handled = true;
440 IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy, msg)
441 IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow, OnSetWindow)
442 #if defined(OS_WIN)
443 IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindowlessPumpEvent,
444 OnSetWindowlessPumpEvent)
445 #endif
446 IPC_MESSAGE_HANDLER(PluginHostMsg_CancelResource, OnCancelResource)
447 IPC_MESSAGE_HANDLER(PluginHostMsg_InvalidateRect, OnInvalidateRect)
448 IPC_MESSAGE_HANDLER(PluginHostMsg_GetWindowScriptNPObject,
449 OnGetWindowScriptNPObject)
450 IPC_MESSAGE_HANDLER(PluginHostMsg_GetPluginElement,
451 OnGetPluginElement)
452 IPC_MESSAGE_HANDLER(PluginHostMsg_SetCookie, OnSetCookie)
453 IPC_MESSAGE_HANDLER(PluginHostMsg_GetCookies, OnGetCookies)
454 IPC_MESSAGE_HANDLER(PluginHostMsg_MissingPluginStatus,
455 OnMissingPluginStatus)
456 IPC_MESSAGE_HANDLER(PluginHostMsg_URLRequest, OnHandleURLRequest)
457 IPC_MESSAGE_HANDLER(PluginHostMsg_CancelDocumentLoad, OnCancelDocumentLoad)
458 IPC_MESSAGE_HANDLER(PluginHostMsg_InitiateHTTPRangeRequest,
459 OnInitiateHTTPRangeRequest)
460 IPC_MESSAGE_HANDLER(PluginHostMsg_DeferResourceLoading,
461 OnDeferResourceLoading)
462
463 #if defined(OS_MACOSX)
464 IPC_MESSAGE_HANDLER(PluginHostMsg_FocusChanged,
465 OnFocusChanged);
466 IPC_MESSAGE_HANDLER(PluginHostMsg_StartIme,
467 OnStartIme);
468 IPC_MESSAGE_HANDLER(PluginHostMsg_BindFakePluginWindowHandle,
469 OnBindFakePluginWindowHandle);
470 IPC_MESSAGE_HANDLER(PluginHostMsg_UpdateGeometry_ACK,
471 OnUpdateGeometry_ACK)
472 // Used only on 10.6 and later.
473 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedSurfaceSetIOSurface,
474 OnAcceleratedSurfaceSetIOSurface)
475 // Used on 10.5 and earlier.
476 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedSurfaceSetTransportDIB,
477 OnAcceleratedSurfaceSetTransportDIB)
478 IPC_MESSAGE_HANDLER(PluginHostMsg_AllocTransportDIB,
479 OnAcceleratedSurfaceAllocTransportDIB)
480 IPC_MESSAGE_HANDLER(PluginHostMsg_FreeTransportDIB,
481 OnAcceleratedSurfaceFreeTransportDIB)
482 IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedSurfaceBuffersSwapped,
483 OnAcceleratedSurfaceBuffersSwapped)
484 #endif
485 IPC_MESSAGE_HANDLER(PluginHostMsg_URLRedirectResponse,
486 OnURLRedirectResponse)
487 IPC_MESSAGE_UNHANDLED(handled = false)
488 IPC_END_MESSAGE_MAP()
489 DCHECK(handled);
490 return handled;
491 }
492
493 void WebPluginDelegateProxy::OnChannelError() {
494 if (plugin_) {
495 if (window_) {
496 // The actual WebPluginDelegate never got a chance to tell the WebPlugin
497 // its window was going away. Do it on its behalf.
498 WillDestroyWindow();
499 }
500 plugin_->Invalidate();
501 }
502 if (!channel_host_->expecting_shutdown())
503 render_view_->PluginCrashed(info_.path);
504
505 #if defined(OS_MACOSX)
506 // Ensure that the renderer doesn't think the plugin still has focus.
507 if (render_view_)
508 render_view_->PluginFocusChanged(false, instance_id_);
509 #endif
510 }
511
512 void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
513 const gfx::Rect& clip_rect) {
514 // window_rect becomes either a window in native windowing system
515 // coords, or a backing buffer. In either case things will go bad
516 // if the rectangle is very large.
517 if (window_rect.width() < 0 || window_rect.width() > (1<<15) ||
518 window_rect.height() < 0 || window_rect.height() > (1<<15) ||
519 // Clip to 8m pixels; we know this won't overflow due to above checks.
520 window_rect.width() * window_rect.height() > (8<<20)) {
521 return;
522 }
523
524 plugin_rect_ = window_rect;
525 clip_rect_ = clip_rect;
526
527 bool bitmaps_changed = false;
528
529 PluginMsg_UpdateGeometry_Param param;
530 #if defined(OS_MACOSX)
531 param.ack_key = -1;
532 #endif
533
534 if (uses_shared_bitmaps_) {
535 if (!backing_store_canvas_.get() ||
536 (window_rect.width() != backing_store_canvas_->getDevice()->width() ||
537 window_rect.height() != backing_store_canvas_->getDevice()->height()))
538 {
539 bitmaps_changed = true;
540
541 bool needs_background_store = transparent_;
542 #if defined(OS_MACOSX)
543 // We don't support transparency under QuickDraw, and CoreGraphics
544 // preserves transparency information (and does the compositing itself)
545 // so plugins don't need access to the page background.
546 needs_background_store = false;
547 if (transport_store_.get()) {
548 // ResetWindowlessBitmaps inserts the old TransportDIBs into
549 // old_transport_dibs_ using the transport store's file descriptor as
550 // the key. The constraints on the keys are that -1 is reserved
551 // to mean "no ACK required," and in-flight keys must be unique.
552 // File descriptors will never be -1, and because they won't be closed
553 // until receipt of the ACK, they're unique.
554 param.ack_key = transport_store_->handle().fd;
555 }
556 #endif
557
558 // Create a shared memory section that the plugin paints into
559 // asynchronously.
560 ResetWindowlessBitmaps();
561 if (!window_rect.IsEmpty()) {
562 if (!CreateSharedBitmap(&transport_store_, &transport_store_canvas_) ||
563 #if defined(OS_WIN)
564 !CreateSharedBitmap(&backing_store_, &backing_store_canvas_) ||
565 #else
566 !CreateLocalBitmap(&backing_store_, &backing_store_canvas_) ||
567 #endif
568 (needs_background_store &&
569 !CreateSharedBitmap(&background_store_,
570 &background_store_canvas_))) {
571 DCHECK(false);
572 ResetWindowlessBitmaps();
573 return;
574 }
575 }
576 }
577 }
578
579 param.window_rect = window_rect;
580 param.clip_rect = clip_rect;
581 param.windowless_buffer = TransportDIB::DefaultHandleValue();
582 param.background_buffer = TransportDIB::DefaultHandleValue();
583 param.transparent = transparent_;
584
585 #if defined(OS_POSIX)
586 // If we're using POSIX mmap'd TransportDIBs, sending the handle across
587 // IPC establishes a new mapping rather than just sending a window ID,
588 // so only do so if we've actually recreated the shared memory bitmaps.
589 if (bitmaps_changed)
590 #endif
591 {
592 if (transport_store_.get())
593 param.windowless_buffer = transport_store_->handle();
594
595 if (background_store_.get())
596 param.background_buffer = background_store_->handle();
597 }
598
599 IPC::Message* msg;
600 #if defined (OS_WIN)
601 if (UseSynchronousGeometryUpdates()) {
602 msg = new PluginMsg_UpdateGeometrySync(instance_id_, param);
603 } else // NOLINT
604 #endif
605 {
606 msg = new PluginMsg_UpdateGeometry(instance_id_, param);
607 msg->set_unblock(true);
608 }
609
610 Send(msg);
611 }
612
613 void WebPluginDelegateProxy::ResetWindowlessBitmaps() {
614 #if defined(OS_MACOSX)
615 DCHECK(!background_store_.get());
616 // The Mac TransportDIB implementation uses base::SharedMemory, which
617 // cannot be disposed of if an in-flight UpdateGeometry message refers to
618 // the shared memory file descriptor. The old_transport_dibs_ map holds
619 // old TransportDIBs waiting to die, keyed by the |ack_key| values used in
620 // UpdateGeometry messages. When an UpdateGeometry_ACK message arrives,
621 // the associated TransportDIB can be released.
622 if (transport_store_.get()) {
623 int ack_key = transport_store_->handle().fd;
624
625 DCHECK_NE(ack_key, -1);
626
627 // DCHECK_EQ does not work with base::hash_map.
628 DCHECK(old_transport_dibs_.find(ack_key) == old_transport_dibs_.end());
629
630 // Stash the old TransportDIB in the map. It'll be released when an
631 // ACK message comes in.
632 old_transport_dibs_[ack_key] =
633 linked_ptr<TransportDIB>(transport_store_.release());
634 }
635 #else
636 transport_store_.reset();
637 background_store_.reset();
638 #endif
639 #if defined(OS_WIN)
640 backing_store_.reset();
641 #else
642 backing_store_.resize(0);
643 #endif
644
645 backing_store_canvas_.reset();
646 transport_store_canvas_.reset();
647 background_store_canvas_.reset();
648 backing_store_painted_ = gfx::Rect();
649 }
650
651 static size_t BitmapSizeForPluginRect(const gfx::Rect& plugin_rect) {
652 const size_t stride =
653 skia::PlatformCanvas::StrideForWidth(plugin_rect.width());
654 return stride * plugin_rect.height();
655 }
656
657 #if !defined(OS_WIN)
658 bool WebPluginDelegateProxy::CreateLocalBitmap(
659 std::vector<uint8>* memory,
660 scoped_ptr<skia::PlatformCanvas>* canvas) {
661 const size_t size = BitmapSizeForPluginRect(plugin_rect_);
662 memory->resize(size);
663 if (memory->size() != size)
664 return false;
665 canvas->reset(new skia::PlatformCanvas(
666 plugin_rect_.width(), plugin_rect_.height(), true, &((*memory)[0])));
667 return true;
668 }
669 #endif
670
671 bool WebPluginDelegateProxy::CreateSharedBitmap(
672 scoped_ptr<TransportDIB>* memory,
673 scoped_ptr<skia::PlatformCanvas>* canvas) {
674 const size_t size = BitmapSizeForPluginRect(plugin_rect_);
675 #if defined(OS_POSIX) && !defined(OS_MACOSX)
676 memory->reset(TransportDIB::Create(size, 0));
677 if (!memory->get())
678 return false;
679 #endif
680 #if defined(OS_MACOSX)
681 TransportDIB::Handle handle;
682 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, true, &handle);
683 if (!RenderThread::current()->Send(msg))
684 return false;
685 if (handle.fd < 0)
686 return false;
687 memory->reset(TransportDIB::Map(handle));
688 #else
689 static uint32 sequence_number = 0;
690 memory->reset(TransportDIB::Create(size, sequence_number++));
691 #endif
692 canvas->reset((*memory)->GetPlatformCanvas(plugin_rect_.width(),
693 plugin_rect_.height()));
694 return !!canvas->get();
695 }
696
697 #if defined(OS_MACOSX)
698 // Flips |rect| vertically within an enclosing rect with height |height|.
699 // Intended for converting rects between flipped and non-flipped contexts.
700 static void FlipRectVerticallyWithHeight(gfx::Rect* rect, int height) {
701 rect->set_y(height - rect->y() - rect->height());
702 }
703 #endif
704
705 void WebPluginDelegateProxy::Paint(WebKit::WebCanvas* canvas,
706 const gfx::Rect& damaged_rect) {
707 // Limit the damaged rectangle to whatever is contained inside the plugin
708 // rectangle, as that's the rectangle that we'll actually draw.
709 gfx::Rect rect = damaged_rect.Intersect(plugin_rect_);
710
711 // If the plugin is no longer connected (channel crashed) draw a crashed
712 // plugin bitmap
713 if (!channel_host_ || !channel_host_->channel_valid()) {
714 PaintSadPlugin(canvas, rect);
715 return;
716 }
717
718 if (!uses_shared_bitmaps_)
719 return;
720
721 // We got a paint before the plugin's coordinates, so there's no buffer to
722 // copy from.
723 if (!backing_store_canvas_.get())
724 return;
725
726 // We're using the native OS APIs from here on out.
727 #if WEBKIT_USING_SKIA
728 gfx::NativeDrawingContext context = canvas->beginPlatformPaint();
729 #elif WEBKIT_USING_CG
730 gfx::NativeDrawingContext context = canvas;
731 #endif
732
733 gfx::Rect offset_rect = rect;
734 offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y());
735 gfx::Rect canvas_rect = offset_rect;
736 #if defined(OS_MACOSX)
737 // The canvases are flipped relative to the context, so flip the rect too.
738 FlipRectVerticallyWithHeight(&canvas_rect, plugin_rect_.height());
739 #endif
740
741 bool background_changed = false;
742 if (background_store_canvas_.get() && BackgroundChanged(context, rect)) {
743 background_changed = true;
744 gfx::Rect flipped_offset_rect = offset_rect;
745 BlitContextToCanvas(background_store_canvas_.get(), canvas_rect,
746 context, rect.origin());
747 }
748
749 if (background_changed || !backing_store_painted_.Contains(offset_rect)) {
750 Send(new PluginMsg_Paint(instance_id_, offset_rect));
751 CopyFromTransportToBacking(offset_rect);
752 }
753
754 BlitCanvasToContext(context, rect, backing_store_canvas_.get(),
755 canvas_rect.origin());
756
757 if (invalidate_pending_) {
758 // Only send the PaintAck message if this paint is in response to an
759 // invalidate from the plugin, since this message acts as an access token
760 // to ensure only one process is using the transport dib at a time.
761 invalidate_pending_ = false;
762 Send(new PluginMsg_DidPaint(instance_id_));
763 }
764
765 #if WEBKIT_USING_SKIA
766 canvas->endPlatformPaint();
767 #endif
768 }
769
770 bool WebPluginDelegateProxy::BackgroundChanged(
771 gfx::NativeDrawingContext context,
772 const gfx::Rect& rect) {
773 #if defined(OS_WIN)
774 HBITMAP hbitmap = static_cast<HBITMAP>(GetCurrentObject(context, OBJ_BITMAP));
775 if (hbitmap == NULL) {
776 NOTREACHED();
777 return true;
778 }
779
780 BITMAP bitmap = { 0 };
781 int result = GetObject(hbitmap, sizeof(bitmap), &bitmap);
782 if (!result) {
783 NOTREACHED();
784 return true;
785 }
786
787 XFORM xf;
788 if (!GetWorldTransform(context, &xf)) {
789 NOTREACHED();
790 return true;
791 }
792
793 // The damaged rect that we're given can be larger than the bitmap, so
794 // intersect their rects first.
795 gfx::Rect bitmap_rect(static_cast<int>(-xf.eDx), static_cast<int>(-xf.eDy),
796 bitmap.bmWidth, bitmap.bmHeight);
797 gfx::Rect check_rect = rect.Intersect(bitmap_rect);
798 int row_byte_size = check_rect.width() * (bitmap.bmBitsPixel / 8);
799 for (int y = check_rect.y(); y < check_rect.bottom(); y++) {
800 char* hdc_row_start = static_cast<char*>(bitmap.bmBits) +
801 (y + static_cast<int>(xf.eDy)) * bitmap.bmWidthBytes +
802 (check_rect.x() + static_cast<int>(xf.eDx)) * (bitmap.bmBitsPixel / 8);
803
804 // getAddr32 doesn't use the translation units, so we have to subtract
805 // the plugin origin from the coordinates.
806 uint32_t* canvas_row_start =
807 background_store_canvas_->getDevice()->accessBitmap(true).getAddr32(
808 check_rect.x() - plugin_rect_.x(), y - plugin_rect_.y());
809 if (memcmp(hdc_row_start, canvas_row_start, row_byte_size) != 0)
810 return true;
811 }
812 #else
813 #if defined(OS_MACOSX)
814 // If there is a translation on the content area context, we need to account
815 // for it; the context may be a subset of the full content area with a
816 // transform that makes the coordinates work out.
817 CGAffineTransform transform = CGContextGetCTM(context);
818 bool flipped = fabs(transform.d + 1) < 0.0001;
819 CGFloat context_offset_x = -transform.tx;
820 CGFloat context_offset_y = flipped ? transform.ty -
821 CGBitmapContextGetHeight(context)
822 : -transform.ty;
823 gfx::Rect full_content_rect(context_offset_x, context_offset_y,
824 CGBitmapContextGetWidth(context),
825 CGBitmapContextGetHeight(context));
826 #else
827 cairo_surface_t* page_surface = cairo_get_target(context);
828 DCHECK_EQ(cairo_surface_get_type(page_surface), CAIRO_SURFACE_TYPE_IMAGE);
829 DCHECK_EQ(cairo_image_surface_get_format(page_surface), CAIRO_FORMAT_ARGB32);
830
831 // Transform context coordinates into surface coordinates.
832 double page_x_double = rect.x();
833 double page_y_double = rect.y();
834 cairo_user_to_device(context, &page_x_double, &page_y_double);
835 gfx::Rect full_content_rect(0, 0,
836 cairo_image_surface_get_width(page_surface),
837 cairo_image_surface_get_height(page_surface));
838 #endif
839 // According to comments in the Windows code, the damage rect that we're given
840 // may project outside the image, so intersect their rects.
841 gfx::Rect content_rect = rect.Intersect(full_content_rect);
842
843 #if defined(OS_MACOSX)
844 const unsigned char* page_bytes = static_cast<const unsigned char*>(
845 CGBitmapContextGetData(context));
846 int page_stride = CGBitmapContextGetBytesPerRow(context);
847 int page_start_x = content_rect.x() - context_offset_x;
848 int page_start_y = content_rect.y() - context_offset_y;
849
850 CGContextRef bg_context =
851 background_store_canvas_->getTopPlatformDevice().GetBitmapContext();
852 DCHECK_EQ(CGBitmapContextGetBitsPerPixel(context),
853 CGBitmapContextGetBitsPerPixel(bg_context));
854 const unsigned char* bg_bytes = static_cast<const unsigned char*>(
855 CGBitmapContextGetData(bg_context));
856 int full_bg_width = CGBitmapContextGetWidth(bg_context);
857 int full_bg_height = CGBitmapContextGetHeight(bg_context);
858 int bg_stride = CGBitmapContextGetBytesPerRow(bg_context);
859 int bg_last_row = CGBitmapContextGetHeight(bg_context) - 1;
860
861 int bytes_per_pixel = CGBitmapContextGetBitsPerPixel(context) / 8;
862 #else
863 cairo_surface_flush(page_surface);
864 const unsigned char* page_bytes = cairo_image_surface_get_data(page_surface);
865 int page_stride = cairo_image_surface_get_stride(page_surface);
866 int page_start_x = static_cast<int>(page_x_double);
867 int page_start_y = static_cast<int>(page_y_double);
868
869 skia::PlatformDevice& device =
870 background_store_canvas_->getTopPlatformDevice();
871 cairo_surface_t* bg_surface = cairo_get_target(device.beginPlatformPaint());
872 DCHECK_EQ(cairo_surface_get_type(bg_surface), CAIRO_SURFACE_TYPE_IMAGE);
873 DCHECK_EQ(cairo_image_surface_get_format(bg_surface), CAIRO_FORMAT_ARGB32);
874 cairo_surface_flush(bg_surface);
875 const unsigned char* bg_bytes = cairo_image_surface_get_data(bg_surface);
876 int full_bg_width = cairo_image_surface_get_width(bg_surface);
877 int full_bg_height = cairo_image_surface_get_height(bg_surface);
878 int bg_stride = cairo_image_surface_get_stride(bg_surface);
879
880 int bytes_per_pixel = 4; // ARGB32 = 4 bytes per pixel.
881 #endif
882
883 int damage_width = content_rect.width();
884 int damage_height = content_rect.height();
885
886 int bg_start_x = rect.x() - plugin_rect_.x();
887 int bg_start_y = rect.y() - plugin_rect_.y();
888 // The damage rect is supposed to have been intersected with the plugin rect;
889 // double-check, since if it hasn't we'll walk off the end of the buffer.
890 DCHECK_LE(bg_start_x + damage_width, full_bg_width);
891 DCHECK_LE(bg_start_y + damage_height, full_bg_height);
892
893 int bg_x_byte_offset = bg_start_x * bytes_per_pixel;
894 int page_x_byte_offset = page_start_x * bytes_per_pixel;
895 for (int row = 0; row < damage_height; ++row) {
896 int page_offset = page_stride * (page_start_y + row) + page_x_byte_offset;
897 int bg_y = bg_start_y + row;
898 #if defined(OS_MACOSX)
899 // The background buffer is upside down relative to the content.
900 bg_y = bg_last_row - bg_y;
901 #endif
902 int bg_offset = bg_stride * bg_y + bg_x_byte_offset;
903 if (memcmp(page_bytes + page_offset,
904 bg_bytes + bg_offset,
905 damage_width * bytes_per_pixel) != 0)
906 return true;
907 }
908 #endif
909
910 return false;
911 }
912
913 void WebPluginDelegateProxy::Print(gfx::NativeDrawingContext context) {
914 base::SharedMemoryHandle shared_memory;
915 uint32 size;
916 if (!Send(new PluginMsg_Print(instance_id_, &shared_memory, &size)))
917 return;
918
919 base::SharedMemory memory(shared_memory, true);
920 if (!memory.Map(size)) {
921 NOTREACHED();
922 return;
923 }
924
925 #if defined(OS_WIN)
926 scoped_ptr<printing::NativeMetafile> metafile(
927 printing::NativeMetafileFactory::CreateMetafile());
928 if (!metafile->Init(memory.memory(), size)) {
929 NOTREACHED();
930 return;
931 }
932 // Playback the buffer.
933 metafile->Playback(context, NULL);
934 #else
935 // TODO(port): plugin printing.
936 NOTIMPLEMENTED();
937 #endif
938 }
939
940 NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() {
941 if (npobject_)
942 return WebBindings::retainObject(npobject_);
943
944 int route_id = MSG_ROUTING_NONE;
945 Send(new PluginMsg_GetPluginScriptableObject(instance_id_, &route_id));
946 if (route_id == MSG_ROUTING_NONE)
947 return NULL;
948
949 npobject_ = NPObjectProxy::Create(
950 channel_host_.get(), route_id, 0, page_url_);
951
952 return WebBindings::retainObject(npobject_);
953 }
954
955 void WebPluginDelegateProxy::DidFinishLoadWithReason(
956 const GURL& url, NPReason reason, int notify_id) {
957 Send(new PluginMsg_DidFinishLoadWithReason(
958 instance_id_, url, reason, notify_id));
959 }
960
961 void WebPluginDelegateProxy::SetFocus(bool focused) {
962 Send(new PluginMsg_SetFocus(instance_id_, focused));
963 }
964
965 bool WebPluginDelegateProxy::HandleInputEvent(
966 const WebInputEvent& event,
967 WebCursorInfo* cursor_info) {
968 bool handled;
969 WebCursor cursor;
970 // A windowless plugin can enter a modal loop in the context of a
971 // NPP_HandleEvent call, in which case we need to pump messages to
972 // the plugin. We pass of the corresponding event handle to the
973 // plugin process, which is set if the plugin does enter a modal loop.
974 IPC::SyncMessage* message = new PluginMsg_HandleInputEvent(
975 instance_id_, &event, &handled, &cursor);
976 message->set_pump_messages_event(modal_loop_pump_messages_event_.get());
977 Send(message);
978 cursor.GetCursorInfo(cursor_info);
979 return handled;
980 }
981
982 int WebPluginDelegateProxy::GetProcessId() {
983 return channel_host_->peer_pid();
984 }
985
986 void WebPluginDelegateProxy::SetContentAreaFocus(bool has_focus) {
987 IPC::Message* msg = new PluginMsg_SetContentAreaFocus(instance_id_,
988 has_focus);
989 // Make sure focus events are delivered in the right order relative to
990 // sync messages they might interact with (Paint, HandleEvent, etc.).
991 msg->set_unblock(true);
992 Send(msg);
993 }
994
995 #if defined(OS_MACOSX)
996 void WebPluginDelegateProxy::SetWindowFocus(bool window_has_focus) {
997 IPC::Message* msg = new PluginMsg_SetWindowFocus(instance_id_,
998 window_has_focus);
999 // Make sure focus events are delivered in the right order relative to
1000 // sync messages they might interact with (Paint, HandleEvent, etc.).
1001 msg->set_unblock(true);
1002 Send(msg);
1003 }
1004
1005 void WebPluginDelegateProxy::SetContainerVisibility(bool is_visible) {
1006 IPC::Message* msg;
1007 if (is_visible) {
1008 gfx::Rect window_frame = render_view_->rootWindowRect();
1009 gfx::Rect view_frame = render_view_->windowRect();
1010 WebKit::WebView* webview = render_view_->webview();
1011 msg = new PluginMsg_ContainerShown(instance_id_, window_frame, view_frame,
1012 webview && webview->isActive());
1013 } else {
1014 msg = new PluginMsg_ContainerHidden(instance_id_);
1015 }
1016 // Make sure visibility events are delivered in the right order relative to
1017 // sync messages they might interact with (Paint, HandleEvent, etc.).
1018 msg->set_unblock(true);
1019 Send(msg);
1020 }
1021
1022 void WebPluginDelegateProxy::WindowFrameChanged(gfx::Rect window_frame,
1023 gfx::Rect view_frame) {
1024 IPC::Message* msg = new PluginMsg_WindowFrameChanged(instance_id_,
1025 window_frame,
1026 view_frame);
1027 // Make sure frame events are delivered in the right order relative to
1028 // sync messages they might interact with (e.g., HandleEvent).
1029 msg->set_unblock(true);
1030 Send(msg);
1031 }
1032 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16& text,
1033 int plugin_id) {
1034 // If the message isn't intended for this plugin, there's nothing to do.
1035 if (instance_id_ != plugin_id)
1036 return;
1037
1038 IPC::Message* msg = new PluginMsg_ImeCompositionCompleted(instance_id_,
1039 text);
1040 // Order relative to other key events is important.
1041 msg->set_unblock(true);
1042 Send(msg);
1043 }
1044 #endif // OS_MACOSX
1045
1046 void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window) {
1047 uses_shared_bitmaps_ = !window;
1048 window_ = window;
1049 if (plugin_)
1050 plugin_->SetWindow(window);
1051 }
1052
1053 void WebPluginDelegateProxy::WillDestroyWindow() {
1054 DCHECK(window_);
1055 plugin_->WillDestroyWindow(window_);
1056 #if defined(OS_MACOSX)
1057 if (window_) {
1058 // This is actually a "fake" window handle only for the GPU
1059 // plugin. Deallocate it on the browser side.
1060 if (render_view_)
1061 render_view_->DestroyFakePluginWindowHandle(window_);
1062 }
1063 #endif
1064 window_ = gfx::kNullPluginWindow;
1065 }
1066
1067 #if defined(OS_WIN)
1068 void WebPluginDelegateProxy::OnSetWindowlessPumpEvent(
1069 HANDLE modal_loop_pump_messages_event) {
1070 DCHECK(modal_loop_pump_messages_event_ == NULL);
1071
1072 // Bug 25583: this can be null because some "virus scanners" block the
1073 // DuplicateHandle call in the plugin process.
1074 if (!modal_loop_pump_messages_event)
1075 return;
1076
1077 modal_loop_pump_messages_event_.reset(
1078 new base::WaitableEvent(modal_loop_pump_messages_event));
1079 }
1080 #endif
1081
1082 void WebPluginDelegateProxy::OnCancelResource(int id) {
1083 if (plugin_)
1084 plugin_->CancelResource(id);
1085 }
1086
1087 void WebPluginDelegateProxy::OnInvalidateRect(const gfx::Rect& rect) {
1088 if (!plugin_)
1089 return;
1090
1091 // Clip the invalidation rect to the plugin bounds; the plugin may have been
1092 // resized since the invalidate message was sent.
1093 const gfx::Rect clipped_rect(rect.Intersect(gfx::Rect(plugin_rect_.size())));
1094
1095 invalidate_pending_ = true;
1096 CopyFromTransportToBacking(clipped_rect);
1097 plugin_->InvalidateRect(clipped_rect);
1098 }
1099
1100 void WebPluginDelegateProxy::OnGetWindowScriptNPObject(
1101 int route_id, bool* success) {
1102 *success = false;
1103 NPObject* npobject = NULL;
1104 if (plugin_)
1105 npobject = plugin_->GetWindowScriptNPObject();
1106
1107 if (!npobject)
1108 return;
1109
1110 // The stub will delete itself when the proxy tells it that it's released, or
1111 // otherwise when the channel is closed.
1112 window_script_object_ = (new NPObjectStub(
1113 npobject, channel_host_.get(), route_id, 0, page_url_))->AsWeakPtr();
1114 *success = true;
1115 }
1116
1117 void WebPluginDelegateProxy::OnGetPluginElement(int route_id, bool* success) {
1118 *success = false;
1119 NPObject* npobject = NULL;
1120 if (plugin_)
1121 npobject = plugin_->GetPluginElement();
1122 if (!npobject)
1123 return;
1124
1125 // The stub will delete itself when the proxy tells it that it's released, or
1126 // otherwise when the channel is closed.
1127 new NPObjectStub(
1128 npobject, channel_host_.get(), route_id, 0, page_url_);
1129 *success = true;
1130 }
1131
1132 void WebPluginDelegateProxy::OnSetCookie(const GURL& url,
1133 const GURL& first_party_for_cookies,
1134 const std::string& cookie) {
1135 if (plugin_)
1136 plugin_->SetCookie(url, first_party_for_cookies, cookie);
1137 }
1138
1139 void WebPluginDelegateProxy::OnGetCookies(const GURL& url,
1140 const GURL& first_party_for_cookies,
1141 std::string* cookies) {
1142 DCHECK(cookies);
1143 if (plugin_)
1144 *cookies = plugin_->GetCookies(url, first_party_for_cookies);
1145 }
1146
1147 void WebPluginDelegateProxy::OnMissingPluginStatus(int status) {
1148 if (render_view_)
1149 render_view_->OnMissingPluginStatus(this, status);
1150 }
1151
1152 void WebPluginDelegateProxy::PaintSadPlugin(WebKit::WebCanvas* native_context,
1153 const gfx::Rect& rect) {
1154 // Lazily load the sad plugin image.
1155 if (!sad_plugin_) {
1156 sad_plugin_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
1157 IDR_SAD_PLUGIN);
1158 }
1159 if (!sad_plugin_)
1160 return;
1161
1162 // Make a temporary canvas for the background image.
1163 const int width = plugin_rect_.width();
1164 const int height = plugin_rect_.height();
1165 gfx::CanvasSkia canvas(width, height, false);
1166 #if defined(OS_MACOSX)
1167 // Flip the canvas, since the context expects flipped data.
1168 canvas.translate(0, height);
1169 canvas.scale(1, -1);
1170 #endif
1171 SkPaint paint;
1172
1173 paint.setStyle(SkPaint::kFill_Style);
1174 paint.setColor(SK_ColorBLACK);
1175 canvas.drawRectCoords(0, 0, SkIntToScalar(width), SkIntToScalar(height),
1176 paint);
1177 canvas.DrawBitmapInt(*sad_plugin_,
1178 std::max(0, (width - sad_plugin_->width())/2),
1179 std::max(0, (height - sad_plugin_->height())/2));
1180
1181 // It's slightly less code to make a big SkBitmap of the sad tab image and
1182 // then copy that to the screen than to use the native APIs. The small speed
1183 // penalty is not important when drawing crashed plugins.
1184 #if WEBKIT_USING_SKIA
1185 gfx::NativeDrawingContext context = native_context->beginPlatformPaint();
1186 BlitCanvasToContext(context, plugin_rect_, &canvas, gfx::Point(0, 0));
1187 native_context->endPlatformPaint();
1188 #elif WEBKIT_USING_CG
1189 BlitCanvasToContext(native_context, plugin_rect_, &canvas, gfx::Point(0, 0));
1190 #endif
1191 }
1192
1193 void WebPluginDelegateProxy::CopyFromTransportToBacking(const gfx::Rect& rect) {
1194 if (!backing_store_canvas_.get()) {
1195 return;
1196 }
1197
1198 // Copy the damaged rect from the transport bitmap to the backing store.
1199 #if defined(OS_MACOSX)
1200 // Blitting the bits directly is much faster than going through CG, and since
1201 // since the goal is just to move the raw pixels between two bitmaps with the
1202 // same pixel format (no compositing, color correction, etc.), it's safe.
1203 const size_t stride =
1204 skia::PlatformCanvas::StrideForWidth(plugin_rect_.width());
1205 const size_t chunk_size = 4 * rect.width();
1206 uint8* source_data = static_cast<uint8*>(transport_store_->memory()) +
1207 rect.y() * stride + 4 * rect.x();
1208 // The two bitmaps are flipped relative to each other.
1209 int dest_starting_row = plugin_rect_.height() - rect.y() - 1;
1210 DCHECK(!backing_store_.empty());
1211 uint8* target_data = &(backing_store_[0]) + dest_starting_row * stride +
1212 4 * rect.x();
1213 for (int row = 0; row < rect.height(); ++row) {
1214 memcpy(target_data, source_data, chunk_size);
1215 source_data += stride;
1216 target_data -= stride;
1217 }
1218 #else
1219 BlitCanvasToCanvas(backing_store_canvas_.get(), rect,
1220 transport_store_canvas_.get(), rect.origin());
1221 #endif
1222 backing_store_painted_ = backing_store_painted_.Union(rect);
1223 }
1224
1225 void WebPluginDelegateProxy::OnHandleURLRequest(
1226 const PluginHostMsg_URLRequest_Params& params) {
1227 const char* data = NULL;
1228 if (params.buffer.size())
1229 data = &params.buffer[0];
1230
1231 const char* target = NULL;
1232 if (params.target.length())
1233 target = params.target.c_str();
1234
1235 plugin_->HandleURLRequest(
1236 params.url.c_str(), params.method.c_str(), target, data,
1237 static_cast<unsigned int>(params.buffer.size()), params.notify_id,
1238 params.popups_allowed, params.notify_redirects);
1239 }
1240
1241 webkit::npapi::WebPluginResourceClient*
1242 WebPluginDelegateProxy::CreateResourceClient(
1243 unsigned long resource_id, const GURL& url, int notify_id) {
1244 if (!channel_host_)
1245 return NULL;
1246
1247 ResourceClientProxy* proxy = new ResourceClientProxy(channel_host_,
1248 instance_id_);
1249 proxy->Initialize(resource_id, url, notify_id);
1250 return proxy;
1251 }
1252
1253 webkit::npapi::WebPluginResourceClient*
1254 WebPluginDelegateProxy::CreateSeekableResourceClient(
1255 unsigned long resource_id, int range_request_id) {
1256 if (!channel_host_)
1257 return NULL;
1258
1259 ResourceClientProxy* proxy = new ResourceClientProxy(channel_host_,
1260 instance_id_);
1261 proxy->InitializeForSeekableStream(resource_id, range_request_id);
1262 return proxy;
1263 }
1264
1265 #if defined(OS_MACOSX)
1266 void WebPluginDelegateProxy::OnFocusChanged(bool focused) {
1267 if (render_view_)
1268 render_view_->PluginFocusChanged(focused, instance_id_);
1269 }
1270
1271 void WebPluginDelegateProxy::OnStartIme() {
1272 if (render_view_)
1273 render_view_->StartPluginIme();
1274 }
1275
1276 void WebPluginDelegateProxy::OnBindFakePluginWindowHandle(bool opaque) {
1277 BindFakePluginWindowHandle(opaque);
1278 }
1279
1280 // Synthesize a fake window handle for the plug-in to identify the instance
1281 // to the browser, allowing mapping to a surface for hardware acceleration
1282 // of plug-in content. The browser generates the handle which is then set on
1283 // the plug-in. Returns true if it successfully sets the window handle on the
1284 // plug-in.
1285 bool WebPluginDelegateProxy::BindFakePluginWindowHandle(bool opaque) {
1286 gfx::PluginWindowHandle fake_window = NULL;
1287 if (render_view_)
1288 fake_window = render_view_->AllocateFakePluginWindowHandle(opaque, false);
1289 // If we aren't running on 10.6, this allocation will fail.
1290 if (!fake_window)
1291 return false;
1292 OnSetWindow(fake_window);
1293 if (!Send(new PluginMsg_SetFakeAcceleratedSurfaceWindowHandle(instance_id_,
1294 fake_window))) {
1295 return false;
1296 }
1297
1298 // Since this isn't a real window, it doesn't get initial size and location
1299 // information the way a real windowed plugin would, so we need to feed it its
1300 // starting geometry.
1301 webkit::npapi::WebPluginGeometry geom;
1302 geom.window = fake_window;
1303 geom.window_rect = plugin_rect_;
1304 geom.clip_rect = clip_rect_;
1305 geom.rects_valid = true;
1306 geom.visible = true;
1307 render_view_->DidMovePlugin(geom);
1308 // Invalidate the plugin region to ensure that the move event actually gets
1309 // dispatched (for a plugin on an otherwise static page).
1310 render_view_->didInvalidateRect(WebKit::WebRect(plugin_rect_.x(),
1311 plugin_rect_.y(),
1312 plugin_rect_.width(),
1313 plugin_rect_.height()));
1314
1315 return true;
1316 }
1317 #endif
1318
1319 gfx::PluginWindowHandle WebPluginDelegateProxy::GetPluginWindowHandle() {
1320 return window_;
1321 }
1322
1323 void WebPluginDelegateProxy::OnCancelDocumentLoad() {
1324 plugin_->CancelDocumentLoad();
1325 }
1326
1327 void WebPluginDelegateProxy::OnInitiateHTTPRangeRequest(
1328 const std::string& url,
1329 const std::string& range_info,
1330 int range_request_id) {
1331 plugin_->InitiateHTTPRangeRequest(
1332 url.c_str(), range_info.c_str(), range_request_id);
1333 }
1334
1335 void WebPluginDelegateProxy::OnDeferResourceLoading(unsigned long resource_id,
1336 bool defer) {
1337 plugin_->SetDeferResourceLoading(resource_id, defer);
1338 }
1339
1340 #if defined(OS_MACOSX)
1341 void WebPluginDelegateProxy::OnUpdateGeometry_ACK(int ack_key) {
1342 DCHECK_NE(ack_key, -1);
1343
1344 OldTransportDIBMap::iterator iterator = old_transport_dibs_.find(ack_key);
1345
1346 // DCHECK_NE does not work with base::hash_map.
1347 DCHECK(iterator != old_transport_dibs_.end());
1348
1349 // Now that the ACK has been received, the TransportDIB that was used
1350 // prior to the UpdateGeometry message now being acknowledged is known to
1351 // be no longer needed. Release it, and take the stale entry out of the map.
1352 ReleaseTransportDIB(iterator->second.get());
1353
1354 old_transport_dibs_.erase(iterator);
1355 }
1356
1357 void WebPluginDelegateProxy::OnAcceleratedSurfaceSetIOSurface(
1358 gfx::PluginWindowHandle window,
1359 int32 width,
1360 int32 height,
1361 uint64 io_surface_identifier) {
1362 if (render_view_)
1363 render_view_->AcceleratedSurfaceSetIOSurface(window, width, height,
1364 io_surface_identifier);
1365 }
1366
1367 void WebPluginDelegateProxy::OnAcceleratedSurfaceSetTransportDIB(
1368 gfx::PluginWindowHandle window,
1369 int32 width,
1370 int32 height,
1371 TransportDIB::Handle transport_dib) {
1372 if (render_view_)
1373 render_view_->AcceleratedSurfaceSetTransportDIB(window, width, height,
1374 transport_dib);
1375 }
1376
1377 void WebPluginDelegateProxy::OnAcceleratedSurfaceAllocTransportDIB(
1378 size_t size,
1379 TransportDIB::Handle* dib_handle) {
1380 if (render_view_)
1381 *dib_handle = render_view_->AcceleratedSurfaceAllocTransportDIB(size);
1382 else
1383 *dib_handle = TransportDIB::DefaultHandleValue();
1384 }
1385
1386 void WebPluginDelegateProxy::OnAcceleratedSurfaceFreeTransportDIB(
1387 TransportDIB::Id dib_id) {
1388 if (render_view_)
1389 render_view_->AcceleratedSurfaceFreeTransportDIB(dib_id);
1390 }
1391
1392 void WebPluginDelegateProxy::OnAcceleratedSurfaceBuffersSwapped(
1393 gfx::PluginWindowHandle window, uint64 surface_id) {
1394 if (render_view_)
1395 render_view_->AcceleratedSurfaceBuffersSwapped(window, surface_id);
1396 }
1397 #endif
1398
1399 #if defined(OS_WIN)
1400 bool WebPluginDelegateProxy::UseSynchronousGeometryUpdates() {
1401 // Need to update geometry synchronously with WMP, otherwise if a site
1402 // scripts the plugin to start playing while it's in the middle of handling
1403 // an update geometry message, videos don't play. See urls in bug 20260.
1404 if (info_.name.find(ASCIIToUTF16("Windows Media Player")) != string16::npos)
1405 return true;
1406
1407 // The move networks plugin needs to be informed of geometry updates
1408 // synchronously.
1409 std::vector<webkit::npapi::WebPluginMimeType>::iterator index;
1410 for (index = info_.mime_types.begin(); index != info_.mime_types.end();
1411 index++) {
1412 if (index->mime_type == "application/x-vnd.moveplayer.qm" ||
1413 index->mime_type == "application/x-vnd.moveplay2.qm" ||
1414 index->mime_type == "application/x-vnd.movenetworks.qm" ||
1415 index->mime_type == "application/x-vnd.mnplayer.qm") {
1416 return true;
1417 }
1418 }
1419 return false;
1420 }
1421 #endif
1422
1423 void WebPluginDelegateProxy::OnURLRedirectResponse(bool allow,
1424 int resource_id) {
1425 if (!plugin_)
1426 return;
1427
1428 plugin_->URLRedirectResponse(allow, resource_id);
1429 }
OLDNEW
« no previous file with comments | « chrome/renderer/webplugin_delegate_proxy.h ('k') | chrome/renderer/websharedworker_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698