kjs_traversal.cpp   [plain text]


/*
 *  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 Lesser 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"
#include "kjs_traversal.h"

#include "Document.h"
#include "Frame.h"
#include "JSNodeFilter.h"
#include "kjs_proxy.h"

#include "kjs_traversal.lut.h"

using namespace WebCore;

namespace KJS {

// -------------------------------------------------------------------------

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
  referenceNode DOMNodeIterator::ReferenceNode  DontDelete|ReadOnly
  pointerBeforeReferenceNode DOMNodeIterator::PointerBeforeReferenceNode        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)

DOMNodeIterator::DOMNodeIterator(ExecState *exec, NodeIterator *ni)
  : m_impl(ni)
{
  setPrototype(DOMNodeIteratorProto::self(exec));
}

DOMNodeIterator::~DOMNodeIterator()
{
  ScriptInterpreter::forgetDOMObject(m_impl.get());
}

void DOMNodeIterator::mark()
{
    m_impl->filter()->mark();
    DOMObject::mark();
}

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
{
  NodeIterator &ni = *m_impl;
  switch (token) {
  case Root:
    return toJS(exec,ni.root());
  case WhatToShow:
    return jsNumber(ni.whatToShow());
  case Filter:
    return toJS(exec,ni.filter());
  case ExpandEntityReferences:
    return jsBoolean(ni.expandEntityReferences());
  case ReferenceNode:
    return toJS(exec,ni.referenceNode());
  case PointerBeforeReferenceNode:
    return jsBoolean(ni.pointerBeforeReferenceNode());
 default:
   return 0;
  }
}

JSValue *DOMNodeIteratorProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &)
{
  if (!thisObj->inherits(&KJS::DOMNodeIterator::info))
    return throwError(exec, TypeError);
  DOMExceptionTranslator exception(exec);
  NodeIterator &nodeIterator = *static_cast<DOMNodeIterator *>(thisObj)->impl();
  switch (id) {
  case DOMNodeIterator::PreviousNode:
    return toJS(exec,nodeIterator.previousNode(exception));
  case DOMNodeIterator::NextNode:
    return toJS(exec,nodeIterator.nextNode(exception));
  case DOMNodeIterator::Detach:
    nodeIterator.detach(exception);
    return jsUndefined();
  }
  return jsUndefined();
}

JSValue *toJS(ExecState *exec, NodeIterator *ni)
{
  return cacheDOMObject<NodeIterator, DOMNodeIterator>(exec, ni);
}


// -------------------------------------------------------------------------

const ClassInfo DOMNodeFilter::info = { "NodeFilter", 0, 0, 0 };
/*
@begin DOMNodeFilterProtoTable 1
  acceptNode    DOMNodeFilter::AcceptNode       DontDelete|Function 0
@end
*/
KJS_DEFINE_PROTOTYPE(DOMNodeFilterProto)
KJS_IMPLEMENT_PROTOFUNC(DOMNodeFilterProtoFunc)
KJS_IMPLEMENT_PROTOTYPE("DOMNodeFilter",DOMNodeFilterProto,DOMNodeFilterProtoFunc)

DOMNodeFilter::DOMNodeFilter(ExecState *exec, NodeFilter *nf)
  : m_impl(nf) 
{
  setPrototype(DOMNodeFilterProto::self(exec));
}

DOMNodeFilter::~DOMNodeFilter()
{
  ScriptInterpreter::forgetDOMObject(m_impl.get());
}

void DOMNodeFilter::mark()
{
    m_impl->mark();
    DOMObject::mark();
}

JSValue *DOMNodeFilterProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
{
  if (!thisObj->inherits(&KJS::DOMNodeFilter::info))
    return throwError(exec, TypeError);
  NodeFilter &nodeFilter = *static_cast<DOMNodeFilter *>(thisObj)->impl();
  switch (id) {
    case DOMNodeFilter::AcceptNode:
      return jsNumber(nodeFilter.acceptNode(toNode(args[0])));
  }
  return jsUndefined();
}

JSValue *toJS(ExecState* exec, NodeFilter* nf)
{
    return cacheDOMObject<NodeFilter, JSNodeFilter>(exec, nf);
}

PassRefPtr<NodeFilter> toNodeFilter(JSValue* val)
{
    if (!val)
        return 0;
    if (!val->isObject())
        return 0;

    if (val->isObject(&DOMNodeFilter::info))
        return static_cast<DOMNodeFilter *>(val)->impl();

    JSObject* o = static_cast<JSObject*>(val);
    if (o->implementsCall())
        return new NodeFilter(new JSNodeFilterCondition(o));

    return 0;
}

// -------------------------------------------------------------------------

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)

DOMTreeWalker::DOMTreeWalker(ExecState *exec, TreeWalker *tw)
  : m_impl(tw)
{
  setPrototype(DOMTreeWalkerProto::self(exec));
}

DOMTreeWalker::~DOMTreeWalker()
{
  ScriptInterpreter::forgetDOMObject(m_impl.get());
}

void DOMTreeWalker::mark()
{
    m_impl->filter()->mark();
    DOMObject::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
{
  TreeWalker &tw = *m_impl;
  switch (token) {
  case Root:
    return toJS(exec,tw.root());
  case WhatToShow:
    return jsNumber(tw.whatToShow());
  case Filter:
    return toJS(exec,tw.filter());
  case ExpandEntityReferences:
    return jsBoolean(tw.expandEntityReferences());
  case CurrentNode:
    return toJS(exec,tw.currentNode());
  default:
    return 0;
  }
}

void DOMTreeWalker::put(ExecState *exec, const Identifier &propertyName,
                           JSValue *value, int attr)
{
  if (propertyName == "currentNode") {
    DOMExceptionTranslator exception(exec);
    m_impl->setCurrentNode(toNode(value), exception);
  }
  else
    JSObject::put(exec, propertyName, value, attr);
}

JSValue *DOMTreeWalkerProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &)
{
  if (!thisObj->inherits(&KJS::DOMTreeWalker::info))
    return throwError(exec, TypeError);
  TreeWalker &treeWalker = *static_cast<DOMTreeWalker *>(thisObj)->impl();
  switch (id) {
    case DOMTreeWalker::ParentNode:
      return toJS(exec,treeWalker.parentNode());
    case DOMTreeWalker::FirstChild:
      return toJS(exec,treeWalker.firstChild());
    case DOMTreeWalker::LastChild:
      return toJS(exec,treeWalker.lastChild());
    case DOMTreeWalker::PreviousSibling:
      return toJS(exec,treeWalker.previousSibling());
    case DOMTreeWalker::NextSibling:
      return toJS(exec,treeWalker.nextSibling());
    case DOMTreeWalker::PreviousNode:
      return toJS(exec,treeWalker.previousNode());
    case DOMTreeWalker::NextNode:
      return toJS(exec,treeWalker.nextNode());
  }
  return jsUndefined();
}

JSValue *toJS(ExecState *exec, TreeWalker *tw)
{
  return cacheDOMObject<TreeWalker, DOMTreeWalker>(exec, tw);
}

// -------------------------------------------------------------------------

JSNodeFilterCondition::JSNodeFilterCondition(JSObject * _filter)
    : filter( _filter )
{
}

void JSNodeFilterCondition::mark()
{
    filter->mark();
}

short JSNodeFilterCondition::acceptNode(WebCore::Node* filterNode) const
{
    WebCore::Node *node = filterNode;
    Frame *frame = node->document()->frame();
    KJSProxy *proxy = frame->jScript();
    if (proxy && filter->implementsCall()) {
        JSLock lock;
        ExecState *exec = proxy->interpreter()->globalExec();
        List args;
        args.append(toJS(exec, node));
        JSObject *obj = filter;
        JSValue *result = obj->call(exec, obj, args);
        return result->toInt32(exec);
    }

    return NodeFilter::FILTER_REJECT;
}

} // namespace