1 /* This file is part of the KDE libraries
2     Copyright (C) 2005, 2006 Ian Reinhart Geiser <geiseri@kde.org>
3     Copyright (C) 2005, 2006 Matt Broadstone <mbroadst@gmail.com>
4     Copyright (C) 2005, 2006 Richard J. Moore <rich@kde.org>
5     Copyright (C) 2005, 2006 Erik L. Bunce <kde@bunce.us>
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16 
17     You should have received a copy of the GNU Library General Public License
18     along with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20     Boston, MA 02110-1301, USA.
21 */
22 #include "kjsembed.h"
23 #include "binding_support.h"
24 
25 #include "qobject_binding.h"
26 #include "variant_binding.h"
27 #include "static_binding.h"
28 
29 #include "iosupport.h"
30 #include "quiloader_binding.h"
31 #ifdef KJSEMBED_FORMBUILDER_BINDING
32 #include "qformbuilder_binding.h"
33 #endif
34 #include "qpainter_binding.h"
35 #include "qwidget_binding.h"
36 #include "qaction_binding.h"
37 #include "qlayout_binding.h"
38 #include "svg_binding.h"
39 #include "filedialog_binding.h"
40 #include "settings.h"
41 #include "fileio.h"
42 #include "color.h"
43 #include "rect.h"
44 #include "size.h"
45 #include "point.h"
46 #include "image.h"
47 #include "pixmap.h"
48 #include "brush.h"
49 #include "pen.h"
50 #include "font.h"
51 #include "dom.h"
52 #include "url.h"
53 #include "application.h"
54 
55 #include "builtins.h"
56 
57 #include <kjs/interpreter.h>
58 #include <kjs/completion.h>
59 
60 #include <QFile>
61 #include <QTextStream>
62 #include <QObject>
63 
64 #include <QDebug>
65 
66 /**
67 * Implement QString-KJS::UString conversion methods. These methods are declared
68 * by KJS, but libkjs doesn't actually contain their implementations.
69 * because we link against khtml , those functions are already implemented there.
70 *
71 */
72 namespace KJS
73 {
74 #ifndef QTONLY_WEBKIT
UString(const QString & d)75 UString::UString(const QString &d)
76 {
77     uint len = d.length();
78     UChar *dat = static_cast<UChar *>(fastMalloc(sizeof(UChar) * len));
79     memcpy(dat, d.unicode(), len * sizeof(UChar));
80     m_rep = UString::Rep::create(dat, len);
81 }
82 
qstring() const83 QString UString::qstring() const
84 {
85     return QString((QChar *) data(), size());
86 }
87 
qstring() const88 QString Identifier::qstring() const
89 {
90     return QString((QChar *) data(), size());
91 }
92 #endif
93 }
94 
95 namespace KJSEmbed
96 {
97 
98 class EnginePrivate
99 {
100 public:
EnginePrivate()101     EnginePrivate()
102     {
103         m_interpreter = new KJS::Interpreter();
104         m_interpreter->initGlobalObject();
105         m_interpreter->ref();
106     }
~EnginePrivate()107     ~EnginePrivate()
108     {
109         m_interpreter->deref();
110     }
111     KJS::Interpreter *m_interpreter;
112     KJS::Completion m_currentResult;
113     bool m_bindingsEnabled;
114 };
115 
setup(KJS::ExecState * exec,KJS::JSObject * parent)116 void setup(KJS::ExecState *exec, KJS::JSObject *parent)
117 {
118     StaticBinding::publish(exec, parent, IoFactory::methods());   // Global methods
119     StaticBinding::publish(exec, parent, FileDialog::methods());   // Global methods
120     StaticBinding::publish(exec, parent, BuiltinsFactory::methods());   // Global methods
121     StaticConstructor::add(exec, parent, FileIO::constructor());   // Ctor
122     StaticConstructor::add(exec, parent, DomNode::constructor());   // Ctor
123     StaticConstructor::add(exec, parent, DomDocument::constructor());   // Ctor
124     StaticConstructor::add(exec, parent, DomElement::constructor());   // Ctor
125     StaticConstructor::add(exec, parent, DomAttr::constructor());   // Ctor
126     StaticConstructor::add(exec, parent, DomDocumentType::constructor());   // Ctor
127     StaticConstructor::add(exec, parent, DomNodeList::constructor());   // Ctor
128     StaticConstructor::add(exec, parent, DomNamedNodeMap::constructor());   // Ctor
129     StaticConstructor::add(exec, parent, DomText::constructor());   // Ctor
130     StaticConstructor::add(exec, parent, Url::constructor());   // Ctor
131     StaticConstructor::add(exec, parent, SettingsBinding::constructor());   // Ctor
132     StaticConstructor::add(exec, parent, CoreApplicationBinding::constructor());
133     StaticConstructor::add(exec, parent, Point::constructor());   // Ctor
134     StaticConstructor::add(exec, parent, Size::constructor());   // Ctor
135     StaticConstructor::add(exec, parent, Rect::constructor());   // Ctor
136     StaticConstructor::add(exec, parent, Color::constructor());   // Ctor
137 
138     // check if this is a GUI application
139     QApplication *app = ::qobject_cast<QApplication *>(QCoreApplication::instance());
140     if (app) {
141         //qDebug("Loading GUI Bindings");
142 
143 #ifdef KJSEMBED_FORMBUILDER_BINDING
144         StaticConstructor::add(exec, parent, FormBuilder::constructor());   // Ctor
145 #endif
146         StaticConstructor::add(exec, parent, UiLoaderBinding::constructor());   // Ctor
147         StaticConstructor::add(exec, parent, QWidgetBinding::constructor());   // Ctor
148         StaticConstructor::add(exec, parent, Layout::constructor());   // Ctor
149         StaticConstructor::add(exec, parent, Action::constructor());   // Ctor
150         StaticConstructor::add(exec, parent, ActionGroup::constructor());   // Ctor
151         StaticConstructor::add(exec, parent, Font::constructor());   // Ctor
152         StaticConstructor::add(exec, parent, Pen::constructor());   // Ctor
153         StaticConstructor::add(exec, parent, Brush::constructor());   // Ctor
154         StaticConstructor::add(exec, parent, Image::constructor());   // Ctor
155         StaticConstructor::add(exec, parent, Pixmap::constructor());   // Ctor
156         StaticConstructor::add(exec, parent, Painter::constructor());   // Ctor
157         StaticConstructor::add(exec, parent, SvgRenderer::constructor());   // Ctor
158         StaticConstructor::add(exec, parent, SvgWidget::constructor());   // Ctor
159         StaticConstructor::add(exec, parent, ApplicationBinding::constructor());
160     }
161 }
162 
Engine(bool enableBindings)163 Engine::Engine(bool enableBindings)
164 {
165     dptr = new EnginePrivate();
166     if (enableBindings) {
167         setup(dptr->m_interpreter->globalExec(), dptr->m_interpreter->globalObject());
168     }
169     dptr->m_bindingsEnabled =  enableBindings;
170 }
171 
~Engine()172 Engine::~Engine()
173 {
174     delete dptr;
175 }
176 
isBindingsEnabled() const177 bool Engine::isBindingsEnabled() const
178 {
179     return dptr->m_bindingsEnabled;
180 }
181 
addObject(QObject * obj,KJS::JSObject * parent,const KJS::UString & name) const182 KJS::JSObject *Engine::addObject(QObject *obj, KJS::JSObject *parent, const KJS::UString &name) const
183 {
184     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
185     KJS::JSObject *returnObject = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::CPPOwned);
186     KJS::Identifier jsName(!name.isEmpty() ? name : toUString(obj->objectName()));
187 
188     parent->putDirect(jsName, returnObject, KJS::DontDelete | KJS::ReadOnly);
189     return returnObject;
190 }
191 
addObject(QObject * obj,const KJS::UString & name) const192 KJS::JSObject *Engine::addObject(QObject *obj, const KJS::UString &name) const
193 {
194     return addObject(obj, dptr->m_interpreter->globalObject(), name);
195 }
196 
completion() const197 KJS::Completion Engine::completion() const
198 {
199     return dptr->m_currentResult;
200 }
201 
interpreter() const202 KJS::Interpreter *Engine::interpreter() const
203 {
204     return dptr->m_interpreter;
205 }
206 
runFile(KJS::Interpreter * interpreter,const KJS::UString & fileName)207 KJS::Completion Engine::runFile(KJS::Interpreter *interpreter, const KJS::UString &fileName)
208 {
209 //    qDebug() << "runFile: " << toQString(fileName);
210     KJS::UString code;
211     QFile file(toQString(fileName));
212     if (file.open(QFile::ReadOnly)) {
213         QTextStream ts(&file);
214 
215         QString line;
216         while (!ts.atEnd()) {
217             line = ts.readLine();
218             if (line[0] != '#') {
219                 code += toUString(line + '\n');
220             }
221         }
222         file.close();
223     } else {
224         code = "println('Could not open file.');";
225         qWarning() << "Could not open file " << toQString(fileName);
226     }
227 
228 //    qDebug() << "Loaded code: " << toQString(code);
229 
230     return interpreter->evaluate(fileName, 0, code, nullptr);
231 }
232 
runFile(const KJS::UString & fileName)233 Engine::ExitStatus Engine::runFile(const KJS::UString &fileName)
234 {
235     dptr->m_currentResult = runFile(dptr->m_interpreter, fileName);
236 
237     if (dptr->m_currentResult.complType() == KJS::Normal) {
238         return Engine::Success;
239     } else if (dptr->m_currentResult.complType() == KJS::ReturnValue) {
240         return Engine::Success;
241     } else {
242         return Engine::Failure;
243     }
244 }
245 
execute(const KJS::UString & code)246 Engine::ExitStatus Engine::execute(const KJS::UString &code)
247 {
248     dptr->m_currentResult = dptr->m_interpreter->evaluate(KJS::UString(""), 0, code, nullptr);
249     if (dptr->m_currentResult.complType() == KJS::Normal) {
250         return Engine::Success;
251     } else if (dptr->m_currentResult.complType() == KJS::ReturnValue) {
252         return Engine::Success;
253     } else {
254         return Engine::Failure;
255     }
256 }
257 
construct(const KJS::UString & className,const KJS::List & args) const258 KJS::JSObject *Engine::construct(const KJS::UString &className, const KJS::List &args) const
259 {
260     KJS::JSObject *global = dptr->m_interpreter->globalObject();
261     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
262     return StaticConstructor::construct(exec, global, className, args);
263 }
264 
callMethod(const KJS::UString & methodName,const KJS::List & args)265 KJS::JSValue *Engine::callMethod(const KJS::UString &methodName, const KJS::List &args)
266 {
267     KJS::JSObject *global = dptr->m_interpreter->globalObject();
268     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
269 
270     KJS::Identifier id = KJS::Identifier(KJS::UString(methodName));
271     KJS::JSObject *fun = global->get(exec, id)->toObject(exec);
272     KJS::JSValue *retValue;
273 
274     if (!fun->implementsCall()) {
275         QString msg = i18n("%1 is not a function and cannot be called.", toQString(methodName));
276         return throwError(exec, KJS::TypeError, msg);
277     }
278 
279     retValue = fun->call(exec, global, args);
280 
281     if (exec->hadException()) {
282         return exec->exception();
283     }
284 
285     return retValue;
286 }
287 
callMethod(KJS::JSObject * parent,const KJS::UString & methodName,const KJS::List & args)288 KJS::JSValue *Engine::callMethod(KJS::JSObject *parent,
289                                  const KJS::UString &methodName, const KJS::List &args)
290 {
291     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
292 
293     KJS::Identifier id = KJS::Identifier(methodName);
294     KJS::JSObject *fun = parent->get(exec, id)->toObject(exec);
295     KJS::JSValue *retValue;
296 
297     if (!fun->implementsCall()) {
298         QString msg = i18n("%1 is not a function and cannot be called.", toQString(methodName));
299         return throwError(exec, KJS::TypeError, msg);
300     }
301 
302     retValue = fun->call(exec, parent, args);
303 
304     if (exec->hadException()) {
305         return exec->exception();
306     }
307 
308     return retValue;
309 }
310 
311 } // namespace KJS
312 
313