6758242b9a83186c9926df14c6f4ac8ee077509b
[platform/framework/web/crosswalk.git] / src / content / renderer / browser_plugin / browser_plugin_bindings.cc
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/message_loop/message_loop.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "content/common/browser_plugin/browser_plugin_constants.h"
17 #include "content/public/renderer/v8_value_converter.h"
18 #include "content/renderer/browser_plugin/browser_plugin.h"
19 #include "third_party/WebKit/public/platform/WebString.h"
20 #include "third_party/WebKit/public/web/WebBindings.h"
21 #include "third_party/WebKit/public/web/WebDOMMessageEvent.h"
22 #include "third_party/WebKit/public/web/WebDocument.h"
23 #include "third_party/WebKit/public/web/WebElement.h"
24 #include "third_party/WebKit/public/web/WebFrame.h"
25 #include "third_party/WebKit/public/web/WebNode.h"
26 #include "third_party/WebKit/public/web/WebPluginContainer.h"
27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "third_party/npapi/bindings/npapi.h"
29 #include "v8/include/v8.h"
30
31 using blink::WebBindings;
32 using blink::WebElement;
33 using blink::WebDOMEvent;
34 using blink::WebDOMMessageEvent;
35 using blink::WebPluginContainer;
36 using blink::WebString;
37
38 namespace content {
39
40 namespace {
41
42 BrowserPluginBindings* GetBindings(NPObject* object) {
43   return static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object)->
44       message_channel.get();
45 }
46
47 std::string StringFromNPVariant(const NPVariant& variant) {
48   if (!NPVARIANT_IS_STRING(variant))
49     return std::string();
50   const NPString& np_string = NPVARIANT_TO_STRING(variant);
51   return std::string(np_string.UTF8Characters, np_string.UTF8Length);
52 }
53
54 // Depending on where the attribute comes from it could be a string, int32,
55 // or a double. Javascript tends to produce an int32 or a string, but setting
56 // the value from the developer tools console may also produce a double.
57 int IntFromNPVariant(const NPVariant& variant) {
58   int value = 0;
59   switch (variant.type) {
60     case NPVariantType_Double:
61       value = NPVARIANT_TO_DOUBLE(variant);
62       break;
63     case NPVariantType_Int32:
64       value = NPVARIANT_TO_INT32(variant);
65       break;
66     case NPVariantType_String:
67       base::StringToInt(StringFromNPVariant(variant), &value);
68       break;
69     default:
70       break;
71   }
72   return value;
73 }
74
75 //------------------------------------------------------------------------------
76 // Implementations of NPClass functions.  These are here to:
77 // - Implement src attribute.
78 //------------------------------------------------------------------------------
79 NPObject* BrowserPluginBindingsAllocate(NPP npp, NPClass* the_class) {
80   return new BrowserPluginBindings::BrowserPluginNPObject;
81 }
82
83 void BrowserPluginBindingsDeallocate(NPObject* object) {
84   BrowserPluginBindings::BrowserPluginNPObject* instance =
85       static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object);
86   delete instance;
87 }
88
89 bool BrowserPluginBindingsHasMethod(NPObject* np_obj, NPIdentifier name) {
90   if (!np_obj)
91     return false;
92
93   BrowserPluginBindings* bindings = GetBindings(np_obj);
94   if (!bindings)
95     return false;
96
97   return bindings->HasMethod(name);
98 }
99
100 bool BrowserPluginBindingsInvoke(NPObject* np_obj, NPIdentifier name,
101                                  const NPVariant* args, uint32 arg_count,
102                                  NPVariant* result) {
103   if (!np_obj)
104     return false;
105
106   BrowserPluginBindings* bindings = GetBindings(np_obj);
107   if (!bindings)
108     return false;
109
110   return bindings->InvokeMethod(name, args, arg_count, result);
111 }
112
113 bool BrowserPluginBindingsInvokeDefault(NPObject* np_obj,
114                                         const NPVariant* args,
115                                         uint32 arg_count,
116                                         NPVariant* result) {
117   NOTIMPLEMENTED();
118   return false;
119 }
120
121 bool BrowserPluginBindingsHasProperty(NPObject* np_obj, NPIdentifier name) {
122   if (!np_obj)
123     return false;
124
125   BrowserPluginBindings* bindings = GetBindings(np_obj);
126   if (!bindings)
127     return false;
128
129   return bindings->HasProperty(name);
130 }
131
132 bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name,
133                                       NPVariant* result) {
134   if (!np_obj)
135     return false;
136
137   if (!result)
138     return false;
139
140   // All attributes from here on rely on the bindings, so retrieve it once and
141   // return on failure.
142   BrowserPluginBindings* bindings = GetBindings(np_obj);
143   if (!bindings)
144     return false;
145
146   return bindings->GetProperty(name, result);
147 }
148
149 bool BrowserPluginBindingsSetProperty(NPObject* np_obj, NPIdentifier name,
150                                       const NPVariant* variant) {
151   if (!np_obj)
152     return false;
153   if (!variant)
154     return false;
155
156   // All attributes from here on rely on the bindings, so retrieve it once and
157   // return on failure.
158   BrowserPluginBindings* bindings = GetBindings(np_obj);
159   if (!bindings)
160     return false;
161
162   if (variant->type == NPVariantType_Null)
163     return bindings->RemoveProperty(np_obj, name);
164
165   return bindings->SetProperty(np_obj, name, variant);
166 }
167
168 bool BrowserPluginBindingsEnumerate(NPObject *np_obj, NPIdentifier **value,
169                                     uint32_t *count) {
170   NOTIMPLEMENTED();
171   return true;
172 }
173
174 NPClass browser_plugin_message_class = {
175   NP_CLASS_STRUCT_VERSION,
176   &BrowserPluginBindingsAllocate,
177   &BrowserPluginBindingsDeallocate,
178   NULL,
179   &BrowserPluginBindingsHasMethod,
180   &BrowserPluginBindingsInvoke,
181   &BrowserPluginBindingsInvokeDefault,
182   &BrowserPluginBindingsHasProperty,
183   &BrowserPluginBindingsGetProperty,
184   &BrowserPluginBindingsSetProperty,
185   NULL,
186   &BrowserPluginBindingsEnumerate,
187 };
188
189 }  // namespace
190
191 // BrowserPluginMethodBinding --------------------------------------------------
192
193 class BrowserPluginMethodBinding {
194  public:
195   BrowserPluginMethodBinding(const char name[], uint32 arg_count)
196       : name_(name),
197         arg_count_(arg_count) {
198   }
199
200   virtual ~BrowserPluginMethodBinding() {}
201
202   bool MatchesName(NPIdentifier name) const {
203     return WebBindings::getStringIdentifier(name_.c_str()) == name;
204   }
205
206   uint32 arg_count() const { return arg_count_; }
207
208   virtual bool Invoke(BrowserPluginBindings* bindings,
209                       const NPVariant* args,
210                       NPVariant* result) = 0;
211
212  private:
213   std::string name_;
214   uint32 arg_count_;
215
216   DISALLOW_COPY_AND_ASSIGN(BrowserPluginMethodBinding);
217 };
218
219 class BrowserPluginBindingAttach: public BrowserPluginMethodBinding {
220  public:
221   BrowserPluginBindingAttach()
222       : BrowserPluginMethodBinding(browser_plugin::kMethodInternalAttach, 2) {}
223
224   virtual bool Invoke(BrowserPluginBindings* bindings,
225                       const NPVariant* args,
226                       NPVariant* result) OVERRIDE {
227     bool attached = InvokeHelper(bindings, args);
228     BOOLEAN_TO_NPVARIANT(attached, *result);
229     return true;
230   }
231
232  private:
233   bool InvokeHelper(BrowserPluginBindings* bindings, const NPVariant* args) {
234     if (!bindings->instance()->render_view())
235       return false;
236
237     int instance_id = IntFromNPVariant(args[0]);
238     if (!instance_id)
239       return false;
240
241     scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
242     v8::Handle<v8::Value> obj(blink::WebBindings::toV8Value(&args[1]));
243     scoped_ptr<base::Value> value(
244         converter->FromV8Value(obj, bindings->instance()->render_view()->
245             GetWebView()->mainFrame()->mainWorldScriptContext()));
246     if (!value)
247       return false;
248
249     if (!value->IsType(base::Value::TYPE_DICTIONARY))
250       return false;
251
252     scoped_ptr<base::DictionaryValue> extra_params(
253         static_cast<base::DictionaryValue*>(value.release()));
254     bindings->instance()->Attach(instance_id, extra_params.Pass());
255     return true;
256   }
257   DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingAttach);
258 };
259
260 // BrowserPluginPropertyBinding ------------------------------------------------
261
262 class BrowserPluginPropertyBinding {
263  public:
264   explicit BrowserPluginPropertyBinding(const char name[]) : name_(name) {}
265   virtual ~BrowserPluginPropertyBinding() {}
266   const std::string& name() const { return name_; }
267   bool MatchesName(NPIdentifier name) const {
268     return WebBindings::getStringIdentifier(name_.c_str()) == name;
269   }
270   virtual bool GetProperty(BrowserPluginBindings* bindings,
271                            NPVariant* result) = 0;
272   virtual bool SetProperty(BrowserPluginBindings* bindings,
273                            NPObject* np_obj,
274                            const NPVariant* variant) = 0;
275   virtual void RemoveProperty(BrowserPluginBindings* bindings,
276                               NPObject* np_obj) = 0;
277   // Updates the DOM Attribute value with the current property value.
278   void UpdateDOMAttribute(BrowserPluginBindings* bindings,
279                           std::string new_value) {
280     bindings->instance()->UpdateDOMAttribute(name(), new_value);
281   }
282  private:
283   std::string name_;
284
285   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBinding);
286 };
287
288 class BrowserPluginPropertyBindingAllowTransparency
289     : public BrowserPluginPropertyBinding {
290  public:
291   BrowserPluginPropertyBindingAllowTransparency()
292       : BrowserPluginPropertyBinding(
293           browser_plugin::kAttributeAllowTransparency) {
294   }
295   virtual bool GetProperty(BrowserPluginBindings* bindings,
296                            NPVariant* result) OVERRIDE {
297     bool allow_transparency =
298         bindings->instance()->GetAllowTransparencyAttribute();
299     BOOLEAN_TO_NPVARIANT(allow_transparency, *result);
300     return true;
301   }
302   virtual bool SetProperty(BrowserPluginBindings* bindings,
303                            NPObject* np_obj,
304                            const NPVariant* variant) OVERRIDE {
305     std::string value = StringFromNPVariant(*variant);
306     if (!bindings->instance()->HasDOMAttribute(name())) {
307       UpdateDOMAttribute(bindings, value);
308       bindings->instance()->ParseAllowTransparencyAttribute();
309     } else {
310       UpdateDOMAttribute(bindings, value);
311     }
312     return true;
313   }
314   virtual void RemoveProperty(BrowserPluginBindings* bindings,
315                               NPObject* np_obj) OVERRIDE {
316     bindings->instance()->RemoveDOMAttribute(name());
317     bindings->instance()->ParseAllowTransparencyAttribute();
318   }
319  private:
320   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingAllowTransparency);
321 };
322
323 class BrowserPluginPropertyBindingAutoSize
324     : public BrowserPluginPropertyBinding {
325  public:
326   BrowserPluginPropertyBindingAutoSize()
327       : BrowserPluginPropertyBinding(browser_plugin::kAttributeAutoSize) {
328   }
329   virtual bool GetProperty(BrowserPluginBindings* bindings,
330                            NPVariant* result) OVERRIDE {
331     bool auto_size = bindings->instance()->GetAutoSizeAttribute();
332     BOOLEAN_TO_NPVARIANT(auto_size, *result);
333     return true;
334   }
335   virtual bool SetProperty(BrowserPluginBindings* bindings,
336                            NPObject* np_obj,
337                            const NPVariant* variant) OVERRIDE {
338     std::string value = StringFromNPVariant(*variant);
339     if (!bindings->instance()->HasDOMAttribute(name())) {
340       UpdateDOMAttribute(bindings, value);
341       bindings->instance()->ParseAutoSizeAttribute();
342     } else {
343       UpdateDOMAttribute(bindings, value);
344     }
345     return true;
346   }
347   virtual void RemoveProperty(BrowserPluginBindings* bindings,
348                               NPObject* np_obj) OVERRIDE {
349     bindings->instance()->RemoveDOMAttribute(name());
350     bindings->instance()->ParseAutoSizeAttribute();
351   }
352  private:
353   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingAutoSize);
354 };
355
356 class BrowserPluginPropertyBindingContentWindow
357     : public BrowserPluginPropertyBinding {
358  public:
359   BrowserPluginPropertyBindingContentWindow()
360       : BrowserPluginPropertyBinding(browser_plugin::kAttributeContentWindow) {
361   }
362   virtual bool GetProperty(BrowserPluginBindings* bindings,
363                            NPVariant* result) OVERRIDE {
364     NPObject* obj = bindings->instance()->GetContentWindow();
365     if (obj) {
366       result->type = NPVariantType_Object;
367       result->value.objectValue = WebBindings::retainObject(obj);
368     }
369     return true;
370   }
371   virtual bool SetProperty(BrowserPluginBindings* bindings,
372                            NPObject* np_obj,
373                            const NPVariant* variant) OVERRIDE {
374     return false;
375   }
376   virtual void RemoveProperty(BrowserPluginBindings* bindings,
377                               NPObject* np_obj) OVERRIDE {}
378  private:
379   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingContentWindow);
380 };
381
382 class BrowserPluginPropertyBindingMaxHeight
383     : public BrowserPluginPropertyBinding {
384  public:
385   BrowserPluginPropertyBindingMaxHeight()
386       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMaxHeight) {
387   }
388   virtual bool GetProperty(BrowserPluginBindings* bindings,
389                            NPVariant* result) OVERRIDE {
390     int max_height = bindings->instance()->GetMaxHeightAttribute();
391     INT32_TO_NPVARIANT(max_height, *result);
392     return true;
393   }
394   virtual bool SetProperty(BrowserPluginBindings* bindings,
395                            NPObject* np_obj,
396                            const NPVariant* variant) OVERRIDE {
397     int new_value = IntFromNPVariant(*variant);
398     if (bindings->instance()->GetMaxHeightAttribute() != new_value) {
399       UpdateDOMAttribute(bindings, base::IntToString(new_value));
400       bindings->instance()->ParseSizeContraintsChanged();
401     }
402     return true;
403   }
404   virtual void RemoveProperty(BrowserPluginBindings* bindings,
405                               NPObject* np_obj) OVERRIDE {
406     bindings->instance()->RemoveDOMAttribute(name());
407     bindings->instance()->ParseSizeContraintsChanged();
408   }
409  private:
410   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMaxHeight);
411 };
412
413 class BrowserPluginPropertyBindingMaxWidth
414     : public BrowserPluginPropertyBinding {
415  public:
416   BrowserPluginPropertyBindingMaxWidth()
417       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMaxWidth) {
418   }
419   virtual bool GetProperty(BrowserPluginBindings* bindings,
420                            NPVariant* result) OVERRIDE {
421     int max_width = bindings->instance()->GetMaxWidthAttribute();
422     INT32_TO_NPVARIANT(max_width, *result);
423     return true;
424   }
425   virtual bool SetProperty(BrowserPluginBindings* bindings,
426                            NPObject* np_obj,
427                            const NPVariant* variant) OVERRIDE {
428     int new_value = IntFromNPVariant(*variant);
429     if (bindings->instance()->GetMaxWidthAttribute() != new_value) {
430       UpdateDOMAttribute(bindings, base::IntToString(new_value));
431       bindings->instance()->ParseSizeContraintsChanged();
432     }
433     return true;
434   }
435   virtual void RemoveProperty(BrowserPluginBindings* bindings,
436                               NPObject* np_obj) OVERRIDE {
437     bindings->instance()->RemoveDOMAttribute(name());
438     bindings->instance()->ParseSizeContraintsChanged();
439   }
440  private:
441   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMaxWidth);
442 };
443
444 class BrowserPluginPropertyBindingMinHeight
445     : public BrowserPluginPropertyBinding {
446  public:
447   BrowserPluginPropertyBindingMinHeight()
448       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMinHeight) {
449   }
450   virtual bool GetProperty(BrowserPluginBindings* bindings,
451                            NPVariant* result) OVERRIDE {
452     int min_height = bindings->instance()->GetMinHeightAttribute();
453     INT32_TO_NPVARIANT(min_height, *result);
454     return true;
455   }
456   virtual bool SetProperty(BrowserPluginBindings* bindings,
457                            NPObject* np_obj,
458                            const NPVariant* variant) OVERRIDE {
459     int new_value = IntFromNPVariant(*variant);
460     if (bindings->instance()->GetMinHeightAttribute() != new_value) {
461       UpdateDOMAttribute(bindings, base::IntToString(new_value));
462       bindings->instance()->ParseSizeContraintsChanged();
463     }
464     return true;
465   }
466   virtual void RemoveProperty(BrowserPluginBindings* bindings,
467                               NPObject* np_obj) OVERRIDE {
468     bindings->instance()->RemoveDOMAttribute(name());
469     bindings->instance()->ParseSizeContraintsChanged();
470   }
471  private:
472   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMinHeight);
473 };
474
475 class BrowserPluginPropertyBindingMinWidth
476     : public BrowserPluginPropertyBinding {
477  public:
478   BrowserPluginPropertyBindingMinWidth()
479       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMinWidth) {
480   }
481   virtual bool GetProperty(BrowserPluginBindings* bindings,
482                            NPVariant* result) OVERRIDE {
483     int min_width = bindings->instance()->GetMinWidthAttribute();
484     INT32_TO_NPVARIANT(min_width, *result);
485     return true;
486   }
487   virtual bool SetProperty(BrowserPluginBindings* bindings,
488                            NPObject* np_obj,
489                            const NPVariant* variant) OVERRIDE {
490     int new_value = IntFromNPVariant(*variant);
491     if (bindings->instance()->GetMinWidthAttribute() != new_value) {
492       UpdateDOMAttribute(bindings, base::IntToString(new_value));
493       bindings->instance()->ParseSizeContraintsChanged();
494     }
495     return true;
496   }
497   virtual void RemoveProperty(BrowserPluginBindings* bindings,
498                               NPObject* np_obj) OVERRIDE {
499     bindings->instance()->RemoveDOMAttribute(name());
500     bindings->instance()->ParseSizeContraintsChanged();
501   }
502  private:
503   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMinWidth);
504 };
505
506
507 // BrowserPluginBindings ------------------------------------------------------
508
509 BrowserPluginBindings::BrowserPluginNPObject::BrowserPluginNPObject() {
510 }
511
512 BrowserPluginBindings::BrowserPluginNPObject::~BrowserPluginNPObject() {
513 }
514
515 BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance)
516     : instance_(instance),
517       np_object_(NULL),
518       weak_ptr_factory_(this) {
519   NPObject* obj =
520       WebBindings::createObject(instance->pluginNPP(),
521                                 &browser_plugin_message_class);
522   np_object_ = static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(obj);
523   np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
524
525   method_bindings_.push_back(new BrowserPluginBindingAttach);
526
527   property_bindings_.push_back(
528       new BrowserPluginPropertyBindingAllowTransparency);
529   property_bindings_.push_back(new BrowserPluginPropertyBindingAutoSize);
530   property_bindings_.push_back(new BrowserPluginPropertyBindingContentWindow);
531   property_bindings_.push_back(new BrowserPluginPropertyBindingMaxHeight);
532   property_bindings_.push_back(new BrowserPluginPropertyBindingMaxWidth);
533   property_bindings_.push_back(new BrowserPluginPropertyBindingMinHeight);
534   property_bindings_.push_back(new BrowserPluginPropertyBindingMinWidth);
535 }
536
537 BrowserPluginBindings::~BrowserPluginBindings() {
538   WebBindings::releaseObject(np_object_);
539 }
540
541 bool BrowserPluginBindings::HasMethod(NPIdentifier name) const {
542   for (BindingList::const_iterator iter = method_bindings_.begin();
543        iter != method_bindings_.end();
544        ++iter) {
545     if ((*iter)->MatchesName(name))
546       return true;
547   }
548   return false;
549 }
550
551 bool BrowserPluginBindings::InvokeMethod(NPIdentifier name,
552                                          const NPVariant* args,
553                                          uint32 arg_count,
554                                          NPVariant* result) {
555   for (BindingList::iterator iter = method_bindings_.begin();
556        iter != method_bindings_.end();
557        ++iter) {
558     if ((*iter)->MatchesName(name) && (*iter)->arg_count() == arg_count)
559       return (*iter)->Invoke(this, args, result);
560   }
561   return false;
562 }
563
564 bool BrowserPluginBindings::HasProperty(NPIdentifier name) const {
565   for (PropertyBindingList::const_iterator iter = property_bindings_.begin();
566        iter != property_bindings_.end();
567        ++iter) {
568     if ((*iter)->MatchesName(name))
569       return true;
570   }
571   return false;
572 }
573
574 bool BrowserPluginBindings::SetProperty(NPObject* np_obj,
575                                         NPIdentifier name,
576                                         const NPVariant* variant) {
577   for (PropertyBindingList::iterator iter = property_bindings_.begin();
578        iter != property_bindings_.end();
579        ++iter) {
580     if ((*iter)->MatchesName(name)) {
581       if ((*iter)->SetProperty(this, np_obj, variant)) {
582         return true;
583       }
584       break;
585     }
586   }
587   return false;
588 }
589
590 bool BrowserPluginBindings::RemoveProperty(NPObject* np_obj,
591                                            NPIdentifier name) {
592   for (PropertyBindingList::iterator iter = property_bindings_.begin();
593        iter != property_bindings_.end();
594        ++iter) {
595     if ((*iter)->MatchesName(name)) {
596       (*iter)->RemoveProperty(this, np_obj);
597       return true;
598     }
599   }
600   return false;
601 }
602
603 bool BrowserPluginBindings::GetProperty(NPIdentifier name, NPVariant* result) {
604   for (PropertyBindingList::iterator iter = property_bindings_.begin();
605        iter != property_bindings_.end();
606        ++iter) {
607     if ((*iter)->MatchesName(name))
608       return (*iter)->GetProperty(this, result);
609   }
610   return false;
611 }
612
613 }  // namespace content