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