// -*- c-basic-offset: 2 -*- /* * This file is part of the KDE libraries * Copyright (C) 2001 Peter Kelly (pmk@post.com) * * 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; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "kjs_traversal.h" #include "kjs_traversal.lut.h" #include "kjs_proxy.h" #include #include #include #include #include #include using namespace KJS; namespace KJS { class TraversalExceptionForwarder { public: explicit TraversalExceptionForwarder(ExecState *exec) : m_exec(exec), m_code(0) { } ~TraversalExceptionForwarder() { if (m_code) m_exec->setException(static_cast(m_code)); } operator void* &() { return m_code; } private: ExecState *m_exec; void* m_code; }; } // ------------------------------------------------------------------------- const ClassInfo DOMNodeIterator::info = { "NodeIterator", 0, &DOMNodeIteratorTable, 0 }; /* @begin DOMNodeIteratorTable 5 root DOMNodeIterator::Root DontDelete|ReadOnly whatToShow DOMNodeIterator::WhatToShow DontDelete|ReadOnly filter DOMNodeIterator::Filter DontDelete|ReadOnly expandEntityReferences DOMNodeIterator::ExpandEntityReferences DontDelete|ReadOnly @end @begin DOMNodeIteratorProtoTable 3 nextNode DOMNodeIterator::NextNode DontDelete|Function 0 previousNode DOMNodeIterator::PreviousNode DontDelete|Function 0 detach DOMNodeIterator::Detach DontDelete|Function 0 @end */ KJS_DEFINE_PROTOTYPE(DOMNodeIteratorProto) KJS_IMPLEMENT_PROTOFUNC(DOMNodeIteratorProtoFunc) KJS_IMPLEMENT_PROTOTYPE("DOMNodeIterator",DOMNodeIteratorProto,DOMNodeIteratorProtoFunc,ObjectPrototype) DOMNodeIterator::DOMNodeIterator(ExecState *exec, DOM::NodeIteratorImpl* ni) : DOMObject(DOMNodeIteratorProto::self(exec)), m_impl(ni) {} DOMNodeIterator::~DOMNodeIterator() { ScriptInterpreter::forgetDOMObject(m_impl.get()); } bool DOMNodeIterator::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { return getStaticValueSlot(exec, &DOMNodeIteratorTable, this, propertyName, slot); } JSValue *DOMNodeIterator::getValueProperty(ExecState *exec, int token) const { DOM::NodeIteratorImpl& ni = *impl(); switch (token) { case Root: return getDOMNode(exec,ni.root()); case WhatToShow: return jsNumber(ni.whatToShow()); case Filter: return getDOMNodeFilter(exec,ni.filter()); case ExpandEntityReferences: return jsBoolean(ni.expandEntityReferences()); default: kDebug(6070) << "WARNING: Unhandled token in DOMNodeIterator::getValueProperty : " << token; return 0; } } JSValue* DOMNodeIteratorProtoFunc::callAsFunction(ExecState *exec, JSObject* thisObj, const List &) { KJS_CHECK_THIS( KJS::DOMNodeIterator, thisObj ); DOMExceptionTranslator exception(exec); TraversalExceptionForwarder filterException(exec); DOM::NodeIteratorImpl& nodeIterator = *static_cast(thisObj)->impl(); switch (id) { case DOMNodeIterator::PreviousNode: { SharedPtr node = nodeIterator.previousNode(exception, filterException); if (!filterException) return getDOMNode(exec, node.get()); break; } case DOMNodeIterator::NextNode: { SharedPtr node = nodeIterator.nextNode(exception, filterException); if (!filterException) return getDOMNode(exec, node.get()); break; } case DOMNodeIterator::Detach: nodeIterator.detach(exception); return jsUndefined(); } return jsUndefined(); } JSValue *KJS::getDOMNodeIterator(ExecState *exec, DOM::NodeIteratorImpl* ni) { return cacheDOMObject(exec, ni); } // ------------------------------------------------------------------------- const ClassInfo NodeFilterConstructor::info = { "NodeFilterConstructor", 0, &NodeFilterConstructorTable, 0 }; /* @begin NodeFilterConstructorTable 17 FILTER_ACCEPT DOM::NodeFilter::FILTER_ACCEPT DontDelete|ReadOnly FILTER_REJECT DOM::NodeFilter::FILTER_REJECT DontDelete|ReadOnly FILTER_SKIP DOM::NodeFilter::FILTER_SKIP DontDelete|ReadOnly SHOW_ALL DOM::NodeFilter::SHOW_ALL DontDelete|ReadOnly SHOW_ELEMENT DOM::NodeFilter::SHOW_ELEMENT DontDelete|ReadOnly SHOW_ATTRIBUTE DOM::NodeFilter::SHOW_ATTRIBUTE DontDelete|ReadOnly SHOW_TEXT DOM::NodeFilter::SHOW_TEXT DontDelete|ReadOnly SHOW_CDATA_SECTION DOM::NodeFilter::SHOW_CDATA_SECTION DontDelete|ReadOnly SHOW_ENTITY_REFERENCE DOM::NodeFilter::SHOW_ENTITY_REFERENCE DontDelete|ReadOnly SHOW_ENTITY DOM::NodeFilter::SHOW_ENTITY DontDelete|ReadOnly SHOW_PROCESSING_INSTRUCTION DOM::NodeFilter::SHOW_PROCESSING_INSTRUCTION DontDelete|ReadOnly SHOW_COMMENT DOM::NodeFilter::SHOW_COMMENT DontDelete|ReadOnly SHOW_DOCUMENT DOM::NodeFilter::SHOW_DOCUMENT DontDelete|ReadOnly SHOW_DOCUMENT_TYPE DOM::NodeFilter::SHOW_DOCUMENT_TYPE DontDelete|ReadOnly SHOW_DOCUMENT_FRAGMENT DOM::NodeFilter::SHOW_DOCUMENT_FRAGMENT DontDelete|ReadOnly SHOW_NOTATION DOM::NodeFilter::SHOW_NOTATION DontDelete|ReadOnly @end */ NodeFilterConstructor::NodeFilterConstructor(ExecState* exec) : DOMObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { } bool NodeFilterConstructor::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { return getStaticValueSlot(exec, &NodeFilterConstructorTable, this, propertyName, slot); } JSValue *NodeFilterConstructor::getValueProperty(ExecState *, int token) const { // We use the token as the value to return directly return jsNumber(token); } JSValue *KJS::getNodeFilterConstructor(ExecState *exec) { return cacheGlobalObject(exec, "[[nodeFilter.constructor]]"); } // ------------------------------------------------------------------------- const ClassInfo DOMTreeWalker::info = { "TreeWalker", 0, &DOMTreeWalkerTable, 0 }; /* @begin DOMTreeWalkerTable 5 root DOMTreeWalker::Root DontDelete|ReadOnly whatToShow DOMTreeWalker::WhatToShow DontDelete|ReadOnly filter DOMTreeWalker::Filter DontDelete|ReadOnly expandEntityReferences DOMTreeWalker::ExpandEntityReferences DontDelete|ReadOnly currentNode DOMTreeWalker::CurrentNode DontDelete @end @begin DOMTreeWalkerProtoTable 7 parentNode DOMTreeWalker::ParentNode DontDelete|Function 0 firstChild DOMTreeWalker::FirstChild DontDelete|Function 0 lastChild DOMTreeWalker::LastChild DontDelete|Function 0 previousSibling DOMTreeWalker::PreviousSibling DontDelete|Function 0 nextSibling DOMTreeWalker::NextSibling DontDelete|Function 0 previousNode DOMTreeWalker::PreviousNode DontDelete|Function 0 nextNode DOMTreeWalker::NextNode DontDelete|Function 0 @end */ KJS_DEFINE_PROTOTYPE(DOMTreeWalkerProto) KJS_IMPLEMENT_PROTOFUNC(DOMTreeWalkerProtoFunc) KJS_IMPLEMENT_PROTOTYPE("DOMTreeWalker",DOMTreeWalkerProto,DOMTreeWalkerProtoFunc,ObjectPrototype) DOMTreeWalker::DOMTreeWalker(ExecState *exec, DOM::TreeWalkerImpl* tw) : m_impl(tw) { setPrototype(DOMTreeWalkerProto::self(exec)); } DOMTreeWalker::~DOMTreeWalker() { ScriptInterpreter::forgetDOMObject(m_impl.get()); } void DOMTreeWalker::mark() { JSObject::mark(); JSNodeFilter* filt = JSNodeFilter::fromDOMFilter(impl()->getFilter()); if (filt) filt->mark(); } bool DOMTreeWalker::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { return getStaticValueSlot(exec, &DOMTreeWalkerTable, this, propertyName, slot); } JSValue *DOMTreeWalker::getValueProperty(ExecState *exec, int token) const { DOM::TreeWalkerImpl& tw = *impl(); switch (token) { case Root: return getDOMNode(exec,tw.getRoot()); case WhatToShow: return jsNumber(tw.getWhatToShow()); case Filter: return getDOMNodeFilter(exec,tw.getFilter()); case ExpandEntityReferences: return jsBoolean(tw.getExpandEntityReferences()); case CurrentNode: return getDOMNode(exec,tw.getCurrentNode()); default: kDebug(6070) << "WARNING: Unhandled token in DOMTreeWalker::getValueProperty : " << token; return 0; } } void DOMTreeWalker::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr) { DOMExceptionTranslator exception(exec); if (propertyName == "currentNode") { m_impl->setCurrentNode(toNode(value), exception); } else JSObject::put(exec, propertyName, value, attr); } JSValue* DOMTreeWalkerProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &) { KJS_CHECK_THIS( KJS::DOMTreeWalker, thisObj ); DOM::TreeWalkerImpl& treeWalker = *static_cast(thisObj)->impl(); TraversalExceptionForwarder filterException(exec); switch (id) { case DOMTreeWalker::ParentNode: return getDOMNode(exec,treeWalker.parentNode(filterException)); case DOMTreeWalker::FirstChild: return getDOMNode(exec,treeWalker.firstChild(filterException)); case DOMTreeWalker::LastChild: return getDOMNode(exec,treeWalker.lastChild(filterException)); case DOMTreeWalker::PreviousSibling: return getDOMNode(exec,treeWalker.previousSibling(filterException)); case DOMTreeWalker::NextSibling: return getDOMNode(exec,treeWalker.nextSibling(filterException)); case DOMTreeWalker::PreviousNode: return getDOMNode(exec,treeWalker.previousNode(filterException)); case DOMTreeWalker::NextNode: return getDOMNode(exec,treeWalker.nextNode(filterException)); } return jsUndefined(); } JSValue *KJS::getDOMTreeWalker(ExecState *exec, DOM::TreeWalkerImpl* tw) { return cacheDOMObject(exec, tw); } // ------------------------------------------------------------------------- DOM::NodeFilterImpl* KJS::toNodeFilter(JSValue *val) { JSObject *obj = val->getObject(); if (!obj) return 0; return new JSNodeFilter(obj); } JSValue *KJS::getDOMNodeFilter(ExecState *exec, DOM::NodeFilterImpl* nf) { Q_UNUSED(exec); if (nf && nf->isJSFilter()) { return static_cast(nf)->filter(); } return jsNull(); } JSNodeFilter::JSNodeFilter(JSObject *_filter) : m_filter( _filter ) {} JSNodeFilter::~JSNodeFilter() {} void JSNodeFilter::mark() { if (!m_filter->marked()) m_filter->mark(); } bool JSNodeFilter::isJSFilter() const { return true; } JSNodeFilter* JSNodeFilter::fromDOMFilter(DOM::NodeFilterImpl* nf) { if (!nf || !nf->isJSFilter()) return 0; return static_cast(nf); } short JSNodeFilter::acceptNode(const DOM::Node &n, void*& bindingsException) { KHTMLPart* part = n.handle()->document()->part(); if (!part) return DOM::NodeFilter::FILTER_REJECT; KJSProxy *proxy = part->jScript(); if (proxy) { ExecState *exec = proxy->interpreter()->globalExec(); JSObject* fn = 0; // Use a function given directly, or extract it from the acceptNode field if (m_filter->implementsCall()) { fn = m_filter; } else { JSObject *acceptNodeFunc = m_filter->get(exec, "acceptNode")->getObject(); if (acceptNodeFunc && acceptNodeFunc->implementsCall()) fn = acceptNodeFunc; } if (fn) { List args; args.append(getDOMNode(exec,n.handle())); JSValue *result = fn->call(exec, m_filter, args); if (exec->hadException()) { bindingsException = exec->exception(); exec->clearException(); return DOM::NodeFilter::FILTER_REJECT; // throw '1' isn't accept :-) } return result->toInteger(exec); } } return DOM::NodeFilter::FILTER_REJECT; }