OLD | NEW |
---|---|
(Empty) | |
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 #include "content/renderer/browser_plugin/browser_plugin_bindings.h" | |
6 | |
7 #include <cstdlib> | |
8 #include <string> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/logging.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/string16.h" | |
14 #include "base/string_split.h" | |
15 #include "base/utf_string_conversions.h" | |
16 #include "content/renderer/browser_plugin/browser_plugin.h" | |
17 #include "third_party/npapi/bindings/npapi.h" | |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" | |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMMessageEvent.h" | |
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" | |
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" | |
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" | |
25 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerialize dScriptValue.h" | |
26 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | |
27 #include "v8/include/v8.h" | |
28 | |
29 using WebKit::WebBindings; | |
30 using WebKit::WebElement; | |
31 using WebKit::WebDOMEvent; | |
32 using WebKit::WebDOMMessageEvent; | |
33 using WebKit::WebPluginContainer; | |
34 using WebKit::WebSerializedScriptValue; | |
35 using WebKit::WebString; | |
36 | |
37 namespace content { | |
38 | |
39 namespace browser_plugin { | |
40 | |
41 namespace { | |
42 | |
43 const char kAddEventListener[] = "addEventListener"; | |
44 const char kRemoveEventListener[] = "removeEventListener"; | |
45 const char kPostMessage[] = "postMessage"; | |
46 const char kSrcAttribute[] = "src"; | |
47 | |
48 BrowserPluginBindings* GetBindings(NPObject* object) { | |
49 return static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object)-> | |
50 message_channel; | |
51 } | |
52 | |
53 bool IdentifierIsAddEventListener(NPIdentifier identifier) { | |
54 return WebBindings::getStringIdentifier(kAddEventListener) == identifier; | |
55 } | |
56 | |
57 bool IdentifierIsRemoveEventListener(NPIdentifier identifier) { | |
58 return WebBindings::getStringIdentifier(kRemoveEventListener) == identifier; | |
59 } | |
60 | |
61 bool IdentifierIsPostMessage(NPIdentifier identifier) { | |
62 return WebBindings::getStringIdentifier(kPostMessage) == identifier; | |
63 } | |
64 | |
65 bool IdentifierIsSrcAttribute(NPIdentifier identifier) { | |
66 return WebBindings::getStringIdentifier(kSrcAttribute) == identifier; | |
67 } | |
68 | |
69 std::string StringFromNPVariant(const NPVariant& variant) { | |
70 if (!NPVARIANT_IS_STRING(variant)) | |
71 return std::string(); | |
72 const NPString& np_string = NPVARIANT_TO_STRING(variant); | |
73 return std::string(np_string.UTF8Characters, np_string.UTF8Length); | |
74 } | |
75 | |
76 string16 String16FromNPVariant(const NPVariant& variant) { | |
77 if (!NPVARIANT_IS_STRING(variant)) | |
78 return string16(); | |
79 const NPString& np_string = NPVARIANT_TO_STRING(variant); | |
80 string16 wstr; | |
81 if (!UTF8ToUTF16(np_string.UTF8Characters, np_string.UTF8Length, &wstr)) | |
82 return string16(); | |
83 return wstr; | |
84 } | |
85 | |
86 bool StringToNPVariant(const std::string &in, NPVariant *variant) { | |
87 size_t length = in.size(); | |
88 NPUTF8 *chars = static_cast<NPUTF8 *>(malloc(length)); | |
89 if (!chars) { | |
90 VOID_TO_NPVARIANT(*variant); | |
91 return false; | |
92 } | |
93 memcpy(chars, in.c_str(), length); | |
94 STRINGN_TO_NPVARIANT(chars, length, *variant); | |
95 return true; | |
96 } | |
97 | |
98 //------------------------------------------------------------------------------ | |
99 // Implementations of NPClass functions. These are here to: | |
100 // - Implement postMessage behavior. | |
101 // - Implement src attribute. | |
102 //------------------------------------------------------------------------------ | |
103 NPObject* BrowserPluginBindingsAllocate(NPP npp, NPClass* the_class) { | |
104 return new BrowserPluginBindings::BrowserPluginNPObject; | |
105 } | |
106 | |
107 void BrowserPluginBindingsDeallocate(NPObject* object) { | |
108 BrowserPluginBindings::BrowserPluginNPObject* instance = | |
109 static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object); | |
110 delete instance; | |
111 } | |
112 | |
113 bool BrowserPluginBindingsHasMethod(NPObject* np_obj, NPIdentifier name) { | |
114 if (!np_obj) | |
115 return false; | |
116 | |
117 if (IdentifierIsPostMessage(name)) | |
118 return true; | |
119 | |
120 if (IdentifierIsAddEventListener(name)) | |
121 return true; | |
122 | |
123 if (IdentifierIsRemoveEventListener(name)) | |
124 return true; | |
125 | |
126 return false; | |
127 } | |
128 | |
129 bool BrowserPluginBindingsInvoke(NPObject* np_obj, NPIdentifier name, | |
130 const NPVariant* args, uint32 arg_count, | |
131 NPVariant* result) { | |
132 if (!np_obj) | |
133 return false; | |
134 | |
135 BrowserPluginBindings* bindings = GetBindings(np_obj); | |
136 if (!bindings) | |
137 return false; | |
138 | |
139 if (IdentifierIsPostMessage(name) && (arg_count == 2)) { | |
Charlie Reis
2012/08/03 18:06:02
Is this a typical pattern for bindings classes, or
Fady Samuel
2012/08/03 19:34:43
I agree, this will grow long fairly quickly as the
| |
140 v8::Handle<v8::Value> v8_val = WebBindings::toV8Value(&args[0]); | |
141 // If serialization fails, there may be a V8 exception pending. | |
142 // Don't touch the V8 state (eg, to raise our own 'error calling | |
143 // method on NPObject' exception). | |
144 if (v8_val.IsEmpty()) | |
145 // This might happen if toV8Value fails an allocation. | |
146 // Does SafeAllocation::newInstance throw an exception in this case? | |
147 return true; | |
148 WebSerializedScriptValue serialized_v8_val = | |
149 WebSerializedScriptValue::serialize(v8_val); | |
150 WebString message_string = serialized_v8_val.toString(); | |
151 // Serialization can sometimes fail (the user might try to fax the | |
152 // |window|, for example); ::serialize will result in a | |
153 // DATA_CLONE_ERR being raised, but we still need to abort | |
154 // the postMessage() operation. There's no clear way to test | |
155 // for failure in WebSerializedScriptValue, but an empty string | |
156 // should signal an invalid object. (The serializer at a nonzero | |
157 // version will always write a version tag.) | |
158 // v8::TryCatch, for some reason, was not catching DATA_CLONE_ERR; | |
159 // if this worked, it would be the right way to go. | |
160 // (This isn't the only way that serialization might fail! Other | |
161 // exceptions are possible.) | |
162 if (!message_string.length()) | |
163 return true; | |
164 string16 message(message_string); | |
165 string16 target_origin = String16FromNPVariant(args[1]); | |
166 bindings->instance()->PostMessage(message, target_origin); | |
Charlie Reis
2012/08/03 18:06:02
Just to confirm my understanding, this allows JS c
Fady Samuel
2012/08/03 19:34:43
That is correct.
| |
167 return true; | |
168 } | |
169 | |
170 if (IdentifierIsAddEventListener(name) && (arg_count == 2)) { | |
171 std::string event_name = StringFromNPVariant(args[0]); | |
172 if (event_name.empty()) | |
173 return false; | |
174 | |
175 v8::Local<v8::Value> value = | |
176 v8::Local<v8::Value>::New(WebBindings::toV8Value(&args[1])); | |
177 if (value.IsEmpty() || !value->IsFunction()) | |
178 return false; | |
179 | |
180 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value); | |
181 return bindings->instance()->AddEventListener(event_name, function); | |
182 } | |
183 | |
184 if (IdentifierIsRemoveEventListener(name) && arg_count == 2) { | |
185 std::string event_name = StringFromNPVariant(args[0]); | |
186 if (event_name.empty()) | |
187 return false; | |
188 | |
189 v8::Local<v8::Value> value = | |
190 v8::Local<v8::Value>::New(WebBindings::toV8Value(&args[1])); | |
191 | |
192 if (value.IsEmpty() || !value->IsFunction()) | |
193 return false; | |
194 | |
195 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value); | |
196 return bindings->instance()->RemoveEventListener(event_name, function); | |
197 } | |
198 | |
199 return false; | |
200 } | |
201 | |
202 bool BrowserPluginBindingsInvokeDefault(NPObject* np_obj, | |
203 const NPVariant* args, | |
204 uint32 arg_count, | |
205 NPVariant* result) { | |
206 NOTIMPLEMENTED(); | |
207 return false; | |
208 } | |
209 | |
210 bool BrowserPluginBindingsHasProperty(NPObject* np_obj, NPIdentifier name) { | |
211 return IdentifierIsSrcAttribute(name); | |
212 } | |
213 | |
214 bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name, | |
215 NPVariant* result) { | |
216 if (!np_obj) | |
217 return false; | |
218 | |
219 if (IdentifierIsPostMessage(name) || | |
220 IdentifierIsAddEventListener(name) || | |
221 IdentifierIsRemoveEventListener(name)) | |
222 return false; | |
223 | |
224 if (IdentifierIsSrcAttribute(name)) { | |
225 BrowserPluginBindings* bindings = GetBindings(np_obj); | |
226 if (!bindings) | |
227 return false; | |
228 std::string src = bindings->instance()->GetSrcAttribute(); | |
229 return StringToNPVariant(src, result); | |
230 } | |
231 | |
232 return false; | |
233 } | |
234 | |
235 bool BrowserPluginBindingsSetProperty(NPObject* np_obj, NPIdentifier name, | |
236 const NPVariant* variant) { | |
237 if (!np_obj) | |
238 return false; | |
239 | |
240 if (IdentifierIsSrcAttribute(name)) { | |
241 std::string src = StringFromNPVariant(*variant); | |
242 BrowserPluginBindings* bindings = GetBindings(np_obj); | |
243 if (!bindings) | |
244 return false; | |
245 bindings->instance()->SetSrcAttribute(src); | |
246 return true; | |
247 } | |
248 return false; | |
249 } | |
250 | |
251 bool BrowserPluginBindingsEnumerate(NPObject *np_obj, NPIdentifier **value, | |
252 uint32_t *count) { | |
253 NOTIMPLEMENTED(); | |
254 return true; | |
255 } | |
256 | |
257 NPClass browser_plugin_message_class = { | |
258 NP_CLASS_STRUCT_VERSION, | |
259 &BrowserPluginBindingsAllocate, | |
260 &BrowserPluginBindingsDeallocate, | |
261 NULL, | |
262 &BrowserPluginBindingsHasMethod, | |
263 &BrowserPluginBindingsInvoke, | |
264 &BrowserPluginBindingsInvokeDefault, | |
265 &BrowserPluginBindingsHasProperty, | |
266 &BrowserPluginBindingsGetProperty, | |
267 &BrowserPluginBindingsSetProperty, | |
268 NULL, | |
269 &BrowserPluginBindingsEnumerate, | |
270 }; | |
271 | |
272 } // namespace | |
273 | |
274 // BrowserPluginBindings ------------------------------------------------------ | |
275 | |
276 BrowserPluginBindings::BrowserPluginNPObject::BrowserPluginNPObject() { | |
277 } | |
278 | |
279 BrowserPluginBindings::BrowserPluginNPObject::~BrowserPluginNPObject() { | |
280 } | |
281 | |
282 BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance) | |
283 : instance_(instance), | |
284 np_object_(NULL), | |
285 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
286 NPObject* obj = | |
287 WebBindings::createObject(NULL, &browser_plugin_message_class); | |
288 np_object_ = static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(obj); | |
289 np_object_->message_channel = weak_ptr_factory_.GetWeakPtr(); | |
290 } | |
291 | |
292 BrowserPluginBindings::~BrowserPluginBindings() { | |
293 WebBindings::releaseObject(np_object_); | |
294 } | |
295 | |
296 } // namespace browser_plugin | |
297 } // namespace content | |
OLD | NEW |