File indexing completed on 2024-05-12 04:33:31

0001 /*
0002     SPDX-FileCopyrightText: 2008 Pino Toscano <pino@kde.org>
0003     SPDX-FileCopyrightText: 2008 Harri Porten <porten@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "config-okular.h"
0009 #include "executor_js_p.h"
0010 
0011 #include "../debug_p.h"
0012 #include "../document_p.h"
0013 
0014 #include "event_p.h"
0015 #include "js_app_p.h"
0016 #include "js_console_p.h"
0017 #include "js_data_p.h"
0018 #include "js_display_p.h"
0019 #include "js_document_p.h"
0020 #include "js_event_p.h"
0021 #include "js_field_p.h"
0022 #include "js_fullscreen_p.h"
0023 #include "js_ocg_p.h"
0024 #include "js_spell_p.h"
0025 #include "js_util_p.h"
0026 
0027 #include <QDebug>
0028 #include <QJSEngine>
0029 #include <QThread>
0030 #include <QTimer>
0031 
0032 using namespace Okular;
0033 
0034 class Okular::ExecutorJSPrivate
0035 {
0036 public:
0037     explicit ExecutorJSPrivate(DocumentPrivate *doc)
0038         : m_doc(doc)
0039     {
0040         initTypes();
0041     }
0042     ~ExecutorJSPrivate()
0043     {
0044         m_watchdogTimer->deleteLater();
0045         m_watchdogThread.quit();
0046         m_watchdogThread.wait();
0047     }
0048 
0049     void initTypes();
0050 
0051     DocumentPrivate *m_doc;
0052     QJSEngine m_interpreter;
0053 
0054     QThread m_watchdogThread;
0055     QTimer *m_watchdogTimer = nullptr;
0056 };
0057 
0058 void ExecutorJSPrivate::initTypes()
0059 {
0060     m_watchdogThread.start();
0061     m_watchdogTimer = new QTimer;
0062     m_watchdogTimer->setInterval(std::chrono::seconds(2)); // max 2 secs allowed
0063     m_watchdogTimer->setSingleShot(true);
0064     m_watchdogTimer->moveToThread(&m_watchdogThread);
0065     QObject::connect(
0066         m_watchdogTimer, &QTimer::timeout, &m_interpreter, [this]() { m_interpreter.setInterrupted(true); }, Qt::DirectConnection);
0067 
0068     m_interpreter.globalObject().setProperty(QStringLiteral("app"), m_interpreter.newQObject(new JSApp(m_doc, m_watchdogTimer)));
0069     m_interpreter.globalObject().setProperty(QStringLiteral("console"), m_interpreter.newQObject(new JSConsole));
0070     m_interpreter.globalObject().setProperty(QStringLiteral("Doc"), m_interpreter.newQObject(new JSDocument(m_doc)));
0071     m_interpreter.globalObject().setProperty(QStringLiteral("display"), m_interpreter.newQObject(new JSDisplay));
0072     m_interpreter.globalObject().setProperty(QStringLiteral("spell"), m_interpreter.newQObject(new JSSpell));
0073     m_interpreter.globalObject().setProperty(QStringLiteral("util"), m_interpreter.newQObject(new JSUtil));
0074 }
0075 
0076 ExecutorJS::ExecutorJS(DocumentPrivate *doc)
0077     : d(new ExecutorJSPrivate(doc))
0078 {
0079 }
0080 
0081 ExecutorJS::~ExecutorJS()
0082 {
0083     JSField::clearCachedFields();
0084     JSApp::clearCachedFields();
0085     delete d;
0086 }
0087 
0088 void ExecutorJS::execute(const QString &script, Event *event)
0089 {
0090     const auto eventVal = event ? d->m_interpreter.newQObject(new JSEvent(event)) : QJSValue(QJSValue::UndefinedValue);
0091     d->m_interpreter.globalObject().setProperty(QStringLiteral("event"), eventVal);
0092 
0093     QMetaObject::invokeMethod(d->m_watchdogTimer, qOverload<>(&QTimer::start));
0094     d->m_interpreter.setInterrupted(false);
0095     auto result = d->m_interpreter.evaluate(script, QStringLiteral("okular.js"));
0096     QMetaObject::invokeMethod(d->m_watchdogTimer, qOverload<>(&QTimer::stop));
0097 
0098     if (result.isError()) {
0099         qCDebug(OkularCoreDebug) << "JS exception" << result.toString() << "(line " << result.property(QStringLiteral("lineNumber")).toInt() << ")";
0100     } else {
0101         qCDebug(OkularCoreDebug) << "result:" << result.toString();
0102 
0103         if (event) {
0104             qCDebug(OkularCoreDebug) << "Event Result:" << event->name() << event->type() << "value:" << event->value();
0105         }
0106     }
0107 }