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/extensions_guest_view_container.h" | 5 #include "extensions/renderer/guest_view/extensions_guest_view_container.h" |
6 | 6 |
7 #include "content/public/renderer/render_frame.h" | 7 #include "content/public/renderer/render_frame.h" |
8 #include "content/public/renderer/render_view.h" | 8 #include "content/public/renderer/render_view.h" |
9 #include "extensions/common/extension_messages.h" | 9 #include "extensions/common/extension_messages.h" |
10 #include "extensions/common/guest_view/guest_view_constants.h" | 10 #include "extensions/common/guest_view/guest_view_constants.h" |
11 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 11 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
12 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" | 12 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" |
13 #include "third_party/WebKit/public/web/WebView.h" | 13 #include "third_party/WebKit/public/web/WebView.h" |
14 | 14 |
15 namespace { | 15 namespace { |
16 typedef std::pair<int, int> GuestViewID; | 16 typedef std::map<int, extensions::ExtensionsGuestViewContainer*> |
17 typedef std::map<GuestViewID, extensions::ExtensionsGuestViewContainer*> | |
18 ExtensionsGuestViewContainerMap; | 17 ExtensionsGuestViewContainerMap; |
19 static base::LazyInstance<ExtensionsGuestViewContainerMap> | 18 static base::LazyInstance<ExtensionsGuestViewContainerMap> |
20 g_guest_view_container_map = LAZY_INSTANCE_INITIALIZER; | 19 g_guest_view_container_map = LAZY_INSTANCE_INITIALIZER; |
21 } // namespace | 20 } // namespace |
22 | 21 |
23 namespace extensions { | 22 namespace extensions { |
24 | 23 |
| 24 ExtensionsGuestViewContainer::Request::Request( |
| 25 GuestViewContainer* container, |
| 26 v8::Handle<v8::Function> callback, |
| 27 v8::Isolate* isolate) |
| 28 : container_(container), |
| 29 callback_(callback), |
| 30 isolate_(isolate) { |
| 31 } |
| 32 |
| 33 ExtensionsGuestViewContainer::Request::~Request() { |
| 34 } |
| 35 |
| 36 bool ExtensionsGuestViewContainer::Request::HasCallback() const { |
| 37 return !callback_.IsEmpty(); |
| 38 } |
| 39 |
| 40 v8::Handle<v8::Function> |
| 41 ExtensionsGuestViewContainer::Request::GetCallback() const { |
| 42 return callback_.NewHandle(isolate_); |
| 43 } |
| 44 |
25 ExtensionsGuestViewContainer::AttachRequest::AttachRequest( | 45 ExtensionsGuestViewContainer::AttachRequest::AttachRequest( |
26 int element_instance_id, | 46 GuestViewContainer* container, |
27 int guest_instance_id, | 47 int guest_instance_id, |
28 scoped_ptr<base::DictionaryValue> params, | 48 scoped_ptr<base::DictionaryValue> params, |
29 v8::Handle<v8::Function> callback, | 49 v8::Handle<v8::Function> callback, |
30 v8::Isolate* isolate) | 50 v8::Isolate* isolate) |
31 : element_instance_id_(element_instance_id), | 51 : Request(container, callback, isolate), |
32 guest_instance_id_(guest_instance_id), | 52 guest_instance_id_(guest_instance_id), |
33 params_(params.Pass()), | 53 params_(params.Pass()) { |
34 callback_(callback), | |
35 isolate_(isolate) { | |
36 } | 54 } |
37 | 55 |
38 ExtensionsGuestViewContainer::AttachRequest::~AttachRequest() { | 56 ExtensionsGuestViewContainer::AttachRequest::~AttachRequest() { |
39 } | 57 } |
40 | 58 |
41 bool ExtensionsGuestViewContainer::AttachRequest::HasCallback() const { | 59 void ExtensionsGuestViewContainer::AttachRequest::PerformRequest() { |
42 return !callback_.IsEmpty(); | 60 // Step 1, send the attach params to extensions/. |
| 61 container()->render_frame()->Send( |
| 62 new ExtensionHostMsg_AttachGuest(container()->render_view_routing_id(), |
| 63 container()->element_instance_id(), |
| 64 guest_instance_id_, |
| 65 *params_)); |
| 66 |
| 67 // Step 2, attach plugin through content/. |
| 68 container()->render_frame()->AttachGuest(container()->element_instance_id()); |
43 } | 69 } |
44 | 70 |
45 v8::Handle<v8::Function> | 71 void ExtensionsGuestViewContainer::AttachRequest::HandleResponse( |
46 ExtensionsGuestViewContainer::AttachRequest::GetCallback() const { | 72 const IPC::Message& message) { |
47 return callback_.NewHandle(isolate_); | 73 ExtensionMsg_GuestAttached::Param param; |
| 74 if (!ExtensionMsg_GuestAttached::Read(&message, ¶m)) |
| 75 return; |
| 76 |
| 77 // If we don't have a callback then there's nothing more to do. |
| 78 if (!HasCallback()) |
| 79 return; |
| 80 |
| 81 content::RenderView* guest_proxy_render_view = |
| 82 content::RenderView::FromRoutingID(param.b); |
| 83 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing? |
| 84 if (!guest_proxy_render_view) |
| 85 return; |
| 86 |
| 87 v8::HandleScope handle_scope(isolate()); |
| 88 v8::Handle<v8::Function> callback = GetCallback(); |
| 89 v8::Handle<v8::Context> context = callback->CreationContext(); |
| 90 if (context.IsEmpty()) |
| 91 return; |
| 92 |
| 93 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame(); |
| 94 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global(); |
| 95 |
| 96 const int argc = 1; |
| 97 v8::Handle<v8::Value> argv[argc] = { window }; |
| 98 |
| 99 v8::Context::Scope context_scope(context); |
| 100 blink::WebScopedMicrotaskSuppression suppression; |
| 101 |
| 102 // Call the AttachGuest API's callback with the guest proxy as the first |
| 103 // parameter. |
| 104 callback->Call(context->Global(), argc, argv); |
48 } | 105 } |
49 | 106 |
50 ExtensionsGuestViewContainer::ExtensionsGuestViewContainer( | 107 ExtensionsGuestViewContainer::ExtensionsGuestViewContainer( |
51 content::RenderFrame* render_frame) | 108 content::RenderFrame* render_frame) |
52 : GuestViewContainer(render_frame), | 109 : GuestViewContainer(render_frame), |
53 ready_(false) { | 110 ready_(false) { |
54 } | 111 } |
55 | 112 |
56 ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() { | 113 ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() { |
57 if (element_instance_id() != guestview::kInstanceIDNone) { | 114 if (element_instance_id() != guestview::kInstanceIDNone) { |
58 g_guest_view_container_map.Get().erase( | 115 g_guest_view_container_map.Get().erase(element_instance_id()); |
59 GuestViewID(render_view_routing_id(), element_instance_id())); | |
60 } | 116 } |
61 } | 117 } |
62 | 118 |
63 ExtensionsGuestViewContainer* ExtensionsGuestViewContainer::FromID( | 119 ExtensionsGuestViewContainer* ExtensionsGuestViewContainer::FromID( |
64 int render_view_routing_id, | |
65 int element_instance_id) { | 120 int element_instance_id) { |
66 ExtensionsGuestViewContainerMap* guest_view_containers = | 121 ExtensionsGuestViewContainerMap* guest_view_containers = |
67 g_guest_view_container_map.Pointer(); | 122 g_guest_view_container_map.Pointer(); |
68 ExtensionsGuestViewContainerMap::iterator it = guest_view_containers->find( | 123 ExtensionsGuestViewContainerMap::iterator it = |
69 GuestViewID(render_view_routing_id, element_instance_id)); | 124 guest_view_containers->find(element_instance_id); |
70 return it == guest_view_containers->end() ? NULL : it->second; | 125 return it == guest_view_containers->end() ? NULL : it->second; |
71 } | 126 } |
72 | 127 |
73 void ExtensionsGuestViewContainer::AttachGuest( | 128 void ExtensionsGuestViewContainer::IssueRequest(linked_ptr<Request> request) { |
74 linked_ptr<AttachRequest> request) { | 129 EnqueueRequest(request); |
75 EnqueueAttachRequest(request); | 130 PerformPendingRequest(); |
76 PerformPendingAttachRequest(); | |
77 } | 131 } |
78 | 132 |
79 void ExtensionsGuestViewContainer::SetElementInstanceID( | 133 void ExtensionsGuestViewContainer::SetElementInstanceID( |
80 int element_instance_id) { | 134 int element_instance_id) { |
81 GuestViewContainer::SetElementInstanceID(element_instance_id); | 135 GuestViewContainer::SetElementInstanceID(element_instance_id); |
82 | 136 |
83 GuestViewID guest_view_id(render_view_routing_id(), element_instance_id); | 137 DCHECK(g_guest_view_container_map.Get().find(element_instance_id) == |
84 DCHECK(g_guest_view_container_map.Get().find(guest_view_id) == | |
85 g_guest_view_container_map.Get().end()); | 138 g_guest_view_container_map.Get().end()); |
86 g_guest_view_container_map.Get().insert(std::make_pair(guest_view_id, this)); | 139 g_guest_view_container_map.Get().insert( |
| 140 std::make_pair(element_instance_id, this)); |
87 } | 141 } |
88 | 142 |
89 void ExtensionsGuestViewContainer::Ready() { | 143 void ExtensionsGuestViewContainer::Ready() { |
90 ready_ = true; | 144 ready_ = true; |
91 CHECK(!pending_response_.get()); | 145 CHECK(!pending_response_.get()); |
92 PerformPendingAttachRequest(); | 146 PerformPendingRequest(); |
93 } | 147 } |
94 | 148 |
95 bool ExtensionsGuestViewContainer::HandlesMessage(const IPC::Message& message) { | 149 bool ExtensionsGuestViewContainer::HandlesMessage(const IPC::Message& message) { |
96 return message.type() == ExtensionMsg_GuestAttached::ID; | 150 return (message.type() == ExtensionMsg_GuestAttached::ID); |
97 } | 151 } |
98 | 152 |
99 bool ExtensionsGuestViewContainer::OnMessage(const IPC::Message& message) { | 153 bool ExtensionsGuestViewContainer::OnMessage(const IPC::Message& message) { |
100 bool handled = false; | 154 if (message.type() == ExtensionMsg_GuestAttached::ID) { |
101 IPC_BEGIN_MESSAGE_MAP(ExtensionsGuestViewContainer, message) | 155 OnHandleCallback(message); |
102 IPC_MESSAGE_HANDLER(ExtensionMsg_GuestAttached, OnGuestAttached) | 156 return true; |
103 IPC_MESSAGE_UNHANDLED(handled = false) | 157 } |
104 IPC_END_MESSAGE_MAP() | 158 return false; |
105 return handled; | |
106 } | 159 } |
107 | 160 |
108 void ExtensionsGuestViewContainer::OnGuestAttached(int /* unused */, | 161 void ExtensionsGuestViewContainer::OnHandleCallback( |
109 int guest_proxy_routing_id) { | 162 const IPC::Message& message) { |
110 // Handle the callback for the current request with a pending response. | 163 // Handle the callback for the current request with a pending response. |
111 HandlePendingResponseCallback(guest_proxy_routing_id); | 164 HandlePendingResponseCallback(message); |
112 // Perform the subsequent attach request if one exists. | 165 // Perform the subsequent attach request if one exists. |
113 PerformPendingAttachRequest(); | 166 PerformPendingRequest(); |
114 } | 167 } |
115 | 168 |
116 void ExtensionsGuestViewContainer::AttachGuestInternal( | 169 void ExtensionsGuestViewContainer::EnqueueRequest(linked_ptr<Request> request) { |
117 linked_ptr<AttachRequest> request) { | |
118 CHECK(!pending_response_.get()); | |
119 // Step 1, send the attach params to chrome/. | |
120 render_frame()->Send( | |
121 new ExtensionHostMsg_AttachGuest(render_view_routing_id(), | |
122 request->element_instance_id(), | |
123 request->guest_instance_id(), | |
124 *request->attach_params())); | |
125 | |
126 // Step 2, attach plugin through content/. | |
127 render_frame()->AttachGuest(request->element_instance_id()); | |
128 | |
129 pending_response_ = request; | |
130 } | |
131 | |
132 void ExtensionsGuestViewContainer::EnqueueAttachRequest( | |
133 linked_ptr<AttachRequest> request) { | |
134 pending_requests_.push_back(request); | 170 pending_requests_.push_back(request); |
135 } | 171 } |
136 | 172 |
137 void ExtensionsGuestViewContainer::PerformPendingAttachRequest() { | 173 void ExtensionsGuestViewContainer::PerformPendingRequest() { |
138 if (!ready_ || pending_requests_.empty() || pending_response_.get()) | 174 if (!ready_ || pending_requests_.empty() || pending_response_.get()) |
139 return; | 175 return; |
140 | 176 |
141 linked_ptr<AttachRequest> pending_request = pending_requests_.front(); | 177 linked_ptr<Request> pending_request = pending_requests_.front(); |
142 pending_requests_.pop_front(); | 178 pending_requests_.pop_front(); |
143 AttachGuestInternal(pending_request); | 179 pending_request->PerformRequest(); |
| 180 pending_response_ = pending_request; |
144 } | 181 } |
145 | 182 |
146 void ExtensionsGuestViewContainer::HandlePendingResponseCallback( | 183 void ExtensionsGuestViewContainer::HandlePendingResponseCallback( |
147 int guest_proxy_routing_id) { | 184 const IPC::Message& message) { |
148 CHECK(pending_response_.get()); | 185 CHECK(pending_response_.get()); |
149 linked_ptr<AttachRequest> pending_response(pending_response_.release()); | 186 linked_ptr<Request> pending_response(pending_response_.release()); |
150 | 187 pending_response->HandleResponse(message); |
151 // If we don't have a callback then there's nothing more to do. | |
152 if (!pending_response->HasCallback()) | |
153 return; | |
154 | |
155 content::RenderView* guest_proxy_render_view = | |
156 content::RenderView::FromRoutingID(guest_proxy_routing_id); | |
157 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing? | |
158 if (!guest_proxy_render_view) | |
159 return; | |
160 | |
161 v8::HandleScope handle_scope(pending_response->isolate()); | |
162 v8::Handle<v8::Function> callback = pending_response->GetCallback(); | |
163 v8::Handle<v8::Context> context = callback->CreationContext(); | |
164 if (context.IsEmpty()) | |
165 return; | |
166 | |
167 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame(); | |
168 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global(); | |
169 | |
170 const int argc = 1; | |
171 v8::Handle<v8::Value> argv[argc] = { window }; | |
172 | |
173 v8::Context::Scope context_scope(context); | |
174 blink::WebScopedMicrotaskSuppression suppression; | |
175 | |
176 // Call the AttachGuest API's callback with the guest proxy as the first | |
177 // parameter. | |
178 callback->Call(context->Global(), argc, argv); | |
179 } | 188 } |
180 | 189 |
181 } // namespace extensions | 190 } // namespace extensions |
OLD | NEW |