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

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

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

Powered by Google App Engine
This is Rietveld 408576698