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/browser/browser_plugin/browser_plugin_embedder.h"
7 #include "base/values.h"
8 #include "content/browser/browser_plugin/browser_plugin_guest.h"
9 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
10 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/common/browser_plugin/browser_plugin_constants.h"
14 #include "content/common/browser_plugin/browser_plugin_messages.h"
15 #include "content/common/drag_messages.h"
16 #include "content/common/gpu/gpu_messages.h"
17 #include "content/public/browser/browser_context.h"
18 #include "content/public/browser/content_browser_client.h"
19 #include "content/public/browser/native_web_keyboard_event.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/user_metrics.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/result_codes.h"
24 #include "content/public/common/url_constants.h"
25 #include "net/base/escape.h"
26 #include "ui/events/keycodes/keyboard_codes.h"
31 BrowserPluginHostFactory* BrowserPluginEmbedder::factory_ = NULL;
33 BrowserPluginEmbedder::BrowserPluginEmbedder(WebContentsImpl* web_contents)
34 : WebContentsObserver(web_contents),
35 weak_ptr_factory_(this) {
38 BrowserPluginEmbedder::~BrowserPluginEmbedder() {
42 BrowserPluginEmbedder* BrowserPluginEmbedder::Create(
43 WebContentsImpl* web_contents) {
45 return factory_->CreateBrowserPluginEmbedder(web_contents);
46 return new BrowserPluginEmbedder(web_contents);
49 void BrowserPluginEmbedder::DragEnteredGuest(BrowserPluginGuest* guest) {
50 guest_dragging_over_ = guest->AsWeakPtr();
53 void BrowserPluginEmbedder::DragLeftGuest(BrowserPluginGuest* guest) {
54 // Avoid race conditions in switching between guests being hovered over by
55 // only un-setting if the caller is marked as the guest being dragged over.
56 if (guest_dragging_over_.get() == guest) {
57 guest_dragging_over_.reset();
61 void BrowserPluginEmbedder::StartDrag(BrowserPluginGuest* guest) {
62 guest_started_drag_ = guest->AsWeakPtr();
65 WebContentsImpl* BrowserPluginEmbedder::GetWebContents() const {
66 return static_cast<WebContentsImpl*>(web_contents());
69 BrowserPluginGuestManager*
70 BrowserPluginEmbedder::GetBrowserPluginGuestManager() const {
71 return BrowserPluginGuestManager::FromBrowserContext(
72 GetWebContents()->GetBrowserContext());
75 bool BrowserPluginEmbedder::DidSendScreenRectsCallback(
76 BrowserPluginGuest* guest) {
77 static_cast<RenderViewHostImpl*>(
78 guest->GetWebContents()->GetRenderViewHost())->SendScreenRects();
79 // Not handled => Iterate over all guests.
83 void BrowserPluginEmbedder::DidSendScreenRects() {
84 BrowserPluginGuestManager::FromBrowserContext(
85 GetWebContents()->GetBrowserContext())->ForEachGuest(
86 GetWebContents(), base::Bind(
87 &BrowserPluginEmbedder::DidSendScreenRectsCallback,
88 base::Unretained(this)));
91 bool BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback(
92 const NativeWebKeyboardEvent& event,
93 BrowserPluginGuest* guest) {
94 return guest->UnlockMouseIfNecessary(event);
97 bool BrowserPluginEmbedder::HandleKeyboardEvent(
98 const NativeWebKeyboardEvent& event) {
99 if ((event.type != blink::WebInputEvent::RawKeyDown) ||
100 (event.windowsKeyCode != ui::VKEY_ESCAPE) ||
101 (event.modifiers & blink::WebInputEvent::InputModifiers)) {
105 return GetBrowserPluginGuestManager()->ForEachGuest(
107 base::Bind(&BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback,
108 base::Unretained(this),
112 bool BrowserPluginEmbedder::SetZoomLevelCallback(
113 double level, BrowserPluginGuest* guest) {
114 double zoom_factor = content::ZoomLevelToZoomFactor(level);
115 guest->SetZoom(zoom_factor);
116 // Not handled => Iterate over all guests.
120 void BrowserPluginEmbedder::SetZoomLevel(double level) {
121 GetBrowserPluginGuestManager()->ForEachGuest(
122 GetWebContents(), base::Bind(
123 &BrowserPluginEmbedder::SetZoomLevelCallback,
124 base::Unretained(this),
128 bool BrowserPluginEmbedder::OnMessageReceived(const IPC::Message& message) {
130 IPC_BEGIN_MESSAGE_MAP(BrowserPluginEmbedder, message)
131 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_AllocateInstanceID,
132 OnAllocateInstanceID)
133 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Attach, OnAttach)
134 IPC_MESSAGE_HANDLER_GENERIC(DragHostMsg_UpdateDragCursor,
135 OnUpdateDragCursor(&handled));
136 IPC_MESSAGE_UNHANDLED(handled = false)
137 IPC_END_MESSAGE_MAP()
141 void BrowserPluginEmbedder::DragSourceEndedAt(int client_x, int client_y,
142 int screen_x, int screen_y, blink::WebDragOperation operation) {
143 if (guest_started_drag_.get()) {
144 gfx::Point guest_offset =
145 guest_started_drag_->GetScreenCoordinates(gfx::Point());
146 guest_started_drag_->DragSourceEndedAt(client_x - guest_offset.x(),
147 client_y - guest_offset.y(), screen_x, screen_y, operation);
151 void BrowserPluginEmbedder::SystemDragEnded() {
152 // When the embedder's drag/drop operation ends, we need to pass the message
153 // to the guest that initiated the drag/drop operation. This will ensure that
154 // the guest's RVH state is reset properly.
155 if (guest_started_drag_.get())
156 guest_started_drag_->EndSystemDrag();
157 guest_started_drag_.reset();
158 guest_dragging_over_.reset();
161 void BrowserPluginEmbedder::OnUpdateDragCursor(bool* handled) {
162 *handled = (guest_dragging_over_.get() != NULL);
165 void BrowserPluginEmbedder::OnAllocateInstanceID(int request_id) {
166 int instance_id = GetBrowserPluginGuestManager()->GetNextInstanceID();
167 Send(new BrowserPluginMsg_AllocateInstanceID_ACK(
168 routing_id(), request_id, instance_id));
171 void BrowserPluginEmbedder::OnGuestCallback(
173 const BrowserPluginHostMsg_Attach_Params& params,
174 const base::DictionaryValue* extra_params,
175 BrowserPluginGuest* guest) {
176 BrowserPluginGuestManager* guest_manager = GetBrowserPluginGuestManager();
178 // There is an implicit order expectation here:
179 // 1. The content embedder is made aware of the attachment.
180 // 2. BrowserPluginGuest::Attach is called.
181 // 3. The content embedder issues queued events if any that happened
182 // prior to attachment.
183 GetContentClient()->browser()->GuestWebContentsAttached(
184 guest->GetWebContents(),
187 guest->Attach(GetWebContents(), params, *extra_params);
191 scoped_ptr<base::DictionaryValue> copy_extra_params(extra_params->DeepCopy());
192 guest = guest_manager->CreateGuest(
193 GetWebContents()->GetSiteInstance(),
195 copy_extra_params.Pass());
197 GetContentClient()->browser()->GuestWebContentsAttached(
198 guest->GetWebContents(),
201 guest->Initialize(params, GetWebContents());
205 void BrowserPluginEmbedder::OnAttach(
207 const BrowserPluginHostMsg_Attach_Params& params,
208 const base::DictionaryValue& extra_params) {
209 GetBrowserPluginGuestManager()->MaybeGetGuestByInstanceIDOrKill(
210 instance_id, GetWebContents()->GetRenderProcessHost()->GetID(),
211 base::Bind(&BrowserPluginEmbedder::OnGuestCallback,
212 base::Unretained(this),
218 } // namespace content