[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

commit-queue at webkit.org commit-queue at webkit.org
Wed Dec 22 11:29:57 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit dabc2ad5bc1a9eda470db2734f11cd4ca92726c0
Author: commit-queue at webkit.org <commit-queue at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Jul 27 15:37:25 2010 +0000

    2010-07-27  Caio Marcelo de Oliveira Filho  <caio.oliveira at openbossa.org>
    
            Reviewed by Kenneth Rohde Christiansen.
    
            [Qt] Implement QScriptEngine::newFunction() parts that doesn't depend on QScriptContext
            https://bugs.webkit.org/show_bug.cgi?id=42174
    
            Since our function can be called in Javascript both as a function
            and as a constructor, we couldn't use the existing
            JSObjectMakeFunctionWithCallback() and JSObjectMakeConstructor().
    
            Instead, a JSClassRef was created, implementing the needed
            callbacks (the callAsConstructor is not there yet because its
            behaviour depends on QScriptContext).
    
            For the moment, QScriptContext is defined as a void type, since we
            still don't use it.
    
            The variant of newFunction() that also takes an external argument
            was also implemented. The details of implementation were added to
            the qscriptfunction{.c,_p.h} files.
    
            This commit also adds tests, some of them from Qt's upstream.
    
            * api/QtScript.pro:
            * api/qscriptengine.cpp:
            (QScriptEngine::newFunction):
            * api/qscriptengine.h:
            * api/qscriptengine_p.cpp:
            (QScriptEnginePrivate::QScriptEnginePrivate):
            (QScriptEnginePrivate::~QScriptEnginePrivate):
            (QScriptEnginePrivate::newFunction):
            * api/qscriptengine_p.h:
            * api/qscriptfunction.cpp: Added.
            (qt_NativeFunction_finalize):
            (qt_NativeFunction_callAsFunction):
            (qt_NativeFunctionWithArg_finalize):
            (qt_NativeFunctionWithArg_callAsFunction):
            * api/qscriptfunction_p.h: Added.
            (QNativeFunctionData::QNativeFunctionData):
            (QNativeFunctionWithArgData::QNativeFunctionWithArgData):
            * api/qscriptoriginalglobalobject_p.h:
            (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject):
            (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject):
            (QScriptOriginalGlobalObject::functionPrototype):
            * tests/qscriptengine/tst_qscriptengine.cpp:
            (myFunction):
            (myFunctionWithArg):
            (myFunctionThatReturns):
            (myFunctionThatReturnsWithoutEngine):
            (myFunctionThatReturnsWrongEngine):
            (tst_QScriptEngine::newFunction):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64130 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/qt/ChangeLog b/JavaScriptCore/qt/ChangeLog
index 2303a53..5f71af5 100644
--- a/JavaScriptCore/qt/ChangeLog
+++ b/JavaScriptCore/qt/ChangeLog
@@ -1,3 +1,56 @@
+2010-07-27  Caio Marcelo de Oliveira Filho  <caio.oliveira at openbossa.org>
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        [Qt] Implement QScriptEngine::newFunction() parts that doesn't depend on QScriptContext
+        https://bugs.webkit.org/show_bug.cgi?id=42174
+
+        Since our function can be called in Javascript both as a function
+        and as a constructor, we couldn't use the existing
+        JSObjectMakeFunctionWithCallback() and JSObjectMakeConstructor().
+
+        Instead, a JSClassRef was created, implementing the needed
+        callbacks (the callAsConstructor is not there yet because its
+        behaviour depends on QScriptContext).
+
+        For the moment, QScriptContext is defined as a void type, since we
+        still don't use it.
+
+        The variant of newFunction() that also takes an external argument
+        was also implemented. The details of implementation were added to
+        the qscriptfunction{.c,_p.h} files.
+
+        This commit also adds tests, some of them from Qt's upstream.
+
+        * api/QtScript.pro:
+        * api/qscriptengine.cpp:
+        (QScriptEngine::newFunction):
+        * api/qscriptengine.h:
+        * api/qscriptengine_p.cpp:
+        (QScriptEnginePrivate::QScriptEnginePrivate):
+        (QScriptEnginePrivate::~QScriptEnginePrivate):
+        (QScriptEnginePrivate::newFunction):
+        * api/qscriptengine_p.h:
+        * api/qscriptfunction.cpp: Added.
+        (qt_NativeFunction_finalize):
+        (qt_NativeFunction_callAsFunction):
+        (qt_NativeFunctionWithArg_finalize):
+        (qt_NativeFunctionWithArg_callAsFunction):
+        * api/qscriptfunction_p.h: Added.
+        (QNativeFunctionData::QNativeFunctionData):
+        (QNativeFunctionWithArgData::QNativeFunctionWithArgData):
+        * api/qscriptoriginalglobalobject_p.h:
+        (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject):
+        (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject):
+        (QScriptOriginalGlobalObject::functionPrototype):
+        * tests/qscriptengine/tst_qscriptengine.cpp:
+        (myFunction):
+        (myFunctionWithArg):
+        (myFunctionThatReturns):
+        (myFunctionThatReturnsWithoutEngine):
+        (myFunctionThatReturnsWrongEngine):
+        (tst_QScriptEngine::newFunction):
+
 2010-07-23  Jedrzej Nowacki  <jedrzej.nowacki at nokia.com>
 
         Reviewed by Kenneth Rohde Christiansen.
diff --git a/JavaScriptCore/qt/api/QtScript.pro b/JavaScriptCore/qt/api/QtScript.pro
index c2c6f83..490758c 100644
--- a/JavaScriptCore/qt/api/QtScript.pro
+++ b/JavaScriptCore/qt/api/QtScript.pro
@@ -28,6 +28,7 @@ SOURCES +=  $$PWD/qscriptengine.cpp \
             $$PWD/qscriptstring.cpp \
             $$PWD/qscriptprogram.cpp \
             $$PWD/qscriptsyntaxcheckresult.cpp \
+            $$PWD/qscriptfunction.cpp
 
 HEADERS +=  $$PWD/qtscriptglobal.h \
             $$PWD/qscriptengine.h \
@@ -43,7 +44,7 @@ HEADERS +=  $$PWD/qtscriptglobal.h \
             $$PWD/qscriptprogram_p.h \
             $$PWD/qscriptsyntaxcheckresult.h \
             $$PWD/qscriptoriginalglobalobject_p.h \
-
+            $$PWD/qscriptfunction_p.h
 
 !static: DEFINES += QT_MAKEDLL
 
diff --git a/JavaScriptCore/qt/api/qscriptengine.cpp b/JavaScriptCore/qt/api/qscriptengine.cpp
index 4b2319b..7ef7c8e 100644
--- a/JavaScriptCore/qt/api/qscriptengine.cpp
+++ b/JavaScriptCore/qt/api/qscriptengine.cpp
@@ -258,6 +258,93 @@ QScriptValue QScriptEngine::undefinedValue()
 }
 
 /*!
+    Creates a QScriptValue that wraps a native (C++) function. \a fun
+    must be a C++ function with signature QScriptEngine::FunctionSignature.
+    \a length is the number of arguments that \a fun expects; this becomes
+    the \c{length} property of the created QScriptValue.
+
+    Note that \a length only gives an indication of the number of
+    arguments that the function expects; an actual invocation of a
+    function can include any number of arguments. You can check the
+    \l{QScriptContext::argumentCount()}{argumentCount()} of the
+    QScriptContext associated with the invocation to determine the
+    actual number of arguments passed.
+
+    A \c{prototype} property is automatically created for the resulting
+    function object, to provide for the possibility that the function
+    will be used as a constructor.
+
+    By combining newFunction() and the property flags
+    QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
+    can create script object properties that behave like normal
+    properties in script code, but are in fact accessed through
+    functions (analogous to how properties work in \l{Qt's Property
+    System}). Example:
+
+    \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11
+
+    When the property \c{foo} of the script object is subsequently
+    accessed in script code, \c{getSetFoo()} will be invoked to handle
+    the access.  In this particular case, we chose to store the "real"
+    value of \c{foo} as a property of the accessor function itself; you
+    are of course free to do whatever you like in this function.
+
+    In the above example, a single native function was used to handle
+    both reads and writes to the property; the argument count is used to
+    determine if we are handling a read or write. You can also use two
+    separate functions; just specify the relevant flag
+    (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
+    setting the property, e.g.:
+
+    \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12
+
+    \sa QScriptValue::call()
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
+{
+    return QScriptValuePrivate::get(d_ptr->newFunction(fun, 0, length));
+}
+
+/*!
+    Creates a constructor function from \a fun, with the given \a length.
+    The \c{prototype} property of the resulting function is set to be the
+    given \a prototype. The \c{constructor} property of \a prototype is
+    set to be the resulting function.
+
+    When a function is called as a constructor (e.g. \c{new Foo()}), the
+    `this' object associated with the function call is the new object
+    that the function is expected to initialize; the prototype of this
+    default constructed object will be the function's public
+    \c{prototype} property. If you always want the function to behave as
+    a constructor (e.g. \c{Foo()} should also create a new object), or
+    if you need to create your own object rather than using the default
+    `this' object, you should make sure that the prototype of your
+    object is set correctly; either by setting it manually, or, when
+    wrapping a custom type, by having registered the defaultPrototype()
+    of that type. Example:
+
+    \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9
+
+    To wrap a custom type and provide a constructor for it, you'd typically
+    do something like this:
+
+    \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, const QScriptValue& prototype, int length)
+{
+    return QScriptValuePrivate::get(d_ptr->newFunction(fun, QScriptValuePrivate::get(prototype), length));
+}
+
+/*!
+    \internal
+    \since 4.4
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg)
+{
+    return QScriptValuePrivate::get(d_ptr->newFunction(fun, arg));
+}
+
+/*!
   Creates a QtScript object of class Object.
 
   The prototype of the created object will be the Object
@@ -294,3 +381,23 @@ QScriptValue QScriptEngine::globalObject() const
 {
     return QScriptValuePrivate::get(d_ptr->globalObject());
 }
+
+/*!
+    \typedef QScriptEngine::FunctionSignature
+    \relates QScriptEngine
+
+    The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}.
+
+    A function with such a signature can be passed to
+    QScriptEngine::newFunction() to wrap the function.
+*/
+
+/*!
+    \typedef QScriptEngine::FunctionWithArgSignature
+    \relates QScriptEngine
+
+    The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}.
+
+    A function with such a signature can be passed to
+    QScriptEngine::newFunction() to wrap the function.
+*/
diff --git a/JavaScriptCore/qt/api/qscriptengine.h b/JavaScriptCore/qt/api/qscriptengine.h
index 1a87a37..b85dc52 100644
--- a/JavaScriptCore/qt/api/qscriptengine.h
+++ b/JavaScriptCore/qt/api/qscriptengine.h
@@ -30,6 +30,9 @@
 class QScriptValue;
 class QScriptEnginePrivate;
 
+// FIXME: Remove this once QScriptContext is properly defined.
+typedef void QScriptContext;
+
 // Internal typedef
 typedef QExplicitlySharedDataPointer<QScriptEnginePrivate> QScriptEnginePtr;
 
@@ -56,6 +59,14 @@ public:
 
     QScriptValue nullValue();
     QScriptValue undefinedValue();
+
+    typedef QScriptValue (*FunctionSignature)(QScriptContext *, QScriptEngine *);
+    typedef QScriptValue (*FunctionWithArgSignature)(QScriptContext *, QScriptEngine *, void *);
+
+    QScriptValue newFunction(FunctionSignature fun, int length = 0);
+    QScriptValue newFunction(FunctionSignature fun, const QScriptValue& prototype, int length = 0);
+    QScriptValue newFunction(FunctionWithArgSignature fun, void* arg);
+
     QScriptValue newObject();
     QScriptValue newArray(uint length = 0);
     QScriptValue globalObject() const;
diff --git a/JavaScriptCore/qt/api/qscriptengine_p.cpp b/JavaScriptCore/qt/api/qscriptengine_p.cpp
index e3311ed..a708a34 100644
--- a/JavaScriptCore/qt/api/qscriptengine_p.cpp
+++ b/JavaScriptCore/qt/api/qscriptengine_p.cpp
@@ -21,6 +21,7 @@
 
 #include "qscriptengine_p.h"
 
+#include "qscriptfunction_p.h"
 #include "qscriptprogram_p.h"
 #include "qscriptvalue_p.h"
 
@@ -33,11 +34,15 @@ QScriptEnginePrivate::QScriptEnginePrivate(const QScriptEngine* engine)
     , m_context(JSGlobalContextCreate(0))
     , m_exception(0)
     , m_originalGlobalObject(m_context)
+    , m_nativeFunctionClass(JSClassCreate(&qt_NativeFunctionClass))
+    , m_nativeFunctionWithArgClass(JSClassCreate(&qt_NativeFunctionWithArgClass))
 {
 }
 
 QScriptEnginePrivate::~QScriptEnginePrivate()
 {
+    JSClassRelease(m_nativeFunctionClass);
+    JSClassRelease(m_nativeFunctionWithArgClass);
     if (m_exception)
         JSValueUnprotect(m_context, m_exception);
     JSGlobalContextRelease(m_context);
@@ -86,6 +91,37 @@ QScriptValuePrivate* QScriptEnginePrivate::uncaughtException() const
     return m_exception ? new QScriptValuePrivate(this, m_exception) : new QScriptValuePrivate();
 }
 
+QScriptValuePrivate* QScriptEnginePrivate::newFunction(QScriptEngine::FunctionSignature fun, QScriptValuePrivate* prototype, int length)
+{
+    // Note that this private data will be deleted in the object finalize function.
+    QNativeFunctionData* data = new QNativeFunctionData(this, fun);
+    JSObjectRef funJS = JSObjectMake(m_context, m_nativeFunctionClass, reinterpret_cast<void*>(data));
+    QScriptValuePrivate* proto = prototype ? prototype : newObject();
+    return newFunction(funJS, proto);
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg)
+{
+    // Note that this private data will be deleted in the object finalize function.
+    QNativeFunctionWithArgData* data = new QNativeFunctionWithArgData(this, fun, arg);
+    JSObjectRef funJS = JSObjectMake(m_context, m_nativeFunctionWithArgClass, reinterpret_cast<void*>(data));
+    QScriptValuePrivate* proto = newObject();
+    return newFunction(funJS, proto);
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newFunction(JSObjectRef funJS, QScriptValuePrivate* prototype)
+{
+    JSObjectSetPrototype(m_context, funJS, m_originalGlobalObject.functionPrototype());
+
+    QScriptValuePrivate* result = new QScriptValuePrivate(this, funJS);
+    static JSStringRef protoName = QScriptConverter::toString("prototype");
+    static JSStringRef constructorName = QScriptConverter::toString("constructor");
+    result->setProperty(protoName, prototype, QScriptValue::Undeletable);
+    prototype->setProperty(constructorName, result, QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+
+    return result;
+}
+
 QScriptValuePrivate* QScriptEnginePrivate::newObject() const
 {
     return new QScriptValuePrivate(this, JSObjectMake(m_context, /* jsClass */ 0, /* userData */ 0));
diff --git a/JavaScriptCore/qt/api/qscriptengine_p.h b/JavaScriptCore/qt/api/qscriptengine_p.h
index d54cdcc..eec1929 100644
--- a/JavaScriptCore/qt/api/qscriptengine_p.h
+++ b/JavaScriptCore/qt/api/qscriptengine_p.h
@@ -71,6 +71,10 @@ public:
     inline JSValueRef makeJSValue(bool number) const;
     inline JSValueRef makeJSValue(QScriptValue::SpecialValue value) const;
 
+    QScriptValuePrivate* newFunction(QScriptEngine::FunctionSignature fun, QScriptValuePrivate* prototype, int length);
+    QScriptValuePrivate* newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg);
+    QScriptValuePrivate* newFunction(JSObjectRef funObject, QScriptValuePrivate* prototype);
+
     QScriptValuePrivate* newObject() const;
     QScriptValuePrivate* newArray(uint length);
     QScriptValuePrivate* globalObject() const;
@@ -89,6 +93,9 @@ private:
     JSValueRef m_exception;
 
     QScriptOriginalGlobalObject m_originalGlobalObject;
+
+    JSClassRef m_nativeFunctionClass;
+    JSClassRef m_nativeFunctionWithArgClass;
 };
 
 
diff --git a/JavaScriptCore/qt/api/qscriptfunction.cpp b/JavaScriptCore/qt/api/qscriptfunction.cpp
new file mode 100644
index 0000000..9fe37e6
--- /dev/null
+++ b/JavaScriptCore/qt/api/qscriptfunction.cpp
@@ -0,0 +1,145 @@
+/*
+    Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+// Contains the necessary helper structures to make possible expose
+// C/C++ functions to JavaScript environment.
+
+#include "config.h"
+
+#include "qscriptfunction_p.h"
+
+static void qt_NativeFunction_finalize(JSObjectRef object)
+{
+    void* priv = JSObjectGetPrivate(object);
+    delete reinterpret_cast<QNativeFunctionData*>(priv);
+}
+
+static JSValueRef qt_NativeFunction_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    QNativeFunctionData* data = reinterpret_cast<QNativeFunctionData*>(JSObjectGetPrivate(object));
+
+    // TODO: build a QScriptContext and use it in the native call.
+    QScriptContext* scriptContext = 0;
+    Q_UNUSED(context);
+    Q_UNUSED(thisObject);
+    Q_UNUSED(argumentCount);
+    Q_UNUSED(arguments);
+    Q_UNUSED(exception);
+
+    QScriptEnginePrivate* engine = data->engine;
+    QScriptValuePrivate* result = QScriptValuePrivate::get(data->fun(scriptContext, QScriptEnginePrivate::get(engine)));
+    if (!result->isValid()) {
+        qWarning("Invalid value returned from native function, returning undefined value instead.");
+        return engine->makeJSValue(QScriptValue::UndefinedValue);
+    }
+
+    // Make sure that the result will be assigned to the correct engine.
+    if (!result->engine()) {
+        Q_ASSERT(result->isValid());
+        result->assignEngine(engine);
+    } else if (result->engine() != engine) {
+        qWarning("Value from different engine returned from native function, returning undefined value instead.");
+        return engine->makeJSValue(QScriptValue::UndefinedValue);
+    }
+
+    return *result;
+}
+
+JSClassDefinition qt_NativeFunctionClass = {
+    0,                                     // version
+    kJSClassAttributeNoAutomaticPrototype, // attributes
+
+    "",                         // className
+    0,                          // parentClass
+
+    0,                          // staticValues
+    0,                          // staticFunctions
+
+    0,                                // initialize
+    qt_NativeFunction_finalize,       // finalize
+    0,                                // hasProperty
+    0,                                // getProperty
+    0,                                // setProperty
+    0,                                // deleteProperty
+    0,                                // getPropertyNames
+    qt_NativeFunction_callAsFunction, // callAsFunction
+    0,                                // callAsConstructor
+    0,                                // hasInstance
+    0                                 // convertToType
+};
+
+static void qt_NativeFunctionWithArg_finalize(JSObjectRef object)
+{
+    void* priv = JSObjectGetPrivate(object);
+    delete reinterpret_cast<QNativeFunctionWithArgData*>(priv);
+}
+
+static JSValueRef qt_NativeFunctionWithArg_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    QNativeFunctionWithArgData* data = reinterpret_cast<QNativeFunctionWithArgData*>(JSObjectGetPrivate(object));
+
+    // TODO: build a QScriptContext and use it in the native call.
+    QScriptContext* scriptContext = 0;
+    Q_UNUSED(context);
+    Q_UNUSED(thisObject);
+    Q_UNUSED(argumentCount);
+    Q_UNUSED(arguments);
+    Q_UNUSED(exception);
+
+    QScriptEnginePrivate* engine = data->engine;
+    QScriptValuePrivate* result = QScriptValuePrivate::get(data->fun(scriptContext, QScriptEnginePrivate::get(engine), data->arg));
+    if (!result->isValid()) {
+        qWarning("Invalid value returned from native function, returning undefined value instead.");
+        return engine->makeJSValue(QScriptValue::UndefinedValue);
+    }
+
+    // Make sure that the result will be assigned to the correct engine.
+    if (!result->engine()) {
+        Q_ASSERT(result->isValid());
+        result->assignEngine(engine);
+    } else if (result->engine() != engine) {
+        qWarning("Value from different engine returned from native function, returning undefined value instead.");
+        return engine->makeJSValue(QScriptValue::UndefinedValue);
+    }
+
+    return *result;
+}
+
+JSClassDefinition qt_NativeFunctionWithArgClass = {
+    0,                                     // version
+    kJSClassAttributeNoAutomaticPrototype, // attributes
+
+    "",                         // className
+    0,                          // parentClass
+
+    0,                          // staticValues
+    0,                          // staticFunctions
+
+    0,                                       // initialize
+    qt_NativeFunctionWithArg_finalize,       // finalize
+    0,                                       // hasProperty
+    0,                                       // getProperty
+    0,                                       // setProperty
+    0,                                       // deleteProperty
+    0,                                       // getPropertyNames
+    qt_NativeFunctionWithArg_callAsFunction, // callAsFunction
+    0,                                       // callAsConstructor
+    0,                                       // hasInstance
+    0                                        // convertToType
+};
diff --git a/JavaScriptCore/qt/api/qscriptfunction_p.h b/JavaScriptCore/qt/api/qscriptfunction_p.h
new file mode 100644
index 0000000..65b6046
--- /dev/null
+++ b/JavaScriptCore/qt/api/qscriptfunction_p.h
@@ -0,0 +1,57 @@
+/*
+    Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef qscriptfunction_p_h
+#define qscriptfunction_p_h
+
+#include "config.h"
+
+#include "qscriptengine.h"
+#include "qscriptvalue_p.h"
+
+extern JSClassDefinition qt_NativeFunctionClass;
+extern JSClassDefinition qt_NativeFunctionWithArgClass;
+
+struct QNativeFunctionData
+{
+    QNativeFunctionData(QScriptEnginePrivate* engine, QScriptEngine::FunctionSignature fun)
+        : engine(engine)
+        , fun(fun)
+    {
+    }
+
+    QScriptEnginePrivate* engine;
+    QScriptEngine::FunctionSignature fun;
+};
+
+struct QNativeFunctionWithArgData
+{
+    QNativeFunctionWithArgData(QScriptEnginePrivate* engine, QScriptEngine::FunctionWithArgSignature fun, void* arg)
+        : engine(engine)
+        , fun(fun)
+        , arg(arg)
+    {
+    }
+
+    QScriptEnginePrivate* engine;
+    QScriptEngine::FunctionWithArgSignature fun;
+    void* arg;
+};
+
+#endif
diff --git a/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h b/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h
index 8d080fb..31e94f7 100644
--- a/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h
+++ b/JavaScriptCore/qt/api/qscriptoriginalglobalobject_p.h
@@ -45,6 +45,8 @@ public:
 
     inline bool isArray(JSValueRef value) const;
     inline bool isError(JSValueRef value) const;
+
+    inline JSValueRef functionPrototype() const;
 private:
     inline bool isType(JSValueRef value, JSObjectRef constructor, JSValueRef prototype) const;
     inline void initializeMember(JSObjectRef globalObject, JSStringRef prototypeName, const char* type, JSObjectRef& constructor, JSValueRef& prototype);
@@ -57,6 +59,8 @@ private:
     JSValueRef m_arrayPrototype;
     JSObjectRef m_errorConstructor;
     JSValueRef m_errorPrototype;
+    JSObjectRef m_functionConstructor;
+    JSValueRef m_functionPrototype;
 
     // Reference to standard JS functions that are not exposed by JSC C API.
     JSObjectRef m_hasOwnPropertyFunction;
@@ -73,6 +77,7 @@ QScriptOriginalGlobalObject::QScriptOriginalGlobalObject(JSGlobalContextRef cont
     propertyName.adopt(JSStringCreateWithUTF8CString("prototype"));
     initializeMember(globalObject, propertyName.get(), "Array", m_arrayConstructor, m_arrayPrototype);
     initializeMember(globalObject, propertyName.get(), "Error", m_errorConstructor, m_errorPrototype);
+    initializeMember(globalObject, propertyName.get(), "Function", m_functionConstructor, m_functionPrototype);
 
     propertyName.adopt(JSStringCreateWithUTF8CString("hasOwnProperty"));
     m_hasOwnPropertyFunction = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, globalObject, propertyName.get(), &exception));
@@ -119,6 +124,8 @@ QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject()
     JSValueUnprotect(m_context, m_arrayPrototype);
     JSValueUnprotect(m_context, m_errorConstructor);
     JSValueUnprotect(m_context, m_errorPrototype);
+    JSValueUnprotect(m_context, m_functionConstructor);
+    JSValueUnprotect(m_context, m_functionPrototype);
     JSValueUnprotect(m_context, m_hasOwnPropertyFunction);
     JSValueUnprotect(m_context, m_getOwnPropertyNamesFunction);
     JSGlobalContextRelease(m_context);
@@ -173,6 +180,11 @@ inline bool QScriptOriginalGlobalObject::isError(JSValueRef value) const
     return isType(value, m_errorConstructor, m_errorPrototype);
 }
 
+inline JSValueRef QScriptOriginalGlobalObject::functionPrototype() const
+{
+    return m_functionPrototype;
+}
+
 inline bool QScriptOriginalGlobalObject::isType(JSValueRef value, JSObjectRef constructor, JSValueRef prototype) const
 {
     // JSC API doesn't export the [[Class]] information for the builtins. But we know that a value
diff --git a/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp b/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp
index 72ca9b1..58a1587 100644
--- a/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp
+++ b/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp
@@ -35,6 +35,7 @@ public slots:
     void cleanup() {}
 
 private slots:
+    void newFunction();
     void newObject();
     void globalObject();
     void evaluate();
@@ -59,6 +60,146 @@ void tst_QScriptEngine::evaluate()
     QVERIFY2(engine.evaluate("ping").isValid(), "Script throwing an unhandled exception should return an exception value");
 }
 
+static QScriptValue myFunction(QScriptContext*, QScriptEngine* eng)
+{
+    return eng->nullValue();
+}
+
+static QScriptValue myFunctionWithArg(QScriptContext*, QScriptEngine* eng, void* arg)
+{
+    int* result = reinterpret_cast<int*>(arg);
+    return QScriptValue(eng, *result);
+}
+
+static QScriptValue myFunctionThatReturns(QScriptContext*, QScriptEngine* eng)
+{
+    return QScriptValue(eng, 42);
+}
+
+static QScriptValue myFunctionThatReturnsWithoutEngine(QScriptContext*, QScriptEngine*)
+{
+    return QScriptValue(1024);
+}
+
+static QScriptValue myFunctionThatReturnsWrongEngine(QScriptContext*, QScriptEngine*, void* arg)
+{
+    QScriptEngine* wrongEngine = reinterpret_cast<QScriptEngine*>(arg);
+    return QScriptValue(wrongEngine, 42);
+}
+
+void tst_QScriptEngine::newFunction()
+{
+    QScriptEngine eng;
+    {
+        QScriptValue fun = eng.newFunction(myFunction);
+        QCOMPARE(fun.isValid(), true);
+        QCOMPARE(fun.isFunction(), true);
+        QCOMPARE(fun.isObject(), true);
+        // QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+        // a prototype property is automatically constructed
+        {
+            QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+            QVERIFY(prot.isObject());
+            QVERIFY(prot.property("constructor").strictlyEquals(fun));
+            QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue);
+            QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
+            QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+            QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+        }
+        // prototype should be Function.prototype
+        QCOMPARE(fun.prototype().isValid(), true);
+        QCOMPARE(fun.prototype().isFunction(), true);
+        QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+        QCOMPARE(fun.call().isNull(), true);
+        // QCOMPARE(fun.construct().isObject(), true);
+    }
+    // the overload that takes an extra argument
+    {
+        int expectedResult = 42;
+        QScriptValue fun = eng.newFunction(myFunctionWithArg, reinterpret_cast<void*>(&expectedResult));
+        QVERIFY(fun.isFunction());
+        // QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+        // a prototype property is automatically constructed
+        {
+            QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+            QVERIFY(prot.isObject());
+            QVERIFY(prot.property("constructor").strictlyEquals(fun));
+            QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue);
+            QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
+            QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+            QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+        }
+        // prototype should be Function.prototype
+        QCOMPARE(fun.prototype().isValid(), true);
+        QCOMPARE(fun.prototype().isFunction(), true);
+        QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+        QScriptValue result = fun.call();
+        QCOMPARE(result.isNumber(), true);
+        QCOMPARE(result.toInt32(), expectedResult);
+    }
+    // the overload that takes a prototype
+    {
+        QScriptValue proto = eng.newObject();
+        QScriptValue fun = eng.newFunction(myFunction, proto);
+        QCOMPARE(fun.isValid(), true);
+        QCOMPARE(fun.isFunction(), true);
+        QCOMPARE(fun.isObject(), true);
+        // internal prototype should be Function.prototype
+        QCOMPARE(fun.prototype().isValid(), true);
+        QCOMPARE(fun.prototype().isFunction(), true);
+        QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+        // public prototype should be the one we passed
+        QCOMPARE(fun.property("prototype").strictlyEquals(proto), true);
+        QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue);
+        QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
+        QCOMPARE(proto.property("constructor").strictlyEquals(fun), true);
+        QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+        QCOMPARE(proto.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+
+        QCOMPARE(fun.call().isNull(), true);
+        // QCOMPARE(fun.construct().isObject(), true);
+    }
+    // whether the return value is correct
+    {
+        QScriptValue fun = eng.newFunction(myFunctionThatReturns);
+        QCOMPARE(fun.isValid(), true);
+        QCOMPARE(fun.isFunction(), true);
+        QCOMPARE(fun.isObject(), true);
+
+        QScriptValue result = fun.call();
+        QCOMPARE(result.isNumber(), true);
+        QCOMPARE(result.toInt32(), 42);
+    }
+    // whether the return value is assigned to the correct engine
+    {
+        QScriptValue fun = eng.newFunction(myFunctionThatReturnsWithoutEngine);
+        QCOMPARE(fun.isValid(), true);
+        QCOMPARE(fun.isFunction(), true);
+        QCOMPARE(fun.isObject(), true);
+
+        QScriptValue result = fun.call();
+        QCOMPARE(result.engine(), &eng);
+        QCOMPARE(result.isNumber(), true);
+        QCOMPARE(result.toInt32(), 1024);
+    }
+    // whether the return value is undefined when returning a value with wrong engine
+    {
+        QScriptEngine wrongEngine;
+
+        QScriptValue fun = eng.newFunction(myFunctionThatReturnsWrongEngine, reinterpret_cast<void*>(&wrongEngine));
+        QCOMPARE(fun.isValid(), true);
+        QCOMPARE(fun.isFunction(), true);
+        QCOMPARE(fun.isObject(), true);
+
+        QTest::ignoreMessage(QtWarningMsg, "Value from different engine returned from native function, returning undefined value instead.");
+        QScriptValue result = fun.call();
+        QCOMPARE(result.isValid(), true);
+        QCOMPARE(result.isUndefined(), true);
+    }
+}
+
 void tst_QScriptEngine::newObject()
 {
     QScriptEngine engine;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list