OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/guest_view/guest_view_container.h" | 5 #include "extensions/renderer/guest_view/guest_view_container.h" |
6 | 6 |
7 #include "content/public/renderer/browser_plugin_delegate.h" | |
8 #include "content/public/renderer/render_frame.h" | 7 #include "content/public/renderer/render_frame.h" |
9 #include "content/public/renderer/render_view.h" | 8 #include "content/public/renderer/render_view.h" |
10 #include "extensions/common/extension_messages.h" | |
11 #include "extensions/common/guest_view/guest_view_constants.h" | 9 #include "extensions/common/guest_view/guest_view_constants.h" |
12 #include "third_party/WebKit/public/web/WebLocalFrame.h" | |
13 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" | |
14 #include "third_party/WebKit/public/web/WebView.h" | |
15 | |
16 namespace { | |
17 typedef std::pair<int, int> GuestViewID; | |
18 typedef std::map<GuestViewID, extensions::GuestViewContainer*> | |
19 GuestViewContainerMap; | |
20 static base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map = | |
21 LAZY_INSTANCE_INITIALIZER; | |
22 } // namespace | |
23 | 10 |
24 namespace extensions { | 11 namespace extensions { |
25 | 12 |
26 GuestViewContainer::AttachRequest::AttachRequest( | 13 GuestViewContainer::GuestViewContainer(content::RenderFrame* render_frame) |
27 int element_instance_id, | 14 : content::RenderFrameObserver(render_frame), |
28 int guest_instance_id, | 15 element_instance_id_(guestview::kInstanceIDNone), |
29 scoped_ptr<base::DictionaryValue> params, | 16 render_view_routing_id_(render_frame->GetRenderView()->GetRoutingID()) { |
30 v8::Handle<v8::Function> callback, | |
31 v8::Isolate* isolate) | |
32 : element_instance_id_(element_instance_id), | |
33 guest_instance_id_(guest_instance_id), | |
34 params_(params.Pass()), | |
35 callback_(callback), | |
36 isolate_(isolate) { | |
37 } | 17 } |
38 | 18 |
39 GuestViewContainer::AttachRequest::~AttachRequest() { | 19 GuestViewContainer::~GuestViewContainer() {} |
40 } | |
41 | |
42 bool GuestViewContainer::AttachRequest::HasCallback() const { | |
43 return !callback_.IsEmpty(); | |
44 } | |
45 | |
46 v8::Handle<v8::Function> | |
47 GuestViewContainer::AttachRequest::GetCallback() const { | |
48 return callback_.NewHandle(isolate_); | |
49 } | |
50 | |
51 GuestViewContainer::GuestViewContainer( | |
52 content::RenderFrame* render_frame, | |
53 const std::string& mime_type) | |
54 : content::BrowserPluginDelegate(render_frame, mime_type), | |
55 content::RenderFrameObserver(render_frame), | |
56 mime_type_(mime_type), | |
57 element_instance_id_(guestview::kInstanceIDNone), | |
58 render_view_routing_id_(render_frame->GetRenderView()->GetRoutingID()), | |
59 attached_(false), | |
60 ready_(false) { | |
61 } | |
62 | |
63 GuestViewContainer::~GuestViewContainer() { | |
64 if (element_instance_id_ != guestview::kInstanceIDNone) { | |
65 g_guest_view_container_map.Get().erase( | |
66 GuestViewID(render_view_routing_id_, element_instance_id_)); | |
67 } | |
68 } | |
69 | |
70 GuestViewContainer* GuestViewContainer::FromID(int render_view_routing_id, | |
71 int element_instance_id) { | |
72 GuestViewContainerMap* guest_view_containers = | |
73 g_guest_view_container_map.Pointer(); | |
74 GuestViewContainerMap::iterator it = guest_view_containers->find( | |
75 GuestViewID(render_view_routing_id, element_instance_id)); | |
76 return it == guest_view_containers->end() ? NULL : it->second; | |
77 } | |
78 | |
79 void GuestViewContainer::AttachGuest(linked_ptr<AttachRequest> request) { | |
80 EnqueueAttachRequest(request); | |
81 PerformPendingAttachRequest(); | |
82 } | |
83 | 20 |
84 void GuestViewContainer::SetElementInstanceID(int element_instance_id) { | 21 void GuestViewContainer::SetElementInstanceID(int element_instance_id) { |
85 GuestViewID guest_view_id(render_view_routing_id_, element_instance_id); | |
86 DCHECK_EQ(element_instance_id_, guestview::kInstanceIDNone); | 22 DCHECK_EQ(element_instance_id_, guestview::kInstanceIDNone); |
87 DCHECK(g_guest_view_container_map.Get().find(guest_view_id) == | |
88 g_guest_view_container_map.Get().end()); | |
89 element_instance_id_ = element_instance_id; | 23 element_instance_id_ = element_instance_id; |
90 g_guest_view_container_map.Get().insert(std::make_pair(guest_view_id, this)); | |
91 } | |
92 | |
93 void GuestViewContainer::DidFinishLoading() { | |
94 if (mime_type_.empty()) | |
95 return; | |
96 | |
97 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone); | |
98 render_frame()->Send(new ExtensionHostMsg_CreateMimeHandlerViewGuest( | |
99 routing_id(), html_string_, mime_type_, element_instance_id_)); | |
100 } | |
101 | |
102 void GuestViewContainer::DidReceiveData(const char* data, int data_length) { | |
103 std::string value(data, data_length); | |
104 html_string_ += value; | |
105 } | |
106 | |
107 void GuestViewContainer::Ready() { | |
108 ready_ = true; | |
109 CHECK(!pending_response_.get()); | |
110 PerformPendingAttachRequest(); | |
111 } | 24 } |
112 | 25 |
113 void GuestViewContainer::OnDestruct() { | 26 void GuestViewContainer::OnDestruct() { |
114 // GuestViewContainer's lifetime is managed by BrowserPlugin so don't let | 27 // GuestViewContainer's lifetime is managed by BrowserPlugin so don't let |
115 // RenderFrameObserver self-destruct here. | 28 // RenderFrameObserver self-destruct here. |
116 } | 29 } |
117 | 30 |
118 bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) { | 31 bool GuestViewContainer::OnMessageReceived( |
119 if (!ShouldHandleMessage(message)) | 32 const IPC::Message& message) { |
| 33 if (!HandlesMessage(message)) |
120 return false; | 34 return false; |
121 | 35 |
122 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone); | 36 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone); |
123 int element_instance_id = guestview::kInstanceIDNone; | 37 int element_instance_id = guestview::kInstanceIDNone; |
124 PickleIterator iter(message); | 38 PickleIterator iter(message); |
125 bool success = iter.ReadInt(&element_instance_id); | 39 bool success = iter.ReadInt(&element_instance_id); |
126 DCHECK(success); | 40 DCHECK(success); |
127 if (element_instance_id != element_instance_id_) | 41 if (element_instance_id != element_instance_id_) |
128 return false; | 42 return false; |
129 | 43 |
130 bool handled = true; | 44 return OnMessage(message); |
131 IPC_BEGIN_MESSAGE_MAP(GuestViewContainer, message) | |
132 IPC_MESSAGE_HANDLER(ExtensionMsg_CreateMimeHandlerViewGuestACK, | |
133 OnCreateMimeHandlerViewGuestACK) | |
134 IPC_MESSAGE_HANDLER(ExtensionMsg_GuestAttached, OnGuestAttached) | |
135 IPC_MESSAGE_UNHANDLED(handled = false) | |
136 IPC_END_MESSAGE_MAP() | |
137 return handled; | |
138 } | |
139 | |
140 void GuestViewContainer::OnCreateMimeHandlerViewGuestACK( | |
141 int element_instance_id) { | |
142 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone); | |
143 DCHECK_EQ(element_instance_id_, element_instance_id); | |
144 DCHECK(!mime_type_.empty()); | |
145 render_frame()->AttachGuest(element_instance_id); | |
146 } | |
147 | |
148 void GuestViewContainer::OnGuestAttached(int element_instance_id, | |
149 int guest_proxy_routing_id) { | |
150 attached_ = true; | |
151 | |
152 if (!mime_type_.empty()) { | |
153 // MimeHandlerView's creation and attachment is not done via JS API. | |
154 return; | |
155 } | |
156 | |
157 // Handle the callback for the current request with a pending response. | |
158 HandlePendingResponseCallback(guest_proxy_routing_id); | |
159 // Perform the subsequent attach request if one exists. | |
160 PerformPendingAttachRequest(); | |
161 } | |
162 | |
163 void GuestViewContainer::AttachGuestInternal( | |
164 linked_ptr<AttachRequest> request) { | |
165 CHECK(!pending_response_.get()); | |
166 // Step 1, send the attach params to chrome/. | |
167 render_frame()->Send( | |
168 new ExtensionHostMsg_AttachGuest(render_view_routing_id_, | |
169 request->element_instance_id(), | |
170 request->guest_instance_id(), | |
171 *request->attach_params())); | |
172 | |
173 // Step 2, attach plugin through content/. | |
174 render_frame()->AttachGuest(request->element_instance_id()); | |
175 | |
176 pending_response_ = request; | |
177 } | |
178 | |
179 void GuestViewContainer::EnqueueAttachRequest( | |
180 linked_ptr<AttachRequest> request) { | |
181 pending_requests_.push_back(request); | |
182 } | |
183 | |
184 void GuestViewContainer::PerformPendingAttachRequest() { | |
185 if (!ready_ || pending_requests_.empty() || pending_response_.get()) | |
186 return; | |
187 | |
188 linked_ptr<AttachRequest> pending_request = pending_requests_.front(); | |
189 pending_requests_.pop_front(); | |
190 AttachGuestInternal(pending_request); | |
191 } | |
192 | |
193 void GuestViewContainer::HandlePendingResponseCallback( | |
194 int guest_proxy_routing_id) { | |
195 CHECK(pending_response_.get()); | |
196 linked_ptr<AttachRequest> pending_response(pending_response_.release()); | |
197 | |
198 // If we don't have a callback then there's nothing more to do. | |
199 if (!pending_response->HasCallback()) | |
200 return; | |
201 | |
202 content::RenderView* guest_proxy_render_view = | |
203 content::RenderView::FromRoutingID(guest_proxy_routing_id); | |
204 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing? | |
205 if (!guest_proxy_render_view) | |
206 return; | |
207 | |
208 v8::HandleScope handle_scope(pending_response->isolate()); | |
209 v8::Handle<v8::Function> callback = pending_response->GetCallback(); | |
210 v8::Handle<v8::Context> context = callback->CreationContext(); | |
211 if (context.IsEmpty()) | |
212 return; | |
213 | |
214 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame(); | |
215 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global(); | |
216 | |
217 const int argc = 1; | |
218 v8::Handle<v8::Value> argv[argc] = { window }; | |
219 | |
220 v8::Context::Scope context_scope(context); | |
221 blink::WebScopedMicrotaskSuppression suppression; | |
222 | |
223 // Call the AttachGuest API's callback with the guest proxy as the first | |
224 // parameter. | |
225 callback->Call(context->Global(), argc, argv); | |
226 } | |
227 | |
228 // static | |
229 bool GuestViewContainer::ShouldHandleMessage(const IPC::Message& message) { | |
230 switch (message.type()) { | |
231 case ExtensionMsg_CreateMimeHandlerViewGuestACK::ID: | |
232 case ExtensionMsg_GuestAttached::ID: | |
233 return true; | |
234 default: | |
235 break; | |
236 } | |
237 return false; | |
238 } | 45 } |
239 | 46 |
240 } // namespace extensions | 47 } // namespace extensions |
OLD | NEW |