Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "bindings/v8/Dictionary.h"
     28 
     29 #include "V8CSSFontFaceRule.h"
     30 #include "V8DOMError.h"
     31 #include "V8EventTarget.h"
     32 #include "V8IDBKeyRange.h"
     33 #include "V8MIDIPort.h"
     34 #include "V8MediaKeyError.h"
     35 #include "V8SpeechRecognitionError.h"
     36 #include "V8SpeechRecognitionResult.h"
     37 #include "V8SpeechRecognitionResultList.h"
     38 #include "V8Storage.h"
     39 #include "V8VoidCallback.h"
     40 #include "V8Window.h"
     41 #include "bindings/v8/ArrayValue.h"
     42 #include "bindings/v8/V8Binding.h"
     43 #include "bindings/v8/V8Utilities.h"
     44 #include "bindings/v8/custom/V8ArrayBufferViewCustom.h"
     45 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
     46 #include "core/dom/DOMStringList.h"
     47 #include "modules/indexeddb/IDBKeyRange.h"
     48 #include "modules/speech/SpeechRecognitionError.h"
     49 #include "modules/speech/SpeechRecognitionResult.h"
     50 #include "modules/speech/SpeechRecognitionResultList.h"
     51 #include "wtf/MathExtras.h"
     52 
     53 #include "V8TextTrack.h"
     54 #include "core/html/track/TrackBase.h"
     55 
     56 #include "V8MediaStream.h"
     57 #include "modules/mediastream/MediaStream.h"
     58 
     59 namespace WebCore {
     60 
     61 Dictionary::Dictionary()
     62     : m_isolate(0)
     63 {
     64 }
     65 
     66 Dictionary::Dictionary(const v8::Local<v8::Value>& options, v8::Isolate* isolate)
     67     : m_options(options)
     68     , m_isolate(isolate)
     69 {
     70     ASSERT(m_isolate);
     71 }
     72 
     73 Dictionary::~Dictionary()
     74 {
     75 }
     76 
     77 Dictionary& Dictionary::operator=(const Dictionary& optionsObject)
     78 {
     79     m_options = optionsObject.m_options;
     80     m_isolate = optionsObject.m_isolate;
     81     return *this;
     82 }
     83 
     84 bool Dictionary::isObject() const
     85 {
     86     return !isUndefinedOrNull() && m_options->IsObject();
     87 }
     88 
     89 bool Dictionary::isUndefinedOrNull() const
     90 {
     91     if (m_options.IsEmpty())
     92         return true;
     93     return WebCore::isUndefinedOrNull(m_options);
     94 }
     95 
     96 bool Dictionary::getKey(const String& key, v8::Local<v8::Value>& value) const
     97 {
     98     if (isUndefinedOrNull())
     99         return false;
    100     v8::Local<v8::Object> options = m_options->ToObject();
    101     ASSERT(!options.IsEmpty());
    102 
    103     ASSERT(m_isolate);
    104     ASSERT(m_isolate == v8::Isolate::GetCurrent());
    105     v8::Handle<v8::String> v8Key = v8String(key, m_isolate);
    106     if (!options->Has(v8Key))
    107         return false;
    108     value = options->Get(v8Key);
    109     if (value.IsEmpty())
    110         return false;
    111     return true;
    112 }
    113 
    114 bool Dictionary::get(const String& key, v8::Local<v8::Value>& value) const
    115 {
    116     return getKey(key, value);
    117 }
    118 
    119 bool Dictionary::get(const String& key, bool& value) const
    120 {
    121     v8::Local<v8::Value> v8Value;
    122     if (!getKey(key, v8Value))
    123         return false;
    124 
    125     v8::Local<v8::Boolean> v8Bool = v8Value->ToBoolean();
    126     if (v8Bool.IsEmpty())
    127         return false;
    128     value = v8Bool->Value();
    129     return true;
    130 }
    131 
    132 bool Dictionary::get(const String& key, int32_t& value) const
    133 {
    134     v8::Local<v8::Value> v8Value;
    135     if (!getKey(key, v8Value))
    136         return false;
    137 
    138     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
    139     if (v8Int32.IsEmpty())
    140         return false;
    141     value = v8Int32->Value();
    142     return true;
    143 }
    144 
    145 bool Dictionary::get(const String& key, double& value) const
    146 {
    147     v8::Local<v8::Value> v8Value;
    148     if (!getKey(key, v8Value))
    149         return false;
    150 
    151     v8::Local<v8::Number> v8Number = v8Value->ToNumber();
    152     if (v8Number.IsEmpty())
    153         return false;
    154     value = v8Number->Value();
    155     return true;
    156 }
    157 
    158 bool Dictionary::get(const String& key, String& value) const
    159 {
    160     v8::Local<v8::Value> v8Value;
    161     if (!getKey(key, v8Value))
    162         return false;
    163 
    164     // FIXME: It is possible for this to throw in which case we'd be getting back
    165     //        an empty string and returning true when we should be returning false.
    166     //        See fast/dom/Geolocation/script-tests/argument-types.js for a similar
    167     //        example.
    168     value = toWebCoreString(v8Value);
    169     return true;
    170 }
    171 
    172 bool Dictionary::get(const String& key, ScriptValue& value) const
    173 {
    174     v8::Local<v8::Value> v8Value;
    175     if (!getKey(key, v8Value))
    176         return false;
    177 
    178     value = ScriptValue(v8Value);
    179     return true;
    180 }
    181 
    182 bool Dictionary::get(const String& key, unsigned short& value) const
    183 {
    184     v8::Local<v8::Value> v8Value;
    185     if (!getKey(key, v8Value))
    186         return false;
    187 
    188     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
    189     if (v8Int32.IsEmpty())
    190         return false;
    191     value = static_cast<unsigned short>(v8Int32->Value());
    192     return true;
    193 }
    194 
    195 bool Dictionary::get(const String& key, short& value) const
    196 {
    197     v8::Local<v8::Value> v8Value;
    198     if (!getKey(key, v8Value))
    199         return false;
    200 
    201     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
    202     if (v8Int32.IsEmpty())
    203         return false;
    204     value = static_cast<short>(v8Int32->Value());
    205     return true;
    206 }
    207 
    208 bool Dictionary::get(const String& key, unsigned& value) const
    209 {
    210     v8::Local<v8::Value> v8Value;
    211     if (!getKey(key, v8Value))
    212         return false;
    213 
    214     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
    215     if (v8Int32.IsEmpty())
    216         return false;
    217     value = static_cast<unsigned>(v8Int32->Value());
    218     return true;
    219 }
    220 
    221 bool Dictionary::get(const String& key, unsigned long& value) const
    222 {
    223     v8::Local<v8::Value> v8Value;
    224     if (!getKey(key, v8Value))
    225         return false;
    226 
    227     v8::Local<v8::Integer> v8Integer = v8Value->ToInteger();
    228     if (v8Integer.IsEmpty())
    229         return false;
    230     value = static_cast<unsigned long>(v8Integer->Value());
    231     return true;
    232 }
    233 
    234 bool Dictionary::get(const String& key, unsigned long long& value) const
    235 {
    236     v8::Local<v8::Value> v8Value;
    237     if (!getKey(key, v8Value))
    238         return false;
    239 
    240     v8::Local<v8::Number> v8Number = v8Value->ToNumber();
    241     if (v8Number.IsEmpty())
    242         return false;
    243     double d = v8Number->Value();
    244     doubleToInteger(d, value);
    245     return true;
    246 }
    247 
    248 bool Dictionary::get(const String& key, RefPtr<DOMWindow>& value) const
    249 {
    250     v8::Local<v8::Value> v8Value;
    251     if (!getKey(key, v8Value))
    252         return false;
    253 
    254     // We need to handle a DOMWindow specially, because a DOMWindow wrapper
    255     // exists on a prototype chain of v8Value.
    256     value = 0;
    257     if (v8Value->IsObject()) {
    258         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
    259         v8::Handle<v8::Object> window = wrapper->FindInstanceInPrototypeChain(V8Window::GetTemplate(m_isolate, worldTypeInMainThread(m_isolate)));
    260         if (!window.IsEmpty())
    261             value = V8Window::toNative(window);
    262     }
    263     return true;
    264 }
    265 
    266 bool Dictionary::get(const String& key, RefPtr<Storage>& value) const
    267 {
    268     v8::Local<v8::Value> v8Value;
    269     if (!getKey(key, v8Value))
    270         return false;
    271 
    272     value = 0;
    273     if (V8Storage::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    274         value = V8Storage::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    275     return true;
    276 }
    277 
    278 bool Dictionary::get(const String& key, MessagePortArray& value) const
    279 {
    280     v8::Local<v8::Value> v8Value;
    281     if (!getKey(key, v8Value))
    282         return false;
    283 
    284     ASSERT(m_isolate);
    285     ASSERT(m_isolate == v8::Isolate::GetCurrent());
    286     return getMessagePortArray(v8Value, value, m_isolate);
    287 }
    288 
    289 bool Dictionary::get(const String& key, HashSet<AtomicString>& value) const
    290 {
    291     v8::Local<v8::Value> v8Value;
    292     if (!getKey(key, v8Value))
    293         return false;
    294 
    295     // FIXME: Support array-like objects
    296     if (!v8Value->IsArray())
    297         return false;
    298 
    299     ASSERT(m_isolate);
    300     ASSERT(m_isolate == v8::Isolate::GetCurrent());
    301     v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
    302     for (size_t i = 0; i < v8Array->Length(); ++i) {
    303         v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(i, m_isolate));
    304         value.add(toWebCoreString(indexedValue));
    305     }
    306 
    307     return true;
    308 }
    309 
    310 bool Dictionary::getWithUndefinedOrNullCheck(const String& key, String& value) const
    311 {
    312     v8::Local<v8::Value> v8Value;
    313     if (!getKey(key, v8Value) || v8Value->IsNull() || v8Value->IsUndefined())
    314         return false;
    315 
    316     // FIXME: It is possible for this to throw in which case we'd be getting back
    317     //        an empty string and returning true when we should be returning false.
    318     //        See fast/dom/Geolocation/script-tests/argument-types.js for a similar
    319     //        example.
    320     value = WebCore::isUndefinedOrNull(v8Value) ? String() : toWebCoreString(v8Value);
    321     return true;
    322 }
    323 
    324 bool Dictionary::get(const String& key, RefPtr<Uint8Array>& value) const
    325 {
    326     v8::Local<v8::Value> v8Value;
    327     if (!getKey(key, v8Value))
    328         return false;
    329 
    330     value = 0;
    331     if (V8Uint8Array::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    332         value = V8Uint8Array::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    333     return true;
    334 }
    335 
    336 bool Dictionary::get(const String& key, RefPtr<ArrayBufferView>& value) const
    337 {
    338     v8::Local<v8::Value> v8Value;
    339     if (!getKey(key, v8Value))
    340         return false;
    341 
    342     value = 0;
    343     if (V8ArrayBufferView::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    344         value = V8ArrayBufferView::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    345     return true;
    346 }
    347 
    348 bool Dictionary::get(const String& key, RefPtr<MIDIPort>& value) const
    349 {
    350     v8::Local<v8::Value> v8Value;
    351     if (!getKey(key, v8Value))
    352         return false;
    353 
    354     value = 0;
    355     if (V8MIDIPort::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    356         value = V8MIDIPort::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    357     return true;
    358 }
    359 
    360 bool Dictionary::get(const String& key, RefPtr<MediaKeyError>& value) const
    361 {
    362     v8::Local<v8::Value> v8Value;
    363     if (!getKey(key, v8Value))
    364         return false;
    365 
    366     value = 0;
    367     if (V8MediaKeyError::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    368         value = V8MediaKeyError::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    369     return true;
    370 }
    371 
    372 bool Dictionary::get(const String& key, RefPtr<TrackBase>& value) const
    373 {
    374     v8::Local<v8::Value> v8Value;
    375     if (!getKey(key, v8Value))
    376         return false;
    377 
    378     TrackBase* source = 0;
    379     if (v8Value->IsObject()) {
    380         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
    381 
    382         // FIXME: this will need to be changed so it can also return an AudioTrack or a VideoTrack once
    383         // we add them.
    384         v8::Handle<v8::Object> track = wrapper->FindInstanceInPrototypeChain(V8TextTrack::GetTemplate(m_isolate, worldType(m_isolate)));
    385         if (!track.IsEmpty())
    386             source = V8TextTrack::toNative(track);
    387     }
    388     value = source;
    389     return true;
    390 }
    391 
    392 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionError>& value) const
    393 {
    394     v8::Local<v8::Value> v8Value;
    395     if (!getKey(key, v8Value))
    396         return false;
    397 
    398     value = 0;
    399     if (V8SpeechRecognitionError::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    400         value = V8SpeechRecognitionError::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    401     return true;
    402 }
    403 
    404 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionResult>& value) const
    405 {
    406     v8::Local<v8::Value> v8Value;
    407     if (!getKey(key, v8Value))
    408         return false;
    409 
    410     value = 0;
    411     if (V8SpeechRecognitionResult::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    412         value = V8SpeechRecognitionResult::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    413     return true;
    414 }
    415 
    416 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionResultList>& value) const
    417 {
    418     v8::Local<v8::Value> v8Value;
    419     if (!getKey(key, v8Value))
    420         return false;
    421 
    422     value = 0;
    423     if (V8SpeechRecognitionResultList::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    424         value = V8SpeechRecognitionResultList::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    425     return true;
    426 }
    427 
    428 bool Dictionary::get(const String& key, RefPtr<MediaStream>& value) const
    429 {
    430     v8::Local<v8::Value> v8Value;
    431     if (!getKey(key, v8Value))
    432         return false;
    433 
    434     value = 0;
    435     if (V8MediaStream::HasInstance(v8Value, m_isolate, worldType(m_isolate)))
    436         value = V8MediaStream::toNative(v8::Handle<v8::Object>::Cast(v8Value));
    437     return true;
    438 }
    439 
    440 bool Dictionary::get(const String& key, RefPtr<EventTarget>& value) const
    441 {
    442     v8::Local<v8::Value> v8Value;
    443     if (!getKey(key, v8Value))
    444         return false;
    445 
    446     value = 0;
    447     // We need to handle a DOMWindow specially, because a DOMWindow wrapper
    448     // exists on a prototype chain of v8Value.
    449     if (v8Value->IsObject()) {
    450         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
    451         v8::Handle<v8::Object> window = wrapper->FindInstanceInPrototypeChain(V8Window::GetTemplate(m_isolate, worldTypeInMainThread(m_isolate)));
    452         if (!window.IsEmpty()) {
    453             value = toWrapperTypeInfo(window)->toEventTarget(window);
    454             return true;
    455         }
    456     }
    457 
    458     if (V8DOMWrapper::isDOMWrapper(v8Value)) {
    459         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
    460         value = toWrapperTypeInfo(wrapper)->toEventTarget(wrapper);
    461     }
    462     return true;
    463 }
    464 
    465 bool Dictionary::get(const String& key, Dictionary& value) const
    466 {
    467     v8::Local<v8::Value> v8Value;
    468     if (!getKey(key, v8Value))
    469         return false;
    470 
    471     if (v8Value->IsObject()) {
    472         ASSERT(m_isolate);
    473         ASSERT(m_isolate == v8::Isolate::GetCurrent());
    474         value = Dictionary(v8Value, m_isolate);
    475     }
    476 
    477     return true;
    478 }
    479 
    480 bool Dictionary::get(const String& key, Vector<String>& value) const
    481 {
    482     v8::Local<v8::Value> v8Value;
    483     if (!getKey(key, v8Value))
    484         return false;
    485 
    486     if (!v8Value->IsArray())
    487         return false;
    488 
    489     v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
    490     for (size_t i = 0; i < v8Array->Length(); ++i) {
    491         v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Uint32::New(i));
    492         value.append(toWebCoreString(indexedValue));
    493     }
    494 
    495     return true;
    496 }
    497 
    498 bool Dictionary::get(const String& key, ArrayValue& value) const
    499 {
    500     v8::Local<v8::Value> v8Value;
    501     if (!getKey(key, v8Value))
    502         return false;
    503 
    504     if (!v8Value->IsArray())
    505         return false;
    506 
    507     ASSERT(m_isolate);
    508     ASSERT(m_isolate == v8::Isolate::GetCurrent());
    509     value = ArrayValue(v8::Local<v8::Array>::Cast(v8Value), m_isolate);
    510     return true;
    511 }
    512 
    513 bool Dictionary::get(const String& key, RefPtr<CSSFontFaceRule>& value) const
    514 {
    515     v8::Local<v8::Value> v8Value;
    516     if (!getKey(key, v8Value))
    517         return false;
    518 
    519     CSSFontFaceRule* source = 0;
    520     if (v8Value->IsObject()) {
    521         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
    522         v8::Handle<v8::Object> fontface = wrapper->FindInstanceInPrototypeChain(V8CSSFontFaceRule::GetTemplate(m_isolate, worldType(m_isolate)));
    523         if (!fontface.IsEmpty())
    524             source = V8CSSFontFaceRule::toNative(fontface);
    525     }
    526     value = source;
    527     return true;
    528 }
    529 
    530 bool Dictionary::get(const String& key, RefPtr<DOMError>& value) const
    531 {
    532     v8::Local<v8::Value> v8Value;
    533     if (!getKey(key, v8Value))
    534         return false;
    535 
    536     DOMError* error = 0;
    537     if (v8Value->IsObject()) {
    538         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
    539         v8::Handle<v8::Object> domError = wrapper->FindInstanceInPrototypeChain(V8DOMError::GetTemplate(m_isolate, worldType(m_isolate)));
    540         if (!domError.IsEmpty())
    541             error = V8DOMError::toNative(domError);
    542     }
    543     value = error;
    544     return true;
    545 }
    546 
    547 bool Dictionary::get(const String& key, RefPtr<VoidCallback>& value) const
    548 {
    549     v8::Local<v8::Value> v8Value;
    550     if (!getKey(key, v8Value))
    551         return false;
    552 
    553     if (!v8Value->IsFunction())
    554         return false;
    555 
    556     value = V8VoidCallback::create(v8Value, getScriptExecutionContext());
    557     return true;
    558 }
    559 
    560 bool Dictionary::getOwnPropertiesAsStringHashMap(HashMap<String, String>& hashMap) const
    561 {
    562     if (!isObject())
    563         return false;
    564 
    565     v8::Handle<v8::Object> options = m_options->ToObject();
    566     if (options.IsEmpty())
    567         return false;
    568 
    569     v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
    570     if (properties.IsEmpty())
    571         return true;
    572     for (uint32_t i = 0; i < properties->Length(); ++i) {
    573         v8::Local<v8::String> key = properties->Get(i)->ToString();
    574         if (!options->Has(key))
    575             continue;
    576 
    577         v8::Local<v8::Value> value = options->Get(key);
    578         String stringKey = toWebCoreString(key);
    579         String stringValue = toWebCoreString(value);
    580         if (!stringKey.isEmpty())
    581             hashMap.set(stringKey, stringValue);
    582     }
    583 
    584     return true;
    585 }
    586 
    587 bool Dictionary::getOwnPropertyNames(Vector<String>& names) const
    588 {
    589     if (!isObject())
    590         return false;
    591 
    592     v8::Handle<v8::Object> options = m_options->ToObject();
    593     if (options.IsEmpty())
    594         return false;
    595 
    596     v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
    597     if (properties.IsEmpty())
    598         return true;
    599     for (uint32_t i = 0; i < properties->Length(); ++i) {
    600         v8::Local<v8::String> key = properties->Get(i)->ToString();
    601         if (!options->Has(key))
    602             continue;
    603         names.append(toWebCoreString(key));
    604     }
    605 
    606     return true;
    607 }
    608 
    609 } // namespace WebCore
    610