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