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. 4 5 #ifndef CONTENT_RENDERER_PEPPER_MESSAGE_CHANNEL_H_ 6 #define CONTENT_RENDERER_PEPPER_MESSAGE_CHANNEL_H_ 7 8 #include <deque> 9 #include <list> 10 #include <map> 11 12 #include "base/memory/weak_ptr.h" 13 #include "ppapi/shared_impl/resource.h" 14 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" 15 #include "third_party/npapi/bindings/npruntime.h" 16 17 struct PP_Var; 18 19 namespace ppapi { 20 class ScopedPPVar; 21 } 22 23 namespace content { 24 25 class PepperPluginInstanceImpl; 26 27 // MessageChannel implements bidirectional postMessage functionality, allowing 28 // calls from JavaScript to plugins and vice-versa. See 29 // PPB_Messaging::PostMessage and PPP_Messaging::HandleMessage for more 30 // information. 31 // 32 // Currently, only 1 MessageChannel can exist, to implement postMessage 33 // functionality for the instance interfaces. In the future, when we create a 34 // MessagePort type in PPAPI, those may be implemented here as well with some 35 // refactoring. 36 // - Separate message ports won't require the passthrough object. 37 // - The message target won't be limited to instance, and should support 38 // either plugin-provided or JS objects. 39 // TODO(dmichael): Add support for separate MessagePorts. 40 class MessageChannel { 41 public: 42 // MessageChannelNPObject is a simple struct that adds a pointer back to a 43 // MessageChannel instance. This way, we can use an NPObject to allow 44 // JavaScript interactions without forcing MessageChannel to inherit from 45 // NPObject. 46 struct MessageChannelNPObject : public NPObject { 47 MessageChannelNPObject(); 48 ~MessageChannelNPObject(); 49 50 base::WeakPtr<MessageChannel> message_channel; 51 }; 52 53 explicit MessageChannel(PepperPluginInstanceImpl* instance); 54 ~MessageChannel(); 55 56 // Post a message to the onmessage handler for this channel's instance 57 // asynchronously. 58 void PostMessageToJavaScript(PP_Var message_data); 59 60 // Post a message to the plugin's HandleMessage function for this channel's 61 // instance. 62 void PostMessageToNative(const NPVariant* message_data); 63 // Post a message to the plugin's HandleBlocking Message function for this 64 // channel's instance synchronously, and return a result. 65 void PostBlockingMessageToNative(const NPVariant* message_data, 66 NPVariant* np_result); 67 68 // Return the NPObject* to which we should forward any calls which aren't 69 // related to postMessage. Note that this can be NULL; it only gets set if 70 // there is a scriptable 'InstanceObject' associated with this channel's 71 // instance. 72 NPObject* passthrough_object() { return passthrough_object_; } 73 void SetPassthroughObject(NPObject* passthrough); 74 75 NPObject* np_object() { return np_object_; } 76 77 PepperPluginInstanceImpl* instance() { return instance_; } 78 79 // Messages are queued initially. After the PepperPluginInstanceImpl is ready 80 // to send and handle messages, users of MessageChannel should call 81 // Start(). 82 void Start(); 83 84 bool GetReadOnlyProperty(NPIdentifier key, NPVariant* value) const; 85 void SetReadOnlyProperty(PP_Var key, PP_Var value); 86 87 private: 88 // Struct for storing the result of a NPVariant being converted to a PP_Var. 89 struct VarConversionResult; 90 91 void EnqueuePluginMessage(const NPVariant* variant); 92 93 void FromV8ValueComplete(VarConversionResult* result_holder, 94 const ppapi::ScopedPPVar& result_var, 95 bool success); 96 void DrainCompletedPluginMessages(); 97 98 PepperPluginInstanceImpl* instance_; 99 100 // We pass all non-postMessage calls through to the passthrough_object_. 101 // This way, a plugin can use PPB_Class or PPP_Class_Deprecated and also 102 // postMessage. This is necessary to support backwards-compatibility, and 103 // also trusted plugins for which we will continue to support synchronous 104 // scripting. 105 NPObject* passthrough_object_; 106 107 // The NPObject we use to expose postMessage to JavaScript. 108 MessageChannelNPObject* np_object_; 109 110 // Post a message to the onmessage handler for this channel's instance 111 // synchronously. This is used by PostMessageToJavaScript. 112 void PostMessageToJavaScriptImpl( 113 const blink::WebSerializedScriptValue& message_data); 114 // Post a message to the PPP_Instance HandleMessage function for this 115 // channel's instance. This is used by PostMessageToNative. 116 void PostMessageToNativeImpl(PP_Var message_data); 117 118 void DrainEarlyMessageQueue(); 119 120 std::deque<blink::WebSerializedScriptValue> early_message_queue_; 121 enum EarlyMessageQueueState { 122 QUEUE_MESSAGES, // Queue JS messages. 123 SEND_DIRECTLY, // Post JS messages directly. 124 }; 125 EarlyMessageQueueState early_message_queue_state_; 126 127 // This queue stores vars that are being sent to the plugin. Because 128 // conversion can happen asynchronously for object types, the queue stores 129 // the var until all previous vars have been converted and sent. This 130 // preserves the order in which JS->plugin messages are processed. 131 // 132 // Note we rely on raw VarConversionResult* pointers remaining valid after 133 // calls to push_back or pop_front; hence why we're using list. (deque would 134 // probably also work, but is less clearly specified). 135 std::list<VarConversionResult> plugin_message_queue_; 136 137 std::map<NPIdentifier, ppapi::ScopedPPVar> internal_properties_; 138 139 // This is used to ensure pending tasks will not fire after this object is 140 // destroyed. 141 base::WeakPtrFactory<MessageChannel> weak_ptr_factory_; 142 143 DISALLOW_COPY_AND_ASSIGN(MessageChannel); 144 }; 145 146 } // namespace content 147 148 #endif // CONTENT_RENDERER_PEPPER_MESSAGE_CHANNEL_H_ 149