Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: webkit/plugins/ppapi/message_channel.cc

Issue 6538028: A proposal for an initial postMessage interface. This will allow JavaScript ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 #include "webkit/plugins/ppapi/message_channel.h"
6
7 #include <cstdlib>
8 #include <cstring>
9 #include <string>
10
11 #include "base/logging.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
17 #include "webkit/plugins/ppapi/npapi_glue.h"
18 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
19 #include "webkit/plugins/ppapi/var.h"
20
21 using WebKit::WebBindings;
22
23 namespace webkit {
24 namespace ppapi {
25
26 namespace {
27
28 const char kPostMessage[] = "postMessage";
29
30 // Helper function to determine if a given identifier is equal to kPostMessage.
31 bool IdentifierIsPostMessage(NPIdentifier identifier) {
32 const NPUTF8* id_as_string = NULL;
33 int32_t int_value = 0;
34 bool is_string = false;
35 WebBindings::extractIdentifierData(identifier, id_as_string, int_value,
36 is_string);
37 if (is_string)
38 return (std::strcmp(id_as_string, kPostMessage) == 0);
39 return false;
40 }
41
42 // Converts the given PP_Var to an NPVariant, returning true on success.
43 // False means that the given variant is invalid. In this case, the result
44 // NPVariant will be set to a void one.
45 //
46 // The contents of the PP_Var will NOT be copied, so you need to ensure that
47 // the PP_Var remains valid while the resultant NPVariant is in use.
48 //
49 //
50 // Note: This is largely copied from var.cc so that we don't depend on code
51 // which will be removed. TODO(dmichael) remove this comment when var
52 // is removed.
53 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
54 switch (var.type) {
55 case PP_VARTYPE_UNDEFINED:
56 VOID_TO_NPVARIANT(*result);
57 break;
58 case PP_VARTYPE_NULL:
59 NULL_TO_NPVARIANT(*result);
60 break;
61 case PP_VARTYPE_BOOL:
62 BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
63 break;
64 case PP_VARTYPE_INT32:
65 INT32_TO_NPVARIANT(var.value.as_int, *result);
66 break;
67 case PP_VARTYPE_DOUBLE:
68 DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
69 break;
70 case PP_VARTYPE_STRING: {
71 scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
72 if (!string) {
73 VOID_TO_NPVARIANT(*result);
74 return false;
75 }
76 const std::string& value = string->value();
77 STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
78 break;
79 }
80 case PP_VARTYPE_OBJECT:
81 // Objects are not currently supported.
82 VOID_TO_NPVARIANT(*result);
83 DCHECK(false);
84 return false;
85 default:
86 VOID_TO_NPVARIANT(*result);
87 return false;
88 }
89 return true;
90 }
91
92 // Helper function to get the MessageChannel that is associated with an
93 // NPObject*.
94 MessageChannel& ToMessageChannel(NPObject* object) {
95 return *(static_cast<MessageChannel::MessageChannelNPObject*>(object)->
96 message_channel);
97 }
98
99 //------------------------------------------------------------------------------
100 // Implementations of NPClass functions. These are here to:
101 // - Implement postMessage behavior.
102 // - Forward calls to the 'passthrough' object to allow backwards-compatibility
103 // with GetInstanceObject() objects.
104 //------------------------------------------------------------------------------
105 NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) {
106 return new MessageChannel::MessageChannelNPObject;
107 }
108
109 void MessageChannelDeallocate(NPObject* object) {
110 MessageChannel::MessageChannelNPObject* instance =
111 static_cast<MessageChannel::MessageChannelNPObject*>(object);
112 delete instance;
113 }
114
115 bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
116 if (NULL == np_obj)
117 return false;
118
119 // We only handle a function called postMessage.
120 if (IdentifierIsPostMessage(name))
brettw 2011/03/16 21:34:11 Can't you just compare identifiers? I thought that
121 return true;
122
123 // Other method names we will pass to the passthrough object, if we have one.
124 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
125 if (passthrough) {
126 return WebBindings::hasMethod(NULL, passthrough, name);
127 }
128 return false;
129 }
130
131 bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name,
132 const NPVariant* args, uint32 arg_count,
133 NPVariant* result) {
134 if (NULL == np_obj)
135 return false;
136
137 // We only handle a function called postMessage.
138 if (IdentifierIsPostMessage(name) && (arg_count == 1)) {
139 MessageChannel& message_channel(ToMessageChannel(np_obj));
140 PP_Var argument(Var::NPVariantToPPVar(message_channel.instance(),
141 &args[0]));
142 message_channel.PostMessageToNative(argument);
143 return true;
144 }
145 // Other method calls we will pass to the passthrough object, if we have one.
146 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
147 if (passthrough) {
148 return WebBindings::invoke(NULL, passthrough, name, args, arg_count,
149 result);
150 }
151 return false;
152 }
153
154 bool MessageChannelInvokeDefault(NPObject* np_obj,
155 const NPVariant* args,
156 uint32 arg_count,
157 NPVariant* result) {
158 if (NULL == np_obj)
159 return false;
160
161 // Invoke on the passthrough object, if we have one.
162 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
163 if (passthrough) {
164 return WebBindings::invokeDefault(NULL, passthrough, args, arg_count,
165 result);
166 }
167 return false;
168 }
169
170 bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) {
171 if (NULL == np_obj)
172 return false;
173
174 // Invoke on the passthrough object, if we have one.
175 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
176 if (passthrough) {
177 return WebBindings::hasProperty(NULL, passthrough, name);
178 }
179 return false;
180 }
181
182 bool MessageChannelGetProperty(NPObject* np_obj, NPIdentifier name,
183 NPVariant* result) {
184 if (NULL == np_obj) return false;
185
186 // Don't allow getting the postMessage function.
187 if (IdentifierIsPostMessage(name))
188 return false;
189
190 // Invoke on the passthrough object, if we have one.
191 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
192 if (passthrough) {
193 return WebBindings::getProperty(NULL, passthrough, name, result);
194 }
195 return false;
196 }
197
198 bool MessageChannelSetProperty(NPObject* np_obj, NPIdentifier name,
199 const NPVariant* variant) {
200 if (NULL == np_obj) return false;
201
202 // Don't allow setting the postMessage function.
203 if (IdentifierIsPostMessage(name))
204 return false;
205
206 // Invoke on the passthrough object, if we have one.
207 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
208 if (passthrough) {
209 return WebBindings::setProperty(NULL, passthrough, name, variant);
210 }
211 return false;
212 }
213
214 bool MessageChannelEnumerate(NPObject *np_obj, NPIdentifier **value,
215 uint32_t *count) {
216 if (NULL == np_obj) return false;
217
218 // Invoke on the passthrough object, if we have one, to enumerate its
219 // properties.
220 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
221 if (passthrough) {
222 bool success = WebBindings::enumerate(NULL, passthrough, value, count);
223 if (success) {
224 // add postMessage to the list and return it.
225 NPIdentifier* new_array = static_cast<NPIdentifier*>(
226 malloc(sizeof(NPIdentifier) * (*count + 1)));
227 std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count));
228 new_array[*count] = WebBindings::getStringIdentifier(kPostMessage);
229 free(*value);
230 *value = new_array;
231 ++(*count);
232 return true;
233 }
234 }
235
236 // Otherwise, build an array that includes only postMessage.
237 *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier)));
238 (*value)[0] = WebBindings::getStringIdentifier(kPostMessage);
239 *count = 1;
240 return true;
241 }
242
243 NPClass message_channel_class = {
244 NP_CLASS_STRUCT_VERSION,
245 &MessageChannelAllocate,
246 &MessageChannelDeallocate,
247 NULL,
248 &MessageChannelHasMethod,
249 &MessageChannelInvoke,
250 &MessageChannelInvokeDefault,
251 &MessageChannelHasProperty,
252 &MessageChannelGetProperty,
253 &MessageChannelSetProperty,
254 NULL,
255 &MessageChannelEnumerate,
256 };
257 } // namespace
258
259 // MessageChannel --------------------------------------------------------------
260 MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {}
261
262 MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {}
263
264 MessageChannel::MessageChannel(PluginInstance* instance)
265 : instance_(instance),
266 passthrough_object_(NULL),
267 np_object_(NULL) {
268 // Now create an NPObject for receiving calls to postMessage.
269 NPObject* obj = WebBindings::createObject(NULL, &message_channel_class);
270 DCHECK(obj != NULL);
271 np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj);
272 np_object_->message_channel = this;
273 }
274
275 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
276 // This is the javascript code that we invoke. It checks to see if onmessage
277 // exists, and if so, it invokes it.
278 const char invoke_onmessage_js[] =
279 "(function(module_instance, message_data) {"
280 " if (module_instance &&" // Only invoke if the instance is valid and
281 " module_instance.onmessage &&" // has a function named onmessage.
282 " typeof(module_instance.onmessage) == 'function') {"
283 " var message_event = document.createEvent('MessageEvent');"
284 " message_event.initMessageEvent('message'," // type
285 " false," // canBubble
286 " false," // cancelable
287 " message_data," // data
288 " ''," // origin
289 " ''," // lastEventId
290 " module_instance," // source
291 " []);" // ports
292 " module_instance.onmessage(message_event);"
293 " }"
294 "})";
295
296 NPString function_string = { invoke_onmessage_js,
297 sizeof(invoke_onmessage_js)-1 };
298 NPVariant invoke_onmessage_js_function;
299 VOID_TO_NPVARIANT(invoke_onmessage_js_function);
300 // Get the current frame to pass to the evaluate function.
301 WebKit::WebFrame* frame =
302 instance_->container()->element().document().frame();
303 // Evaluate the function and obtain an NPVariant pointing to it.
304 if (!WebBindings::evaluate(NULL, frame->windowObject(), &function_string,
305 &invoke_onmessage_js_function)) {
306 // If it fails, do nothing.
307 return;
308 }
309 DCHECK(NPVARIANT_IS_OBJECT(invoke_onmessage_js_function));
310 DCHECK(instance_ != NULL);
311
312 NPVariant result_var;
313 VOID_TO_NPVARIANT(result_var);
314 NPVariant npvariant_args[2];
315 OBJECT_TO_NPVARIANT(instance_->container()->scriptableObjectForElement(),
316 npvariant_args[0]);
317 // Convert message to an NPVariant without copying. Note this means that
318 // in-process plugins will not copy the data, so isn't really following the
319 // postMessage spec in spirit. Copying is handled in the proxy, and we don't
320 // want to re-copy unnecessarily.
321 //
322 // TODO(dmichael): We need to do structured clone eventually to copy a object
323 // structure. The details and PPAPI changes for this are TBD.
324 if (!PPVarToNPVariantNoCopy(message_data, &npvariant_args[1])) {
325 return;
326 }
327 WebBindings::invokeDefault(NULL,
328 NPVARIANT_TO_OBJECT(invoke_onmessage_js_function),
329 npvariant_args,
330 sizeof(npvariant_args)/sizeof(*npvariant_args),
331 &result_var);
332 WebBindings::releaseVariantValue(&invoke_onmessage_js_function);
333 }
334
335 void MessageChannel::PostMessageToNative(PP_Var message_data) {
336 instance_->HandleMessage(message_data);
337 }
338
339 MessageChannel::~MessageChannel() {}
340
341 } // namespace ppapi
342 } // namespace webkit
343
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698