JSDOMBinding.h 25 KB
Newer Older
kocienda's avatar
kocienda committed
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.
weinig's avatar
weinig committed
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>
kocienda's avatar
kocienda committed
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
ddkilzer's avatar
ddkilzer committed
21
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
kocienda's avatar
kocienda committed
22 23
 */

darin@apple.com's avatar
darin@apple.com committed
24 25
#ifndef JSDOMBinding_h
#define JSDOMBinding_h
kocienda's avatar
kocienda committed
26

27
#include "BindingState.h"
ap@webkit.org's avatar
ap@webkit.org committed
28
#include "JSDOMGlobalObject.h"
29
#include "JSDOMWrapper.h"
30
#include "DOMWrapperWorld.h"
31
#include "ScriptWrappable.h"
32
#include "ScriptWrappableInlines.h"
33
#include "WebCoreTypedArrayController.h"
34
#include <cstddef>
35
#include <heap/Weak.h>
36
#include <heap/WeakInlines.h>
37
#include <runtime/Error.h>
38
#include <runtime/FunctionPrototype.h>
39
#include <runtime/JSArray.h>
40 41 42
#include <runtime/JSArrayBuffer.h>
#include <runtime/JSDataView.h>
#include <runtime/JSTypedArrays.h>
43
#include <runtime/Lookup.h>
44
#include <runtime/ObjectPrototype.h>
45
#include <runtime/Operations.h>
46 47
#include <runtime/TypedArrayInlines.h>
#include <runtime/TypedArrays.h>
48
#include <wtf/Forward.h>
darin's avatar
darin committed
49
#include <wtf/Noncopyable.h>
50
#include <wtf/Vector.h>
51

52 53 54 55
namespace JSC {
class HashEntry;
}

darin's avatar
darin committed
56
namespace WebCore {
darin@apple.com's avatar
darin@apple.com committed
57

58 59
class DOMStringList;

60
    class CachedScript;
61
    class Document;
darin's avatar
darin committed
62
    class Frame;
63
    class HTMLDocument;
darin@apple.com's avatar
darin@apple.com committed
64
    class URL;
65
    class Node;
darin's avatar
darin committed
66 67

    typedef int ExceptionCode;
oliver's avatar
oliver committed
68

69
    // Base class for all constructor objects in the JSC bindings.
weinig@apple.com's avatar
weinig@apple.com committed
70
    class DOMConstructorObject : public JSDOMWrapper {
71
        typedef JSDOMWrapper Base;
bfulgham@webkit.org's avatar
bfulgham@webkit.org committed
72
    public:
ggaren@apple.com's avatar
ggaren@apple.com committed
73
        static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
bfulgham@webkit.org's avatar
bfulgham@webkit.org committed
74
        {
75
            return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
bfulgham@webkit.org's avatar
bfulgham@webkit.org committed
76 77 78
        }

    protected:
weinig@apple.com's avatar
weinig@apple.com committed
79
        static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesVisitChildren | JSDOMWrapper::StructureFlags;
80
        DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
weinig@apple.com's avatar
weinig@apple.com committed
81
            : JSDOMWrapper(structure, globalObject)
82 83 84 85
        {
        }
    };

weinig@apple.com's avatar
weinig@apple.com committed
86
    JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
87
    JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*);
darin@apple.com's avatar
darin@apple.com committed
88

89 90 91 92 93
    inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
    {
        // FIXME: Callers to this function should be using the global object
        // from which the object is being created, instead of assuming the lexical one.
        // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
94
        return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
95 96
    }

97
    template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::VM& vm, JSDOMGlobalObject* globalObject)
darin@apple.com's avatar
darin@apple.com committed
98
    {
99
        if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info()))
darin@apple.com's avatar
darin@apple.com committed
100
            return structure;
101
        return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, globalObject, WrapperClass::createPrototype(vm, globalObject)), WrapperClass::info());
weinig@apple.com's avatar
weinig@apple.com committed
102
    }
103

104
    template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
weinig@apple.com's avatar
weinig@apple.com committed
105
    {
106
        // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
107
        return getDOMStructure<WrapperClass>(exec->vm(), deprecatedGlobalObjectForPrototype(exec));
darin@apple.com's avatar
darin@apple.com committed
108
    }
109

110
    template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
darin@apple.com's avatar
darin@apple.com committed
111
    {
112
        return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
darin@apple.com's avatar
darin@apple.com committed
113
    }
114

115
    inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*)
116
    {
117
        return static_cast<WebCoreTypedArrayController*>(world.vm()->m_typedArrayController.get())->wrapperOwner();
118 119
    }
    
120
    inline void* wrapperContext(DOMWrapperWorld& world, JSC::ArrayBuffer*)
121
    {
122
        return &world;
123 124
    }

125 126 127
    inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return 0; }
    inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*, JSC::WeakHandleOwner*, void*) { return false; }
    inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*) { return false; }
128

129
    inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject)
130
    {
131
        if (!world.isNormal())
132 133 134 135
            return 0;
        return domObject->wrapper();
    }

136
    inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer)
137
    {
138
        if (!world.isNormal())
139 140 141 142
            return 0;
        return buffer->m_wrapper.get();
    }

143
    inline bool setInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context)
144
    {
145
        if (!world.isNormal())
146
            return false;
147
        domObject->setWrapper(wrapper, wrapperOwner, context);
148 149 150
        return true;
    }

151
    inline bool setInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context)
152
    {
153
        if (!world.isNormal())
154
            return false;
andersca@apple.com's avatar
andersca@apple.com committed
155
        domObject->m_wrapper = JSC::Weak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, context);
156 157 158
        return true;
    }

159
    inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMWrapper* wrapper)
160
    {
161
        if (!world.isNormal())
162 163 164 165 166
            return false;
        domObject->clearWrapper(wrapper);
        return true;
    }

167
    inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper)
darin@apple.com's avatar
darin@apple.com committed
168
    {
169
        if (!world.isNormal())
170 171 172 173 174
            return false;
        weakClear(domObject->m_wrapper, wrapper);
        return true;
    }

175
    template <typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, DOMClass* domObject)
176 177
    {
        if (JSC::JSObject* wrapper = getInlineCachedWrapper(world, domObject))
178
            return wrapper;
179
        return world.m_wrappers.get(domObject);
darin@apple.com's avatar
darin@apple.com committed
180
    }
181

182
    template <typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper)
darin's avatar
darin committed
183
    {
184 185 186
        JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject);
        void* context = wrapperContext(world, domObject);
        if (setInlineCachedWrapper(world, domObject, wrapper, owner, context))
187
            return;
188
        weakAdd(world.m_wrappers, (void*)domObject, JSC::Weak<JSC::JSObject>(wrapper, owner, context));
darin's avatar
darin committed
189 190
    }

191
    template <typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper)
192 193 194
    {
        if (clearInlineCachedWrapper(world, domObject, wrapper))
            return;
195
        weakRemove(world.m_wrappers, (void*)domObject, wrapper);
196 197
    }
    
198
    #define CREATE_DOM_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
199
    template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
darin@apple.com's avatar
darin@apple.com committed
200 201
    {
        ASSERT(node);
202
        ASSERT(!getCachedWrapper(currentWorld(exec), node));
203
        WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(exec->vm(), globalObject), globalObject, node);
204 205
        // FIXME: The entire function can be removed, once we fix caching.
        // This function is a one-off hack to make Nodes cache in the right global object.
206
        cacheWrapper(currentWorld(exec), node, wrapper);
darin@apple.com's avatar
darin@apple.com committed
207 208
        return wrapper;
    }
209 210

    template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
darin@apple.com's avatar
darin@apple.com committed
211
    {
212
        if (!domObject)
darin@apple.com's avatar
darin@apple.com committed
213
            return JSC::jsNull();
214
        if (JSC::JSObject* wrapper = getCachedWrapper(currentWorld(exec), domObject))
darin@apple.com's avatar
darin@apple.com committed
215
            return wrapper;
216
        return createWrapper<WrapperClass>(exec, globalObject, domObject);
darin@apple.com's avatar
darin@apple.com committed
217 218
    }

219 220 221 222 223 224 225 226 227 228 229 230 231
    template<class WrapperClass, class DOMClass> inline JSC::JSValue getExistingWrapper(JSC::ExecState* exec, DOMClass* domObject)
    {
        ASSERT(domObject);
        return getCachedWrapper(currentWorld(exec), domObject);
    }

    template<class WrapperClass, class DOMClass> inline JSC::JSValue createNewWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
    {
        ASSERT(domObject);
        ASSERT(!getCachedWrapper(currentWorld(exec), domObject));
        return createWrapper<WrapperClass>(exec, globalObject, domObject);
    }

232
    inline JSC::JSValue argumentOrNull(JSC::ExecState* exec, unsigned index)
233
    {
234
        return index >= exec->argumentCount() ? JSC::JSValue() : exec->argument(index);
235 236
    }

237
    const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
ap@webkit.org's avatar
ap@webkit.org committed
238

239
    void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = 0);
ap@webkit.org's avatar
ap@webkit.org committed
240 241
    void reportCurrentException(JSC::ExecState*);

darin's avatar
darin committed
242
    // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
243
    void setDOMException(JSC::ExecState*, ExceptionCode);
darin's avatar
darin committed
244

245
    JSC::JSValue jsStringWithCache(JSC::ExecState*, const String&);
darin@apple.com's avatar
darin@apple.com committed
246
    JSC::JSValue jsString(JSC::ExecState*, const URL&); // empty if the URL is null
247
    inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const AtomicString& s)
248
    { 
249
        return jsStringWithCache(exec, s.string());
250 251
    }
        
ggaren@apple.com's avatar
ggaren@apple.com committed
252
    JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
darin@apple.com's avatar
darin@apple.com committed
253
    JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null
mjs's avatar
mjs committed
254

ggaren@apple.com's avatar
ggaren@apple.com committed
255
    JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
darin@apple.com's avatar
darin@apple.com committed
256
    JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const URL&); // undefined if the URL is null
darin's avatar
darin committed
257

258
    // See JavaScriptCore for explanation: Should be used for any string that is already owned by another
darin@apple.com's avatar
darin@apple.com committed
259
    // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
260
    JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&); 
weinig's avatar
weinig committed
261

262
    String propertyNameToString(JSC::PropertyName);
263

264 265
    AtomicString propertyNameToAtomicString(JSC::PropertyName);
    AtomicStringImpl* findAtomicString(JSC::PropertyName);
266

267 268
    String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
    String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
kocienda's avatar
kocienda committed
269

270 271 272
    inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay)
    {
        double number = value.toNumber(exec);
273
        okay = std::isfinite(number);
274 275 276
        return JSC::toInt32(number);
    }

277 278 279 280 281 282 283 284 285
    enum IntegerConversionConfiguration {
        NormalConversion,
        EnforceRange,
        // FIXME: Implement Clamp
    };

    int32_t toInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
    uint32_t toUInt32EnforceRange(JSC::ExecState*, JSC::JSValue);

286 287 288
    int8_t toInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
    uint8_t toUInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);

289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    /*
        Convert a value to an integer as per <http://www.w3.org/TR/WebIDL/>.
        The conversion fails if the value cannot be converted to a number or,
        if EnforceRange is specified, the value is outside the range of the
        destination integer type.
    */
    inline int32_t toInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration)
    {
        if (configuration == EnforceRange)
            return toInt32EnforceRange(exec, value);
        return value.toInt32(exec);
    }

    inline uint32_t toUInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration)
    {
        if (configuration == EnforceRange)
            return toUInt32EnforceRange(exec, value);
        return value.toUInt32(exec);
    }

    int64_t toInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
    uint64_t toUInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);

312 313 314 315 316
    // Returns a Date instance for the specified value, or null if the value is NaN or infinity.
    JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
    // NaN if the value can't be converted to a date.
    double valueToDate(JSC::ExecState*, JSC::JSValue);

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
    // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
    inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, unsigned& length)
    {
        JSC::JSObject* object = value.getObject();
        if (!object) {
            throwTypeError(exec);
            return 0;
        }

        JSC::JSValue lengthValue = object->get(exec, exec->propertyNames().length);
        if (exec->hadException())
            return 0;

        if (lengthValue.isUndefinedOrNull()) {
            throwTypeError(exec);
            return 0;
        }

        length = lengthValue.toUInt32(exec);
        if (exec->hadException())
            return 0;

        return object;
    }

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
    inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer)
    {
        if (!buffer)
            return JSC::jsNull();
        if (JSC::JSValue result = getExistingWrapper<JSC::JSArrayBuffer>(exec, buffer))
            return result;
        buffer->ref();
        JSC::JSArrayBuffer* wrapper = JSC::JSArrayBuffer::create(exec->vm(), globalObject->arrayBufferStructure(), buffer);
        cacheWrapper(currentWorld(exec), buffer, wrapper);
        return wrapper;
    }

    inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBufferView* view)
    {
        if (!view)
            return JSC::jsNull();
        return view->wrap(exec, globalObject);
    }

361 362 363 364 365
    template <typename T>
    inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
    {
        return toJS(exec, globalObject, ptr.get());
    }
weinig@apple.com's avatar
weinig@apple.com committed
366

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    template <typename T>
    inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Vector<T> vector)
    {
        JSC::JSArray* array = constructEmptyArray(exec, 0, vector.size());
        
        for (size_t i = 0; i < vector.size(); ++i)
            array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i]));
        
        return array;
    }

    template <typename T>
    inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Vector<RefPtr<T>> vector)
    {
        JSC::JSArray* array = constructEmptyArray(exec, 0, vector.size());
        
        for (size_t i = 0; i < vector.size(); ++i)
            array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i].get()));
        
        return array;
    }
    
389
    template <class T>
390
    struct JSValueTraits {
391 392 393 394 395 396 397
        static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value)
        {
            return toJS(exec, globalObject, WTF::getPtr(value));
        }
    };

    template<>
398
    struct JSValueTraits<String> {
399 400
        static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
        {
401
            return jsStringWithCache(exec, value);
402 403 404 405
        }
    };

    template<>
406
    struct JSValueTraits<float> {
407 408 409 410 411 412 413
        static inline JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value)
        {
            return JSC::jsNumber(value);
        }
    };

    template<>
414
    struct JSValueTraits<unsigned long> {
415 416 417 418 419 420
        static inline JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const unsigned long& value)
        {
            return JSC::jsNumber(value);
        }
    };

421 422
    template <typename T, size_t inlineCapacity>
    JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& iterator)
423 424
    {
        JSC::MarkedArgumentBuffer list;
425
        typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();        
426
        typedef JSValueTraits<T> TraitsType;
427

428
        for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
429
            list.append(TraitsType::arrayJSValue(exec, globalObject, *iter));
430

431
        return JSC::constructArray(exec, 0, globalObject, list);
432 433
    }

434 435
    JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>);

436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    inline PassRefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value)
    {
        JSC::JSArrayBufferView* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value);
        if (!wrapper)
            return 0;
        return wrapper->impl();
    }
    
    inline PassRefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); }
    inline PassRefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); }
    inline PassRefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); }
    inline PassRefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); }
    inline PassRefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
    inline PassRefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); }
    inline PassRefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); }
    inline PassRefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); }
    inline PassRefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); }
    
    inline PassRefPtr<JSC::DataView> toDataView(JSC::JSValue value)
    {
        JSC::JSDataView* wrapper = JSC::jsDynamicCast<JSC::JSDataView*>(value);
        if (!wrapper)
            return 0;
        return wrapper->typedImpl();
    }

462 463 464 465
    template<class T> struct NativeValueTraits;

    template<>
    struct NativeValueTraits<String> {
466
        static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue)
467
        {
468
            indexedValue = jsValue.toString(exec)->value(exec);
469 470 471 472 473
            return true;
        }
    };

    template<>
474 475
    struct NativeValueTraits<unsigned> {
        static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned& indexedValue)
476 477 478 479 480 481 482 483 484 485 486 487
        {
            if (!jsValue.isNumber())
                return false;

            indexedValue = jsValue.toUInt32(exec);
            if (exec->hadException())
                return false;

            return true;
        }
    };

488 489
    template<>
    struct NativeValueTraits<float> {
490
        static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue)
491 492 493 494 495 496
        {
            indexedValue = jsValue.toFloat(exec);
            return !exec->hadException();
        }
    };

497 498 499 500 501 502 503 504 505 506
    template <class T, class JST>
    Vector<RefPtr<T> > toRefPtrNativeArray(JSC::ExecState* exec, JSC::JSValue value, T* (*toT)(JSC::JSValue value))
    {
        if (!isJSArray(value))
            return Vector<RefPtr<T> >();

        Vector<RefPtr<T> > result;
        JSC::JSArray* array = asArray(value);
        for (size_t i = 0; i < array->length(); ++i) {
            JSC::JSValue element = array->getIndex(exec, i);
507
            if (element.inherits(JST::info()))
508 509 510 511 512 513 514 515 516
                result.append((*toT)(element));
            else {
                throwVMError(exec, createTypeError(exec, "Invalid Array element type"));
                return Vector<RefPtr<T> >();
            }
        }
        return result;
    }

517 518 519
    template <class T>
    Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value)
    {
520 521 522 523 524 525 526 527
        unsigned length = 0;
        if (isJSArray(value)) {
            JSC::JSArray* array = asArray(value);
            length = array->length();
        } else
            toJSSequence(exec, value, length);

        JSC::JSObject* object = value.getObject();
528
        Vector<T> result;
529
        typedef NativeValueTraits<T> TraitsType;
530

531 532
        for (unsigned i = 0; i < length; ++i) {
            T indexValue;
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
            if (!TraitsType::nativeValue(exec, object->get(exec, i), indexValue))
                return Vector<T>();
            result.append(indexValue);
        }
        return result;
    }

    template <class T>
    Vector<T> toNativeArguments(JSC::ExecState* exec, size_t startIndex = 0)
    {
        size_t length = exec->argumentCount();
        ASSERT(startIndex <= length);

        Vector<T> result;
        typedef NativeValueTraits<T> TraitsType;

        for (size_t i = startIndex; i < length; ++i) {
            T indexValue;
            if (!TraitsType::nativeValue(exec, exec->argument(i), indexValue))
552 553
                return Vector<T>();
            result.append(indexValue);
554 555 556 557
        }
        return result;
    }

558 559 560
    bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
    bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*);
    bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message);
561
    bool shouldAllowAccessToDOMWindow(BindingState*, DOMWindow*, String& message);
562

weinig@apple.com's avatar
weinig@apple.com committed
563
    void printErrorMessageForFrame(Frame*, const String& message);
564
    JSC::JSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);
weinig@apple.com's avatar
weinig@apple.com committed
565

566
    inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const String& s)
567 568 569 570 571
    {
        StringImpl* stringImpl = s.impl();
        if (!stringImpl || !stringImpl->length())
            return jsEmptyString(exec);

572
        if (stringImpl->length() == 1) {
573
            UChar singleCharacter = (*stringImpl)[0u];
574
            if (singleCharacter <= JSC::maxSingleCharacterString) {
ggaren@apple.com's avatar
ggaren@apple.com committed
575
                JSC::VM* vm = &exec->vm();
576
                return vm->smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
577 578
            }
        }
579

580
        JSStringCache& stringCache = currentWorld(exec).m_stringCache;
581 582 583 584
        JSStringCache::AddResult addResult = stringCache.add(stringImpl, nullptr);
        if (addResult.isNewEntry)
            addResult.iterator->value = JSC::jsString(exec, String(stringImpl));
        return JSC::JSValue(addResult.iterator->value.get());
585 586
    }

587
    inline String propertyNameToString(JSC::PropertyName propertyName)
588
    {
589
        return propertyName.publicName();
590 591
    }

592
    inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName)
593
    {
594
        return AtomicString(propertyName.publicName());
595 596
    }

597 598 599
    template <class ThisImp>
    inline const JSC::HashEntry* getStaticValueSlotEntryWithoutCaching(JSC::ExecState* exec, JSC::PropertyName propertyName)
    {
600
        const JSC::HashEntry* entry = ThisImp::info()->propHashTable(exec)->entry(exec, propertyName);
601 602 603 604 605 606 607 608 609 610 611
        if (!entry) // not found, forward to parent
            return getStaticValueSlotEntryWithoutCaching<typename ThisImp::Base>(exec, propertyName);
        return entry;
    }

    template <>
    inline const JSC::HashEntry* getStaticValueSlotEntryWithoutCaching<JSDOMWrapper>(JSC::ExecState*, JSC::PropertyName)
    {
        return 0;
    }

612 613 614 615 616 617 618
    template<typename T>
    class HasMemoryCostMemberFunction {
        typedef char YesType;
        struct NoType {
            char padding[8];
        };

619 620
        template<typename U>
        static decltype(static_cast<U*>(nullptr)->memoryCost(), YesType()) test(int);
621 622

        template<typename U>
623
        static NoType test(...);
624 625

    public:
626
        static const bool value = sizeof(test<T>(0)) == sizeof(YesType);
627
    };
628

629 630 631 632 633 634 635 636 637 638 639 640
    template <typename T, bool hasReportCostFunction = HasMemoryCostMemberFunction<T>::value > struct ReportMemoryCost;
    template <typename T> struct ReportMemoryCost<T, true> {
        static void reportMemoryCost(JSC::ExecState* exec, T* impl)
        {
            exec->heap()->reportExtraMemoryCost(impl->memoryCost());
        }
    };
    template <typename T> struct ReportMemoryCost<T, false> {
        static void reportMemoryCost(JSC::ExecState*, T*)
        {
        }
    };
641

weinig@apple.com's avatar
weinig@apple.com committed
642 643
} // namespace WebCore

darin@apple.com's avatar
darin@apple.com committed
644
#endif // JSDOMBinding_h