7936b8721a5f3b1b0a318217cbb2fee4036c099d
[WebKit-https.git] / Source / WebCore / bindings / v8 / Dictionary.cpp
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 "Dictionary.h"
28
29 #include "ArrayValue.h"
30 #include "DOMStringList.h"
31 #include "V8Binding.h"
32 #include "V8DOMWindow.h"
33 #include "V8Storage.h"
34 #include "V8Uint8Array.h"
35 #include "V8Utilities.h"
36 #include <wtf/MathExtras.h>
37
38 #if ENABLE(INDEXED_DATABASE)
39 #include "IDBKeyRange.h"
40 #include "V8IDBKeyRange.h"
41 #endif
42
43 #if ENABLE(ENCRYPTED_MEDIA)
44 #include "V8MediaKeyError.h"
45 #endif
46
47 #if ENABLE(VIDEO_TRACK)
48 #include "TrackBase.h"
49 #include "V8TextTrack.h"
50 #endif
51
52 #if ENABLE(SCRIPTED_SPEECH)
53 #include "SpeechRecognitionError.h"
54 #include "SpeechRecognitionResult.h"
55 #include "SpeechRecognitionResultList.h"
56 #include "V8SpeechRecognitionError.h"
57 #include "V8SpeechRecognitionResult.h"
58 #include "V8SpeechRecognitionResultList.h"
59 #endif
60
61 #if ENABLE(MEDIA_STREAM)
62 #include "MediaStream.h"
63 #include "V8MediaStream.h"
64 #endif
65
66 namespace WebCore {
67
68 Dictionary::Dictionary()
69     : m_isolate(0)
70 {
71 }
72
73 Dictionary::Dictionary(const v8::Local<v8::Value>& options, v8::Isolate* isolate)
74     : m_options(options)
75     , m_isolate(isolate)
76 {
77     ASSERT(m_isolate);
78 }
79
80 Dictionary::~Dictionary()
81 {
82 }
83
84 Dictionary& Dictionary::operator=(const Dictionary& optionsObject)
85 {
86     m_options = optionsObject.m_options;
87     m_isolate = optionsObject.m_isolate;
88     return *this;
89 }
90
91 bool Dictionary::isObject() const
92 {
93     return !isUndefinedOrNull() && m_options->IsObject();
94 }
95
96 bool Dictionary::isUndefinedOrNull() const
97 {
98     if (m_options.IsEmpty())
99         return true;
100     return WebCore::isUndefinedOrNull(m_options);
101 }
102
103 bool Dictionary::getKey(const String& key, v8::Local<v8::Value>& value) const
104 {
105     if (isUndefinedOrNull())
106         return false;
107     v8::Local<v8::Object> options = m_options->ToObject();
108     ASSERT(!options.IsEmpty());
109
110     ASSERT(m_isolate);
111     ASSERT(m_isolate == v8::Isolate::GetCurrent());
112     v8::Handle<v8::String> v8Key = v8String(key, m_isolate);
113     if (!options->Has(v8Key))
114         return false;
115     value = options->Get(v8Key);
116     if (value.IsEmpty())
117         return false;
118     return true;
119 }
120
121 bool Dictionary::get(const String& key, bool& value) const
122 {
123     v8::Local<v8::Value> v8Value;
124     if (!getKey(key, v8Value))
125         return false;
126
127     v8::Local<v8::Boolean> v8Bool = v8Value->ToBoolean();
128     if (v8Bool.IsEmpty())
129         return false;
130     value = v8Bool->Value();
131     return true;
132 }
133
134 bool Dictionary::get(const String& key, int32_t& value) const
135 {
136     v8::Local<v8::Value> v8Value;
137     if (!getKey(key, v8Value))
138         return false;
139
140     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
141     if (v8Int32.IsEmpty())
142         return false;
143     value = v8Int32->Value();
144     return true;
145 }
146
147 bool Dictionary::get(const String& key, double& value) const
148 {
149     v8::Local<v8::Value> v8Value;
150     if (!getKey(key, v8Value))
151         return false;
152
153     v8::Local<v8::Number> v8Number = v8Value->ToNumber();
154     if (v8Number.IsEmpty())
155         return false;
156     value = v8Number->Value();
157     return true;
158 }
159
160 bool Dictionary::get(const String& key, String& value) const
161 {
162     v8::Local<v8::Value> v8Value;
163     if (!getKey(key, v8Value))
164         return false;
165
166     // FIXME: It is possible for this to throw in which case we'd be getting back
167     //        an empty string and returning true when we should be returning false.
168     //        See fast/dom/Geolocation/script-tests/argument-types.js for a similar
169     //        example.
170     value = toWebCoreString(v8Value);
171     return true;
172 }
173
174 bool Dictionary::get(const String& key, ScriptValue& value) const
175 {
176     v8::Local<v8::Value> v8Value;
177     if (!getKey(key, v8Value))
178         return false;
179
180     value = ScriptValue(v8Value);
181     return true;
182 }
183
184 bool Dictionary::get(const String& key, unsigned short& value) const
185 {
186     v8::Local<v8::Value> v8Value;
187     if (!getKey(key, v8Value))
188         return false;
189
190     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
191     if (v8Int32.IsEmpty())
192         return false;
193     value = static_cast<unsigned short>(v8Int32->Value());
194     return true;
195 }
196
197 bool Dictionary::get(const String& key, short& value) const
198 {
199     v8::Local<v8::Value> v8Value;
200     if (!getKey(key, v8Value))
201         return false;
202
203     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
204     if (v8Int32.IsEmpty())
205         return false;
206     value = static_cast<short>(v8Int32->Value());
207     return true;
208 }
209
210 bool Dictionary::get(const String& key, unsigned& value) const
211 {
212     v8::Local<v8::Value> v8Value;
213     if (!getKey(key, v8Value))
214         return false;
215
216     v8::Local<v8::Int32> v8Int32 = v8Value->ToInt32();
217     if (v8Int32.IsEmpty())
218         return false;
219     value = static_cast<unsigned>(v8Int32->Value());
220     return true;
221 }
222
223 bool Dictionary::get(const String& key, unsigned long& value) const
224 {
225     v8::Local<v8::Value> v8Value;
226     if (!getKey(key, v8Value))
227         return false;
228
229     v8::Local<v8::Integer> v8Integer = v8Value->ToInteger();
230     if (v8Integer.IsEmpty())
231         return false;
232     value = static_cast<unsigned long>(v8Integer->Value());
233     return true;
234 }
235
236 bool Dictionary::get(const String& key, unsigned long long& value) const
237 {
238     v8::Local<v8::Value> v8Value;
239     if (!getKey(key, v8Value))
240         return false;
241
242     v8::Local<v8::Number> v8Number = v8Value->ToNumber();
243     if (v8Number.IsEmpty())
244         return false;
245     double d = v8Number->Value();
246     doubleToInteger(d, value);
247     return true;
248 }
249
250 bool Dictionary::get(const String& key, RefPtr<DOMWindow>& value) const
251 {
252     v8::Local<v8::Value> v8Value;
253     if (!getKey(key, v8Value))
254         return false;
255
256     DOMWindow* source = 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(V8DOMWindow::GetTemplate());
260         if (!window.IsEmpty())
261             source = V8DOMWindow::toNative(window);
262     }
263     value = source;
264     return true;
265 }
266
267 bool Dictionary::get(const String& key, RefPtr<Storage>& value) const
268 {
269     v8::Local<v8::Value> v8Value;
270     if (!getKey(key, v8Value))
271         return false;
272
273     Storage* source = 0;
274     if (v8Value->IsObject()) {
275         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
276         v8::Handle<v8::Object> storage = wrapper->FindInstanceInPrototypeChain(V8Storage::GetTemplate());
277         if (!storage.IsEmpty())
278             source = V8Storage::toNative(storage);
279     }
280     value = source;
281     return true;
282 }
283
284 bool Dictionary::get(const String& key, MessagePortArray& value) const
285 {
286     v8::Local<v8::Value> v8Value;
287     if (!getKey(key, v8Value))
288         return false;
289
290     ASSERT(m_isolate);
291     ASSERT(m_isolate == v8::Isolate::GetCurrent());
292     return getMessagePortArray(v8Value, value, m_isolate);
293 }
294
295 bool Dictionary::get(const String& key, HashSet<AtomicString>& value) const
296 {
297     v8::Local<v8::Value> v8Value;
298     if (!getKey(key, v8Value))
299         return false;
300
301     // FIXME: Support array-like objects
302     if (!v8Value->IsArray())
303         return false;
304
305     ASSERT(m_isolate);
306     ASSERT(m_isolate == v8::Isolate::GetCurrent());
307     v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
308     for (size_t i = 0; i < v8Array->Length(); ++i) {
309         v8::Local<v8::Value> indexedValue = v8Array->Get(v8Integer(i, m_isolate));
310         value.add(toWebCoreString(indexedValue));
311     }
312
313     return true;
314 }
315
316 bool Dictionary::getWithUndefinedOrNullCheck(const String& key, String& value) const
317 {
318     v8::Local<v8::Value> v8Value;
319     if (!getKey(key, v8Value) || v8Value->IsNull() || v8Value->IsUndefined())
320         return false;
321
322     // FIXME: It is possible for this to throw in which case we'd be getting back
323     //        an empty string and returning true when we should be returning false.
324     //        See fast/dom/Geolocation/script-tests/argument-types.js for a similar
325     //        example.
326     value = WebCore::isUndefinedOrNull(v8Value) ? String() : toWebCoreString(v8Value);
327     return true;
328 }
329
330 bool Dictionary::get(const String& key, RefPtr<Uint8Array>& value) const
331 {
332     v8::Local<v8::Value> v8Value;
333     if (!getKey(key, v8Value))
334         return false;
335
336     Uint8Array* source = 0;
337     if (v8Value->IsObject()) {
338         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
339         v8::Handle<v8::Object> array = wrapper->FindInstanceInPrototypeChain(V8Uint8Array::GetTemplate());
340         if (!array.IsEmpty())
341             source = V8Uint8Array::toNative(array);
342     }
343     value = source;
344     return true;
345 }
346
347 #if ENABLE(ENCRYPTED_MEDIA)
348 bool Dictionary::get(const String& key, RefPtr<MediaKeyError>& value) const
349 {
350     v8::Local<v8::Value> v8Value;
351     if (!getKey(key, v8Value))
352         return false;
353
354     MediaKeyError* source = 0;
355     if (v8Value->IsObject()) {
356         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
357         v8::Handle<v8::Object> error = wrapper->FindInstanceInPrototypeChain(V8MediaKeyError::GetTemplate());
358         if (!error.IsEmpty())
359             source = V8MediaKeyError::toNative(error);
360     }
361     value = source;
362     return true;
363 }
364 #endif
365
366 #if ENABLE(VIDEO_TRACK)
367 bool Dictionary::get(const String& key, RefPtr<TrackBase>& value) const
368 {
369     v8::Local<v8::Value> v8Value;
370     if (!getKey(key, v8Value))
371         return false;
372
373     TrackBase* source = 0;
374     if (v8Value->IsObject()) {
375         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
376
377         // FIXME: this will need to be changed so it can also return an AudioTrack or a VideoTrack once
378         // we add them.
379         v8::Handle<v8::Object> track = wrapper->FindInstanceInPrototypeChain(V8TextTrack::GetTemplate());
380         if (!track.IsEmpty())
381             source = V8TextTrack::toNative(track);
382     }
383     value = source;
384     return true;
385 }
386 #endif
387
388 #if ENABLE(SCRIPTED_SPEECH)
389 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionError>& value) const
390 {
391     v8::Local<v8::Value> v8Value;
392     if (!getKey(key, v8Value))
393         return false;
394
395     SpeechRecognitionError* source = 0;
396     if (v8Value->IsObject()) {
397         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
398         v8::Handle<v8::Object> speechRecognitionError = wrapper->FindInstanceInPrototypeChain(V8SpeechRecognitionError::GetTemplate());
399         if (!speechRecognitionError.IsEmpty())
400             source = V8SpeechRecognitionError::toNative(speechRecognitionError);
401     }
402     value = source;
403     return true;
404 }
405
406 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionResult>& value) const
407 {
408     v8::Local<v8::Value> v8Value;
409     if (!getKey(key, v8Value))
410         return false;
411
412     SpeechRecognitionResult* source = 0;
413     if (v8Value->IsObject()) {
414         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
415         v8::Handle<v8::Object> speechRecognitionResult = wrapper->FindInstanceInPrototypeChain(V8SpeechRecognitionResult::GetTemplate());
416         if (!speechRecognitionResult.IsEmpty())
417             source = V8SpeechRecognitionResult::toNative(speechRecognitionResult);
418     }
419     value = source;
420     return true;
421 }
422
423 bool Dictionary::get(const String& key, RefPtr<SpeechRecognitionResultList>& value) const
424 {
425     v8::Local<v8::Value> v8Value;
426     if (!getKey(key, v8Value))
427         return false;
428
429     SpeechRecognitionResultList* source = 0;
430     if (v8Value->IsObject()) {
431         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
432         v8::Handle<v8::Object> speechRecognitionResultList = wrapper->FindInstanceInPrototypeChain(V8SpeechRecognitionResultList::GetTemplate());
433         if (!speechRecognitionResultList.IsEmpty())
434             source = V8SpeechRecognitionResultList::toNative(speechRecognitionResultList);
435     }
436     value = source;
437     return true;
438 }
439
440 #endif
441
442 #if ENABLE(MEDIA_STREAM)
443 bool Dictionary::get(const String& key, RefPtr<MediaStream>& value) const
444 {
445     v8::Local<v8::Value> v8Value;
446     if (!getKey(key, v8Value))
447         return false;
448
449     MediaStream* stream = 0;
450     if (v8Value->IsObject()) {
451         v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value);
452         v8::Handle<v8::Object> error = wrapper->FindInstanceInPrototypeChain(V8MediaStream::GetTemplate());
453         if (!error.IsEmpty())
454             stream = V8MediaStream::toNative(error);
455     }
456     value = stream;
457     return true;
458 }
459 #endif
460
461 bool Dictionary::get(const String& key, Dictionary& value) const
462 {
463     v8::Local<v8::Value> v8Value;
464     if (!getKey(key, v8Value))
465         return false;
466
467     if (v8Value->IsObject()) {
468         ASSERT(m_isolate);
469         ASSERT(m_isolate == v8::Isolate::GetCurrent());
470         value = Dictionary(v8Value, m_isolate);
471     }
472
473     return true;
474 }
475
476 bool Dictionary::get(const String& key, Vector<String>& value) const
477 {
478     v8::Local<v8::Value> v8Value;
479     if (!getKey(key, v8Value))
480         return false;
481
482     if (!v8Value->IsArray())
483         return false;
484
485     v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
486     for (size_t i = 0; i < v8Array->Length(); ++i) {
487         v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Uint32::New(i));
488         value.append(toWebCoreString(indexedValue));
489     }
490
491     return true;
492 }
493
494 bool Dictionary::get(const String& key, ArrayValue& value) const
495 {
496     v8::Local<v8::Value> v8Value;
497     if (!getKey(key, v8Value))
498         return false;
499
500     if (!v8Value->IsArray())
501         return false;
502
503     ASSERT(m_isolate);
504     ASSERT(m_isolate == v8::Isolate::GetCurrent());
505     value = ArrayValue(v8::Local<v8::Array>::Cast(v8Value), m_isolate);
506     return true;
507 }
508
509 bool Dictionary::getOwnPropertiesAsStringHashMap(HashMap<String, String>& hashMap) const
510 {
511     if (!isObject())
512         return false;
513
514     v8::Handle<v8::Object> options = m_options->ToObject();
515     if (options.IsEmpty())
516         return false;
517
518     v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
519     if (properties.IsEmpty())
520         return true;
521     for (uint32_t i = 0; i < properties->Length(); ++i) {
522         v8::Local<v8::String> key = properties->Get(i)->ToString();
523         if (!options->Has(key))
524             continue;
525
526         v8::Local<v8::Value> value = options->Get(key);
527         String stringKey = toWebCoreString(key);
528         String stringValue = toWebCoreString(value);
529         if (!stringKey.isEmpty())
530             hashMap.set(stringKey, stringValue);
531     }
532
533     return true;
534 }
535
536 bool Dictionary::getOwnPropertyNames(Vector<String>& names) const
537 {
538     if (!isObject())
539         return false;
540
541     v8::Handle<v8::Object> options = m_options->ToObject();
542     if (options.IsEmpty())
543         return false;
544
545     v8::Local<v8::Array> properties = options->GetOwnPropertyNames();
546     if (properties.IsEmpty())
547         return true;
548     for (uint32_t i = 0; i < properties->Length(); ++i) {
549         v8::Local<v8::String> key = properties->Get(i)->ToString();
550         if (!options->Has(key))
551             continue;
552         names.append(toWebCoreString(key));
553     }
554
555     return true;
556 }
557
558 } // namespace WebCore