2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "bindings/v8/Dictionary.h"
29 #include "bindings/core/v8/V8DOMError.h"
30 #include "bindings/core/v8/V8EventTarget.h"
31 #include "bindings/core/v8/V8MediaKeyError.h"
32 #include "bindings/core/v8/V8MessagePort.h"
33 #include "bindings/core/v8/V8Storage.h"
34 #include "bindings/core/v8/V8TextTrack.h"
35 #include "bindings/core/v8/V8VoidCallback.h"
36 #include "bindings/core/v8/V8Window.h"
37 #include "bindings/modules/v8/V8Gamepad.h"
38 #include "bindings/modules/v8/V8HeaderMap.h"
39 #include "bindings/modules/v8/V8IDBKeyRange.h"
40 #include "bindings/modules/v8/V8MIDIPort.h"
41 #include "bindings/modules/v8/V8MediaStream.h"
42 #include "bindings/modules/v8/V8SpeechRecognitionResult.h"
43 #include "bindings/modules/v8/V8SpeechRecognitionResultList.h"
44 #include "bindings/v8/ArrayValue.h"
45 #include "bindings/v8/ExceptionMessages.h"
46 #include "bindings/v8/ExceptionState.h"
47 #include "bindings/v8/V8Binding.h"
48 #include "bindings/v8/custom/V8ArrayBufferViewCustom.h"
49 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
50 #include "core/html/track/TrackBase.h"
51 #include "modules/gamepad/Gamepad.h"
52 #include "modules/indexeddb/IDBKeyRange.h"
53 #include "modules/mediastream/MediaStream.h"
54 #include "modules/speech/SpeechRecognitionResult.h"
55 #include "modules/speech/SpeechRecognitionResultList.h"
56 #include "wtf/MathExtras.h"
60 Dictionary::Dictionary()
65 Dictionary::Dictionary(const v8::Handle<v8::Value>& options, v8::Isolate* isolate)
72 Dictionary::~Dictionary()
76 Dictionary& Dictionary::operator=(const Dictionary& optionsObject)
78 m_options = optionsObject.m_options;
79 m_isolate = optionsObject.m_isolate;
83 bool Dictionary::isObject() const
85 return !isUndefinedOrNull() && m_options->IsObject();
88 bool Dictionary::isUndefinedOrNull() const
90 if (m_options.IsEmpty())
92 return WebCore::isUndefinedOrNull(m_options);
95 bool Dictionary::hasProperty(const String& key) const
97 if (isUndefinedOrNull())
99 v8::Local<v8::Object> options = m_options->ToObject();
100 ASSERT(!options.IsEmpty());
103 ASSERT(m_isolate == v8::Isolate::GetCurrent());
104 v8::Handle<v8::String> v8Key = v8String(m_isolate, key);
105 if (!options->Has(v8Key))
111 bool Dictionary::getKey(const String& key, v8::Local<v8::Value>& value) const
113 if (isUndefinedOrNull())
115 v8::Local<v8::Object> options = m_options->ToObject();
116 ASSERT(!options.IsEmpty());
119 ASSERT(m_isolate == v8::Isolate::GetCurrent());
120 v8::Handle<v8::String> v8Key = v8String(m_isolate, key);
121 if (!options->Has(v8Key))
123 value = options->Get(v8Key);
129 bool Dictionary::get(const String& key, v8::Local<v8::Value>& value) const
131 return getKey(key, value);
134 bool Dictionary::get(const String& key, bool& value) const
136 v8::Local<v8::Value> v8Value;
137 if (!getKey(key, v8Value))
140 v8::Local<v8::Boolean> v8Bool = v8Value->ToBoolean();
141 if (v8Bool.IsEmpty())
143 value = v8Bool->Value();
147 bool Dictionary::convert(ConversionContext& context, const String& key, bool& value) const
149 ConversionContextScope scope(context);
154 bool Dictionary::get(const String& key, int32_t& value) const
156 v8::Local<v8::Value> v8Value;
157 if (!getKey(key, v8Value))
160 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
161 if (v8Int32.IsEmpty())
163 value = v8Int32->Value();
167 bool Dictionary::get(const String& key, double& value, bool& hasValue) const
169 v8::Local<v8::Value> v8Value;
170 if (!getKey(key, v8Value)) {
176 TONATIVE_DEFAULT(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
177 if (v8Number.IsEmpty())
179 value = v8Number->Value();
183 bool Dictionary::get(const String& key, double& value) const
186 return get(key, value, unused);
189 bool Dictionary::convert(ConversionContext& context, const String& key, double& value) const
191 ConversionContextScope scope(context);
193 bool hasValue = false;
194 if (!get(key, value, hasValue) && hasValue) {
195 context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "is not of type 'double'."));
201 template<typename StringType>
202 inline bool Dictionary::getStringType(const String& key, StringType& value) const
204 v8::Local<v8::Value> v8Value;
205 if (!getKey(key, v8Value))
208 TOSTRING_DEFAULT(V8StringResource<>, stringValue, v8Value, false);
213 bool Dictionary::get(const String& key, String& value) const
215 return getStringType(key, value);
218 bool Dictionary::get(const String& key, AtomicString& value) const
220 return getStringType(key, value);
223 bool Dictionary::convert(ConversionContext& context, const String& key, String& value) const
225 ConversionContextScope scope(context);
227 v8::Local<v8::Value> v8Value;
228 if (!getKey(key, v8Value))
231 TOSTRING_DEFAULT(V8StringResource<>, stringValue, v8Value, false);
236 bool Dictionary::get(const String& key, ScriptValue& value) const
238 v8::Local<v8::Value> v8Value;
239 if (!getKey(key, v8Value))
242 value = ScriptValue(ScriptState::current(m_isolate), v8Value);
246 bool Dictionary::convert(ConversionContext& context, const String& key, ScriptValue& value) const
248 ConversionContextScope scope(context);
254 bool Dictionary::get(const String& key, unsigned short& value) const
256 v8::Local<v8::Value> v8Value;
257 if (!getKey(key, v8Value))
260 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
261 if (v8Int32.IsEmpty())
263 value = static_cast<unsigned short>(v8Int32->Value());
267 bool Dictionary::get(const String& key, short& value) const
269 v8::Local<v8::Value> v8Value;
270 if (!getKey(key, v8Value))
273 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
274 if (v8Int32.IsEmpty())
276 value = static_cast<short>(v8Int32->Value());
280 bool Dictionary::get(const String& key, unsigned& value) const
282 v8::Local<v8::Value> v8Value;
283 if (!getKey(key, v8Value))
286 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
287 if (v8Int32.IsEmpty())
289 value = static_cast<unsigned>(v8Int32->Value());
293 bool Dictionary::get(const String& key, unsigned long& value) const
295 v8::Local<v8::Value> v8Value;
296 if (!getKey(key, v8Value))
299 v8::Local<v8::Integer> v8Integer = v8Value->ToInteger();
300 if (v8Integer.IsEmpty())
302 value = static_cast<unsigned long>(v8Integer->Value());
306 bool Dictionary::get(const String& key, unsigned long long& value) const
308 v8::Local<v8::Value> v8Value;
309 if (!getKey(key, v8Value))
312 TONATIVE_DEFAULT(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
313 if (v8Number.IsEmpty())
315 double d = v8Number->Value();
316 doubleToInteger(d, value);
320 bool Dictionary::get(const String& key, RefPtrWillBeMember<LocalDOMWindow>& value) const
322 v8::Local<v8::Value> v8Value;
323 if (!getKey(key, v8Value))
326 // We need to handle a DOMWindow specially, because a DOMWindow wrapper
327 // exists on a prototype chain of v8Value.
328 value = toDOMWindow(v8Value, m_isolate);
332 bool Dictionary::get(const String& key, RefPtrWillBeMember<Storage>& value) const
334 v8::Local<v8::Value> v8Value;
335 if (!getKey(key, v8Value))
338 value = V8Storage::toNativeWithTypeCheck(m_isolate, v8Value);
342 bool Dictionary::get(const String& key, MessagePortArray& value) const
344 v8::Local<v8::Value> v8Value;
345 if (!getKey(key, v8Value))
349 ASSERT(m_isolate == v8::Isolate::GetCurrent());
350 if (WebCore::isUndefinedOrNull(v8Value))
352 bool success = false;
353 value = toRefPtrNativeArray<MessagePort, V8MessagePort>(v8Value, key, m_isolate, &success);
357 bool Dictionary::convert(ConversionContext& context, const String& key, MessagePortArray& value) const
359 ConversionContextScope scope(context);
361 v8::Local<v8::Value> v8Value;
362 if (!getKey(key, v8Value))
365 return get(key, value);
368 bool Dictionary::get(const String& key, HashSet<AtomicString>& value) const
370 v8::Local<v8::Value> v8Value;
371 if (!getKey(key, v8Value))
374 // FIXME: Support array-like objects
375 if (!v8Value->IsArray())
379 ASSERT(m_isolate == v8::Isolate::GetCurrent());
380 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
381 for (size_t i = 0; i < v8Array->Length(); ++i) {
382 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(m_isolate, i));
383 TOSTRING_DEFAULT(V8StringResource<>, stringValue, indexedValue, false);
384 value.add(stringValue);
390 bool Dictionary::convert(ConversionContext& context, const String& key, HashSet<AtomicString>& value) const
392 ConversionContextScope scope(context);
394 v8::Local<v8::Value> v8Value;
395 if (!getKey(key, v8Value))
398 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
401 if (!v8Value->IsArray()) {
402 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
406 return get(key, value);
409 bool Dictionary::getWithUndefinedOrNullCheck(const String& key, String& value) const
411 v8::Local<v8::Value> v8Value;
412 if (!getKey(key, v8Value) || WebCore::isUndefinedOrNull(v8Value))
415 TOSTRING_DEFAULT(V8StringResource<>, stringValue, v8Value, false);
420 bool Dictionary::get(const String& key, RefPtr<Uint8Array>& value) const
422 v8::Local<v8::Value> v8Value;
423 if (!getKey(key, v8Value))
426 value = V8Uint8Array::toNativeWithTypeCheck(m_isolate, v8Value);
430 bool Dictionary::get(const String& key, RefPtr<ArrayBufferView>& value) const
432 v8::Local<v8::Value> v8Value;
433 if (!getKey(key, v8Value))
436 value = V8ArrayBufferView::toNativeWithTypeCheck(m_isolate, v8Value);
440 bool Dictionary::get(const String& key, RefPtrWillBeMember<MIDIPort>& value) const
442 v8::Local<v8::Value> v8Value;
443 if (!getKey(key, v8Value))
446 value = V8MIDIPort::toNativeWithTypeCheck(m_isolate, v8Value);
450 bool Dictionary::get(const String& key, RefPtr<MediaKeyError>& value) const
452 v8::Local<v8::Value> v8Value;
453 if (!getKey(key, v8Value))
456 value = V8MediaKeyError::toNativeWithTypeCheck(m_isolate, v8Value);
460 bool Dictionary::get(const String& key, RefPtrWillBeMember<TrackBase>& value) const
462 v8::Local<v8::Value> v8Value;
463 if (!getKey(key, v8Value))
466 TrackBase* source = 0;
467 if (v8Value->IsObject()) {
468 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
470 // FIXME: this will need to be changed so it can also return an AudioTrack or a VideoTrack once
472 v8::Handle<v8::Object> track = V8TextTrack::findInstanceInPrototypeChain(wrapper, m_isolate);
473 if (!track.IsEmpty())
474 source = V8TextTrack::toNative(track);
480 bool Dictionary::get(const String& key, Member<SpeechRecognitionResult>& value) const
482 v8::Local<v8::Value> v8Value;
483 if (!getKey(key, v8Value))
486 value = V8SpeechRecognitionResult::toNativeWithTypeCheck(m_isolate, v8Value);
490 bool Dictionary::get(const String& key, Member<SpeechRecognitionResultList>& value) const
492 v8::Local<v8::Value> v8Value;
493 if (!getKey(key, v8Value))
496 value = V8SpeechRecognitionResultList::toNativeWithTypeCheck(m_isolate, v8Value);
500 bool Dictionary::get(const String& key, Member<Gamepad>& value) const
502 v8::Local<v8::Value> v8Value;
503 if (!getKey(key, v8Value))
506 value = V8Gamepad::toNativeWithTypeCheck(m_isolate, v8Value);
510 bool Dictionary::get(const String& key, RefPtr<MediaStream>& value) const
512 v8::Local<v8::Value> v8Value;
513 if (!getKey(key, v8Value))
516 value = V8MediaStream::toNativeWithTypeCheck(m_isolate, v8Value);
520 bool Dictionary::get(const String& key, RefPtrWillBeMember<EventTarget>& value) const
522 v8::Local<v8::Value> v8Value;
523 if (!getKey(key, v8Value))
527 // We need to handle a LocalDOMWindow specially, because a LocalDOMWindow wrapper
528 // exists on a prototype chain of v8Value.
529 if (v8Value->IsObject()) {
530 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
531 v8::Handle<v8::Object> window = V8Window::findInstanceInPrototypeChain(wrapper, m_isolate);
532 if (!window.IsEmpty()) {
533 value = toWrapperTypeInfo(window)->toEventTarget(window);
538 if (V8DOMWrapper::isDOMWrapper(v8Value)) {
539 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
540 value = toWrapperTypeInfo(wrapper)->toEventTarget(wrapper);
545 bool Dictionary::get(const String& key, Dictionary& value) const
547 v8::Local<v8::Value> v8Value;
548 if (!getKey(key, v8Value))
551 if (v8Value->IsObject()) {
553 ASSERT(m_isolate == v8::Isolate::GetCurrent());
554 value = Dictionary(v8Value, m_isolate);
560 bool Dictionary::get(const String& key, RefPtr<HeaderMap>& value) const
562 v8::Local<v8::Value> v8Value;
563 if (!getKey(key, v8Value))
566 value = V8HeaderMap::toNativeWithTypeCheck(m_isolate, v8Value);
570 bool Dictionary::convert(ConversionContext& context, const String& key, Dictionary& value) const
572 ConversionContextScope scope(context);
574 v8::Local<v8::Value> v8Value;
575 if (!getKey(key, v8Value))
578 if (v8Value->IsObject())
579 return get(key, value);
581 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
584 context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "does not have a Dictionary type."));
588 bool Dictionary::get(const String& key, Vector<String>& value) const
590 v8::Local<v8::Value> v8Value;
591 if (!getKey(key, v8Value))
594 if (!v8Value->IsArray())
597 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
598 for (size_t i = 0; i < v8Array->Length(); ++i) {
599 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Uint32::New(m_isolate, i));
600 TOSTRING_DEFAULT(V8StringResource<>, stringValue, indexedValue, false);
601 value.append(stringValue);
607 bool Dictionary::convert(ConversionContext& context, const String& key, Vector<String>& value) const
609 ConversionContextScope scope(context);
611 v8::Local<v8::Value> v8Value;
612 if (!getKey(key, v8Value))
615 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
618 if (!v8Value->IsArray()) {
619 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
623 return get(key, value);
626 bool Dictionary::get(const String& key, ArrayValue& value) const
628 v8::Local<v8::Value> v8Value;
629 if (!getKey(key, v8Value))
632 if (!v8Value->IsArray())
636 ASSERT(m_isolate == v8::Isolate::GetCurrent());
637 value = ArrayValue(v8::Local<v8::Array>::Cast(v8Value), m_isolate);
641 bool Dictionary::convert(ConversionContext& context, const String& key, ArrayValue& value) const
643 ConversionContextScope scope(context);
645 v8::Local<v8::Value> v8Value;
646 if (!getKey(key, v8Value))
649 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
652 if (!v8Value->IsArray()) {
653 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
657 return get(key, value);
660 bool Dictionary::get(const String& key, RefPtrWillBeMember<DOMError>& value) const
662 v8::Local<v8::Value> v8Value;
663 if (!getKey(key, v8Value))
666 value = V8DOMError::toNativeWithTypeCheck(m_isolate, v8Value);
670 bool Dictionary::getOwnPropertiesAsStringHashMap(HashMap<String, String>& hashMap) const
675 v8::Handle<v8::Object> options = m_options->ToObject();
676 if (options.IsEmpty())
679 v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
680 if (properties.IsEmpty())
682 for (uint32_t i = 0; i < properties->Length(); ++i) {
683 v8::Local<v8::String> key = properties->Get(i)->ToString();
684 if (!options->Has(key))
687 v8::Local<v8::Value> value = options->Get(key);
688 TOSTRING_DEFAULT(V8StringResource<>, stringKey, key, false);
689 TOSTRING_DEFAULT(V8StringResource<>, stringValue, value, false);
690 if (!static_cast<const String&>(stringKey).isEmpty())
691 hashMap.set(stringKey, stringValue);
697 bool Dictionary::getOwnPropertyNames(Vector<String>& names) const
702 v8::Handle<v8::Object> options = m_options->ToObject();
703 if (options.IsEmpty())
706 v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
707 if (properties.IsEmpty())
709 for (uint32_t i = 0; i < properties->Length(); ++i) {
710 v8::Local<v8::String> key = properties->Get(i)->ToString();
711 if (!options->Has(key))
713 TOSTRING_DEFAULT(V8StringResource<>, stringKey, key, false);
714 names.append(stringKey);
720 void Dictionary::ConversionContext::resetPerPropertyContext()
724 m_isNullable = false;
725 m_propertyTypeName = "";
729 Dictionary::ConversionContext& Dictionary::ConversionContext::setConversionType(const String& typeName, bool isNullable)
733 m_isNullable = isNullable;
734 m_propertyTypeName = typeName;
739 void Dictionary::ConversionContext::throwTypeError(const String& detail)
741 exceptionState().throwTypeError(detail);
744 } // namespace WebCore