Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / core / v8 / V8Binding.cpp
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         result %= LimitsTrait::numberOfValues;
201         return static_cast<T>(result > LimitsTrait::maxValue ? result - LimitsTrait::numberOfValues : result);
202     }
203
204     // Can the value be converted to a number?
205     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
206     if (numberObject.IsEmpty()) {
207         exceptionState.throwTypeError("Not convertible to a number value (of type '" + String(typeName) + "'.");
208         return 0;
209     }
210
211     if (configuration == EnforceRange)
212         return enforceRange(numberObject->Value(), LimitsTrait::minValue, LimitsTrait::maxValue, typeName, exceptionState);
213
214     double numberValue = numberObject->Value();
215     if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue)
216         return 0;
217
218     numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue));
219     numberValue = fmod(numberValue, LimitsTrait::numberOfValues);
220
221     return static_cast<T>(numberValue > LimitsTrait::maxValue ? numberValue - LimitsTrait::numberOfValues : numberValue);
222 }
223
224 template <typename T>
225 static inline T toSmallerUInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState)
226 {
227     typedef IntTypeLimits<T> LimitsTrait;
228
229     // Fast case. The value is a 32-bit signed integer - possibly positive?
230     if (value->IsInt32()) {
231         int32_t result = value->Int32Value();
232         if (result >= 0 && result <= LimitsTrait::maxValue)
233             return static_cast<T>(result);
234         if (configuration == EnforceRange) {
235             exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
236             return 0;
237         }
238         return static_cast<T>(result);
239     }
240
241     // Can the value be converted to a number?
242     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
243     if (numberObject.IsEmpty()) {
244         exceptionState.throwTypeError("Not convertible to a number value (of type '" + String(typeName) + "'.");
245         return 0;
246     }
247
248     if (configuration == EnforceRange)
249         return enforceRange(numberObject->Value(), 0, LimitsTrait::maxValue, typeName, exceptionState);
250
251     // Does the value convert to nan or to an infinity?
252     double numberValue = numberObject->Value();
253     if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue)
254         return 0;
255
256     if (configuration == Clamp)
257         return clampTo<T>(numberObject->Value());
258
259     numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue));
260     return static_cast<T>(fmod(numberValue, LimitsTrait::numberOfValues));
261 }
262
263 int8_t toInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
264 {
265     return toSmallerInt<int8_t>(value, configuration, "byte", exceptionState);
266 }
267
268 int8_t toInt8(v8::Handle<v8::Value> value)
269 {
270     NonThrowableExceptionState exceptionState;
271     return toInt8(value, NormalConversion, exceptionState);
272 }
273
274 uint8_t toUInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
275 {
276     return toSmallerUInt<uint8_t>(value, configuration, "octet", exceptionState);
277 }
278
279 uint8_t toUInt8(v8::Handle<v8::Value> value)
280 {
281     NonThrowableExceptionState exceptionState;
282     return toUInt8(value, NormalConversion, exceptionState);
283 }
284
285 int16_t toInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
286 {
287     return toSmallerInt<int16_t>(value, configuration, "short", exceptionState);
288 }
289
290 int16_t toInt16(v8::Handle<v8::Value> value)
291 {
292     NonThrowableExceptionState exceptionState;
293     return toInt16(value, NormalConversion, exceptionState);
294 }
295
296 uint16_t toUInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
297 {
298     return toSmallerUInt<uint16_t>(value, configuration, "unsigned short", exceptionState);
299 }
300
301 uint16_t toUInt16(v8::Handle<v8::Value> value)
302 {
303     NonThrowableExceptionState exceptionState;
304     return toUInt16(value, NormalConversion, exceptionState);
305 }
306
307 int32_t toInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
308 {
309     // Fast case. The value is already a 32-bit integer.
310     if (value->IsInt32())
311         return value->Int32Value();
312
313     // Can the value be converted to a number?
314     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
315     if (numberObject.IsEmpty()) {
316         exceptionState.throwTypeError("Not convertible to a number value (of type 'long'.)");
317         return 0;
318     }
319
320     if (configuration == EnforceRange)
321         return enforceRange(numberObject->Value(), kMinInt32, kMaxInt32, "long", exceptionState);
322
323     // Does the value convert to nan or to an infinity?
324     double numberValue = numberObject->Value();
325     if (std::isnan(numberValue) || std::isinf(numberValue))
326         return 0;
327
328     if (configuration == Clamp)
329         return clampTo<int32_t>(numberObject->Value());
330
331     TONATIVE_DEFAULT_EXCEPTIONSTATE(int32_t, result, numberObject->Int32Value(), exceptionState, 0);
332     return result;
333 }
334
335 int32_t toInt32(v8::Handle<v8::Value> value)
336 {
337     NonThrowableExceptionState exceptionState;
338     return toInt32(value, NormalConversion, exceptionState);
339 }
340
341 uint32_t toUInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
342 {
343     // Fast case. The value is already a 32-bit unsigned integer.
344     if (value->IsUint32())
345         return value->Uint32Value();
346
347     // Fast case. The value is a 32-bit signed integer - possibly positive?
348     if (value->IsInt32()) {
349         int32_t result = value->Int32Value();
350         if (result >= 0)
351             return result;
352         if (configuration == EnforceRange) {
353             exceptionState.throwTypeError("Value is outside the 'unsigned long' value range.");
354             return 0;
355         }
356         return result;
357     }
358
359     // Can the value be converted to a number?
360     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
361     if (numberObject.IsEmpty()) {
362         exceptionState.throwTypeError("Not convertible to a number value (of type 'unsigned long'.)");
363         return 0;
364     }
365
366     if (configuration == EnforceRange)
367         return enforceRange(numberObject->Value(), 0, kMaxUInt32, "unsigned long", exceptionState);
368
369     // Does the value convert to nan or to an infinity?
370     double numberValue = numberObject->Value();
371     if (std::isnan(numberValue) || std::isinf(numberValue))
372         return 0;
373
374     if (configuration == Clamp)
375         return clampTo<uint32_t>(numberObject->Value());
376
377     TONATIVE_DEFAULT(uint32_t, result, numberObject->Uint32Value(), 0);
378     return result;
379 }
380
381 uint32_t toUInt32(v8::Handle<v8::Value> value)
382 {
383     NonThrowableExceptionState exceptionState;
384     return toUInt32(value, NormalConversion, exceptionState);
385 }
386
387 int64_t toInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
388 {
389     // Fast case. The value is a 32-bit integer.
390     if (value->IsInt32())
391         return value->Int32Value();
392
393     // Can the value be converted to a number?
394     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
395     if (numberObject.IsEmpty()) {
396         exceptionState.throwTypeError("Not convertible to a number value (of type 'long long'.)");
397         return 0;
398     }
399
400     double x = numberObject->Value();
401
402     if (configuration == EnforceRange)
403         return enforceRange(x, -kJSMaxInteger, kJSMaxInteger, "long long", exceptionState);
404
405     // Does the value convert to nan or to an infinity?
406     if (std::isnan(x) || std::isinf(x))
407         return 0;
408
409     // NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
410     unsigned long long integer;
411     doubleToInteger(x, integer);
412     return integer;
413 }
414
415 int64_t toInt64(v8::Handle<v8::Value> value)
416 {
417     NonThrowableExceptionState exceptionState;
418     return toInt64(value, NormalConversion, exceptionState);
419 }
420
421 uint64_t toUInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
422 {
423     // Fast case. The value is a 32-bit unsigned integer.
424     if (value->IsUint32())
425         return value->Uint32Value();
426
427     // Fast case. The value is a 32-bit integer.
428     if (value->IsInt32()) {
429         int32_t result = value->Int32Value();
430         if (result >= 0)
431             return result;
432         if (configuration == EnforceRange) {
433             exceptionState.throwTypeError("Value is outside the 'unsigned long long' value range.");
434             return 0;
435         }
436         return result;
437     }
438
439     // Can the value be converted to a number?
440     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
441     if (numberObject.IsEmpty()) {
442         exceptionState.throwTypeError("Not convertible to a number value (of type 'unsigned long long'.)");
443         return 0;
444     }
445
446     double x = numberObject->Value();
447
448     if (configuration == EnforceRange)
449         return enforceRange(x, 0, kJSMaxInteger, "unsigned long long", exceptionState);
450
451     // Does the value convert to nan or to an infinity?
452     if (std::isnan(x) || std::isinf(x))
453         return 0;
454
455     // NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
456     unsigned long long integer;
457     doubleToInteger(x, integer);
458     return integer;
459 }
460
461 uint64_t toUInt64(v8::Handle<v8::Value> value)
462 {
463     NonThrowableExceptionState exceptionState;
464     return toUInt64(value, NormalConversion, exceptionState);
465 }
466
467 float toFloat(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
468 {
469     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
470     return numberObject->NumberValue();
471 }
472
473 String toByteString(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
474 {
475     // Handle null default value.
476     if (value.IsEmpty())
477         return String();
478
479     // From the Web IDL spec: http://heycam.github.io/webidl/#es-ByteString
480     if (value.IsEmpty())
481         return String();
482
483     // 1. Let x be ToString(v)
484     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::String>, stringObject, value->ToString(), exceptionState, String());
485     String x = toCoreString(stringObject);
486
487     // 2. If the value of any element of x is greater than 255, then throw a TypeError.
488     if (!x.containsOnlyLatin1()) {
489         exceptionState.throwTypeError("Value is not a valid ByteString.");
490         return String();
491     }
492
493     // 3. Return an IDL ByteString value whose length is the length of x, and where the
494     // value of each element is the value of the corresponding element of x.
495     // Blink: A ByteString is simply a String with a range constrained per the above, so
496     // this is the identity operation.
497     return x;
498 }
499
500 static bool hasUnmatchedSurrogates(const String& string)
501 {
502     // By definition, 8-bit strings are confined to the Latin-1 code page and
503     // have no surrogates, matched or otherwise.
504     if (string.is8Bit())
505         return false;
506
507     const UChar* characters = string.characters16();
508     const unsigned length = string.length();
509
510     for (unsigned i = 0; i < length; ++i) {
511         UChar c = characters[i];
512         if (U16_IS_SINGLE(c))
513             continue;
514         if (U16_IS_TRAIL(c))
515             return true;
516         ASSERT(U16_IS_LEAD(c));
517         if (i == length - 1)
518             return true;
519         UChar d = characters[i + 1];
520         if (!U16_IS_TRAIL(d))
521             return true;
522         ++i;
523     }
524     return false;
525 }
526
527 // Replace unmatched surrogates with REPLACEMENT CHARACTER U+FFFD.
528 static String replaceUnmatchedSurrogates(const String& string)
529 {
530     // This roughly implements http://heycam.github.io/webidl/#dfn-obtain-unicode
531     // but since Blink strings are 16-bits internally, the output is simply
532     // re-encoded to UTF-16.
533
534     // The concept of surrogate pairs is explained at:
535     // http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G2630
536
537     // Blink-specific optimization to avoid making an unnecessary copy.
538     if (!hasUnmatchedSurrogates(string))
539         return string;
540     ASSERT(!string.is8Bit());
541
542     // 1. Let S be the DOMString value.
543     const UChar* s = string.characters16();
544
545     // 2. Let n be the length of S.
546     const unsigned n = string.length();
547
548     // 3. Initialize i to 0.
549     unsigned i = 0;
550
551     // 4. Initialize U to be an empty sequence of Unicode characters.
552     StringBuilder u;
553     u.reserveCapacity(n);
554
555     // 5. While i < n:
556     while (i < n) {
557         // 1. Let c be the code unit in S at index i.
558         UChar c = s[i];
559         // 2. Depending on the value of c:
560         if (U16_IS_SINGLE(c)) {
561             // c < 0xD800 or c > 0xDFFF
562             // Append to U the Unicode character with code point c.
563             u.append(c);
564         } else if (U16_IS_TRAIL(c)) {
565             // 0xDC00 <= c <= 0xDFFF
566             // Append to U a U+FFFD REPLACEMENT CHARACTER.
567             u.append(WTF::Unicode::replacementCharacter);
568         } else {
569             // 0xD800 <= c <= 0xDBFF
570             ASSERT(U16_IS_LEAD(c));
571             if (i == n - 1) {
572                 // 1. If i = n−1, then append to U a U+FFFD REPLACEMENT CHARACTER.
573                 u.append(WTF::Unicode::replacementCharacter);
574             } else {
575                 // 2. Otherwise, i < n−1:
576                 ASSERT(i < n - 1);
577                 // ....1. Let d be the code unit in S at index i+1.
578                 UChar d = s[i + 1];
579                 if (U16_IS_TRAIL(d)) {
580                     // 2. If 0xDC00 <= d <= 0xDFFF, then:
581                     // ..1. Let a be c & 0x3FF.
582                     // ..2. Let b be d & 0x3FF.
583                     // ..3. Append to U the Unicode character with code point 2^16+2^10*a+b.
584                     u.append(U16_GET_SUPPLEMENTARY(c, d));
585                     // Blink: This is equivalent to u.append(c); u.append(d);
586                     ++i;
587                 } else {
588                     // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a U+FFFD REPLACEMENT CHARACTER.
589                     u.append(WTF::Unicode::replacementCharacter);
590                 }
591             }
592         }
593         // 3. Set i to i+1.
594         ++i;
595     }
596
597     // 6. Return U.
598     ASSERT(u.length() == string.length());
599     return u.toString();
600 }
601
602 String toScalarValueString(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
603 {
604     // From the Encoding standard (with a TODO to move to Web IDL):
605     // http://encoding.spec.whatwg.org/#type-scalarvaluestring
606     if (value.IsEmpty())
607         return String();
608     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::String>, stringObject, value->ToString(), exceptionState, String());
609
610     // ScalarValueString is identical to DOMString except that "convert a
611     // DOMString to a sequence of Unicode characters" is used subsequently
612     // when converting to an IDL value
613     String x = toCoreString(stringObject);
614     return replaceUnmatchedSurrogates(x);
615 }
616
617 PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value> value, v8::Isolate* isolate)
618 {
619     RefPtrWillBeRawPtr<XPathNSResolver> resolver = nullptr;
620     if (V8XPathNSResolver::hasInstance(value, isolate))
621         resolver = V8XPathNSResolver::toNative(v8::Handle<v8::Object>::Cast(value));
622     else if (value->IsObject())
623         resolver = V8CustomXPathNSResolver::create(value->ToObject(), isolate);
624     return resolver;
625 }
626
627 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value> value, v8::Isolate* isolate)
628 {
629     if (value.IsEmpty() || !value->IsObject())
630         return 0;
631
632     v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(v8::Handle<v8::Object>::Cast(value), isolate);
633     if (!windowWrapper.IsEmpty())
634         return V8Window::toNative(windowWrapper);
635     return 0;
636 }
637
638 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context> context)
639 {
640     if (context.IsEmpty())
641         return 0;
642     return toDOMWindow(context->Global(), context->GetIsolate());
643 }
644
645 LocalDOMWindow* enteredDOMWindow(v8::Isolate* isolate)
646 {
647     LocalDOMWindow* window = toDOMWindow(isolate->GetEnteredContext());
648     if (!window) {
649         // We don't always have an entered DOM window, for example during microtask callbacks from V8
650         // (where the entered context may be the DOM-in-JS context). In that case, we fall back
651         // to the current context.
652         window = currentDOMWindow(isolate);
653         ASSERT(window);
654     }
655     return window;
656 }
657
658 LocalDOMWindow* currentDOMWindow(v8::Isolate* isolate)
659 {
660     return toDOMWindow(isolate->GetCurrentContext());
661 }
662
663 LocalDOMWindow* callingDOMWindow(v8::Isolate* isolate)
664 {
665     v8::Handle<v8::Context> context = isolate->GetCallingContext();
666     if (context.IsEmpty()) {
667         // Unfortunately, when processing script from a plug-in, we might not
668         // have a calling context. In those cases, we fall back to the
669         // entered context.
670         context = isolate->GetEnteredContext();
671     }
672     return toDOMWindow(context);
673 }
674
675 ExecutionContext* toExecutionContext(v8::Handle<v8::Context> context)
676 {
677     if (context.IsEmpty())
678         return 0;
679     v8::Handle<v8::Object> global = context->Global();
680     v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(global, context->GetIsolate());
681     if (!windowWrapper.IsEmpty())
682         return V8Window::toNative(windowWrapper)->executionContext();
683     v8::Handle<v8::Object> workerWrapper = V8WorkerGlobalScope::findInstanceInPrototypeChain(global, context->GetIsolate());
684     if (!workerWrapper.IsEmpty())
685         return V8WorkerGlobalScope::toNative(workerWrapper)->executionContext();
686     // FIXME: Is this line of code reachable?
687     return 0;
688 }
689
690 ExecutionContext* currentExecutionContext(v8::Isolate* isolate)
691 {
692     return toExecutionContext(isolate->GetCurrentContext());
693 }
694
695 ExecutionContext* callingExecutionContext(v8::Isolate* isolate)
696 {
697     v8::Handle<v8::Context> context = isolate->GetCallingContext();
698     if (context.IsEmpty()) {
699         // Unfortunately, when processing script from a plug-in, we might not
700         // have a calling context. In those cases, we fall back to the
701         // entered context.
702         context = isolate->GetEnteredContext();
703     }
704     return toExecutionContext(context);
705 }
706
707 LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context> context)
708 {
709     LocalDOMWindow* window = toDOMWindow(context);
710     if (window && window->isCurrentlyDisplayedInFrame())
711         return window->frame();
712     // We return 0 here because |context| is detached from the LocalFrame. If we
713     // did return |frame| we could get in trouble because the frame could be
714     // navigated to another security origin.
715     return 0;
716 }
717
718 v8::Local<v8::Context> toV8Context(ExecutionContext* context, DOMWrapperWorld& world)
719 {
720     ASSERT(context);
721     if (context->isDocument()) {
722         if (LocalFrame* frame = toDocument(context)->frame())
723             return frame->script().windowProxy(world)->context();
724     } else if (context->isWorkerGlobalScope()) {
725         if (WorkerScriptController* script = toWorkerGlobalScope(context)->script())
726             return script->context();
727     }
728     return v8::Local<v8::Context>();
729 }
730
731 v8::Local<v8::Context> toV8Context(LocalFrame* frame, DOMWrapperWorld& world)
732 {
733     if (!frame)
734         return v8::Local<v8::Context>();
735     v8::Local<v8::Context> context = frame->script().windowProxy(world)->context();
736     if (context.IsEmpty())
737         return v8::Local<v8::Context>();
738     LocalFrame* attachedFrame= toFrameIfNotDetached(context);
739     return frame == attachedFrame ? context : v8::Local<v8::Context>();
740 }
741
742 void crashIfV8IsDead()
743 {
744     if (v8::V8::IsDead()) {
745         // FIXME: We temporarily deal with V8 internal error situations
746         // such as out-of-memory by crashing the renderer.
747         CRASH();
748     }
749 }
750
751 v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function> function)
752 {
753     v8::Handle<v8::Value> boundFunction = function->GetBoundFunction();
754     return boundFunction->IsFunction() ? v8::Handle<v8::Function>::Cast(boundFunction) : function;
755 }
756
757 void addHiddenValueToArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate)
758 {
759     v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex);
760     if (arrayValue->IsNull() || arrayValue->IsUndefined()) {
761         arrayValue = v8::Array::New(isolate);
762         object->SetInternalField(arrayIndex, arrayValue);
763     }
764
765     v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue);
766     array->Set(v8::Integer::New(isolate, array->Length()), value);
767 }
768
769 void removeHiddenValueFromArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate)
770 {
771     v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex);
772     if (!arrayValue->IsArray())
773         return;
774     v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue);
775     for (int i = array->Length() - 1; i >= 0; --i) {
776         v8::Local<v8::Value> item = array->Get(v8::Integer::New(isolate, i));
777         if (item->StrictEquals(value)) {
778             array->Delete(i);
779             return;
780         }
781     }
782 }
783
784 void moveEventListenerToNewWrapper(v8::Handle<v8::Object> object, EventListener* oldValue, v8::Local<v8::Value> newValue, int arrayIndex, v8::Isolate* isolate)
785 {
786     if (oldValue) {
787         V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue);
788         if (oldListener) {
789             v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();
790             if (!oldListenerObject.IsEmpty())
791                 removeHiddenValueFromArray(object, oldListenerObject, arrayIndex, isolate);
792         }
793     }
794     // Non-callable input is treated as null and ignored
795     if (newValue->IsFunction())
796         addHiddenValueToArray(object, newValue, arrayIndex, isolate);
797 }
798
799 v8::Isolate* toIsolate(ExecutionContext* context)
800 {
801     if (context && context->isDocument())
802         return V8PerIsolateData::mainThreadIsolate();
803     return v8::Isolate::GetCurrent();
804 }
805
806 v8::Isolate* toIsolate(LocalFrame* frame)
807 {
808     ASSERT(frame);
809     return frame->script().isolate();
810 }
811
812 PassRefPtr<JSONValue> v8ToJSONValue(v8::Isolate* isolate, v8::Handle<v8::Value> value, int maxDepth)
813 {
814     if (value.IsEmpty()) {
815         ASSERT_NOT_REACHED();
816         return nullptr;
817     }
818
819     if (!maxDepth)
820         return nullptr;
821     maxDepth--;
822
823     if (value->IsNull() || value->IsUndefined())
824         return JSONValue::null();
825     if (value->IsBoolean())
826         return JSONBasicValue::create(value->BooleanValue());
827     if (value->IsNumber())
828         return JSONBasicValue::create(value->NumberValue());
829     if (value->IsString())
830         return JSONString::create(toCoreString(value.As<v8::String>()));
831     if (value->IsArray()) {
832         v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
833         RefPtr<JSONArray> inspectorArray = JSONArray::create();
834         uint32_t length = array->Length();
835         for (uint32_t i = 0; i < length; i++) {
836             v8::Local<v8::Value> value = array->Get(v8::Int32::New(isolate, i));
837             RefPtr<JSONValue> element = v8ToJSONValue(isolate, value, maxDepth);
838             if (!element)
839                 return nullptr;
840             inspectorArray->pushValue(element);
841         }
842         return inspectorArray;
843     }
844     if (value->IsObject()) {
845         RefPtr<JSONObject> jsonObject = JSONObject::create();
846         v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
847         v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
848         uint32_t length = propertyNames->Length();
849         for (uint32_t i = 0; i < length; i++) {
850             v8::Local<v8::Value> name = propertyNames->Get(v8::Int32::New(isolate, i));
851             // FIXME(yurys): v8::Object should support GetOwnPropertyNames
852             if (name->IsString() && !object->HasRealNamedProperty(v8::Handle<v8::String>::Cast(name)))
853                 continue;
854             RefPtr<JSONValue> propertyValue = v8ToJSONValue(isolate, object->Get(name), maxDepth);
855             if (!propertyValue)
856                 return nullptr;
857             TOSTRING_DEFAULT(V8StringResource<TreatNullAsNullString>, nameString, name, nullptr);
858             jsonObject->setValue(nameString, propertyValue);
859         }
860         return jsonObject;
861     }
862     ASSERT_NOT_REACHED();
863     return nullptr;
864 }
865
866 V8TestingScope::V8TestingScope(v8::Isolate* isolate)
867     : m_handleScope(isolate)
868     , m_contextScope(v8::Context::New(isolate))
869     , m_scriptState(ScriptStateForTesting::create(isolate->GetCurrentContext(), DOMWrapperWorld::create()))
870 {
871 }
872
873 V8TestingScope::~V8TestingScope()
874 {
875     m_scriptState->disposePerContextData();
876 }
877
878 ScriptState* V8TestingScope::scriptState() const
879 {
880     return m_scriptState.get();
881 }
882
883 v8::Isolate* V8TestingScope::isolate() const
884 {
885     return m_scriptState->isolate();
886 }
887
888 void GetDevToolsFunctionInfo(v8::Handle<v8::Function> function, v8::Isolate* isolate, int& scriptId, String& resourceName, int& lineNumber)
889 {
890     v8::Handle<v8::Function> originalFunction = getBoundFunction(function);
891     scriptId = originalFunction->ScriptId();
892     v8::ScriptOrigin origin = originalFunction->GetScriptOrigin();
893     if (!origin.ResourceName().IsEmpty()) {
894         resourceName = NativeValueTraits<String>::nativeValue(origin.ResourceName(), isolate);
895         lineNumber = originalFunction->GetScriptLineNumber() + 1;
896     }
897     if (resourceName.isEmpty()) {
898         resourceName = "undefined";
899         lineNumber = 1;
900     }
901 }
902
903 PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(ExecutionContext* context, v8::Handle<v8::Function> function, v8::Isolate* isolate)
904 {
905     int scriptId = 0;
906     String resourceName;
907     int lineNumber = 1;
908     GetDevToolsFunctionInfo(function, isolate, scriptId, resourceName, lineNumber);
909     return InspectorFunctionCallEvent::data(context, scriptId, resourceName, lineNumber);
910 }
911
912 } // namespace blink