diff options
Diffstat (limited to 'ksvg/ecma')
-rw-r--r-- | ksvg/ecma/Makefile.am | 7 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_bridge.h | 103 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_cacheimpl.h | 65 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_ecma.cpp | 336 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_ecma.h | 114 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_ecmaeventlistener.cpp | 99 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_ecmaeventlistener.h | 54 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_helper.cpp | 68 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_lookup.h | 318 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_scriptinterpreter.cpp | 92 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_scriptinterpreter.h | 71 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_window.cpp | 578 | ||||
-rw-r--r-- | ksvg/ecma/ksvg_window.h | 122 |
13 files changed, 2027 insertions, 0 deletions
diff --git a/ksvg/ecma/Makefile.am b/ksvg/ecma/Makefile.am new file mode 100644 index 00000000..b3eea2b5 --- /dev/null +++ b/ksvg/ecma/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/data -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes) +METASOURCES = AUTO +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_LTLIBRARIES = libksvgecma.la + +libksvgecma_la_SOURCES = ksvg_scriptinterpreter.cpp ksvg_ecma.cpp ksvg_helper.cpp ksvg_ecmaeventlistener.cpp ksvg_window.cpp diff --git a/ksvg/ecma/ksvg_bridge.h b/ksvg/ecma/ksvg_bridge.h new file mode 100644 index 00000000..784dea15 --- /dev/null +++ b/ksvg/ecma/ksvg_bridge.h @@ -0,0 +1,103 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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 KSVGBridge_H +#define KSVGBridge_H + +#include <kdebug.h> + +#include <kjs/object.h> +#include <kjs/lookup.h> +#include <kjs/interpreter.h> // for ExecState + +namespace KJS +{ + class Value; + class UString; + class ExecState; +} + +// Base class for all bridges +// The T class must provide prototype(exec), get and hasProperty +// and have a static s_classInfo object +template<class T> +class KSVGBridge : public KJS::ObjectImp +{ +public: + KSVGBridge(KJS::ExecState *exec, T *impl) : KJS::ObjectImp(impl->prototype(exec)), m_impl(impl) { } + + T *impl() const { return m_impl; } + + virtual KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const + { + kdDebug(26004) << "KSVGBridge::get(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl; + + // Look for standard properties (e.g. those in the hashtables) + KJS::Value val = m_impl->get(exec, propertyName, this); + + if(val.type() != KJS::UndefinedType) + return val; + + // Not found -> forward to ObjectImp. + val = KJS::ObjectImp::get(exec, propertyName); + if(val.type() == KJS::UndefinedType) + kdDebug(26004) << "WARNING: " << propertyName.qstring() << " not found in... Name: " << classInfo()->className << " Object: " << m_impl << " on line : " << exec->context().curStmtFirstLine() << endl; + return val; + } + + virtual bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const + { + kdDebug(26004) << "KSVGBridge::hasProperty(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl; + + if(m_impl->hasProperty(exec, propertyName)) + return true; + + return KJS::ObjectImp::hasProperty(exec, propertyName); + } + + virtual const KJS::ClassInfo *classInfo() const { return &T::s_classInfo; } + +protected: + T *m_impl; +}; + +// Base class for readwrite bridges +// T must also implement put (use KSVG_PUT in the header file) +template<class T> +class KSVGRWBridge : public KSVGBridge<T> +{ +public: + KSVGRWBridge(KJS::ExecState *exec, T *impl) : KSVGBridge<T>(exec, impl) { } + + virtual void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr) + { +// if(!(attr & KJS::Internal)) +// kdDebug(26004) << "KSVGBridge::put(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl; + + // Try to see if we know this property (and need to take special action) + if(this->m_impl->put(exec, propertyName, value, attr)) + return; + + // We don't -> set property in ObjectImp. + KJS::ObjectImp::put(exec, propertyName, value, attr); + } +}; + +#endif diff --git a/ksvg/ecma/ksvg_cacheimpl.h b/ksvg/ecma/ksvg_cacheimpl.h new file mode 100644 index 00000000..1140f1b4 --- /dev/null +++ b/ksvg/ecma/ksvg_cacheimpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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 KSVGCacheImpl_H +#define KSVGCacheImpl_H + +#include "ksvg_scriptinterpreter.h" + +// Lookup or create JS object around an existing "DOM Object" +template<class DOMObj, class KJSDOMObj> +inline KJS::Value cacheDOMObject(KJS::ExecState *exec, DOMObj *domObj) +{ + KJS::ObjectImp *ret; + if(!domObj) + return KJS::Null(); + + KSVGScriptInterpreter *interp = static_cast<KSVGScriptInterpreter *>(exec->interpreter()); + if((ret = interp->getDOMObject(domObj))) + return KJS::Value(ret); + else + { + ret = new KJSDOMObj(exec, domObj); + interp->putDOMObject(domObj, ret); + return KJS::Value(ret); + } +} + +// Lookup or create singleton Impl object, and return a unique bridge object for it. +// (Very much like KJS::cacheGlobalObject, which is for a singleton ObjectImp) +// This one is mostly used for Constructor objects. +template <class ClassCtor> +inline KJS::Object cacheGlobalBridge(KJS::ExecState *exec, const KJS::Identifier &propertyName) +{ + KJS::ValueImp *obj = static_cast<KJS::ObjectImp*>(exec->interpreter()->globalObject().imp())->getDirect(propertyName); + if(obj) + return KJS::Object::dynamicCast(KJS::Value(obj)); + else + { + ClassCtor* ctor = new ClassCtor(exec); // create the ClassCtor instance + KJS::Object newObject(new KSVGBridge<ClassCtor>(exec, ctor)); // create the bridge around it + exec->interpreter()->globalObject().put(exec, propertyName, newObject, KJS::Internal); + return newObject; + } +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecma.cpp b/ksvg/ecma/ksvg_ecma.cpp new file mode 100644 index 00000000..a2aed6ce --- /dev/null +++ b/ksvg/ecma/ksvg_ecma.cpp @@ -0,0 +1,336 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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. +*/ + +#include <kdebug.h> + +#include <qvariant.h> + +#include <dom/dom2_events.h> + +#include "SVGEcma.h" + +#include "SVGDocumentImpl.h" + +#include "ksvg_ecma.h" +#include "ksvg_window.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecmaeventlistener.h" + +#include "KSVGLoader.h" + +using namespace KSVG; +using namespace KJS; + +class AsyncStatus : public ObjectImp +{ +public: + AsyncStatus() : ObjectImp() { } + + virtual bool implementsCall() const { return true; } + virtual Value call(ExecState *exec, Object &thisObj, const List &args); +}; + +Value AsyncStatus::call(ExecState *exec, Object &, const List &args) +{ + kdDebug(26004) << "[AsyncStatus] " << args[0].toString(exec).ascii() << endl; + + if(args[0].toString(exec) == "success") + return Number(1); + else + return Undefined(); +} + +KSVGEcma::KSVGEcma(SVGDocumentImpl *doc) : m_doc(doc) +{ + m_init = false; + m_hasListeners = false; + + m_window = 0; + m_interpreter = 0; + + m_ecmaEventListeners.setAutoDelete(true); +} + +KSVGEcma::~KSVGEcma() +{ + // We are 0 soon so event listeners may NOT call us + QPtrListIterator<KSVGEcmaEventListener> it(m_ecmaEventListeners); + for(; it.current(); ++it) + it.current()->forbidRemove(); + + if(m_interpreter) + delete m_interpreter; +} + +bool KSVGEcma::initialized() +{ + return m_init; +} + +void KSVGEcma::setup() +{ + if(m_init) + return; + + m_init = true; + + // Create handler for js calls + m_window = new KSVG::Window(m_doc); + Object globalObject(m_window); + + // Create code interpreter + m_interpreter = new KSVGScriptInterpreter(globalObject, m_doc); + + // Set object prototype for global object + m_window->setPrototype(m_interpreter->builtinObjectPrototype()); + + // Create bridge for document. Could be done on demand now, though + KSVGBridge<SVGDocumentImpl> *documentRequest = new KSVGBridge<SVGDocumentImpl>(m_interpreter->globalExec(), m_doc); + documentRequest->ref(); + + m_interpreter->putDOMObject(m_doc->handle(), documentRequest); +} + +Completion KSVGEcma::evaluate(const UString &code, const Value &thisV) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KSVGEcma::evaluate " << code.qstring() << endl; +#endif + + return m_interpreter->evaluate(code, thisV); +} + +Object KSVGEcma::globalObject() +{ + return m_interpreter->globalObject(); +} + +ExecState *KSVGEcma::globalExec() +{ + return m_interpreter->globalExec(); +} + +SVGEventListener *KSVGEcma::createEventListener(DOM::DOMString type) +{ + QPtrListIterator<KSVGEcmaEventListener> it(m_ecmaEventListeners); + + for(; it.current(); ++it) + { + if(it.current()->type() == type.string()) + return static_cast<SVGEventListener *>(it.current()); + } + + setup(); + + Object constr = m_interpreter->builtinFunction(); + + List args; + args.append(String("event")); + args.append(String(type.string())); + + Object obj = constr.construct(m_interpreter->globalExec(), args); + + // Note that the KSVGEcmaEventListener constructor adds itself to the m_ecmaEventListeners list + KSVGEcmaEventListener *event = new KSVGEcmaEventListener(obj, type.string(), this); + event->ref(); + + // addEventListener() is called by KSVGEcmaListeners ctor, so it's + // safe to check to count of the eventListeners list (Niko) + if(m_ecmaEventListeners.count() > 0) + m_hasListeners = true; + + return event; +} + +QString KSVGEcma::valueOfEventListener(SVGEventListener *listener) const +{ + KSVGEcmaEventListener *event = static_cast<KSVGEcmaEventListener *>(listener); + if(!event) + return QString::null; + + return event->type(); +} + +void KSVGEcma::addEventListener(KSVGEcmaEventListener *listener) +{ + m_ecmaEventListeners.append(listener); +} + +void KSVGEcma::removeEventListener(KSVGEcmaEventListener *listener) +{ + m_ecmaEventListeners.take(m_ecmaEventListeners.find(listener)); + + if(m_ecmaEventListeners.count() == 0) + m_hasListeners = false; +} + +bool KSVGEcma::hasEventListeners() +{ + return m_hasListeners; +} + +void KSVGEcma::finishedWithEvent(SVGEventImpl *event) +{ + KSVGScriptInterpreter *interpreter = static_cast<KSVGScriptInterpreter *>(globalExec()->interpreter()); + interpreter->removeDOMObject(event); +} + +Value KSVGEcma::getUrl(ExecState *exec, ::KURL url) +{ + Object *status = new Object(new AsyncStatus()); + + // FIXME: Security issue, allows local testing of getURL(), REMOVE BEFORE RELEASE! (Niko) + QString svgDocument = KSVGLoader::getUrl(url, true); + if(svgDocument.length() > 0) + { + status->put(exec, Identifier("success"), Boolean(true)); + status->put(exec, Identifier("content"), String(svgDocument)); + } + else + { + status->put(exec, Identifier("success"), Boolean(false)); + status->put(exec, Identifier("content"), String("")); + } + + return Value(*status); +} + +void KSVGEcma::postUrl(ExecState *exec, ::KURL url, const QString &data, const QString &mimeType, const QString &contentEncoding, Object &callBackFunction) +{ + Object *status = new Object(new AsyncStatus()); + status->put(exec, Identifier("content"), String("")); + status->put(exec, Identifier("success"), Boolean(false)); + + QByteArray byteArray; + QDataStream ds(byteArray, IO_WriteOnly); + ds << data; + + // Support gzip compression + if(contentEncoding == "gzip" || contentEncoding == "deflate") + byteArray = qCompress(byteArray); + + KSVGLoader *loader = new KSVGLoader(); + loader->postUrl(url, byteArray, mimeType, exec, callBackFunction, *status); + delete loader; +} + +// Helpers +Value KSVG::getDOMNode(ExecState *exec, DOM::Node n) +{ + ObjectImp *ret = 0; + if(n.isNull()) + return Null(); + + KSVGScriptInterpreter *interpreter = static_cast<KSVGScriptInterpreter *>(exec->interpreter()); + + ObjectImp *request = interpreter->getDOMObject(n.handle()); + if(request) + return Value(request); + + SVGElementImpl *elem = 0; + + switch(n.nodeType()) + { + case DOM::Node::ELEMENT_NODE: + elem = interpreter->document()->getElementFromHandle(n.handle()); + if(!elem) + { + // Lookup different document, if possible + SVGDocumentImpl *different = interpreter->document()->getDocumentFromHandle(n.ownerDocument().handle()); + + if(!different) + return Null(); + + elem = different->getElementFromHandle(n.handle()); + + if(!elem) + return Null(); + } + + // The generated bridge() function does not ref the ret itself + ret = elem->bridge(exec); + ret->ref(); + break; + case DOM::Node::TEXT_NODE: + ret = new KSVGRWBridge<SVGDOMTextBridge>(exec, new SVGDOMTextBridge(n)); + ret->ref(); + break; + default: + ret = new KSVGBridge<SVGDOMNodeBridge>(exec, new SVGDOMNodeBridge(n)); + ret->ref(); + break; + } + + interpreter->putDOMObject(n.handle(), ret); + + return Value(ret); +} + +Value KSVG::getDOMEvent(ExecState *exec, SVGEventImpl *e) +{ + return e->cache(exec); +} + +Value KSVG::getString(DOM::DOMString s) +{ + if(s.isNull()) + return Null(); + else + return String(s); +} + +DOM::Node KSVG::toNode(const Value &val) +{ + Object obj = Object::dynamicCast(val); + if(obj.isNull()) + return DOM::Node(); + + SVGDOMNodeBridge *bridge = toNodeBridge(static_cast<ObjectImp *>(obj.imp())); + + if(bridge) + return bridge->impl(); + + return DOM::Node(); +} + +QVariant KSVG::valueToVariant(ExecState *exec, const Value &val) +{ + QVariant res; + + switch(val.type()) + { + case BooleanType: + res = QVariant(val.toBoolean(exec), 0); + break; + case NumberType: + res = QVariant(val.toNumber(exec)); + break; + case StringType: + res = QVariant(val.toString(exec).qstring()); + break; + default: + // everything else will be 'invalid' + break; + } + + return res; +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecma.h b/ksvg/ecma/ksvg_ecma.h new file mode 100644 index 00000000..7c236454 --- /dev/null +++ b/ksvg/ecma/ksvg_ecma.h @@ -0,0 +1,114 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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 KSVGEcma_H +#define KSVGEcma_H + +#include <qptrlist.h> + +#include "ksvg_bridge.h" + +namespace DOM +{ + class Node; + class DOMString; +} + +namespace KJS +{ + class Value; + class Object; + class UString; + class ExecState; + class Completion; +} + +namespace KSVG +{ + class Window; + class SVGEventImpl; + class SVGDocumentImpl; + class SVGEventListener; + class SVGDOMNodeBridge; +} + +class QVariant; + +class KSVGEcmaEventListener; +class KSVGScriptInterpreter; + +typedef KSVGBridge<KSVG::SVGEventImpl> KSVGEcmaEvent; + +// Helpers +namespace KSVG +{ + KJS::Value getDOMNode(KJS::ExecState *, DOM::Node); + KJS::Value getDOMEvent(KJS::ExecState *, KSVG::SVGEventImpl *); + KJS::Value getString(DOM::DOMString); + + QVariant valueToVariant(KJS::ExecState *, const KJS::Value &); + + DOM::Node toNode(const KJS::Value &); + + // This one is part of generateddata.cpp + SVGDOMNodeBridge *toNodeBridge(const KJS::ObjectImp *); +} + +class KSVGEcma +{ +public: + KSVGEcma(KSVG::SVGDocumentImpl *doc); + ~KSVGEcma(); + + void setup(); + bool initialized(); + + KJS::Completion evaluate(const KJS::UString &code, const KJS::Value &thisV); + + KJS::Object globalObject(); + KJS::ExecState *globalExec(); + + KSVGScriptInterpreter *interpreter() { return m_interpreter; } + + KSVG::SVGEventListener *createEventListener(DOM::DOMString type); + QString valueOfEventListener(KSVG::SVGEventListener *listener) const; + void addEventListener(KSVGEcmaEventListener *listener); + void removeEventListener(KSVGEcmaEventListener *listener); + bool hasEventListeners(); + + void finishedWithEvent(KSVG::SVGEventImpl *event); + + KJS::Value getUrl(KJS::ExecState *exec, ::KURL url); + void postUrl(KJS::ExecState *exec, ::KURL url, const QString &data, const QString &mimeType, const QString &contentEncoding, KJS::Object &callBackFunction); + +private: + bool m_init, m_hasListeners; + + KSVG::SVGDocumentImpl *m_doc; + + KSVG::Window *m_window; + KSVGScriptInterpreter *m_interpreter; + QPtrList<KSVGEcmaEventListener> m_ecmaEventListeners; + +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecmaeventlistener.cpp b/ksvg/ecma/ksvg_ecmaeventlistener.cpp new file mode 100644 index 00000000..4b59f924 --- /dev/null +++ b/ksvg/ecma/ksvg_ecmaeventlistener.cpp @@ -0,0 +1,99 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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. +*/ + +#include <kdebug.h> + +#include <qvariant.h> + +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +#include "ksvg_ecma.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecmaeventlistener.h" + +using namespace KSVG; +using namespace KJS; + +KSVGEcmaEventListener::KSVGEcmaEventListener(KJS::Object _listener, QString _type, KSVGEcma *_ecma) : SVGEventListener() +{ + m_listener = _listener; + m_remove = true; + m_type = _type; + m_ecma = _ecma; + + m_ecma->addEventListener(this); +} + +KSVGEcmaEventListener::~KSVGEcmaEventListener() +{ + if(m_remove) + m_ecma->removeEventListener(this); +} + +void KSVGEcmaEventListener::forbidRemove() +{ + m_remove = false; +} + +void KSVGEcmaEventListener::handleEvent(SVGEventImpl *evt) +{ + if(m_ecma && m_listener.implementsCall()) + { + KSVGScriptInterpreter *interpreter = m_ecma->interpreter(); + ExecState *exec = m_ecma->globalExec(); + + // Append 'evt' + List args; + args.append(getDOMEvent(exec, evt)); + + // Set current event + interpreter->setCurrentEvent(evt); + + // Call it! + Object thisObj = Object::dynamicCast(getDOMNode(exec, *evt->currentTarget())); + Value retval = m_listener.call(exec, thisObj, args); + + interpreter->setCurrentEvent(0); + + if(exec->hadException()) + { + exec->clearException(); + + // onerror support + SVGSVGElementImpl *rootElement = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->document()->rootElement(); + if(rootElement) + rootElement->dispatchEvent(SVGEvent::ERROR_EVENT, true, false); + } + else + { + QVariant ret = valueToVariant(exec, retval); + if(ret.type() == QVariant::Bool && ret.toBool() == false) + evt->preventDefault(); + } + } +} + +DOM::DOMString KSVGEcmaEventListener::eventListenerType() +{ + return "KSVGEcmaEventListener - " + m_type; +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecmaeventlistener.h b/ksvg/ecma/ksvg_ecmaeventlistener.h new file mode 100644 index 00000000..16ebe3bc --- /dev/null +++ b/ksvg/ecma/ksvg_ecmaeventlistener.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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 KSVGEcmaEventListener_H +#define KSVGEcmaEventListener_H + +#include "SVGEventImpl.h" + +namespace KJS +{ + class Object; +} + +class KSVGEcmaEventListener : public KSVG::SVGEventListener +{ +public: + KSVGEcmaEventListener(KJS::Object _listener, QString _type, KSVGEcma *_ecma); + virtual ~KSVGEcmaEventListener(); + + virtual void handleEvent(KSVG::SVGEventImpl *evt); + virtual DOM::DOMString eventListenerType(); + + QString type() { return m_type; } + + void forbidRemove(); + +private: + KSVGEcma *m_ecma; + QString m_type; + bool m_remove; + + KJS::Object m_listener; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_helper.cpp b/ksvg/ecma/ksvg_helper.cpp new file mode 100644 index 00000000..597f9a06 --- /dev/null +++ b/ksvg/ecma/ksvg_helper.cpp @@ -0,0 +1,68 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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. +*/ + +#include <kjs/ustring.h> +#include <kjs/identifier.h> + +#include <dom/dom_string.h> + +KJS::UString::UString(const DOM::DOMString &d) +{ + if(d.isNull()) + { + attach(&Rep::null); + return; + } + + unsigned int len = d.length(); + KJS::UChar *dat = new UChar[len]; + memcpy(dat, d.unicode(), len * sizeof(UChar)); + rep = KJS::UString::Rep::create(dat, len); +} + +KJS::UString::UString(const QString &d) +{ + unsigned int len = d.length(); + KJS::UChar *dat = new UChar[len]; + memcpy(dat, d.unicode(), len * sizeof(UChar)); + rep = KJS::UString::Rep::create(dat, len); +} + +QString KJS::UString::qstring() const +{ + return QString(reinterpret_cast<QChar *>(const_cast<KJS::UChar *>(data())), size()); +} + +DOM::DOMString KJS::UString::string() const +{ + return DOM::DOMString(reinterpret_cast<QChar *>(const_cast<KJS::UChar *>(data())), size()); +} + +DOM::DOMString KJS::Identifier::string() const +{ + return DOM::DOMString((QChar*) data(), size()); +} + +QString KJS::Identifier::qstring() const +{ + return QString((QChar*) data(), size()); +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_lookup.h b/ksvg/ecma/ksvg_lookup.h new file mode 100644 index 00000000..11c41462 --- /dev/null +++ b/ksvg/ecma/ksvg_lookup.h @@ -0,0 +1,318 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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 KSVG_LOOKUP_H +#define KSVG_LOOKUP_H + +#include <kjs/object.h> +#include <kjs/lookup.h> +#include <kjs/interpreter.h> // for ExecState + +#include "ksvg_bridge.h" +#include "ksvg_scriptinterpreter.h" + +#define KSVG_GET_COMMON \ +public: \ + \ + /* The standard hasProperty call, auto-generated. Looks in hashtable, forwards to parents. */ \ + bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + \ + /* get() method, called by KSVGBridge::get */ \ + KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \ + \ + /* Called by lookupGet(). Auto-generated. Forwards to the parent which has the given property. */ \ + KJS::Value getInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \ + \ + KJS::Object prototype(KJS::ExecState *exec) const;\ + \ + static const KJS::ClassInfo s_classInfo; \ + \ + static const struct KJS::HashTable s_hashTable; \ + \ + int m_attrFlags; + +// For classes with properties to read, and a hashtable. +#define KSVG_GET \ + KSVG_GET_COMMON \ + KJS::Value cache(KJS::ExecState *exec) const; + +// Same thing, for base classes (kalyptus helps finding them) +// The difference is that cache() is virtual +#define KSVG_BASECLASS_GET \ + KSVG_GET_COMMON \ + virtual KJS::Value cache(KJS::ExecState *exec) const; + +// For classes without properties, but with a parent class to forward to +#define KSVG_FORWARDGET \ +public: \ + \ + bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + \ + /* will have the code for getInParents */ \ + KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \ + \ + KJS::Object prototype(KJS::ExecState *exec) const;\ + \ + static const KJS::ClassInfo s_classInfo; \ + \ + KJS::Value cache(KJS::ExecState *exec) const; + +// For read-write classes only, i.e. those which support put() +#define KSVG_PUT \ + \ + /* put() method, called by KSVGBridge::put */ \ + bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); \ + \ + /* Called by lookupPut. Auto-generated. Looks in hashtable, forwards to parents. */ \ + bool putInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); + +// For classes which inherit a read-write class, but have no readwrite property themselves +#define KSVG_FORWARDPUT \ + \ + /* put() method, called by KSVGBridge::put */ \ + bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); + +// For classes which need to be accessable with getElementById -> elements +#define KSVG_NO_TAG_BRIDGE \ +public: \ + KJS::ObjectImp *bridge(KJS::ExecState *) const { return 0; } + +#define KSVG_BRIDGE \ +public: \ + KJS::ObjectImp *bridge(KJS::ExecState *) const; \ + virtual DOM::DOMString tagName() const { return s_tagName; } \ + static const DOM::DOMString s_tagName; + +// Fast setting of default values, if the token is known +// Note: this is actually misnamed it should be KSVG_SET_DEFAULT_ATTRIBUTE +#define KSVG_SET_ALT_ATTRIBUTE(Token, Name) putValueProperty(ownerDoc()->ecmaEngine()->globalExec(), Token, String(Name), Internal); + +// Check if attribute has not been parsed, if the token is known +#define KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, Element) (~Element->m_attrFlags & (1 << Token)) +#define KSVG_TOKEN_NOT_PARSED(Token) KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, this) + +// Checks if the interpreter is in attribute "getting" mode +#define KSVG_CHECK_ATTRIBUTE bool attributeMode = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->attributeGetMode(); + +// Sets the class specific flags to a ZERO value +#define KSVG_EMPTY_FLAGS m_attrFlags = 0; + +// to be used in generatedata.cpp +// GET p1=exec, p2=propertyName, p3=bridge +// PUT p1=exec, p2=propertyName, p3=value, p4=attr +#define GET_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::ObjectImp *p3 +#define PUT_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::Value &p3, int p4 + +namespace KSVG +{ + /** + * Helper method for property lookups + * + * This method does it all (looking in the hashtable, checking for function + * overrides, creating the function or retrieving from cache, calling + * getValueProperty in case of a non-function property, forwarding to parent[s] if + * unknown property). + * + * Template arguments: + * @param FuncImp the class which implements this object's functions + * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method, + * for non-function properties, and the getInParents() method (auto-generated). + * + * Method arguments: + * @param exec execution state, as usual + * @param propertyName the property we're looking for + * @param table the static hashtable for this class + * @param thisObj "this" + */ + template<class FuncImp, class ThisImp> + inline KJS::Value lookupGet(KJS::ExecState *exec, + const KJS::Identifier &propertyName, + const KJS::HashTable *table, + const ThisImp *thisObj, // the 'impl' object + const KJS::ObjectImp *bridge) + { + const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName); + + if(!entry) // not found, forward to parents + return thisObj->getInParents(exec, propertyName, bridge); + + if(entry->attr & KJS::Function) + return KJS::lookupOrCreateFunction<FuncImp>(exec, propertyName, + const_cast<KJS::ObjectImp *>(bridge), + entry->value, entry->params, entry->attr); + + return thisObj->getValueProperty(exec, entry->value); + } + + /** + * Simplified version of lookupGet in case there are no functions, only "values". + * Using this instead of lookupGet removes the need for a FuncImp class. + */ + template <class ThisImp> + inline KJS::Value lookupGetValue(KJS::ExecState *exec, + const KJS::Identifier &propertyName, + const KJS::HashTable *table, + const ThisImp *thisObj, // the 'impl' object + const KJS::ObjectImp *bridge) + { + const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName); + + if(!entry) // not found, forward to parents + return thisObj->getInParents(exec, propertyName, bridge); + + if(entry->attr & KJS::Function) + kdError(26004) << "Function bit set! Shouldn't happen in lookupGetValue! propertyName was " << propertyName.qstring() << endl; + + return thisObj->getValueProperty(exec, entry->value); + } + + /** + * This one is for "put". + * Lookup hash entry for property to be set, and set the value. + * The "this" class must implement putValueProperty. + * If it returns false, put() will return false, and KSVGRequest will set a dynamic property in ObjectImp + */ + template <class ThisImp> + inline bool lookupPut(KJS::ExecState *exec, + const KJS::Identifier &propertyName, + const KJS::Value &value, + int attr, + const KJS::HashTable *table, + ThisImp *thisObj) + { + const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName); + + if(!entry) // not found, forward to parents + return thisObj->putInParents(exec, propertyName, value, attr); + else if(entry->attr & KJS::Function) // Function: put as override property + return false; + else if(entry->attr & KJS::ReadOnly && !(attr & KJS::Internal)) // readonly! Can't put! + { +#ifdef KJS_VERBOSE + kdWarning(26004) <<" Attempt to change value of readonly property '" << propertyName.qstring() << "'" << endl; +#endif + return true; // "we did it" -> don't put override property + } + else + { + if(static_cast<KSVGScriptInterpreter *>(exec->interpreter())->attributeSetMode()) + thisObj->m_attrFlags |= (1 << entry->value); + + thisObj->putValueProperty(exec, entry->value, value, attr); + return true; + } + } +} + +// Same as kjs' DEFINE_PROTOTYPE, but with a pointer to the hashtable too, and no ClassName here +// The ClassProto ctor(exec) must be public, so we can use KJS::cacheGlobalObject... (Niko) +#define KSVG_DEFINE_PROTOTYPE(ClassProto) \ + namespace KSVG { \ + class ClassProto : public KJS::ObjectImp { \ + public: \ + static KJS::Object self(KJS::ExecState *exec); \ + ClassProto( KJS::ExecState *exec ) \ + : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \ + virtual const KJS::ClassInfo *classInfo() const { return &info; } \ + static const KJS::ClassInfo info; \ + KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + \ + static const struct KJS::HashTable s_hashTable; \ + }; \ + } + +// same as IMPLEMENT_PROTOTYPE but in the KSVG namespace, and with ClassName here +// so that KSVG_DEFINE_PROTOTYPE can be put in a header file ('info' defined here) +#define KSVG_IMPLEMENT_PROTOTYPE(ClassName,ClassProto,ClassFunc) \ + KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { \ + return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &s_hashTable, this ); \ + } \ + bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { /*stupid but we need this to have a common macro for the declaration*/ \ + return KJS::ObjectImp::hasProperty(exec, propertyName); \ + } \ + KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \ + { \ + return KJS::cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \ + } \ + const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \ + +// same as KSVG_IMPLEMENT_PROTOTYPE but with a parent class to forward calls to +// Not used within KSVG up to now - each class does a self proto lookup in generateddata.cpp +#define KSVG_IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassName,ClassProto,ClassFunc,ParentProto) \ + KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { \ + KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &s_hashTable, this ); \ + if ( val.type() != UndefinedType ) return val; \ + /* Not found -> forward request to "parent" prototype */ \ + return ParentProto::self(exec).get( exec, propertyName ); \ + } \ + bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { \ + if (KJS::ObjectImp::hasProperty(exec, propertyName)) \ + return true; \ + return ParentProto::self(exec).hasProperty(exec, propertyName); \ + } \ + KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \ + { \ + return KJS::cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \ + } \ + const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \ + +#define KSVG_IMPLEMENT_PROTOFUNC(ClassFunc,Class) \ + namespace KSVG { \ + class ClassFunc : public KJS::ObjectImp { \ + public: \ + ClassFunc(KJS::ExecState *exec, int i, int len) \ + : KJS::ObjectImp( /*proto? */ ), id(i) { \ + KJS::Value protect(this); \ + put(exec,"length",KJS::Number(len),KJS::DontDelete|KJS::ReadOnly|KJS::DontEnum); \ + } \ + /** Used by call() to check the type of thisObj. Generated code */ \ + Class * cast(const KJS::ObjectImp* bridge) const; \ + \ + virtual bool implementsCall() const { return true; } \ + /** You need to implement that one */ \ + virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \ + private: \ + int id; \ + }; \ + } + +// To be used when casting the type of an argument +#define KSVG_CHECK(ClassName, theObj) \ + ClassName* obj = cast(static_cast<KJS::ObjectImp*>(theObj.imp())); \ + if (!obj) { \ + kdDebug(26004) << k_funcinfo << " Wrong object type: expected " << ClassName::s_classInfo.className << " got " << thisObj.classInfo()->className << endl; \ + Object err = Error::create(exec,TypeError); \ + exec->setException(err); \ + return err; \ + } + +// To be used in all call() implementations! +// Can't use if (!thisObj.inherits(&ClassName::s_classInfo) since we don't +// use the (single-parent) inheritance of ClassInfo... +#define KSVG_CHECK_THIS(ClassName) KSVG_CHECK(ClassName, thisObj) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_scriptinterpreter.cpp b/ksvg/ecma/ksvg_scriptinterpreter.cpp new file mode 100644 index 00000000..b5b9e6dd --- /dev/null +++ b/ksvg/ecma/ksvg_scriptinterpreter.cpp @@ -0,0 +1,92 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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. +*/ + +#include "SVGEventImpl.h" +#include "SVGDocumentImpl.h" +#include "ksvg_scriptinterpreter.h" + +using namespace KSVG; +using namespace KJS; + +KSVGScriptInterpreter::KSVGScriptInterpreter(const Object &global, SVGDocumentImpl *doc) : Interpreter(global), m_document(doc) +{ + m_evt = 0; + + m_attributeGetMode = false; + m_attributeSetMode = false; +} + +KSVGScriptInterpreter::~KSVGScriptInterpreter() +{ + if(m_evt) + m_evt->deref(); +} + +SVGDocumentImpl *KSVGScriptInterpreter::document() +{ + return m_document; +} + +KSVG::SVGEventImpl *KSVGScriptInterpreter::currentEvent() +{ + return m_evt; +} + +void KSVGScriptInterpreter::setCurrentEvent(KSVG::SVGEventImpl *evt) +{ + m_evt = evt; +} + +KJS::ObjectImp *KSVGScriptInterpreter::getDOMObject(void *objectHandle) const +{ + return m_domObjects[objectHandle]; +} + +void KSVGScriptInterpreter::putDOMObject(void *objectHandle, KJS::ObjectImp *obj) +{ + m_domObjects.insert(objectHandle, obj); +} + +void KSVGScriptInterpreter::removeDOMObject(void *objectHandle) +{ + m_domObjects.take(objectHandle); +} + +bool KSVGScriptInterpreter::attributeGetMode() +{ + return m_attributeGetMode; +} + +bool KSVGScriptInterpreter::attributeSetMode() +{ + return m_attributeSetMode; +} + +void KSVGScriptInterpreter::setAttributeGetMode(bool temp) +{ + m_attributeGetMode = temp; +} + +void KSVGScriptInterpreter::setAttributeSetMode(bool temp) +{ + m_attributeSetMode = temp; +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_scriptinterpreter.h b/ksvg/ecma/ksvg_scriptinterpreter.h new file mode 100644 index 00000000..ed7c6af8 --- /dev/null +++ b/ksvg/ecma/ksvg_scriptinterpreter.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + 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 KSVGScriptInterpreter_H +#define KSVGScriptInterpreter_H + +#include <qptrdict.h> + +namespace KJS +{ + class Value; + class Object; + class Interpreter; +} + +namespace KSVG +{ + class SVGEventImpl; + class SVGDocumentImpl; +} + +class KSVGScriptInterpreter : public KJS::Interpreter +{ +public: + KSVGScriptInterpreter(const KJS::Object &global, KSVG::SVGDocumentImpl *doc); + virtual ~KSVGScriptInterpreter(); + + KSVG::SVGDocumentImpl *document(); + + KJS::ObjectImp *getDOMObject(void *objectHandle) const; + void putDOMObject(void *objectHandle, KJS::ObjectImp *obj); + void removeDOMObject(void *objectHandle); + + KSVG::SVGEventImpl *currentEvent(); + void setCurrentEvent(KSVG::SVGEventImpl *evt); + + bool attributeGetMode(); + void setAttributeGetMode(bool temp); + + bool attributeSetMode(); + void setAttributeSetMode(bool temp); + +private: + KSVG::SVGDocumentImpl *m_document; + KSVG::SVGEventImpl *m_evt; + + bool m_attributeGetMode, m_attributeSetMode; + + QPtrDict<KJS::ObjectImp> m_domObjects; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_window.cpp b/ksvg/ecma/ksvg_window.cpp new file mode 100644 index 00000000..d4c04de3 --- /dev/null +++ b/ksvg/ecma/ksvg_window.cpp @@ -0,0 +1,578 @@ +/* This file is part of the KDE project + Copyright (C) 2002 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ksvg_window.moc" +#include "ksvg_lookup.h" +#include "ksvg_ecma.h" +#include "ksvg_bridge.h" +#include "ksvg_scriptinterpreter.h" +#include <SVGEventImpl.h> +#include <SVGDocumentImpl.h> +#include <KSVGCanvas.h> +#include <SVGWindowImpl.h> +// for js constants +#include <SVGTransformImpl.h> +#include <SVGLengthImpl.h> +#include <SVGAngleImpl.h> +#include <SVGColorImpl.h> +#include <SVGPreserveAspectRatioImpl.h> +#include <SVGTextContentElementImpl.h> +#include <SVGPathSegImpl.h> +#include <SVGGradientElementImpl.h> +#include <SVGMarkerElementImpl.h> +#include <SVGTextPathElementImpl.h> +#include <SVGPaintImpl.h> +#include <SVGZoomAndPanImpl.h> + +#include <kparts/part.h> +#include <assert.h> +#include <kdebug.h> +#include <qstylesheet.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kinputdialog.h> + +using namespace KSVG; + +#include "ksvg_window.lut.h" + +// Spec on http://www.protocol7.com/svg-wiki/ow.asp?AdobeSVGViewerWindow + +/* +@namespace KSVG +@begin KSVG::Window::s_hashTable 34 + closed KSVG::Window::_Closed DontDelete|ReadOnly + window KSVG::Window::_Window DontDelete|ReadOnly + evt KSVG::Window::_Evt DontDelete|ReadOnly + document KSVG::Window::_Document DontDelete|ReadOnly + svgDocument KSVG::Window::_Document DontDelete|ReadOnly + innerWidth KSVG::Window::_InnerWidth DontDelete|ReadOnly + innerHeight KSVG::Window::_InnerHeight DontDelete|ReadOnly + setTimeout KSVG::Window::_SetTimeout DontDelete|Function 2 + clearTimeout KSVG::Window::_ClearTimeout DontDelete|Function 1 + setInterval KSVG::Window::_SetInterval DontDelete|Function 2 + clearInterval KSVG::Window::_ClearInterval DontDelete|Function 1 + navigator KSVG::Window::_Navigator DontDelete|ReadOnly + printNode KSVG::Window::_PrintNode DontDelete|Function 1 + +# todo navigator, status/defaultstatus, like in KJS::Window (khtml) +# todo close +# todo instancename +# todo setsrc, getsrc, reload, focus, blur, browsereval, findinstancebyname + +# "Constructors" (usually repositories for constants) + SVGTransform KSVG::Window::_SVGTransform DontDelete|ReadOnly + SVGLength KSVG::Window::_SVGLength DontDelete|ReadOnly + SVGAngle KSVG::Window::_SVGAngle DontDelete|ReadOnly + SVGPreserveAspectRatio KSVG::Window::_SVGPreserveAspectRatio DontDelete|ReadOnly + SVGPathSeg KSVG::Window::_SVGPathSeg DontDelete|ReadOnly + SVGGradientElement KSVG::Window::_SVGGradientElement DontDelete|ReadOnly + SVGMarkerElement KSVG::Window::_SVGMarkerElement DontDelete|ReadOnly + SVGTextPathElement KSVG::Window::_SVGTextPathElement DontDelete|ReadOnly + SVGPaint KSVG::Window::_SVGPaint DontDelete|ReadOnly + SVGTextContentElement KSVG::Window::_SVGTextContentElement DontDelete|ReadOnly + SVGZoomAndPan KSVG::Window::_SVGZoomAndPan DontDelete|ReadOnly + SVGColor KSVG::Window::_SVGColor DontDelete|ReadOnly + +# Functions + alert KSVG::Window::_Alert DontDelete|Function 1 + prompt KSVG::Window::_Prompt DontDelete|Function 2 + confirm KSVG::Window::_Confirm DontDelete|Function 1 + debug KSVG::Window::_Debug DontDelete|Function 1 + success KSVG::Window::_Success DontDelete|Function 1 + getSVGViewerVersion KSVG::Window::_GetSVGViewerVersion DontDelete|Function 0 + getURL KSVG::Window::_GetURL DontDelete|Function 2 + postURL KSVG::Window::_PostURL DontDelete|Function 5 + parseXML KSVG::Window::_ParseXML DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOFUNC(WindowFunc, Window) + +const ClassInfo KSVG::Window::s_classInfo = { "Window", 0, &s_hashTable, 0 }; + +KSVG::Window::Window(KSVG::SVGDocumentImpl *p) : ObjectImp(), m_doc(p) +{ + winq = new WindowQObject(this); +} + +KSVG::Window::~Window() +{ + delete winq; +} + +KSVG::Window *KSVG::Window::retrieveActive(ExecState *exec) +{ + ValueImp *imp = exec->interpreter()->globalObject().imp(); + assert(imp); + return static_cast<KSVG::Window*>(imp); +} + +bool KSVG::Window::hasProperty(ExecState *, const Identifier &) const +{ + return true; // See KJS::KSVG::Window::hasProperty +} + +Value KSVG::Window::get(ExecState *exec, const Identifier &p) const +{ + kdDebug(26004) << "KSVG::Window (" << this << ")::get " << p.qstring() << endl; + + if(p == "closed") + return Boolean(m_doc.isNull()); + + // we don't want any operations on a closed window + if(m_doc.isNull()) + return Undefined(); + + // Look for overrides first + Value val = ObjectImp::get(exec, p); + if(!val.isA(UndefinedType)) + return isSafeScript(exec) ? val : Undefined(); + + // Not the right way in the long run. Should use retrieve(m_doc)... + KSVGScriptInterpreter* interpreter = static_cast<KSVGScriptInterpreter *>(exec->interpreter()); + + const HashEntry *entry = Lookup::findEntry(&KSVG::Window::s_hashTable, p); + if(entry) + { + switch(entry->value) + { + case _Document: + // special case, KSVGEcma::setup created it, so we don't need to do it + return Value(interpreter->getDOMObject(m_doc->handle())); + case _Window: + return Value(const_cast<Window *>(this)); + case _Evt: + { + KSVG::SVGEventImpl *evt = interpreter->currentEvent(); + if(evt) + return getDOMEvent(exec, evt); + else + return Undefined(); + } + case _InnerWidth: + return Number(m_doc->canvas()->width()); + case _InnerHeight: + return Number(m_doc->canvas()->height()); + case _SetTimeout: + case _ClearTimeout: + case _SetInterval: + case _ClearInterval: + case _PrintNode: + { + if(isSafeScript(exec)) + return lookupOrCreateFunction<WindowFunc>(exec, p, this, entry->value, entry->params, entry->attr); + else + return Undefined(); + } + case _Alert: + case _Confirm: + case _Debug: + case _Success: + case _GetSVGViewerVersion: + case _GetURL: + case _PostURL: + case _ParseXML: + case _Prompt: + return lookupOrCreateFunction<WindowFunc>(exec, p, this, entry->value, entry->params, entry->attr); + case _SVGTransform: + return getSVGTransformImplConstructor(exec); + case _SVGLength: + return getSVGLengthImplConstructor(exec); + case _SVGAngle: + return getSVGAngleImplConstructor(exec); + case _SVGColor: + return getSVGColorImplConstructor(exec); + case _SVGPreserveAspectRatio: + return getSVGPreserveAspectRatioImplConstructor(exec); + case _SVGPathSeg: + return getSVGPathSegImplConstructor(exec); + case _SVGGradientElement: + return getSVGGradientElementImplConstructor(exec); + case _SVGMarkerElement: + return getSVGMarkerElementImplConstructor(exec); + case _SVGTextPathElement: + return getSVGTextPathElementImplConstructor(exec); + case _SVGPaint: + return getSVGPaintImplConstructor(exec); + case _SVGTextContentElement: + return getSVGTextContentElementImplConstructor(exec); + case _SVGZoomAndPan: + return getSVGZoomAndPanImplConstructor(exec); + } + } + + // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1 + // But it can also mean something isn't loaded or implemented... + kdDebug(26004) << "KSVG::Window::get property not found: " << p.qstring() << endl; + + return Undefined(); +} + +void KSVG::Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr) +{ + // Called by an internal KJS call (e.g. InterpreterImp's constructor) ? + // If yes, save time and jump directly to ObjectImp. + if((attr != None && attr != DontDelete) + // Same thing if we have a local override (e.g. "var location") + || (ObjectImp::getDirect(propertyName) && isSafeScript(exec))) + { + ObjectImp::put( exec, propertyName, value, attr ); + return; + } + + const HashEntry *entry = Lookup::findEntry(&KSVG::Window::s_hashTable, propertyName); + if(entry) + { +#ifdef KJS_VERBOSE + kdDebug(26004) << "Window(" << this << ")::put " << propertyName.qstring() << endl; +#endif + //switch(entry->value) + //{ + // ... + //} + } + + if(isSafeScript(exec)) + ObjectImp::put(exec, propertyName, value, attr); +} + +bool KSVG::Window::isSafeScript(ExecState *exec) const +{ + if(m_doc.isNull()) // part deleted ? can't grant access + { + kdDebug(26004) << "KSVG::Window::isSafeScript: accessing deleted part !" << endl; + return false; + } + + KSVG::SVGDocumentImpl *activePart = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->document(); + + if(!activePart) + { + kdDebug(26004) << "KSVG::Window::isSafeScript: current interpreter's part is 0L!" << endl; + return false; + } + + if(activePart == m_doc) // Not calling from another frame, no problem. + return true; + + return false; +} + +void KSVG::Window::clear(ExecState *exec) +{ + kdDebug(26004) << "KSVG::Window::clear " << this << endl; + delete winq; + winq = new WindowQObject(this);; + + // Get rid of everything, those user vars could hold references to DOM nodes + deleteAllProperties(exec); + + // Really delete those properties, so that the DOM nodes get deref'ed + // KJS::Collector::collect(); + + // Now recreate a working global object for the next URL that will use us + Interpreter *interpreter = exec->interpreter(); + interpreter->initGlobalObject(); +} + +Value WindowFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + if(!thisObj.inherits(&KSVG::Window::s_classInfo)) + { + Object err = Error::create(exec, TypeError); + exec->setException(err); + return err; + } + + Window *window = static_cast<Window *>(thisObj.imp()); + Value v = args[0]; + UString s = v.toString(exec); + QString str = s.qstring(); + + switch(id) + { + case KSVG::Window::_Alert: + SVGWindowImpl::alert(DOM::DOMString(str), "Javascript"); + return Undefined(); + case KSVG::Window::_Confirm: + return Boolean(SVGWindowImpl::confirm(DOM::DOMString(str), "Javascript")); + case KSVG::Window::_Debug: + kdDebug(26004) << "[Debug] " << str << endl; + return Undefined(); + case KSVG::Window::_Success: + //if(args[0].toString(exec) == "success") // ? Did you really mean that ? + return Number(1); + //return Undefined(); + case KSVG::Window::_GetSVGViewerVersion: + return String("0.1"); // I cant really find a central place for the version nr, so... (Rob) + case KSVG::Window::_ClearTimeout: + case KSVG::Window::_ClearInterval: + (const_cast<Window *>(window))->clearTimeout(v.toInt32(exec)); + return Undefined(); + case KSVG::Window::_PrintNode: + return String(const_cast<Window *>(window)->doc()->window()->printNode(toNode(args[0]))); + case KSVG::Window::_GetURL: + { + KURL url((const_cast<Window *>(window))->doc()->baseUrl(), args[0].toString(exec).qstring()); + Value asyncStatus = (const_cast<Window *>(window))->doc()->ecmaEngine()->getUrl(exec, url); + Object callBackFunction = Object::dynamicCast(args[1]); + List callBackArgs; + + callBackArgs.append(asyncStatus); + callBackFunction.call(exec, callBackFunction, callBackArgs); + + return Undefined(); + } + case KSVG::Window::_PostURL: + { + KURL url((const_cast<Window *>(window))->doc()->baseUrl(), args[0].toString(exec).qstring()); + QString data = args[1].toString(exec).qstring(); + QString mimeType = args[3].toString(exec).qstring(); + QString contentEncoding = args[4].toString(exec).qstring(); + Object callBackFunction = Object::dynamicCast(args[2]); + + (const_cast<Window *>(window))->doc()->ecmaEngine()->postUrl(exec, url, data, mimeType, contentEncoding, callBackFunction); + + return Undefined(); + }; + case KSVG::Window::_ParseXML: + { + SVGDocumentImpl *doc = new SVGDocumentImpl(); + doc->ref(); + doc->attach(0); + + // So we can find it later... + (const_cast<Window *>(window))->doc()->addToDocumentDict(doc->handle(), doc); + + // Also add the current doc to the new doc! + SVGDocumentImpl *curDoc = (const_cast<Window *>(window))->doc(); + doc->addToDocumentDict(curDoc->handle(), curDoc); + + QXmlInputSource *svgFragment = new QXmlInputSource(); + svgFragment->setData(args[0].toString(exec).qstring()); + + doc->parseSVG(svgFragment, true); + + DOM::DocumentFragment fragment = doc->createDocumentFragment(); + DOM::Node node = doc->firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + fragment.appendChild(node); + + +// fragment = *doc; // Should copy the nodes into here... + + return (new SVGDOMDocumentFragmentBridge(fragment))->cache(exec); + } + case KSVG::Window::_Prompt: + { + // mop: from khtml. do we need that? + // part->xmlDocImpl()->updateRendering(); + bool ok; + QString str2; + if (args.size() >= 2) + str2 = KInputDialog::getText(i18n("Prompt"), + QStyleSheet::convertFromPlainText(str), + args[1].toString(exec).qstring(), &ok); + else + str2 = KInputDialog::getText(i18n("Prompt"), + QStyleSheet::convertFromPlainText(str), + QString::null, &ok); + if ( ok ) + return String(str2); + else + return Null(); + } + case KSVG::Window::_SetInterval: + if(args.size() >= 2 && v.isA(StringType)) + { + int i = args[1].toInt32(exec); + int r = (const_cast<Window *>(window))->installTimeout(s, i, false); + return Number(r); + } + else if(args.size() >= 2 && !Object::dynamicCast(v).isNull() && Object::dynamicCast(v).implementsCall()) + { + Value func = args[0]; + int i = args[1].toInt32(exec); + int r = (const_cast<Window *>(window))->installTimeout(s, i, false); + return Number(r); + } + else + return Undefined(); + case KSVG::Window::_SetTimeout: + if (args.size() == 2 && v.isA(StringType)) + { + int i = args[1].toInt32(exec); + int r = (const_cast<Window *>(window))->installTimeout(s, i, true /*single shot*/); + return Number(r); + } + else if(args.size() >= 2 && v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) + { + Value func = args[0]; + int i = args[1].toInt32(exec); + int r = (const_cast<Window *>(window))->installTimeout(s, i, false); + return Number(r); + } + else + return Undefined(); + } + + return Undefined(); +} + +int KSVG::Window::installTimeout(const UString &handler, int t, bool singleShot) +{ + return winq->installTimeout(handler, t, singleShot); +} + +void KSVG::Window::clearTimeout(int timerId) +{ + winq->clearTimeout(timerId); +} + +////////////////////// ScheduledAction //////////////////////// + +ScheduledAction::ScheduledAction(Object _func, List _args, bool _singleShot) +{ + func = _func; + args = _args; + isFunction = true; + singleShot = _singleShot; +} + +ScheduledAction::ScheduledAction(QString _code, bool _singleShot) +{ + code = _code; + isFunction = false; + singleShot = _singleShot; +} + +ScheduledAction::~ScheduledAction() +{ +} + +void ScheduledAction::execute(Window *window) +{ + Q_ASSERT(window->doc()); + + KSVGScriptInterpreter *interpreter = window->doc()->ecmaEngine()->interpreter(); + if(isFunction) + { + if(func.implementsCall()) + { + ExecState *exec = interpreter->globalExec(); + Q_ASSERT(window == interpreter->globalObject().imp()); + Object obj(window); + func.call(exec, obj, args); // note that call() creates its own execution state for the func call + } + } + else + { + interpreter->evaluate(code); + window->doc()->rerender(); + } +} + +////////////////////// WindowQObject //////////////////////// + +WindowQObject::WindowQObject(Window *w) : parent(w) +{ +} + +WindowQObject::~WindowQObject() +{ + parentDestroyed(); // reuse same code +} + +void WindowQObject::parentDestroyed() +{ + killTimers(); + + QMapIterator<int, ScheduledAction *> it; + for(it = scheduledActions.begin(); it != scheduledActions.end(); ++it) + { + ScheduledAction *action = *it; + delete action; + } + + scheduledActions.clear(); +} + +int WindowQObject::installTimeout(const UString &handler, int t, bool singleShot) +{ + int id = startTimer(t); + ScheduledAction *action = new ScheduledAction(handler.qstring(), singleShot); + scheduledActions.insert(id, action); + return id; +} + +int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot) +{ + Object objFunc = Object::dynamicCast(func); + int id = startTimer(t); + scheduledActions.insert(id, new ScheduledAction(objFunc, args, singleShot)); + return id; +} + +void WindowQObject::clearTimeout(int timerId, bool delAction) +{ + killTimer(timerId); + + if(delAction) + { + QMapIterator<int, ScheduledAction *> it = scheduledActions.find(timerId); + if(it != scheduledActions.end()) + { + ScheduledAction *action = *it; + scheduledActions.remove(it); + delete action; + } + } +} + +void WindowQObject::timerEvent(QTimerEvent *e) +{ + QMapIterator<int, ScheduledAction *> it = scheduledActions.find(e->timerId()); + if(it != scheduledActions.end()) + { + ScheduledAction *action = *it; + bool singleShot = action->singleShot; + + // remove single shots installed by setTimeout() + if(singleShot) + { + clearTimeout(e->timerId(), false); + scheduledActions.remove(it); + } + + if(parent->doc()) + action->execute(parent); + + // It is important to test singleShot and not action->singleShot here - the + // action could have been deleted already if not single shot and if the + // JS code called by execute() calls clearTimeout(). + if(singleShot) + delete action; + } + else + kdWarning(6070) << "WindowQObject::timerEvent this=" << this << " timer " << e->timerId() << " not found (" << scheduledActions.count() << " actions in map)" << endl; +} + +void WindowQObject::timeoutClose() +{ +} diff --git a/ksvg/ecma/ksvg_window.h b/ksvg/ecma/ksvg_window.h new file mode 100644 index 00000000..28c9699e --- /dev/null +++ b/ksvg/ecma/ksvg_window.h @@ -0,0 +1,122 @@ +/* This file is part of the KDE project + Copyright (C) 2002 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSVG_WINDOW_H +#define KSVG_WINDOW_H + +#include <kjs/object.h> +#include <qguardedptr.h> + +namespace KSVG { + +class SVGDocumentImpl; +class WindowQObject; + +// This is currently a fork of khtml's Window object, simplified. +// However in the long run it could become a base class for it. +// Author: David Faure <[email protected]> +class Window : public KJS::ObjectImp { + friend class WindowFunc; + friend class WindowQObject; + friend class ScheduledAction; +public: + Window(KSVG::SVGDocumentImpl *p); + ~Window(); + + virtual KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; + virtual void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr = KJS::None); + virtual bool hasProperty(KJS::ExecState * /*exec*/, const KJS::Identifier &/*p*/) const; + + /** + * Returns and registers a window object. In case there's already a Window + * for the specified part p this will be returned in order to have unique + * bindings. + */ + //static KJS::Value retrieve(KSVG::SVGDocumentImpl *p); + /** + * Returns the Window object for a given part + */ + //static Window *retrieveWindow(KSVG::SVGDocumentImpl *p); + /** + * returns a pointer to the Window object this javascript interpreting instance + * was called from. + */ + static Window *retrieveActive(KJS::ExecState *exec); + + QGuardedPtr<KSVG::SVGDocumentImpl> doc() const { return m_doc; } + + int installTimeout(const KJS::UString &handler, int t, bool singleShot); + void clearTimeout(int timerId); + + bool isSafeScript(KJS::ExecState *exec) const; + void clear( KJS::ExecState *exec ); + + enum { + // Properties + _Closed, _Window, _Document, _Evt, _InnerWidth, _InnerHeight, + _SVGTransform, _SVGLength, _SVGAngle, _SVGColor, _SVGPreserveAspectRatio, _SVGGradientElement, + _SVGPathSeg, _SVGTextContentElement, _SVGPaint, _SVGZoomAndPan, _SVGMarkerElement, _SVGTextPathElement, + _SetInterval, _ClearInterval, _SetTimeout, _ClearTimeout, _Navigator, _PrintNode, + // Functions + _Alert, _Confirm, _Debug, _Success, _GetSVGViewerVersion, _GetURL, _PostURL, _ParseXML, _Prompt + }; + + virtual const KJS::ClassInfo* classInfo() const { return &s_classInfo; } + static const KJS::ClassInfo s_classInfo; + static const struct KJS::HashTable s_hashTable; + +private: + WindowQObject *winq; + QGuardedPtr<KSVG::SVGDocumentImpl> m_doc; +}; + +class ScheduledAction { +public: + ScheduledAction(KJS::Object _func, KJS::List _args, bool _singleShot); + ScheduledAction(QString _code, bool _singleShot); + ~ScheduledAction(); + void execute(Window *window); + KJS::Object func; + KJS::List args; + QString code; + bool isFunction; + bool singleShot; +}; + +class WindowQObject : public QObject { + Q_OBJECT +public: + WindowQObject(Window *w); + ~WindowQObject(); + int installTimeout(const KJS::UString &handler, int t, bool singleShot); + int installTimeout(const KJS::Value &func, KJS::List args, int t, bool singleShot); + void clearTimeout(int timerId, bool delAction = true); +public slots: + void timeoutClose(); +protected slots: + void parentDestroyed(); +protected: + void timerEvent(QTimerEvent *e); +private: + Window *parent; + //KHTMLPart *part; // not guarded, may be dangling + QMap<int, ScheduledAction*> scheduledActions; +}; + +} +#endif // KSVG_WINDOW_H |