<webview>: Remove broken captureVisibleRegion code until feature is properly supported
[chromium-blink-merge.git] / content / renderer / browser_plugin / browser_plugin.cc
blob2eca1da2c993cfb58cc0a9cf6b542fbf984c26ff
1 // Copyright 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/browser_plugin/browser_plugin.h"
7 #include "base/command_line.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/common/browser_plugin/browser_plugin_constants.h"
12 #include "content/common/browser_plugin/browser_plugin_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/common/content_client.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/renderer/browser_plugin_delegate.h"
17 #include "content/public/renderer/content_renderer_client.h"
18 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
19 #include "content/renderer/child_frame_compositing_helper.h"
20 #include "content/renderer/cursor_utils.h"
21 #include "content/renderer/drop_data_builder.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "content/renderer/sad_plugin.h"
24 #include "third_party/WebKit/public/platform/WebRect.h"
25 #include "third_party/WebKit/public/web/WebDocument.h"
26 #include "third_party/WebKit/public/web/WebElement.h"
27 #include "third_party/WebKit/public/web/WebInputEvent.h"
28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
29 #include "third_party/WebKit/public/web/WebPluginContainer.h"
30 #include "third_party/WebKit/public/web/WebView.h"
31 #include "third_party/skia/include/core/SkCanvas.h"
32 #include "ui/events/keycodes/keyboard_codes.h"
34 using blink::WebCanvas;
35 using blink::WebPluginContainer;
36 using blink::WebPoint;
37 using blink::WebRect;
38 using blink::WebURL;
39 using blink::WebVector;
41 namespace {
42 typedef std::map<blink::WebPluginContainer*, content::BrowserPlugin*>
43 PluginContainerMap;
44 static base::LazyInstance<PluginContainerMap> g_plugin_container_map =
45 LAZY_INSTANCE_INITIALIZER;
46 } // namespace
48 namespace content {
50 // static
51 BrowserPlugin* BrowserPlugin::GetFromNode(blink::WebNode& node) {
52 blink::WebPluginContainer* container = node.pluginContainer();
53 if (!container)
54 return NULL;
56 PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
57 PluginContainerMap::iterator it = browser_plugins->find(container);
58 return it == browser_plugins->end() ? NULL : it->second;
61 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
62 blink::WebFrame* frame,
63 scoped_ptr<BrowserPluginDelegate> delegate)
64 : attached_(false),
65 attach_pending_(false),
66 render_view_(render_view->AsWeakPtr()),
67 render_view_routing_id_(render_view->GetRoutingID()),
68 container_(NULL),
69 last_device_scale_factor_(GetDeviceScaleFactor()),
70 sad_guest_(NULL),
71 guest_crashed_(false),
72 plugin_focused_(false),
73 visible_(true),
74 mouse_locked_(false),
75 ready_(false),
76 browser_plugin_manager_(render_view->GetBrowserPluginManager()),
77 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
78 contents_opaque_(true),
79 delegate_(delegate.Pass()),
80 weak_ptr_factory_(this) {
81 browser_plugin_instance_id_ = browser_plugin_manager()->GetNextInstanceID();
83 if (delegate_)
84 delegate_->SetElementInstanceID(browser_plugin_instance_id_);
87 BrowserPlugin::~BrowserPlugin() {
88 browser_plugin_manager()->RemoveBrowserPlugin(browser_plugin_instance_id_);
91 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
92 bool handled = true;
93 IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
94 IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
95 IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
96 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
97 OnCompositorFrameSwapped(message))
98 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
99 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetContentsOpaque, OnSetContentsOpaque)
100 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
101 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
102 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetTooltipText, OnSetTooltipText)
103 IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
104 OnShouldAcceptTouchEvents)
105 IPC_MESSAGE_UNHANDLED(handled = false)
106 IPC_END_MESSAGE_MAP()
107 return handled;
110 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
111 const base::string16& attribute_value) {
112 if (!container())
113 return;
115 blink::WebElement element = container()->element();
116 blink::WebString web_attribute_name =
117 blink::WebString::fromUTF8(attribute_name);
118 element.setAttribute(web_attribute_name, attribute_value);
121 void BrowserPlugin::Attach() {
122 if (ready()) {
123 attached_ = false;
124 guest_crashed_ = false;
125 EnableCompositing(false);
126 if (compositing_helper_.get()) {
127 compositing_helper_->OnContainerDestroy();
128 compositing_helper_ = NULL;
132 // TODO(fsamuel): Add support for reattachment.
133 BrowserPluginHostMsg_Attach_Params attach_params;
134 attach_params.focused = ShouldGuestBeFocused();
135 attach_params.visible = visible_;
136 attach_params.origin = plugin_rect().origin();
137 attach_params.is_full_page_plugin = false;
138 if (container()) {
139 blink::WebLocalFrame* frame = container()->element().document().frame();
140 attach_params.is_full_page_plugin =
141 frame->view()->mainFrame()->document().isPluginDocument();
143 gfx::Size view_size(width(), height());
144 if (!view_size.IsEmpty()) {
145 PopulateResizeGuestParameters(view_size,
146 &attach_params.resize_guest_params);
148 browser_plugin_manager()->Send(new BrowserPluginHostMsg_Attach(
149 render_view_routing_id_,
150 browser_plugin_instance_id_,
151 attach_params));
153 attach_pending_ = true;
156 void BrowserPlugin::DidCommitCompositorFrame() {
157 if (compositing_helper_.get())
158 compositing_helper_->DidCommitCompositorFrame();
161 void BrowserPlugin::OnAdvanceFocus(int browser_plugin_instance_id,
162 bool reverse) {
163 DCHECK(render_view_);
164 render_view_->GetWebView()->advanceFocus(reverse);
167 void BrowserPlugin::OnAttachACK(int browser_plugin_instance_id) {
168 DCHECK(!attached());
169 attached_ = true;
170 attach_pending_ = false;
173 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
174 BrowserPluginMsg_CompositorFrameSwapped::Param param;
175 if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
176 return;
177 // Note that there is no need to send ACK for this message.
178 // If the guest has updated pixels then it is no longer crashed.
179 guest_crashed_ = false;
181 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
182 param.b.frame.AssignTo(frame.get());
184 EnableCompositing(true);
185 compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
186 param.b.producing_route_id,
187 param.b.output_surface_id,
188 param.b.producing_host_id,
189 param.b.shared_memory_handle);
192 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
193 guest_crashed_ = true;
195 // Turn off compositing so we can display the sad graphic. Changes to
196 // compositing state will show up at a later time after a layout and commit.
197 EnableCompositing(false);
199 // Queue up showing the sad graphic to give content embedders an opportunity
200 // to fire their listeners and potentially overlay the webview with custom
201 // behavior. If the BrowserPlugin is destroyed in the meantime, then the
202 // task will not be executed.
203 base::MessageLoop::current()->PostTask(
204 FROM_HERE,
205 base::Bind(&BrowserPlugin::ShowSadGraphic,
206 weak_ptr_factory_.GetWeakPtr()));
209 void BrowserPlugin::OnSetContentsOpaque(int browser_plugin_instance_id,
210 bool opaque) {
211 if (contents_opaque_ == opaque)
212 return;
213 contents_opaque_ = opaque;
214 if (compositing_helper_.get())
215 compositing_helper_->SetContentsOpaque(opaque);
218 void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id,
219 const WebCursor& cursor) {
220 cursor_ = cursor;
223 void BrowserPlugin::OnSetMouseLock(int browser_plugin_instance_id,
224 bool enable) {
225 if (enable) {
226 if (mouse_locked_)
227 return;
228 render_view_->mouse_lock_dispatcher()->LockMouse(this);
229 } else {
230 if (!mouse_locked_) {
231 OnLockMouseACK(false);
232 return;
234 render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
238 void BrowserPlugin::OnSetTooltipText(int instance_id,
239 const base::string16& tooltip_text) {
240 // Show tooltip text by setting the BrowserPlugin's |title| attribute.
241 UpdateDOMAttribute("title", tooltip_text);
244 void BrowserPlugin::OnShouldAcceptTouchEvents(int browser_plugin_instance_id,
245 bool accept) {
246 if (container()) {
247 container()->requestTouchEventType(
248 accept ? WebPluginContainer::TouchEventRequestTypeRaw
249 : WebPluginContainer::TouchEventRequestTypeNone);
253 void BrowserPlugin::ShowSadGraphic() {
254 // If the BrowserPlugin is scheduled to be deleted, then container_ will be
255 // NULL so we shouldn't attempt to access it.
256 if (container_)
257 container_->invalidate();
260 float BrowserPlugin::GetDeviceScaleFactor() const {
261 if (!render_view_)
262 return 1.0f;
263 return render_view_->GetWebView()->deviceScaleFactor();
266 void BrowserPlugin::UpdateDeviceScaleFactor() {
267 if (last_device_scale_factor_ == GetDeviceScaleFactor())
268 return;
270 BrowserPluginHostMsg_ResizeGuest_Params params;
271 PopulateResizeGuestParameters(plugin_size(), &params);
272 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
273 render_view_routing_id_,
274 browser_plugin_instance_id_,
275 params));
278 void BrowserPlugin::UpdateGuestFocusState() {
279 if (!ready())
280 return;
281 bool should_be_focused = ShouldGuestBeFocused();
282 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
283 render_view_routing_id_,
284 browser_plugin_instance_id_,
285 should_be_focused));
288 bool BrowserPlugin::ShouldGuestBeFocused() const {
289 bool embedder_focused = false;
290 if (render_view_)
291 embedder_focused = render_view_->has_focus();
292 return plugin_focused_ && embedder_focused;
295 WebPluginContainer* BrowserPlugin::container() const {
296 return container_;
299 bool BrowserPlugin::initialize(WebPluginContainer* container) {
300 if (!container)
301 return false;
303 container_ = container;
304 container_->setWantsWheelEvents(true);
306 g_plugin_container_map.Get().insert(std::make_pair(container_, this));
308 browser_plugin_manager()->AddBrowserPlugin(browser_plugin_instance_id_, this);
310 // This is a way to notify observers of our attributes that this plugin is
311 // available in render tree.
312 // TODO(lazyboy): This should be done through the delegate instead. Perhaps
313 // by firing an event from there.
314 UpdateDOMAttribute(
315 "internalinstanceid",
316 base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
318 return true;
321 void BrowserPlugin::EnableCompositing(bool enable) {
322 bool enabled = !!compositing_helper_.get();
323 if (enabled == enable)
324 return;
326 if (enable) {
327 DCHECK(!compositing_helper_.get());
328 if (!compositing_helper_.get()) {
329 compositing_helper_ = ChildFrameCompositingHelper::CreateForBrowserPlugin(
330 weak_ptr_factory_.GetWeakPtr());
333 compositing_helper_->EnableCompositing(enable);
334 compositing_helper_->SetContentsOpaque(contents_opaque_);
336 if (!enable) {
337 DCHECK(compositing_helper_.get());
338 compositing_helper_->OnContainerDestroy();
339 compositing_helper_ = NULL;
343 void BrowserPlugin::destroy() {
344 if (container_) {
345 //container_->clearScriptObjects();
347 // The BrowserPlugin's WebPluginContainer is deleted immediately after this
348 // call returns, so let's not keep a reference to it around.
349 g_plugin_container_map.Get().erase(container_);
352 if (compositing_helper_.get())
353 compositing_helper_->OnContainerDestroy();
354 container_ = NULL;
355 // Will be a no-op if the mouse is not currently locked.
356 if (render_view_)
357 render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
358 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
361 bool BrowserPlugin::supportsKeyboardFocus() const {
362 return true;
365 bool BrowserPlugin::supportsEditCommands() const {
366 return true;
369 bool BrowserPlugin::supportsInputMethod() const {
370 return true;
373 bool BrowserPlugin::canProcessDrag() const {
374 return true;
377 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
378 if (guest_crashed_) {
379 if (!sad_guest_) // Lazily initialize bitmap.
380 sad_guest_ = content::GetContentClient()->renderer()->
381 GetSadWebViewBitmap();
382 // content_shell does not have the sad plugin bitmap, so we'll paint black
383 // instead to make it clear that something went wrong.
384 if (sad_guest_) {
385 PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
386 return;
389 SkAutoCanvasRestore auto_restore(canvas, true);
390 canvas->translate(plugin_rect_.x(), plugin_rect_.y());
391 SkRect image_data_rect = SkRect::MakeXYWH(
392 SkIntToScalar(0),
393 SkIntToScalar(0),
394 SkIntToScalar(plugin_rect_.width()),
395 SkIntToScalar(plugin_rect_.height()));
396 canvas->clipRect(image_data_rect);
397 // Paint black or white in case we have nothing in our backing store or we
398 // need to show a gutter.
399 SkPaint paint;
400 paint.setStyle(SkPaint::kFill_Style);
401 paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
402 canvas->drawRect(image_data_rect, paint);
405 // static
406 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
407 const IPC::Message& message) {
408 switch (message.type()) {
409 case BrowserPluginMsg_Attach_ACK::ID:
410 case BrowserPluginMsg_AdvanceFocus::ID:
411 case BrowserPluginMsg_CompositorFrameSwapped::ID:
412 case BrowserPluginMsg_GuestGone::ID:
413 case BrowserPluginMsg_SetContentsOpaque::ID:
414 case BrowserPluginMsg_SetCursor::ID:
415 case BrowserPluginMsg_SetMouseLock::ID:
416 case BrowserPluginMsg_SetTooltipText::ID:
417 case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
418 return true;
419 default:
420 break;
422 return false;
425 void BrowserPlugin::updateGeometry(
426 const WebRect& window_rect,
427 const WebRect& clip_rect,
428 const WebVector<WebRect>& cut_outs_rects,
429 bool is_visible) {
430 int old_width = width();
431 int old_height = height();
432 plugin_rect_ = window_rect;
433 if (!ready_) {
434 if (delegate_)
435 delegate_->Ready();
436 ready_ = true;
438 if (!attached())
439 return;
441 if (old_width == window_rect.width && old_height == window_rect.height) {
442 // Let the browser know about the updated view rect.
443 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
444 render_view_routing_id_, browser_plugin_instance_id_, plugin_rect_));
445 return;
448 BrowserPluginHostMsg_ResizeGuest_Params params;
449 PopulateResizeGuestParameters(plugin_size(), &params);
450 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
451 render_view_routing_id_,
452 browser_plugin_instance_id_,
453 params));
456 void BrowserPlugin::PopulateResizeGuestParameters(
457 const gfx::Size& view_size,
458 BrowserPluginHostMsg_ResizeGuest_Params* params) {
459 params->view_size = view_size;
460 params->scale_factor = GetDeviceScaleFactor();
461 if (last_device_scale_factor_ != params->scale_factor) {
462 last_device_scale_factor_ = params->scale_factor;
463 params->repaint = true;
467 void BrowserPlugin::updateFocus(bool focused) {
468 plugin_focused_ = focused;
469 UpdateGuestFocusState();
472 void BrowserPlugin::updateVisibility(bool visible) {
473 if (visible_ == visible)
474 return;
476 visible_ = visible;
477 if (!ready())
478 return;
480 if (compositing_helper_.get())
481 compositing_helper_->UpdateVisibility(visible);
483 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
484 render_view_routing_id_,
485 browser_plugin_instance_id_,
486 visible));
489 bool BrowserPlugin::acceptsInputEvents() {
490 return true;
493 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
494 blink::WebCursorInfo& cursor_info) {
495 if (guest_crashed_ || !ready())
496 return false;
498 if (event.type == blink::WebInputEvent::ContextMenu)
499 return true;
501 if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
502 !edit_commands_.empty()) {
503 browser_plugin_manager()->Send(
504 new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
505 render_view_routing_id_,
506 browser_plugin_instance_id_,
507 edit_commands_));
508 edit_commands_.clear();
511 browser_plugin_manager()->Send(
512 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
513 browser_plugin_instance_id_,
514 plugin_rect_,
515 &event));
516 GetWebKitCursorInfo(cursor_, &cursor_info);
517 return true;
520 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
521 const blink::WebDragData& drag_data,
522 blink::WebDragOperationsMask mask,
523 const blink::WebPoint& position,
524 const blink::WebPoint& screen) {
525 if (guest_crashed_ || !ready())
526 return false;
527 browser_plugin_manager()->Send(
528 new BrowserPluginHostMsg_DragStatusUpdate(
529 render_view_routing_id_,
530 browser_plugin_instance_id_,
531 drag_status,
532 DropDataBuilder::Build(drag_data),
533 mask,
534 position));
535 return true;
538 void BrowserPlugin::didReceiveResponse(
539 const blink::WebURLResponse& response) {
542 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
543 if (delegate_)
544 delegate_->DidReceiveData(data, data_length);
547 void BrowserPlugin::didFinishLoading() {
548 if (delegate_)
549 delegate_->DidFinishLoading();
552 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
555 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
556 void* notify_data) {
559 void BrowserPlugin::didFailLoadingFrameRequest(
560 const blink::WebURL& url,
561 void* notify_data,
562 const blink::WebURLError& error) {
565 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
566 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
567 render_view_routing_id_,
568 browser_plugin_instance_id_,
569 name.utf8()));
571 // BrowserPlugin swallows edit commands.
572 return true;
575 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
576 const blink::WebString& value) {
577 edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
578 // BrowserPlugin swallows edit commands.
579 return true;
582 bool BrowserPlugin::setComposition(
583 const blink::WebString& text,
584 const blink::WebVector<blink::WebCompositionUnderline>& underlines,
585 int selectionStart,
586 int selectionEnd) {
587 if (!ready())
588 return false;
589 std::vector<blink::WebCompositionUnderline> std_underlines;
590 for (size_t i = 0; i < underlines.size(); ++i) {
591 std_underlines.push_back(underlines[i]);
593 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
594 render_view_routing_id_,
595 browser_plugin_instance_id_,
596 text.utf8(),
597 std_underlines,
598 selectionStart,
599 selectionEnd));
600 // TODO(kochi): This assumes the IPC handling always succeeds.
601 return true;
604 bool BrowserPlugin::confirmComposition(
605 const blink::WebString& text,
606 blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
607 if (!ready())
608 return false;
609 bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
610 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
611 render_view_routing_id_,
612 browser_plugin_instance_id_,
613 text.utf8(),
614 keep_selection));
615 // TODO(kochi): This assumes the IPC handling always succeeds.
616 return true;
619 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
620 if (!ready())
621 return;
622 browser_plugin_manager()->Send(
623 new BrowserPluginHostMsg_ExtendSelectionAndDelete(
624 render_view_routing_id_,
625 browser_plugin_instance_id_,
626 before,
627 after));
630 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
631 mouse_locked_ = succeeded;
632 browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
633 render_view_routing_id_,
634 browser_plugin_instance_id_,
635 succeeded));
638 void BrowserPlugin::OnMouseLockLost() {
639 mouse_locked_ = false;
640 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
641 render_view_routing_id_,
642 browser_plugin_instance_id_));
645 bool BrowserPlugin::HandleMouseLockedInputEvent(
646 const blink::WebMouseEvent& event) {
647 browser_plugin_manager()->Send(
648 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
649 browser_plugin_instance_id_,
650 plugin_rect_,
651 &event));
652 return true;
655 } // namespace content