diff options
Diffstat (limited to 'ksvg/ecma/ksvg_window.cpp')
-rw-r--r-- | ksvg/ecma/ksvg_window.cpp | 578 |
1 files changed, 578 insertions, 0 deletions
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 <faure@kde.org> + + 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() +{ +} |