Home | History | Annotate | Download | only in v8
      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