1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "bindings/core/v8/V8Binding.h" 33 34 #include "bindings/core/v8/ScriptController.h" 35 #include "bindings/core/v8/V8AbstractEventListener.h" 36 #include "bindings/core/v8/V8BindingMacros.h" 37 #include "bindings/core/v8/V8Element.h" 38 #include "bindings/core/v8/V8NodeFilter.h" 39 #include "bindings/core/v8/V8NodeFilterCondition.h" 40 #include "bindings/core/v8/V8ObjectConstructor.h" 41 #include "bindings/core/v8/V8Window.h" 42 #include "bindings/core/v8/V8WorkerGlobalScope.h" 43 #include "bindings/core/v8/V8XPathNSResolver.h" 44 #include "bindings/core/v8/WindowProxy.h" 45 #include "bindings/core/v8/WorkerScriptController.h" 46 #include "bindings/core/v8/custom/V8CustomXPathNSResolver.h" 47 #include "core/dom/Document.h" 48 #include "core/dom/Element.h" 49 #include "core/dom/NodeFilter.h" 50 #include "core/dom/QualifiedName.h" 51 #include "core/frame/LocalFrame.h" 52 #include "core/frame/Settings.h" 53 #include "core/inspector/BindingVisitors.h" 54 #include "core/inspector/InspectorTraceEvents.h" 55 #include "core/loader/FrameLoader.h" 56 #include "core/loader/FrameLoaderClient.h" 57 #include "core/workers/WorkerGlobalScope.h" 58 #include "core/xml/XPathNSResolver.h" 59 #include "platform/EventTracer.h" 60 #include "platform/JSONValues.h" 61 #include "wtf/ArrayBufferContents.h" 62 #include "wtf/MainThread.h" 63 #include "wtf/MathExtras.h" 64 #include "wtf/StdLibExtras.h" 65 #include "wtf/Threading.h" 66 #include "wtf/text/AtomicString.h" 67 #include "wtf/text/CString.h" 68 #include "wtf/text/StringBuffer.h" 69 #include "wtf/text/StringHash.h" 70 #include "wtf/text/WTFString.h" 71 #include "wtf/unicode/CharacterNames.h" 72 #include "wtf/unicode/Unicode.h" 73 74 namespace blink { 75 76 void setArityTypeError(ExceptionState& exceptionState, const char* valid, unsigned provided) 77 { 78 exceptionState.throwTypeError(ExceptionMessages::invalidArity(valid, provided)); 79 } 80 81 v8::Local<v8::Value> createMinimumArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned provided, v8::Isolate* isolate) 82 { 83 return V8ThrowException::createTypeError(ExceptionMessages::failedToExecute(method, type, ExceptionMessages::notEnoughArguments(expected, provided)), isolate); 84 } 85 86 v8::Local<v8::Value> createMinimumArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned provided, v8::Isolate* isolate) 87 { 88 return V8ThrowException::createTypeError(ExceptionMessages::failedToConstruct(type, ExceptionMessages::notEnoughArguments(expected, provided)), isolate); 89 } 90 91 void setMinimumArityTypeError(ExceptionState& exceptionState, unsigned expected, unsigned provided) 92 { 93 exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(expected, provided)); 94 } 95 96 class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { 97 virtual void* Allocate(size_t size) OVERRIDE 98 { 99 void* data; 100 WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::ZeroInitialize, data); 101 return data; 102 } 103 104 virtual void* AllocateUninitialized(size_t size) OVERRIDE 105 { 106 void* data; 107 WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::DontInitialize, data); 108 return data; 109 } 110 111 virtual void Free(void* data, size_t size) OVERRIDE 112 { 113 WTF::ArrayBufferContents::freeMemory(data, size); 114 } 115 }; 116 117 v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator() 118 { 119 DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ()); 120 return &arrayBufferAllocator; 121 } 122 123 PassRefPtrWillBeRawPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value> callback, v8::Handle<v8::Object> creationContext, ScriptState* scriptState) 124 { 125 if (callback->IsNull()) 126 return nullptr; 127 RefPtrWillBeRawPtr<NodeFilter> filter = NodeFilter::create(); 128 129 v8::Handle<v8::Object> filterWrapper = toV8(filter, creationContext, scriptState->isolate()).As<v8::Object>(); 130 131 RefPtrWillBeRawPtr<NodeFilterCondition> condition = V8NodeFilterCondition::create(callback, filterWrapper, scriptState); 132 filter->setCondition(condition.release()); 133 134 return filter.release(); 135 } 136 137 const int32_t kMaxInt32 = 0x7fffffff; 138 const int32_t kMinInt32 = -kMaxInt32 - 1; 139 const uint32_t kMaxUInt32 = 0xffffffff; 140 const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, maximum uniquely representable integer in ECMAScript. 141 142 static double enforceRange(double x, double minimum, double maximum, const char* typeName, ExceptionState& exceptionState) 143 { 144 if (std::isnan(x) || std::isinf(x)) { 145 exceptionState.throwTypeError("Value is" + String(std::isinf(x) ? " infinite and" : "") + " not of type '" + String(typeName) + "'."); 146 return 0; 147 } 148 x = trunc(x); 149 if (x < minimum || x > maximum) { 150 exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range."); 151 return 0; 152 } 153 return x; 154 } 155 156 template <typename T> 157 struct IntTypeLimits { 158 }; 159 160 template <> 161 struct IntTypeLimits<int8_t> { 162 static const int8_t minValue = -128; 163 static const int8_t maxValue = 127; 164 static const unsigned numberOfValues = 256; // 2^8 165 }; 166 167 template <> 168 struct IntTypeLimits<uint8_t> { 169 static const uint8_t maxValue = 255; 170 static const unsigned numberOfValues = 256; // 2^8 171 }; 172 173 template <> 174 struct IntTypeLimits<int16_t> { 175 static const short minValue = -32768; 176 static const short maxValue = 32767; 177 static const unsigned numberOfValues = 65536; // 2^16 178 }; 179 180 template <> 181 struct IntTypeLimits<uint16_t> { 182 static const unsigned short maxValue = 65535; 183 static const unsigned numberOfValues = 65536; // 2^16 184 }; 185 186 template <typename T> 187 static inline T toSmallerInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState) 188 { 189 typedef IntTypeLimits<T> LimitsTrait; 190 191 // Fast case. The value is already a 32-bit integer in the right range. 192 if (value->IsInt32()) { 193 int32_t result = value->Int32Value(); 194 if (result >= LimitsTrait::minValue && result <= LimitsTrait::maxValue) 195 return static_cast<T>(result); 196 if (configuration == EnforceRange) { 197 exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range."); 198 return 0; 199 } 200 if (configuration == Clamp) 201 return clampTo<T>(result); 202 result %= LimitsTrait::numberOfValues; 203 return static_cast<T>(result > LimitsTrait::maxValue ? result - LimitsTrait::numberOfValues : result); 204 } 205 206 // Can the value be converted to a number? 207 v8::TryCatch block; 208 v8::Local<v8::Number> numberObject(value->ToNumber()); 209 if (block.HasCaught()) { 210 exceptionState.rethrowV8Exception(block.Exception()); 211 return 0; 212 } 213 214 ASSERT(!numberObject.IsEmpty()); 215 216 if (configuration == EnforceRange) 217 return enforceRange(numberObject->Value(), LimitsTrait::minValue, LimitsTrait::maxValue, typeName, exceptionState); 218 219 double numberValue = numberObject->Value(); 220 if (std::isnan(numberValue) || !numberValue) 221 return 0; 222 223 if (configuration == Clamp) 224 return clampTo<T>(numberValue); 225 226 if (std::isinf(numberValue)) 227 return 0; 228 229 numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue)); 230 numberValue = fmod(numberValue, LimitsTrait::numberOfValues); 231 232 return static_cast<T>(numberValue > LimitsTrait::maxValue ? numberValue - LimitsTrait::numberOfValues : numberValue); 233 } 234 235 template <typename T> 236 static inline T toSmallerUInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState) 237 { 238 typedef IntTypeLimits<T> LimitsTrait; 239 240 // Fast case. The value is a 32-bit signed integer - possibly positive? 241 if (value->IsInt32()) { 242 int32_t result = value->Int32Value(); 243 if (result >= 0 && result <= LimitsTrait::maxValue) 244 return static_cast<T>(result); 245 if (configuration == EnforceRange) { 246 exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range."); 247 return 0; 248 } 249 if (configuration == Clamp) 250 return clampTo<T>(result); 251 return static_cast<T>(result); 252 } 253 254 // Can the value be converted to a number? 255 v8::TryCatch block; 256 v8::Local<v8::Number> numberObject(value->ToNumber()); 257 if (block.HasCaught()) { 258 exceptionState.rethrowV8Exception(block.Exception()); 259 return 0; 260 } 261 262 ASSERT(!numberObject.IsEmpty()); 263 264 if (configuration == EnforceRange) 265 return enforceRange(numberObject->Value(), 0, LimitsTrait::maxValue, typeName, exceptionState); 266 267 double numberValue = numberObject->Value(); 268 269 if (std::isnan(numberValue) || !numberValue) 270 return 0; 271 272 if (configuration == Clamp) 273 return clampTo<T>(numberValue); 274 275 if (std::isinf(numberValue)) 276 return 0; 277 278 numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue)); 279 return static_cast<T>(fmod(numberValue, LimitsTrait::numberOfValues)); 280 } 281 282 int8_t toInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 283 { 284 return toSmallerInt<int8_t>(value, configuration, "byte", exceptionState); 285 } 286 287 int8_t toInt8(v8::Handle<v8::Value> value) 288 { 289 NonThrowableExceptionState exceptionState; 290 return toInt8(value, NormalConversion, exceptionState); 291 } 292 293 uint8_t toUInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 294 { 295 return toSmallerUInt<uint8_t>(value, configuration, "octet", exceptionState); 296 } 297 298 uint8_t toUInt8(v8::Handle<v8::Value> value) 299 { 300 NonThrowableExceptionState exceptionState; 301 return toUInt8(value, NormalConversion, exceptionState); 302 } 303 304 int16_t toInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 305 { 306 return toSmallerInt<int16_t>(value, configuration, "short", exceptionState); 307 } 308 309 int16_t toInt16(v8::Handle<v8::Value> value) 310 { 311 NonThrowableExceptionState exceptionState; 312 return toInt16(value, NormalConversion, exceptionState); 313 } 314 315 uint16_t toUInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 316 { 317 return toSmallerUInt<uint16_t>(value, configuration, "unsigned short", exceptionState); 318 } 319 320 uint16_t toUInt16(v8::Handle<v8::Value> value) 321 { 322 NonThrowableExceptionState exceptionState; 323 return toUInt16(value, NormalConversion, exceptionState); 324 } 325 326 int32_t toInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 327 { 328 // Fast case. The value is already a 32-bit integer. 329 if (value->IsInt32()) 330 return value->Int32Value(); 331 332 // Can the value be converted to a number? 333 v8::TryCatch block; 334 v8::Local<v8::Number> numberObject(value->ToNumber()); 335 if (block.HasCaught()) { 336 exceptionState.rethrowV8Exception(block.Exception()); 337 return 0; 338 } 339 340 ASSERT(!numberObject.IsEmpty()); 341 342 if (configuration == EnforceRange) 343 return enforceRange(numberObject->Value(), kMinInt32, kMaxInt32, "long", exceptionState); 344 345 double numberValue = numberObject->Value(); 346 347 if (std::isnan(numberValue)) 348 return 0; 349 350 if (configuration == Clamp) 351 return clampTo<int32_t>(numberValue); 352 353 if (std::isinf(numberValue)) 354 return 0; 355 356 return numberObject->Int32Value(); 357 } 358 359 int32_t toInt32(v8::Handle<v8::Value> value) 360 { 361 NonThrowableExceptionState exceptionState; 362 return toInt32(value, NormalConversion, exceptionState); 363 } 364 365 uint32_t toUInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 366 { 367 // Fast case. The value is already a 32-bit unsigned integer. 368 if (value->IsUint32()) 369 return value->Uint32Value(); 370 371 // Fast case. The value is a 32-bit signed integer - possibly positive? 372 if (value->IsInt32()) { 373 int32_t result = value->Int32Value(); 374 if (result >= 0) 375 return result; 376 if (configuration == EnforceRange) { 377 exceptionState.throwTypeError("Value is outside the 'unsigned long' value range."); 378 return 0; 379 } 380 if (configuration == Clamp) 381 return clampTo<uint32_t>(result); 382 return result; 383 } 384 385 // Can the value be converted to a number? 386 v8::TryCatch block; 387 v8::Local<v8::Number> numberObject(value->ToNumber()); 388 if (block.HasCaught()) { 389 exceptionState.rethrowV8Exception(block.Exception()); 390 return 0; 391 } 392 393 ASSERT(!numberObject.IsEmpty()); 394 395 if (configuration == EnforceRange) 396 return enforceRange(numberObject->Value(), 0, kMaxUInt32, "unsigned long", exceptionState); 397 398 double numberValue = numberObject->Value(); 399 400 if (std::isnan(numberValue)) 401 return 0; 402 403 if (configuration == Clamp) 404 return clampTo<uint32_t>(numberValue); 405 406 if (std::isinf(numberValue)) 407 return 0; 408 409 return numberObject->Uint32Value(); 410 } 411 412 uint32_t toUInt32(v8::Handle<v8::Value> value) 413 { 414 NonThrowableExceptionState exceptionState; 415 return toUInt32(value, NormalConversion, exceptionState); 416 } 417 418 int64_t toInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 419 { 420 // Clamping not supported for int64_t/long long int. See Source/wtf/MathExtras.h. 421 ASSERT(configuration != Clamp); 422 423 // Fast case. The value is a 32-bit integer. 424 if (value->IsInt32()) 425 return value->Int32Value(); 426 427 // Can the value be converted to a number? 428 v8::TryCatch block; 429 v8::Local<v8::Number> numberObject(value->ToNumber()); 430 if (block.HasCaught()) { 431 exceptionState.rethrowV8Exception(block.Exception()); 432 return 0; 433 } 434 435 ASSERT(!numberObject.IsEmpty()); 436 437 double numberValue = numberObject->Value(); 438 439 if (configuration == EnforceRange) 440 return enforceRange(numberValue, -kJSMaxInteger, kJSMaxInteger, "long long", exceptionState); 441 442 if (std::isnan(numberValue) || std::isinf(numberValue)) 443 return 0; 444 445 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64. 446 unsigned long long integer; 447 doubleToInteger(numberValue, integer); 448 return integer; 449 } 450 451 int64_t toInt64(v8::Handle<v8::Value> value) 452 { 453 NonThrowableExceptionState exceptionState; 454 return toInt64(value, NormalConversion, exceptionState); 455 } 456 457 uint64_t toUInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState) 458 { 459 // Fast case. The value is a 32-bit unsigned integer. 460 if (value->IsUint32()) 461 return value->Uint32Value(); 462 463 // Fast case. The value is a 32-bit integer. 464 if (value->IsInt32()) { 465 int32_t result = value->Int32Value(); 466 if (result >= 0) 467 return result; 468 if (configuration == EnforceRange) { 469 exceptionState.throwTypeError("Value is outside the 'unsigned long long' value range."); 470 return 0; 471 } 472 if (configuration == Clamp) 473 return clampTo<uint64_t>(result); 474 return result; 475 } 476 477 // Can the value be converted to a number? 478 v8::TryCatch block; 479 v8::Local<v8::Number> numberObject(value->ToNumber()); 480 if (block.HasCaught()) { 481 exceptionState.rethrowV8Exception(block.Exception()); 482 return 0; 483 } 484 485 ASSERT(!numberObject.IsEmpty()); 486 487 double numberValue = numberObject->Value(); 488 489 if (configuration == EnforceRange) 490 return enforceRange(numberValue, 0, kJSMaxInteger, "unsigned long long", exceptionState); 491 492 if (std::isnan(numberValue)) 493 return 0; 494 495 if (configuration == Clamp) 496 return clampTo<uint64_t>(numberValue); 497 498 if (std::isinf(numberValue)) 499 return 0; 500 501 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64. 502 unsigned long long integer; 503 doubleToInteger(numberValue, integer); 504 return integer; 505 } 506 507 uint64_t toUInt64(v8::Handle<v8::Value> value) 508 { 509 NonThrowableExceptionState exceptionState; 510 return toUInt64(value, NormalConversion, exceptionState); 511 } 512 513 float toFloat(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 514 { 515 return static_cast<float>(toDouble(value, exceptionState)); 516 } 517 518 double toDouble(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 519 { 520 if (value->IsNumber()) 521 return value->NumberValue(); 522 523 v8::TryCatch block; 524 v8::Local<v8::Number> numberObject(value->ToNumber()); 525 if (block.HasCaught()) { 526 exceptionState.rethrowV8Exception(block.Exception()); 527 return 0; 528 } 529 530 return numberObject->NumberValue(); 531 } 532 533 String toByteString(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 534 { 535 // Handle null default value. 536 if (value.IsEmpty()) 537 return String(); 538 539 // From the Web IDL spec: http://heycam.github.io/webidl/#es-ByteString 540 if (value.IsEmpty()) 541 return String(); 542 543 // 1. Let x be ToString(v) 544 v8::TryCatch block; 545 v8::Local<v8::String> stringObject(value->ToString()); 546 if (block.HasCaught()) { 547 exceptionState.rethrowV8Exception(block.Exception()); 548 return String(); 549 } 550 551 String x = toCoreString(stringObject); 552 553 // 2. If the value of any element of x is greater than 255, then throw a TypeError. 554 if (!x.containsOnlyLatin1()) { 555 exceptionState.throwTypeError("Value is not a valid ByteString."); 556 return String(); 557 } 558 559 // 3. Return an IDL ByteString value whose length is the length of x, and where the 560 // value of each element is the value of the corresponding element of x. 561 // Blink: A ByteString is simply a String with a range constrained per the above, so 562 // this is the identity operation. 563 return x; 564 } 565 566 static bool hasUnmatchedSurrogates(const String& string) 567 { 568 // By definition, 8-bit strings are confined to the Latin-1 code page and 569 // have no surrogates, matched or otherwise. 570 if (string.is8Bit()) 571 return false; 572 573 const UChar* characters = string.characters16(); 574 const unsigned length = string.length(); 575 576 for (unsigned i = 0; i < length; ++i) { 577 UChar c = characters[i]; 578 if (U16_IS_SINGLE(c)) 579 continue; 580 if (U16_IS_TRAIL(c)) 581 return true; 582 ASSERT(U16_IS_LEAD(c)); 583 if (i == length - 1) 584 return true; 585 UChar d = characters[i + 1]; 586 if (!U16_IS_TRAIL(d)) 587 return true; 588 ++i; 589 } 590 return false; 591 } 592 593 // Replace unmatched surrogates with REPLACEMENT CHARACTER U+FFFD. 594 static String replaceUnmatchedSurrogates(const String& string) 595 { 596 // This roughly implements http://heycam.github.io/webidl/#dfn-obtain-unicode 597 // but since Blink strings are 16-bits internally, the output is simply 598 // re-encoded to UTF-16. 599 600 // The concept of surrogate pairs is explained at: 601 // http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G2630 602 603 // Blink-specific optimization to avoid making an unnecessary copy. 604 if (!hasUnmatchedSurrogates(string)) 605 return string; 606 ASSERT(!string.is8Bit()); 607 608 // 1. Let S be the DOMString value. 609 const UChar* s = string.characters16(); 610 611 // 2. Let n be the length of S. 612 const unsigned n = string.length(); 613 614 // 3. Initialize i to 0. 615 unsigned i = 0; 616 617 // 4. Initialize U to be an empty sequence of Unicode characters. 618 StringBuilder u; 619 u.reserveCapacity(n); 620 621 // 5. While i < n: 622 while (i < n) { 623 // 1. Let c be the code unit in S at index i. 624 UChar c = s[i]; 625 // 2. Depending on the value of c: 626 if (U16_IS_SINGLE(c)) { 627 // c < 0xD800 or c > 0xDFFF 628 // Append to U the Unicode character with code point c. 629 u.append(c); 630 } else if (U16_IS_TRAIL(c)) { 631 // 0xDC00 <= c <= 0xDFFF 632 // Append to U a U+FFFD REPLACEMENT CHARACTER. 633 u.append(WTF::Unicode::replacementCharacter); 634 } else { 635 // 0xD800 <= c <= 0xDBFF 636 ASSERT(U16_IS_LEAD(c)); 637 if (i == n - 1) { 638 // 1. If i = n1, then append to U a U+FFFD REPLACEMENT CHARACTER. 639 u.append(WTF::Unicode::replacementCharacter); 640 } else { 641 // 2. Otherwise, i < n1: 642 ASSERT(i < n - 1); 643 // ....1. Let d be the code unit in S at index i+1. 644 UChar d = s[i + 1]; 645 if (U16_IS_TRAIL(d)) { 646 // 2. If 0xDC00 <= d <= 0xDFFF, then: 647 // ..1. Let a be c & 0x3FF. 648 // ..2. Let b be d & 0x3FF. 649 // ..3. Append to U the Unicode character with code point 2^16+2^10*a+b. 650 u.append(U16_GET_SUPPLEMENTARY(c, d)); 651 // Blink: This is equivalent to u.append(c); u.append(d); 652 ++i; 653 } else { 654 // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a U+FFFD REPLACEMENT CHARACTER. 655 u.append(WTF::Unicode::replacementCharacter); 656 } 657 } 658 } 659 // 3. Set i to i+1. 660 ++i; 661 } 662 663 // 6. Return U. 664 ASSERT(u.length() == string.length()); 665 return u.toString(); 666 } 667 668 String toScalarValueString(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 669 { 670 // From the Encoding standard (with a TODO to move to Web IDL): 671 // http://encoding.spec.whatwg.org/#type-scalarvaluestring 672 if (value.IsEmpty()) 673 return String(); 674 675 v8::TryCatch block; 676 v8::Local<v8::String> stringObject(value->ToString()); 677 if (block.HasCaught()) { 678 exceptionState.rethrowV8Exception(block.Exception()); 679 return String(); 680 } 681 682 // ScalarValueString is identical to DOMString except that "convert a 683 // DOMString to a sequence of Unicode characters" is used subsequently 684 // when converting to an IDL value 685 String x = toCoreString(stringObject); 686 return replaceUnmatchedSurrogates(x); 687 } 688 689 PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value> value, v8::Isolate* isolate) 690 { 691 RefPtrWillBeRawPtr<XPathNSResolver> resolver = nullptr; 692 if (V8XPathNSResolver::hasInstance(value, isolate)) 693 resolver = V8XPathNSResolver::toImpl(v8::Handle<v8::Object>::Cast(value)); 694 else if (value->IsObject()) 695 resolver = V8CustomXPathNSResolver::create(value->ToObject(), isolate); 696 return resolver; 697 } 698 699 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value> value, v8::Isolate* isolate) 700 { 701 if (value.IsEmpty() || !value->IsObject()) 702 return 0; 703 704 v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(v8::Handle<v8::Object>::Cast(value), isolate); 705 if (!windowWrapper.IsEmpty()) 706 return V8Window::toImpl(windowWrapper); 707 return 0; 708 } 709 710 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context> context) 711 { 712 if (context.IsEmpty()) 713 return 0; 714 return toDOMWindow(context->Global(), context->GetIsolate()); 715 } 716 717 LocalDOMWindow* enteredDOMWindow(v8::Isolate* isolate) 718 { 719 LocalDOMWindow* window = toDOMWindow(isolate->GetEnteredContext()); 720 if (!window) { 721 // We don't always have an entered DOM window, for example during microtask callbacks from V8 722 // (where the entered context may be the DOM-in-JS context). In that case, we fall back 723 // to the current context. 724 window = currentDOMWindow(isolate); 725 ASSERT(window); 726 } 727 return window; 728 } 729 730 LocalDOMWindow* currentDOMWindow(v8::Isolate* isolate) 731 { 732 return toDOMWindow(isolate->GetCurrentContext()); 733 } 734 735 LocalDOMWindow* callingDOMWindow(v8::Isolate* isolate) 736 { 737 v8::Handle<v8::Context> context = isolate->GetCallingContext(); 738 if (context.IsEmpty()) { 739 // Unfortunately, when processing script from a plug-in, we might not 740 // have a calling context. In those cases, we fall back to the 741 // entered context. 742 context = isolate->GetEnteredContext(); 743 } 744 return toDOMWindow(context); 745 } 746 747 ExecutionContext* toExecutionContext(v8::Handle<v8::Context> context) 748 { 749 if (context.IsEmpty()) 750 return 0; 751 v8::Handle<v8::Object> global = context->Global(); 752 v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(global, context->GetIsolate()); 753 if (!windowWrapper.IsEmpty()) 754 return V8Window::toImpl(windowWrapper)->executionContext(); 755 v8::Handle<v8::Object> workerWrapper = V8WorkerGlobalScope::findInstanceInPrototypeChain(global, context->GetIsolate()); 756 if (!workerWrapper.IsEmpty()) 757 return V8WorkerGlobalScope::toImpl(workerWrapper)->executionContext(); 758 // FIXME: Is this line of code reachable? 759 return 0; 760 } 761 762 ExecutionContext* currentExecutionContext(v8::Isolate* isolate) 763 { 764 return toExecutionContext(isolate->GetCurrentContext()); 765 } 766 767 ExecutionContext* callingExecutionContext(v8::Isolate* isolate) 768 { 769 v8::Handle<v8::Context> context = isolate->GetCallingContext(); 770 if (context.IsEmpty()) { 771 // Unfortunately, when processing script from a plug-in, we might not 772 // have a calling context. In those cases, we fall back to the 773 // entered context. 774 context = isolate->GetEnteredContext(); 775 } 776 return toExecutionContext(context); 777 } 778 779 LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context> context) 780 { 781 LocalDOMWindow* window = toDOMWindow(context); 782 if (window && window->isCurrentlyDisplayedInFrame()) 783 return window->frame(); 784 // We return 0 here because |context| is detached from the LocalFrame. If we 785 // did return |frame| we could get in trouble because the frame could be 786 // navigated to another security origin. 787 return 0; 788 } 789 790 v8::Local<v8::Context> toV8Context(ExecutionContext* context, DOMWrapperWorld& world) 791 { 792 ASSERT(context); 793 if (context->isDocument()) { 794 if (LocalFrame* frame = toDocument(context)->frame()) 795 return frame->script().windowProxy(world)->context(); 796 } else if (context->isWorkerGlobalScope()) { 797 if (WorkerScriptController* script = toWorkerGlobalScope(context)->script()) 798 return script->context(); 799 } 800 return v8::Local<v8::Context>(); 801 } 802 803 v8::Local<v8::Context> toV8Context(LocalFrame* frame, DOMWrapperWorld& world) 804 { 805 if (!frame) 806 return v8::Local<v8::Context>(); 807 v8::Local<v8::Context> context = frame->script().windowProxy(world)->context(); 808 if (context.IsEmpty()) 809 return v8::Local<v8::Context>(); 810 LocalFrame* attachedFrame = toFrameIfNotDetached(context); 811 return frame == attachedFrame ? context : v8::Local<v8::Context>(); 812 } 813 814 void crashIfV8IsDead() 815 { 816 if (v8::V8::IsDead()) { 817 // FIXME: We temporarily deal with V8 internal error situations 818 // such as out-of-memory by crashing the renderer. 819 CRASH(); 820 } 821 } 822 823 v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function> function) 824 { 825 v8::Handle<v8::Value> boundFunction = function->GetBoundFunction(); 826 return boundFunction->IsFunction() ? v8::Handle<v8::Function>::Cast(boundFunction) : function; 827 } 828 829 void addHiddenValueToArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate) 830 { 831 v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex); 832 if (arrayValue->IsNull() || arrayValue->IsUndefined()) { 833 arrayValue = v8::Array::New(isolate); 834 object->SetInternalField(arrayIndex, arrayValue); 835 } 836 837 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue); 838 array->Set(v8::Integer::New(isolate, array->Length()), value); 839 } 840 841 void removeHiddenValueFromArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate) 842 { 843 v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex); 844 if (!arrayValue->IsArray()) 845 return; 846 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue); 847 for (int i = array->Length() - 1; i >= 0; --i) { 848 v8::Local<v8::Value> item = array->Get(v8::Integer::New(isolate, i)); 849 if (item->StrictEquals(value)) { 850 array->Delete(i); 851 return; 852 } 853 } 854 } 855 856 void moveEventListenerToNewWrapper(v8::Handle<v8::Object> object, EventListener* oldValue, v8::Local<v8::Value> newValue, int arrayIndex, v8::Isolate* isolate) 857 { 858 if (oldValue) { 859 V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue); 860 if (oldListener) { 861 v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject(); 862 if (!oldListenerObject.IsEmpty()) 863 removeHiddenValueFromArray(object, oldListenerObject, arrayIndex, isolate); 864 } 865 } 866 // Non-callable input is treated as null and ignored 867 if (newValue->IsFunction()) 868 addHiddenValueToArray(object, newValue, arrayIndex, isolate); 869 } 870 871 v8::Isolate* toIsolate(ExecutionContext* context) 872 { 873 if (context && context->isDocument()) 874 return V8PerIsolateData::mainThreadIsolate(); 875 return v8::Isolate::GetCurrent(); 876 } 877 878 v8::Isolate* toIsolate(LocalFrame* frame) 879 { 880 ASSERT(frame); 881 return frame->script().isolate(); 882 } 883 884 PassRefPtr<JSONValue> v8ToJSONValue(v8::Isolate* isolate, v8::Handle<v8::Value> value, int maxDepth) 885 { 886 if (value.IsEmpty()) { 887 ASSERT_NOT_REACHED(); 888 return nullptr; 889 } 890 891 if (!maxDepth) 892 return nullptr; 893 maxDepth--; 894 895 if (value->IsNull() || value->IsUndefined()) 896 return JSONValue::null(); 897 if (value->IsBoolean()) 898 return JSONBasicValue::create(value->BooleanValue()); 899 if (value->IsNumber()) 900 return JSONBasicValue::create(value->NumberValue()); 901 if (value->IsString()) 902 return JSONString::create(toCoreString(value.As<v8::String>())); 903 if (value->IsArray()) { 904 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); 905 RefPtr<JSONArray> inspectorArray = JSONArray::create(); 906 uint32_t length = array->Length(); 907 for (uint32_t i = 0; i < length; i++) { 908 v8::Local<v8::Value> value = array->Get(v8::Int32::New(isolate, i)); 909 RefPtr<JSONValue> element = v8ToJSONValue(isolate, value, maxDepth); 910 if (!element) 911 return nullptr; 912 inspectorArray->pushValue(element); 913 } 914 return inspectorArray; 915 } 916 if (value->IsObject()) { 917 RefPtr<JSONObject> jsonObject = JSONObject::create(); 918 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 919 v8::Local<v8::Array> propertyNames = object->GetPropertyNames(); 920 uint32_t length = propertyNames->Length(); 921 for (uint32_t i = 0; i < length; i++) { 922 v8::Local<v8::Value> name = propertyNames->Get(v8::Int32::New(isolate, i)); 923 // FIXME(yurys): v8::Object should support GetOwnPropertyNames 924 if (name->IsString() && !object->HasRealNamedProperty(v8::Handle<v8::String>::Cast(name))) 925 continue; 926 RefPtr<JSONValue> propertyValue = v8ToJSONValue(isolate, object->Get(name), maxDepth); 927 if (!propertyValue) 928 return nullptr; 929 TOSTRING_DEFAULT(V8StringResource<TreatNullAsNullString>, nameString, name, nullptr); 930 jsonObject->setValue(nameString, propertyValue); 931 } 932 return jsonObject; 933 } 934 ASSERT_NOT_REACHED(); 935 return nullptr; 936 } 937 938 V8TestingScope::V8TestingScope(v8::Isolate* isolate) 939 : m_handleScope(isolate) 940 , m_contextScope(v8::Context::New(isolate)) 941 // We reuse the main world since the main world is guaranteed to be registered to ScriptController. 942 , m_scriptState(ScriptStateForTesting::create(isolate->GetCurrentContext(), &DOMWrapperWorld::mainWorld())) 943 { 944 } 945 946 V8TestingScope::~V8TestingScope() 947 { 948 m_scriptState->disposePerContextData(); 949 } 950 951 ScriptState* V8TestingScope::scriptState() const 952 { 953 return m_scriptState.get(); 954 } 955 956 v8::Isolate* V8TestingScope::isolate() const 957 { 958 return m_scriptState->isolate(); 959 } 960 961 void GetDevToolsFunctionInfo(v8::Handle<v8::Function> function, v8::Isolate* isolate, int& scriptId, String& resourceName, int& lineNumber) 962 { 963 v8::Handle<v8::Function> originalFunction = getBoundFunction(function); 964 scriptId = originalFunction->ScriptId(); 965 v8::ScriptOrigin origin = originalFunction->GetScriptOrigin(); 966 if (!origin.ResourceName().IsEmpty()) { 967 V8StringResource<> stringResource(origin.ResourceName()); 968 stringResource.prepare(); 969 resourceName = stringResource; 970 lineNumber = originalFunction->GetScriptLineNumber() + 1; 971 } 972 if (resourceName.isEmpty()) { 973 resourceName = "undefined"; 974 lineNumber = 1; 975 } 976 } 977 978 PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(ExecutionContext* context, v8::Handle<v8::Function> function, v8::Isolate* isolate) 979 { 980 int scriptId = 0; 981 String resourceName; 982 int lineNumber = 1; 983 GetDevToolsFunctionInfo(function, isolate, scriptId, resourceName, lineNumber); 984 return InspectorFunctionCallEvent::data(context, scriptId, resourceName, lineNumber); 985 } 986 987 v8::Local<v8::Value> v8DoneIteratorResult(v8::Isolate* isolate) 988 { 989 v8::Local<v8::Object> result = v8::Object::New(isolate); 990 result->Set(v8String(isolate, "value"), v8::Undefined(isolate)); 991 result->Set(v8String(isolate, "done"), v8Boolean(true, isolate)); 992 return result; 993 } 994 995 v8::Local<v8::Value> v8IteratorResult(v8::Isolate* isolate, v8::Handle<v8::Value> value) 996 { 997 v8::Local<v8::Object> result = v8::Object::New(isolate); 998 result->Set(v8String(isolate, "value"), value); 999 result->Set(v8String(isolate, "done"), v8Boolean(false, isolate)); 1000 return result; 1001 } 1002 1003 } // namespace blink 1004