OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "content/renderer/pepper/message_channel.h" | 5 #include "content/renderer/pepper/message_channel.h" |
6 | 6 |
7 #include <cstdlib> | 7 #include <cstdlib> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 return message_channel; | 103 return message_channel; |
104 } | 104 } |
105 | 105 |
106 MessageChannel::~MessageChannel() { | 106 MessageChannel::~MessageChannel() { |
107 passthrough_object_.Reset(); | 107 passthrough_object_.Reset(); |
108 if (instance_) | 108 if (instance_) |
109 instance_->MessageChannelDestroyed(); | 109 instance_->MessageChannelDestroyed(); |
110 } | 110 } |
111 | 111 |
112 void MessageChannel::InstanceDeleted() { | 112 void MessageChannel::InstanceDeleted() { |
113 ppapi::proxy::HostDispatcher* dispatcher = | |
114 ppapi::proxy::HostDispatcher::GetForInstance(instance_->pp_instance()); | |
115 // The dispatcher is NULL for in-process. | |
116 if (dispatcher) | |
117 dispatcher->RemoveSyncMessageStatusObserver(this); | |
118 | |
119 instance_ = NULL; | 113 instance_ = NULL; |
120 } | 114 } |
121 | 115 |
122 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { | 116 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { |
123 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 117 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
124 | 118 |
125 // Because V8 is probably not on the stack for Native->JS calls, we need to | 119 // Because V8 is probably not on the stack for Native->JS calls, we need to |
126 // enter the appropriate context for the plugin. | 120 // enter the appropriate context for the plugin. |
127 v8::Local<v8::Context> context = instance_->GetContext(); | 121 v8::Local<v8::Context> context = instance_->GetContext(); |
128 if (context.IsEmpty()) | 122 if (context.IsEmpty()) |
129 return; | 123 return; |
130 | 124 |
131 v8::Context::Scope context_scope(context); | 125 v8::Context::Scope context_scope(context); |
132 | 126 |
133 v8::Handle<v8::Value> v8_val; | 127 v8::Handle<v8::Value> v8_val; |
134 if (!V8VarConverter(instance_->pp_instance()) | 128 if (!V8VarConverter(instance_->pp_instance()) |
135 .ToV8Value(message_data, context, &v8_val)) { | 129 .ToV8Value(message_data, context, &v8_val)) { |
136 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(), | 130 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(), |
137 PP_LOGLEVEL_ERROR, | 131 PP_LOGLEVEL_ERROR, |
138 std::string(), | 132 std::string(), |
139 kVarToV8ConversionError); | 133 kVarToV8ConversionError); |
140 return; | 134 return; |
141 } | 135 } |
142 | 136 |
143 WebSerializedScriptValue serialized_val = | 137 WebSerializedScriptValue serialized_val = |
144 WebSerializedScriptValue::serialize(v8_val); | 138 WebSerializedScriptValue::serialize(v8_val); |
145 | 139 |
146 if (js_message_queue_state_ != SEND_DIRECTLY) { | 140 if (early_message_queue_state_ != SEND_DIRECTLY) { |
147 // We can't just PostTask here; the messages would arrive out of | 141 // We can't just PostTask here; the messages would arrive out of |
148 // order. Instead, we queue them up until we're ready to post | 142 // order. Instead, we queue them up until we're ready to post |
149 // them. | 143 // them. |
150 js_message_queue_.push_back(serialized_val); | 144 early_message_queue_.push_back(serialized_val); |
151 } else { | 145 } else { |
152 // The proxy sent an asynchronous message, so the plugin is already | 146 // The proxy sent an asynchronous message, so the plugin is already |
153 // unblocked. Therefore, there's no need to PostTask. | 147 // unblocked. Therefore, there's no need to PostTask. |
154 DCHECK(js_message_queue_.empty()); | 148 DCHECK(early_message_queue_.empty()); |
155 PostMessageToJavaScriptImpl(serialized_val); | 149 PostMessageToJavaScriptImpl(serialized_val); |
156 } | 150 } |
157 } | 151 } |
158 | 152 |
159 void MessageChannel::Start() { | 153 void MessageChannel::Start() { |
160 DCHECK_EQ(WAITING_TO_START, js_message_queue_state_); | 154 // We PostTask here instead of draining the message queue directly |
161 DCHECK_EQ(WAITING_TO_START, plugin_message_queue_state_); | |
162 | |
163 ppapi::proxy::HostDispatcher* dispatcher = | |
164 ppapi::proxy::HostDispatcher::GetForInstance(instance_->pp_instance()); | |
165 // The dispatcher is NULL for in-process. | |
166 if (dispatcher) | |
167 dispatcher->AddSyncMessageStatusObserver(this); | |
168 | |
169 // We can't drain the JS message queue directly | |
170 // since we haven't finished initializing the PepperWebPluginImpl yet, so | 155 // since we haven't finished initializing the PepperWebPluginImpl yet, so |
171 // the plugin isn't available in the DOM. | 156 // the plugin isn't available in the DOM. |
172 DrainJSMessageQueueSoon(); | 157 base::MessageLoop::current()->PostTask( |
173 | 158 FROM_HERE, |
174 plugin_message_queue_state_ = SEND_DIRECTLY; | 159 base::Bind(&MessageChannel::DrainEarlyMessageQueue, |
175 DrainCompletedPluginMessages(); | 160 weak_ptr_factory_.GetWeakPtr())); |
176 } | 161 } |
177 | 162 |
178 void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) { | 163 void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) { |
179 passthrough_object_.Reset(instance_->GetIsolate(), passthrough); | 164 passthrough_object_.Reset(instance_->GetIsolate(), passthrough); |
180 } | 165 } |
181 | 166 |
182 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { | 167 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { |
183 StringVar* key_string = StringVar::FromPPVar(key); | 168 StringVar* key_string = StringVar::FromPPVar(key); |
184 if (key_string) { | 169 if (key_string) { |
185 internal_named_properties_[key_string->value()] = ScopedPPVar(value); | 170 internal_named_properties_[key_string->value()] = ScopedPPVar(value); |
186 } else { | 171 } else { |
187 NOTREACHED(); | 172 NOTREACHED(); |
188 } | 173 } |
189 } | 174 } |
190 | 175 |
191 MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance) | 176 MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance) |
192 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), | 177 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), |
193 instance_(instance), | 178 instance_(instance), |
194 js_message_queue_state_(WAITING_TO_START), | 179 early_message_queue_state_(QUEUE_MESSAGES), |
195 blocking_message_depth_(0), | |
196 plugin_message_queue_state_(WAITING_TO_START), | |
197 weak_ptr_factory_(this) { | 180 weak_ptr_factory_(this) { |
198 } | 181 } |
199 | 182 |
200 gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder( | 183 gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder( |
201 v8::Isolate* isolate) { | 184 v8::Isolate* isolate) { |
202 return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate) | 185 return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate) |
203 .AddNamedPropertyInterceptor(); | 186 .AddNamedPropertyInterceptor(); |
204 } | 187 } |
205 | 188 |
206 void MessageChannel::BeginBlockOnSyncMessage() { | |
207 js_message_queue_state_ = QUEUE_MESSAGES; | |
208 ++blocking_message_depth_; | |
209 } | |
210 | |
211 void MessageChannel::EndBlockOnSyncMessage() { | |
212 --blocking_message_depth_; | |
213 if (!blocking_message_depth_) | |
214 DrainJSMessageQueueSoon(); | |
215 } | |
216 | |
217 v8::Local<v8::Value> MessageChannel::GetNamedProperty( | 189 v8::Local<v8::Value> MessageChannel::GetNamedProperty( |
218 v8::Isolate* isolate, | 190 v8::Isolate* isolate, |
219 const std::string& identifier) { | 191 const std::string& identifier) { |
220 if (!instance_) | 192 if (!instance_) |
221 return v8::Local<v8::Value>(); | 193 return v8::Local<v8::Value>(); |
222 | 194 |
223 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, | 195 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, |
224 isolate); | 196 isolate); |
225 if (identifier == kPostMessage) { | 197 if (identifier == kPostMessage) { |
226 return gin::CreateFunctionTemplate(isolate, | 198 return gin::CreateFunctionTemplate(isolate, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 try_catch.ThrowException( | 279 try_catch.ThrowException( |
308 "postMessageAndAwaitResponse requires one argument"); | 280 "postMessageAndAwaitResponse requires one argument"); |
309 return; | 281 return; |
310 } | 282 } |
311 | 283 |
312 v8::Handle<v8::Value> message_data; | 284 v8::Handle<v8::Value> message_data; |
313 if (!args->GetNext(&message_data)) { | 285 if (!args->GetNext(&message_data)) { |
314 NOTREACHED(); | 286 NOTREACHED(); |
315 } | 287 } |
316 | 288 |
317 if (plugin_message_queue_state_ == WAITING_TO_START) { | 289 if (early_message_queue_state_ == QUEUE_MESSAGES) { |
318 try_catch.ThrowException( | 290 try_catch.ThrowException( |
319 "Attempted to call a synchronous method on a plugin that was not " | 291 "Attempted to call a synchronous method on a plugin that was not " |
320 "yet loaded."); | 292 "yet loaded."); |
321 return; | 293 return; |
322 } | 294 } |
323 | 295 |
324 // If the queue of messages to the plugin is non-empty, we're still waiting on | 296 // If the queue of messages to the plugin is non-empty, we're still waiting on |
325 // pending Var conversions. This means at some point in the past, JavaScript | 297 // pending Var conversions. This means at some point in the past, JavaScript |
326 // called postMessage (the async one) and passed us something with a browser- | 298 // called postMessage (the async one) and passed us something with a browser- |
327 // side host (e.g., FileSystem) and we haven't gotten a response from the | 299 // side host (e.g., FileSystem) and we haven't gotten a response from the |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 const ScopedPPVar& result, | 392 const ScopedPPVar& result, |
421 bool success) { | 393 bool success) { |
422 if (!instance_) | 394 if (!instance_) |
423 return; | 395 return; |
424 result_holder->ConversionCompleted(result, success); | 396 result_holder->ConversionCompleted(result, success); |
425 DrainCompletedPluginMessages(); | 397 DrainCompletedPluginMessages(); |
426 } | 398 } |
427 | 399 |
428 void MessageChannel::DrainCompletedPluginMessages() { | 400 void MessageChannel::DrainCompletedPluginMessages() { |
429 DCHECK(instance_); | 401 DCHECK(instance_); |
430 if (plugin_message_queue_state_ == WAITING_TO_START) | 402 if (early_message_queue_state_ == QUEUE_MESSAGES) |
431 return; | 403 return; |
432 | 404 |
433 while (!plugin_message_queue_.empty() && | 405 while (!plugin_message_queue_.empty() && |
434 plugin_message_queue_.front().conversion_completed()) { | 406 plugin_message_queue_.front().conversion_completed()) { |
435 const VarConversionResult& front = plugin_message_queue_.front(); | 407 const VarConversionResult& front = plugin_message_queue_.front(); |
436 if (front.success()) { | 408 if (front.success()) { |
437 instance_->HandleMessage(front.var()); | 409 instance_->HandleMessage(front.var()); |
438 } else { | 410 } else { |
439 PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(), | 411 PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(), |
440 PP_LOGLEVEL_ERROR, | 412 PP_LOGLEVEL_ERROR, |
441 std::string(), | 413 std::string(), |
442 kV8ToVarConversionError); | 414 kV8ToVarConversionError); |
443 } | 415 } |
444 plugin_message_queue_.pop_front(); | 416 plugin_message_queue_.pop_front(); |
445 } | 417 } |
446 } | 418 } |
447 | 419 |
448 void MessageChannel::DrainJSMessageQueue() { | 420 void MessageChannel::DrainEarlyMessageQueue() { |
449 if (!instance_) | 421 if (!instance_) |
450 return; | 422 return; |
451 if (js_message_queue_state_ == SEND_DIRECTLY) | 423 DCHECK(early_message_queue_state_ == QUEUE_MESSAGES); |
452 return; | |
453 | 424 |
454 // Take a reference on the PluginInstance. This is because JavaScript code | 425 // Take a reference on the PluginInstance. This is because JavaScript code |
455 // may delete the plugin, which would destroy the PluginInstance and its | 426 // may delete the plugin, which would destroy the PluginInstance and its |
456 // corresponding MessageChannel. | 427 // corresponding MessageChannel. |
457 scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_); | 428 scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_); |
458 while (!js_message_queue_.empty()) { | 429 while (!early_message_queue_.empty()) { |
459 PostMessageToJavaScriptImpl(js_message_queue_.front()); | 430 PostMessageToJavaScriptImpl(early_message_queue_.front()); |
460 js_message_queue_.pop_front(); | 431 early_message_queue_.pop_front(); |
461 } | 432 } |
462 js_message_queue_state_ = SEND_DIRECTLY; | 433 early_message_queue_state_ = SEND_DIRECTLY; |
463 } | |
464 | 434 |
465 void MessageChannel::DrainJSMessageQueueSoon() { | 435 DrainCompletedPluginMessages(); |
466 base::MessageLoop::current()->PostTask( | |
467 FROM_HERE, | |
468 base::Bind(&MessageChannel::DrainJSMessageQueue, | |
469 weak_ptr_factory_.GetWeakPtr())); | |
470 } | 436 } |
471 | 437 |
472 } // namespace content | 438 } // namespace content |
OLD | NEW |