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

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
24 namespace ppapi {
25
26 namespace {
27
28 const char kPostMessage[] = "postMessage";
29
30 // Helper function to get the MessageChannel that is associated with an
31 // NPObject*.
32 MessageChannel& ToMessageChannel(NPObject* object) {
33 return *(static_cast<MessageChannel::MessageChannelNPObject*>(object)->
34 message_channel);
35 }
36
37 // Helper function to determine if a given identifier is equal to kPostMessage.
38 bool IdentifierIsPostMessage(NPIdentifier identifier) {
39 return WebBindings::getStringIdentifier(kPostMessage) == identifier;
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 // Note: This is largely copied from var.cc so that we don't depend on code
50 // which will be removed. TODO(dmichael) remove this comment when var
51 // is removed.
52 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
53 switch (var.type) {
54 case PP_VARTYPE_UNDEFINED:
55 VOID_TO_NPVARIANT(*result);
56 break;
57 case PP_VARTYPE_NULL:
58 NULL_TO_NPVARIANT(*result);
59 break;
60 case PP_VARTYPE_BOOL:
61 BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
62 break;
63 case PP_VARTYPE_INT32:
64 INT32_TO_NPVARIANT(var.value.as_int, *result);
65 break;
66 case PP_VARTYPE_DOUBLE:
67 DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
68 break;
69 case PP_VARTYPE_STRING: {
70 scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
71 if (!string) {
72 VOID_TO_NPVARIANT(*result);
73 return false;
74 }
75 const std::string& value = string->value();
76 STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
77 break;
78 }
79 case PP_VARTYPE_OBJECT:
80 // Objects are not currently supported.
81 DCHECK(false);
82 VOID_TO_NPVARIANT(*result);
83 return false;
84 default:
85 VOID_TO_NPVARIANT(*result);
86 return false;
87 }
88 return true;
89 }
90
91 //------------------------------------------------------------------------------
92 // Implementations of NPClass functions. These are here to:
93 // - Implement postMessage behavior.
94 // - Forward calls to the 'passthrough' object to allow backwards-compatibility
95 // with GetInstanceObject() objects.
96 //------------------------------------------------------------------------------
97 NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) {
98 return new MessageChannel::MessageChannelNPObject;
99 }
100
101 void MessageChannelDeallocate(NPObject* object) {
102 MessageChannel::MessageChannelNPObject* instance =
103 static_cast<MessageChannel::MessageChannelNPObject*>(object);
104 delete instance;
105 }
106
107 bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
108 if (!np_obj)
109 return false;
110
111 // We only handle a function called postMessage.
112 if (IdentifierIsPostMessage(name))
113 return true;
114
115 // Other method names we will pass to the passthrough object, if we have one.
116 NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
117 if (passthrough)
118 return WebBindings::hasMethod(NULL, passthrough, name);
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 (!np_obj)
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 (!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 (!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 return false;
170 }
171
172 bool MessageChannelGetProperty(NPObject* np_obj, NPIdentifier name,
173 NPVariant* result) {
174 if (!np_obj)
175 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 return false;
186 }
187
188 bool MessageChannelSetProperty(NPObject* np_obj, NPIdentifier name,
189 const NPVariant* variant) {
190 if (!np_obj)
191 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 return false;
202 }
203
204 bool MessageChannelEnumerate(NPObject *np_obj, NPIdentifier **value,
205 uint32_t *count) {
206 if (!np_obj)
207 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.
216 NPIdentifier* new_array = static_cast<NPIdentifier*>(
217 std::malloc(sizeof(NPIdentifier) * (*count + 1)));
218 std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count));
219 new_array[*count] = WebBindings::getStringIdentifier(kPostMessage);
220 std::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
249 } // namespace
250
251 // MessageChannel --------------------------------------------------------------
252 MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {}
253
254 MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {}
255
256 MessageChannel::MessageChannel(PluginInstance* instance)
257 : instance_(instance),
258 passthrough_object_(NULL),
259 np_object_(NULL) {
260 VOID_TO_NPVARIANT(onmessage_invoker_);
261
262 // Now create an NPObject for receiving calls to postMessage.
263 NPObject* obj = WebBindings::createObject(NULL, &message_channel_class);
264 DCHECK(obj);
265 np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj);
266 np_object_->message_channel = this;
267 }
268
269 bool MessageChannel::EvaluateOnMessageInvoker() {
270 // If we've already evaluated the function, just return.
271 if (NPVARIANT_IS_OBJECT(onmessage_invoker_))
272 return true;
273
274 // This is the javascript code that we invoke. It checks to see if onmessage
275 // exists, and if so, it invokes it.
276 const char invoke_onmessage_js[] =
277 "(function(module_instance, message_data) {"
278 " if (module_instance &&" // Only invoke if the instance is valid and
279 " module_instance.onmessage &&" // has a function named onmessage.
280 " typeof(module_instance.onmessage) == 'function') {"
281 " var message_event = document.createEvent('MessageEvent');"
282 " message_event.initMessageEvent('message'," // type
283 " false," // canBubble
284 " false," // cancelable
285 " message_data," // data
286 " ''," // origin
287 " ''," // lastEventId
288 " module_instance," // source
289 " []);" // ports
290 " module_instance.onmessage(message_event);"
291 " }"
292 "})";
293 NPString function_string = { invoke_onmessage_js,
294 sizeof(invoke_onmessage_js)-1 };
295 // Get the current frame to pass to the evaluate function.
296 WebKit::WebFrame* frame =
297 instance_->container()->element().document().frame();
298 // Evaluate the function and obtain an NPVariant pointing to it.
299 if (!WebBindings::evaluate(NULL, frame->windowObject(), &function_string,
300 &onmessage_invoker_)) {
301 // If it fails, do nothing.
302 return false;
303 }
304 DCHECK(NPVARIANT_IS_OBJECT(onmessage_invoker_));
305 return true;
306 }
307
308 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
309 // Make sure we have our function for invoking a JavaScript onmessage
310 // function.
311 bool success = EvaluateOnMessageInvoker();
312 DCHECK(success);
313 if (!success)
314 return;
315
316 DCHECK(instance_);
317
318 NPVariant result_var;
319 VOID_TO_NPVARIANT(result_var);
320 NPVariant npvariant_args[2];
321 OBJECT_TO_NPVARIANT(instance_->container()->scriptableObjectForElement(),
322 npvariant_args[0]);
323 // Convert message to an NPVariant without copying. Note this means that
324 // in-process plugins will not copy the data, so isn't really following the
325 // postMessage spec in spirit. Copying is handled in the proxy, and we don't
326 // want to re-copy unnecessarily.
327 //
328 // TODO(dmichael): We need to do structured clone eventually to copy a object
329 // structure. The details and PPAPI changes for this are TBD.
330 if (!PPVarToNPVariantNoCopy(message_data, &npvariant_args[1]))
331 return;
332
333 WebBindings::invokeDefault(NULL,
334 NPVARIANT_TO_OBJECT(onmessage_invoker_),
335 npvariant_args,
336 sizeof(npvariant_args)/sizeof(*npvariant_args),
337 &result_var);
338 }
339
340 void MessageChannel::PostMessageToNative(PP_Var message_data) {
341 instance_->HandleMessage(message_data);
342 }
343
344 MessageChannel::~MessageChannel() {
345 WebBindings::releaseVariantValue(&onmessage_invoker_);
346 }
347
348 } // namespace ppapi
349 } // namespace webkit
350
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698