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