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