kdelibs/khtml/ecma/kjs_traversal.cpp
Ivailo Monev 39f1e04295 generic: add back khtml and kjs with some changes
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2015-11-09 23:23:53 +02:00

363 lines
12 KiB
C++

// -*- 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 <dom/dom_node.h>
#include <xml/dom_nodeimpl.h>
#include <xml/dom_docimpl.h>
#include <khtmlview.h>
#include <khtml_part.h>
#include <kdebug.h>
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<JSValue*>(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<DOMNodeIterator,DOMObject>(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<DOMNodeIterator *>(thisObj)->impl();
switch (id) {
case DOMNodeIterator::PreviousNode: {
SharedPtr<DOM::NodeImpl> node = nodeIterator.previousNode(exception, filterException);
if (!filterException)
return getDOMNode(exec, node.get());
break;
}
case DOMNodeIterator::NextNode: {
SharedPtr<DOM::NodeImpl> 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<DOM::NodeIteratorImpl, DOMNodeIterator>(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<NodeFilterConstructor,DOMObject>(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<NodeFilterConstructor>(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<DOMTreeWalker,DOMObject>(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<DOMTreeWalker *>(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<DOM::TreeWalkerImpl, DOMTreeWalker>(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<JSNodeFilter*>(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<JSNodeFilter*>(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;
}