1/* 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2013 Apple Inc. All rights reserved. 4 * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> 5 * Copyright (C) 2009 Google, Inc. All rights reserved. 6 * Copyright (C) 2012 Ericsson AB. All rights reserved. 7 * Copyright (C) 2013 Michael Pruett <michael@68k.org> 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24#ifndef JSDOMBinding_h 25#define JSDOMBinding_h 26 27#include "JSDOMGlobalObject.h" 28#include "JSDOMWrapper.h" 29#include "DOMWrapperWorld.h" 30#include "ScriptWrappable.h" 31#include "ScriptWrappableInlines.h" 32#include "WebCoreTypedArrayController.h" 33#include <cstddef> 34#include <heap/SlotVisitorInlines.h> 35#include <heap/Weak.h> 36#include <heap/WeakInlines.h> 37#include <runtime/Error.h> 38#include <runtime/JSArray.h> 39#include <runtime/JSArrayBuffer.h> 40#include <runtime/JSCJSValueInlines.h> 41#include <runtime/JSCellInlines.h> 42#include <runtime/JSTypedArrays.h> 43#include <runtime/Lookup.h> 44#include <runtime/StructureInlines.h> 45#include <runtime/TypedArrayInlines.h> 46#include <runtime/TypedArrays.h> 47#include <wtf/Forward.h> 48#include <wtf/Noncopyable.h> 49#include <wtf/Vector.h> 50 51namespace JSC { 52class HashEntry; 53} 54 55#if ENABLE(GAMEPAD) 56namespace WTF { 57 58template<typename T> inline T* getPtr(const Ref<T>& p) 59{ 60 return const_cast<T*>(&p.get()); 61} 62 63} 64#endif 65 66namespace WebCore { 67 68class CachedScript; 69class DOMStringList; 70class DOMWindow; 71class Frame; 72class URL; 73class Node; 74 75typedef int ExceptionCode; 76 77DOMWindow& activeDOMWindow(JSC::ExecState*); 78DOMWindow& firstDOMWindow(JSC::ExecState*); 79 80JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName); 81void reportDeprecatedSetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName); 82 83void throwArrayElementTypeError(JSC::ExecState&); 84void throwAttributeTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName, const char* expectedType); 85void throwSequenceTypeError(JSC::ExecState&); 86void throwSetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName); 87 88JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues); 89JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName); 90JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType); 91JSC::EncodedJSValue throwConstructorDocumentUnavailableError(JSC::ExecState&, const char* interfaceName); 92JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName); 93JSC::EncodedJSValue throwThisTypeError(JSC::ExecState&, const char* interfaceName, const char* functionName); 94 95// Base class for all constructor objects in the JSC bindings. 96class DOMConstructorObject : public JSDOMWrapper { 97 typedef JSDOMWrapper Base; 98public: 99 static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) 100 { 101 return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); 102 } 103 104protected: 105 static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesVisitChildren | JSDOMWrapper::StructureFlags; 106 DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject) 107 : JSDOMWrapper(structure, globalObject) 108 { 109 } 110}; 111 112JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*); 113JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*); 114 115inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec) 116{ 117 // FIXME: Callers to this function should be using the global object 118 // from which the object is being created, instead of assuming the lexical one. 119 // e.g. subframe.document.body should use the subframe's global object, not the lexical one. 120 return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); 121} 122 123template<typename WrapperClass> inline JSC::Structure* getDOMStructure(JSC::VM& vm, JSDOMGlobalObject* globalObject) 124{ 125 if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info())) 126 return structure; 127 return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, globalObject, WrapperClass::createPrototype(vm, globalObject)), WrapperClass::info()); 128} 129 130template<typename WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec) 131{ 132 // FIXME: This function is wrong. It uses the wrong global object for creating the prototype structure. 133 return getDOMStructure<WrapperClass>(exec->vm(), deprecatedGlobalObjectForPrototype(exec)); 134} 135 136template<typename WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject) 137{ 138 return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype())); 139} 140 141inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*) 142{ 143 return static_cast<WebCoreTypedArrayController*>(world.vm().m_typedArrayController.get())->wrapperOwner(); 144} 145 146inline void* wrapperContext(DOMWrapperWorld& world, JSC::ArrayBuffer*) 147{ 148 return &world; 149} 150 151inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return nullptr; } 152inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*, JSC::WeakHandleOwner*, void*) { return false; } 153inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*) { return false; } 154 155inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject) 156{ 157 if (!world.isNormal()) 158 return nullptr; 159 return domObject->wrapper(); 160} 161 162inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer) 163{ 164 if (!world.isNormal()) 165 return nullptr; 166 return buffer->m_wrapper.get(); 167} 168 169inline bool setInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) 170{ 171 if (!world.isNormal()) 172 return false; 173 domObject->setWrapper(wrapper, wrapperOwner, context); 174 return true; 175} 176 177inline bool setInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) 178{ 179 if (!world.isNormal()) 180 return false; 181 domObject->m_wrapper = JSC::Weak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, context); 182 return true; 183} 184 185inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMWrapper* wrapper) 186{ 187 if (!world.isNormal()) 188 return false; 189 domObject->clearWrapper(wrapper); 190 return true; 191} 192 193inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper) 194{ 195 if (!world.isNormal()) 196 return false; 197 weakClear(domObject->m_wrapper, wrapper); 198 return true; 199} 200 201template<typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, DOMClass* domObject) 202{ 203 if (JSC::JSObject* wrapper = getInlineCachedWrapper(world, domObject)) 204 return wrapper; 205 return world.m_wrappers.get(domObject); 206} 207 208template<typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper) 209{ 210 JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject); 211 void* context = wrapperContext(world, domObject); 212 if (setInlineCachedWrapper(world, domObject, wrapper, owner, context)) 213 return; 214 weakAdd(world.m_wrappers, (void*)domObject, JSC::Weak<JSC::JSObject>(wrapper, owner, context)); 215} 216 217template<typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper) 218{ 219 if (clearInlineCachedWrapper(world, domObject, wrapper)) 220 return; 221 weakRemove(world.m_wrappers, (void*)domObject, wrapper); 222} 223 224#define CREATE_DOM_WRAPPER(globalObject, className, object) createWrapper<JS##className>(globalObject, static_cast<className*>(object)) 225template<typename WrapperClass, typename DOMClass> inline JSDOMWrapper* createWrapper(JSDOMGlobalObject* globalObject, DOMClass* node) 226{ 227 ASSERT(node); 228 ASSERT(!getCachedWrapper(globalObject->world(), node)); 229 WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(globalObject->vm(), globalObject), globalObject, node); 230 cacheWrapper(globalObject->world(), node, wrapper); 231 return wrapper; 232} 233 234template<typename WrapperClass, typename DOMClass> inline JSC::JSValue wrap(JSDOMGlobalObject* globalObject, DOMClass* domObject) 235{ 236 if (!domObject) 237 return JSC::jsNull(); 238 if (JSC::JSObject* wrapper = getCachedWrapper(globalObject->world(), domObject)) 239 return wrapper; 240 return createWrapper<WrapperClass>(globalObject, domObject); 241} 242 243template<typename WrapperClass, typename DOMClass> inline JSC::JSValue getExistingWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject) 244{ 245 ASSERT(domObject); 246 return getCachedWrapper(globalObject->world(), domObject); 247} 248 249template<typename WrapperClass, typename DOMClass> inline JSC::JSValue createNewWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject) 250{ 251 ASSERT(domObject); 252 ASSERT(!getCachedWrapper(globalObject->world(), domObject)); 253 return createWrapper<WrapperClass>(globalObject, domObject); 254} 255 256inline JSC::JSValue argumentOrNull(JSC::ExecState* exec, unsigned index) 257{ 258 return index >= exec->argumentCount() ? JSC::JSValue() : exec->argument(index); 259} 260 261void addImpureProperty(const AtomicString&); 262 263const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable); 264 265void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr); 266void reportCurrentException(JSC::ExecState*); 267 268// Convert a DOM implementation exception code into a JavaScript exception in the execution state. 269void setDOMException(JSC::ExecState*, ExceptionCode); 270 271JSC::JSValue jsString(JSC::ExecState*, const URL&); // empty if the URL is null 272 273JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null 274JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null 275 276JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null 277JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const URL&); // undefined if the URL is null 278 279// See JavaScriptCore for explanation: Should be used for any string that is already owned by another 280// object, to let the engine know that collecting the JSString wrapper is unlikely to save memory. 281JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&); 282 283String propertyNameToString(JSC::PropertyName); 284 285AtomicString propertyNameToAtomicString(JSC::PropertyName); 286AtomicStringImpl* findAtomicString(JSC::PropertyName); 287 288String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null 289String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined 290 291inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay) 292{ 293 double number = value.toNumber(exec); 294 okay = std::isfinite(number); 295 return JSC::toInt32(number); 296} 297 298enum IntegerConversionConfiguration { 299 NormalConversion, 300 EnforceRange, 301 // FIXME: Implement Clamp 302}; 303 304int32_t toInt32EnforceRange(JSC::ExecState*, JSC::JSValue); 305uint32_t toUInt32EnforceRange(JSC::ExecState*, JSC::JSValue); 306 307int8_t toInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); 308uint8_t toUInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); 309 310int16_t toInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); 311uint16_t toUInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); 312 313/* 314 Convert a value to an integer as per <http://www.w3.org/TR/WebIDL/>. 315 The conversion fails if the value cannot be converted to a number or, 316 if EnforceRange is specified, the value is outside the range of the 317 destination integer type. 318*/ 319inline int32_t toInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration) 320{ 321 if (configuration == EnforceRange) 322 return toInt32EnforceRange(exec, value); 323 return value.toInt32(exec); 324} 325 326inline uint32_t toUInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration) 327{ 328 if (configuration == EnforceRange) 329 return toUInt32EnforceRange(exec, value); 330 return value.toUInt32(exec); 331} 332 333int64_t toInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); 334uint64_t toUInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); 335 336// Returns a Date instance for the specified value, or null if the value is NaN or infinity. 337JSC::JSValue jsDateOrNull(JSC::ExecState*, double); 338// NaN if the value can't be converted to a date. 339double valueToDate(JSC::ExecState*, JSC::JSValue); 340 341// Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec. 342inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, unsigned& length) 343{ 344 JSC::JSObject* object = value.getObject(); 345 if (!object) { 346 throwSequenceTypeError(*exec); 347 return nullptr; 348 } 349 350 JSC::JSValue lengthValue = object->get(exec, exec->propertyNames().length); 351 if (exec->hadException()) 352 return nullptr; 353 354 if (lengthValue.isUndefinedOrNull()) { 355 throwSequenceTypeError(*exec); 356 return nullptr; 357 } 358 359 length = lengthValue.toUInt32(exec); 360 if (exec->hadException()) 361 return nullptr; 362 363 return object; 364} 365 366inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer) 367{ 368 if (!buffer) 369 return JSC::jsNull(); 370 if (JSC::JSValue result = getExistingWrapper<JSC::JSArrayBuffer>(globalObject, buffer)) 371 return result; 372 buffer->ref(); 373 JSC::JSArrayBuffer* wrapper = JSC::JSArrayBuffer::create(exec->vm(), globalObject->arrayBufferStructure(), buffer); 374 cacheWrapper(globalObject->world(), buffer, wrapper); 375 return wrapper; 376} 377 378inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBufferView* view) 379{ 380 if (!view) 381 return JSC::jsNull(); 382 return view->wrap(exec, globalObject); 383} 384 385template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr) 386{ 387 return toJS(exec, globalObject, ptr.get()); 388} 389 390template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T>& vector) 391{ 392 JSC::JSArray* array = constructEmptyArray(exec, nullptr, vector.size()); 393 for (size_t i = 0; i < vector.size(); ++i) 394 array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i])); 395 return array; 396} 397 398template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<RefPtr<T>>& vector) 399{ 400 JSC::JSArray* array = constructEmptyArray(exec, nullptr, vector.size()); 401 for (size_t i = 0; i < vector.size(); ++i) 402 array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i].get())); 403 return array; 404} 405 406inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value) 407{ 408 return jsStringOrNull(exec, value); 409} 410 411template<typename T> struct JSValueTraits { 412 static JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value) 413 { 414 return toJS(exec, globalObject, WTF::getPtr(value)); 415 } 416}; 417 418template<> struct JSValueTraits<String> { 419 static JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value) 420 { 421 return JSC::jsStringWithCache(exec, value); 422 } 423}; 424 425template<> struct JSValueTraits<double> { 426 static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const double& value) 427 { 428 return JSC::jsNumber(value); 429 } 430}; 431 432template<> struct JSValueTraits<float> { 433 static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value) 434 { 435 return JSC::jsNumber(value); 436 } 437}; 438 439template<> struct JSValueTraits<unsigned long> { 440 static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const unsigned long& value) 441 { 442 return JSC::jsNumber(value); 443 } 444}; 445 446template<typename T, size_t inlineCapacity> JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& vector) 447{ 448 JSC::MarkedArgumentBuffer list; 449 for (auto& element : vector) 450 list.append(JSValueTraits<T>::arrayJSValue(exec, globalObject, element)); 451 return JSC::constructArray(exec, nullptr, globalObject, list); 452} 453 454JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>); 455 456inline PassRefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value) 457{ 458 JSC::JSArrayBufferView* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value); 459 if (!wrapper) 460 return nullptr; 461 return wrapper->impl(); 462} 463 464inline PassRefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); } 465inline PassRefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); } 466inline PassRefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); } 467inline PassRefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); } 468inline PassRefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); } 469inline PassRefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); } 470inline PassRefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); } 471inline PassRefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); } 472inline PassRefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); } 473 474template<typename T> struct NativeValueTraits; 475 476template<> struct NativeValueTraits<String> { 477 static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue) 478 { 479 indexedValue = jsValue.toString(exec)->value(exec); 480 return true; 481 } 482}; 483 484template<> struct NativeValueTraits<unsigned> { 485 static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned& indexedValue) 486 { 487 if (!jsValue.isNumber()) 488 return false; 489 490 indexedValue = jsValue.toUInt32(exec); 491 if (exec->hadException()) 492 return false; 493 494 return true; 495 } 496}; 497 498template<> struct NativeValueTraits<float> { 499 static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue) 500 { 501 indexedValue = jsValue.toFloat(exec); 502 return !exec->hadException(); 503 } 504}; 505 506template<typename T, typename JST> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState* exec, JSC::JSValue value, T* (*toT)(JSC::JSValue value)) 507{ 508 if (!isJSArray(value)) 509 return Vector<RefPtr<T>>(); 510 511 Vector<RefPtr<T>> result; 512 JSC::JSArray* array = asArray(value); 513 size_t size = array->length(); 514 result.reserveInitialCapacity(size); 515 for (size_t i = 0; i < size; ++i) { 516 JSC::JSValue element = array->getIndex(exec, i); 517 if (element.inherits(JST::info())) 518 result.uncheckedAppend((*toT)(element)); 519 else { 520 throwArrayElementTypeError(*exec); 521 return Vector<RefPtr<T>>(); 522 } 523 } 524 return result; 525} 526 527template<typename T> Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value) 528{ 529 JSC::JSObject* object = value.getObject(); 530 if (!object) 531 return Vector<T>(); 532 533 unsigned length = 0; 534 if (isJSArray(value)) { 535 JSC::JSArray* array = asArray(value); 536 length = array->length(); 537 } else 538 toJSSequence(exec, value, length); 539 540 Vector<T> result; 541 result.reserveInitialCapacity(length); 542 typedef NativeValueTraits<T> TraitsType; 543 544 for (unsigned i = 0; i < length; ++i) { 545 T indexValue; 546 if (!TraitsType::nativeValue(exec, object->get(exec, i), indexValue)) 547 return Vector<T>(); 548 result.uncheckedAppend(indexValue); 549 } 550 return result; 551} 552 553template<typename T> Vector<T> toNativeArguments(JSC::ExecState* exec, size_t startIndex = 0) 554{ 555 size_t length = exec->argumentCount(); 556 ASSERT(startIndex <= length); 557 558 Vector<T> result; 559 result.reserveInitialCapacity(length - startIndex); 560 typedef NativeValueTraits<T> TraitsType; 561 562 for (size_t i = startIndex; i < length; ++i) { 563 T indexValue; 564 if (!TraitsType::nativeValue(exec, exec->argument(i), indexValue)) 565 return Vector<T>(); 566 result.uncheckedAppend(indexValue); 567 } 568 return result; 569} 570 571bool shouldAllowAccessToNode(JSC::ExecState*, Node*); 572bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*); 573bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message); 574bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, String& message); 575 576void printErrorMessageForFrame(Frame*, const String& message); 577JSC::EncodedJSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName); 578 579inline String propertyNameToString(JSC::PropertyName propertyName) 580{ 581 return propertyName.publicName(); 582} 583 584inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName) 585{ 586 return AtomicString(propertyName.publicName()); 587} 588 589template<typename DOMClass> inline const JSC::HashTableValue* getStaticValueSlotEntryWithoutCaching(JSC::ExecState* exec, JSC::PropertyName propertyName) 590{ 591 const JSC::HashTable* table = DOMClass::info()->propHashTable(exec); 592 if (!table) 593 return getStaticValueSlotEntryWithoutCaching<typename DOMClass::Base>(exec, propertyName); 594 const JSC::HashTableValue* entry = table->entry(exec, propertyName); 595 if (!entry) // not found, forward to parent 596 return getStaticValueSlotEntryWithoutCaching<typename DOMClass::Base>(exec, propertyName); 597 return entry; 598} 599 600template<> inline const JSC::HashTableValue* getStaticValueSlotEntryWithoutCaching<JSDOMWrapper>(JSC::ExecState*, JSC::PropertyName) 601{ 602 return nullptr; 603} 604 605template<JSC::NativeFunction nativeFunction, int length> 606JSC::EncodedJSValue nonCachingStaticFunctionGetter(JSC::ExecState* exec, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName propertyName) 607{ 608 return JSC::JSValue::encode(JSC::JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), length, propertyName.publicName(), nativeFunction)); 609} 610 611enum SecurityReportingOption { 612 DoNotReportSecurityError, 613 ReportSecurityError, 614}; 615 616class BindingSecurity { 617public: 618 static bool shouldAllowAccessToNode(JSC::ExecState*, Node*); 619 static bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, SecurityReportingOption = ReportSecurityError); 620 static bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, SecurityReportingOption = ReportSecurityError); 621}; 622 623} // namespace WebCore 624 625#endif // JSDOMBinding_h 626