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