Home | History | Annotate | Download | only in renderer
      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 // This file contains definitions for CppVariant.
      6 
      7 #include <limits>
      8 #include "base/logging.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "third_party/WebKit/public/web/WebBindings.h"
     13 #include "webkit/renderer/cpp_variant.h"
     14 
     15 using blink::WebBindings;
     16 
     17 namespace webkit_glue {
     18 
     19 CppVariant::CppVariant() {
     20   type = NPVariantType_Null;
     21 }
     22 
     23 // Note that Set() performs a deep copy, which is necessary to safely
     24 // call FreeData() on the value in the destructor.
     25 CppVariant::CppVariant(const CppVariant& original) {
     26   type = NPVariantType_Null;
     27   Set(original);
     28 }
     29 
     30 // See comment for copy constructor, above.
     31 CppVariant& CppVariant::operator=(const CppVariant& original) {
     32   if (&original != this)
     33     Set(original);
     34   return *this;
     35 }
     36 
     37 CppVariant::~CppVariant() {
     38   FreeData();
     39 }
     40 
     41 void CppVariant::FreeData() {
     42   WebBindings::releaseVariantValue(this);
     43 }
     44 
     45 bool CppVariant::isEqual(const CppVariant& other) const {
     46   if (type != other.type)
     47     return false;
     48 
     49   switch (type) {
     50     case NPVariantType_Bool: {
     51       return (value.boolValue == other.value.boolValue);
     52     }
     53     case NPVariantType_Int32: {
     54       return (value.intValue == other.value.intValue);
     55     }
     56     case NPVariantType_Double: {
     57       return (value.doubleValue == other.value.doubleValue);
     58     }
     59     case NPVariantType_String: {
     60       const NPString *this_value = &value.stringValue;
     61       const NPString *other_value = &other.value.stringValue;
     62       uint32_t len = this_value->UTF8Length;
     63       return (len == other_value->UTF8Length &&
     64               !strncmp(this_value->UTF8Characters, other_value->UTF8Characters,
     65                        len));
     66     }
     67     case NPVariantType_Null:
     68     case NPVariantType_Void: {
     69       return true;
     70     }
     71     case NPVariantType_Object: {
     72       NPObject *this_value = value.objectValue;
     73       NPObject *other_value = other.value.objectValue;
     74       return (this_value->_class == other_value->_class &&
     75               this_value->referenceCount == other_value->referenceCount);
     76     }
     77   }
     78   return false;
     79 }
     80 
     81 void CppVariant::CopyToNPVariant(NPVariant* result) const {
     82   result->type = type;
     83   switch (type) {
     84     case NPVariantType_Bool:
     85       result->value.boolValue = value.boolValue;
     86       break;
     87     case NPVariantType_Int32:
     88       result->value.intValue = value.intValue;
     89       break;
     90     case NPVariantType_Double:
     91       result->value.doubleValue = value.doubleValue;
     92       break;
     93     case NPVariantType_String:
     94       WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
     95       break;
     96     case NPVariantType_Null:
     97     case NPVariantType_Void:
     98       // Nothing to set.
     99       break;
    100     case NPVariantType_Object:
    101       result->type = NPVariantType_Object;
    102       result->value.objectValue = WebBindings::retainObject(value.objectValue);
    103       break;
    104   }
    105 }
    106 
    107 void CppVariant::Set(const NPVariant& new_value) {
    108   FreeData();
    109   switch (new_value.type) {
    110     case NPVariantType_Bool:
    111       Set(new_value.value.boolValue);
    112       break;
    113     case NPVariantType_Int32:
    114       Set(new_value.value.intValue);
    115       break;
    116     case NPVariantType_Double:
    117       Set(new_value.value.doubleValue);
    118       break;
    119     case NPVariantType_String:
    120       Set(new_value.value.stringValue);
    121       break;
    122     case NPVariantType_Null:
    123     case NPVariantType_Void:
    124       type = new_value.type;
    125       break;
    126     case NPVariantType_Object:
    127       Set(new_value.value.objectValue);
    128       break;
    129   }
    130 }
    131 
    132 void CppVariant::SetNull() {
    133   FreeData();
    134   type = NPVariantType_Null;
    135 }
    136 
    137 void CppVariant::Set(bool new_value) {
    138   FreeData();
    139   type = NPVariantType_Bool;
    140   value.boolValue = new_value;
    141 }
    142 
    143 void CppVariant::Set(int32_t new_value) {
    144   FreeData();
    145   type = NPVariantType_Int32;
    146   value.intValue = new_value;
    147 }
    148 
    149 void CppVariant::Set(double new_value) {
    150   FreeData();
    151   type = NPVariantType_Double;
    152   value.doubleValue = new_value;
    153 }
    154 
    155 // The new_value must be a null-terminated string.
    156 void CppVariant::Set(const char* new_value) {
    157   FreeData();
    158   type = NPVariantType_String;
    159   NPString new_string = {new_value,
    160                          static_cast<uint32_t>(strlen(new_value))};
    161   WebBindings::initializeVariantWithStringCopy(this, &new_string);
    162 }
    163 
    164 void CppVariant::Set(const std::string& new_value) {
    165   FreeData();
    166   type = NPVariantType_String;
    167   NPString new_string = {new_value.data(),
    168                          static_cast<uint32_t>(new_value.size())};
    169   WebBindings::initializeVariantWithStringCopy(this, &new_string);
    170 }
    171 void CppVariant::Set(const NPString& new_value) {
    172   FreeData();
    173   type = NPVariantType_String;
    174   WebBindings::initializeVariantWithStringCopy(this, &new_value);
    175 }
    176 
    177 void CppVariant::Set(NPObject* new_value) {
    178   FreeData();
    179   type = NPVariantType_Object;
    180   value.objectValue = WebBindings::retainObject(new_value);
    181 }
    182 
    183 std::string CppVariant::ToString() const {
    184   DCHECK(isString());
    185   return std::string(value.stringValue.UTF8Characters,
    186                      value.stringValue.UTF8Length);
    187 }
    188 
    189 int32_t CppVariant::ToInt32() const {
    190   if (isInt32()) {
    191     return value.intValue;
    192   } else if (isDouble()) {
    193     return static_cast<int32_t>(value.doubleValue);
    194   } else {
    195     NOTREACHED();
    196     return 0;
    197   }
    198 }
    199 
    200 double CppVariant::ToDouble() const {
    201   if (isInt32()) {
    202     return static_cast<double>(value.intValue);
    203   } else if (isDouble()) {
    204     return value.doubleValue;
    205   } else {
    206     NOTREACHED();
    207     return 0.0;
    208   }
    209 }
    210 
    211 bool CppVariant::ToBoolean() const {
    212   DCHECK(isBool());
    213   return value.boolValue;
    214 }
    215 
    216 std::vector<CppVariant> CppVariant::ToVector() const {
    217   DCHECK(isObject());
    218   std::vector<CppVariant> vector;
    219   NPObject* np_value = value.objectValue;
    220   NPIdentifier length_id = WebBindings::getStringIdentifier("length");
    221 
    222   if (WebBindings::hasProperty(NULL, np_value, length_id)) {
    223     CppVariant length_value;
    224     if (WebBindings::getProperty(NULL, np_value, length_id, &length_value)) {
    225       int length = 0;
    226       // The length is a double in some cases.
    227       if (NPVARIANT_IS_DOUBLE(length_value))
    228         length = static_cast<int>(NPVARIANT_TO_DOUBLE(length_value));
    229       else if (NPVARIANT_IS_INT32(length_value))
    230         length = NPVARIANT_TO_INT32(length_value);
    231       else
    232         NOTREACHED();
    233 
    234       // For sanity, only allow 60000 items.
    235       length = std::min(60000, length);
    236       for (int i = 0; i < length; ++i) {
    237         // Get each of the items.
    238         NPIdentifier index = WebBindings::getIntIdentifier(i);
    239         if (WebBindings::hasProperty(NULL, np_value, index)) {
    240           CppVariant index_value;
    241           if (WebBindings::getProperty(NULL, np_value, index, &index_value))
    242             vector.push_back(index_value);
    243         }
    244       }
    245     }
    246   } else {
    247     NOTREACHED();
    248   }
    249   return vector;
    250 }
    251 
    252 bool CppVariant::Invoke(const std::string& method, const CppVariant* args,
    253                         uint32 arg_count, CppVariant& result) const {
    254   DCHECK(isObject());
    255   NPIdentifier method_name = WebBindings::getStringIdentifier(method.c_str());
    256   NPObject* np_object = value.objectValue;
    257   if (WebBindings::hasMethod(NULL, np_object, method_name)) {
    258     NPVariant r;
    259     bool status =
    260         WebBindings::invoke(NULL, np_object, method_name, args, arg_count, &r);
    261     result.Set(r);
    262     return status;
    263   } else {
    264     return false;
    265   }
    266 }
    267 
    268 }  // namespace webkit_glue
    269