diff --git a/src/js/console.cpp b/src/js/console.cpp new file mode 100644 index 0000000000..aaf52d9f49 --- /dev/null +++ b/src/js/console.cpp @@ -0,0 +1,61 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2013 execjosh, http://execjosh.blogspot.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "console.h" + +#include +#include + +namespace JS +{ + +// public: + +Console::Console(QObject *parent) + : QObject(parent) +{ +} + +Console::~Console() +{ +} + +// public slots: + +void Console::log(const QVariant &val) +{ + QStringList strList; + strList << "[CONSOLE.LOG]"; + strList << val.toString(); + std::cout << qPrintable(strList.join(' ')) << std::endl; +} + +}; + +// vim:ts=4:sw=4:sts=4:et: diff --git a/src/js/console.h b/src/js/console.h new file mode 100644 index 0000000000..5086fba852 --- /dev/null +++ b/src/js/console.h @@ -0,0 +1,54 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2013 execjosh, http://execjosh.blogspot.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef JS_CONSOLE_H +#define JS_CONSOLE_H + +#include +#include + +namespace JS +{ + class Console : public QObject + { + Q_OBJECT + + public: + explicit Console(QObject *parent = 0); + virtual ~Console(); + + public slots: + void log(const QVariant &val); + }; + +}; + +#endif // JS_CONSOLE_H + +// vim:ts=4:sw=4:sts=4:et: diff --git a/src/js/pjsengine.cpp b/src/js/pjsengine.cpp new file mode 100644 index 0000000000..0f63b0b160 --- /dev/null +++ b/src/js/pjsengine.cpp @@ -0,0 +1,178 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2013 execjosh, http://execjosh.blogspot.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "pjsengine.h" + +#include +#include +#include +#include + +namespace JS +{ + +// public: + +PJSEngine::PJSEngine(QObject *parent) + : QObject(parent) + , m_initialized(false) + , m_terminated(false) + , m_js((QJSEngine *) NULL) + , m_console((JS::Console *) NULL) + , m_timers() +{ +} + +PJSEngine::~PJSEngine() +{ + qDeleteAll(m_timers); +} + +bool PJSEngine::init() +{ + // Bail out if already initialized + if (m_initialized) { + return false; + } + + if ((QJSEngine *) NULL == m_js) { + m_js = new QJSEngine(this); + } + + if ((JS::Console *) NULL == m_console) { + m_console = new JS::Console(this); + QJSValue console = m_js->newQObject(m_console); + m_js->globalObject().setProperty("console", console); + } + + QJSValue me = m_js->newQObject(this); + + m_js->globalObject().setProperty("_createSingleShotTimer", me.property("createSingleShotTimer")); + m_js->globalObject().setProperty("_createRepeatingTimer", me.property("createRepeatingTimer")); + QJSValue timerFuncs = m_js->evaluate( + "(function () {" + "function timerFunc(timerFactory) {" + "return function (cb, ms) {" + "var t = timerFactory(ms);" + "t.timeout.connect(cb);" + "return t.timerId;" + "};" + "}" + "return {" + " setTimeout: timerFunc(_createSingleShotTimer)" + ",setInterval: timerFunc(_createRepeatingTimer)" + "};" + "}())" + ); + m_js->globalObject().setProperty("setTimeout", timerFuncs.property("setTimeout")); + m_js->globalObject().setProperty("setInterval", timerFuncs.property("setInterval")); + m_js->globalObject().setProperty("clearTimeout", me.property("clearTimer")); + m_js->globalObject().setProperty("clearInterval", me.property("clearTimer")); + + QJSValue phantom = m_js->newObject(); + phantom.setProperty("exit", me.property("exit")); + m_js->globalObject().setProperty("phantom", phantom); + + m_initialized = true; + + return true; +} + +void PJSEngine::evaluate(const QString &src, const QString &file) +{ + if (!m_initialized) { + return; + } + + QJSValue result = m_js->evaluate(src, file); + if (result.isError()) { + qDebug() << "uncaught exception:" << result.toString(); + } +} + +// public slots: + +void PJSEngine::exit(int code) +{ + // TODO + std::cerr << "EXIT(" << code << ")" << std::endl; + QApplication::instance()->exit(code); +} + +bool PJSEngine::isTerminated() const +{ + return m_terminated; +} + +QObject *PJSEngine::createSingleShotTimer(int ms) +{ + return _createTimer(ms, true); +} + +QObject *PJSEngine::createRepeatingTimer(int ms) +{ + return _createTimer(ms, false); +} + +void PJSEngine::clearTimer(int id) +{ + // TODO: how to prevent double kills? + QObject::killTimer(id); + m_timers.remove(id); +} + +void PJSEngine::timerEvent(QTimerEvent *e) +{ + int id = e->timerId(); + JS::TimerContext *tc = m_timers.value(id); + if (-1 == tc->timerId()) { + QObject::killTimer(id); + } else if (tc->isSingleShot()) { + clearTimer(id); + tc->invokeTimeout(); + tc->deleteLater(); + } else { + tc->invokeTimeout(); + } +} + +// private: + +QObject *PJSEngine::_createTimer(int ms, bool isSingleShot) +{ + // TODO: Use Qt::CoarseTimer for long timeouts? + Qt::TimerType timerType = Qt::PreciseTimer; + JS::TimerContext *tc = new JS::TimerContext(QObject::startTimer(ms, timerType), isSingleShot, this); + m_timers.insert(tc->timerId(), tc); + return tc; +} + +}; + +// vim:ts=4:sw=4:sts=4:et: diff --git a/src/js/pjsengine.h b/src/js/pjsengine.h new file mode 100644 index 0000000000..e6927b5d69 --- /dev/null +++ b/src/js/pjsengine.h @@ -0,0 +1,82 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2013 execjosh, http://execjosh.blogspot.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef JS_PJSENGINE_H +#define JS_PJSENGINE_H + +#include +#include +#include + +#include "console.h" +#include "timercontext.h" + +namespace JS +{ + +class PJSEngine : public QObject +{ + Q_OBJECT + +public: + explicit PJSEngine(QObject *parent = 0); + virtual ~PJSEngine(); + + bool init(); + void evaluate(const QString &src, const QString &file = ""); + +signals: + +public slots: + void exit(int code = 0); + bool isTerminated() const; + + // Timeout stuff + QObject *createSingleShotTimer(int ms); + QObject *createRepeatingTimer(int ms); + void clearTimer(int id); + +protected: + void timerEvent(QTimerEvent *e); + +private: + QObject *_createTimer(int ms, bool isSingleShot); + + bool m_initialized; + bool m_terminated; + QJSEngine *m_js; + JS::Console *m_console; + QMap m_timers; +}; + +}; + +#endif // JS_PJSENGINE_H + +// vim:ts=4:sw=4:sts=4:et: diff --git a/src/js/timercontext.cpp b/src/js/timercontext.cpp new file mode 100644 index 0000000000..d7c8253b11 --- /dev/null +++ b/src/js/timercontext.cpp @@ -0,0 +1,70 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2013 execjosh, http://execjosh.blogspot.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "timercontext.h" + +namespace JS +{ + +static const int INV_TIMER = -1; + +// public: + +TimerContext::TimerContext(int id, bool isSingleShot, QObject *parent) + : QObject(parent) + , m_id(id) + , m_ss(isSingleShot) +{ +} + +TimerContext::~TimerContext() +{ + m_id = INV_TIMER; +} + +void TimerContext::invokeTimeout() const +{ + emit timeout(); +} + +// public slots: + +int TimerContext::timerId() const +{ + return m_id; +} + +bool TimerContext::isSingleShot() const +{ + return m_ss; +} + +}; + +// vim:ts=4:sw=4:sts=4:et: diff --git a/src/js/timercontext.h b/src/js/timercontext.h new file mode 100644 index 0000000000..68c8c85a44 --- /dev/null +++ b/src/js/timercontext.h @@ -0,0 +1,65 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2013 execjosh, http://execjosh.blogspot.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef JS_TIMERCONTEXT_H +#define JS_TIMERCONTEXT_H + +#include + +namespace JS +{ + +class TimerContext : public QObject +{ + Q_OBJECT + Q_PROPERTY(int timerId READ timerId) + +public: + explicit TimerContext(int id, bool isSingleShot, QObject *parent = 0); + virtual ~TimerContext(); + + void invokeTimeout() const; + +signals: + void timeout() const; + +public slots: + int timerId() const; + bool isSingleShot() const; + +private: + int m_id; + bool m_ss; +}; + +}; + +#endif // JS_TIMERCONTEXT_H + +// vim:ts=4:sw=4:sts=4:et: diff --git a/src/main.cpp b/src/main.cpp index a143878da8..6e269cd615 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,56 @@ */ #include "consts.h" + +#include +#include + +#include "js/pjsengine.h" + +int main(int argc, char** argv, const char** envp) +{ + Q_UNUSED(envp) + + QApplication app(argc, argv); + + app.setWindowIcon(QIcon(":/phantomjs-icon.png")); + app.setApplicationName("PhantomJS"); + app.setOrganizationName("Ofi Labs"); + app.setOrganizationDomain("www.ofilabs.com"); + app.setApplicationVersion(PHANTOMJS_VERSION_STRING); + + JS::PJSEngine pjse(&app); + + if (!pjse.init()) { + return -1; + } + + pjse.evaluate( + "var timeoutId = setTimeout(function () {" + "console.log('Hello, ' + timeoutId + '!');" + "phantom.exit(0);" + "}, 3000);" + "var omfg = 5;" + "var intervalId = setInterval(function () {" + "if (--omfg) {" + "console.log('' + intervalId + ' ' + omfg);" + "} else {" + "clearInterval(intervalId);" + "console.log('' + intervalId + ' ' + omfg + ' -- clearInterval');" + "}" + "}, 300);" + ); + + if (pjse.isTerminated()) { + // TODO: return value... + return 0; + } + + // TODO: return value... + return app.exec(); +} + +/* #include "utils.h" #include "env.h" #include "phantom.h" @@ -123,3 +173,4 @@ int main(int argc, char** argv, const char** envp) delete phantom; return retVal; } +*/ diff --git a/src/phantomjs.pro b/src/phantomjs.pro index 9471fbc557..5647a426dd 100644 --- a/src/phantomjs.pro +++ b/src/phantomjs.pro @@ -13,6 +13,9 @@ RESOURCES = phantomjs.qrc \ HEADERS += csconverter.h \ phantom.h \ + js/pjsengine.h \ + js/console.h \ + js/timercontext.h \ callback.h \ webpage.h \ webserver.h \ @@ -30,6 +33,9 @@ HEADERS += csconverter.h \ repl.h SOURCES += phantom.cpp \ + js/pjsengine.cpp \ + js/console.cpp \ + js/timercontext.cpp \ callback.cpp \ webpage.cpp \ webserver.cpp \