Commit 54b5cc13 authored by dino@apple.com's avatar dino@apple.com

2008-07-07 Simon Fraser <simon.fraser@apple.com>

        Reviewed by Darin.

        Fix for https://bugs.webkit.org/show_bug.cgi?id=19933
        nodeIterator with filter fails on documents not in a frame

        Tests: traversal/node-iterator-009.html
               traversal/tree-walker-006.html

        * bindings/js/JSNodeFilterCondition.cpp:
        * bindings/js/JSNodeFilterCondition.h:
        * bindings/js/JSNodeFilterCustom.cpp:
        * bindings/js/JSNodeIteratorCustom.cpp:
        * bindings/js/JSTreeWalkerCustom.cpp:
        * bindings/objc/DOM.mm:
        * dom/NodeFilter.cpp:
        * dom/NodeFilter.h:
        * dom/NodeFilterCondition.cpp:
        * dom/NodeFilterCondition.h:
        * dom/NodeIterator.cpp:
        * dom/NodeIterator.h:
        * dom/Traversal.cpp:
        * dom/Traversal.h:
        * dom/TreeWalker.cpp:
        * dom/TreeWalker.h:
        


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@35054 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 832e37f2
2008-07-07 Simon Fraser <simon.fraser@apple.com>
Reviewed by Darin.
Tests for https://bugs.webkit.org/show_bug.cgi?id=19933
nodeIterator with filter fails on documents not in a frame
* traversal/node-iterator-009-expected.txt: Added.
* traversal/node-iterator-009.html: Added.
* traversal/tree-walker-006-expected.txt: Added.
* traversal/tree-walker-006.html: Added.
2008-07-07 Adele Peterson <adele@apple.com>
Reviewed by Dan Bernstein.
XML doc elements:
records
Across the Universe 2:30 Not yet rated Sony Pictures 2007-02-15 2007-09-28
movieinfo
Across the Universe 2:30 Not yet rated Sony Pictures 2007-02-15 2007-09-28
info
Across the Universe 2:30 Not yet rated Sony Pictures 2007-02-15 2007-09-28
title
Across the Universe
runtime
2:30
rating
Not yet rated
postdate
2007-02-15
releasedate
2007-09-28
<html>
<head>
<title>Traversal Test</title>
</head>
<body>
<h2>XML doc elements:</h2>
<div style="font-family: Courier; font-size: 14;">
<script type="text/javascript" charset="utf-8">
if (window.layoutTestController)
layoutTestController.dumpAsText();
var dataURL = 'resources/node-iterator-009-data.xml';
function fetchXML()
{
var request = new XMLHttpRequest();
request.open("GET", dataURL, false /* sync */);
request.overrideMimeType("application/xml");
request.send();
if (request.readyState == 4) {
// only if "OK"
if (request.status == 200 || (request.status == 0 && request.responseText.length > 0))
walkXML(request.responseXML);
}
}
function testNodeFiter(n)
{
if (n.tagName == 'studio') return NodeFilter.FILTER_SKIP;
return NodeFilter.FILTER_ACCEPT;
}
function walkXML(xmlDoc)
{
var iter = document.createNodeIterator(xmlDoc, NodeFilter.SHOW_ELEMENT, testNodeFiter);
var curNode;
while (curNode = iter.nextNode()) {
document.write('<h3>' + curNode.tagName + '</h3><p>' + curNode.textContent + '</p>');
}
}
fetchXML();
</script>
</div>
</body>
</html>
XML doc elements:
records
Across the Universe 2:30 Not yet rated Sony Pictures 2007-02-15 2007-09-28
movieinfo
Across the Universe 2:30 Not yet rated Sony Pictures 2007-02-15 2007-09-28
info
Across the Universe 2:30 Not yet rated Sony Pictures 2007-02-15 2007-09-28
title
Across the Universe
runtime
2:30
rating
Not yet rated
postdate
2007-02-15
releasedate
2007-09-28
<html>
<head>
<title>Traversal Test</title>
</head>
<body>
<h2>XML doc elements:</h2>
<div style="font-family: Courier; font-size: 14;">
<script type="text/javascript" charset="utf-8">
if (window.layoutTestController)
layoutTestController.dumpAsText();
var dataURL = 'resources/node-iterator-009-data.xml';
function fetchXML()
{
var request = new XMLHttpRequest();
request.open("GET", dataURL, false /* sync */);
request.overrideMimeType("application/xml");
request.send();
if (request.readyState == 4) {
// only if "OK"
if (request.status == 200 || (request.status == 0 && request.responseText.length > 0))
walkXML(request.responseXML);
}
}
function testNodeFiter(n)
{
if (n.tagName == 'studio') return NodeFilter.FILTER_SKIP;
return NodeFilter.FILTER_ACCEPT;
}
function walkXML(xmlDoc)
{
var iter = document.createTreeWalker(xmlDoc, NodeFilter.SHOW_ELEMENT, testNodeFiter, false);
var curNode;
while (curNode = iter.nextNode()) {
document.write('<h3>' + curNode.tagName + '</h3><p>' + curNode.textContent + '</p>');
}
}
fetchXML();
</script>
</div>
</body>
</html>
2008-07-07 Simon Fraser <simon.fraser@apple.com>
Reviewed by Darin.
Fix for https://bugs.webkit.org/show_bug.cgi?id=19933
nodeIterator with filter fails on documents not in a frame
Tests: traversal/node-iterator-009.html
traversal/tree-walker-006.html
* bindings/js/JSNodeFilterCondition.cpp:
* bindings/js/JSNodeFilterCondition.h:
* bindings/js/JSNodeFilterCustom.cpp:
* bindings/js/JSNodeIteratorCustom.cpp:
* bindings/js/JSTreeWalkerCustom.cpp:
* bindings/objc/DOM.mm:
* dom/NodeFilter.cpp:
* dom/NodeFilter.h:
* dom/NodeFilterCondition.cpp:
* dom/NodeFilterCondition.h:
* dom/NodeIterator.cpp:
* dom/NodeIterator.h:
* dom/Traversal.cpp:
* dom/Traversal.h:
* dom/TreeWalker.cpp:
* dom/TreeWalker.h:
2008-07-07 Adele Peterson <adele@apple.com>
Reviewed by Dan Bernstein.
......@@ -20,26 +20,15 @@
#include "config.h"
#include "JSNodeFilterCondition.h"
#include "Document.h"
#include "Frame.h"
#include "JSNode.h"
#include "JSNodeFilter.h"
#include "NodeFilter.h"
#include "ScriptController.h"
#include <kjs/JSLock.h>
namespace WebCore {
using namespace KJS;
// FIXME: Add takeException as a member of ExecState?
static JSValue* takeException(ExecState* exec)
{
JSValue* exception = exec->exception();
exec->clearException();
return exception;
}
JSNodeFilterCondition::JSNodeFilterCondition(JSValue* filter)
: m_filter(filter)
{
......@@ -51,13 +40,8 @@ void JSNodeFilterCondition::mark()
m_filter->mark();
}
short JSNodeFilterCondition::acceptNode(Node* filterNode, JSValue*& exception) const
short JSNodeFilterCondition::acceptNode(KJS::ExecState* exec, Node* filterNode) const
{
// FIXME: It makes no sense for this to depend on the document being in a frame!
Frame* frame = filterNode->document()->frame();
if (!frame)
return NodeFilter::FILTER_REJECT;
JSLock lock(false);
CallData callData;
......@@ -65,23 +49,28 @@ short JSNodeFilterCondition::acceptNode(Node* filterNode, JSValue*& exception) c
if (callType == CallTypeNone)
return NodeFilter::FILTER_ACCEPT;
ExecState* exec = frame->script()->globalObject()->globalExec();
// The exec argument here should only be null if this was called from a
// non-JavaScript language, and this is a JavaScript filter, and the document
// in question is not associated with the frame. In that case, we're going to
// behave incorrectly, and just reject nodes instead of calling the filter function.
// To fix that we'd need to come up with a way to find a suitable JavaScript
// execution context for the filter function to run in.
if (!exec)
return NodeFilter::FILTER_REJECT;
ArgList args;
args.append(toJS(exec, filterNode));
if (exec->hadException()) {
exception = takeException(exec);
if (exec->hadException())
return NodeFilter::FILTER_REJECT;
}
JSValue* result = call(exec, m_filter, callType, callData, m_filter, args);
if (exec->hadException()) {
exception = takeException(exec);
if (exec->hadException())
return NodeFilter::FILTER_REJECT;
}
int intResult = result->toInt32(exec);
if (exec->hadException()) {
exception = takeException(exec);
if (exec->hadException())
return NodeFilter::FILTER_REJECT;
}
return intResult;
}
......
......@@ -41,7 +41,7 @@ namespace WebCore {
private:
JSNodeFilterCondition(KJS::JSValue* filter);
virtual short acceptNode(Node*, KJS::JSValue*& exception) const;
virtual short acceptNode(KJS::ExecState*, Node*) const;
virtual void mark();
KJS::JSValue* m_filter;
......
......@@ -43,11 +43,7 @@ void JSNodeFilter::mark()
JSValue* JSNodeFilter::acceptNode(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
short result = impl()->acceptNode(toNode(args[0]), exception);
if (exception)
exec->setException(exception);
return jsNumber(exec, result);
return jsNumber(exec, impl()->acceptNode(exec, toNode(args[0])));
}
PassRefPtr<NodeFilter> toNodeFilter(JSValue* value)
......
......@@ -40,32 +40,30 @@ void JSNodeIterator::mark()
JSValue* JSNodeIterator::nextNode(ExecState* exec, const ArgList& args)
{
ExceptionCode ec = 0;
JSValue* exception = 0;
RefPtr<Node> node = impl()->nextNode(ec, exception);
RefPtr<Node> node = impl()->nextNode(exec, ec);
if (ec) {
setDOMException(exec, ec);
return jsUndefined();
}
if (exception) {
exec->setException(exception);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node.get());
}
JSValue* JSNodeIterator::previousNode(ExecState* exec, const ArgList& args)
{
ExceptionCode ec = 0;
JSValue* exception = 0;
RefPtr<Node> node = impl()->previousNode(ec, exception);
RefPtr<Node> node = impl()->previousNode(exec, ec);
if (ec) {
setDOMException(exec, ec);
return jsUndefined();
}
if (exception) {
exec->setException(exception);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node.get());
}
......
......@@ -39,78 +39,57 @@ void JSTreeWalker::mark()
JSValue* JSTreeWalker::parentNode(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->parentNode(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->parentNode(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
JSValue* JSTreeWalker::firstChild(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->firstChild(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->firstChild(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
JSValue* JSTreeWalker::lastChild(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->lastChild(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->lastChild(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
JSValue* JSTreeWalker::nextSibling(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->nextSibling(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->nextSibling(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
JSValue* JSTreeWalker::previousSibling(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->previousSibling(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->previousSibling(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
JSValue* JSTreeWalker::previousNode(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->previousNode(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->previousNode(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
JSValue* JSTreeWalker::nextNode(ExecState* exec, const ArgList& args)
{
JSValue* exception = 0;
Node* node = impl()->nextNode(exception);
if (exception) {
exec->setException(exception);
Node* node = impl()->nextNode(exec);
if (exec->hadException())
return jsUndefined();
}
return toJS(exec, node);
}
......
......@@ -697,7 +697,7 @@ public:
return adoptRef(new ObjCNodeFilterCondition(filter));
}
virtual short acceptNode(Node*, JSValue*& exception) const;
virtual short acceptNode(ExecState*, Node*) const;
private:
ObjCNodeFilterCondition(id <DOMNodeFilter> filter)
......@@ -708,7 +708,7 @@ private:
RetainPtr<id <DOMNodeFilter> > m_filter;
};
short ObjCNodeFilterCondition::acceptNode(Node* node, JSValue*&) const
short ObjCNodeFilterCondition::acceptNode(ExecState*, Node* node) const
{
if (!node)
return NodeFilter::FILTER_REJECT;
......
......@@ -25,14 +25,37 @@
#include "config.h"
#include "NodeFilter.h"
#include "Document.h"
#include "Frame.h"
#include "Node.h"
#include "ScriptController.h"
using namespace KJS;
namespace WebCore {
short NodeFilter::acceptNode(Node* node, JSValue*& exception) const
short NodeFilter::acceptNode(ExecState* exec, Node* node) const
{
// cast to short silences "enumeral and non-enumeral types in return" warning
return m_condition ? m_condition->acceptNode(node, exception) : static_cast<short>(FILTER_ACCEPT);
return m_condition ? m_condition->acceptNode(exec, node) : static_cast<short>(FILTER_ACCEPT);
}
ExecState* NodeFilter::execStateFromNode(Node* node)
{
if (!node)
return 0;
Document* document = node->document();
if (!document)
return 0;
Frame* frame = document->frame();
if (!frame)
return 0;
if (!frame->script()->isEnabled())
return 0;
return frame->script()->globalObject()->globalExec();
}
} // namespace WebCore
......@@ -70,14 +70,18 @@ namespace WebCore {
return adoptRef(new NodeFilter(condition));
}
short acceptNode(Node*, KJS::JSValue*& exception) const;
short acceptNode(KJS::ExecState*, Node*) const;
void mark() { m_condition->mark(); };
// For non-JS bindings. Silently ignores the JavaScript exception if any.
short acceptNode(Node* node) const { KJS::JSValue* exception; return acceptNode(node, exception); }
short acceptNode(Node* node) const { return acceptNode(execStateFromNode(node), node); }
public:
static KJS::ExecState* execStateFromNode(Node*);
private:
NodeFilter(PassRefPtr<NodeFilterCondition> condition) : m_condition(condition) { }
RefPtr<NodeFilterCondition> m_condition;
};
......
......@@ -31,7 +31,7 @@ using namespace KJS;
namespace WebCore {
short NodeFilterCondition::acceptNode(Node*, JSValue*&) const
short NodeFilterCondition::acceptNode(ExecState*, Node*) const
{
return NodeFilter::FILTER_ACCEPT;
}
......
......@@ -28,7 +28,7 @@
#include <wtf/RefCounted.h>
namespace KJS {
class JSValue;
class ExecState;
}
namespace WebCore {
......@@ -38,7 +38,7 @@ namespace WebCore {
class NodeFilterCondition : public RefCounted<NodeFilterCondition> {
public:
virtual ~NodeFilterCondition() { }
virtual short acceptNode(Node*, KJS::JSValue*& exception) const = 0;
virtual short acceptNode(KJS::ExecState*, Node*) const = 0;
virtual void mark() { }
};
......
......@@ -25,6 +25,7 @@
#include "config.h"
#include "NodeIterator.h"
#include <kjs/ExecState.h>
#include "Document.h"
#include "ExceptionCode.h"
#include "NodeFilter.h"
......@@ -85,7 +86,7 @@ NodeIterator::~NodeIterator()
root()->document()->detachNodeIterator(this);
}
PassRefPtr<Node> NodeIterator::nextNode(ExceptionCode& ec, JSValue*& exception)
PassRefPtr<Node> NodeIterator::nextNode(ExecState* exec, ExceptionCode& ec)
{
if (m_detached) {
ec = INVALID_STATE_ERR;
......@@ -99,10 +100,9 @@ PassRefPtr<Node> NodeIterator::nextNode(ExceptionCode& ec, JSValue*& exception)
// NodeIterators treat the DOM tree as a flat list of nodes.
// In other words, FILTER_REJECT does not pass over descendants
// of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
exception = 0;
RefPtr<Node> provisionalResult = m_candidateNode.node;
bool nodeWasAccepted = acceptNode(provisionalResult.get(), exception) == NodeFilter::FILTER_ACCEPT;
if (exception)
bool nodeWasAccepted = acceptNode(exec, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
if (exec && exec->hadException())
break;
if (nodeWasAccepted) {
m_referenceNode = m_candidateNode;
......@@ -115,7 +115,7 @@ PassRefPtr<Node> NodeIterator::nextNode(ExceptionCode& ec, JSValue*& exception)
return result.release();
}
PassRefPtr<Node> NodeIterator::previousNode(ExceptionCode& ec, JSValue*& exception)
PassRefPtr<Node> NodeIterator::previousNode(ExecState* exec, ExceptionCode& ec)
{
if (m_detached) {
ec = INVALID_STATE_ERR;
......@@ -129,10 +129,9 @@ PassRefPtr<Node> NodeIterator::previousNode(ExceptionCode& ec, JSValue*& excepti
// NodeIterators treat the DOM tree as a flat list of nodes.
// In other words, FILTER_REJECT does not pass over descendants
// of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
exception = 0;
RefPtr<Node> provisionalResult = m_candidateNode.node;
bool nodeWasAccepted = acceptNode(provisionalResult.get(), exception) == NodeFilter::FILTER_ACCEPT;
if (exception)
bool nodeWasAccepted = acceptNode(exec, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
if (exec && exec->hadException())
break;
if (nodeWasAccepted) {
m_referenceNode = m_candidateNode;
......@@ -227,4 +226,5 @@ void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenc
}
}
} // namespace WebCore
......@@ -25,6 +25,7 @@
#ifndef NodeIterator_h
#define NodeIterator_h
#include "NodeFilter.h"
#include "Traversal.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
......@@ -41,8 +42,8 @@ namespace WebCore {
}
~NodeIterator();
PassRefPtr<Node> nextNode(ExceptionCode&, KJS::JSValue*& exception);
PassRefPtr<Node> previousNode(