/* 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 #include #include #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 TQPtrListIterator 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 *documentRequest = new KSVGBridge(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) { TQPtrListIterator it(m_ecmaEventListeners); for(; it.current(); ++it) { if(it.current()->type() == type.string()) return static_cast(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; } TQString KSVGEcma::valueOfEventListener(SVGEventListener *listener) const { KSVGEcmaEventListener *event = static_cast(listener); if(!event) return TQString(); 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(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) TQString 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 TQString &data, const TQString &mimeType, const TQString &contentEncoding, Object &callBackFunction) { Object *status = new Object(new AsyncStatus()); status->put(exec, Identifier("content"), String("")); status->put(exec, Identifier("success"), Boolean(false)); TQByteArray byteArray; TQDataStream ds(byteArray, IO_WriteOnly); ds << data; // Support gzip compression if(contentEncoding == "gzip" || contentEncoding == "deflate") byteArray = tqCompress(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(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(exec, new SVGDOMTextBridge(n)); ret->ref(); break; default: ret = new KSVGBridge(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(obj.imp())); if(bridge) return bridge->impl(); return DOM::Node(); } TQVariant KSVG::valueToVariant(ExecState *exec, const Value &val) { TQVariant res; switch(val.type()) { case BooleanType: res = TQVariant(val.toBoolean(exec), 0); break; case NumberType: res = TQVariant(val.toNumber(exec)); break; case StringType: res = TQVariant(val.toString(exec).qstring()); break; default: // everything else will be 'invalid' break; } return res; }