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