Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp

Issue 2834053003: Split V8Binding (Closed)
Patch Set: Rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 12 matching lines...) Expand all
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "bindings/core/v8/V8Binding.h" 31 #include "bindings/core/v8/V8Binding.h"
32 32
33 #include "bindings/core/v8/ScriptController.h"
34 #include "bindings/core/v8/V8AbstractEventListener.h"
35 #include "bindings/core/v8/V8ArrayBufferView.h"
36 #include "bindings/core/v8/V8BindingMacros.h" 33 #include "bindings/core/v8/V8BindingMacros.h"
37 #include "bindings/core/v8/V8Element.h"
38 #include "bindings/core/v8/V8EventTarget.h"
39 #include "bindings/core/v8/V8HTMLLinkElement.h"
40 #include "bindings/core/v8/V8NodeFilter.h"
41 #include "bindings/core/v8/V8NodeFilterCondition.h"
42 #include "bindings/core/v8/V8ObjectConstructor.h"
43 #include "bindings/core/v8/V8Window.h"
44 #include "bindings/core/v8/V8WorkerGlobalScope.h"
45 #include "bindings/core/v8/V8WorkletGlobalScope.h"
46 #include "bindings/core/v8/V8XPathNSResolver.h"
47 #include "bindings/core/v8/WindowProxy.h"
48 #include "bindings/core/v8/WorkerOrWorkletScriptController.h"
49 #include "bindings/core/v8/custom/V8CustomXPathNSResolver.h"
50 #include "core/dom/Document.h"
51 #include "core/dom/Element.h"
52 #include "core/dom/FlexibleArrayBufferView.h"
53 #include "core/dom/NodeFilter.h"
54 #include "core/dom/QualifiedName.h"
55 #include "core/frame/LocalDOMWindow.h"
56 #include "core/frame/LocalFrame.h"
57 #include "core/frame/LocalFrameClient.h"
58 #include "core/frame/Settings.h"
59 #include "core/inspector/InspectorTraceEvents.h"
60 #include "core/loader/FrameLoader.h"
61 #include "core/workers/WorkerGlobalScope.h"
62 #include "core/workers/WorkletGlobalScope.h"
63 #include "core/xml/XPathNSResolver.h"
64 #include "platform/instrumentation/tracing/TracedValue.h"
65 #include "platform/wtf/MathExtras.h"
66 #include "platform/wtf/StdLibExtras.h"
67 #include "platform/wtf/Threading.h"
68 #include "platform/wtf/text/AtomicString.h"
69 #include "platform/wtf/text/CString.h"
70 #include "platform/wtf/text/CharacterNames.h"
71 #include "platform/wtf/text/StringBuffer.h"
72 #include "platform/wtf/text/StringHash.h"
73 #include "platform/wtf/text/Unicode.h"
74 #include "platform/wtf/text/WTFString.h"
75 34
76 namespace blink { 35 namespace blink {
77 36
78 NodeFilter* ToNodeFilter(v8::Local<v8::Value> callback,
79 v8::Local<v8::Object> creation_context,
80 ScriptState* script_state) {
81 if (callback->IsNull())
82 return nullptr;
83 NodeFilter* filter = NodeFilter::Create();
84
85 v8::Local<v8::Value> filter_wrapper =
86 ToV8(filter, creation_context, script_state->GetIsolate());
87 if (filter_wrapper.IsEmpty())
88 return nullptr;
89
90 NodeFilterCondition* condition = V8NodeFilterCondition::Create(
91 callback, filter_wrapper.As<v8::Object>(), script_state);
92 filter->SetCondition(condition);
93
94 return filter;
95 }
96
97 bool ToBooleanSlow(v8::Isolate* isolate,
98 v8::Local<v8::Value> value,
99 ExceptionState& exception_state) {
100 DCHECK(!value->IsBoolean());
101 v8::TryCatch block(isolate);
102 bool result = false;
103 if (!V8Call(value->BooleanValue(isolate->GetCurrentContext()), result, block))
104 exception_state.RethrowV8Exception(block.Exception());
105 return result;
106 }
107
108 const int32_t kMaxInt32 = 0x7fffffff;
109 const int32_t kMinInt32 = -kMaxInt32 - 1;
110 const uint32_t kMaxUInt32 = 0xffffffff;
111 const int64_t kJSMaxInteger =
112 0x20000000000000LL -
113 1; // 2^53 - 1, maximum uniquely representable integer in ECMAScript.
114
115 static double EnforceRange(double x,
116 double minimum,
117 double maximum,
118 const char* type_name,
119 ExceptionState& exception_state) {
120 if (std::isnan(x) || std::isinf(x)) {
121 exception_state.ThrowTypeError(
122 "Value is" + String(std::isinf(x) ? " infinite and" : "") +
123 " not of type '" + String(type_name) + "'.");
124 return 0;
125 }
126 x = trunc(x);
127 if (x < minimum || x > maximum) {
128 exception_state.ThrowTypeError("Value is outside the '" +
129 String(type_name) + "' value range.");
130 return 0;
131 }
132 return x;
133 }
134
135 template <typename T>
136 struct IntTypeLimits {};
137
138 template <>
139 struct IntTypeLimits<int8_t> {
140 static const int8_t kMinValue = -128;
141 static const int8_t kMaxValue = 127;
142 static const unsigned kNumberOfValues = 256; // 2^8
143 };
144
145 template <>
146 struct IntTypeLimits<uint8_t> {
147 static const uint8_t kMaxValue = 255;
148 static const unsigned kNumberOfValues = 256; // 2^8
149 };
150
151 template <>
152 struct IntTypeLimits<int16_t> {
153 static const short kMinValue = -32768;
154 static const short kMaxValue = 32767;
155 static const unsigned kNumberOfValues = 65536; // 2^16
156 };
157
158 template <>
159 struct IntTypeLimits<uint16_t> {
160 static const unsigned short kMaxValue = 65535;
161 static const unsigned kNumberOfValues = 65536; // 2^16
162 };
163
164 template <typename T>
165 static inline T ToSmallerInt(v8::Isolate* isolate,
166 v8::Local<v8::Value> value,
167 IntegerConversionConfiguration configuration,
168 const char* type_name,
169 ExceptionState& exception_state) {
170 typedef IntTypeLimits<T> LimitsTrait;
171
172 // Fast case. The value is already a 32-bit integer in the right range.
173 if (value->IsInt32()) {
174 int32_t result = value.As<v8::Int32>()->Value();
175 if (result >= LimitsTrait::kMinValue && result <= LimitsTrait::kMaxValue)
176 return static_cast<T>(result);
177 if (configuration == kEnforceRange) {
178 exception_state.ThrowTypeError("Value is outside the '" +
179 String(type_name) + "' value range.");
180 return 0;
181 }
182 if (configuration == kClamp)
183 return clampTo<T>(result);
184 result %= LimitsTrait::kNumberOfValues;
185 return static_cast<T>(result > LimitsTrait::kMaxValue
186 ? result - LimitsTrait::kNumberOfValues
187 : result);
188 }
189
190 v8::Local<v8::Number> number_object;
191 if (value->IsNumber()) {
192 number_object = value.As<v8::Number>();
193 } else {
194 // Can the value be converted to a number?
195 v8::TryCatch block(isolate);
196 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object,
197 block)) {
198 exception_state.RethrowV8Exception(block.Exception());
199 return 0;
200 }
201 }
202 DCHECK(!number_object.IsEmpty());
203
204 if (configuration == kEnforceRange)
205 return EnforceRange(number_object->Value(), LimitsTrait::kMinValue,
206 LimitsTrait::kMaxValue, type_name, exception_state);
207
208 double number_value = number_object->Value();
209 if (std::isnan(number_value) || !number_value)
210 return 0;
211
212 if (configuration == kClamp)
213 return clampTo<T>(number_value);
214
215 if (std::isinf(number_value))
216 return 0;
217
218 number_value =
219 number_value < 0 ? -floor(fabs(number_value)) : floor(fabs(number_value));
220 number_value = fmod(number_value, LimitsTrait::kNumberOfValues);
221
222 return static_cast<T>(number_value > LimitsTrait::kMaxValue
223 ? number_value - LimitsTrait::kNumberOfValues
224 : number_value);
225 }
226
227 template <typename T>
228 static inline T ToSmallerUInt(v8::Isolate* isolate,
229 v8::Local<v8::Value> value,
230 IntegerConversionConfiguration configuration,
231 const char* type_name,
232 ExceptionState& exception_state) {
233 typedef IntTypeLimits<T> LimitsTrait;
234
235 // Fast case. The value is a 32-bit signed integer - possibly positive?
236 if (value->IsInt32()) {
237 int32_t result = value.As<v8::Int32>()->Value();
238 if (result >= 0 && result <= LimitsTrait::kMaxValue)
239 return static_cast<T>(result);
240 if (configuration == kEnforceRange) {
241 exception_state.ThrowTypeError("Value is outside the '" +
242 String(type_name) + "' value range.");
243 return 0;
244 }
245 if (configuration == kClamp)
246 return clampTo<T>(result);
247 return static_cast<T>(result);
248 }
249
250 v8::Local<v8::Number> number_object;
251 if (value->IsNumber()) {
252 number_object = value.As<v8::Number>();
253 } else {
254 // Can the value be converted to a number?
255 v8::TryCatch block(isolate);
256 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object,
257 block)) {
258 exception_state.RethrowV8Exception(block.Exception());
259 return 0;
260 }
261 }
262 DCHECK(!number_object.IsEmpty());
263
264 if (configuration == kEnforceRange)
265 return EnforceRange(number_object->Value(), 0, LimitsTrait::kMaxValue,
266 type_name, exception_state);
267
268 double number_value = number_object->Value();
269
270 if (std::isnan(number_value) || !number_value)
271 return 0;
272
273 if (configuration == kClamp)
274 return clampTo<T>(number_value);
275
276 if (std::isinf(number_value))
277 return 0;
278
279 number_value =
280 number_value < 0 ? -floor(fabs(number_value)) : floor(fabs(number_value));
281 return static_cast<T>(fmod(number_value, LimitsTrait::kNumberOfValues));
282 }
283
284 int8_t ToInt8(v8::Isolate* isolate,
285 v8::Local<v8::Value> value,
286 IntegerConversionConfiguration configuration,
287 ExceptionState& exception_state) {
288 return ToSmallerInt<int8_t>(isolate, value, configuration, "byte",
289 exception_state);
290 }
291
292 uint8_t ToUInt8(v8::Isolate* isolate,
293 v8::Local<v8::Value> value,
294 IntegerConversionConfiguration configuration,
295 ExceptionState& exception_state) {
296 return ToSmallerUInt<uint8_t>(isolate, value, configuration, "octet",
297 exception_state);
298 }
299
300 int16_t ToInt16(v8::Isolate* isolate,
301 v8::Local<v8::Value> value,
302 IntegerConversionConfiguration configuration,
303 ExceptionState& exception_state) {
304 return ToSmallerInt<int16_t>(isolate, value, configuration, "short",
305 exception_state);
306 }
307
308 uint16_t ToUInt16(v8::Isolate* isolate,
309 v8::Local<v8::Value> value,
310 IntegerConversionConfiguration configuration,
311 ExceptionState& exception_state) {
312 return ToSmallerUInt<uint16_t>(isolate, value, configuration,
313 "unsigned short", exception_state);
314 }
315
316 int32_t ToInt32Slow(v8::Isolate* isolate,
317 v8::Local<v8::Value> value,
318 IntegerConversionConfiguration configuration,
319 ExceptionState& exception_state) {
320 DCHECK(!value->IsInt32());
321 // Can the value be converted to a number?
322 v8::TryCatch block(isolate);
323 v8::Local<v8::Number> number_object;
324 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object,
325 block)) {
326 exception_state.RethrowV8Exception(block.Exception());
327 return 0;
328 }
329
330 DCHECK(!number_object.IsEmpty());
331
332 double number_value = number_object->Value();
333 if (configuration == kEnforceRange)
334 return EnforceRange(number_value, kMinInt32, kMaxInt32, "long",
335 exception_state);
336
337 if (std::isnan(number_value))
338 return 0;
339
340 if (configuration == kClamp)
341 return clampTo<int32_t>(number_value);
342
343 if (std::isinf(number_value))
344 return 0;
345
346 int32_t result;
347 if (!V8Call(number_object->Int32Value(isolate->GetCurrentContext()), result,
348 block)) {
349 exception_state.RethrowV8Exception(block.Exception());
350 return 0;
351 }
352 return result;
353 }
354
355 uint32_t ToUInt32Slow(v8::Isolate* isolate,
356 v8::Local<v8::Value> value,
357 IntegerConversionConfiguration configuration,
358 ExceptionState& exception_state) {
359 DCHECK(!value->IsUint32());
360 if (value->IsInt32()) {
361 DCHECK_NE(configuration, kNormalConversion);
362 int32_t result = value.As<v8::Int32>()->Value();
363 if (result >= 0)
364 return result;
365 if (configuration == kEnforceRange) {
366 exception_state.ThrowTypeError(
367 "Value is outside the 'unsigned long' value range.");
368 return 0;
369 }
370 DCHECK_EQ(configuration, kClamp);
371 return clampTo<uint32_t>(result);
372 }
373
374 // Can the value be converted to a number?
375 v8::TryCatch block(isolate);
376 v8::Local<v8::Number> number_object;
377 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object,
378 block)) {
379 exception_state.RethrowV8Exception(block.Exception());
380 return 0;
381 }
382 DCHECK(!number_object.IsEmpty());
383
384 if (configuration == kEnforceRange)
385 return EnforceRange(number_object->Value(), 0, kMaxUInt32, "unsigned long",
386 exception_state);
387
388 double number_value = number_object->Value();
389
390 if (std::isnan(number_value))
391 return 0;
392
393 if (configuration == kClamp)
394 return clampTo<uint32_t>(number_value);
395
396 if (std::isinf(number_value))
397 return 0;
398
399 uint32_t result;
400 if (!V8Call(number_object->Uint32Value(isolate->GetCurrentContext()), result,
401 block)) {
402 exception_state.RethrowV8Exception(block.Exception());
403 return 0;
404 }
405 return result;
406 }
407
408 int64_t ToInt64Slow(v8::Isolate* isolate,
409 v8::Local<v8::Value> value,
410 IntegerConversionConfiguration configuration,
411 ExceptionState& exception_state) {
412 DCHECK(!value->IsInt32());
413
414 v8::Local<v8::Number> number_object;
415 // Can the value be converted to a number?
416 v8::TryCatch block(isolate);
417 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object,
418 block)) {
419 exception_state.RethrowV8Exception(block.Exception());
420 return 0;
421 }
422 DCHECK(!number_object.IsEmpty());
423
424 double number_value = number_object->Value();
425
426 if (configuration == kEnforceRange)
427 return EnforceRange(number_value, -kJSMaxInteger, kJSMaxInteger,
428 "long long", exception_state);
429
430 if (std::isnan(number_value) || std::isinf(number_value))
431 return 0;
432
433 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
434 unsigned long long integer;
435 doubleToInteger(number_value, integer);
436 return integer;
437 }
438
439 uint64_t ToUInt64Slow(v8::Isolate* isolate,
440 v8::Local<v8::Value> value,
441 IntegerConversionConfiguration configuration,
442 ExceptionState& exception_state) {
443 DCHECK(!value->IsUint32());
444 if (value->IsInt32()) {
445 ASSERT(configuration != kNormalConversion);
446 int32_t result = value.As<v8::Int32>()->Value();
447 if (result >= 0)
448 return result;
449 if (configuration == kEnforceRange) {
450 exception_state.ThrowTypeError(
451 "Value is outside the 'unsigned long long' value range.");
452 return 0;
453 }
454 DCHECK_EQ(configuration, kClamp);
455 return clampTo<uint64_t>(result);
456 }
457
458 v8::Local<v8::Number> number_object;
459 // Can the value be converted to a number?
460 v8::TryCatch block(isolate);
461 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object,
462 block)) {
463 exception_state.RethrowV8Exception(block.Exception());
464 return 0;
465 }
466 DCHECK(!number_object.IsEmpty());
467
468 double number_value = number_object->Value();
469
470 if (configuration == kEnforceRange)
471 return EnforceRange(number_value, 0, kJSMaxInteger, "unsigned long long",
472 exception_state);
473
474 if (std::isnan(number_value))
475 return 0;
476
477 if (configuration == kClamp)
478 return clampTo<uint64_t>(number_value);
479
480 if (std::isinf(number_value))
481 return 0;
482
483 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
484 unsigned long long integer;
485 doubleToInteger(number_value, integer);
486 return integer;
487 }
488
489 float ToRestrictedFloat(v8::Isolate* isolate,
490 v8::Local<v8::Value> value,
491 ExceptionState& exception_state) {
492 float number_value = ToFloat(isolate, value, exception_state);
493 if (exception_state.HadException())
494 return 0;
495 if (!std::isfinite(number_value)) {
496 exception_state.ThrowTypeError("The provided float value is non-finite.");
497 return 0;
498 }
499 return number_value;
500 }
501
502 double ToDoubleSlow(v8::Isolate* isolate,
503 v8::Local<v8::Value> value,
504 ExceptionState& exception_state) {
505 DCHECK(!value->IsNumber());
506 v8::TryCatch block(isolate);
507 v8::Local<v8::Number> number_value;
508 if (!value->ToNumber(isolate->GetCurrentContext()).ToLocal(&number_value)) {
509 exception_state.RethrowV8Exception(block.Exception());
510 return 0;
511 }
512 return number_value->Value();
513 }
514
515 double ToRestrictedDouble(v8::Isolate* isolate,
516 v8::Local<v8::Value> value,
517 ExceptionState& exception_state) {
518 double number_value = ToDouble(isolate, value, exception_state);
519 if (exception_state.HadException())
520 return 0;
521 if (!std::isfinite(number_value)) {
522 exception_state.ThrowTypeError("The provided double value is non-finite.");
523 return 0;
524 }
525 return number_value;
526 }
527
528 String ToByteString(v8::Isolate* isolate,
529 v8::Local<v8::Value> value,
530 ExceptionState& exception_state) {
531 // Handle null default value.
532 if (value.IsEmpty())
533 return String();
534
535 // From the Web IDL spec: http://heycam.github.io/webidl/#es-ByteString
536 if (value.IsEmpty())
537 return String();
538
539 // 1. Let x be ToString(v)
540 v8::Local<v8::String> string_object;
541 if (value->IsString()) {
542 string_object = value.As<v8::String>();
543 } else {
544 v8::TryCatch block(isolate);
545 if (!V8Call(value->ToString(isolate->GetCurrentContext()), string_object,
546 block)) {
547 exception_state.RethrowV8Exception(block.Exception());
548 return String();
549 }
550 }
551
552 String x = ToCoreString(string_object);
553
554 // 2. If the value of any element of x is greater than 255, then throw a
555 // TypeError.
556 if (!x.ContainsOnlyLatin1()) {
557 exception_state.ThrowTypeError("Value is not a valid ByteString.");
558 return String();
559 }
560
561 // 3. Return an IDL ByteString value whose length is the length of x, and
562 // where the value of each element is the value of the corresponding
563 // element of x.
564 // Blink: A ByteString is simply a String with a range constrained per the
565 // above, so this is the identity operation.
566 return x;
567 }
568
569 static bool HasUnmatchedSurrogates(const String& string) {
570 // By definition, 8-bit strings are confined to the Latin-1 code page and
571 // have no surrogates, matched or otherwise.
572 if (string.Is8Bit())
573 return false;
574
575 const UChar* characters = string.Characters16();
576 const unsigned length = string.length();
577
578 for (unsigned i = 0; i < length; ++i) {
579 UChar c = characters[i];
580 if (U16_IS_SINGLE(c))
581 continue;
582 if (U16_IS_TRAIL(c))
583 return true;
584 ASSERT(U16_IS_LEAD(c));
585 if (i == length - 1)
586 return true;
587 UChar d = characters[i + 1];
588 if (!U16_IS_TRAIL(d))
589 return true;
590 ++i;
591 }
592 return false;
593 }
594
595 // Replace unmatched surrogates with REPLACEMENT CHARACTER U+FFFD.
596 static String ReplaceUnmatchedSurrogates(const String& string) {
597 // This roughly implements http://heycam.github.io/webidl/#dfn-obtain-unicode
598 // but since Blink strings are 16-bits internally, the output is simply
599 // re-encoded to UTF-16.
600
601 // The concept of surrogate pairs is explained at:
602 // http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G2630
603
604 // Blink-specific optimization to avoid making an unnecessary copy.
605 if (!HasUnmatchedSurrogates(string))
606 return string;
607 DCHECK(!string.Is8Bit());
608
609 // 1. Let S be the DOMString value.
610 const UChar* s = string.Characters16();
611
612 // 2. Let n be the length of S.
613 const unsigned n = string.length();
614
615 // 3. Initialize i to 0.
616 unsigned i = 0;
617
618 // 4. Initialize U to be an empty sequence of Unicode characters.
619 StringBuilder u;
620 u.ReserveCapacity(n);
621
622 // 5. While i < n:
623 while (i < n) {
624 // 1. Let c be the code unit in S at index i.
625 UChar c = s[i];
626 // 2. Depending on the value of c:
627 if (U16_IS_SINGLE(c)) {
628 // c < 0xD800 or c > 0xDFFF
629 // Append to U the Unicode character with code point c.
630 u.Append(c);
631 } else if (U16_IS_TRAIL(c)) {
632 // 0xDC00 <= c <= 0xDFFF
633 // Append to U a U+FFFD REPLACEMENT CHARACTER.
634 u.Append(kReplacementCharacter);
635 } else {
636 // 0xD800 <= c <= 0xDBFF
637 DCHECK(U16_IS_LEAD(c));
638 if (i == n - 1) {
639 // 1. If i = n-1, then append to U a U+FFFD REPLACEMENT CHARACTER.
640 u.Append(kReplacementCharacter);
641 } else {
642 // 2. Otherwise, i < n-1:
643 DCHECK_LT(i, n - 1);
644 // ....1. Let d be the code unit in S at index i+1.
645 UChar d = s[i + 1];
646 if (U16_IS_TRAIL(d)) {
647 // 2. If 0xDC00 <= d <= 0xDFFF, then:
648 // ..1. Let a be c & 0x3FF.
649 // ..2. Let b be d & 0x3FF.
650 // ..3. Append to U the Unicode character with code point
651 // 2^16+2^10*a+b.
652 u.Append(U16_GET_SUPPLEMENTARY(c, d));
653 // Blink: This is equivalent to u.append(c); u.append(d);
654 ++i;
655 } else {
656 // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a U+FFFD
657 // REPLACEMENT CHARACTER.
658 u.Append(kReplacementCharacter);
659 }
660 }
661 }
662 // 3. Set i to i+1.
663 ++i;
664 }
665
666 // 6. Return U.
667 DCHECK_EQ(u.length(), string.length());
668 return u.ToString();
669 }
670
671 String ToUSVString(v8::Isolate* isolate,
672 v8::Local<v8::Value> value,
673 ExceptionState& exception_state) {
674 // http://heycam.github.io/webidl/#es-USVString
675 if (value.IsEmpty())
676 return String();
677
678 v8::Local<v8::String> string_object;
679 if (value->IsString()) {
680 string_object = value.As<v8::String>();
681 } else {
682 v8::TryCatch block(isolate);
683 if (!V8Call(value->ToString(isolate->GetCurrentContext()), string_object,
684 block)) {
685 exception_state.RethrowV8Exception(block.Exception());
686 return String();
687 }
688 }
689
690 // USVString is identical to DOMString except that "convert a
691 // DOMString to a sequence of Unicode characters" is used subsequently
692 // when converting to an IDL value
693 String x = ToCoreString(string_object);
694 return ReplaceUnmatchedSurrogates(x);
695 }
696
697 XPathNSResolver* ToXPathNSResolver(ScriptState* script_state,
698 v8::Local<v8::Value> value) {
699 XPathNSResolver* resolver = nullptr;
700 if (V8XPathNSResolver::hasInstance(value, script_state->GetIsolate()))
701 resolver = V8XPathNSResolver::toImpl(v8::Local<v8::Object>::Cast(value));
702 else if (value->IsObject())
703 resolver =
704 V8CustomXPathNSResolver::Create(script_state, value.As<v8::Object>());
705 return resolver;
706 }
707
708 DOMWindow* ToDOMWindow(v8::Isolate* isolate, v8::Local<v8::Value> value) {
709 if (value.IsEmpty() || !value->IsObject())
710 return 0;
711
712 v8::Local<v8::Object> window_wrapper = V8Window::findInstanceInPrototypeChain(
713 v8::Local<v8::Object>::Cast(value), isolate);
714 if (!window_wrapper.IsEmpty())
715 return V8Window::toImpl(window_wrapper);
716 return 0;
717 }
718
719 LocalDOMWindow* ToLocalDOMWindow(v8::Local<v8::Context> context) {
720 if (context.IsEmpty())
721 return 0;
722 return ToLocalDOMWindow(
723 ToDOMWindow(context->GetIsolate(), context->Global()));
724 }
725
726 LocalDOMWindow* EnteredDOMWindow(v8::Isolate* isolate) {
727 LocalDOMWindow* window =
728 ToLocalDOMWindow(isolate->GetEnteredOrMicrotaskContext());
729 DCHECK(window);
730 return window;
731 }
732
733 LocalDOMWindow* CurrentDOMWindow(v8::Isolate* isolate) {
734 return ToLocalDOMWindow(isolate->GetCurrentContext());
735 }
736
737 ExecutionContext* ToExecutionContext(v8::Local<v8::Context> context) {
738 if (context.IsEmpty())
739 return 0;
740 v8::Local<v8::Object> global = context->Global();
741 v8::Local<v8::Object> window_wrapper =
742 V8Window::findInstanceInPrototypeChain(global, context->GetIsolate());
743 if (!window_wrapper.IsEmpty())
744 return V8Window::toImpl(window_wrapper)->GetExecutionContext();
745 v8::Local<v8::Object> worker_wrapper =
746 V8WorkerGlobalScope::findInstanceInPrototypeChain(global,
747 context->GetIsolate());
748 if (!worker_wrapper.IsEmpty())
749 return V8WorkerGlobalScope::toImpl(worker_wrapper)->GetExecutionContext();
750 v8::Local<v8::Object> worklet_wrapper =
751 V8WorkletGlobalScope::findInstanceInPrototypeChain(global,
752 context->GetIsolate());
753 if (!worklet_wrapper.IsEmpty())
754 return V8WorkletGlobalScope::toImpl(worklet_wrapper);
755 // FIXME: Is this line of code reachable?
756 return nullptr;
757 }
758
759 ExecutionContext* CurrentExecutionContext(v8::Isolate* isolate) {
760 return ToExecutionContext(isolate->GetCurrentContext());
761 }
762
763 LocalFrame* ToLocalFrameIfNotDetached(v8::Local<v8::Context> context) {
764 LocalDOMWindow* window = ToLocalDOMWindow(context);
765 if (window && window->IsCurrentlyDisplayedInFrame())
766 return window->GetFrame();
767 // We return 0 here because |context| is detached from the Frame. If we
768 // did return |frame| we could get in trouble because the frame could be
769 // navigated to another security origin.
770 return nullptr;
771 }
772
773 void ToFlexibleArrayBufferView(v8::Isolate* isolate,
774 v8::Local<v8::Value> value,
775 FlexibleArrayBufferView& result,
776 void* storage) {
777 DCHECK(value->IsArrayBufferView());
778 v8::Local<v8::ArrayBufferView> buffer = value.As<v8::ArrayBufferView>();
779 if (!storage) {
780 result.SetFull(V8ArrayBufferView::toImpl(buffer));
781 return;
782 }
783 size_t length = buffer->ByteLength();
784 buffer->CopyContents(storage, length);
785 result.SetSmall(storage, length);
786 }
787
788 static ScriptState* ToScriptStateImpl(LocalFrame* frame,
789 DOMWrapperWorld& world) {
790 if (!frame)
791 return nullptr;
792 v8::Local<v8::Context> context = ToV8ContextEvenIfDetached(frame, world);
793 if (context.IsEmpty())
794 return nullptr;
795 ScriptState* script_state = ScriptState::From(context);
796 if (!script_state->ContextIsValid())
797 return nullptr;
798 DCHECK_EQ(frame, ToLocalFrameIfNotDetached(context));
799 return script_state;
800 }
801
802 v8::Local<v8::Context> ToV8Context(ExecutionContext* context,
803 DOMWrapperWorld& world) {
804 DCHECK(context);
805 if (context->IsDocument()) {
806 if (LocalFrame* frame = ToDocument(context)->GetFrame())
807 return ToV8Context(frame, world);
808 } else if (context->IsWorkerGlobalScope()) {
809 if (WorkerOrWorkletScriptController* script =
810 ToWorkerOrWorkletGlobalScope(context)->ScriptController()) {
811 if (script->GetScriptState()->ContextIsValid())
812 return script->GetScriptState()->GetContext();
813 }
814 }
815 return v8::Local<v8::Context>();
816 }
817
818 v8::Local<v8::Context> ToV8Context(LocalFrame* frame, DOMWrapperWorld& world) {
819 ScriptState* script_state = ToScriptStateImpl(frame, world);
820 if (!script_state)
821 return v8::Local<v8::Context>();
822 return script_state->GetContext();
823 }
824
825 v8::Local<v8::Context> ToV8ContextEvenIfDetached(LocalFrame* frame,
826 DOMWrapperWorld& world) {
827 DCHECK(frame);
828 return frame->WindowProxy(world)->ContextIfInitialized();
829 }
830
831 ScriptState* ToScriptState(LocalFrame* frame, DOMWrapperWorld& world) {
832 v8::HandleScope handle_scope(ToIsolate(frame));
833 return ToScriptStateImpl(frame, world);
834 }
835
836 ScriptState* ToScriptStateForMainWorld(LocalFrame* frame) {
837 return ToScriptState(frame, DOMWrapperWorld::MainWorld());
838 }
839
840 bool IsValidEnum(const String& value,
841 const char** valid_values,
842 size_t length,
843 const String& enum_name,
844 ExceptionState& exception_state) {
845 for (size_t i = 0; i < length; ++i) {
846 // Avoid the strlen inside String::operator== (because of the StringView).
847 if (WTF::Equal(value.Impl(), valid_values[i]))
848 return true;
849 }
850 exception_state.ThrowTypeError("The provided value '" + value +
851 "' is not a valid enum value of type " +
852 enum_name + ".");
853 return false;
854 }
855
856 bool IsValidEnum(const Vector<String>& values,
857 const char** valid_values,
858 size_t length,
859 const String& enum_name,
860 ExceptionState& exception_state) {
861 for (auto value : values) {
862 if (!IsValidEnum(value, valid_values, length, enum_name, exception_state))
863 return false;
864 }
865 return true;
866 }
867
868 v8::Local<v8::Function> GetBoundFunction(v8::Local<v8::Function> function) { 37 v8::Local<v8::Function> GetBoundFunction(v8::Local<v8::Function> function) {
869 v8::Local<v8::Value> bound_function = function->GetBoundFunction(); 38 v8::Local<v8::Value> bound_function = function->GetBoundFunction();
870 return bound_function->IsFunction() 39 return bound_function->IsFunction()
871 ? v8::Local<v8::Function>::Cast(bound_function) 40 ? v8::Local<v8::Function>::Cast(bound_function)
872 : function; 41 : function;
873 } 42 }
874 43
875 v8::Local<v8::Object> GetEsIterator(v8::Isolate* isolate,
876 v8::Local<v8::Object> object,
877 ExceptionState& exception_state) {
878 v8::TryCatch block(isolate);
879 v8::Local<v8::Context> context = isolate->GetCurrentContext();
880 v8::Local<v8::Value> iterator_getter;
881 if (!object->Get(context, v8::Symbol::GetIterator(isolate))
882 .ToLocal(&iterator_getter)) {
883 exception_state.RethrowV8Exception(block.Exception());
884 return v8::Local<v8::Object>();
885 }
886 if (!iterator_getter->IsFunction()) {
887 exception_state.ThrowTypeError("Iterator getter is not callable.");
888 return v8::Local<v8::Object>();
889 }
890
891 v8::Local<v8::Function> getter_function = iterator_getter.As<v8::Function>();
892 v8::Local<v8::Value> iterator;
893 if (!V8ScriptRunner::CallFunction(getter_function,
894 ToExecutionContext(context), object, 0,
895 nullptr, isolate)
896 .ToLocal(&iterator)) {
897 exception_state.RethrowV8Exception(block.Exception());
898 return v8::Local<v8::Object>();
899 }
900 if (!iterator->IsObject()) {
901 exception_state.ThrowTypeError("Iterator is not an object.");
902 return v8::Local<v8::Object>();
903 }
904 return iterator.As<v8::Object>();
905 }
906
907 bool HasCallableIteratorSymbol(v8::Isolate* isolate,
908 v8::Local<v8::Value> value,
909 ExceptionState& exception_state) {
910 if (!value->IsObject())
911 return false;
912 v8::TryCatch block(isolate);
913 v8::Local<v8::Context> context = isolate->GetCurrentContext();
914 v8::Local<v8::Value> iterator_getter;
915 if (!value.As<v8::Object>()
916 ->Get(context, v8::Symbol::GetIterator(isolate))
917 .ToLocal(&iterator_getter)) {
918 exception_state.RethrowV8Exception(block.Exception());
919 return false;
920 }
921 return iterator_getter->IsFunction();
922 }
923
924 bool AddHiddenValueToArray(v8::Isolate* isolate, 44 bool AddHiddenValueToArray(v8::Isolate* isolate,
925 v8::Local<v8::Object> object, 45 v8::Local<v8::Object> object,
926 v8::Local<v8::Value> value, 46 v8::Local<v8::Value> value,
927 int array_index) { 47 int array_index) {
928 DCHECK(!value.IsEmpty()); 48 DCHECK(!value.IsEmpty());
929 v8::Local<v8::Value> array_value = object->GetInternalField(array_index); 49 v8::Local<v8::Value> array_value = object->GetInternalField(array_index);
930 if (array_value->IsNull() || array_value->IsUndefined()) { 50 if (array_value->IsNull() || array_value->IsUndefined()) {
931 array_value = v8::Array::New(isolate); 51 array_value = v8::Array::New(isolate);
932 object->SetInternalField(array_index, array_value); 52 object->SetInternalField(array_index, array_value);
933 } 53 }
(...skipping 15 matching lines...) Expand all
949 v8::Local<v8::Value> item; 69 v8::Local<v8::Value> item;
950 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&item)) 70 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&item))
951 return; 71 return;
952 if (item->StrictEquals(value)) { 72 if (item->StrictEquals(value)) {
953 array->Delete(isolate->GetCurrentContext(), i).ToChecked(); 73 array->Delete(isolate->GetCurrentContext(), i).ToChecked();
954 return; 74 return;
955 } 75 }
956 } 76 }
957 } 77 }
958 78
959 void MoveEventListenerToNewWrapper(v8::Isolate* isolate,
960 v8::Local<v8::Object> object,
961 EventListener* old_value,
962 v8::Local<v8::Value> new_value,
963 int array_index) {
964 if (old_value) {
965 V8AbstractEventListener* old_listener =
966 V8AbstractEventListener::Cast(old_value);
967 if (old_listener) {
968 v8::Local<v8::Object> old_listener_object =
969 old_listener->GetExistingListenerObject();
970 if (!old_listener_object.IsEmpty())
971 RemoveHiddenValueFromArray(isolate, object, old_listener_object,
972 array_index);
973 }
974 }
975 // Non-callable input is treated as null and ignored
976 if (new_value->IsFunction())
977 AddHiddenValueToArray(isolate, object, new_value, array_index);
978 }
979
980 v8::Isolate* ToIsolate(ExecutionContext* context) {
981 if (context && context->IsDocument())
982 return V8PerIsolateData::MainThreadIsolate();
983 return v8::Isolate::GetCurrent();
984 }
985
986 v8::Isolate* ToIsolate(LocalFrame* frame) {
987 DCHECK(frame);
988 return frame->GetWindowProxyManager()->GetIsolate();
989 }
990
991 v8::Local<v8::Value> FreezeV8Object(v8::Local<v8::Value> value, 79 v8::Local<v8::Value> FreezeV8Object(v8::Local<v8::Value> value,
992 v8::Isolate* isolate) { 80 v8::Isolate* isolate) {
993 value.As<v8::Object>() 81 value.As<v8::Object>()
994 ->SetIntegrityLevel(isolate->GetCurrentContext(), 82 ->SetIntegrityLevel(isolate->GetCurrentContext(),
995 v8::IntegrityLevel::kFrozen) 83 v8::IntegrityLevel::kFrozen)
996 .ToChecked(); 84 .ToChecked();
997 return value; 85 return value;
998 } 86 }
999 87
1000 v8::Local<v8::Value> FromJSONString(v8::Isolate* isolate,
1001 const String& stringified_json,
1002 ExceptionState& exception_state) {
1003 v8::Local<v8::Value> parsed;
1004 v8::TryCatch try_catch(isolate);
1005 if (!V8Call(v8::JSON::Parse(isolate, V8String(isolate, stringified_json)),
1006 parsed, try_catch)) {
1007 if (try_catch.HasCaught())
1008 exception_state.RethrowV8Exception(try_catch.Exception());
1009 }
1010
1011 return parsed;
1012 }
1013
1014 } // namespace blink 88 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/bindings/core/v8/V8Binding.h ('k') | third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698