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
74namespace blink {
75
76void setArityTypeError(ExceptionState& exceptionState, const char* valid, unsigned provided)
77{
78    exceptionState.throwTypeError(ExceptionMessages::invalidArity(valid, provided));
79}
80
81v8::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
86v8::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
91void setMinimumArityTypeError(ExceptionState& exceptionState, unsigned expected, unsigned provided)
92{
93    exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(expected, provided));
94}
95
96class 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
117v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator()
118{
119    DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ());
120    return &arrayBufferAllocator;
121}
122
123PassRefPtrWillBeRawPtr<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
137const int32_t kMaxInt32 = 0x7fffffff;
138const int32_t kMinInt32 = -kMaxInt32 - 1;
139const uint32_t kMaxUInt32 = 0xffffffff;
140const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, maximum uniquely representable integer in ECMAScript.
141
142static 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
156template <typename T>
157struct IntTypeLimits {
158};
159
160template <>
161struct 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
167template <>
168struct IntTypeLimits<uint8_t> {
169    static const uint8_t maxValue = 255;
170    static const unsigned numberOfValues = 256; // 2^8
171};
172
173template <>
174struct 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
180template <>
181struct IntTypeLimits<uint16_t> {
182    static const unsigned short maxValue = 65535;
183    static const unsigned numberOfValues = 65536; // 2^16
184};
185
186template <typename T>
187static 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
235template <typename T>
236static 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
282int8_t toInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
283{
284    return toSmallerInt<int8_t>(value, configuration, "byte", exceptionState);
285}
286
287int8_t toInt8(v8::Handle<v8::Value> value)
288{
289    NonThrowableExceptionState exceptionState;
290    return toInt8(value, NormalConversion, exceptionState);
291}
292
293uint8_t toUInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
294{
295    return toSmallerUInt<uint8_t>(value, configuration, "octet", exceptionState);
296}
297
298uint8_t toUInt8(v8::Handle<v8::Value> value)
299{
300    NonThrowableExceptionState exceptionState;
301    return toUInt8(value, NormalConversion, exceptionState);
302}
303
304int16_t toInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
305{
306    return toSmallerInt<int16_t>(value, configuration, "short", exceptionState);
307}
308
309int16_t toInt16(v8::Handle<v8::Value> value)
310{
311    NonThrowableExceptionState exceptionState;
312    return toInt16(value, NormalConversion, exceptionState);
313}
314
315uint16_t toUInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
316{
317    return toSmallerUInt<uint16_t>(value, configuration, "unsigned short", exceptionState);
318}
319
320uint16_t toUInt16(v8::Handle<v8::Value> value)
321{
322    NonThrowableExceptionState exceptionState;
323    return toUInt16(value, NormalConversion, exceptionState);
324}
325
326int32_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
359int32_t toInt32(v8::Handle<v8::Value> value)
360{
361    NonThrowableExceptionState exceptionState;
362    return toInt32(value, NormalConversion, exceptionState);
363}
364
365uint32_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
412uint32_t toUInt32(v8::Handle<v8::Value> value)
413{
414    NonThrowableExceptionState exceptionState;
415    return toUInt32(value, NormalConversion, exceptionState);
416}
417
418int64_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
451int64_t toInt64(v8::Handle<v8::Value> value)
452{
453    NonThrowableExceptionState exceptionState;
454    return toInt64(value, NormalConversion, exceptionState);
455}
456
457uint64_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
507uint64_t toUInt64(v8::Handle<v8::Value> value)
508{
509    NonThrowableExceptionState exceptionState;
510    return toUInt64(value, NormalConversion, exceptionState);
511}
512
513float toFloat(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
514{
515    return static_cast<float>(toDouble(value, exceptionState));
516}
517
518double 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
533String 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
566static 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.
594static 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 = n−1, then append to U a U+FFFD REPLACEMENT CHARACTER.
639                u.append(WTF::Unicode::replacementCharacter);
640            } else {
641                // 2. Otherwise, i < n−1:
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
668String 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
689PassRefPtrWillBeRawPtr<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
699LocalDOMWindow* 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
710LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context> context)
711{
712    if (context.IsEmpty())
713        return 0;
714    return toDOMWindow(context->Global(), context->GetIsolate());
715}
716
717LocalDOMWindow* 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
730LocalDOMWindow* currentDOMWindow(v8::Isolate* isolate)
731{
732    return toDOMWindow(isolate->GetCurrentContext());
733}
734
735LocalDOMWindow* 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
747ExecutionContext* 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
762ExecutionContext* currentExecutionContext(v8::Isolate* isolate)
763{
764    return toExecutionContext(isolate->GetCurrentContext());
765}
766
767ExecutionContext* 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
779LocalFrame* 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
790v8::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
803v8::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
814void 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
823v8::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
829void 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
841void 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
856void 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
871v8::Isolate* toIsolate(ExecutionContext* context)
872{
873    if (context && context->isDocument())
874        return V8PerIsolateData::mainThreadIsolate();
875    return v8::Isolate::GetCurrent();
876}
877
878v8::Isolate* toIsolate(LocalFrame* frame)
879{
880    ASSERT(frame);
881    return frame->script().isolate();
882}
883
884PassRefPtr<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
938V8TestingScope::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
946V8TestingScope::~V8TestingScope()
947{
948    m_scriptState->disposePerContextData();
949}
950
951ScriptState* V8TestingScope::scriptState() const
952{
953    return m_scriptState.get();
954}
955
956v8::Isolate* V8TestingScope::isolate() const
957{
958    return m_scriptState->isolate();
959}
960
961void 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
978PassRefPtr<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
987v8::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
995v8::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