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 "V8DOMError.h"
30 #include "V8EventTarget.h"
31 #include "V8IDBKeyRange.h"
32 #include "V8MIDIPort.h"
33 #include "V8MediaKeyError.h"
34 #include "V8MessagePort.h"
35 #include "V8SpeechRecognitionError.h"
36 #include "V8SpeechRecognitionResult.h"
37 #include "V8SpeechRecognitionResultList.h"
38 #include "V8Storage.h"
39 #include "V8VoidCallback.h"
41 #include "bindings/v8/ArrayValue.h"
42 #include "bindings/v8/ExceptionMessages.h"
43 #include "bindings/v8/ExceptionState.h"
44 #include "bindings/v8/V8Binding.h"
45 #include "bindings/v8/V8Utilities.h"
46 #include "bindings/v8/custom/V8ArrayBufferViewCustom.h"
47 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
48 #include "modules/indexeddb/IDBKeyRange.h"
49 #include "modules/speech/SpeechRecognitionError.h"
50 #include "modules/speech/SpeechRecognitionResult.h"
51 #include "modules/speech/SpeechRecognitionResultList.h"
52 #include "wtf/MathExtras.h"
54 #include "V8TextTrack.h"
55 #include "core/html/track/TrackBase.h"
57 #include "V8MediaStream.h"
58 #include "modules/mediastream/MediaStream.h"
62 Dictionary::Dictionary()
67 Dictionary::Dictionary(const v8::Handle<v8::Value>& options, v8::Isolate* isolate)
74 Dictionary::~Dictionary()
78 Dictionary& Dictionary::operator=(const Dictionary& optionsObject)
80 m_options = optionsObject.m_options;
81 m_isolate = optionsObject.m_isolate;
85 bool Dictionary::isObject() const
87 return !isUndefinedOrNull() && m_options->IsObject();
90 bool Dictionary::isUndefinedOrNull() const
92 if (m_options.IsEmpty())
94 return WebCore::isUndefinedOrNull(m_options);
97 bool Dictionary::hasProperty(const String& key) const
99 if (isUndefinedOrNull())
101 v8::Local<v8::Object> options = m_options->ToObject();
102 ASSERT(!options.IsEmpty());
105 ASSERT(m_isolate == v8::Isolate::GetCurrent());
106 v8::Handle<v8::String> v8Key = v8String(m_isolate, key);
107 if (!options->Has(v8Key))
113 bool Dictionary::getKey(const String& key, v8::Local<v8::Value>& value) const
115 if (isUndefinedOrNull())
117 v8::Local<v8::Object> options = m_options->ToObject();
118 ASSERT(!options.IsEmpty());
121 ASSERT(m_isolate == v8::Isolate::GetCurrent());
122 v8::Handle<v8::String> v8Key = v8String(m_isolate, key);
123 if (!options->Has(v8Key))
125 value = options->Get(v8Key);
131 bool Dictionary::get(const String& key, v8::Local<v8::Value>& value) const
133 return getKey(key, value);
136 bool Dictionary::get(const String& key, bool& value) const
138 v8::Local<v8::Value> v8Value;
139 if (!getKey(key, v8Value))
142 v8::Local<v8::Boolean> v8Bool = v8Value->ToBoolean();
143 if (v8Bool.IsEmpty())
145 value = v8Bool->Value();
149 bool Dictionary::convert(ConversionContext& context, const String& key, bool& value) const
151 ConversionContextScope scope(context);
156 bool Dictionary::get(const String& key, int32_t& value) const
158 v8::Local<v8::Value> v8Value;
159 if (!getKey(key, v8Value))
162 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
163 if (v8Int32.IsEmpty())
165 value = v8Int32->Value();
169 bool Dictionary::get(const String& key, double& value, bool& hasValue) const
171 v8::Local<v8::Value> v8Value;
172 if (!getKey(key, v8Value)) {
178 V8TRYCATCH_RETURN(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
179 if (v8Number.IsEmpty())
181 value = v8Number->Value();
185 bool Dictionary::get(const String& key, double& value) const
188 return get(key, value, unused);
191 bool Dictionary::convert(ConversionContext& context, const String& key, double& value) const
193 ConversionContextScope scope(context);
195 bool hasValue = false;
196 if (!get(key, value, hasValue) && hasValue) {
197 context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "is not of type 'double'."));
203 template<typename StringType>
204 inline bool Dictionary::getStringType(const String& key, StringType& value) const
206 v8::Local<v8::Value> v8Value;
207 if (!getKey(key, v8Value))
210 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, v8Value, false);
215 bool Dictionary::get(const String& key, String& value) const
217 return getStringType(key, value);
220 bool Dictionary::get(const String& key, AtomicString& value) const
222 return getStringType(key, value);
225 bool Dictionary::convert(ConversionContext& context, const String& key, String& value) const
227 ConversionContextScope scope(context);
229 v8::Local<v8::Value> v8Value;
230 if (!getKey(key, v8Value))
233 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, v8Value, false);
238 bool Dictionary::get(const String& key, ScriptValue& value) const
240 v8::Local<v8::Value> v8Value;
241 if (!getKey(key, v8Value))
244 value = ScriptValue(v8Value, m_isolate);
248 bool Dictionary::convert(ConversionContext& context, const String& key, ScriptValue& value) const
250 ConversionContextScope scope(context);
256 bool Dictionary::get(const String& key, unsigned short& value) const
258 v8::Local<v8::Value> v8Value;
259 if (!getKey(key, v8Value))
262 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
263 if (v8Int32.IsEmpty())
265 value = static_cast<unsigned short>(v8Int32->Value());
269 bool Dictionary::get(const String& key, short& value) const
271 v8::Local<v8::Value> v8Value;
272 if (!getKey(key, v8Value))
275 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
276 if (v8Int32.IsEmpty())
278 value = static_cast<short>(v8Int32->Value());
282 bool Dictionary::get(const String& key, unsigned& value) const
284 v8::Local<v8::Value> v8Value;
285 if (!getKey(key, v8Value))
288 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
289 if (v8Int32.IsEmpty())
291 value = static_cast<unsigned>(v8Int32->Value());
295 bool Dictionary::get(const String& key, unsigned long& value) const
297 v8::Local<v8::Value> v8Value;
298 if (!getKey(key, v8Value))
301 v8::Local<v8::Integer> v8Integer = v8Value->ToInteger();
302 if (v8Integer.IsEmpty())
304 value = static_cast<unsigned long>(v8Integer->Value());
308 bool Dictionary::get(const String& key, unsigned long long& value) const
310 v8::Local<v8::Value> v8Value;
311 if (!getKey(key, v8Value))
314 V8TRYCATCH_RETURN(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
315 if (v8Number.IsEmpty())
317 double d = v8Number->Value();
318 doubleToInteger(d, value);
322 bool Dictionary::get(const String& key, RefPtr<DOMWindow>& value) const
324 v8::Local<v8::Value> v8Value;
325 if (!getKey(key, v8Value))
328 // We need to handle a DOMWindow specially, because a DOMWindow wrapper
329 // exists on a prototype chain of v8Value.
330 value = toDOMWindow(v8Value, m_isolate);
334 bool Dictionary::get(const String& key, RefPtrWillBeRawPtr<Storage>& value) const
336 v8::Local<v8::Value> v8Value;
337 if (!getKey(key, v8Value))
341 if (V8Storage::hasInstance(v8Value, m_isolate))
342 value = V8Storage::toNative(v8::Handle<v8::Object>::Cast(v8Value));
346 bool Dictionary::get(const String& key, MessagePortArray& value) const
348 v8::Local<v8::Value> v8Value;
349 if (!getKey(key, v8Value))
353 ASSERT(m_isolate == v8::Isolate::GetCurrent());
354 if (WebCore::isUndefinedOrNull(v8Value))
356 bool success = false;
357 value = toRefPtrNativeArray<MessagePort, V8MessagePort>(v8Value, key, m_isolate, &success);
361 bool Dictionary::convert(ConversionContext& context, const String& key, MessagePortArray& value) const
363 ConversionContextScope scope(context);
365 v8::Local<v8::Value> v8Value;
366 if (!getKey(key, v8Value))
369 return get(key, value);
372 bool Dictionary::get(const String& key, HashSet<AtomicString>& value) const
374 v8::Local<v8::Value> v8Value;
375 if (!getKey(key, v8Value))
378 // FIXME: Support array-like objects
379 if (!v8Value->IsArray())
383 ASSERT(m_isolate == v8::Isolate::GetCurrent());
384 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
385 for (size_t i = 0; i < v8Array->Length(); ++i) {
386 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(m_isolate, i));
387 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, indexedValue, false);
388 value.add(stringValue);
394 bool Dictionary::convert(ConversionContext& context, const String& key, HashSet<AtomicString>& value) const
396 ConversionContextScope scope(context);
398 v8::Local<v8::Value> v8Value;
399 if (!getKey(key, v8Value))
402 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
405 if (!v8Value->IsArray()) {
406 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
410 return get(key, value);
413 bool Dictionary::getWithUndefinedOrNullCheck(const String& key, String& value) const
415 v8::Local<v8::Value> v8Value;
416 if (!getKey(key, v8Value) || WebCore::isUndefinedOrNull(v8Value))
419 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, v8Value, false);
424 bool Dictionary::get(const String& key, RefPtr<Uint8Array>& value) const
426 v8::Local<v8::Value> v8Value;
427 if (!getKey(key, v8Value))
431 if (V8Uint8Array::hasInstance(v8Value, m_isolate))
432 value = V8Uint8Array::toNative(v8::Handle<v8::Object>::Cast(v8Value));
436 bool Dictionary::get(const String& key, RefPtr<ArrayBufferView>& value) const
438 v8::Local<v8::Value> v8Value;
439 if (!getKey(key, v8Value))
443 if (V8ArrayBufferView::hasInstance(v8Value, m_isolate))
444 value = V8ArrayBufferView::toNative(v8::Handle<v8::Object>::Cast(v8Value));
448 bool Dictionary::get(const String& key, RefPtr<MIDIPort>& value) const
450 v8::Local<v8::Value> v8Value;
451 if (!getKey(key, v8Value))
455 if (V8MIDIPort::hasInstance(v8Value, m_isolate))
456 value = V8MIDIPort::toNative(v8::Handle<v8::Object>::Cast(v8Value));
460 bool Dictionary::get(const String& key, RefPtr<MediaKeyError>& value) const
462 v8::Local<v8::Value> v8Value;
463 if (!getKey(key, v8Value))
467 if (V8MediaKeyError::hasInstance(v8Value, m_isolate))
468 value = V8MediaKeyError::toNative(v8::Handle<v8::Object>::Cast(v8Value));
472 bool Dictionary::get(const String& key, RefPtr<TrackBase>& value) const
474 v8::Local<v8::Value> v8Value;
475 if (!getKey(key, v8Value))
478 TrackBase* source = 0;
479 if (v8Value->IsObject()) {
480 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
482 // FIXME: this will need to be changed so it can also return an AudioTrack or a VideoTrack once
484 v8::Handle<v8::Object> track = wrapper->FindInstanceInPrototypeChain(V8TextTrack::domTemplate(m_isolate, worldType(m_isolate)));
485 if (!track.IsEmpty())
486 source = V8TextTrack::toNative(track);
492 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionError>& value) const
494 v8::Local<v8::Value> v8Value;
495 if (!getKey(key, v8Value))
499 if (V8SpeechRecognitionError::hasInstance(v8Value, m_isolate))
500 value = V8SpeechRecognitionError::toNative(v8::Handle<v8::Object>::Cast(v8Value));
504 bool Dictionary::get(const String& key, RefPtrWillBeRawPtr<SpeechRecognitionResult>& value) const
506 v8::Local<v8::Value> v8Value;
507 if (!getKey(key, v8Value))
511 if (V8SpeechRecognitionResult::hasInstance(v8Value, m_isolate))
512 value = V8SpeechRecognitionResult::toNative(v8::Handle<v8::Object>::Cast(v8Value));
516 bool Dictionary::get(const String& key, RefPtrWillBeRawPtr<SpeechRecognitionResultList>& value) const
518 v8::Local<v8::Value> v8Value;
519 if (!getKey(key, v8Value))
523 if (V8SpeechRecognitionResultList::hasInstance(v8Value, m_isolate))
524 value = V8SpeechRecognitionResultList::toNative(v8::Handle<v8::Object>::Cast(v8Value));
528 bool Dictionary::get(const String& key, RefPtr<MediaStream>& value) const
530 v8::Local<v8::Value> v8Value;
531 if (!getKey(key, v8Value))
535 if (V8MediaStream::hasInstance(v8Value, m_isolate))
536 value = V8MediaStream::toNative(v8::Handle<v8::Object>::Cast(v8Value));
540 bool Dictionary::get(const String& key, RefPtr<EventTarget>& value) const
542 v8::Local<v8::Value> v8Value;
543 if (!getKey(key, v8Value))
547 // We need to handle a DOMWindow specially, because a DOMWindow wrapper
548 // exists on a prototype chain of v8Value.
549 if (v8Value->IsObject()) {
550 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
551 v8::Handle<v8::Object> window = wrapper->FindInstanceInPrototypeChain(V8Window::domTemplate(m_isolate, worldTypeInMainThread(m_isolate)));
552 if (!window.IsEmpty()) {
553 value = toWrapperTypeInfo(window)->toEventTarget(window);
558 if (V8DOMWrapper::isDOMWrapper(v8Value)) {
559 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
560 value = toWrapperTypeInfo(wrapper)->toEventTarget(wrapper);
565 bool Dictionary::get(const String& key, Dictionary& value) const
567 v8::Local<v8::Value> v8Value;
568 if (!getKey(key, v8Value))
571 if (v8Value->IsObject()) {
573 ASSERT(m_isolate == v8::Isolate::GetCurrent());
574 value = Dictionary(v8Value, m_isolate);
580 bool Dictionary::convert(ConversionContext& context, const String& key, Dictionary& value) const
582 ConversionContextScope scope(context);
584 v8::Local<v8::Value> v8Value;
585 if (!getKey(key, v8Value))
588 if (v8Value->IsObject())
589 return get(key, value);
591 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
594 context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "does not have a Dictionary type."));
598 bool Dictionary::get(const String& key, Vector<String>& value) const
600 v8::Local<v8::Value> v8Value;
601 if (!getKey(key, v8Value))
604 if (!v8Value->IsArray())
607 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
608 for (size_t i = 0; i < v8Array->Length(); ++i) {
609 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Uint32::New(m_isolate, i));
610 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, indexedValue, false);
611 value.append(stringValue);
617 bool Dictionary::convert(ConversionContext& context, const String& key, Vector<String>& value) const
619 ConversionContextScope scope(context);
621 v8::Local<v8::Value> v8Value;
622 if (!getKey(key, v8Value))
625 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
628 if (!v8Value->IsArray()) {
629 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
633 return get(key, value);
636 bool Dictionary::get(const String& key, ArrayValue& value) const
638 v8::Local<v8::Value> v8Value;
639 if (!getKey(key, v8Value))
642 if (!v8Value->IsArray())
646 ASSERT(m_isolate == v8::Isolate::GetCurrent());
647 value = ArrayValue(v8::Local<v8::Array>::Cast(v8Value), m_isolate);
651 bool Dictionary::convert(ConversionContext& context, const String& key, ArrayValue& value) const
653 ConversionContextScope scope(context);
655 v8::Local<v8::Value> v8Value;
656 if (!getKey(key, v8Value))
659 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
662 if (!v8Value->IsArray()) {
663 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
667 return get(key, value);
670 bool Dictionary::get(const String& key, RefPtr<DOMError>& value) const
672 v8::Local<v8::Value> v8Value;
673 if (!getKey(key, v8Value))
677 if (v8Value->IsObject()) {
678 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
679 v8::Handle<v8::Object> domError = wrapper->FindInstanceInPrototypeChain(V8DOMError::domTemplate(m_isolate, worldType(m_isolate)));
680 if (!domError.IsEmpty())
681 error = V8DOMError::toNative(domError);
687 bool Dictionary::get(const String& key, OwnPtr<VoidCallback>& value) const
689 v8::Local<v8::Value> v8Value;
690 if (!getKey(key, v8Value))
693 if (!v8Value->IsFunction())
696 value = V8VoidCallback::create(v8::Handle<v8::Function>::Cast(v8Value), currentExecutionContext(m_isolate));
700 bool Dictionary::getOwnPropertiesAsStringHashMap(HashMap<String, String>& hashMap) const
705 v8::Handle<v8::Object> options = m_options->ToObject();
706 if (options.IsEmpty())
709 v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
710 if (properties.IsEmpty())
712 for (uint32_t i = 0; i < properties->Length(); ++i) {
713 v8::Local<v8::String> key = properties->Get(i)->ToString();
714 if (!options->Has(key))
717 v8::Local<v8::Value> value = options->Get(key);
718 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringKey, key, false);
719 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, value, false);
720 if (!static_cast<const String&>(stringKey).isEmpty())
721 hashMap.set(stringKey, stringValue);
727 bool Dictionary::getOwnPropertyNames(Vector<String>& names) const
732 v8::Handle<v8::Object> options = m_options->ToObject();
733 if (options.IsEmpty())
736 v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
737 if (properties.IsEmpty())
739 for (uint32_t i = 0; i < properties->Length(); ++i) {
740 v8::Local<v8::String> key = properties->Get(i)->ToString();
741 if (!options->Has(key))
743 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringKey, key, false);
744 names.append(stringKey);
750 void Dictionary::ConversionContext::resetPerPropertyContext()
754 m_isNullable = false;
755 m_propertyTypeName = "";
759 Dictionary::ConversionContext& Dictionary::ConversionContext::setConversionType(const String& typeName, bool isNullable)
763 m_isNullable = isNullable;
764 m_propertyTypeName = typeName;
769 void Dictionary::ConversionContext::throwTypeError(const String& detail)
771 if (forConstructor()) {
772 exceptionState().throwTypeError(detail);
774 ASSERT(!methodName().isEmpty());
775 exceptionState().throwTypeError(ExceptionMessages::failedToExecute(interfaceName(), methodName(), detail));
779 } // namespace WebCore