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