|
OLD | NEW |
---|---|
(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 | |
OLD | NEW |