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 "V8SpeechRecognitionError.h"
35 #include "V8SpeechRecognitionResult.h"
36 #include "V8SpeechRecognitionResultList.h"
37 #include "V8Storage.h"
38 #include "V8VoidCallback.h"
40 #include "bindings/v8/ArrayValue.h"
41 #include "bindings/v8/ExceptionMessages.h"
42 #include "bindings/v8/ExceptionState.h"
43 #include "bindings/v8/V8Binding.h"
44 #include "bindings/v8/V8Utilities.h"
45 #include "bindings/v8/custom/V8ArrayBufferViewCustom.h"
46 #include "bindings/v8/custom/V8Uint8ArrayCustom.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"
53 #include "V8TextTrack.h"
54 #include "core/html/track/TrackBase.h"
56 #include "V8MediaStream.h"
57 #include "modules/mediastream/MediaStream.h"
61 Dictionary::Dictionary()
66 Dictionary::Dictionary(const v8::Handle<v8::Value>& options, v8::Isolate* isolate)
73 Dictionary::~Dictionary()
77 Dictionary& Dictionary::operator=(const Dictionary& optionsObject)
79 m_options = optionsObject.m_options;
80 m_isolate = optionsObject.m_isolate;
84 bool Dictionary::isObject() const
86 return !isUndefinedOrNull() && m_options->IsObject();
89 bool Dictionary::isUndefinedOrNull() const
91 if (m_options.IsEmpty())
93 return WebCore::isUndefinedOrNull(m_options);
96 bool Dictionary::hasProperty(const String& key) const
98 if (isUndefinedOrNull())
100 v8::Local<v8::Object> options = m_options->ToObject();
101 ASSERT(!options.IsEmpty());
104 ASSERT(m_isolate == v8::Isolate::GetCurrent());
105 v8::Handle<v8::String> v8Key = v8String(m_isolate, key);
106 if (!options->Has(v8Key))
112 bool Dictionary::getKey(const String& key, v8::Local<v8::Value>& value) const
114 if (isUndefinedOrNull())
116 v8::Local<v8::Object> options = m_options->ToObject();
117 ASSERT(!options.IsEmpty());
120 ASSERT(m_isolate == v8::Isolate::GetCurrent());
121 v8::Handle<v8::String> v8Key = v8String(m_isolate, key);
122 if (!options->Has(v8Key))
124 value = options->Get(v8Key);
130 bool Dictionary::get(const String& key, v8::Local<v8::Value>& value) const
132 return getKey(key, value);
135 bool Dictionary::get(const String& key, bool& value) const
137 v8::Local<v8::Value> v8Value;
138 if (!getKey(key, v8Value))
141 v8::Local<v8::Boolean> v8Bool = v8Value->ToBoolean();
142 if (v8Bool.IsEmpty())
144 value = v8Bool->Value();
148 bool Dictionary::convert(ConversionContext& context, const String& key, bool& value) const
150 ConversionContextScope scope(context);
155 bool Dictionary::get(const String& key, int32_t& value) const
157 v8::Local<v8::Value> v8Value;
158 if (!getKey(key, v8Value))
161 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
162 if (v8Int32.IsEmpty())
164 value = v8Int32->Value();
168 bool Dictionary::get(const String& key, double& value, bool& hasValue) const
170 v8::Local<v8::Value> v8Value;
171 if (!getKey(key, v8Value)) {
177 V8TRYCATCH_RETURN(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
178 if (v8Number.IsEmpty())
180 value = v8Number->Value();
184 bool Dictionary::get(const String& key, double& value) const
187 return get(key, value, unused);
190 bool Dictionary::convert(ConversionContext& context, const String& key, double& value) const
192 ConversionContextScope scope(context);
194 bool hasValue = false;
195 if (!get(key, value, hasValue) && hasValue) {
196 context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "is not of type 'double'."));
202 template<typename StringType>
203 inline bool Dictionary::getStringType(const String& key, StringType& value) const
205 v8::Local<v8::Value> v8Value;
206 if (!getKey(key, v8Value))
209 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, v8Value, false);
214 bool Dictionary::get(const String& key, String& value) const
216 return getStringType(key, value);
219 bool Dictionary::get(const String& key, AtomicString& value) const
221 return getStringType(key, value);
224 bool Dictionary::convert(ConversionContext& context, const String& key, String& value) const
226 ConversionContextScope scope(context);
228 v8::Local<v8::Value> v8Value;
229 if (!getKey(key, v8Value))
232 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, v8Value, false);
237 bool Dictionary::get(const String& key, ScriptValue& value) const
239 v8::Local<v8::Value> v8Value;
240 if (!getKey(key, v8Value))
243 value = ScriptValue(v8Value, m_isolate);
247 bool Dictionary::convert(ConversionContext& context, const String& key, ScriptValue& value) const
249 ConversionContextScope scope(context);
255 bool Dictionary::get(const String& key, unsigned short& value) const
257 v8::Local<v8::Value> v8Value;
258 if (!getKey(key, v8Value))
261 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
262 if (v8Int32.IsEmpty())
264 value = static_cast<unsigned short>(v8Int32->Value());
268 bool Dictionary::get(const String& key, short& value) const
270 v8::Local<v8::Value> v8Value;
271 if (!getKey(key, v8Value))
274 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
275 if (v8Int32.IsEmpty())
277 value = static_cast<short>(v8Int32->Value());
281 bool Dictionary::get(const String& key, unsigned& value) const
283 v8::Local<v8::Value> v8Value;
284 if (!getKey(key, v8Value))
287 v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
288 if (v8Int32.IsEmpty())
290 value = static_cast<unsigned>(v8Int32->Value());
294 bool Dictionary::get(const String& key, unsigned long& value) const
296 v8::Local<v8::Value> v8Value;
297 if (!getKey(key, v8Value))
300 v8::Local<v8::Integer> v8Integer = v8Value->ToInteger();
301 if (v8Integer.IsEmpty())
303 value = static_cast<unsigned long>(v8Integer->Value());
307 bool Dictionary::get(const String& key, unsigned long long& value) const
309 v8::Local<v8::Value> v8Value;
310 if (!getKey(key, v8Value))
313 V8TRYCATCH_RETURN(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
314 if (v8Number.IsEmpty())
316 double d = v8Number->Value();
317 doubleToInteger(d, value);
321 bool Dictionary::get(const String& key, RefPtr<DOMWindow>& value) const
323 v8::Local<v8::Value> v8Value;
324 if (!getKey(key, v8Value))
327 // We need to handle a DOMWindow specially, because a DOMWindow wrapper
328 // exists on a prototype chain of v8Value.
329 value = toNativeDOMWindow(v8Value, m_isolate);
333 bool Dictionary::get(const String& key, RefPtr<Storage>& value) const
335 v8::Local<v8::Value> v8Value;
336 if (!getKey(key, v8Value))
340 if (V8Storage::hasInstance(v8Value, m_isolate))
341 value = V8Storage::toNative(v8::Handle<v8::Object>::Cast(v8Value));
345 bool Dictionary::get(const String& key, MessagePortArray& value) const
347 v8::Local<v8::Value> v8Value;
348 if (!getKey(key, v8Value))
352 ASSERT(m_isolate == v8::Isolate::GetCurrent());
353 return getMessagePortArray(v8Value, key, value, m_isolate);
356 bool Dictionary::convert(ConversionContext& context, const String& key, MessagePortArray& value) const
358 ConversionContextScope scope(context);
360 v8::Local<v8::Value> v8Value;
361 if (!getKey(key, v8Value))
364 return get(key, value);
367 bool Dictionary::get(const String& key, HashSet<AtomicString>& value) const
369 v8::Local<v8::Value> v8Value;
370 if (!getKey(key, v8Value))
373 // FIXME: Support array-like objects
374 if (!v8Value->IsArray())
378 ASSERT(m_isolate == v8::Isolate::GetCurrent());
379 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
380 for (size_t i = 0; i < v8Array->Length(); ++i) {
381 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(m_isolate, i));
382 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, indexedValue, false);
383 value.add(stringValue);
389 bool Dictionary::convert(ConversionContext& context, const String& key, HashSet<AtomicString>& value) const
391 ConversionContextScope scope(context);
393 v8::Local<v8::Value> v8Value;
394 if (!getKey(key, v8Value))
397 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
400 if (!v8Value->IsArray()) {
401 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
405 return get(key, value);
408 bool Dictionary::getWithUndefinedOrNullCheck(const String& key, String& value) const
410 v8::Local<v8::Value> v8Value;
411 if (!getKey(key, v8Value) || WebCore::isUndefinedOrNull(v8Value))
414 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, v8Value, false);
419 bool Dictionary::get(const String& key, RefPtr<Uint8Array>& value) const
421 v8::Local<v8::Value> v8Value;
422 if (!getKey(key, v8Value))
426 if (V8Uint8Array::hasInstance(v8Value, m_isolate))
427 value = V8Uint8Array::toNative(v8::Handle<v8::Object>::Cast(v8Value));
431 bool Dictionary::get(const String& key, RefPtr<ArrayBufferView>& value) const
433 v8::Local<v8::Value> v8Value;
434 if (!getKey(key, v8Value))
438 if (V8ArrayBufferView::hasInstance(v8Value, m_isolate))
439 value = V8ArrayBufferView::toNative(v8::Handle<v8::Object>::Cast(v8Value));
443 bool Dictionary::get(const String& key, RefPtr<MIDIPort>& value) const
445 v8::Local<v8::Value> v8Value;
446 if (!getKey(key, v8Value))
450 if (V8MIDIPort::hasInstance(v8Value, m_isolate))
451 value = V8MIDIPort::toNative(v8::Handle<v8::Object>::Cast(v8Value));
455 bool Dictionary::get(const String& key, RefPtr<MediaKeyError>& value) const
457 v8::Local<v8::Value> v8Value;
458 if (!getKey(key, v8Value))
462 if (V8MediaKeyError::hasInstance(v8Value, m_isolate))
463 value = V8MediaKeyError::toNative(v8::Handle<v8::Object>::Cast(v8Value));
467 bool Dictionary::get(const String& key, RefPtr<TrackBase>& value) const
469 v8::Local<v8::Value> v8Value;
470 if (!getKey(key, v8Value))
473 TrackBase* source = 0;
474 if (v8Value->IsObject()) {
475 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
477 // FIXME: this will need to be changed so it can also return an AudioTrack or a VideoTrack once
479 v8::Handle<v8::Object> track = wrapper->FindInstanceInPrototypeChain(V8TextTrack::domTemplate(m_isolate, worldType(m_isolate)));
480 if (!track.IsEmpty())
481 source = V8TextTrack::toNative(track);
487 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionError>& value) const
489 v8::Local<v8::Value> v8Value;
490 if (!getKey(key, v8Value))
494 if (V8SpeechRecognitionError::hasInstance(v8Value, m_isolate))
495 value = V8SpeechRecognitionError::toNative(v8::Handle<v8::Object>::Cast(v8Value));
499 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionResult>& value) const
501 v8::Local<v8::Value> v8Value;
502 if (!getKey(key, v8Value))
506 if (V8SpeechRecognitionResult::hasInstance(v8Value, m_isolate))
507 value = V8SpeechRecognitionResult::toNative(v8::Handle<v8::Object>::Cast(v8Value));
511 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionResultList>& value) const
513 v8::Local<v8::Value> v8Value;
514 if (!getKey(key, v8Value))
518 if (V8SpeechRecognitionResultList::hasInstance(v8Value, m_isolate))
519 value = V8SpeechRecognitionResultList::toNative(v8::Handle<v8::Object>::Cast(v8Value));
523 bool Dictionary::get(const String& key, RefPtr<MediaStream>& value) const
525 v8::Local<v8::Value> v8Value;
526 if (!getKey(key, v8Value))
530 if (V8MediaStream::hasInstance(v8Value, m_isolate))
531 value = V8MediaStream::toNative(v8::Handle<v8::Object>::Cast(v8Value));
535 bool Dictionary::get(const String& key, RefPtr<EventTarget>& value) const
537 v8::Local<v8::Value> v8Value;
538 if (!getKey(key, v8Value))
542 // We need to handle a DOMWindow specially, because a DOMWindow wrapper
543 // exists on a prototype chain of v8Value.
544 if (v8Value->IsObject()) {
545 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
546 v8::Handle<v8::Object> window = wrapper->FindInstanceInPrototypeChain(V8Window::domTemplate(m_isolate, worldTypeInMainThread(m_isolate)));
547 if (!window.IsEmpty()) {
548 value = toWrapperTypeInfo(window)->toEventTarget(window);
553 if (V8DOMWrapper::isDOMWrapper(v8Value)) {
554 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
555 value = toWrapperTypeInfo(wrapper)->toEventTarget(wrapper);
560 bool Dictionary::get(const String& key, Dictionary& value) const
562 v8::Local<v8::Value> v8Value;
563 if (!getKey(key, v8Value))
566 if (v8Value->IsObject()) {
568 ASSERT(m_isolate == v8::Isolate::GetCurrent());
569 value = Dictionary(v8Value, m_isolate);
575 bool Dictionary::convert(ConversionContext& context, const String& key, Dictionary& value) const
577 ConversionContextScope scope(context);
579 v8::Local<v8::Value> v8Value;
580 if (!getKey(key, v8Value))
583 if (v8Value->IsObject())
584 return get(key, value);
586 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
589 context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "does not have a Dictionary type."));
593 bool Dictionary::get(const String& key, Vector<String>& value) const
595 v8::Local<v8::Value> v8Value;
596 if (!getKey(key, v8Value))
599 if (!v8Value->IsArray())
602 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
603 for (size_t i = 0; i < v8Array->Length(); ++i) {
604 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Uint32::New(m_isolate, i));
605 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, indexedValue, false);
606 value.append(stringValue);
612 bool Dictionary::convert(ConversionContext& context, const String& key, Vector<String>& value) const
614 ConversionContextScope scope(context);
616 v8::Local<v8::Value> v8Value;
617 if (!getKey(key, v8Value))
620 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
623 if (!v8Value->IsArray()) {
624 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
628 return get(key, value);
631 bool Dictionary::get(const String& key, ArrayValue& value) const
633 v8::Local<v8::Value> v8Value;
634 if (!getKey(key, v8Value))
637 if (!v8Value->IsArray())
641 ASSERT(m_isolate == v8::Isolate::GetCurrent());
642 value = ArrayValue(v8::Local<v8::Array>::Cast(v8Value), m_isolate);
646 bool Dictionary::convert(ConversionContext& context, const String& key, ArrayValue& value) const
648 ConversionContextScope scope(context);
650 v8::Local<v8::Value> v8Value;
651 if (!getKey(key, v8Value))
654 if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
657 if (!v8Value->IsArray()) {
658 context.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key));
662 return get(key, value);
665 bool Dictionary::get(const String& key, RefPtr<DOMError>& value) const
667 v8::Local<v8::Value> v8Value;
668 if (!getKey(key, v8Value))
672 if (v8Value->IsObject()) {
673 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
674 v8::Handle<v8::Object> domError = wrapper->FindInstanceInPrototypeChain(V8DOMError::domTemplate(m_isolate, worldType(m_isolate)));
675 if (!domError.IsEmpty())
676 error = V8DOMError::toNative(domError);
682 bool Dictionary::get(const String& key, OwnPtr<VoidCallback>& value) const
684 v8::Local<v8::Value> v8Value;
685 if (!getKey(key, v8Value))
688 if (!v8Value->IsFunction())
691 value = V8VoidCallback::create(v8::Handle<v8::Function>::Cast(v8Value), getExecutionContext());
695 bool Dictionary::getOwnPropertiesAsStringHashMap(HashMap<String, String>& hashMap) const
700 v8::Handle<v8::Object> options = m_options->ToObject();
701 if (options.IsEmpty())
704 v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
705 if (properties.IsEmpty())
707 for (uint32_t i = 0; i < properties->Length(); ++i) {
708 v8::Local<v8::String> key = properties->Get(i)->ToString();
709 if (!options->Has(key))
712 v8::Local<v8::Value> value = options->Get(key);
713 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringKey, key, false);
714 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, value, false);
715 if (!static_cast<const String&>(stringKey).isEmpty())
716 hashMap.set(stringKey, stringValue);
722 bool Dictionary::getOwnPropertyNames(Vector<String>& names) const
727 v8::Handle<v8::Object> options = m_options->ToObject();
728 if (options.IsEmpty())
731 v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
732 if (properties.IsEmpty())
734 for (uint32_t i = 0; i < properties->Length(); ++i) {
735 v8::Local<v8::String> key = properties->Get(i)->ToString();
736 if (!options->Has(key))
738 V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringKey, key, false);
739 names.append(stringKey);
745 void Dictionary::ConversionContext::resetPerPropertyContext()
749 m_isNullable = false;
750 m_propertyTypeName = "";
754 Dictionary::ConversionContext& Dictionary::ConversionContext::setConversionType(const String& typeName, bool isNullable)
758 m_isNullable = isNullable;
759 m_propertyTypeName = typeName;
764 void Dictionary::ConversionContext::throwTypeError(const String& detail)
766 if (forConstructor()) {
767 exceptionState().throwTypeError(detail);
769 ASSERT(!methodName().isEmpty());
770 exceptionState().throwTypeError(ExceptionMessages::failedToExecute(interfaceName(), methodName(), detail));
774 } // namespace WebCore