Home | History | Annotate | Download | only in browser_plugin
      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 WebKit::WebBindings;
     32 using WebKit::WebElement;
     33 using WebKit::WebDOMEvent;
     34 using WebKit::WebDOMMessageEvent;
     35 using WebKit::WebPluginContainer;
     36 using WebKit::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 bool StringToNPVariant(const std::string &in, NPVariant *variant) {
     55   size_t length = in.size();
     56   NPUTF8 *chars = static_cast<NPUTF8 *>(malloc(length));
     57   if (!chars) {
     58     VOID_TO_NPVARIANT(*variant);
     59     return false;
     60   }
     61   memcpy(chars, in.c_str(), length);
     62   STRINGN_TO_NPVARIANT(chars, length, *variant);
     63   return true;
     64 }
     65 
     66 // Depending on where the attribute comes from it could be a string, int32,
     67 // or a double. Javascript tends to produce an int32 or a string, but setting
     68 // the value from the developer tools console may also produce a double.
     69 int IntFromNPVariant(const NPVariant& variant) {
     70   int value = 0;
     71   switch (variant.type) {
     72     case NPVariantType_Double:
     73       value = NPVARIANT_TO_DOUBLE(variant);
     74       break;
     75     case NPVariantType_Int32:
     76       value = NPVARIANT_TO_INT32(variant);
     77       break;
     78     case NPVariantType_String:
     79       base::StringToInt(StringFromNPVariant(variant), &value);
     80       break;
     81     default:
     82       break;
     83   }
     84   return value;
     85 }
     86 
     87 //------------------------------------------------------------------------------
     88 // Implementations of NPClass functions.  These are here to:
     89 // - Implement src attribute.
     90 //------------------------------------------------------------------------------
     91 NPObject* BrowserPluginBindingsAllocate(NPP npp, NPClass* the_class) {
     92   return new BrowserPluginBindings::BrowserPluginNPObject;
     93 }
     94 
     95 void BrowserPluginBindingsDeallocate(NPObject* object) {
     96   BrowserPluginBindings::BrowserPluginNPObject* instance =
     97       static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object);
     98   delete instance;
     99 }
    100 
    101 bool BrowserPluginBindingsHasMethod(NPObject* np_obj, NPIdentifier name) {
    102   if (!np_obj)
    103     return false;
    104 
    105   BrowserPluginBindings* bindings = GetBindings(np_obj);
    106   if (!bindings)
    107     return false;
    108 
    109   return bindings->HasMethod(name);
    110 }
    111 
    112 bool BrowserPluginBindingsInvoke(NPObject* np_obj, NPIdentifier name,
    113                                  const NPVariant* args, uint32 arg_count,
    114                                  NPVariant* result) {
    115   if (!np_obj)
    116     return false;
    117 
    118   BrowserPluginBindings* bindings = GetBindings(np_obj);
    119   if (!bindings)
    120     return false;
    121 
    122   return bindings->InvokeMethod(name, args, arg_count, result);
    123 }
    124 
    125 bool BrowserPluginBindingsInvokeDefault(NPObject* np_obj,
    126                                         const NPVariant* args,
    127                                         uint32 arg_count,
    128                                         NPVariant* result) {
    129   NOTIMPLEMENTED();
    130   return false;
    131 }
    132 
    133 bool BrowserPluginBindingsHasProperty(NPObject* np_obj, NPIdentifier name) {
    134   if (!np_obj)
    135     return false;
    136 
    137   BrowserPluginBindings* bindings = GetBindings(np_obj);
    138   if (!bindings)
    139     return false;
    140 
    141   return bindings->HasProperty(name);
    142 }
    143 
    144 bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name,
    145                                       NPVariant* result) {
    146   if (!np_obj)
    147     return false;
    148 
    149   if (!result)
    150     return false;
    151 
    152   // All attributes from here on rely on the bindings, so retrieve it once and
    153   // return on failure.
    154   BrowserPluginBindings* bindings = GetBindings(np_obj);
    155   if (!bindings)
    156     return false;
    157 
    158   return bindings->GetProperty(name, result);
    159 }
    160 
    161 bool BrowserPluginBindingsSetProperty(NPObject* np_obj, NPIdentifier name,
    162                                       const NPVariant* variant) {
    163   if (!np_obj)
    164     return false;
    165   if (!variant)
    166     return false;
    167 
    168   // All attributes from here on rely on the bindings, so retrieve it once and
    169   // return on failure.
    170   BrowserPluginBindings* bindings = GetBindings(np_obj);
    171   if (!bindings)
    172     return false;
    173 
    174   if (variant->type == NPVariantType_Null)
    175     return bindings->RemoveProperty(np_obj, name);
    176 
    177   return bindings->SetProperty(np_obj, name, variant);
    178 }
    179 
    180 bool BrowserPluginBindingsEnumerate(NPObject *np_obj, NPIdentifier **value,
    181                                     uint32_t *count) {
    182   NOTIMPLEMENTED();
    183   return true;
    184 }
    185 
    186 NPClass browser_plugin_message_class = {
    187   NP_CLASS_STRUCT_VERSION,
    188   &BrowserPluginBindingsAllocate,
    189   &BrowserPluginBindingsDeallocate,
    190   NULL,
    191   &BrowserPluginBindingsHasMethod,
    192   &BrowserPluginBindingsInvoke,
    193   &BrowserPluginBindingsInvokeDefault,
    194   &BrowserPluginBindingsHasProperty,
    195   &BrowserPluginBindingsGetProperty,
    196   &BrowserPluginBindingsSetProperty,
    197   NULL,
    198   &BrowserPluginBindingsEnumerate,
    199 };
    200 
    201 }  // namespace
    202 
    203 // BrowserPluginMethodBinding --------------------------------------------------
    204 
    205 class BrowserPluginMethodBinding {
    206  public:
    207   BrowserPluginMethodBinding(const char name[], uint32 arg_count)
    208       : name_(name),
    209         arg_count_(arg_count) {
    210   }
    211 
    212   virtual ~BrowserPluginMethodBinding() {}
    213 
    214   bool MatchesName(NPIdentifier name) const {
    215     return WebBindings::getStringIdentifier(name_.c_str()) == name;
    216   }
    217 
    218   uint32 arg_count() const { return arg_count_; }
    219 
    220   virtual bool Invoke(BrowserPluginBindings* bindings,
    221                       const NPVariant* args,
    222                       NPVariant* result) = 0;
    223 
    224  private:
    225   std::string name_;
    226   uint32 arg_count_;
    227 
    228   DISALLOW_COPY_AND_ASSIGN(BrowserPluginMethodBinding);
    229 };
    230 
    231 class BrowserPluginBindingAttach: public BrowserPluginMethodBinding {
    232  public:
    233   BrowserPluginBindingAttach()
    234       : BrowserPluginMethodBinding(
    235           browser_plugin::kMethodInternalAttach, 1) {
    236   }
    237 
    238   virtual bool Invoke(BrowserPluginBindings* bindings,
    239                       const NPVariant* args,
    240                       NPVariant* result) OVERRIDE {
    241     if (!bindings->instance()->render_view())
    242       return false;
    243 
    244     scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
    245     v8::Handle<v8::Value> obj(WebKit::WebBindings::toV8Value(&args[0]));
    246     scoped_ptr<base::Value> value(
    247         converter->FromV8Value(obj, bindings->instance()->render_view()->
    248             GetWebView()->mainFrame()->mainWorldScriptContext()));
    249     if (!value)
    250       return false;
    251 
    252     if (!value->IsType(Value::TYPE_DICTIONARY))
    253       return false;
    254 
    255     scoped_ptr<base::DictionaryValue> extra_params(
    256         static_cast<base::DictionaryValue*>(value.release()));
    257     bindings->instance()->Attach(extra_params.Pass());
    258     return true;
    259   }
    260 
    261  private:
    262   DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingAttach);
    263 };
    264 
    265 class BrowserPluginBindingAttachWindowTo : public BrowserPluginMethodBinding {
    266  public:
    267   BrowserPluginBindingAttachWindowTo()
    268       : BrowserPluginMethodBinding(
    269           browser_plugin::kMethodInternalAttachWindowTo, 2) {
    270   }
    271 
    272   virtual bool Invoke(BrowserPluginBindings* bindings,
    273                       const NPVariant* args,
    274                       NPVariant* result) OVERRIDE {
    275     WebKit::WebNode node;
    276     WebBindings::getNode(NPVARIANT_TO_OBJECT(args[0]), &node);
    277     int window_id = IntFromNPVariant(args[1]);
    278     BOOLEAN_TO_NPVARIANT(BrowserPlugin::AttachWindowTo(node, window_id),
    279                          *result);
    280     return true;
    281   }
    282 
    283  private:
    284   DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingAttachWindowTo);
    285 };
    286 
    287 // Note: This is a method that is used internally by the <webview> shim only.
    288 // This should not be exposed to developers.
    289 class BrowserPluginBindingGetGuestInstanceID :
    290     public BrowserPluginMethodBinding {
    291  public:
    292   BrowserPluginBindingGetGuestInstanceID()
    293       : BrowserPluginMethodBinding(
    294           browser_plugin::kMethodGetGuestInstanceId, 0) {
    295   }
    296 
    297   virtual bool Invoke(BrowserPluginBindings* bindings,
    298                       const NPVariant* args,
    299                       NPVariant* result) OVERRIDE {
    300     int guest_instance_id = bindings->instance()->guest_instance_id();
    301     INT32_TO_NPVARIANT(guest_instance_id, *result);
    302     return true;
    303   }
    304 
    305  private:
    306   DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingGetGuestInstanceID);
    307 };
    308 
    309 // Note: This is a method that is used internally by the <webview> shim only.
    310 // This should not be exposed to developers.
    311 class BrowserPluginBindingTrackObjectLifetime
    312     : public BrowserPluginMethodBinding {
    313  public:
    314   BrowserPluginBindingTrackObjectLifetime()
    315       : BrowserPluginMethodBinding(
    316           browser_plugin::kMethodInternalTrackObjectLifetime, 2) {
    317   }
    318 
    319   virtual bool Invoke(BrowserPluginBindings* bindings,
    320                       const NPVariant* args,
    321                       NPVariant* result) OVERRIDE {
    322     bindings->instance()->TrackObjectLifetime(args, IntFromNPVariant(args[1]));
    323     return true;
    324   }
    325 
    326  private:
    327   DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingTrackObjectLifetime);
    328 };
    329 
    330 // BrowserPluginPropertyBinding ------------------------------------------------
    331 
    332 class BrowserPluginPropertyBinding {
    333  public:
    334   explicit BrowserPluginPropertyBinding(const char name[]) : name_(name) {}
    335   virtual ~BrowserPluginPropertyBinding() {}
    336   const std::string& name() const { return name_; }
    337   bool MatchesName(NPIdentifier name) const {
    338     return WebBindings::getStringIdentifier(name_.c_str()) == name;
    339   }
    340   virtual bool GetProperty(BrowserPluginBindings* bindings,
    341                            NPVariant* result) = 0;
    342   virtual bool SetProperty(BrowserPluginBindings* bindings,
    343                            NPObject* np_obj,
    344                            const NPVariant* variant) = 0;
    345   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    346                               NPObject* np_obj) = 0;
    347   // Updates the DOM Attribute value with the current property value.
    348   void UpdateDOMAttribute(BrowserPluginBindings* bindings,
    349                           std::string new_value) {
    350     bindings->instance()->UpdateDOMAttribute(name(), new_value);
    351   }
    352  private:
    353   std::string name_;
    354 
    355   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBinding);
    356 };
    357 
    358 class BrowserPluginPropertyBindingAutoSize
    359     : public BrowserPluginPropertyBinding {
    360  public:
    361   BrowserPluginPropertyBindingAutoSize()
    362       : BrowserPluginPropertyBinding(browser_plugin::kAttributeAutoSize) {
    363   }
    364   virtual bool GetProperty(BrowserPluginBindings* bindings,
    365                            NPVariant* result) OVERRIDE {
    366     bool auto_size = bindings->instance()->GetAutoSizeAttribute();
    367     BOOLEAN_TO_NPVARIANT(auto_size, *result);
    368     return true;
    369   }
    370   virtual bool SetProperty(BrowserPluginBindings* bindings,
    371                            NPObject* np_obj,
    372                            const NPVariant* variant) OVERRIDE {
    373     std::string value = StringFromNPVariant(*variant);
    374     if (!bindings->instance()->HasDOMAttribute(name())) {
    375       UpdateDOMAttribute(bindings, value);
    376       bindings->instance()->ParseAutoSizeAttribute();
    377     } else {
    378       UpdateDOMAttribute(bindings, value);
    379     }
    380     return true;
    381   }
    382   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    383                               NPObject* np_obj) OVERRIDE {
    384     bindings->instance()->RemoveDOMAttribute(name());
    385     bindings->instance()->ParseAutoSizeAttribute();
    386   }
    387  private:
    388   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingAutoSize);
    389 };
    390 
    391 class BrowserPluginPropertyBindingContentWindow
    392     : public BrowserPluginPropertyBinding {
    393  public:
    394   BrowserPluginPropertyBindingContentWindow()
    395       : BrowserPluginPropertyBinding(browser_plugin::kAttributeContentWindow) {
    396   }
    397   virtual bool GetProperty(BrowserPluginBindings* bindings,
    398                            NPVariant* result) OVERRIDE {
    399     NPObject* obj = bindings->instance()->GetContentWindow();
    400     if (obj) {
    401       result->type = NPVariantType_Object;
    402       result->value.objectValue = WebBindings::retainObject(obj);
    403     }
    404     return true;
    405   }
    406   virtual bool SetProperty(BrowserPluginBindings* bindings,
    407                            NPObject* np_obj,
    408                            const NPVariant* variant) OVERRIDE {
    409     return false;
    410   }
    411   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    412                               NPObject* np_obj) OVERRIDE {}
    413  private:
    414   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingContentWindow);
    415 };
    416 
    417 class BrowserPluginPropertyBindingMaxHeight
    418     : public BrowserPluginPropertyBinding {
    419  public:
    420   BrowserPluginPropertyBindingMaxHeight()
    421       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMaxHeight) {
    422   }
    423   virtual bool GetProperty(BrowserPluginBindings* bindings,
    424                            NPVariant* result) OVERRIDE {
    425     int max_height = bindings->instance()->GetMaxHeightAttribute();
    426     INT32_TO_NPVARIANT(max_height, *result);
    427     return true;
    428   }
    429   virtual bool SetProperty(BrowserPluginBindings* bindings,
    430                            NPObject* np_obj,
    431                            const NPVariant* variant) OVERRIDE {
    432     int new_value = IntFromNPVariant(*variant);
    433     if (bindings->instance()->GetMaxHeightAttribute() != new_value) {
    434       UpdateDOMAttribute(bindings, base::IntToString(new_value));
    435       bindings->instance()->ParseSizeContraintsChanged();
    436     }
    437     return true;
    438   }
    439   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    440                               NPObject* np_obj) OVERRIDE {
    441     bindings->instance()->RemoveDOMAttribute(name());
    442     bindings->instance()->ParseSizeContraintsChanged();
    443   }
    444  private:
    445   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMaxHeight);
    446 };
    447 
    448 class BrowserPluginPropertyBindingMaxWidth
    449     : public BrowserPluginPropertyBinding {
    450  public:
    451   BrowserPluginPropertyBindingMaxWidth()
    452       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMaxWidth) {
    453   }
    454   virtual bool GetProperty(BrowserPluginBindings* bindings,
    455                            NPVariant* result) OVERRIDE {
    456     int max_width = bindings->instance()->GetMaxWidthAttribute();
    457     INT32_TO_NPVARIANT(max_width, *result);
    458     return true;
    459   }
    460   virtual bool SetProperty(BrowserPluginBindings* bindings,
    461                            NPObject* np_obj,
    462                            const NPVariant* variant) OVERRIDE {
    463     int new_value = IntFromNPVariant(*variant);
    464     if (bindings->instance()->GetMaxWidthAttribute() != new_value) {
    465       UpdateDOMAttribute(bindings, base::IntToString(new_value));
    466       bindings->instance()->ParseSizeContraintsChanged();
    467     }
    468     return true;
    469   }
    470   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    471                               NPObject* np_obj) OVERRIDE {
    472     bindings->instance()->RemoveDOMAttribute(name());
    473     bindings->instance()->ParseSizeContraintsChanged();
    474   }
    475  private:
    476   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMaxWidth);
    477 };
    478 
    479 class BrowserPluginPropertyBindingMinHeight
    480     : public BrowserPluginPropertyBinding {
    481  public:
    482   BrowserPluginPropertyBindingMinHeight()
    483       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMinHeight) {
    484   }
    485   virtual bool GetProperty(BrowserPluginBindings* bindings,
    486                            NPVariant* result) OVERRIDE {
    487     int min_height = bindings->instance()->GetMinHeightAttribute();
    488     INT32_TO_NPVARIANT(min_height, *result);
    489     return true;
    490   }
    491   virtual bool SetProperty(BrowserPluginBindings* bindings,
    492                            NPObject* np_obj,
    493                            const NPVariant* variant) OVERRIDE {
    494     int new_value = IntFromNPVariant(*variant);
    495     if (bindings->instance()->GetMinHeightAttribute() != new_value) {
    496       UpdateDOMAttribute(bindings, base::IntToString(new_value));
    497       bindings->instance()->ParseSizeContraintsChanged();
    498     }
    499     return true;
    500   }
    501   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    502                               NPObject* np_obj) OVERRIDE {
    503     bindings->instance()->RemoveDOMAttribute(name());
    504     bindings->instance()->ParseSizeContraintsChanged();
    505   }
    506  private:
    507   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMinHeight);
    508 };
    509 
    510 class BrowserPluginPropertyBindingMinWidth
    511     : public BrowserPluginPropertyBinding {
    512  public:
    513   BrowserPluginPropertyBindingMinWidth()
    514       : BrowserPluginPropertyBinding(browser_plugin::kAttributeMinWidth) {
    515   }
    516   virtual bool GetProperty(BrowserPluginBindings* bindings,
    517                            NPVariant* result) OVERRIDE {
    518     int min_width = bindings->instance()->GetMinWidthAttribute();
    519     INT32_TO_NPVARIANT(min_width, *result);
    520     return true;
    521   }
    522   virtual bool SetProperty(BrowserPluginBindings* bindings,
    523                            NPObject* np_obj,
    524                            const NPVariant* variant) OVERRIDE {
    525     int new_value = IntFromNPVariant(*variant);
    526     if (bindings->instance()->GetMinWidthAttribute() != new_value) {
    527       UpdateDOMAttribute(bindings, base::IntToString(new_value));
    528       bindings->instance()->ParseSizeContraintsChanged();
    529     }
    530     return true;
    531   }
    532   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    533                               NPObject* np_obj) OVERRIDE {
    534     bindings->instance()->RemoveDOMAttribute(name());
    535     bindings->instance()->ParseSizeContraintsChanged();
    536   }
    537  private:
    538   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMinWidth);
    539 };
    540 
    541 class BrowserPluginPropertyBindingName
    542     : public BrowserPluginPropertyBinding {
    543  public:
    544   BrowserPluginPropertyBindingName()
    545       : BrowserPluginPropertyBinding(browser_plugin::kAttributeName) {
    546   }
    547   virtual bool GetProperty(BrowserPluginBindings* bindings,
    548                            NPVariant* result) OVERRIDE {
    549     std::string name = bindings->instance()->GetNameAttribute();
    550     return StringToNPVariant(name, result);
    551     return true;
    552   }
    553   virtual bool SetProperty(BrowserPluginBindings* bindings,
    554                            NPObject* np_obj,
    555                            const NPVariant* variant) OVERRIDE {
    556     std::string new_value = StringFromNPVariant(*variant);
    557     if (bindings->instance()->GetNameAttribute() != new_value) {
    558       UpdateDOMAttribute(bindings, new_value);
    559       bindings->instance()->ParseNameAttribute();
    560     }
    561     return true;
    562   }
    563   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    564                               NPObject* np_obj) OVERRIDE {
    565     bindings->instance()->RemoveDOMAttribute(name());
    566     bindings->instance()->ParseNameAttribute();
    567   }
    568  private:
    569   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingName);
    570 };
    571 
    572 class BrowserPluginPropertyBindingPartition
    573     : public BrowserPluginPropertyBinding {
    574  public:
    575   BrowserPluginPropertyBindingPartition()
    576       : BrowserPluginPropertyBinding(browser_plugin::kAttributePartition) {
    577   }
    578   virtual bool GetProperty(BrowserPluginBindings* bindings,
    579                            NPVariant* result) OVERRIDE {
    580     std::string partition_id = bindings->instance()->GetPartitionAttribute();
    581     return StringToNPVariant(partition_id, result);
    582   }
    583   virtual bool SetProperty(BrowserPluginBindings* bindings,
    584                            NPObject* np_obj,
    585                            const NPVariant* variant) OVERRIDE {
    586     std::string new_value = StringFromNPVariant(*variant);
    587     std::string old_value = bindings->instance()->GetPartitionAttribute();
    588     if (old_value != new_value) {
    589       UpdateDOMAttribute(bindings, new_value);
    590       std::string error_message;
    591       if (!bindings->instance()->ParsePartitionAttribute(&error_message)) {
    592         WebBindings::setException(
    593             np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
    594         // Reset to old value on error.
    595         UpdateDOMAttribute(bindings, old_value);
    596         return false;
    597       }
    598     }
    599     return true;
    600   }
    601   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    602                               NPObject* np_obj) OVERRIDE {
    603     std::string error_message;
    604     if (bindings->instance()->CanRemovePartitionAttribute(&error_message)) {
    605       bindings->instance()->RemoveDOMAttribute(name());
    606     } else {
    607       WebBindings::setException(
    608           np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
    609     }
    610   }
    611  private:
    612   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingPartition);
    613 };
    614 
    615 class BrowserPluginPropertyBindingSrc : public BrowserPluginPropertyBinding {
    616  public:
    617   BrowserPluginPropertyBindingSrc()
    618       : BrowserPluginPropertyBinding(browser_plugin::kAttributeSrc) {
    619   }
    620   virtual bool GetProperty(BrowserPluginBindings* bindings,
    621                            NPVariant* result) OVERRIDE {
    622     std::string src = bindings->instance()->GetSrcAttribute();
    623     return StringToNPVariant(src, result);
    624   }
    625   virtual bool SetProperty(BrowserPluginBindings* bindings,
    626                            NPObject* np_obj,
    627                            const NPVariant* variant) OVERRIDE {
    628     std::string new_value = StringFromNPVariant(*variant);
    629     // We should not be issuing navigation IPCs if we attempt to set the
    630     // src property to the empty string. Instead, we want to simply restore
    631     // the src attribute back to its old value.
    632     if (new_value.empty()) {
    633       RemoveProperty(bindings, np_obj);
    634       return true;
    635     }
    636     std::string old_value = bindings->instance()->GetSrcAttribute();
    637     bool guest_crashed = bindings->instance()->guest_crashed();
    638     if ((old_value != new_value) || guest_crashed) {
    639       // If the new value was empty then we're effectively resetting the
    640       // attribute to the old value here. This will be picked up by <webview>'s
    641       // mutation observer and will restore the src attribute after it has been
    642       // removed.
    643       UpdateDOMAttribute(bindings, new_value);
    644       std::string error_message;
    645       if (!bindings->instance()->ParseSrcAttribute(&error_message)) {
    646         WebBindings::setException(
    647             np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
    648         // Reset to old value on error.
    649         UpdateDOMAttribute(bindings, old_value);
    650         return false;
    651       }
    652     }
    653     return true;
    654   }
    655   virtual void RemoveProperty(BrowserPluginBindings* bindings,
    656                               NPObject* np_obj) OVERRIDE {
    657     std::string old_value = bindings->instance()->GetSrcAttribute();
    658     // Remove the DOM attribute to trigger the mutation observer when it is
    659     // restored to its original value again.
    660     bindings->instance()->RemoveDOMAttribute(name());
    661     UpdateDOMAttribute(bindings, old_value);
    662   }
    663  private:
    664   DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingSrc);
    665 };
    666 
    667 
    668 // BrowserPluginBindings ------------------------------------------------------
    669 
    670 BrowserPluginBindings::BrowserPluginNPObject::BrowserPluginNPObject() {
    671 }
    672 
    673 BrowserPluginBindings::BrowserPluginNPObject::~BrowserPluginNPObject() {
    674 }
    675 
    676 BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance)
    677     : instance_(instance),
    678       np_object_(NULL),
    679       weak_ptr_factory_(this) {
    680   NPObject* obj =
    681       WebBindings::createObject(instance->pluginNPP(),
    682                                 &browser_plugin_message_class);
    683   np_object_ = static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(obj);
    684   np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
    685 
    686   method_bindings_.push_back(new BrowserPluginBindingAttach);
    687   method_bindings_.push_back(new BrowserPluginBindingAttachWindowTo);
    688   method_bindings_.push_back(new BrowserPluginBindingGetGuestInstanceID);
    689   method_bindings_.push_back(new BrowserPluginBindingTrackObjectLifetime);
    690 
    691   property_bindings_.push_back(new BrowserPluginPropertyBindingAutoSize);
    692   property_bindings_.push_back(new BrowserPluginPropertyBindingContentWindow);
    693   property_bindings_.push_back(new BrowserPluginPropertyBindingMaxHeight);
    694   property_bindings_.push_back(new BrowserPluginPropertyBindingMaxWidth);
    695   property_bindings_.push_back(new BrowserPluginPropertyBindingMinHeight);
    696   property_bindings_.push_back(new BrowserPluginPropertyBindingMinWidth);
    697   property_bindings_.push_back(new BrowserPluginPropertyBindingName);
    698   property_bindings_.push_back(new BrowserPluginPropertyBindingPartition);
    699   property_bindings_.push_back(new BrowserPluginPropertyBindingSrc);
    700 }
    701 
    702 BrowserPluginBindings::~BrowserPluginBindings() {
    703   WebBindings::releaseObject(np_object_);
    704 }
    705 
    706 bool BrowserPluginBindings::HasMethod(NPIdentifier name) const {
    707   for (BindingList::const_iterator iter = method_bindings_.begin();
    708        iter != method_bindings_.end();
    709        ++iter) {
    710     if ((*iter)->MatchesName(name))
    711       return true;
    712   }
    713   return false;
    714 }
    715 
    716 bool BrowserPluginBindings::InvokeMethod(NPIdentifier name,
    717                                          const NPVariant* args,
    718                                          uint32 arg_count,
    719                                          NPVariant* result) {
    720   for (BindingList::iterator iter = method_bindings_.begin();
    721        iter != method_bindings_.end();
    722        ++iter) {
    723     if ((*iter)->MatchesName(name) && (*iter)->arg_count() == arg_count)
    724       return (*iter)->Invoke(this, args, result);
    725   }
    726   return false;
    727 }
    728 
    729 bool BrowserPluginBindings::HasProperty(NPIdentifier name) const {
    730   for (PropertyBindingList::const_iterator iter = property_bindings_.begin();
    731        iter != property_bindings_.end();
    732        ++iter) {
    733     if ((*iter)->MatchesName(name))
    734       return true;
    735   }
    736   return false;
    737 }
    738 
    739 bool BrowserPluginBindings::SetProperty(NPObject* np_obj,
    740                                         NPIdentifier name,
    741                                         const NPVariant* variant) {
    742   for (PropertyBindingList::iterator iter = property_bindings_.begin();
    743        iter != property_bindings_.end();
    744        ++iter) {
    745     if ((*iter)->MatchesName(name)) {
    746       if ((*iter)->SetProperty(this, np_obj, variant)) {
    747         return true;
    748       }
    749       break;
    750     }
    751   }
    752   return false;
    753 }
    754 
    755 bool BrowserPluginBindings::RemoveProperty(NPObject* np_obj,
    756                                            NPIdentifier name) {
    757   for (PropertyBindingList::iterator iter = property_bindings_.begin();
    758        iter != property_bindings_.end();
    759        ++iter) {
    760     if ((*iter)->MatchesName(name)) {
    761       (*iter)->RemoveProperty(this, np_obj);
    762       return true;
    763     }
    764   }
    765   return false;
    766 }
    767 
    768 bool BrowserPluginBindings::GetProperty(NPIdentifier name, NPVariant* result) {
    769   for (PropertyBindingList::iterator iter = property_bindings_.begin();
    770        iter != property_bindings_.end();
    771        ++iter) {
    772     if ((*iter)->MatchesName(name))
    773       return (*iter)->GetProperty(this, result);
    774   }
    775   return false;
    776 }
    777 
    778 }  // namespace content
    779