summaryrefslogtreecommitdiffstats
path: root/WebCore/xml
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
commit8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch)
tree11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/xml
parent648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff)
downloadexternal_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip
external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz
external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/xml')
-rw-r--r--WebCore/xml/DOMParser.cpp42
-rw-r--r--WebCore/xml/DOMParser.h41
-rw-r--r--WebCore/xml/DOMParser.idl24
-rw-r--r--WebCore/xml/NativeXPathNSResolver.cpp58
-rw-r--r--WebCore/xml/NativeXPathNSResolver.h53
-rw-r--r--WebCore/xml/XMLHttpRequest.cpp1317
-rw-r--r--WebCore/xml/XMLHttpRequest.h232
-rw-r--r--WebCore/xml/XMLHttpRequest.idl99
-rw-r--r--WebCore/xml/XMLHttpRequestException.h60
-rw-r--r--WebCore/xml/XMLHttpRequestException.idl49
-rw-r--r--WebCore/xml/XMLHttpRequestProgressEvent.h61
-rw-r--r--WebCore/xml/XMLHttpRequestProgressEvent.idl36
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.cpp144
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.h110
-rw-r--r--WebCore/xml/XMLHttpRequestUpload.idl54
-rw-r--r--WebCore/xml/XMLSerializer.cpp48
-rw-r--r--WebCore/xml/XMLSerializer.h44
-rw-r--r--WebCore/xml/XMLSerializer.idl28
-rw-r--r--WebCore/xml/XPathEvaluator.cpp77
-rw-r--r--WebCore/xml/XPathEvaluator.h62
-rw-r--r--WebCore/xml/XPathEvaluator.idl35
-rw-r--r--WebCore/xml/XPathException.h64
-rw-r--r--WebCore/xml/XPathException.idl50
-rw-r--r--WebCore/xml/XPathExpression.cpp93
-rw-r--r--WebCore/xml/XPathExpression.h66
-rw-r--r--WebCore/xml/XPathExpression.idl34
-rw-r--r--WebCore/xml/XPathExpressionNode.cpp56
-rw-r--r--WebCore/xml/XPathExpressionNode.h85
-rw-r--r--WebCore/xml/XPathFunctions.cpp683
-rw-r--r--WebCore/xml/XPathFunctions.h62
-rw-r--r--WebCore/xml/XPathGrammar.y554
-rw-r--r--WebCore/xml/XPathNSResolver.cpp40
-rw-r--r--WebCore/xml/XPathNSResolver.h51
-rw-r--r--WebCore/xml/XPathNSResolver.idl27
-rw-r--r--WebCore/xml/XPathNamespace.cpp85
-rw-r--r--WebCore/xml/XPathNamespace.h66
-rw-r--r--WebCore/xml/XPathNodeSet.cpp206
-rw-r--r--WebCore/xml/XPathNodeSet.h82
-rw-r--r--WebCore/xml/XPathParser.cpp633
-rw-r--r--WebCore/xml/XPathParser.h131
-rw-r--r--WebCore/xml/XPathPath.cpp201
-rw-r--r--WebCore/xml/XPathPath.h93
-rw-r--r--WebCore/xml/XPathPredicate.cpp284
-rw-r--r--WebCore/xml/XPathPredicate.h111
-rw-r--r--WebCore/xml/XPathResult.cpp245
-rw-r--r--WebCore/xml/XPathResult.h94
-rw-r--r--WebCore/xml/XPathResult.idl57
-rw-r--r--WebCore/xml/XPathStep.cpp306
-rw-r--r--WebCore/xml/XPathStep.h104
-rw-r--r--WebCore/xml/XPathUtil.cpp96
-rw-r--r--WebCore/xml/XPathUtil.h56
-rw-r--r--WebCore/xml/XPathValue.cpp128
-rw-r--r--WebCore/xml/XPathValue.h106
-rw-r--r--WebCore/xml/XPathVariableReference.cpp55
-rw-r--r--WebCore/xml/XPathVariableReference.h50
-rw-r--r--WebCore/xml/XSLImportRule.cpp117
-rw-r--r--WebCore/xml/XSLImportRule.h72
-rw-r--r--WebCore/xml/XSLStyleSheet.cpp288
-rw-r--r--WebCore/xml/XSLStyleSheet.h99
-rw-r--r--WebCore/xml/XSLTExtensions.cpp88
-rw-r--r--WebCore/xml/XSLTExtensions.h40
-rw-r--r--WebCore/xml/XSLTProcessor.cpp461
-rw-r--r--WebCore/xml/XSLTProcessor.h81
-rw-r--r--WebCore/xml/XSLTProcessor.idl52
-rw-r--r--WebCore/xml/XSLTUnicodeSort.cpp352
-rw-r--r--WebCore/xml/XSLTUnicodeSort.h42
-rw-r--r--WebCore/xml/xmlattrs.in6
67 files changed, 9426 insertions, 0 deletions
diff --git a/WebCore/xml/DOMParser.cpp b/WebCore/xml/DOMParser.cpp
new file mode 100644
index 0000000..448dcb1
--- /dev/null
+++ b/WebCore/xml/DOMParser.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "DOMParser.h"
+
+#include "DOMImplementation.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+PassRefPtr<Document> DOMParser::parseFromString(const String& str, const String& contentType)
+{
+ if (!DOMImplementation::isXMLMIMEType(contentType))
+ return 0;
+
+ RefPtr<Document> doc = DOMImplementation::createDocument(contentType, 0, false);
+
+ doc->open();
+ doc->write(str);
+ doc->finishParsing();
+ doc->close();
+
+ return doc.release();
+}
+
+}
diff --git a/WebCore/xml/DOMParser.h b/WebCore/xml/DOMParser.h
new file mode 100644
index 0000000..5036d22
--- /dev/null
+++ b/WebCore/xml/DOMParser.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DOMParser_h
+#define DOMParser_h
+
+#include <wtf/RefCounted.h>
+#include "Document.h"
+
+namespace WebCore {
+
+ class String;
+
+ class DOMParser : public RefCounted<DOMParser> {
+ public:
+ static PassRefPtr<DOMParser> create() { return adoptRef(new DOMParser); }
+
+ PassRefPtr<Document> parseFromString(const String& str, const String& contentType);
+
+ private:
+ DOMParser() { }
+ };
+
+}
+
+#endif // XMLSerializer.h
diff --git a/WebCore/xml/DOMParser.idl b/WebCore/xml/DOMParser.idl
new file mode 100644
index 0000000..9caaa21
--- /dev/null
+++ b/WebCore/xml/DOMParser.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module xpath {
+ interface [GenerateConstructor, CanBeConstructed] DOMParser {
+ Document parseFromString(in DOMString str, in DOMString contentType);
+ };
+}
diff --git a/WebCore/xml/NativeXPathNSResolver.cpp b/WebCore/xml/NativeXPathNSResolver.cpp
new file mode 100644
index 0000000..11faea6
--- /dev/null
+++ b/WebCore/xml/NativeXPathNSResolver.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "NativeXPathNSResolver.h"
+
+#if ENABLE(XPATH)
+
+#include "Node.h"
+#include "PlatformString.h"
+#include "XMLNames.h"
+
+namespace WebCore {
+
+NativeXPathNSResolver::NativeXPathNSResolver(PassRefPtr<Node> node)
+ : m_node(node)
+{
+}
+
+NativeXPathNSResolver::~NativeXPathNSResolver()
+{
+}
+
+String NativeXPathNSResolver::lookupNamespaceURI(const String& prefix)
+{
+ // This is not done by Node::lookupNamespaceURI as per the DOM3 Core spec,
+ // but the XPath spec says that we should do it for XPathNSResolver.
+ if (prefix == "xml")
+ return XMLNames::xmlNamespaceURI;
+
+ return m_node ? m_node->lookupNamespaceURI(prefix) : String();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/NativeXPathNSResolver.h b/WebCore/xml/NativeXPathNSResolver.h
new file mode 100644
index 0000000..212b929
--- /dev/null
+++ b/WebCore/xml/NativeXPathNSResolver.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NativeXPathNSResolver_h
+#define NativeXPathNSResolver_h
+
+#if ENABLE(XPATH)
+
+#include "XPathNSResolver.h"
+#include "Node.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class NativeXPathNSResolver : public XPathNSResolver {
+ public:
+ static PassRefPtr<NativeXPathNSResolver> create(PassRefPtr<Node> node) { return adoptRef(new NativeXPathNSResolver(node)); }
+ virtual ~NativeXPathNSResolver();
+
+ virtual String lookupNamespaceURI(const String& prefix);
+
+ private:
+ NativeXPathNSResolver(PassRefPtr<Node>);
+ RefPtr<Node> m_node;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(XPATH)
+
+#endif // NativeXPathNSResolver_h
diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp
new file mode 100644
index 0000000..67aba0b
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequest.cpp
@@ -0,0 +1,1317 @@
+/*
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
+ * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "XMLHttpRequest.h"
+
+#include "CString.h"
+#include "Console.h"
+#include "DOMImplementation.h"
+#include "DOMWindow.h"
+#include "Event.h"
+#include "EventException.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "File.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "HTTPParsers.h"
+#include "InspectorController.h"
+#include "JSDOMBinding.h"
+#include "JSDOMWindow.h"
+#include "KURL.h"
+#include "KURLHash.h"
+#include "Page.h"
+#include "Settings.h"
+#include "SubresourceLoader.h"
+#include "SystemTime.h"
+#include "TextResourceDecoder.h"
+#include "XMLHttpRequestException.h"
+#include "XMLHttpRequestProgressEvent.h"
+#include "XMLHttpRequestUpload.h"
+#include "markup.h"
+#include <runtime/JSLock.h>
+
+namespace WebCore {
+
+struct PreflightResultCacheItem {
+ PreflightResultCacheItem(unsigned expiryDelta, bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
+ : m_absoluteExpiryTime(currentTime() + expiryDelta)
+ , m_credentials(credentials)
+ , m_methods(methods)
+ , m_headers(headers)
+ {
+ }
+
+ // FIXME: A better solution to holding onto the absolute expiration time might be
+ // to start a timer for the expiration delta, that removes this from the cache when
+ // it fires.
+ double m_absoluteExpiryTime;
+ bool m_credentials;
+ OwnPtr<HashSet<String> > m_methods;
+ OwnPtr<HashSet<String, CaseFoldingHash> > m_headers;
+};
+
+typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultCache;
+
+static PreflightResultCache& preflightResultCache()
+{
+ static PreflightResultCache cache;
+ return cache;
+}
+
+static void appendPreflightResultCacheEntry(String origin, KURL url, unsigned expiryDelta,
+ bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
+{
+ ASSERT(!preflightResultCache().contains(std::make_pair(origin, url)));
+
+ PreflightResultCacheItem* item = new PreflightResultCacheItem(expiryDelta, credentials, methods, headers);
+ preflightResultCache().set(std::make_pair(origin, url), item);
+}
+
+static bool isSafeRequestHeader(const String& name)
+{
+ static HashSet<String, CaseFoldingHash> forbiddenHeaders;
+ static String proxyString("proxy-");
+ static String secString("sec-");
+
+ if (forbiddenHeaders.isEmpty()) {
+ forbiddenHeaders.add("accept-charset");
+ forbiddenHeaders.add("accept-encoding");
+ forbiddenHeaders.add("connection");
+ forbiddenHeaders.add("content-length");
+ forbiddenHeaders.add("content-transfer-encoding");
+ forbiddenHeaders.add("date");
+ forbiddenHeaders.add("expect");
+ forbiddenHeaders.add("host");
+ forbiddenHeaders.add("keep-alive");
+ forbiddenHeaders.add("referer");
+ forbiddenHeaders.add("te");
+ forbiddenHeaders.add("trailer");
+ forbiddenHeaders.add("transfer-encoding");
+ forbiddenHeaders.add("upgrade");
+ forbiddenHeaders.add("via");
+ }
+
+ return !forbiddenHeaders.contains(name) && !name.startsWith(proxyString, false) &&
+ !name.startsWith(secString, false);
+}
+
+static bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name)
+{
+ return equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-type");
+}
+
+static bool isOnAccessControlResponseHeaderWhitelist(const String& name)
+{
+ static HashSet<String, CaseFoldingHash> allowedHeaders;
+ if (allowedHeaders.isEmpty()) {
+ allowedHeaders.add("cache-control");
+ allowedHeaders.add("content-language");
+ allowedHeaders.add("content-type");
+ allowedHeaders.add("expires");
+ allowedHeaders.add("last-modified");
+ allowedHeaders.add("pragma");
+ }
+
+ return allowedHeaders.contains(name);
+}
+
+// Determines if a string is a valid token, as defined by
+// "token" in section 2.2 of RFC 2616.
+static bool isValidToken(const String& name)
+{
+ unsigned length = name.length();
+ for (unsigned i = 0; i < length; i++) {
+ UChar c = name[i];
+
+ if (c >= 127 || c <= 32)
+ return false;
+
+ if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
+ c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
+ c == '/' || c == '[' || c == ']' || c == '?' || c == '=' ||
+ c == '{' || c == '}')
+ return false;
+ }
+
+ return true;
+}
+
+static bool isValidHeaderValue(const String& name)
+{
+ // FIXME: This should really match name against
+ // field-value in section 4.2 of RFC 2616.
+
+ return !name.contains('\r') && !name.contains('\n');
+}
+
+XMLHttpRequest::XMLHttpRequest(Document* doc)
+ : ActiveDOMObject(doc, this)
+ , m_async(true)
+ , m_includeCredentials(false)
+ , m_state(UNSENT)
+ , m_identifier(std::numeric_limits<unsigned long>::max())
+ , m_responseText("")
+ , m_createdDocument(false)
+ , m_error(false)
+ , m_uploadComplete(false)
+ , m_sameOriginRequest(true)
+ , m_inPreflight(false)
+ , m_receivedLength(0)
+ , m_lastSendLineNumber(0)
+{
+ ASSERT(document());
+}
+
+XMLHttpRequest::~XMLHttpRequest()
+{
+ if (m_upload)
+ m_upload->disconnectXMLHttpRequest();
+}
+
+Document* XMLHttpRequest::document() const
+{
+ ASSERT(scriptExecutionContext()->isDocument());
+ return static_cast<Document*>(scriptExecutionContext());
+}
+
+XMLHttpRequest::State XMLHttpRequest::readyState() const
+{
+ return m_state;
+}
+
+const JSC::UString& XMLHttpRequest::responseText() const
+{
+ return m_responseText;
+}
+
+Document* XMLHttpRequest::responseXML() const
+{
+ if (m_state != DONE)
+ return 0;
+
+ if (!m_createdDocument) {
+ if (m_response.isHTTP() && !responseIsXML()) {
+ // The W3C spec requires this.
+ m_responseXML = 0;
+ } else {
+ m_responseXML = document()->implementation()->createDocument(0);
+ m_responseXML->open();
+ m_responseXML->setURL(m_url);
+ // FIXME: set Last-Modified and cookies (currently, those are only available for HTMLDocuments).
+ m_responseXML->write(String(m_responseText));
+ m_responseXML->finishParsing();
+ m_responseXML->close();
+
+ if (!m_responseXML->wellFormed())
+ m_responseXML = 0;
+ }
+ m_createdDocument = true;
+ }
+
+ return m_responseXML.get();
+}
+
+XMLHttpRequestUpload* XMLHttpRequest::upload()
+{
+ if (!m_upload)
+ m_upload = XMLHttpRequestUpload::create(this);
+ return m_upload.get();
+}
+
+void XMLHttpRequest::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool)
+{
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
+ if (iter == m_eventListeners.end()) {
+ ListenerVector listeners;
+ listeners.append(eventListener);
+ m_eventListeners.add(eventType, listeners);
+ } else {
+ ListenerVector& listeners = iter->second;
+ for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter)
+ if (*listenerIter == eventListener)
+ return;
+
+ listeners.append(eventListener);
+ m_eventListeners.add(eventType, listeners);
+ }
+}
+
+void XMLHttpRequest::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
+{
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
+ if (iter == m_eventListeners.end())
+ return;
+
+ ListenerVector& listeners = iter->second;
+ for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter)
+ if (*listenerIter == eventListener) {
+ listeners.remove(listenerIter - listeners.begin());
+ return;
+ }
+}
+
+bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec)
+{
+ // FIXME: check for other error conditions enumerated in the spec.
+ if (evt->type().isEmpty()) {
+ ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ return true;
+ }
+
+ ListenerVector listenersCopy = m_eventListeners.get(evt->type());
+ for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listenerIter->get()->handleEvent(evt.get(), false);
+ }
+
+ return !evt->defaultPrevented();
+}
+
+void XMLHttpRequest::changeState(State newState)
+{
+ if (m_state != newState) {
+ m_state = newState;
+ callReadyStateChangeListener();
+ }
+}
+
+void XMLHttpRequest::callReadyStateChangeListener()
+{
+ if (!document() || !document()->frame())
+ return;
+
+ dispatchReadyStateChangeEvent();
+
+ if (m_state == DONE)
+ dispatchLoadEvent();
+}
+
+void XMLHttpRequest::open(const String& method, const KURL& url, bool async, ExceptionCode& ec)
+{
+ internalAbort();
+ State previousState = m_state;
+ m_state = UNSENT;
+ m_error = false;
+
+ m_uploadComplete = false;
+
+ // clear stuff from possible previous load
+ clearResponse();
+ clearRequest();
+
+ ASSERT(m_state == UNSENT);
+
+ if (!isValidToken(method)) {
+ ec = SYNTAX_ERR;
+ return;
+ }
+
+ // Method names are case sensitive. But since Firefox uppercases method names it knows, we'll do the same.
+ String methodUpper(method.upper());
+
+ if (methodUpper == "TRACE" || methodUpper == "TRACK" || methodUpper == "CONNECT") {
+ ec = SECURITY_ERR;
+ return;
+ }
+
+ m_url = url;
+
+ if (methodUpper == "COPY" || methodUpper == "DELETE" || methodUpper == "GET" || methodUpper == "HEAD"
+ || methodUpper == "INDEX" || methodUpper == "LOCK" || methodUpper == "M-POST" || methodUpper == "MKCOL" || methodUpper == "MOVE"
+ || methodUpper == "OPTIONS" || methodUpper == "POST" || methodUpper == "PROPFIND" || methodUpper == "PROPPATCH" || methodUpper == "PUT"
+ || methodUpper == "UNLOCK")
+ m_method = methodUpper;
+ else
+ m_method = method;
+
+ m_async = async;
+
+ ASSERT(!m_loader);
+
+ // Check previous state to avoid dispatching readyState event
+ // when calling open several times in a row.
+ if (previousState != OPENED)
+ changeState(OPENED);
+ else
+ m_state = OPENED;
+}
+
+void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, ExceptionCode& ec)
+{
+ KURL urlWithCredentials(url);
+ urlWithCredentials.setUser(user);
+
+ open(method, urlWithCredentials, async, ec);
+}
+
+void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, const String& password, ExceptionCode& ec)
+{
+ KURL urlWithCredentials(url);
+ urlWithCredentials.setUser(user);
+ urlWithCredentials.setPass(password);
+
+ open(method, urlWithCredentials, async, ec);
+}
+
+bool XMLHttpRequest::initSend(ExceptionCode& ec)
+{
+ if (!document())
+ return false;
+
+ if (m_state != OPENED || m_loader) {
+ ec = INVALID_STATE_ERR;
+ return false;
+ }
+
+ m_error = false;
+ return true;
+}
+
+void XMLHttpRequest::send(ExceptionCode& ec)
+{
+ send(String(), ec);
+}
+
+void XMLHttpRequest::send(Document* document, ExceptionCode& ec)
+{
+ ASSERT(document);
+
+ if (!initSend(ec))
+ return;
+
+ if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
+ String contentType = getRequestHeader("Content-Type");
+ if (contentType.isEmpty()) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ Settings* settings = document->settings();
+ if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
+ else
+#endif
+ // FIXME: this should include the charset used for encoding.
+ setRequestHeaderInternal("Content-Type", "application/xml");
+ }
+
+ // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
+ // from the HTML5 specification to serialize the document.
+ String body = createMarkup(document);
+
+ // FIXME: this should use value of document.inputEncoding to determine the encoding to use.
+ TextEncoding encoding = UTF8Encoding();
+ m_requestEntityBody = FormData::create(encoding.encode(body.characters(), body.length(), EntitiesForUnencodables));
+ if (m_upload)
+ m_requestEntityBody->setAlwaysStream(true);
+ }
+
+ createRequest(ec);
+}
+
+void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
+{
+ if (!initSend(ec))
+ return;
+
+ if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
+ String contentType = getRequestHeader("Content-Type");
+ if (contentType.isEmpty()) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ Settings* settings = document()->settings();
+ if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
+ else
+#endif
+ setRequestHeaderInternal("Content-Type", "application/xml");
+ }
+
+ m_requestEntityBody = FormData::create(UTF8Encoding().encode(body.characters(), body.length(), EntitiesForUnencodables));
+ if (m_upload)
+ m_requestEntityBody->setAlwaysStream(true);
+ }
+
+ createRequest(ec);
+}
+
+void XMLHttpRequest::send(File* body, ExceptionCode& ec)
+{
+ if (!initSend(ec))
+ return;
+
+ if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
+ // FIXME: Should we set a Content-Type if one is not set.
+ // FIXME: add support for uploading bundles.
+ m_requestEntityBody = FormData::create();
+ m_requestEntityBody->appendFile(body->path(), false);
+ }
+
+ createRequest(ec);
+}
+
+void XMLHttpRequest::createRequest(ExceptionCode& ec)
+{
+ if (m_async) {
+ dispatchLoadStartEvent();
+ if (m_requestEntityBody && m_upload)
+ m_upload->dispatchLoadStartEvent();
+ }
+
+ m_sameOriginRequest = document()->securityOrigin()->canRequest(m_url);
+
+ if (!m_sameOriginRequest) {
+ makeCrossSiteAccessRequest(ec);
+ return;
+ }
+
+ makeSameOriginRequest(ec);
+}
+
+void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec)
+{
+ ASSERT(m_sameOriginRequest);
+
+ ResourceRequest request(m_url);
+ request.setHTTPMethod(m_method);
+
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+
+ if (m_async)
+ loadRequestAsynchronously(request);
+ else
+ loadRequestSynchronously(request, ec);
+}
+
+bool XMLHttpRequest::isSimpleCrossSiteAccessRequest() const
+{
+ if (m_method != "GET" && m_method != "POST")
+ return false;
+
+ HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
+ for (HTTPHeaderMap::const_iterator it = m_requestHeaders.begin(); it != end; ++it) {
+ if (!isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
+ return false;
+ }
+
+ return true;
+}
+
+void XMLHttpRequest::makeCrossSiteAccessRequest(ExceptionCode& ec)
+{
+ ASSERT(!m_sameOriginRequest);
+
+ if (isSimpleCrossSiteAccessRequest())
+ makeSimpleCrossSiteAccessRequest(ec);
+ else
+ makeCrossSiteAccessRequestWithPreflight(ec);
+}
+
+void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
+{
+ ASSERT(isSimpleCrossSiteAccessRequest());
+
+ KURL url = m_url;
+ url.setUser(String());
+ url.setPass(String());
+
+ ResourceRequest request(url);
+ request.setHTTPMethod(m_method);
+ request.setAllowHTTPCookies(m_includeCredentials);
+ request.setHTTPOrigin(document()->securityOrigin()->toString());
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+
+ if (m_async)
+ loadRequestAsynchronously(request);
+ else
+ loadRequestSynchronously(request, ec);
+}
+
+static bool canSkipPrelight(PreflightResultCache::iterator cacheIt, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders)
+{
+ PreflightResultCacheItem* item = cacheIt->second;
+ if (item->m_absoluteExpiryTime < currentTime())
+ return false;
+ if (includeCredentials && !item->m_credentials)
+ return false;
+ if (!item->m_methods->contains(method) && method != "GET" && method != "POST")
+ return false;
+ HTTPHeaderMap::const_iterator end = requestHeaders.end();
+ for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
+ if (!item->m_headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
+ return false;
+ }
+
+ return true;
+}
+
+void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
+{
+ String origin = document()->securityOrigin()->toString();
+ KURL url = m_url;
+ url.setUser(String());
+ url.setPass(String());
+
+ bool skipPreflight = false;
+
+ PreflightResultCache::iterator cacheIt = preflightResultCache().find(std::make_pair(origin, url));
+ if (cacheIt != preflightResultCache().end()) {
+ skipPreflight = canSkipPrelight(cacheIt, m_includeCredentials, m_method, m_requestHeaders);
+ if (!skipPreflight) {
+ delete cacheIt->second;
+ preflightResultCache().remove(cacheIt);
+ }
+ }
+
+ if (!skipPreflight) {
+ m_inPreflight = true;
+ ResourceRequest preflightRequest(url);
+ preflightRequest.setHTTPMethod("OPTIONS");
+ preflightRequest.setHTTPHeaderField("Origin", origin);
+ preflightRequest.setHTTPHeaderField("Access-Control-Request-Method", m_method);
+
+ if (m_requestHeaders.size() > 0) {
+ Vector<UChar> headerBuffer;
+ HTTPHeaderMap::const_iterator it = m_requestHeaders.begin();
+ append(headerBuffer, it->first);
+ ++it;
+
+ HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
+ for (; it != end; ++it) {
+ headerBuffer.append(',');
+ headerBuffer.append(' ');
+ append(headerBuffer, it->first);
+ }
+
+ preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", String::adopt(headerBuffer));
+ preflightRequest.addHTTPHeaderFields(m_requestHeaders);
+ }
+
+ if (m_async) {
+ loadRequestAsynchronously(preflightRequest);
+ return;
+ }
+
+ loadRequestSynchronously(preflightRequest, ec);
+ m_inPreflight = false;
+
+ if (ec)
+ return;
+ }
+
+ // Send the actual request.
+ ResourceRequest request(url);
+ request.setHTTPMethod(m_method);
+ request.setAllowHTTPCookies(m_includeCredentials);
+ request.setHTTPHeaderField("Origin", origin);
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
+ if (m_async) {
+ loadRequestAsynchronously(request);
+ return;
+ }
+
+ loadRequestSynchronously(request, ec);
+}
+
+void XMLHttpRequest::handleAsynchronousPreflightResult()
+{
+ ASSERT(m_inPreflight);
+ ASSERT(m_async);
+
+ m_inPreflight = false;
+
+ KURL url = m_url;
+ url.setUser(String());
+ url.setPass(String());
+
+ ResourceRequest request(url);
+ request.setHTTPMethod(m_method);
+ request.setAllowHTTPCookies(m_includeCredentials);
+ request.setHTTPOrigin(document()->securityOrigin()->toString());
+
+ if (m_requestHeaders.size() > 0)
+ request.addHTTPHeaderFields(m_requestHeaders);
+
+ if (m_requestEntityBody) {
+ ASSERT(m_method != "GET");
+ request.setHTTPBody(m_requestEntityBody.release());
+ }
+
+ loadRequestAsynchronously(request);
+}
+
+void XMLHttpRequest::loadRequestSynchronously(ResourceRequest& request, ExceptionCode& ec)
+{
+ ASSERT(!m_async);
+ Vector<char> data;
+ ResourceError error;
+ ResourceResponse response;
+
+ if (document()->frame())
+ m_identifier = document()->frame()->loader()->loadResourceSynchronously(request, error, response, data);
+
+ m_loader = 0;
+
+ // No exception for file:/// resources, see <rdar://problem/4962298>.
+ // Also, if we have an HTTP response, then it wasn't a network error in fact.
+ if (error.isNull() || request.url().isLocalFile() || response.httpStatusCode() > 0) {
+ processSyncLoadResults(data, response, ec);
+ return;
+ }
+
+ if (error.isCancellation()) {
+ abortError();
+ ec = XMLHttpRequestException::ABORT_ERR;
+ return;
+ }
+
+ networkError();
+ ec = XMLHttpRequestException::NETWORK_ERR;
+}
+
+
+void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
+{
+ ASSERT(m_async);
+ // SubresourceLoader::create can return null here, for example if we're no longer attached to a page.
+ // This is true while running onunload handlers.
+ // FIXME: We need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
+ // FIXME: Maybe create can return null for other reasons too?
+ // We need to keep content sniffing enabled for local files due to CFNetwork not providing a MIME type
+ // for local files otherwise, <rdar://problem/5671813>.
+ bool sendResourceLoadCallbacks = !m_inPreflight;
+ m_loader = SubresourceLoader::create(document()->frame(), this, request, false, sendResourceLoadCallbacks, request.url().isLocalFile());
+
+ if (m_loader) {
+ // Neither this object nor the JavaScript wrapper should be deleted while
+ // a request is in progress because we need to keep the listeners alive,
+ // and they are referenced by the JavaScript wrapper.
+ setPendingActivity(this);
+ }
+}
+
+void XMLHttpRequest::abort()
+{
+ bool sendFlag = m_loader;
+
+ internalAbort();
+
+ // Clear headers as required by the spec
+ m_requestHeaders.clear();
+
+ if ((m_state <= OPENED && !sendFlag) || m_state == DONE)
+ m_state = UNSENT;
+ else {
+ ASSERT(!m_loader);
+ changeState(DONE);
+ m_state = UNSENT;
+ }
+
+ dispatchAbortEvent();
+ if (!m_uploadComplete) {
+ m_uploadComplete = true;
+ if (m_upload)
+ m_upload->dispatchAbortEvent();
+ }
+}
+
+void XMLHttpRequest::internalAbort()
+{
+ bool hadLoader = m_loader;
+
+ m_error = true;
+
+ // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
+ m_receivedLength = 0;
+
+ if (hadLoader) {
+ m_loader->cancel();
+ m_loader = 0;
+ }
+
+ m_decoder = 0;
+
+ if (hadLoader)
+ dropProtection();
+}
+
+void XMLHttpRequest::clearResponse()
+{
+ m_response = ResourceResponse();
+ {
+ JSC::JSLock lock(false);
+ m_responseText = "";
+ }
+ m_createdDocument = false;
+ m_responseXML = 0;
+}
+
+void XMLHttpRequest::clearRequest()
+{
+ m_requestHeaders.clear();
+ m_requestEntityBody = 0;
+}
+
+void XMLHttpRequest::genericError()
+{
+ clearResponse();
+ clearRequest();
+ m_error = true;
+
+ // The spec says we should "Synchronously switch the state to DONE." and then "Synchronously dispatch a readystatechange event on the object"
+ // but this does not match Firefox.
+}
+
+void XMLHttpRequest::networkError()
+{
+ genericError();
+ dispatchErrorEvent();
+ if (!m_uploadComplete) {
+ m_uploadComplete = true;
+ if (m_upload)
+ m_upload->dispatchErrorEvent();
+ }
+}
+
+void XMLHttpRequest::abortError()
+{
+ genericError();
+ dispatchAbortEvent();
+ if (!m_uploadComplete) {
+ m_uploadComplete = true;
+ if (m_upload)
+ m_upload->dispatchAbortEvent();
+ }
+}
+
+void XMLHttpRequest::dropProtection()
+{
+ // The XHR object itself holds on to the responseText, and
+ // thus has extra cost even independent of any
+ // responseText or responseXML objects it has handed
+ // out. But it is protected from GC while loading, so this
+ // can't be recouped until the load is done, so only
+ // report the extra cost at that point.
+
+ if (JSDOMWindow* window = toJSDOMWindow(document()->frame())) {
+ if (JSC::JSValue* wrapper = getCachedDOMObjectWrapper(*window->globalData(), this))
+ JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2);
+ }
+
+ unsetPendingActivity(this);
+}
+
+void XMLHttpRequest::overrideMimeType(const String& override)
+{
+ m_mimeTypeOverride = override;
+}
+
+void XMLHttpRequest::setRequestHeader(const String& name, const String& value, ExceptionCode& ec)
+{
+ if (m_state != OPENED || m_loader) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ Settings* settings = document() ? document()->settings() : 0;
+ if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ return;
+#endif
+
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!isValidToken(name) || !isValidHeaderValue(value)) {
+ ec = SYNTAX_ERR;
+ return;
+ }
+
+ // A privileged script (e.g. a Dashboard widget) can set any headers.
+ if (!document()->securityOrigin()->canLoadLocalResources() && !isSafeRequestHeader(name)) {
+ if (document() && document()->frame())
+ document()->frame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Refused to set unsafe header \"" + name + "\"", 1, String());
+ return;
+ }
+
+ setRequestHeaderInternal(name, value);
+}
+
+void XMLHttpRequest::setRequestHeaderInternal(const String& name, const String& value)
+{
+ pair<HTTPHeaderMap::iterator, bool> result = m_requestHeaders.add(name, value);
+ if (!result.second)
+ result.first->second += ", " + value;
+}
+
+String XMLHttpRequest::getRequestHeader(const String& name) const
+{
+ return m_requestHeaders.get(name);
+}
+
+String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
+{
+ if (m_state < LOADING) {
+ ec = INVALID_STATE_ERR;
+ return "";
+ }
+
+ Vector<UChar> stringBuilder;
+ String separator(": ");
+
+ HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
+ for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->first))
+ continue;
+
+ stringBuilder.append(it->first.characters(), it->first.length());
+ stringBuilder.append(separator.characters(), separator.length());
+ stringBuilder.append(it->second.characters(), it->second.length());
+ stringBuilder.append((UChar)'\r');
+ stringBuilder.append((UChar)'\n');
+ }
+
+ return String::adopt(stringBuilder);
+}
+
+String XMLHttpRequest::getResponseHeader(const String& name, ExceptionCode& ec) const
+{
+ if (m_state < LOADING) {
+ ec = INVALID_STATE_ERR;
+ return "";
+ }
+
+ if (!isValidToken(name))
+ return "";
+
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name))
+ return "";
+
+ return m_response.httpHeaderField(name);
+}
+
+String XMLHttpRequest::responseMIMEType() const
+{
+ String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
+ if (mimeType.isEmpty()) {
+ if (m_response.isHTTP())
+ mimeType = extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type"));
+ else
+ mimeType = m_response.mimeType();
+ }
+ if (mimeType.isEmpty())
+ mimeType = "text/xml";
+
+ return mimeType;
+}
+
+bool XMLHttpRequest::responseIsXML() const
+{
+ return DOMImplementation::isXMLMIMEType(responseMIMEType());
+}
+
+int XMLHttpRequest::status(ExceptionCode& ec) const
+{
+ if (m_response.httpStatusCode())
+ return m_response.httpStatusCode();
+
+ if (m_state == OPENED) {
+ // Firefox only raises an exception in this state; we match it.
+ // Note the case of local file requests, where we have no HTTP response code! Firefox never raises an exception for those, but we match HTTP case for consistency.
+ ec = INVALID_STATE_ERR;
+ }
+
+ return 0;
+}
+
+String XMLHttpRequest::statusText(ExceptionCode& ec) const
+{
+ // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=3547> XMLHttpRequest.statusText returns always "OK".
+ if (m_response.httpStatusCode())
+ return "OK";
+
+ if (m_state == OPENED) {
+ // See comments in getStatus() above.
+ ec = INVALID_STATE_ERR;
+ }
+
+ return String();
+}
+
+void XMLHttpRequest::processSyncLoadResults(const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec)
+{
+ if (m_sameOriginRequest && !document()->securityOrigin()->canRequest(response.url())) {
+ abort();
+ return;
+ }
+
+ didReceiveResponse(0, response);
+ changeState(HEADERS_RECEIVED);
+
+ const char* bytes = static_cast<const char*>(data.data());
+ int len = static_cast<int>(data.size());
+ didReceiveData(0, bytes, len);
+
+ didFinishLoading(0);
+ if (m_error)
+ ec = XMLHttpRequestException::NETWORK_ERR;
+}
+
+void XMLHttpRequest::didFail(SubresourceLoader* loader, const ResourceError& error)
+{
+ // If we are already in an error state, for instance we called abort(), bail out early.
+ if (m_error)
+ return;
+
+ if (error.isCancellation()) {
+ abortError();
+ return;
+ }
+
+ networkError();
+ return;
+}
+
+void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader)
+{
+ if (m_error)
+ return;
+
+ if (m_inPreflight) {
+ didFinishLoadingPreflight(loader);
+ return;
+ }
+
+ ASSERT(loader == m_loader);
+
+ if (m_state < HEADERS_RECEIVED)
+ changeState(HEADERS_RECEIVED);
+
+ {
+ JSC::JSLock lock(false);
+ if (m_decoder)
+ m_responseText += m_decoder->flush();
+ }
+
+ if (Frame* frame = document()->frame()) {
+ if (Page* page = frame->page()) {
+ page->inspectorController()->resourceRetrievedByXMLHttpRequest(m_loader ? m_loader->identifier() : m_identifier, m_responseText);
+ page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, "XHR finished loading: \"" + m_url + "\".", m_lastSendLineNumber, m_lastSendURL);
+ }
+ }
+
+ bool hadLoader = m_loader;
+ m_loader = 0;
+
+ changeState(DONE);
+ m_decoder = 0;
+
+ if (hadLoader)
+ dropProtection();
+}
+
+void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader* loader)
+{
+ ASSERT(m_inPreflight);
+ ASSERT(!m_sameOriginRequest);
+
+ // FIXME: this can probably be moved to didReceiveResponsePreflight.
+ if (m_async)
+ handleAsynchronousPreflightResult();
+
+ if (m_loader)
+ unsetPendingActivity(this);
+}
+
+void XMLHttpRequest::willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
+ if (!document()->securityOrigin()->canRequest(request.url())) {
+ internalAbort();
+ networkError();
+ }
+}
+
+void XMLHttpRequest::didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+{
+ if (!m_upload)
+ return;
+
+ m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
+
+ if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
+ m_uploadComplete = true;
+ m_upload->dispatchLoadEvent();
+ }
+}
+
+bool XMLHttpRequest::accessControlCheck(const ResourceResponse& response)
+{
+ const String& accessControlOriginString = response.httpHeaderField("Access-Control-Origin");
+ if (accessControlOriginString == "*" && !m_includeCredentials)
+ return true;
+
+ KURL accessControlOriginURL(accessControlOriginString);
+ if (!accessControlOriginURL.isValid())
+ return false;
+
+ RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::create(accessControlOriginURL);
+ if (!accessControlOrigin->isSameSchemeHostPort(document()->securityOrigin()))
+ return false;
+
+ if (m_includeCredentials) {
+ const String& accessControlCredentialsString = response.httpHeaderField("Access-Control-Credentials");
+ if (accessControlCredentialsString != "true")
+ return false;
+ }
+
+ return true;
+}
+
+void XMLHttpRequest::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
+{
+ if (m_inPreflight) {
+ didReceiveResponsePreflight(loader, response);
+ return;
+ }
+
+ if (!m_sameOriginRequest) {
+ if (!accessControlCheck(response)) {
+ networkError();
+ return;
+ }
+ }
+
+ m_response = response;
+ m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
+ if (m_responseEncoding.isEmpty())
+ m_responseEncoding = response.textEncodingName();
+}
+
+template<class HashType>
+static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>* set)
+{
+ int start = 0;
+ int end;
+ while ((end = string.find(',', start)) != -1) {
+ if (start == end)
+ return false;
+
+ // FIXME: this could be made more efficient by not not allocating twice.
+ set->add(string.substring(start, end - start).stripWhiteSpace());
+ start = end + 1;
+ }
+ if (start != static_cast<int>(string.length()))
+ set->add(string.substring(start).stripWhiteSpace());
+
+ return true;
+}
+
+static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta)
+{
+ // FIXME: this will not do the correct thing for a number starting with a '+'
+ bool ok = false;
+ expiryDelta = string.toUIntStrict(&ok);
+ return ok;
+}
+
+void XMLHttpRequest::didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse& response)
+{
+ ASSERT(m_inPreflight);
+ ASSERT(!m_sameOriginRequest);
+
+ if (!accessControlCheck(response)) {
+ networkError();
+ return;
+ }
+
+ OwnPtr<HashSet<String> > methods(new HashSet<String>);
+ if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), methods.get())) {
+ networkError();
+ return;
+ }
+
+ if (!methods->contains(m_method) && m_method != "GET" && m_method != "POST") {
+ networkError();
+ return;
+ }
+
+ OwnPtr<HashSet<String, CaseFoldingHash> > headers(new HashSet<String, CaseFoldingHash>);
+ if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), headers.get())) {
+ networkError();
+ return;
+ }
+
+ HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
+ for (HTTPHeaderMap::const_iterator it = m_requestHeaders.begin(); it != end; ++it) {
+ if (!headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first)) {
+ networkError();
+ return;
+ }
+ }
+
+ unsigned expiryDelta = 0;
+ if (!parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta))
+ expiryDelta = 5;
+
+ appendPreflightResultCacheEntry(document()->securityOrigin()->toString(), m_url, expiryDelta, m_includeCredentials, methods.release(), headers.release());
+}
+
+void XMLHttpRequest::receivedCancellation(SubresourceLoader*, const AuthenticationChallenge& challenge)
+{
+ m_response = challenge.failureResponse();
+}
+
+void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int len)
+{
+ if (m_inPreflight)
+ return;
+
+ if (m_state < HEADERS_RECEIVED)
+ changeState(HEADERS_RECEIVED);
+
+ if (!m_decoder) {
+ if (!m_responseEncoding.isEmpty())
+ m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding);
+ // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
+ else if (responseIsXML())
+ m_decoder = TextResourceDecoder::create("application/xml");
+ else if (responseMIMEType() == "text/html")
+ m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
+ else
+ m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
+ }
+ if (len == 0)
+ return;
+
+ if (len == -1)
+ len = strlen(data);
+
+ String decoded = m_decoder->decode(data, len);
+
+ {
+ JSC::JSLock lock(false);
+ m_responseText += decoded;
+ }
+
+ if (!m_error) {
+ updateAndDispatchOnProgress(len);
+
+ if (m_state != LOADING)
+ changeState(LOADING);
+ else
+ // Firefox calls readyStateChanged every time it receives data, 4449442
+ callReadyStateChangeListener();
+ }
+}
+
+void XMLHttpRequest::updateAndDispatchOnProgress(unsigned int len)
+{
+ long long expectedLength = m_response.expectedContentLength();
+ m_receivedLength += len;
+
+ // FIXME: the spec requires that we dispatch the event according to the least
+ // frequent method between every 350ms (+/-200ms) and for every byte received.
+ dispatchProgressEvent(expectedLength);
+}
+
+void XMLHttpRequest::dispatchReadyStateChangeEvent()
+{
+ RefPtr<Event> evt = Event::create(eventNames().readystatechangeEvent, false, false);
+ if (m_onReadyStateChangeListener) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ m_onReadyStateChangeListener->handleEvent(evt.get(), false);
+ }
+
+ ExceptionCode ec = 0;
+ dispatchEvent(evt.release(), ec);
+ ASSERT(!ec);
+}
+
+void XMLHttpRequest::dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+{
+ RefPtr<XMLHttpRequestProgressEvent> evt = XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total);
+ if (listener) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listener->handleEvent(evt.get(), false);
+ }
+
+ ExceptionCode ec = 0;
+ dispatchEvent(evt.release(), ec);
+ ASSERT(!ec);
+}
+
+void XMLHttpRequest::dispatchAbortEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onAbortListener.get(), eventNames().abortEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchErrorEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onErrorListener.get(), eventNames().errorEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchLoadEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadListener.get(), eventNames().loadEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchLoadStartEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadStartListener.get(), eventNames().loadstartEvent, false, 0, 0);
+}
+
+void XMLHttpRequest::dispatchProgressEvent(long long expectedLength)
+{
+ dispatchXMLHttpRequestProgressEvent(m_onProgressListener.get(), eventNames().progressEvent, expectedLength && m_receivedLength <= expectedLength,
+ static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength));
+}
+
+void XMLHttpRequest::stop()
+{
+ internalAbort();
+}
+
+void XMLHttpRequest::contextDestroyed()
+{
+ ActiveDOMObject::contextDestroyed();
+ internalAbort();
+}
+
+ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const
+{
+ return ActiveDOMObject::scriptExecutionContext();
+}
+
+} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequest.h b/WebCore/xml/XMLHttpRequest.h
new file mode 100644
index 0000000..6962ab1
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequest.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@nypop.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XMLHttpRequest_h
+#define XMLHttpRequest_h
+
+#include "ActiveDOMObject.h"
+#include "AtomicStringHash.h"
+#include "EventListener.h"
+#include "EventTarget.h"
+#include "FormData.h"
+#include "ResourceResponse.h"
+#include "SubresourceLoaderClient.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class Document;
+class File;
+class TextResourceDecoder;
+
+class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private SubresourceLoaderClient, public ActiveDOMObject {
+public:
+ static PassRefPtr<XMLHttpRequest> create(Document* document) { return adoptRef(new XMLHttpRequest(document)); }
+ ~XMLHttpRequest();
+
+ // These exact numeric values are important because JS expects them.
+ enum State {
+ UNSENT = 0,
+ OPENED = 1,
+ HEADERS_RECEIVED = 2,
+ LOADING = 3,
+ DONE = 4
+ };
+
+ virtual XMLHttpRequest* toXMLHttpRequest() { return this; }
+
+ virtual void contextDestroyed();
+ virtual void stop();
+
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+
+ String statusText(ExceptionCode&) const;
+ int status(ExceptionCode&) const;
+ State readyState() const;
+ void open(const String& method, const KURL&, bool async, ExceptionCode&);
+ void open(const String& method, const KURL&, bool async, const String& user, ExceptionCode&);
+ void open(const String& method, const KURL&, bool async, const String& user, const String& password, ExceptionCode&);
+ void send(ExceptionCode&);
+ void send(Document*, ExceptionCode&);
+ void send(const String&, ExceptionCode&);
+ void send(File*, ExceptionCode&);
+ void abort();
+ void setRequestHeader(const String& name, const String& value, ExceptionCode&);
+ void overrideMimeType(const String& override);
+ String getAllResponseHeaders(ExceptionCode&) const;
+ String getResponseHeader(const String& name, ExceptionCode&) const;
+ const JSC::UString& responseText() const;
+ Document* responseXML() const;
+ void setLastSendLineNumber(unsigned lineNumber) { m_lastSendLineNumber = lineNumber; }
+ void setLastSendURL(JSC::UString url) { m_lastSendURL = url; }
+
+ XMLHttpRequestUpload* upload();
+ XMLHttpRequestUpload* optionalUpload() const { return m_upload.get(); }
+
+ void setOnreadystatechange(PassRefPtr<EventListener> eventListener) { m_onReadyStateChangeListener = eventListener; }
+ EventListener* onreadystatechange() const { return m_onReadyStateChangeListener.get(); }
+
+ void setOnabort(PassRefPtr<EventListener> eventListener) { m_onAbortListener = eventListener; }
+ EventListener* onabort() const { return m_onAbortListener.get(); }
+
+ void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
+ EventListener* onerror() const { return m_onErrorListener.get(); }
+
+ void setOnload(PassRefPtr<EventListener> eventListener) { m_onLoadListener = eventListener; }
+ EventListener* onload() const { return m_onLoadListener.get(); }
+
+ void setOnloadstart(PassRefPtr<EventListener> eventListener) { m_onLoadStartListener = eventListener; }
+ EventListener* onloadstart() const { return m_onLoadStartListener.get(); }
+
+ void setOnprogress(PassRefPtr<EventListener> eventListener) { m_onProgressListener = eventListener; }
+ EventListener* onprogress() const { return m_onProgressListener.get(); }
+
+ typedef Vector<RefPtr<EventListener> > ListenerVector;
+ typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
+
+ // useCapture is not used, even for add/remove pairing (for Firefox compatibility).
+ virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
+ virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&);
+ EventListenersMap& eventListeners() { return m_eventListeners; }
+
+ using RefCounted<XMLHttpRequest>::ref;
+ using RefCounted<XMLHttpRequest>::deref;
+
+private:
+ XMLHttpRequest(Document*);
+
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+
+ Document* document() const;
+
+ virtual void willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse);
+ virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
+ virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
+ virtual void didReceiveData(SubresourceLoader*, const char* data, int size);
+ virtual void didFail(SubresourceLoader*, const ResourceError&);
+ virtual void didFinishLoading(SubresourceLoader*);
+ virtual void receivedCancellation(SubresourceLoader*, const AuthenticationChallenge&);
+
+ // Special versions for the preflight
+ void didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse&);
+ void didFinishLoadingPreflight(SubresourceLoader*);
+
+ void processSyncLoadResults(const Vector<char>& data, const ResourceResponse&, ExceptionCode&);
+ void updateAndDispatchOnProgress(unsigned int len);
+
+ String responseMIMEType() const;
+ bool responseIsXML() const;
+
+ bool initSend(ExceptionCode&);
+
+ String getRequestHeader(const String& name) const;
+ void setRequestHeaderInternal(const String& name, const String& value);
+
+ void changeState(State newState);
+ void callReadyStateChangeListener();
+ void dropProtection();
+ void internalAbort();
+ void clearResponse();
+ void clearRequest();
+
+ void createRequest(ExceptionCode&);
+
+ void makeSameOriginRequest(ExceptionCode&);
+ void makeCrossSiteAccessRequest(ExceptionCode&);
+
+ void makeSimpleCrossSiteAccessRequest(ExceptionCode&);
+ void makeCrossSiteAccessRequestWithPreflight(ExceptionCode&);
+ void handleAsynchronousPreflightResult();
+
+ void loadRequestSynchronously(ResourceRequest&, ExceptionCode&);
+ void loadRequestAsynchronously(ResourceRequest&);
+
+ bool isSimpleCrossSiteAccessRequest() const;
+ String accessControlOrigin() const;
+ bool accessControlCheck(const ResourceResponse&);
+
+ void genericError();
+ void networkError();
+ void abortError();
+
+ void dispatchReadyStateChangeEvent();
+ void dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total);
+ void dispatchAbortEvent();
+ void dispatchErrorEvent();
+ void dispatchLoadEvent();
+ void dispatchLoadStartEvent();
+ void dispatchProgressEvent(long long expectedLength);
+
+ RefPtr<EventListener> m_onReadyStateChangeListener;
+ RefPtr<EventListener> m_onAbortListener;
+ RefPtr<EventListener> m_onErrorListener;
+ RefPtr<EventListener> m_onLoadListener;
+ RefPtr<EventListener> m_onLoadStartListener;
+ RefPtr<EventListener> m_onProgressListener;
+ EventListenersMap m_eventListeners;
+
+ RefPtr<XMLHttpRequestUpload> m_upload;
+
+ KURL m_url;
+ String m_method;
+ HTTPHeaderMap m_requestHeaders;
+ RefPtr<FormData> m_requestEntityBody;
+ String m_mimeTypeOverride;
+ bool m_async;
+ bool m_includeCredentials;
+
+ RefPtr<SubresourceLoader> m_loader;
+ State m_state;
+
+ ResourceResponse m_response;
+ String m_responseEncoding;
+
+ RefPtr<TextResourceDecoder> m_decoder;
+ unsigned long m_identifier;
+
+ // Unlike most strings in the DOM, we keep this as a JSC::UString, not a WebCore::String.
+ // That's because these strings can easily get huge (they are filled from the network with
+ // no parsing) and because JS can easily observe many intermediate states, so it's very useful
+ // to be able to share the buffer with JavaScript versions of the whole or partial string.
+ // In contrast, this string doesn't interact much with the rest of the engine so it's not that
+ // big a cost that it isn't a String.
+ JSC::UString m_responseText;
+ mutable bool m_createdDocument;
+ mutable RefPtr<Document> m_responseXML;
+
+ bool m_error;
+
+ bool m_uploadComplete;
+
+ bool m_sameOriginRequest;
+ bool m_allowAccess;
+ bool m_inPreflight;
+
+ // Used for onprogress tracking
+ long long m_receivedLength;
+
+ unsigned m_lastSendLineNumber;
+ JSC::UString m_lastSendURL;
+};
+
+} // namespace WebCore
+
+#endif // XMLHttpRequest_h
diff --git a/WebCore/xml/XMLHttpRequest.idl b/WebCore/xml/XMLHttpRequest.idl
new file mode 100644
index 0000000..fa6b9ca
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequest.idl
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ interface [
+ CustomMarkFunction
+ ] XMLHttpRequest {
+ // From XMLHttpRequestEventTarget
+ // event handler attributes
+ attribute EventListener onabort;
+ attribute EventListener onerror;
+ attribute EventListener onload;
+ attribute EventListener onloadstart;
+ attribute EventListener onprogress;
+
+ // event handler attributes
+ attribute EventListener onreadystatechange;
+
+ // state
+ const unsigned short UNSENT = 0;
+ const unsigned short OPENED = 1;
+ const unsigned short HEADERS_RECEIVED = 2;
+ const unsigned short LOADING = 3;
+ const unsigned short DONE = 4;
+
+ readonly attribute unsigned short readyState;
+
+ // request
+ // void open(in DOMString method, in DOMString url);
+ // void open(in DOMString method, in DOMString url, in boolean async);
+ // void open(in DOMString method, in DOMString url, in boolean async, in DOMString user);
+ [Custom] void open(in DOMString method, in DOMString url, in boolean async, in DOMString user, in DOMString password)
+ raises(DOMException);
+
+ [Custom] void setRequestHeader(in DOMString header, in DOMString value)
+ raises(DOMException);
+
+ // void send();
+ // void send(in DOMString data);
+ [Custom] void send(in Document data)
+ raises(DOMException);
+
+ void abort();
+
+ readonly attribute XMLHttpRequestUpload upload;
+
+ // response
+ [ConvertNullStringTo=Undefined] DOMString getAllResponseHeaders()
+ raises(DOMException);
+ [Custom, ConvertNullStringTo=Null] DOMString getResponseHeader(in DOMString header)
+ raises(DOMException);
+ readonly attribute [ConvertNullStringTo=Null] DOMString responseText;
+ readonly attribute Document responseXML;
+ readonly attribute unsigned short status
+ getter raises(DOMException);
+ readonly attribute DOMString statusText
+ getter raises(DOMException);
+
+ // Extension
+ [Custom] void overrideMimeType(in DOMString override);
+
+ // EventTarget interface
+ [Custom] void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [Custom] void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+ };
+
+}
diff --git a/WebCore/xml/XMLHttpRequestException.h b/WebCore/xml/XMLHttpRequestException.h
new file mode 100644
index 0000000..737cab0
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestException.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XMLHttpRequestException_h
+#define XMLHttpRequestException_h
+
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+ class XMLHttpRequestException : public ExceptionBase {
+ public:
+ static PassRefPtr<XMLHttpRequestException> create(const ExceptionCodeDescription& description)
+ {
+ return adoptRef(new XMLHttpRequestException(description));
+ }
+
+ static const int XMLHttpRequestExceptionOffset = 500;
+ static const int XMLHttpRequestExceptionMax = 699;
+
+ enum XMLHttpRequestExceptionCode {
+ NETWORK_ERR = XMLHttpRequestExceptionOffset + 101,
+ ABORT_ERR
+ };
+
+ private:
+ XMLHttpRequestException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+ };
+
+} // namespace WebCore
+
+#endif // XMLHttpRequestException_h
diff --git a/WebCore/xml/XMLHttpRequestException.idl b/WebCore/xml/XMLHttpRequestException.idl
new file mode 100644
index 0000000..2feb574
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestException.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ interface [
+ GenerateConstructor
+ ] XMLHttpRequestException {
+
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ // Override in a Mozilla compatible format
+ [DontEnum] DOMString toString();
+#endif
+
+ // XMLHttpRequestExceptionCode
+ const unsigned short NETWORK_ERR = 101;
+ const unsigned short ABORT_ERR = 102;
+ };
+
+}
diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.h b/WebCore/xml/XMLHttpRequestProgressEvent.h
new file mode 100644
index 0000000..02bfdea
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestProgressEvent.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Julien Chaffraix <jchaffraix@webkit.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XMLHttpRequestProgressEvent_h
+#define XMLHttpRequestProgressEvent_h
+
+#include "ProgressEvent.h"
+
+namespace WebCore {
+
+ class XMLHttpRequestProgressEvent : public ProgressEvent {
+ public:
+ static PassRefPtr<XMLHttpRequestProgressEvent> create()
+ {
+ return adoptRef(new XMLHttpRequestProgressEvent);
+ }
+ static PassRefPtr<XMLHttpRequestProgressEvent> create(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+ {
+ return adoptRef(new XMLHttpRequestProgressEvent(type, lengthComputable, loaded, total));
+ }
+
+ virtual bool isXMLHttpRequestProgressEvent() const { return true; }
+
+ // Those 2 methods are to be compatible with Firefox and are only a wrapper on top of the real implementation.
+ unsigned position() const { return loaded(); }
+ unsigned totalSize() const { return total(); }
+
+ private:
+ XMLHttpRequestProgressEvent() { }
+ XMLHttpRequestProgressEvent(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+ : ProgressEvent(type, lengthComputable, loaded, total)
+ {
+ }
+ };
+
+} // namespace WebCore
+
+#endif // XMLHttpRequestProgressEvent_h
diff --git a/WebCore/xml/XMLHttpRequestProgressEvent.idl b/WebCore/xml/XMLHttpRequestProgressEvent.idl
new file mode 100644
index 0000000..6de9690
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestProgressEvent.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module events {
+
+ interface [
+ GenerateConstructor
+ // We should also inherit from LSProgressEvent when the idl is added.
+ ] XMLHttpRequestProgressEvent : ProgressEvent {
+ readonly attribute unsigned long position;
+ readonly attribute unsigned long totalSize;
+ };
+
+}
diff --git a/WebCore/xml/XMLHttpRequestUpload.cpp b/WebCore/xml/XMLHttpRequestUpload.cpp
new file mode 100644
index 0000000..cef1798
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestUpload.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XMLHttpRequestUpload.h"
+
+#include "AtomicString.h"
+#include "Event.h"
+#include "EventException.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "XMLHttpRequest.h"
+#include "XMLHttpRequestProgressEvent.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+XMLHttpRequestUpload::XMLHttpRequestUpload(XMLHttpRequest* xmlHttpRequest)
+ : m_xmlHttpRequest(xmlHttpRequest)
+{
+}
+
+ScriptExecutionContext* XMLHttpRequestUpload::scriptExecutionContext() const
+{
+ XMLHttpRequest* xmlHttpRequest = associatedXMLHttpRequest();
+ if (!xmlHttpRequest)
+ return 0;
+ return xmlHttpRequest->scriptExecutionContext();
+}
+
+void XMLHttpRequestUpload::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool)
+{
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
+ if (iter == m_eventListeners.end()) {
+ ListenerVector listeners;
+ listeners.append(eventListener);
+ m_eventListeners.add(eventType, listeners);
+ } else {
+ ListenerVector& listeners = iter->second;
+ for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) {
+ if (*listenerIter == eventListener)
+ return;
+ }
+
+ listeners.append(eventListener);
+ m_eventListeners.add(eventType, listeners);
+ }
+}
+
+void XMLHttpRequestUpload::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
+{
+ EventListenersMap::iterator iter = m_eventListeners.find(eventType);
+ if (iter == m_eventListeners.end())
+ return;
+
+ ListenerVector& listeners = iter->second;
+ for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) {
+ if (*listenerIter == eventListener) {
+ listeners.remove(listenerIter - listeners.begin());
+ return;
+ }
+ }
+}
+
+bool XMLHttpRequestUpload::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec)
+{
+ // FIXME: check for other error conditions enumerated in the spec.
+ if (evt->type().isEmpty()) {
+ ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ return true;
+ }
+
+ ListenerVector listenersCopy = m_eventListeners.get(evt->type());
+ for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listenerIter->get()->handleEvent(evt.get(), false);
+ }
+
+ return !evt->defaultPrevented();
+}
+
+void XMLHttpRequestUpload::dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+{
+ RefPtr<XMLHttpRequestProgressEvent> evt = XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total);
+ if (listener) {
+ evt->setTarget(this);
+ evt->setCurrentTarget(this);
+ listener->handleEvent(evt.get(), false);
+ }
+
+ ExceptionCode ec = 0;
+ dispatchEvent(evt.release(), ec);
+ ASSERT(!ec);
+}
+
+void XMLHttpRequestUpload::dispatchAbortEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onAbortListener.get(), eventNames().abortEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchErrorEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onErrorListener.get(), eventNames().errorEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchLoadEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadListener.get(), eventNames().loadEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchLoadStartEvent()
+{
+ dispatchXMLHttpRequestProgressEvent(m_onLoadStartListener.get(), eventNames().loadstartEvent, false, 0, 0);
+}
+
+void XMLHttpRequestUpload::dispatchProgressEvent(long long bytesSent, long long totalBytesToBeSent)
+{
+ dispatchXMLHttpRequestProgressEvent(m_onProgressListener.get(), eventNames().progressEvent, true, static_cast<unsigned>(bytesSent), static_cast<unsigned>(totalBytesToBeSent));
+}
+
+} // namespace WebCore
diff --git a/WebCore/xml/XMLHttpRequestUpload.h b/WebCore/xml/XMLHttpRequestUpload.h
new file mode 100644
index 0000000..93fa7f9
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestUpload.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XMLHttpRequestUpload_h
+#define XMLHttpRequestUpload_h
+
+#include "AtomicStringHash.h"
+#include "EventListener.h"
+#include "EventTarget.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class AtomicStringImpl;
+ class ScriptExecutionContext;
+ class XMLHttpRequest;
+
+ class XMLHttpRequestUpload : public RefCounted<XMLHttpRequestUpload>, public EventTarget {
+ public:
+ static PassRefPtr<XMLHttpRequestUpload> create(XMLHttpRequest* xmlHttpRequest)
+ {
+ return adoptRef(new XMLHttpRequestUpload(xmlHttpRequest));
+ }
+
+ virtual XMLHttpRequestUpload* toXMLHttpRequestUpload() { return this; }
+
+ XMLHttpRequest* associatedXMLHttpRequest() const { return m_xmlHttpRequest; }
+ void disconnectXMLHttpRequest() { m_xmlHttpRequest = 0; }
+
+ ScriptExecutionContext* scriptExecutionContext() const;
+
+ void dispatchAbortEvent();
+ void dispatchErrorEvent();
+ void dispatchLoadEvent();
+ void dispatchLoadStartEvent();
+ void dispatchProgressEvent(long long bytesSent, long long totalBytesToBeSent);
+
+ void setOnabort(PassRefPtr<EventListener> eventListener) { m_onAbortListener = eventListener; }
+ EventListener* onabort() const { return m_onAbortListener.get(); }
+
+ void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
+ EventListener* onerror() const { return m_onErrorListener.get(); }
+
+ void setOnload(PassRefPtr<EventListener> eventListener) { m_onLoadListener = eventListener; }
+ EventListener* onload() const { return m_onLoadListener.get(); }
+
+ void setOnloadstart(PassRefPtr<EventListener> eventListener) { m_onLoadStartListener = eventListener; }
+ EventListener* onloadstart() const { return m_onLoadStartListener.get(); }
+
+ void setOnprogress(PassRefPtr<EventListener> eventListener) { m_onProgressListener = eventListener; }
+ EventListener* onprogress() const { return m_onProgressListener.get(); }
+
+ typedef Vector<RefPtr<EventListener> > ListenerVector;
+ typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
+
+ virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
+ virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&);
+ EventListenersMap& eventListeners() { return m_eventListeners; }
+
+ using RefCounted<XMLHttpRequestUpload>::ref;
+ using RefCounted<XMLHttpRequestUpload>::deref;
+
+ private:
+ XMLHttpRequestUpload(XMLHttpRequest*);
+
+ void dispatchXMLHttpRequestProgressEvent(EventListener*, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total);
+
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+
+ RefPtr<EventListener> m_onAbortListener;
+ RefPtr<EventListener> m_onErrorListener;
+ RefPtr<EventListener> m_onLoadListener;
+ RefPtr<EventListener> m_onLoadStartListener;
+ RefPtr<EventListener> m_onProgressListener;
+ EventListenersMap m_eventListeners;
+
+ XMLHttpRequest* m_xmlHttpRequest;
+ };
+
+} // namespace WebCore
+
+#endif // XMLHttpRequestUpload_h
diff --git a/WebCore/xml/XMLHttpRequestUpload.idl b/WebCore/xml/XMLHttpRequestUpload.idl
new file mode 100644
index 0000000..c066710
--- /dev/null
+++ b/WebCore/xml/XMLHttpRequestUpload.idl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ interface [
+ GenerateConstructor,
+ CustomMarkFunction
+ ] XMLHttpRequestUpload {
+ // From XMLHttpRequestEventTarget
+ // event handler attributes
+ attribute EventListener onabort;
+ attribute EventListener onerror;
+ attribute EventListener onload;
+ attribute EventListener onloadstart;
+ attribute EventListener onprogress;
+
+ // EventTarget interface
+ [Custom] void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [Custom] void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+ };
+
+}
diff --git a/WebCore/xml/XMLSerializer.cpp b/WebCore/xml/XMLSerializer.cpp
new file mode 100644
index 0000000..ac7dc19
--- /dev/null
+++ b/WebCore/xml/XMLSerializer.cpp
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig (sam@webkit.org)
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "XMLSerializer.h"
+
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "markup.h"
+
+namespace WebCore {
+
+String XMLSerializer::serializeToString(Node* node, ExceptionCode& ec)
+{
+ if (!node)
+ return String();
+
+ if (!node->document()) {
+ // Due to the fact that DocumentType nodes are created by the DOMImplementation
+ // and not the Document, it is possible for it to not have a Document associated
+ // with it. It should be the only type of node where this is possible.
+ ASSERT(node->nodeType() == Node::DOCUMENT_TYPE_NODE);
+
+ ec = INVALID_ACCESS_ERR;
+ return String();
+ }
+
+ return createMarkup(node);
+}
+
+} // namespace WebCore
diff --git a/WebCore/xml/XMLSerializer.h b/WebCore/xml/XMLSerializer.h
new file mode 100644
index 0000000..33e94b7
--- /dev/null
+++ b/WebCore/xml/XMLSerializer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig (sam@webkit.org)
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XMLSerializer_h
+#define XMLSerializer_h
+
+#include <wtf/RefCounted.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class Node;
+
+ class XMLSerializer : public RefCounted<XMLSerializer> {
+ public:
+ static PassRefPtr<XMLSerializer> create() { return adoptRef(new XMLSerializer); }
+
+ String serializeToString(Node*, ExceptionCode&);
+
+ private:
+ XMLSerializer() { }
+ };
+
+} // namespace WebCore
+
+#endif // XMLSerializer_h
diff --git a/WebCore/xml/XMLSerializer.idl b/WebCore/xml/XMLSerializer.idl
new file mode 100644
index 0000000..6dcc3a4
--- /dev/null
+++ b/WebCore/xml/XMLSerializer.idl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig (sam@webkit.org)
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module xpath {
+
+ interface [GenerateConstructor, CanBeConstructed] XMLSerializer {
+ DOMString serializeToString(in Node node)
+ raises(DOMException);
+ };
+
+}
diff --git a/WebCore/xml/XPathEvaluator.cpp b/WebCore/xml/XPathEvaluator.cpp
new file mode 100644
index 0000000..8fb203f
--- /dev/null
+++ b/WebCore/xml/XPathEvaluator.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathEvaluator.h"
+
+#if ENABLE(XPATH)
+
+#include "ExceptionCode.h"
+#include "NativeXPathNSResolver.h"
+#include "Node.h"
+#include "XPathExpression.h"
+#include "XPathResult.h"
+#include "XPathUtil.h"
+
+namespace WebCore {
+
+using namespace XPath;
+
+PassRefPtr<XPathExpression> XPathEvaluator::createExpression(const String& expression,
+ XPathNSResolver* resolver,
+ ExceptionCode& ec)
+{
+ return XPathExpression::createExpression(expression, resolver, ec);
+}
+
+PassRefPtr<XPathNSResolver> XPathEvaluator::createNSResolver(Node* nodeResolver)
+{
+ return NativeXPathNSResolver::create(nodeResolver);
+}
+
+PassRefPtr<XPathResult> XPathEvaluator::evaluate(const String& expression,
+ Node* contextNode,
+ XPathNSResolver* resolver,
+ unsigned short type,
+ XPathResult* result,
+ ExceptionCode& ec)
+{
+ if (!isValidContextNode(contextNode)) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+
+ ec = 0;
+ RefPtr<XPathExpression> expr = createExpression(expression, resolver, ec);
+ if (ec)
+ return 0;
+
+ return expr->evaluate(contextNode, type, result, ec);
+}
+
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathEvaluator.h b/WebCore/xml/XPathEvaluator.h
new file mode 100644
index 0000000..c8e456e
--- /dev/null
+++ b/WebCore/xml/XPathEvaluator.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathEvaluator_h
+#define XPathEvaluator_h
+
+#if ENABLE(XPATH)
+
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class Node;
+ class String;
+ class XPathExpression;
+ class XPathNSResolver;
+ class XPathResult;
+
+ class XPathEvaluator : public RefCounted<XPathEvaluator> {
+ public:
+ static PassRefPtr<XPathEvaluator> create() { return adoptRef(new XPathEvaluator); }
+
+ PassRefPtr<XPathExpression> createExpression(const String& expression, XPathNSResolver*, ExceptionCode&);
+ PassRefPtr<XPathNSResolver> createNSResolver(Node* nodeResolver);
+ PassRefPtr<XPathResult> evaluate(const String& expression, Node* contextNode,
+ XPathNSResolver*, unsigned short type, XPathResult*, ExceptionCode&);
+
+ private:
+ XPathEvaluator() { }
+ };
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathEvaluator_h
diff --git a/WebCore/xml/XPathEvaluator.idl b/WebCore/xml/XPathEvaluator.idl
new file mode 100644
index 0000000..da6155b
--- /dev/null
+++ b/WebCore/xml/XPathEvaluator.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module xpath {
+ interface [GenerateConstructor, CanBeConstructed, Conditional=XPATH] XPathEvaluator {
+ XPathExpression createExpression(in DOMString expression,
+ in XPathNSResolver resolver)
+ raises(core::DOMException);
+
+ XPathNSResolver createNSResolver(in Node nodeResolver);
+
+ XPathResult evaluate(in DOMString expression,
+ in Node contextNode,
+ in XPathNSResolver resolver,
+ in unsigned short type,
+ in XPathResult inResult)
+ raises(DOMException);
+ };
+}
diff --git a/WebCore/xml/XPathException.h b/WebCore/xml/XPathException.h
new file mode 100644
index 0000000..45ad628
--- /dev/null
+++ b/WebCore/xml/XPathException.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathException_h
+#define XPathException_h
+
+#include "ExceptionBase.h"
+
+#if ENABLE(XPATH)
+
+namespace WebCore {
+
+ class XPathException : public ExceptionBase {
+ public:
+ static PassRefPtr<XPathException> create(const ExceptionCodeDescription& description)
+ {
+ return adoptRef(new XPathException(description));
+ }
+
+ static const int XPathExceptionOffset = 400;
+ static const int XPathExceptionMax = 499;
+
+ enum XPathExceptionCode {
+ INVALID_EXPRESSION_ERR = XPathExceptionOffset + 51,
+ TYPE_ERR
+ };
+
+ private:
+ XPathException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathException_h
diff --git a/WebCore/xml/XPathException.idl b/WebCore/xml/XPathException.idl
new file mode 100644
index 0000000..6e25514
--- /dev/null
+++ b/WebCore/xml/XPathException.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xpath {
+
+ interface [
+ GenerateConstructor,
+ Conditional=XPATH
+ ] XPathException {
+
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ // Override in a Mozilla compatible format
+ [DontEnum] DOMString toString();
+#endif
+
+ // XPathExceptionCode
+ const unsigned short INVALID_EXPRESSION_ERR = 51;
+ const unsigned short TYPE_ERR = 52;
+ };
+
+}
diff --git a/WebCore/xml/XPathExpression.cpp b/WebCore/xml/XPathExpression.cpp
new file mode 100644
index 0000000..446a7ad
--- /dev/null
+++ b/WebCore/xml/XPathExpression.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathExpression.h"
+
+#if ENABLE(XPATH)
+
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "Node.h"
+#include "PlatformString.h"
+#include "XPathExpressionNode.h"
+#include "XPathNSResolver.h"
+#include "XPathParser.h"
+#include "XPathResult.h"
+#include "XPathUtil.h"
+
+namespace WebCore {
+
+using namespace XPath;
+
+PassRefPtr<XPathExpression> XPathExpression::createExpression(const String& expression, XPathNSResolver* resolver, ExceptionCode& ec)
+{
+ RefPtr<XPathExpression> expr = XPathExpression::create();
+ Parser parser;
+
+ expr->m_topExpression = parser.parseStatement(expression, resolver, ec);
+ if (!expr->m_topExpression)
+ return 0;
+
+ return expr.release();
+}
+
+XPathExpression::~XPathExpression()
+{
+ delete m_topExpression;
+}
+
+PassRefPtr<XPathResult> XPathExpression::evaluate(Node* contextNode, unsigned short type, XPathResult*, ExceptionCode& ec)
+{
+ if (!isValidContextNode(contextNode)) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+
+ EventTargetNode* eventTarget = contextNode->ownerDocument()
+ ? contextNode->ownerDocument()
+ : static_cast<EventTargetNode*>(contextNode);
+
+ EvaluationContext& evaluationContext = Expression::evaluationContext();
+ evaluationContext.node = contextNode;
+ evaluationContext.size = 1;
+ evaluationContext.position = 1;
+ RefPtr<XPathResult> result = XPathResult::create(eventTarget, m_topExpression->evaluate());
+ evaluationContext.node = 0; // Do not hold a reference to the context node, as this may prevent the whole document from being destroyed in time.
+
+ if (type != XPathResult::ANY_TYPE) {
+ ec = 0;
+ result->convertTo(type, ec);
+ if (ec)
+ return 0;
+ }
+
+ return result;
+}
+
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathExpression.h b/WebCore/xml/XPathExpression.h
new file mode 100644
index 0000000..a2b75d7
--- /dev/null
+++ b/WebCore/xml/XPathExpression.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathExpression_h
+#define XPathExpression_h
+
+#if ENABLE(XPATH)
+
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class Node;
+ class String;
+ class XPathNSResolver;
+ class XPathResult;
+
+ namespace XPath {
+ class Expression;
+ }
+
+ class XPathExpression : public RefCounted<XPathExpression> {
+ public:
+ static PassRefPtr<XPathExpression> create() { return adoptRef(new XPathExpression); }
+ ~XPathExpression();
+
+ static PassRefPtr<XPathExpression> createExpression(const String& expression, XPathNSResolver*, ExceptionCode&);
+ PassRefPtr<XPathResult> evaluate(Node* contextNode, unsigned short type, XPathResult*, ExceptionCode&);
+
+ private:
+ XPathExpression() { }
+
+ XPath::Expression* m_topExpression;
+ };
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathExpression_h
diff --git a/WebCore/xml/XPathExpression.idl b/WebCore/xml/XPathExpression.idl
new file mode 100644
index 0000000..c1fc15e
--- /dev/null
+++ b/WebCore/xml/XPathExpression.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module xpath {
+
+
+ interface [
+ Conditional=XPATH,
+ GenerateConstructor
+ ] XPathExpression {
+ [OldStyleObjC] XPathResult evaluate(in Node contextNode,
+ in unsigned short type,
+ in XPathResult inResult)
+ raises(DOMException);
+ };
+
+}
diff --git a/WebCore/xml/XPathExpressionNode.cpp b/WebCore/xml/XPathExpressionNode.cpp
new file mode 100644
index 0000000..88e349e
--- /dev/null
+++ b/WebCore/xml/XPathExpressionNode.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathExpressionNode.h"
+
+#if ENABLE(XPATH)
+
+#include "Node.h"
+#include "XPathValue.h"
+
+namespace WebCore {
+namespace XPath {
+
+EvaluationContext& Expression::evaluationContext()
+{
+ static EvaluationContext evaluationContext;
+ return evaluationContext;
+}
+
+Expression::Expression()
+{
+}
+
+Expression::~Expression()
+{
+ deleteAllValues(m_subExpressions);
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathExpressionNode.h b/WebCore/xml/XPathExpressionNode.h
new file mode 100644
index 0000000..9c5f79b
--- /dev/null
+++ b/WebCore/xml/XPathExpressionNode.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathExpressionNode_h
+#define XPathExpressionNode_h
+
+#if ENABLE(XPATH)
+
+#include "StringHash.h"
+#include "Node.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class Value;
+
+ struct EvaluationContext {
+ EvaluationContext() : node(0), size(0), position(0) { }
+
+ RefPtr<Node> node;
+ unsigned long size;
+ unsigned long position;
+ HashMap<String, String> variableBindings;
+
+ };
+
+ class ParseNode {
+ public:
+ virtual ~ParseNode() { }
+ };
+
+ class Expression : public ParseNode, Noncopyable {
+ public:
+ static EvaluationContext& evaluationContext();
+
+ Expression();
+ virtual ~Expression();
+
+ virtual Value evaluate() const = 0;
+
+ void addSubExpression(Expression* expr) { m_subExpressions.append(expr); }
+
+ protected:
+ unsigned subExprCount() const { return m_subExpressions.size(); }
+ Expression* subExpr(unsigned i) { return m_subExpressions[i]; }
+ const Expression* subExpr(unsigned i) const { return m_subExpressions[i]; }
+
+ private:
+ Vector<Expression*> m_subExpressions;
+ };
+
+ }
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // EXPRESSION_H
+
diff --git a/WebCore/xml/XPathFunctions.cpp b/WebCore/xml/XPathFunctions.cpp
new file mode 100644
index 0000000..841b436
--- /dev/null
+++ b/WebCore/xml/XPathFunctions.cpp
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathFunctions.h"
+
+#if ENABLE(XPATH)
+
+#include "Document.h"
+#include "Element.h"
+#include "NamedAttrMap.h"
+#include "XMLNames.h"
+#include "XPathUtil.h"
+#include "XPathValue.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+namespace XPath {
+
+static inline bool isWhitespace(UChar c)
+{
+ return c == ' ' || c == '\n' || c == '\r' || c == '\t';
+}
+
+
+#define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
+
+class Interval {
+public:
+ static const int Inf = -1;
+
+ Interval();
+ Interval(int value);
+ Interval(int min, int max);
+
+ bool contains(int value) const;
+
+private:
+ int m_min;
+ int m_max;
+};
+
+struct FunctionRec {
+ typedef Function *(*FactoryFn)();
+ FactoryFn factoryFn;
+ Interval args;
+};
+
+static HashMap<String, FunctionRec>* functionMap;
+
+class FunLast : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunPosition : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunCount : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunId : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunLocalName : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunNamespaceURI : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunName : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunString : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunConcat : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunStartsWith : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunContains : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunSubstringBefore : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunSubstringAfter : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunSubstring : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunStringLength : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunNormalizeSpace : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunTranslate : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunBoolean : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunNot : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunTrue : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunFalse : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunLang : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunNumber : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunSum : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunFloor : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunCeiling : public Function {
+ virtual Value evaluate() const;
+};
+
+class FunRound : public Function {
+ virtual Value evaluate() const;
+public:
+ static double round(double);
+};
+
+DEFINE_FUNCTION_CREATOR(FunLast)
+DEFINE_FUNCTION_CREATOR(FunPosition)
+DEFINE_FUNCTION_CREATOR(FunCount)
+DEFINE_FUNCTION_CREATOR(FunId)
+DEFINE_FUNCTION_CREATOR(FunLocalName)
+DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
+DEFINE_FUNCTION_CREATOR(FunName)
+
+DEFINE_FUNCTION_CREATOR(FunString)
+DEFINE_FUNCTION_CREATOR(FunConcat)
+DEFINE_FUNCTION_CREATOR(FunStartsWith)
+DEFINE_FUNCTION_CREATOR(FunContains)
+DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
+DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
+DEFINE_FUNCTION_CREATOR(FunSubstring)
+DEFINE_FUNCTION_CREATOR(FunStringLength)
+DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
+DEFINE_FUNCTION_CREATOR(FunTranslate)
+
+DEFINE_FUNCTION_CREATOR(FunBoolean)
+DEFINE_FUNCTION_CREATOR(FunNot)
+DEFINE_FUNCTION_CREATOR(FunTrue)
+DEFINE_FUNCTION_CREATOR(FunFalse)
+DEFINE_FUNCTION_CREATOR(FunLang)
+
+DEFINE_FUNCTION_CREATOR(FunNumber)
+DEFINE_FUNCTION_CREATOR(FunSum)
+DEFINE_FUNCTION_CREATOR(FunFloor)
+DEFINE_FUNCTION_CREATOR(FunCeiling)
+DEFINE_FUNCTION_CREATOR(FunRound)
+
+#undef DEFINE_FUNCTION_CREATOR
+
+inline Interval::Interval()
+ : m_min(Inf), m_max(Inf)
+{
+}
+
+inline Interval::Interval(int value)
+ : m_min(value), m_max(value)
+{
+}
+
+inline Interval::Interval(int min, int max)
+ : m_min(min), m_max(max)
+{
+}
+
+inline bool Interval::contains(int value) const
+{
+ if (m_min == Inf && m_max == Inf)
+ return true;
+
+ if (m_min == Inf)
+ return value <= m_max;
+
+ if (m_max == Inf)
+ return value >= m_min;
+
+ return value >= m_min && value <= m_max;
+}
+
+void Function::setArguments(const Vector<Expression*>& args)
+{
+ Vector<Expression*>::const_iterator end = args.end();
+
+ for (Vector<Expression*>::const_iterator it = args.begin(); it != end; it++)
+ addSubExpression(*it);
+}
+
+Value FunLast::evaluate() const
+{
+ return Expression::evaluationContext().size;
+}
+
+Value FunPosition::evaluate() const
+{
+ return Expression::evaluationContext().position;
+}
+
+Value FunId::evaluate() const
+{
+ Value a = arg(0)->evaluate();
+ Vector<UChar> idList; // A whitespace-separated list of IDs
+
+ if (a.isNodeSet()) {
+ const NodeSet& nodes = a.toNodeSet();
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ String str = stringValue(nodes[i]);
+ idList.append(str.characters(), str.length());
+ idList.append(' ');
+ }
+ } else {
+ String str = a.toString();
+ idList.append(str.characters(), str.length());
+ }
+
+ Document* contextDocument = evaluationContext().node->document();
+ NodeSet result;
+ HashSet<Node*> resultSet;
+
+ size_t startPos = 0;
+ size_t length = idList.size();
+ while (true) {
+ while (startPos < length && isWhitespace(idList[startPos]))
+ ++startPos;
+
+ if (startPos == length)
+ break;
+
+ size_t endPos = startPos;
+ while (endPos < length && !isWhitespace(idList[endPos]))
+ ++endPos;
+
+ // If there are several nodes with the same id, id() should return the first one.
+ // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
+ Node* node = contextDocument->getElementById(String(&idList[startPos], endPos - startPos));
+ if (node && resultSet.add(node).second)
+ result.append(node);
+
+ startPos = endPos;
+ }
+
+ result.markSorted(false);
+
+ return Value(result, Value::adopt);
+}
+
+Value FunLocalName::evaluate() const
+{
+ Node* node = 0;
+ if (argCount() > 0) {
+ Value a = arg(0)->evaluate();
+ if (!a.isNodeSet())
+ return "";
+
+ node = a.toNodeSet().firstNode();
+ if (!node)
+ return "";
+ }
+
+ if (!node)
+ node = evaluationContext().node.get();
+
+ return node->localName().string();
+}
+
+Value FunNamespaceURI::evaluate() const
+{
+ Node* node = 0;
+ if (argCount() > 0) {
+ Value a = arg(0)->evaluate();
+ if (!a.isNodeSet())
+ return "";
+
+ node = a.toNodeSet().firstNode();
+ if (!node)
+ return "";
+ }
+
+ if (!node)
+ node = evaluationContext().node.get();
+
+ return node->namespaceURI().string();
+}
+
+Value FunName::evaluate() const
+{
+ Node* node = 0;
+ if (argCount() > 0) {
+ Value a = arg(0)->evaluate();
+ if (!a.isNodeSet())
+ return "";
+
+ node = a.toNodeSet().firstNode();
+ if (!node)
+ return "";
+ }
+
+ if (!node)
+ node = evaluationContext().node.get();
+
+ const AtomicString& prefix = node->prefix();
+ return prefix.isEmpty() ? node->localName().string() : prefix + ":" + node->localName();
+}
+
+Value FunCount::evaluate() const
+{
+ Value a = arg(0)->evaluate();
+
+ if (!a.isNodeSet())
+ return 0.0;
+
+ return double(a.toNodeSet().size());
+}
+
+Value FunString::evaluate() const
+{
+ if (!argCount())
+ return Value(Expression::evaluationContext().node.get()).toString();
+ return arg(0)->evaluate().toString();
+}
+
+Value FunConcat::evaluate() const
+{
+ Vector<UChar, 1024> result;
+
+ unsigned count = argCount();
+ for (unsigned i = 0; i < count; ++i) {
+ String str(arg(i)->evaluate().toString());
+ result.append(str.characters(), str.length());
+ }
+
+ return String(result.data(), result.size());
+}
+
+Value FunStartsWith::evaluate() const
+{
+ String s1 = arg(0)->evaluate().toString();
+ String s2 = arg(1)->evaluate().toString();
+
+ if (s2.isEmpty())
+ return true;
+
+ return s1.startsWith(s2);
+}
+
+Value FunContains::evaluate() const
+{
+ String s1 = arg(0)->evaluate().toString();
+ String s2 = arg(1)->evaluate().toString();
+
+ if (s2.isEmpty())
+ return true;
+
+ return s1.contains(s2) != 0;
+}
+
+Value FunSubstringBefore::evaluate() const
+{
+ String s1 = arg(0)->evaluate().toString();
+ String s2 = arg(1)->evaluate().toString();
+
+ if (s2.isEmpty())
+ return "";
+
+ int i = s1.find(s2);
+
+ if (i == -1)
+ return "";
+
+ return s1.left(i);
+}
+
+Value FunSubstringAfter::evaluate() const
+{
+ String s1 = arg(0)->evaluate().toString();
+ String s2 = arg(1)->evaluate().toString();
+
+ int i = s1.find(s2);
+ if (i == -1)
+ return "";
+
+ return s1.substring(i + s2.length());
+}
+
+Value FunSubstring::evaluate() const
+{
+ String s = arg(0)->evaluate().toString();
+ long pos = static_cast<long>(FunRound::round(arg(1)->evaluate().toNumber()));
+ bool haveLength = argCount() == 3;
+ long len = -1;
+ if (haveLength) {
+ double doubleLen = arg(2)->evaluate().toNumber();
+ if (isnan(doubleLen))
+ return "";
+ len = static_cast<long>(FunRound::round(doubleLen));
+ }
+
+ if (pos > long(s.length()))
+ return "";
+
+ if (haveLength && pos < 1) {
+ len -= 1 - pos;
+ pos = 1;
+ if (len < 1)
+ return "";
+ }
+
+ return s.substring(pos - 1, len);
+}
+
+Value FunStringLength::evaluate() const
+{
+ if (!argCount())
+ return Value(Expression::evaluationContext().node.get()).toString().length();
+ return arg(0)->evaluate().toString().length();
+}
+
+Value FunNormalizeSpace::evaluate() const
+{
+ if (!argCount()) {
+ String s = Value(Expression::evaluationContext().node.get()).toString();
+ return s.simplifyWhiteSpace();
+ }
+
+ String s = arg(0)->evaluate().toString();
+ return s.simplifyWhiteSpace();
+}
+
+Value FunTranslate::evaluate() const
+{
+ String s1 = arg(0)->evaluate().toString();
+ String s2 = arg(1)->evaluate().toString();
+ String s3 = arg(2)->evaluate().toString();
+ String newString;
+
+ // FIXME: Building a String a character at a time is quite slow.
+ for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
+ UChar ch = s1[i1];
+ int i2 = s2.find(ch);
+
+ if (i2 == -1)
+ newString += String(&ch, 1);
+ else if ((unsigned)i2 < s3.length()) {
+ UChar c2 = s3[i2];
+ newString += String(&c2, 1);
+ }
+ }
+
+ return newString;
+}
+
+Value FunBoolean::evaluate() const
+{
+ return arg(0)->evaluate().toBoolean();
+}
+
+Value FunNot::evaluate() const
+{
+ return !arg(0)->evaluate().toBoolean();
+}
+
+Value FunTrue::evaluate() const
+{
+ return true;
+}
+
+Value FunLang::evaluate() const
+{
+ String lang = arg(0)->evaluate().toString();
+
+ RefPtr<Node> langNode = 0;
+ Node* node = evaluationContext().node.get();
+ while (node) {
+ NamedAttrMap* attrs = node->attributes();
+ if (attrs)
+ langNode = attrs->getNamedItemNS(XMLNames::xmlNamespaceURI, "lang");
+ if (langNode)
+ break;
+ node = node->parentNode();
+ }
+
+ if (!langNode)
+ return false;
+
+ String langNodeValue = langNode->nodeValue();
+ while (true) {
+ if (equalIgnoringCase(langNodeValue, lang))
+ return true;
+
+ // Remove suffixes one by one.
+ int index = langNodeValue.reverseFind('-');
+ if (index == -1)
+ break;
+ langNodeValue = langNodeValue.left(index);
+ }
+
+ return false;
+}
+
+Value FunFalse::evaluate() const
+{
+ return false;
+}
+
+Value FunNumber::evaluate() const
+{
+ if (!argCount())
+ return Value(Expression::evaluationContext().node.get()).toNumber();
+ return arg(0)->evaluate().toNumber();
+}
+
+Value FunSum::evaluate() const
+{
+ Value a = arg(0)->evaluate();
+ if (!a.isNodeSet())
+ return 0.0;
+
+ double sum = 0.0;
+ const NodeSet& nodes = a.toNodeSet();
+ // To be really compliant, we should sort the node-set, as floating point addition is not associative.
+ // However, this is unlikely to ever become a practical issue, and sorting is slow.
+
+ for (unsigned i = 0; i < nodes.size(); i++)
+ sum += Value(stringValue(nodes[i])).toNumber();
+
+ return sum;
+}
+
+Value FunFloor::evaluate() const
+{
+ return floor(arg(0)->evaluate().toNumber());
+}
+
+Value FunCeiling::evaluate() const
+{
+ return ceil(arg(0)->evaluate().toNumber());
+}
+
+double FunRound::round(double val)
+{
+ if (!isnan(val) && !isinf(val)) {
+ if (signbit(val) && val >= -0.5)
+ val *= 0; // negative zero
+ else
+ val = floor(val + 0.5);
+ }
+ return val;
+}
+
+Value FunRound::evaluate() const
+{
+ return round(arg(0)->evaluate().toNumber());
+}
+
+static void createFunctionMap()
+{
+ struct FunctionMapping {
+ const char *name;
+ FunctionRec function;
+ };
+ static const FunctionMapping functions[] = {
+ { "boolean", { &createFunBoolean, 1 } },
+ { "ceiling", { &createFunCeiling, 1 } },
+ { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
+ { "contains", { &createFunContains, 2 } },
+ { "count", { &createFunCount, 1 } },
+ { "false", { &createFunFalse, 0 } },
+ { "floor", { &createFunFloor, 1 } },
+ { "id", { &createFunId, 1 } },
+ { "lang", { &createFunLang, 1 } },
+ { "last", { &createFunLast, 0 } },
+ { "local-name", { &createFunLocalName, Interval(0, 1) } },
+ { "name", { &createFunName, Interval(0, 1) } },
+ { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
+ { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
+ { "not", { &createFunNot, 1 } },
+ { "number", { &createFunNumber, Interval(0, 1) } },
+ { "position", { &createFunPosition, 0 } },
+ { "round", { &createFunRound, 1 } },
+ { "starts-with", { &createFunStartsWith, 2 } },
+ { "string", { &createFunString, Interval(0, 1) } },
+ { "string-length", { &createFunStringLength, Interval(0, 1) } },
+ { "substring", { &createFunSubstring, Interval(2, 3) } },
+ { "substring-after", { &createFunSubstringAfter, 2 } },
+ { "substring-before", { &createFunSubstringBefore, 2 } },
+ { "sum", { &createFunSum, 1 } },
+ { "translate", { &createFunTranslate, 3 } },
+ { "true", { &createFunTrue, 0 } },
+ };
+ const unsigned int numFunctions = sizeof(functions) / sizeof(functions[0]);
+
+ functionMap = new HashMap<String, FunctionRec>;
+ for (unsigned i = 0; i < numFunctions; ++i)
+ functionMap->set(functions[i].name, functions[i].function);
+}
+
+Function* createFunction(const String& name, const Vector<Expression*>& args)
+{
+ if (!functionMap)
+ createFunctionMap();
+
+ HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name);
+ FunctionRec* functionRec = 0;
+
+ if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->second)->args.contains(args.size()))
+ return 0;
+
+ Function* function = functionRec->factoryFn();
+ function->setArguments(args);
+ function->setName(name);
+ return function;
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathFunctions.h b/WebCore/xml/XPathFunctions.h
new file mode 100644
index 0000000..f22d3ef
--- /dev/null
+++ b/WebCore/xml/XPathFunctions.h
@@ -0,0 +1,62 @@
+/*
+ * functions.h - Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathFunctions_h
+#define XPathFunctions_h
+
+#if ENABLE(XPATH)
+
+#include "XPathExpressionNode.h"
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class Function : public Expression {
+ public:
+ void setArguments(const Vector<Expression*>&);
+ void setName(const String& name) { m_name = name; }
+
+ protected:
+ Expression* arg(int pos) { return subExpr(pos); }
+ const Expression* arg(int pos) const { return subExpr(pos); }
+ unsigned int argCount() const { return subExprCount(); }
+ String name() const { return m_name; }
+
+ private:
+ String m_name;
+ };
+
+ Function* createFunction(const String& name, const Vector<Expression*>& args = Vector<Expression*>());
+
+ }
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPath_Functions_H
+
diff --git a/WebCore/xml/XPathGrammar.y b/WebCore/xml/XPathGrammar.y
new file mode 100644
index 0000000..50a69c2
--- /dev/null
+++ b/WebCore/xml/XPathGrammar.y
@@ -0,0 +1,554 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+
+#include "config.h"
+
+#if ENABLE(XPATH)
+
+#include "XPathFunctions.h"
+#include "XPathNSResolver.h"
+#include "XPathParser.h"
+#include "XPathPath.h"
+#include "XPathPredicate.h"
+#include "XPathVariableReference.h"
+
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
+#define YYDEBUG 0
+#define YYMAXDEPTH 10000
+#define YYPARSE_PARAM parserParameter
+#define PARSER static_cast<Parser*>(parserParameter)
+
+using namespace WebCore;
+using namespace XPath;
+
+%}
+
+%pure_parser
+
+%union
+{
+ Step::Axis axis;
+ Step::NodeTest* nodeTest;
+ NumericOp::Opcode numop;
+ EqTestOp::Opcode eqop;
+ String* str;
+ Expression* expr;
+ Vector<Predicate*>* predList;
+ Vector<Expression*>* argList;
+ Step* step;
+ LocationPath* locationPath;
+}
+
+%{
+
+int xpathyylex(YYSTYPE* yylval) { return Parser::current()->lex(yylval); }
+void xpathyyerror(const char* str) { }
+
+%}
+
+%left <numop> MULOP
+%left <eqop> EQOP RELOP
+%left PLUS MINUS
+%left OR AND
+%token <axis> AXISNAME
+%token <str> NODETYPE PI FUNCTIONNAME LITERAL
+%token <str> VARIABLEREFERENCE NUMBER
+%token DOTDOT SLASHSLASH
+%token <str> NAMETEST
+%token XPATH_ERROR
+
+%type <locationPath> LocationPath
+%type <locationPath> AbsoluteLocationPath
+%type <locationPath> RelativeLocationPath
+%type <step> Step
+%type <axis> AxisSpecifier
+%type <step> DescendantOrSelf
+%type <nodeTest> NodeTest
+%type <expr> Predicate
+%type <predList> OptionalPredicateList
+%type <predList> PredicateList
+%type <step> AbbreviatedStep
+%type <expr> Expr
+%type <expr> PrimaryExpr
+%type <expr> FunctionCall
+%type <argList> ArgumentList
+%type <expr> Argument
+%type <expr> UnionExpr
+%type <expr> PathExpr
+%type <expr> FilterExpr
+%type <expr> OrExpr
+%type <expr> AndExpr
+%type <expr> EqualityExpr
+%type <expr> RelationalExpr
+%type <expr> AdditiveExpr
+%type <expr> MultiplicativeExpr
+%type <expr> UnaryExpr
+
+%%
+
+Expr:
+ OrExpr
+ {
+ PARSER->m_topExpr = $1;
+ }
+ ;
+
+LocationPath:
+ RelativeLocationPath
+ {
+ $$->setAbsolute(false);
+ }
+ |
+ AbsoluteLocationPath
+ {
+ $$->setAbsolute(true);
+ }
+ ;
+
+AbsoluteLocationPath:
+ '/'
+ {
+ $$ = new LocationPath;
+ PARSER->registerParseNode($$);
+ }
+ |
+ '/' RelativeLocationPath
+ {
+ $$ = $2;
+ }
+ |
+ DescendantOrSelf RelativeLocationPath
+ {
+ $$ = $2;
+ $$->insertFirstStep($1);
+ PARSER->unregisterParseNode($1);
+ }
+ ;
+
+RelativeLocationPath:
+ Step
+ {
+ $$ = new LocationPath;
+ $$->appendStep($1);
+ PARSER->unregisterParseNode($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ RelativeLocationPath '/' Step
+ {
+ $$->appendStep($3);
+ PARSER->unregisterParseNode($3);
+ }
+ |
+ RelativeLocationPath DescendantOrSelf Step
+ {
+ $$->appendStep($2);
+ $$->appendStep($3);
+ PARSER->unregisterParseNode($2);
+ PARSER->unregisterParseNode($3);
+ }
+ ;
+
+Step:
+ NodeTest OptionalPredicateList
+ {
+ if ($2) {
+ $$ = new Step(Step::ChildAxis, *$1, *$2);
+ PARSER->deletePredicateVector($2);
+ } else
+ $$ = new Step(Step::ChildAxis, *$1);
+ PARSER->deleteNodeTest($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ NAMETEST OptionalPredicateList
+ {
+ String localName;
+ String namespaceURI;
+ if (!PARSER->expandQName(*$1, localName, namespaceURI)) {
+ PARSER->m_gotNamespaceError = true;
+ YYABORT;
+ }
+
+ if ($2) {
+ $$ = new Step(Step::ChildAxis, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI), *$2);
+ PARSER->deletePredicateVector($2);
+ } else
+ $$ = new Step(Step::ChildAxis, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI));
+ PARSER->deleteString($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ AxisSpecifier NodeTest OptionalPredicateList
+ {
+ if ($3) {
+ $$ = new Step($1, *$2, *$3);
+ PARSER->deletePredicateVector($3);
+ } else
+ $$ = new Step($1, *$2);
+ PARSER->deleteNodeTest($2);
+ PARSER->registerParseNode($$);
+ }
+ |
+ AxisSpecifier NAMETEST OptionalPredicateList
+ {
+ String localName;
+ String namespaceURI;
+ if (!PARSER->expandQName(*$2, localName, namespaceURI)) {
+ PARSER->m_gotNamespaceError = true;
+ YYABORT;
+ }
+
+ if ($3) {
+ $$ = new Step($1, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI), *$3);
+ PARSER->deletePredicateVector($3);
+ } else
+ $$ = new Step($1, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI));
+ PARSER->deleteString($2);
+ PARSER->registerParseNode($$);
+ }
+ |
+ AbbreviatedStep
+ ;
+
+AxisSpecifier:
+ AXISNAME
+ |
+ '@'
+ {
+ $$ = Step::AttributeAxis;
+ }
+ ;
+
+NodeTest:
+ NODETYPE '(' ')'
+ {
+ if (*$1 == "node")
+ $$ = new Step::NodeTest(Step::NodeTest::AnyNodeTest);
+ else if (*$1 == "text")
+ $$ = new Step::NodeTest(Step::NodeTest::TextNodeTest);
+ else if (*$1 == "comment")
+ $$ = new Step::NodeTest(Step::NodeTest::CommentNodeTest);
+
+ PARSER->deleteString($1);
+ PARSER->registerNodeTest($$);
+ }
+ |
+ PI '(' ')'
+ {
+ $$ = new Step::NodeTest(Step::NodeTest::ProcessingInstructionNodeTest);
+ PARSER->deleteString($1);
+ PARSER->registerNodeTest($$);
+ }
+ |
+ PI '(' LITERAL ')'
+ {
+ $$ = new Step::NodeTest(Step::NodeTest::ProcessingInstructionNodeTest, $3->stripWhiteSpace());
+ PARSER->deleteString($1);
+ PARSER->deleteString($3);
+ PARSER->registerNodeTest($$);
+ }
+ ;
+
+OptionalPredicateList:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ |
+ PredicateList
+ ;
+
+PredicateList:
+ Predicate
+ {
+ $$ = new Vector<Predicate*>;
+ $$->append(new Predicate($1));
+ PARSER->unregisterParseNode($1);
+ PARSER->registerPredicateVector($$);
+ }
+ |
+ PredicateList Predicate
+ {
+ $$->append(new Predicate($2));
+ PARSER->unregisterParseNode($2);
+ }
+ ;
+
+Predicate:
+ '[' Expr ']'
+ {
+ $$ = $2;
+ }
+ ;
+
+DescendantOrSelf:
+ SLASHSLASH
+ {
+ $$ = new Step(Step::DescendantOrSelfAxis, Step::NodeTest(Step::NodeTest::AnyNodeTest));
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+AbbreviatedStep:
+ '.'
+ {
+ $$ = new Step(Step::SelfAxis, Step::NodeTest(Step::NodeTest::AnyNodeTest));
+ PARSER->registerParseNode($$);
+ }
+ |
+ DOTDOT
+ {
+ $$ = new Step(Step::ParentAxis, Step::NodeTest(Step::NodeTest::AnyNodeTest));
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+PrimaryExpr:
+ VARIABLEREFERENCE
+ {
+ $$ = new VariableReference(*$1);
+ PARSER->deleteString($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ '(' Expr ')'
+ {
+ $$ = $2;
+ }
+ |
+ LITERAL
+ {
+ $$ = new StringExpression(*$1);
+ PARSER->deleteString($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ NUMBER
+ {
+ $$ = new Number($1->toDouble());
+ PARSER->deleteString($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ FunctionCall
+ ;
+
+FunctionCall:
+ FUNCTIONNAME '(' ')'
+ {
+ $$ = createFunction(*$1);
+ if (!$$)
+ YYABORT;
+ PARSER->deleteString($1);
+ PARSER->registerParseNode($$);
+ }
+ |
+ FUNCTIONNAME '(' ArgumentList ')'
+ {
+ $$ = createFunction(*$1, *$3);
+ if (!$$)
+ YYABORT;
+ PARSER->deleteString($1);
+ PARSER->deleteExpressionVector($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+ArgumentList:
+ Argument
+ {
+ $$ = new Vector<Expression*>;
+ $$->append($1);
+ PARSER->unregisterParseNode($1);
+ PARSER->registerExpressionVector($$);
+ }
+ |
+ ArgumentList ',' Argument
+ {
+ $$->append($3);
+ PARSER->unregisterParseNode($3);
+ }
+ ;
+
+Argument:
+ Expr
+ ;
+
+UnionExpr:
+ PathExpr
+ |
+ UnionExpr '|' PathExpr
+ {
+ $$ = new Union;
+ $$->addSubExpression($1);
+ $$->addSubExpression($3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+PathExpr:
+ LocationPath
+ {
+ $$ = $1;
+ }
+ |
+ FilterExpr
+ |
+ FilterExpr '/' RelativeLocationPath
+ {
+ $3->setAbsolute(true);
+ $$ = new Path(static_cast<Filter*>($1), $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ |
+ FilterExpr DescendantOrSelf RelativeLocationPath
+ {
+ $3->insertFirstStep($2);
+ $3->setAbsolute(true);
+ $$ = new Path(static_cast<Filter*>($1), $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($2);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+FilterExpr:
+ PrimaryExpr
+ |
+ PrimaryExpr PredicateList
+ {
+ $$ = new Filter($1, *$2);
+ PARSER->unregisterParseNode($1);
+ PARSER->deletePredicateVector($2);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+OrExpr:
+ AndExpr
+ |
+ OrExpr OR AndExpr
+ {
+ $$ = new LogicalOp(LogicalOp::OP_Or, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+AndExpr:
+ EqualityExpr
+ |
+ AndExpr AND EqualityExpr
+ {
+ $$ = new LogicalOp(LogicalOp::OP_And, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+EqualityExpr:
+ RelationalExpr
+ |
+ EqualityExpr EQOP RelationalExpr
+ {
+ $$ = new EqTestOp($2, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+RelationalExpr:
+ AdditiveExpr
+ |
+ RelationalExpr RELOP AdditiveExpr
+ {
+ $$ = new EqTestOp($2, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+AdditiveExpr:
+ MultiplicativeExpr
+ |
+ AdditiveExpr PLUS MultiplicativeExpr
+ {
+ $$ = new NumericOp(NumericOp::OP_Add, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ |
+ AdditiveExpr MINUS MultiplicativeExpr
+ {
+ $$ = new NumericOp(NumericOp::OP_Sub, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+MultiplicativeExpr:
+ UnaryExpr
+ |
+ MultiplicativeExpr MULOP UnaryExpr
+ {
+ $$ = new NumericOp($2, $1, $3);
+ PARSER->unregisterParseNode($1);
+ PARSER->unregisterParseNode($3);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+UnaryExpr:
+ UnionExpr
+ |
+ MINUS UnaryExpr
+ {
+ $$ = new Negative;
+ $$->addSubExpression($2);
+ PARSER->unregisterParseNode($2);
+ PARSER->registerParseNode($$);
+ }
+ ;
+
+%%
+
+#endif
diff --git a/WebCore/xml/XPathNSResolver.cpp b/WebCore/xml/XPathNSResolver.cpp
new file mode 100644
index 0000000..3dde1f2
--- /dev/null
+++ b/WebCore/xml/XPathNSResolver.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathNSResolver.h"
+
+#if ENABLE(XPATH)
+
+namespace WebCore {
+
+XPathNSResolver::~XPathNSResolver()
+{
+}
+
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathNSResolver.h b/WebCore/xml/XPathNSResolver.h
new file mode 100644
index 0000000..04b5f80
--- /dev/null
+++ b/WebCore/xml/XPathNSResolver.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathNSResolver_h
+#define XPathNSResolver_h
+
+#if ENABLE(XPATH)
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class String;
+
+ class XPathNSResolver : public RefCounted<XPathNSResolver> {
+ public:
+ virtual ~XPathNSResolver();
+ virtual String lookupNamespaceURI(const String& prefix) = 0;
+
+ protected:
+ XPathNSResolver() { }
+ };
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathNSResolver_h
diff --git a/WebCore/xml/XPathNSResolver.idl b/WebCore/xml/XPathNSResolver.idl
new file mode 100644
index 0000000..48c0113
--- /dev/null
+++ b/WebCore/xml/XPathNSResolver.idl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module xpath {
+
+ interface [ObjCProtocol, Conditional=XPATH] XPathNSResolver {
+ [ConvertNullStringTo=Null] DOMString lookupNamespaceURI(in DOMString prefix);
+ };
+
+}
diff --git a/WebCore/xml/XPathNamespace.cpp b/WebCore/xml/XPathNamespace.cpp
new file mode 100644
index 0000000..3c8c42c
--- /dev/null
+++ b/WebCore/xml/XPathNamespace.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathNamespace.h"
+
+#if ENABLE(XPATH)
+
+#include "Element.h"
+
+namespace WebCore {
+
+XPathNamespace::XPathNamespace(PassRefPtr<Element> ownerElement, const String& prefix, const String& uri)
+ : Node(ownerElement->document())
+ , m_ownerElement(ownerElement)
+ , m_prefix(prefix)
+ , m_uri(uri)
+{
+}
+
+XPathNamespace::~XPathNamespace()
+{
+}
+
+Document* XPathNamespace::ownerDocument() const
+{
+ return m_ownerElement->ownerDocument();
+}
+
+Element* XPathNamespace::ownerElement() const
+{
+ return m_ownerElement.get();
+}
+
+const AtomicString& XPathNamespace::prefix() const
+{
+ return m_prefix;
+}
+
+String XPathNamespace::nodeName() const
+{
+ return "#namespace";
+}
+
+String XPathNamespace::nodeValue() const
+{
+ return m_uri;
+}
+
+const AtomicString& XPathNamespace::namespaceURI() const
+{
+ return m_uri;
+}
+
+Node::NodeType XPathNamespace::nodeType() const
+{
+ return Node::XPATH_NAMESPACE_NODE;
+}
+
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathNamespace.h b/WebCore/xml/XPathNamespace.h
new file mode 100644
index 0000000..c0e4280
--- /dev/null
+++ b/WebCore/xml/XPathNamespace.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathNamespace_h
+#define XPathNamespace_h
+
+#if ENABLE(XPATH)
+
+#include "AtomicString.h"
+#include "Node.h"
+
+namespace WebCore {
+
+ class Document;
+ class Element;
+
+ class XPathNamespace : public Node {
+ public:
+ XPathNamespace(PassRefPtr<Element> ownerElement, const String& prefix, const String& uri);
+ virtual ~XPathNamespace();
+
+ virtual Document* ownerDocument() const;
+ virtual Element* ownerElement() const;
+
+ virtual const AtomicString& prefix() const;
+ virtual String nodeName() const;
+ virtual String nodeValue() const;
+ virtual const AtomicString& namespaceURI() const;
+
+ virtual Node::NodeType nodeType() const;
+
+ private:
+ RefPtr<Element> m_ownerElement;
+ AtomicString m_prefix;
+ AtomicString m_uri;
+ };
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathNamespace_h
+
diff --git a/WebCore/xml/XPathNodeSet.cpp b/WebCore/xml/XPathNodeSet.cpp
new file mode 100644
index 0000000..e29c096
--- /dev/null
+++ b/WebCore/xml/XPathNodeSet.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(XPATH)
+#include "XPathNodeSet.h"
+
+#include "Attr.h"
+#include "Element.h"
+#include "Node.h"
+
+namespace WebCore {
+namespace XPath {
+
+static inline Node* parentWithDepth(unsigned depth, const Vector<Node*>& parents)
+{
+ ASSERT(parents.size() >= depth + 1);
+ return parents[parents.size() - 1 - depth];
+}
+
+static void sortBlock(unsigned from, unsigned to, Vector<Vector<Node*> >& parentMatrix, bool mayContainAttributeNodes)
+{
+ ASSERT(from + 1 < to); // Should not call this function with less that two nodes to sort.
+ unsigned minDepth = UINT_MAX;
+ for (unsigned i = from; i < to; ++i) {
+ unsigned depth = parentMatrix[i].size() - 1;
+ if (minDepth > depth)
+ minDepth = depth;
+ }
+
+ // Find the common ancestor.
+ unsigned commonAncestorDepth = minDepth;
+ Node* commonAncestor;
+ while (true) {
+ commonAncestor = parentWithDepth(commonAncestorDepth, parentMatrix[from]);
+ if (commonAncestorDepth == 0)
+ break;
+
+ bool allEqual = true;
+ for (unsigned i = from + 1; i < to; ++i) {
+ if (commonAncestor != parentWithDepth(commonAncestorDepth, parentMatrix[i])) {
+ allEqual = false;
+ break;
+ }
+ }
+ if (allEqual)
+ break;
+
+ --commonAncestorDepth;
+ }
+
+ if (commonAncestorDepth == minDepth) {
+ // One of the nodes is the common ancestor => it is the first in document order.
+ // Find it and move it to the beginning.
+ for (unsigned i = from; i < to; ++i)
+ if (commonAncestor == parentMatrix[i][0]) {
+ parentMatrix[i].swap(parentMatrix[from]);
+ if (from + 2 < to)
+ sortBlock(from + 1, to, parentMatrix, mayContainAttributeNodes);
+ return;
+ }
+ }
+
+ if (mayContainAttributeNodes && commonAncestor->isElementNode()) {
+ // The attribute nodes and namespace nodes of an element occur before the children of the element.
+ // The namespace nodes are defined to occur before the attribute nodes.
+ // The relative order of namespace nodes is implementation-dependent.
+ // The relative order of attribute nodes is implementation-dependent.
+ unsigned sortedEnd = from;
+ // FIXME: namespace nodes are not implemented.
+ for (unsigned i = sortedEnd; i < to; ++i) {
+ Node* n = parentMatrix[i][0];
+ if (n->isAttributeNode() && static_cast<Attr*>(n)->ownerElement() == commonAncestor)
+ parentMatrix[i].swap(parentMatrix[sortedEnd++]);
+ }
+ if (sortedEnd != from) {
+ if (to - sortedEnd > 1)
+ sortBlock(sortedEnd, to, parentMatrix, mayContainAttributeNodes);
+ return;
+ }
+ }
+
+ // Children nodes of the common ancestor induce a subdivision of our node-set.
+ // Sort it according to this subdivision, and recursively sort each group.
+ HashSet<Node*> parentNodes;
+ for (unsigned i = from; i < to; ++i)
+ parentNodes.add(parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]));
+
+ unsigned previousGroupEnd = from;
+ unsigned groupEnd = from;
+ for (Node* n = commonAncestor->firstChild(); n; n = n->nextSibling()) {
+ // If parentNodes contains the node, perform a linear search to move its children in the node-set to the beginning.
+ if (parentNodes.contains(n)) {
+ for (unsigned i = groupEnd; i < to; ++i)
+ if (parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]) == n)
+ parentMatrix[i].swap(parentMatrix[groupEnd++]);
+
+ if (groupEnd - previousGroupEnd > 1)
+ sortBlock(previousGroupEnd, groupEnd, parentMatrix, mayContainAttributeNodes);
+
+ ASSERT(previousGroupEnd != groupEnd);
+ previousGroupEnd = groupEnd;
+#ifndef NDEBUG
+ parentNodes.remove(n);
+#endif
+ }
+ }
+
+ ASSERT(parentNodes.isEmpty());
+}
+
+void NodeSet::sort() const
+{
+ if (m_isSorted)
+ return;
+
+ unsigned nodeCount = m_nodes.size();
+ if (nodeCount < 2) {
+ const_cast<bool&>(m_isSorted) = true;
+ return;
+ }
+
+ bool containsAttributeNodes = false;
+
+ Vector<Vector<Node*> > parentMatrix(nodeCount);
+ for (unsigned i = 0; i < nodeCount; ++i) {
+ Vector<Node*>& parentsVector = parentMatrix[i];
+ Node* n = m_nodes[i].get();
+ parentsVector.append(n);
+ if (n->isAttributeNode()) {
+ n = static_cast<Attr*>(n)->ownerElement();
+ parentsVector.append(n);
+ containsAttributeNodes = true;
+ }
+ while ((n = n->parent()))
+ parentsVector.append(n);
+ }
+ sortBlock(0, nodeCount, parentMatrix, containsAttributeNodes);
+
+ // It is not possible to just assign the result to m_nodes, because some nodes may get dereferenced and destroyed.
+ Vector<RefPtr<Node> > sortedNodes;
+ sortedNodes.reserveCapacity(nodeCount);
+ for (unsigned i = 0; i < nodeCount; ++i)
+ sortedNodes.append(parentMatrix[i][0]);
+
+ const_cast<Vector<RefPtr<Node> >& >(m_nodes).swap(sortedNodes);
+}
+
+void NodeSet::reverse()
+{
+ if (m_nodes.isEmpty())
+ return;
+
+ unsigned from = 0;
+ unsigned to = m_nodes.size() - 1;
+ while (from < to) {
+ m_nodes[from].swap(m_nodes[to]);
+ ++from;
+ --to;
+ }
+}
+
+Node* NodeSet::firstNode() const
+{
+ if (isEmpty())
+ return 0;
+
+ sort(); // FIXME: fully sorting the node-set just to find its first node is wasteful.
+ return m_nodes.at(0).get();
+}
+
+Node* NodeSet::anyNode() const
+{
+ if (isEmpty())
+ return 0;
+
+ return m_nodes.at(0).get();
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathNodeSet.h b/WebCore/xml/XPathNodeSet.h
new file mode 100644
index 0000000..2ab6f1f
--- /dev/null
+++ b/WebCore/xml/XPathNodeSet.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathNodeSet_h
+#define XPathNodeSet_h
+
+#if ENABLE(XPATH)
+
+#include <wtf/Vector.h>
+#include <wtf/Forward.h>
+
+#include "Node.h"
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class NodeSet {
+ public:
+
+ NodeSet() : m_isSorted(true) {}
+ NodeSet(const NodeSet& other) : m_isSorted(other.m_isSorted), m_nodes(other.m_nodes) {}
+ NodeSet& operator=(const NodeSet& other) { m_isSorted = other.m_isSorted; m_nodes = other.m_nodes; return *this; }
+
+ size_t size() const { return m_nodes.size(); }
+ bool isEmpty() const { return !m_nodes.size(); }
+ Node* operator[](unsigned i) const { return m_nodes.at(i).get(); }
+ void reserveCapacity(size_t newCapacity) { m_nodes.reserveCapacity(newCapacity); }
+ void clear() { m_nodes.clear(); }
+ void swap(NodeSet& other) { std::swap(m_isSorted, other.m_isSorted); m_nodes.swap(other.m_nodes); }
+
+ // NodeSet itself does not verify that nodes in it are unique.
+ void append(Node* node) { m_nodes.append(node); }
+ void append(PassRefPtr<Node> node) { m_nodes.append(node); }
+ void append(const NodeSet& nodeSet) { m_nodes.append(nodeSet.m_nodes); }
+
+ // Returns the set's first node in document order, or 0 if the set is empty.
+ Node* firstNode() const;
+
+ // Returns 0 if the set is empty.
+ Node* anyNode() const;
+
+ // NodeSet itself doesn't check if it is contains sorted data - the caller should tell it if it does not.
+ void markSorted(bool isSorted) { m_isSorted = isSorted; }
+ bool isSorted() const { return m_isSorted; }
+
+ void sort() const;
+
+ void reverse();
+
+ private:
+ bool m_isSorted;
+ Vector<RefPtr<Node> > m_nodes;
+ };
+
+ }
+}
+
+#endif // ENABLE(XPATH)
+#endif // XPathNodeSet_h
diff --git a/WebCore/xml/XPathParser.cpp b/WebCore/xml/XPathParser.cpp
new file mode 100644
index 0000000..77c3011
--- /dev/null
+++ b/WebCore/xml/XPathParser.cpp
@@ -0,0 +1,633 @@
+/*
+ * Copyright 2005 Maksim Orlovich <maksim@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathParser.h"
+
+#if ENABLE(XPATH)
+
+#include "ExceptionCode.h"
+#include "StringHash.h"
+#include "XPathEvaluator.h"
+#include "XPathException.h"
+#include "XPathNSResolver.h"
+#include "XPathStep.h"
+
+int xpathyyparse(void*);
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+namespace XPath {
+
+class LocationPath;
+
+#include "XPathGrammar.h"
+
+Parser* Parser::currentParser = 0;
+
+enum XMLCat { NameStart, NameCont, NotPartOfName };
+
+static XMLCat charCat(UChar aChar)
+{
+ //### might need to add some special cases from the XML spec.
+
+ if (aChar == '_')
+ return NameStart;
+
+ if (aChar == '.' || aChar == '-')
+ return NameCont;
+ CharCategory category = Unicode::category(aChar);
+ if (category & (Letter_Uppercase | Letter_Lowercase | Letter_Other | Letter_Titlecase | Number_Letter))
+ return NameStart;
+ if (category & (Mark_NonSpacing | Mark_SpacingCombining | Mark_Enclosing | Letter_Modifier | Number_DecimalDigit))
+ return NameCont;
+ return NotPartOfName;
+}
+
+static void setUpAxisNamesMap(HashMap<String, Step::Axis>& axisNames)
+{
+ struct AxisName {
+ const char* name;
+ Step::Axis axis;
+ };
+ const AxisName axisNameList[] = {
+ { "ancestor", Step::AncestorAxis },
+ { "ancestor-or-self", Step::AncestorOrSelfAxis },
+ { "attribute", Step::AttributeAxis },
+ { "child", Step::ChildAxis },
+ { "descendant", Step::DescendantAxis },
+ { "descendant-or-self", Step::DescendantOrSelfAxis },
+ { "following", Step::FollowingAxis },
+ { "following-sibling", Step::FollowingSiblingAxis },
+ { "namespace", Step::NamespaceAxis },
+ { "parent", Step::ParentAxis },
+ { "preceding", Step::PrecedingAxis },
+ { "preceding-sibling", Step::PrecedingSiblingAxis },
+ { "self", Step::SelfAxis }
+ };
+ for (unsigned i = 0; i < sizeof(axisNameList) / sizeof(axisNameList[0]); ++i)
+ axisNames.set(axisNameList[i].name, axisNameList[i].axis);
+}
+
+static bool isAxisName(const String& name, Step::Axis& type)
+{
+ static HashMap<String, Step::Axis> axisNames;
+
+ if (axisNames.isEmpty())
+ setUpAxisNamesMap(axisNames);
+
+ HashMap<String, Step::Axis>::iterator it = axisNames.find(name);
+ if (it == axisNames.end())
+ return false;
+ type = it->second;
+ return true;
+}
+
+static bool isNodeTypeName(const String& name)
+{
+ static HashSet<String> nodeTypeNames;
+ if (nodeTypeNames.isEmpty()) {
+ nodeTypeNames.add("comment");
+ nodeTypeNames.add("text");
+ nodeTypeNames.add("processing-instruction");
+ nodeTypeNames.add("node");
+ }
+ return nodeTypeNames.contains(name);
+}
+
+/* Returns whether the last parsed token matches the [32] Operator rule
+ * (check http://www.w3.org/TR/xpath#exprlex). Necessary to disambiguate
+ * the tokens.
+ */
+bool Parser::isOperatorContext() const
+{
+ if (m_nextPos == 0)
+ return false;
+
+ switch (m_lastTokenType) {
+ case AND: case OR: case MULOP:
+ case '/': case SLASHSLASH: case '|': case PLUS: case MINUS:
+ case EQOP: case RELOP:
+ case '@': case AXISNAME: case '(': case '[':
+ return false;
+ default:
+ return true;
+ }
+}
+
+void Parser::skipWS()
+{
+ while (m_nextPos < m_data.length() && isSpaceOrNewline(m_data[m_nextPos]))
+ ++m_nextPos;
+}
+
+Token Parser::makeTokenAndAdvance(int code, int advance)
+{
+ m_nextPos += advance;
+ return Token(code);
+}
+
+Token Parser::makeTokenAndAdvance(int code, NumericOp::Opcode val, int advance)
+{
+ m_nextPos += advance;
+ return Token(code, val);
+}
+
+Token Parser::makeTokenAndAdvance(int code, EqTestOp::Opcode val, int advance)
+{
+ m_nextPos += advance;
+ return Token(code, val);
+}
+
+// Returns next char if it's there and interesting, 0 otherwise
+char Parser::peekAheadHelper()
+{
+ if (m_nextPos + 1 >= m_data.length())
+ return 0;
+ UChar next = m_data[m_nextPos + 1];
+ if (next >= 0xff)
+ return 0;
+ return next;
+}
+
+char Parser::peekCurHelper()
+{
+ if (m_nextPos >= m_data.length())
+ return 0;
+ UChar next = m_data[m_nextPos];
+ if (next >= 0xff)
+ return 0;
+ return next;
+}
+
+Token Parser::lexString()
+{
+ UChar delimiter = m_data[m_nextPos];
+ int startPos = m_nextPos + 1;
+
+ for (m_nextPos = startPos; m_nextPos < m_data.length(); ++m_nextPos) {
+ if (m_data[m_nextPos] == delimiter) {
+ String value = m_data.substring(startPos, m_nextPos - startPos);
+ if (value.isNull())
+ value = "";
+ ++m_nextPos; // Consume the char.
+ return Token(LITERAL, value);
+ }
+ }
+
+ // Ouch, went off the end -- report error.
+ return Token(XPATH_ERROR);
+}
+
+Token Parser::lexNumber()
+{
+ int startPos = m_nextPos;
+ bool seenDot = false;
+
+ // Go until end or a non-digits character.
+ for (; m_nextPos < m_data.length(); ++m_nextPos) {
+ UChar aChar = m_data[m_nextPos];
+ if (aChar >= 0xff) break;
+
+ if (aChar < '0' || aChar > '9') {
+ if (aChar == '.' && !seenDot)
+ seenDot = true;
+ else
+ break;
+ }
+ }
+
+ return Token(NUMBER, m_data.substring(startPos, m_nextPos - startPos));
+}
+
+bool Parser::lexNCName(String& name)
+{
+ int startPos = m_nextPos;
+ if (m_nextPos >= m_data.length())
+ return false;
+
+ if (charCat(m_data[m_nextPos]) != NameStart)
+ return false;
+
+ // Keep going until we get a character that's not good for names.
+ for (; m_nextPos < m_data.length(); ++m_nextPos)
+ if (charCat(m_data[m_nextPos]) == NotPartOfName)
+ break;
+
+ name = m_data.substring(startPos, m_nextPos - startPos);
+ return true;
+}
+
+bool Parser::lexQName(String& name)
+{
+ String n1;
+ if (!lexNCName(n1))
+ return false;
+
+ skipWS();
+
+ // If the next character is :, what we just got it the prefix, if not,
+ // it's the whole thing.
+ if (peekAheadHelper() != ':') {
+ name = n1;
+ return true;
+ }
+
+ String n2;
+ if (!lexNCName(n2))
+ return false;
+
+ name = n1 + ":" + n2;
+ return true;
+}
+
+Token Parser::nextTokenInternal()
+{
+ skipWS();
+
+ if (m_nextPos >= m_data.length())
+ return Token(0);
+
+ char code = peekCurHelper();
+ switch (code) {
+ case '(': case ')': case '[': case ']':
+ case '@': case ',': case '|':
+ return makeTokenAndAdvance(code);
+ case '\'':
+ case '\"':
+ return lexString();
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return lexNumber();
+ case '.': {
+ char next = peekAheadHelper();
+ if (next == '.')
+ return makeTokenAndAdvance(DOTDOT, 2);
+ if (next >= '0' && next <= '9')
+ return lexNumber();
+ return makeTokenAndAdvance('.');
+ }
+ case '/':
+ if (peekAheadHelper() == '/')
+ return makeTokenAndAdvance(SLASHSLASH, 2);
+ return makeTokenAndAdvance('/');
+ case '+':
+ return makeTokenAndAdvance(PLUS);
+ case '-':
+ return makeTokenAndAdvance(MINUS);
+ case '=':
+ return makeTokenAndAdvance(EQOP, EqTestOp::OP_EQ);
+ case '!':
+ if (peekAheadHelper() == '=')
+ return makeTokenAndAdvance(EQOP, EqTestOp::OP_NE, 2);
+ return Token(XPATH_ERROR);
+ case '<':
+ if (peekAheadHelper() == '=')
+ return makeTokenAndAdvance(RELOP, EqTestOp::OP_LE, 2);
+ return makeTokenAndAdvance(RELOP, EqTestOp::OP_LT);
+ case '>':
+ if (peekAheadHelper() == '=')
+ return makeTokenAndAdvance(RELOP, EqTestOp::OP_GE, 2);
+ return makeTokenAndAdvance(RELOP, EqTestOp::OP_GT);
+ case '*':
+ if (isOperatorContext())
+ return makeTokenAndAdvance(MULOP, NumericOp::OP_Mul);
+ ++m_nextPos;
+ return Token(NAMETEST, "*");
+ case '$': { // $ QName
+ m_nextPos++;
+ String name;
+ if (!lexQName(name))
+ return Token(XPATH_ERROR);
+ return Token(VARIABLEREFERENCE, name);
+ }
+ }
+
+ String name;
+ if (!lexNCName(name))
+ return Token(XPATH_ERROR);
+
+ skipWS();
+ // If we're in an operator context, check for any operator names
+ if (isOperatorContext()) {
+ if (name == "and") //### hash?
+ return Token(AND);
+ if (name == "or")
+ return Token(OR);
+ if (name == "mod")
+ return Token(MULOP, NumericOp::OP_Mod);
+ if (name == "div")
+ return Token(MULOP, NumericOp::OP_Div);
+ }
+
+ // See whether we are at a :
+ if (peekCurHelper() == ':') {
+ m_nextPos++;
+ // Any chance it's an axis name?
+ if (peekCurHelper() == ':') {
+ m_nextPos++;
+
+ //It might be an axis name.
+ Step::Axis axis;
+ if (isAxisName(name, axis))
+ return Token(AXISNAME, axis);
+ // Ugh, :: is only valid in axis names -> error
+ return Token(XPATH_ERROR);
+ }
+
+ // Seems like this is a fully qualified qname, or perhaps the * modified one from NameTest
+ skipWS();
+ if (peekCurHelper() == '*') {
+ m_nextPos++;
+ return Token(NAMETEST, name + ":*");
+ }
+
+ // Make a full qname.
+ String n2;
+ if (!lexNCName(n2))
+ return Token(XPATH_ERROR);
+
+ name = name + ":" + n2;
+ }
+
+ skipWS();
+ if (peekCurHelper() == '(') {
+ //note: we don't swallow the (here!
+
+ //either node type of function name
+ if (isNodeTypeName(name)) {
+ if (name == "processing-instruction")
+ return Token(PI, name);
+
+ return Token(NODETYPE, name);
+ }
+ //must be a function name.
+ return Token(FUNCTIONNAME, name);
+ }
+
+ // At this point, it must be NAMETEST.
+ return Token(NAMETEST, name);
+}
+
+Token Parser::nextToken()
+{
+ Token toRet = nextTokenInternal();
+ m_lastTokenType = toRet.type;
+ return toRet;
+}
+
+Parser::Parser()
+{
+ reset(String());
+}
+
+void Parser::reset(const String& data)
+{
+ m_nextPos = 0;
+ m_data = data;
+ m_lastTokenType = 0;
+
+ m_topExpr = 0;
+ m_gotNamespaceError = false;
+}
+
+int Parser::lex(void* data)
+{
+ YYSTYPE* yylval = static_cast<YYSTYPE*>(data);
+ Token tok = nextToken();
+
+ switch (tok.type) {
+ case AXISNAME:
+ yylval->axis = tok.axis;
+ break;
+ case MULOP:
+ yylval->numop = tok.numop;
+ break;
+ case RELOP:
+ case EQOP:
+ yylval->eqop = tok.eqop;
+ break;
+ case NODETYPE:
+ case PI:
+ case FUNCTIONNAME:
+ case LITERAL:
+ case VARIABLEREFERENCE:
+ case NUMBER:
+ case NAMETEST:
+ yylval->str = new String(tok.str);
+ registerString(yylval->str);
+ break;
+ }
+
+ return tok.type;
+}
+
+bool Parser::expandQName(const String& qName, String& localName, String& namespaceURI)
+{
+ int colon = qName.find(':');
+ if (colon >= 0) {
+ if (!m_resolver)
+ return false;
+ namespaceURI = m_resolver->lookupNamespaceURI(qName.left(colon));
+ if (namespaceURI.isNull())
+ return false;
+ localName = qName.substring(colon + 1);
+ } else
+ localName = qName;
+
+ return true;
+}
+
+Expression* Parser::parseStatement(const String& statement, PassRefPtr<XPathNSResolver> resolver, ExceptionCode& ec)
+{
+ reset(statement);
+
+ m_resolver = resolver;
+
+ Parser* oldParser = currentParser;
+ currentParser = this;
+ int parseError = xpathyyparse(this);
+ currentParser = oldParser;
+
+ if (parseError) {
+ deleteAllValues(m_parseNodes);
+ m_parseNodes.clear();
+
+ HashSet<Vector<Predicate*>*>::iterator pend = m_predicateVectors.end();
+ for (HashSet<Vector<Predicate*>*>::iterator it = m_predicateVectors.begin(); it != pend; ++it) {
+ deleteAllValues(**it);
+ delete *it;
+ }
+ m_predicateVectors.clear();
+
+ HashSet<Vector<Expression*>*>::iterator eend = m_expressionVectors.end();
+ for (HashSet<Vector<Expression*>*>::iterator it = m_expressionVectors.begin(); it != eend; ++it) {
+ deleteAllValues(**it);
+ delete *it;
+ }
+ m_expressionVectors.clear();
+
+ deleteAllValues(m_strings);
+ m_strings.clear();
+
+ deleteAllValues(m_nodeTests);
+ m_nodeTests.clear();
+
+ m_topExpr = 0;
+
+ if (m_gotNamespaceError)
+ ec = NAMESPACE_ERR;
+ else
+ ec = XPathException::INVALID_EXPRESSION_ERR;
+ return 0;
+ }
+
+ ASSERT(m_parseNodes.size() == 1);
+ ASSERT(*m_parseNodes.begin() == m_topExpr);
+ ASSERT(m_expressionVectors.size() == 0);
+ ASSERT(m_predicateVectors.size() == 0);
+ ASSERT(m_strings.size() == 0);
+ ASSERT(m_nodeTests.size() == 0);
+
+ m_parseNodes.clear();
+ Expression* result = m_topExpr;
+ m_topExpr = 0;
+
+ return result;
+}
+
+void Parser::registerParseNode(ParseNode* node)
+{
+ if (node == 0)
+ return;
+
+ ASSERT(!m_parseNodes.contains(node));
+
+ m_parseNodes.add(node);
+}
+
+void Parser::unregisterParseNode(ParseNode* node)
+{
+ if (node == 0)
+ return;
+
+ ASSERT(m_parseNodes.contains(node));
+
+ m_parseNodes.remove(node);
+}
+
+void Parser::registerPredicateVector(Vector<Predicate*>* vector)
+{
+ if (vector == 0)
+ return;
+
+ ASSERT(!m_predicateVectors.contains(vector));
+
+ m_predicateVectors.add(vector);
+}
+
+void Parser::deletePredicateVector(Vector<Predicate*>* vector)
+{
+ if (vector == 0)
+ return;
+
+ ASSERT(m_predicateVectors.contains(vector));
+
+ m_predicateVectors.remove(vector);
+ delete vector;
+}
+
+
+void Parser::registerExpressionVector(Vector<Expression*>* vector)
+{
+ if (vector == 0)
+ return;
+
+ ASSERT(!m_expressionVectors.contains(vector));
+
+ m_expressionVectors.add(vector);
+}
+
+void Parser::deleteExpressionVector(Vector<Expression*>* vector)
+{
+ if (vector == 0)
+ return;
+
+ ASSERT(m_expressionVectors.contains(vector));
+
+ m_expressionVectors.remove(vector);
+ delete vector;
+}
+
+void Parser::registerString(String* s)
+{
+ if (s == 0)
+ return;
+
+ ASSERT(!m_strings.contains(s));
+
+ m_strings.add(s);
+}
+
+void Parser::deleteString(String* s)
+{
+ if (s == 0)
+ return;
+
+ ASSERT(m_strings.contains(s));
+
+ m_strings.remove(s);
+ delete s;
+}
+
+void Parser::registerNodeTest(Step::NodeTest* t)
+{
+ if (t == 0)
+ return;
+
+ ASSERT(!m_nodeTests.contains(t));
+
+ m_nodeTests.add(t);
+}
+
+void Parser::deleteNodeTest(Step::NodeTest* t)
+{
+ if (t == 0)
+ return;
+
+ ASSERT(m_nodeTests.contains(t));
+
+ m_nodeTests.remove(t);
+ delete t;
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathParser.h b/WebCore/xml/XPathParser.h
new file mode 100644
index 0000000..8d6da3f
--- /dev/null
+++ b/WebCore/xml/XPathParser.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2005 Maksim Orlovich <maksim@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathParser_h
+#define XPathParser_h
+
+#if ENABLE(XPATH)
+
+#include "XPathStep.h"
+#include "XPathPredicate.h"
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class XPathNSResolver;
+
+ namespace XPath {
+
+ class Expression;
+ class ParseNode;
+ class Predicate;
+
+ struct Token {
+ int type;
+ String str;
+ Step::Axis axis;
+ NumericOp::Opcode numop;
+ EqTestOp::Opcode eqop;
+
+ Token(int t) : type(t) {}
+ Token(int t, const String& v): type(t), str(v) {}
+ Token(int t, Step::Axis v): type(t), axis(v) {}
+ Token(int t, NumericOp::Opcode v): type(t), numop(v) {}
+ Token(int t, EqTestOp::Opcode v): type(t), eqop(v) {}
+ };
+
+ class Parser : Noncopyable {
+ public:
+ Parser();
+
+ XPathNSResolver* resolver() const { return m_resolver.get(); }
+ bool expandQName(const String& qName, String& localName, String& namespaceURI);
+
+ Expression* parseStatement(const String& statement, PassRefPtr<XPathNSResolver>, ExceptionCode&);
+
+ static Parser* current() { return currentParser; }
+
+ int lex(void* yylval);
+
+ Expression* m_topExpr;
+ bool m_gotNamespaceError;
+
+ void registerParseNode(ParseNode*);
+ void unregisterParseNode(ParseNode*);
+
+ void registerPredicateVector(Vector<Predicate*>*);
+ void deletePredicateVector(Vector<Predicate*>*);
+
+ void registerExpressionVector(Vector<Expression*>*);
+ void deleteExpressionVector(Vector<Expression*>*);
+
+ void registerString(String*);
+ void deleteString(String*);
+
+ void registerNodeTest(Step::NodeTest*);
+ void deleteNodeTest(Step::NodeTest*);
+
+ private:
+ bool isOperatorContext() const;
+
+ void skipWS();
+ Token makeTokenAndAdvance(int type, int advance = 1);
+ Token makeTokenAndAdvance(int type, NumericOp::Opcode, int advance = 1);
+ Token makeTokenAndAdvance(int type, EqTestOp::Opcode, int advance = 1);
+ char peekAheadHelper();
+ char peekCurHelper();
+
+ Token lexString();
+ Token lexNumber();
+ bool lexNCName(String&);
+ bool lexQName(String&);
+
+ Token nextToken();
+ Token nextTokenInternal();
+
+ void reset(const String& data);
+
+ static Parser* currentParser;
+
+ unsigned m_nextPos;
+ String m_data;
+ int m_lastTokenType;
+ RefPtr<XPathNSResolver> m_resolver;
+
+ HashSet<ParseNode*> m_parseNodes;
+ HashSet<Vector<Predicate*>*> m_predicateVectors;
+ HashSet<Vector<Expression*>*> m_expressionVectors;
+ HashSet<String*> m_strings;
+ HashSet<Step::NodeTest*> m_nodeTests;
+ };
+
+ }
+}
+
+#endif // ENABLE(XPATH)
+
+#endif
diff --git a/WebCore/xml/XPathPath.cpp b/WebCore/xml/XPathPath.cpp
new file mode 100644
index 0000000..bc7b153
--- /dev/null
+++ b/WebCore/xml/XPathPath.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathPath.h"
+
+#if ENABLE(XPATH)
+
+#include "Document.h"
+#include "XPathPredicate.h"
+#include "XPathStep.h"
+#include "XPathValue.h"
+
+namespace WebCore {
+namespace XPath {
+
+Filter::Filter(Expression* expr, const Vector<Predicate*>& predicates)
+ : m_expr(expr), m_predicates(predicates)
+{
+}
+
+Filter::~Filter()
+{
+ delete m_expr;
+ deleteAllValues(m_predicates);
+}
+
+Value Filter::evaluate() const
+{
+ Value v = m_expr->evaluate();
+
+ if (!v.isNodeSet())
+ return v;
+
+ NodeSet& nodes = v.modifiableNodeSet();
+ nodes.sort();
+
+ EvaluationContext& evaluationContext = Expression::evaluationContext();
+ for (unsigned i = 0; i < m_predicates.size(); i++) {
+ NodeSet newNodes;
+ evaluationContext.size = nodes.size();
+ evaluationContext.position = 0;
+
+ for (unsigned j = 0; j < nodes.size(); j++) {
+ Node* node = nodes[j];
+
+ evaluationContext.node = node;
+ ++evaluationContext.position;
+
+ if (m_predicates[i]->evaluate())
+ newNodes.append(node);
+ }
+ nodes.swap(newNodes);
+ }
+
+ return v;
+}
+
+LocationPath::LocationPath()
+ : m_absolute(false)
+{
+}
+
+LocationPath::~LocationPath()
+{
+ deleteAllValues(m_steps);
+}
+
+Value LocationPath::evaluate() const
+{
+ EvaluationContext& evaluationContext = Expression::evaluationContext();
+ EvaluationContext backupContext = evaluationContext;
+ /* For absolute location paths, the context node is ignored - the
+ * document's root node is used instead.
+ */
+ Node* context = evaluationContext.node.get();
+ if (m_absolute && context->nodeType() != Node::DOCUMENT_NODE)
+ context = context->ownerDocument();
+
+ NodeSet nodes;
+ nodes.append(context);
+ evaluate(nodes);
+
+ evaluationContext = backupContext;
+ return Value(nodes, Value::adopt);
+}
+
+void LocationPath::evaluate(NodeSet& nodes) const
+{
+ for (unsigned i = 0; i < m_steps.size(); i++) {
+ Step* step = m_steps[i];
+ NodeSet newNodes;
+ HashSet<Node*> newNodesSet;
+
+ for (unsigned j = 0; j < nodes.size(); j++) {
+ NodeSet matches;
+ step->evaluate(nodes[j], matches);
+
+ for (size_t nodeIndex = 0; nodeIndex < matches.size(); ++nodeIndex) {
+ Node* node = matches[nodeIndex];
+ if (newNodesSet.add(node).second)
+ newNodes.append(node);
+ }
+ }
+
+ nodes.swap(newNodes);
+ }
+
+ nodes.markSorted(false);
+}
+
+void LocationPath::optimizeStepPair(unsigned index)
+{
+ Step* first = m_steps[index];
+
+ if (first->axis() == Step::DescendantOrSelfAxis
+ && first->nodeTest().kind() == Step::NodeTest::AnyNodeTest
+ && first->predicates().size() == 0) {
+
+ Step* second = m_steps[index + 1];
+ if (second->axis() == Step::ChildAxis
+ && second->nodeTest().namespaceURI().isEmpty()
+ && second->nodeTest().kind() == Step::NodeTest::NameTest
+ && second->nodeTest().data() == "*") {
+
+ // Optimize the common case of "//*" AKA descendant-or-self::node()/child::*.
+ first->setAxis(Step::DescendantAxis);
+ second->setAxis(Step::SelfAxis);
+ second->setNodeTest(Step::NodeTest::ElementNodeTest);
+ ASSERT(second->nodeTest().data().isEmpty());
+ }
+ }
+}
+
+void LocationPath::appendStep(Step* step)
+{
+ m_steps.append(step);
+
+ unsigned stepCount = m_steps.size();
+ if (stepCount > 1)
+ optimizeStepPair(stepCount - 2);
+}
+
+void LocationPath::insertFirstStep(Step* step)
+{
+ m_steps.insert(0, step);
+
+ if (m_steps.size() > 1)
+ optimizeStepPair(0);
+}
+
+Path::Path(Filter* filter, LocationPath* path)
+ : m_filter(filter),
+ m_path(path)
+{
+}
+
+Path::~Path()
+{
+ delete m_filter;
+ delete m_path;
+}
+
+Value Path::evaluate() const
+{
+ Value v = m_filter->evaluate();
+
+ NodeSet& nodes = v.modifiableNodeSet();
+ m_path->evaluate(nodes);
+
+ return v;
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathPath.h b/WebCore/xml/XPathPath.h
new file mode 100644
index 0000000..97692b2
--- /dev/null
+++ b/WebCore/xml/XPathPath.h
@@ -0,0 +1,93 @@
+/*
+ * path.h - Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathPath_h
+#define XPathPath_h
+
+#if ENABLE(XPATH)
+
+#include "XPathExpressionNode.h"
+#include "XPathNodeSet.h"
+
+int xpathyyparse(void*);
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class Predicate;
+ class Step;
+
+ class Filter : public Expression {
+ public:
+ Filter(Expression*, const Vector<Predicate*>& = Vector<Predicate*>());
+ virtual ~Filter();
+
+ virtual Value evaluate() const;
+
+ private:
+ Expression* m_expr;
+ Vector<Predicate*> m_predicates;
+ };
+
+ class LocationPath : public Expression {
+ public:
+ LocationPath();
+ virtual ~LocationPath();
+ void setAbsolute(bool value) { m_absolute = value; }
+
+ virtual Value evaluate() const;
+ void evaluate(NodeSet& nodes) const; // nodes is an input/output parameter
+
+ void appendStep(Step* step);
+ void insertFirstStep(Step* step);
+
+ private:
+ void optimizeStepPair(unsigned index);
+
+ Vector<Step*> m_steps;
+ bool m_absolute;
+ };
+
+ class Path : public Expression
+ {
+ public:
+ Path(Filter*, LocationPath*);
+ virtual ~Path();
+
+ virtual Value evaluate() const;
+
+ private:
+ Filter* m_filter;
+ LocationPath* m_path;
+ };
+
+ }
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPath_Path_H
diff --git a/WebCore/xml/XPathPredicate.cpp b/WebCore/xml/XPathPredicate.cpp
new file mode 100644
index 0000000..7b3e4d8
--- /dev/null
+++ b/WebCore/xml/XPathPredicate.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(XPATH)
+
+#include "XPathPredicate.h"
+
+#include "Node.h"
+#include "XPathFunctions.h"
+#include "XPathUtil.h"
+#include "XPathValue.h"
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+namespace XPath {
+
+Number::Number(double value)
+ : m_value(value)
+{
+}
+
+Value Number::evaluate() const
+{
+ return m_value;
+}
+
+StringExpression::StringExpression(const String& value)
+ : m_value(value)
+{
+}
+
+Value StringExpression::evaluate() const
+{
+ return m_value;
+}
+
+Value Negative::evaluate() const
+{
+ Value p(subExpr(0)->evaluate());
+ return -p.toNumber();
+}
+
+NumericOp::NumericOp(Opcode opcode, Expression* lhs, Expression* rhs)
+ : m_opcode(opcode)
+{
+ addSubExpression(lhs);
+ addSubExpression(rhs);
+}
+
+Value NumericOp::evaluate() const
+{
+ Value lhs(subExpr(0)->evaluate());
+ Value rhs(subExpr(1)->evaluate());
+
+ double leftVal = lhs.toNumber();
+ double rightVal = rhs.toNumber();
+
+ switch (m_opcode) {
+ case OP_Add:
+ return leftVal + rightVal;
+ case OP_Sub:
+ return leftVal - rightVal;
+ case OP_Mul:
+ return leftVal * rightVal;
+ case OP_Div:
+ return leftVal / rightVal;
+ case OP_Mod:
+ return fmod(leftVal, rightVal);
+ }
+ ASSERT_NOT_REACHED();
+ return 0.0;
+}
+
+EqTestOp::EqTestOp(Opcode opcode, Expression* lhs, Expression* rhs)
+ : m_opcode(opcode)
+{
+ addSubExpression(lhs);
+ addSubExpression(rhs);
+}
+
+bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
+{
+ if (lhs.isNodeSet()) {
+ const NodeSet& lhsSet = lhs.toNodeSet();
+ if (rhs.isNodeSet()) {
+ // If both objects to be compared are node-sets, then the comparison will be true if and only if
+ // there is a node in the first node-set and a node in the second node-set such that the result of
+ // performing the comparison on the string-values of the two nodes is true.
+ const NodeSet& rhsSet = rhs.toNodeSet();
+ for (unsigned lindex = 0; lindex < lhsSet.size(); ++lindex)
+ for (unsigned rindex = 0; rindex < rhsSet.size(); ++rindex)
+ if (compare(stringValue(lhsSet[lindex]), stringValue(rhsSet[rindex])))
+ return true;
+ return false;
+ }
+ if (rhs.isNumber()) {
+ // If one object to be compared is a node-set and the other is a number, then the comparison will be true
+ // if and only if there is a node in the node-set such that the result of performing the comparison on the number
+ // to be compared and on the result of converting the string-value of that node to a number using the number function is true.
+ for (unsigned lindex = 0; lindex < lhsSet.size(); ++lindex)
+ if (compare(Value(stringValue(lhsSet[lindex])).toNumber(), rhs))
+ return true;
+ return false;
+ }
+ if (rhs.isString()) {
+ // If one object to be compared is a node-set and the other is a string, then the comparison will be true
+ // if and only if there is a node in the node-set such that the result of performing the comparison on
+ // the string-value of the node and the other string is true.
+ for (unsigned lindex = 0; lindex < lhsSet.size(); ++lindex)
+ if (compare(stringValue(lhsSet[lindex]), rhs))
+ return true;
+ return false;
+ }
+ if (rhs.isBoolean()) {
+ // If one object to be compared is a node-set and the other is a boolean, then the comparison will be true
+ // if and only if the result of performing the comparison on the boolean and on the result of converting
+ // the node-set to a boolean using the boolean function is true.
+ return compare(lhs.toBoolean(), rhs);
+ }
+ ASSERT(0);
+ }
+ if (rhs.isNodeSet()) {
+ const NodeSet& rhsSet = rhs.toNodeSet();
+ if (lhs.isNumber()) {
+ for (unsigned rindex = 0; rindex < rhsSet.size(); ++rindex)
+ if (compare(lhs, Value(stringValue(rhsSet[rindex])).toNumber()))
+ return true;
+ return false;
+ }
+ if (lhs.isString()) {
+ for (unsigned rindex = 0; rindex < rhsSet.size(); ++rindex)
+ if (compare(lhs, stringValue(rhsSet[rindex])))
+ return true;
+ return false;
+ }
+ if (lhs.isBoolean())
+ return compare(lhs, rhs.toBoolean());
+ ASSERT(0);
+ }
+
+ // Neither side is a NodeSet.
+ switch (m_opcode) {
+ case OP_EQ:
+ case OP_NE:
+ bool equal;
+ if (lhs.isBoolean() || rhs.isBoolean())
+ equal = lhs.toBoolean() == rhs.toBoolean();
+ else if (lhs.isNumber() || rhs.isNumber())
+ equal = lhs.toNumber() == rhs.toNumber();
+ else
+ equal = lhs.toString() == rhs.toString();
+
+ if (m_opcode == OP_EQ)
+ return equal;
+ return !equal;
+ case OP_GT:
+ return lhs.toNumber() > rhs.toNumber();
+ case OP_GE:
+ return lhs.toNumber() >= rhs.toNumber();
+ case OP_LT:
+ return lhs.toNumber() < rhs.toNumber();
+ case OP_LE:
+ return lhs.toNumber() <= rhs.toNumber();
+ }
+ ASSERT(0);
+ return false;
+}
+
+Value EqTestOp::evaluate() const
+{
+ Value lhs(subExpr(0)->evaluate());
+ Value rhs(subExpr(1)->evaluate());
+
+ return compare(lhs, rhs);
+}
+
+LogicalOp::LogicalOp(Opcode opcode, Expression* lhs, Expression* rhs)
+ : m_opcode(opcode)
+{
+ addSubExpression(lhs);
+ addSubExpression(rhs);
+}
+
+bool LogicalOp::shortCircuitOn() const
+{
+ if (m_opcode == OP_And)
+ return false; //false and foo
+
+ return true; //true or bar
+}
+
+Value LogicalOp::evaluate() const
+{
+ Value lhs(subExpr(0)->evaluate());
+
+ // This is not only an optimization, http://www.w3.org/TR/xpath
+ // dictates that we must do short-circuit evaluation
+ bool lhsBool = lhs.toBoolean();
+ if (lhsBool == shortCircuitOn())
+ return lhsBool;
+
+ return subExpr(1)->evaluate().toBoolean();
+}
+
+Value Union::evaluate() const
+{
+ Value lhsResult = subExpr(0)->evaluate();
+ Value rhs = subExpr(1)->evaluate();
+ if (!lhsResult.isNodeSet() || !rhs.isNodeSet())
+ return NodeSet();
+
+ NodeSet& resultSet = lhsResult.modifiableNodeSet();
+ const NodeSet& rhsNodes = rhs.toNodeSet();
+
+ HashSet<Node*> nodes;
+ for (size_t i = 0; i < resultSet.size(); ++i)
+ nodes.add(resultSet[i]);
+
+ for (size_t i = 0; i < rhsNodes.size(); ++i) {
+ Node* node = rhsNodes[i];
+ if (nodes.add(node).second)
+ resultSet.append(node);
+ }
+
+ // It is also possible to use merge sort to avoid making the result unsorted;
+ // but this would waste the time in cases when order is not important.
+ resultSet.markSorted(false);
+ return lhsResult;
+}
+
+Predicate::Predicate(Expression* expr)
+ : m_expr(expr)
+{
+}
+
+Predicate::~Predicate()
+{
+ delete m_expr;
+}
+
+bool Predicate::evaluate() const
+{
+ ASSERT(m_expr != 0);
+
+ Value result(m_expr->evaluate());
+
+ // foo[3] means foo[position()=3]
+ if (result.isNumber())
+ return EqTestOp(EqTestOp::OP_EQ, createFunction("position"), new Number(result.toNumber())).evaluate().toBoolean();
+
+ return result.toBoolean();
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathPredicate.h b/WebCore/xml/XPathPredicate.h
new file mode 100644
index 0000000..8d1b0d8
--- /dev/null
+++ b/WebCore/xml/XPathPredicate.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathPredicate_h
+#define XPathPredicate_h
+
+#if ENABLE(XPATH)
+
+#include "XPathExpressionNode.h"
+#include "XPathValue.h"
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class Number : public Expression {
+ public:
+ Number(double);
+ private:
+ virtual Value evaluate() const;
+ Value m_value;
+ };
+
+ class StringExpression : public Expression {
+ public:
+ StringExpression(const String&);
+ private:
+ virtual Value evaluate() const;
+ Value m_value;
+ };
+
+ class Negative : public Expression {
+ private:
+ virtual Value evaluate() const;
+ };
+
+ class NumericOp : public Expression {
+ public:
+ enum Opcode {
+ OP_Add, OP_Sub, OP_Mul, OP_Div, OP_Mod
+ };
+ NumericOp(Opcode, Expression* lhs, Expression* rhs);
+ private:
+ virtual Value evaluate() const;
+ Opcode m_opcode;
+ };
+
+ class EqTestOp : public Expression {
+ public:
+ enum Opcode { OP_EQ, OP_NE, OP_GT, OP_LT, OP_GE, OP_LE };
+ EqTestOp(Opcode, Expression* lhs, Expression* rhs);
+ virtual Value evaluate() const;
+ private:
+ bool compare(const Value&, const Value&) const;
+ Opcode m_opcode;
+ };
+
+ class LogicalOp : public Expression {
+ public:
+ enum Opcode { OP_And, OP_Or };
+ LogicalOp(Opcode, Expression* lhs, Expression* rhs);
+ private:
+ bool shortCircuitOn() const;
+ virtual Value evaluate() const;
+ Opcode m_opcode;
+ };
+
+ class Union : public Expression {
+ private:
+ virtual Value evaluate() const;
+ };
+
+ class Predicate : Noncopyable {
+ public:
+ Predicate(Expression*);
+ ~Predicate();
+ bool evaluate() const;
+ private:
+ Expression* m_expr;
+ };
+
+ }
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathPredicate_h
diff --git a/WebCore/xml/XPathResult.cpp b/WebCore/xml/XPathResult.cpp
new file mode 100644
index 0000000..285350e
--- /dev/null
+++ b/WebCore/xml/XPathResult.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathResult.h"
+
+#if ENABLE(XPATH)
+
+#include "EventListener.h"
+#include "EventNames.h"
+#include "EventTargetNode.h"
+#include "ExceptionCode.h"
+#include "XPathEvaluator.h"
+#include "XPathException.h"
+
+namespace WebCore {
+
+using namespace XPath;
+
+class InvalidatingEventListener : public EventListener {
+public:
+ static PassRefPtr<InvalidatingEventListener> create(XPathResult* result) { return adoptRef(new InvalidatingEventListener(result)); }
+ virtual void handleEvent(Event*, bool) { m_result->invalidateIteratorState(); }
+
+private:
+ InvalidatingEventListener(XPathResult* result) : m_result(result) { }
+ XPathResult* m_result;
+};
+
+XPathResult::XPathResult(EventTargetNode* eventTarget, const Value& value)
+ : m_value(value)
+ , m_eventTarget(eventTarget)
+{
+ m_eventListener = InvalidatingEventListener::create(this);
+ m_eventTarget->addEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener, false);
+ switch (m_value.type()) {
+ case Value::BooleanValue:
+ m_resultType = BOOLEAN_TYPE;
+ return;
+ case Value::NumberValue:
+ m_resultType = NUMBER_TYPE;
+ return;
+ case Value::StringValue:
+ m_resultType = STRING_TYPE;
+ return;
+ case Value::NodeSetValue:
+ m_resultType = UNORDERED_NODE_ITERATOR_TYPE;
+ m_nodeSetPosition = 0;
+ m_nodeSet = m_value.toNodeSet();
+ m_invalidIteratorState = false;
+ return;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+XPathResult::~XPathResult()
+{
+ if (m_eventTarget)
+ m_eventTarget->removeEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener.get(), false);
+}
+
+void XPathResult::convertTo(unsigned short type, ExceptionCode& ec)
+{
+ switch (type) {
+ case ANY_TYPE:
+ break;
+ case NUMBER_TYPE:
+ m_resultType = type;
+ m_value = m_value.toNumber();
+ break;
+ case STRING_TYPE:
+ m_resultType = type;
+ m_value = m_value.toString();
+ break;
+ case BOOLEAN_TYPE:
+ m_resultType = type;
+ m_value = m_value.toBoolean();
+ break;
+ case UNORDERED_NODE_ITERATOR_TYPE:
+ case UNORDERED_NODE_SNAPSHOT_TYPE:
+ case ANY_UNORDERED_NODE_TYPE:
+ case FIRST_ORDERED_NODE_TYPE: // This is correct - singleNodeValue() will take care of ordering.
+ if (!m_value.isNodeSet()) {
+ ec = XPathException::TYPE_ERR;
+ return;
+ }
+ m_resultType = type;
+ break;
+ case ORDERED_NODE_ITERATOR_TYPE:
+ if (!m_value.isNodeSet()) {
+ ec = XPathException::TYPE_ERR;
+ return;
+ }
+ m_nodeSet.sort();
+ m_resultType = type;
+ break;
+ case ORDERED_NODE_SNAPSHOT_TYPE:
+ if (!m_value.isNodeSet()) {
+ ec = XPathException::TYPE_ERR;
+ return;
+ }
+ m_value.toNodeSet().sort();
+ m_resultType = type;
+ break;
+ }
+}
+
+unsigned short XPathResult::resultType() const
+{
+ return m_resultType;
+}
+
+double XPathResult::numberValue(ExceptionCode& ec) const
+{
+ if (resultType() != NUMBER_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return 0.0;
+ }
+ return m_value.toNumber();
+}
+
+String XPathResult::stringValue(ExceptionCode& ec) const
+{
+ if (resultType() != STRING_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return String();
+ }
+ return m_value.toString();
+}
+
+bool XPathResult::booleanValue(ExceptionCode& ec) const
+{
+ if (resultType() != BOOLEAN_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return false;
+ }
+ return m_value.toBoolean();
+}
+
+Node* XPathResult::singleNodeValue(ExceptionCode& ec) const
+{
+ if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return 0;
+ }
+
+ const NodeSet& nodes = m_value.toNodeSet();
+ if (resultType() == FIRST_ORDERED_NODE_TYPE)
+ return nodes.firstNode();
+ else
+ return nodes.anyNode();
+}
+
+void XPathResult::invalidateIteratorState()
+{
+ m_invalidIteratorState = true;
+
+ ASSERT(m_eventTarget);
+ ASSERT(m_eventListener);
+
+ m_eventTarget->removeEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener.get(), false);
+
+ m_eventTarget = 0;
+}
+
+bool XPathResult::invalidIteratorState() const
+{
+ if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE)
+ return false;
+
+ return m_invalidIteratorState;
+}
+
+unsigned long XPathResult::snapshotLength(ExceptionCode& ec) const
+{
+ if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return 0;
+ }
+
+ return m_value.toNodeSet().size();
+}
+
+Node* XPathResult::iterateNext(ExceptionCode& ec)
+{
+ if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return 0;
+ }
+
+ if (m_invalidIteratorState) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ if (m_nodeSetPosition + 1 > m_nodeSet.size())
+ return 0;
+
+ Node* node = m_nodeSet[m_nodeSetPosition];
+
+ m_nodeSetPosition++;
+
+ return node;
+}
+
+Node* XPathResult::snapshotItem(unsigned long index, ExceptionCode& ec)
+{
+ if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
+ ec = XPathException::TYPE_ERR;
+ return 0;
+ }
+
+ const NodeSet& nodes = m_value.toNodeSet();
+ if (index >= nodes.size())
+ return 0;
+
+ return nodes[index];
+}
+
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathResult.h b/WebCore/xml/XPathResult.h
new file mode 100644
index 0000000..ecd5cac
--- /dev/null
+++ b/WebCore/xml/XPathResult.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathResult_h
+#define XPathResult_h
+
+#if ENABLE(XPATH)
+
+#include <wtf/RefCounted.h>
+#include "XPathValue.h"
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class EventListener;
+ class EventTargetNode;
+ class Node;
+ class String;
+
+ class XPathResult : public RefCounted<XPathResult> {
+ public:
+ enum XPathResultType {
+ ANY_TYPE = 0,
+ NUMBER_TYPE = 1,
+ STRING_TYPE = 2,
+ BOOLEAN_TYPE = 3,
+ UNORDERED_NODE_ITERATOR_TYPE = 4,
+ ORDERED_NODE_ITERATOR_TYPE = 5,
+ UNORDERED_NODE_SNAPSHOT_TYPE = 6,
+ ORDERED_NODE_SNAPSHOT_TYPE = 7,
+ ANY_UNORDERED_NODE_TYPE = 8,
+ FIRST_ORDERED_NODE_TYPE = 9
+ };
+
+ static PassRefPtr<XPathResult> create(EventTargetNode* eventTarget, const XPath::Value& value) { return adoptRef(new XPathResult(eventTarget, value)); }
+ ~XPathResult();
+
+ void convertTo(unsigned short type, ExceptionCode&);
+
+ unsigned short resultType() const;
+
+ double numberValue(ExceptionCode&) const;
+ String stringValue(ExceptionCode&) const;
+ bool booleanValue(ExceptionCode&) const;
+ Node* singleNodeValue(ExceptionCode&) const;
+
+ bool invalidIteratorState() const;
+ unsigned long snapshotLength(ExceptionCode&) const;
+ Node* iterateNext(ExceptionCode&);
+ Node* snapshotItem(unsigned long index, ExceptionCode&);
+
+ void invalidateIteratorState();
+
+ private:
+ XPathResult(EventTargetNode*, const XPath::Value&);
+
+ XPath::Value m_value;
+ unsigned m_nodeSetPosition;
+ XPath::NodeSet m_nodeSet; // FIXME: why duplicate the node set stored in m_value?
+ unsigned short m_resultType;
+ bool m_invalidIteratorState;
+ RefPtr<EventTargetNode> m_eventTarget;
+ RefPtr<EventListener> m_eventListener;
+ };
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPathResult_h
diff --git a/WebCore/xml/XPathResult.idl b/WebCore/xml/XPathResult.idl
new file mode 100644
index 0000000..bc36c3e
--- /dev/null
+++ b/WebCore/xml/XPathResult.idl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module xpath {
+
+ interface [GenerateConstructor, Conditional=XPATH] XPathResult {
+ const unsigned short ANY_TYPE = 0;
+ const unsigned short NUMBER_TYPE = 1;
+ const unsigned short STRING_TYPE = 2;
+ const unsigned short BOOLEAN_TYPE = 3;
+ const unsigned short UNORDERED_NODE_ITERATOR_TYPE = 4;
+ const unsigned short ORDERED_NODE_ITERATOR_TYPE = 5;
+ const unsigned short UNORDERED_NODE_SNAPSHOT_TYPE = 6;
+ const unsigned short ORDERED_NODE_SNAPSHOT_TYPE = 7;
+ const unsigned short ANY_UNORDERED_NODE_TYPE = 8;
+ const unsigned short FIRST_ORDERED_NODE_TYPE = 9;
+
+ readonly attribute unsigned short resultType;
+ readonly attribute double numberValue
+ getter raises (DOMException);
+
+ readonly attribute DOMString stringValue
+ getter raises (DOMException);
+
+ readonly attribute boolean booleanValue
+ getter raises (DOMException);
+
+ readonly attribute Node singleNodeValue
+ getter raises (DOMException);
+
+ readonly attribute boolean invalidIteratorState;
+ readonly attribute unsigned long snapshotLength
+ getter raises (DOMException);
+
+ Node iterateNext()
+ raises (DOMException);
+ Node snapshotItem(in unsigned long index)
+ raises (DOMException);
+ };
+
+}
diff --git a/WebCore/xml/XPathStep.cpp b/WebCore/xml/XPathStep.cpp
new file mode 100644
index 0000000..abdcba5
--- /dev/null
+++ b/WebCore/xml/XPathStep.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathStep.h"
+
+#if ENABLE(XPATH)
+
+#include "Document.h"
+#include "Element.h"
+#include "NamedAttrMap.h"
+#include "XPathNSResolver.h"
+#include "XPathParser.h"
+#include "XPathUtil.h"
+
+namespace WebCore {
+namespace XPath {
+
+Step::Step(Axis axis, const NodeTest& nodeTest, const Vector<Predicate*>& predicates)
+ : m_axis(axis)
+ , m_nodeTest(nodeTest)
+ , m_predicates(predicates)
+{
+}
+
+Step::~Step()
+{
+ deleteAllValues(m_predicates);
+}
+
+void Step::evaluate(Node* context, NodeSet& nodes) const
+{
+ nodesInAxis(context, nodes);
+
+ EvaluationContext& evaluationContext = Expression::evaluationContext();
+
+ for (unsigned i = 0; i < m_predicates.size(); i++) {
+ Predicate* predicate = m_predicates[i];
+
+ NodeSet newNodes;
+ if (!nodes.isSorted())
+ newNodes.markSorted(false);
+
+ for (unsigned j = 0; j < nodes.size(); j++) {
+ Node* node = nodes[j];
+
+ Expression::evaluationContext().node = node;
+ evaluationContext.size = nodes.size();
+ evaluationContext.position = j + 1;
+ if (predicate->evaluate())
+ newNodes.append(node);
+ }
+
+ nodes.swap(newNodes);
+ }
+}
+
+void Step::nodesInAxis(Node* context, NodeSet& nodes) const
+{
+ ASSERT(nodes.isEmpty());
+ switch (m_axis) {
+ case ChildAxis:
+ if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
+ return;
+
+ for (Node* n = context->firstChild(); n; n = n->nextSibling())
+ if (nodeMatches(n))
+ nodes.append(n);
+ return;
+ case DescendantAxis:
+ if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
+ return;
+
+ for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
+ if (nodeMatches(n))
+ nodes.append(n);
+ return;
+ case ParentAxis:
+ if (context->isAttributeNode()) {
+ Node* n = static_cast<Attr*>(context)->ownerElement();
+ if (nodeMatches(n))
+ nodes.append(n);
+ } else {
+ Node* n = context->parentNode();
+ if (n && nodeMatches(n))
+ nodes.append(n);
+ }
+ return;
+ case AncestorAxis: {
+ Node* n = context;
+ if (context->isAttributeNode()) {
+ n = static_cast<Attr*>(context)->ownerElement();
+ if (nodeMatches(n))
+ nodes.append(n);
+ }
+ for (n = n->parentNode(); n; n = n->parentNode())
+ if (nodeMatches(n))
+ nodes.append(n);
+ nodes.markSorted(false);
+ return;
+ }
+ case FollowingSiblingAxis:
+ if (context->nodeType() == Node::ATTRIBUTE_NODE ||
+ context->nodeType() == Node::XPATH_NAMESPACE_NODE)
+ return;
+
+ for (Node* n = context->nextSibling(); n; n = n->nextSibling())
+ if (nodeMatches(n))
+ nodes.append(n);
+ return;
+ case PrecedingSiblingAxis:
+ if (context->nodeType() == Node::ATTRIBUTE_NODE ||
+ context->nodeType() == Node::XPATH_NAMESPACE_NODE)
+ return;
+
+ for (Node* n = context->previousSibling(); n; n = n->previousSibling())
+ if (nodeMatches(n))
+ nodes.append(n);
+
+ nodes.markSorted(false);
+ return;
+ case FollowingAxis:
+ if (context->isAttributeNode()) {
+ Node* p = static_cast<Attr*>(context)->ownerElement();
+ while ((p = p->traverseNextNode()))
+ if (nodeMatches(p))
+ nodes.append(p);
+ } else {
+ for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
+ for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
+ if (nodeMatches(n))
+ nodes.append(n);
+ for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
+ if (nodeMatches(c))
+ nodes.append(c);
+ }
+ }
+ }
+ return;
+ case PrecedingAxis: {
+ if (context->isAttributeNode())
+ context = static_cast<Attr*>(context)->ownerElement();
+
+ Node* n = context;
+ while (Node* parent = n->parent()) {
+ for (n = n->traversePreviousNode(); n != parent; n = n->traversePreviousNode())
+ if (nodeMatches(n))
+ nodes.append(n);
+ n = parent;
+ }
+ nodes.markSorted(false);
+ return;
+ }
+ case AttributeAxis: {
+ if (context->nodeType() != Node::ELEMENT_NODE)
+ return;
+
+ // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
+ if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != "*") {
+ RefPtr<Node> n = static_cast<Element*>(context)->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
+ if (n && n->namespaceURI() != "http://www.w3.org/2000/xmlns/") // In XPath land, namespace nodes are not accessible on the attribute axis.
+ nodes.append(n.release());
+ return;
+ }
+
+ NamedAttrMap* attrs = context->attributes();
+ if (!attrs)
+ return;
+
+ for (unsigned long i = 0; i < attrs->length(); ++i) {
+ RefPtr<Node> n = attrs->item(i);
+ if (nodeMatches(n.get()))
+ nodes.append(n.release());
+ }
+ return;
+ }
+ case NamespaceAxis:
+ // XPath namespace nodes are not implemented yet.
+ return;
+ case SelfAxis:
+ if (nodeMatches(context))
+ nodes.append(context);
+ return;
+ case DescendantOrSelfAxis:
+ if (nodeMatches(context))
+ nodes.append(context);
+ if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
+ return;
+
+ for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
+ if (nodeMatches(n))
+ nodes.append(n);
+ return;
+ case AncestorOrSelfAxis: {
+ if (nodeMatches(context))
+ nodes.append(context);
+ Node* n = context;
+ if (context->isAttributeNode()) {
+ n = static_cast<Attr*>(context)->ownerElement();
+ if (nodeMatches(n))
+ nodes.append(n);
+ }
+ for (n = n->parentNode(); n; n = n->parentNode())
+ if (nodeMatches(n))
+ nodes.append(n);
+
+ nodes.markSorted(false);
+ return;
+ }
+ }
+ ASSERT_NOT_REACHED();
+}
+
+
+bool Step::nodeMatches(Node* node) const
+{
+ switch (m_nodeTest.kind()) {
+ case NodeTest::TextNodeTest:
+ return node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE;
+ case NodeTest::CommentNodeTest:
+ return node->nodeType() == Node::COMMENT_NODE;
+ case NodeTest::ProcessingInstructionNodeTest: {
+ const String& name = m_nodeTest.data();
+ return node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node->nodeName() == name);
+ }
+ case NodeTest::ElementNodeTest:
+ return node->isElementNode();
+ case NodeTest::AnyNodeTest:
+ return true;
+ case NodeTest::NameTest: {
+ const String& name = m_nodeTest.data();
+ const String& namespaceURI = m_nodeTest.namespaceURI();
+
+ if (m_axis == AttributeAxis) {
+ ASSERT(node->isAttributeNode());
+
+ // In XPath land, namespace nodes are not accessible on the attribute axis.
+ if (node->namespaceURI() == "http://www.w3.org/2000/xmlns/")
+ return false;
+
+ if (name == "*")
+ return namespaceURI.isEmpty() || node->namespaceURI() == namespaceURI;
+
+ return node->localName() == name && node->namespaceURI() == namespaceURI;
+ }
+
+ if (m_axis == NamespaceAxis) {
+ // Node test on the namespace axis is not implemented yet
+ return false;
+ }
+
+ if (name == "*")
+ return node->nodeType() == primaryNodeType(m_axis) && (namespaceURI.isEmpty() || namespaceURI == node->namespaceURI());
+
+ // We use tagQName here because we don't want the element name in uppercase
+ // like we get with HTML elements.
+ // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace.
+ return node->nodeType() == Node::ELEMENT_NODE
+ && static_cast<Element*>(node)->tagQName().localName() == name
+ && ((node->isHTMLElement() && node->document()->isHTMLDocument() && namespaceURI.isNull()) || namespaceURI == node->namespaceURI());
+ }
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+Node::NodeType Step::primaryNodeType(Axis axis) const
+{
+ switch (axis) {
+ case AttributeAxis:
+ return Node::ATTRIBUTE_NODE;
+ case NamespaceAxis:
+ return Node::XPATH_NAMESPACE_NODE;
+ default:
+ return Node::ELEMENT_NODE;
+ }
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathStep.h b/WebCore/xml/XPathStep.h
new file mode 100644
index 0000000..f1420d0
--- /dev/null
+++ b/WebCore/xml/XPathStep.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathStep_h
+#define XPathStep_h
+
+#if ENABLE(XPATH)
+
+#include "Node.h"
+#include "XPathExpressionNode.h"
+#include "XPathNodeSet.h"
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class Predicate;
+
+ class Step : public ParseNode, Noncopyable {
+ public:
+ enum Axis {
+ AncestorAxis, AncestorOrSelfAxis, AttributeAxis,
+ ChildAxis, DescendantAxis, DescendantOrSelfAxis,
+ FollowingAxis, FollowingSiblingAxis, NamespaceAxis,
+ ParentAxis, PrecedingAxis, PrecedingSiblingAxis,
+ SelfAxis
+ };
+
+ class NodeTest {
+ public:
+ enum Kind {
+ TextNodeTest, CommentNodeTest, ProcessingInstructionNodeTest, AnyNodeTest, NameTest,
+ ElementNodeTest // XPath 2.0
+ };
+
+ NodeTest(Kind kind) : m_kind(kind) {}
+ NodeTest(Kind kind, const String& data) : m_kind(kind), m_data(data) {}
+ NodeTest(Kind kind, const String& data, const String& namespaceURI) : m_kind(kind), m_data(data), m_namespaceURI(namespaceURI) {}
+
+ Kind kind() const { return m_kind; }
+ const String data() const { return m_data; }
+ const String namespaceURI() const { return m_namespaceURI; }
+
+ private:
+ Kind m_kind;
+ String m_data;
+ String m_namespaceURI;
+ };
+
+ Step(Axis, const NodeTest& nodeTest, const Vector<Predicate*>& predicates = Vector<Predicate*>());
+ ~Step();
+
+ void evaluate(Node* context, NodeSet&) const;
+
+ Axis axis() const { return m_axis; }
+ NodeTest nodeTest() const { return m_nodeTest; }
+ const Vector<Predicate*>& predicates() const { return m_predicates; }
+
+ void setAxis(Axis axis) { m_axis = axis; }
+ void setNodeTest(NodeTest nodeTest) { m_nodeTest = nodeTest; }
+ void setPredicates(const Vector<Predicate*>& predicates) { m_predicates = predicates; }
+
+ private:
+ void parseNodeTest(const String&);
+ void nodesInAxis(Node* context, NodeSet&) const;
+ bool nodeMatches(Node*) const;
+ String namespaceFromNodetest(const String& nodeTest) const;
+ Node::NodeType primaryNodeType(Axis) const;
+
+ Axis m_axis;
+ NodeTest m_nodeTest;
+ Vector<Predicate*> m_predicates;
+ };
+
+ }
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPath_Step_H
diff --git a/WebCore/xml/XPathUtil.cpp b/WebCore/xml/XPathUtil.cpp
new file mode 100644
index 0000000..ab4b1d4
--- /dev/null
+++ b/WebCore/xml/XPathUtil.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathUtil.h"
+
+#if ENABLE(XPATH)
+
+#include "ContainerNode.h"
+
+namespace WebCore {
+namespace XPath {
+
+bool isRootDomNode(Node* node)
+{
+ return node && !node->parentNode();
+}
+
+String stringValue(Node* node)
+{
+ switch (node->nodeType()) {
+ case Node::ATTRIBUTE_NODE:
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ case Node::COMMENT_NODE:
+ case Node::TEXT_NODE:
+ case Node::CDATA_SECTION_NODE:
+ case Node::XPATH_NAMESPACE_NODE:
+ return node->nodeValue();
+ default:
+ if (isRootDomNode(node) || node->nodeType() == Node::ELEMENT_NODE) {
+ String str;
+
+ for (Node* n = node->firstChild(); n; n = n->traverseNextNode(node))
+ if (n->isTextNode())
+ str += n->nodeValue();
+
+ return str;
+ }
+ }
+
+ return String();
+}
+
+bool isValidContextNode(Node* node)
+{
+ if (!node)
+ return false;
+ switch (node->nodeType()) {
+ case Node::ATTRIBUTE_NODE:
+ case Node::CDATA_SECTION_NODE:
+ case Node::COMMENT_NODE:
+ case Node::DOCUMENT_NODE:
+ case Node::ELEMENT_NODE:
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ case Node::XPATH_NAMESPACE_NODE:
+ return true;
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ case Node::DOCUMENT_TYPE_NODE:
+ case Node::ENTITY_NODE:
+ case Node::ENTITY_REFERENCE_NODE:
+ case Node::NOTATION_NODE:
+ return false;
+ case Node::TEXT_NODE:
+ return !(node->parentNode() && node->parentNode()->isAttributeNode());
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathUtil.h b/WebCore/xml/XPathUtil.h
new file mode 100644
index 0000000..30f21ae
--- /dev/null
+++ b/WebCore/xml/XPathUtil.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathUtil_h
+#define XPathUtil_h
+
+#if ENABLE(XPATH)
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class Node;
+ class String;
+
+ namespace XPath {
+
+ /* @return whether the given node is the root node */
+ bool isRootDomNode(Node*);
+
+ /* @return the 'string-value' of the given node as specified by http://www.w3.org/TR/xpath */
+ String stringValue(Node*);
+
+ /* @return whether the given node is a valid context node */
+ bool isValidContextNode(Node*);
+
+ }
+
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPath_Util_H
diff --git a/WebCore/xml/XPathValue.cpp b/WebCore/xml/XPathValue.cpp
new file mode 100644
index 0000000..b3cad38
--- /dev/null
+++ b/WebCore/xml/XPathValue.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathValue.h"
+
+#if ENABLE(XPATH)
+
+#include "Node.h"
+#include "XPathUtil.h"
+
+#include <wtf/MathExtras.h>
+#include <limits>
+
+using std::numeric_limits;
+
+namespace WebCore {
+namespace XPath {
+
+const Value::AdoptTag Value::adopt = {};
+
+const NodeSet& Value::toNodeSet() const
+{
+ if (!m_data) {
+ static NodeSet emptyNodeSet;
+ return emptyNodeSet;
+ }
+
+ return m_data->m_nodeSet;
+}
+
+NodeSet& Value::modifiableNodeSet()
+{
+ if (!m_data)
+ m_data = ValueData::create();
+
+ m_type = NodeSetValue;
+ return m_data->m_nodeSet;
+}
+
+bool Value::toBoolean() const
+{
+ switch (m_type) {
+ case NodeSetValue:
+ return !m_data->m_nodeSet.isEmpty();
+ case BooleanValue:
+ return m_bool;
+ case NumberValue:
+ return m_number != 0 && !isnan(m_number);
+ case StringValue:
+ return !m_data->m_string.isEmpty();
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+double Value::toNumber() const
+{
+ switch (m_type) {
+ case NodeSetValue:
+ return Value(toString()).toNumber();
+ case NumberValue:
+ return m_number;
+ case StringValue: {
+ bool canConvert;
+ double value = m_data->m_string.simplifyWhiteSpace().toDouble(&canConvert);
+ if (canConvert)
+ return value;
+ return numeric_limits<double>::quiet_NaN();
+ }
+ case BooleanValue:
+ return m_bool;
+ }
+ ASSERT_NOT_REACHED();
+ return 0.0;
+}
+
+String Value::toString() const
+{
+ switch (m_type) {
+ case NodeSetValue:
+ if (m_data->m_nodeSet.isEmpty())
+ return "";
+ return stringValue(m_data->m_nodeSet.firstNode());
+ case StringValue:
+ return m_data->m_string;
+ case NumberValue:
+ if (isnan(m_number))
+ return "NaN";
+ if (m_number == 0)
+ return "0";
+ if (isinf(m_number))
+ return signbit(m_number) ? "-Infinity" : "Infinity";
+ return String::number(m_number);
+ case BooleanValue:
+ return m_bool ? "true" : "false";
+ }
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathValue.h b/WebCore/xml/XPathValue.h
new file mode 100644
index 0000000..a0cd24d
--- /dev/null
+++ b/WebCore/xml/XPathValue.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathValue_h
+#define XPathValue_h
+
+#if ENABLE(XPATH)
+
+#include "PlatformString.h"
+#include "XPathNodeSet.h"
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class ValueData : public RefCounted<ValueData> {
+ public:
+ static PassRefPtr<ValueData> create() { return adoptRef(new ValueData); }
+ static PassRefPtr<ValueData> create(const NodeSet& nodeSet) { return adoptRef(new ValueData(nodeSet)); }
+ static PassRefPtr<ValueData> create(const String& string) { return adoptRef(new ValueData(string)); }
+
+ NodeSet m_nodeSet;
+ String m_string;
+
+ private:
+ ValueData() { }
+ ValueData(const NodeSet& nodeSet) : m_nodeSet(nodeSet) { }
+ ValueData(const String& string) : m_string(string) { }
+ };
+
+ // Copying Value objects makes their data partially shared, so care has to be taken when dealing with copies.
+ class Value {
+ public:
+ enum Type { NodeSetValue, BooleanValue, NumberValue, StringValue };
+
+ Value(unsigned value) : m_type(NumberValue), m_bool(false), m_number(value) {}
+ Value(unsigned long value) : m_type(NumberValue), m_bool(false), m_number(value) {}
+ Value(double value) : m_type(NumberValue), m_bool(false), m_number(value) {}
+
+ Value(const char* value) : m_type(StringValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
+ Value(const String& value) : m_type(StringValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
+ Value(const NodeSet& value) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
+ Value(Node* value) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create()) { m_data->m_nodeSet.append(value); }
+
+ // This is needed to safely implement constructing from bool - with normal function overloading, any pointer type would match.
+ template<typename T> Value(T);
+
+ static const struct AdoptTag {} adopt;
+ Value(NodeSet& value, const AdoptTag&) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create()) { value.swap(m_data->m_nodeSet); }
+
+ Type type() const { return m_type; }
+
+ bool isNodeSet() const { return m_type == NodeSetValue; }
+ bool isBoolean() const { return m_type == BooleanValue; }
+ bool isNumber() const { return m_type == NumberValue; }
+ bool isString() const { return m_type == StringValue; }
+
+ const NodeSet& toNodeSet() const;
+ NodeSet& modifiableNodeSet();
+ bool toBoolean() const;
+ double toNumber() const;
+ String toString() const;
+
+ private:
+ Type m_type;
+ bool m_bool;
+ double m_number;
+ RefPtr<ValueData> m_data;
+ };
+
+ template<>
+ inline Value::Value(bool value)
+ : m_type(BooleanValue)
+ , m_bool(value)
+ , m_number(0)
+ {
+ }
+ }
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPath_Value_H
diff --git a/WebCore/xml/XPathVariableReference.cpp b/WebCore/xml/XPathVariableReference.cpp
new file mode 100644
index 0000000..efe9cf9
--- /dev/null
+++ b/WebCore/xml/XPathVariableReference.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XPathVariableReference.h"
+
+#if ENABLE(XPATH)
+
+#include "Node.h"
+#include "XPathValue.h"
+
+namespace WebCore {
+namespace XPath {
+
+VariableReference::VariableReference(const String& name)
+ : m_name(name)
+{
+}
+
+Value VariableReference::evaluate() const
+{
+ HashMap<String, String>& bindings = evaluationContext().variableBindings;
+ if (!bindings.contains(m_name))
+ // FIXME: Is this the right thing to do if an unknown variable is referenced?
+ return "";
+ return bindings.get(m_name);
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)
diff --git a/WebCore/xml/XPathVariableReference.h b/WebCore/xml/XPathVariableReference.h
new file mode 100644
index 0000000..811176d
--- /dev/null
+++ b/WebCore/xml/XPathVariableReference.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XPathVariableReference_h
+#define XPathVariableReference_h
+
+#if ENABLE(XPATH)
+
+#include "XPathExpressionNode.h"
+
+namespace WebCore {
+
+ namespace XPath {
+
+ class VariableReference : public Expression {
+ public:
+ VariableReference(const String& name);
+ private:
+ virtual Value evaluate() const;
+ String m_name;
+ };
+
+ }
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // XPath_VariableReference_H
diff --git a/WebCore/xml/XSLImportRule.cpp b/WebCore/xml/XSLImportRule.cpp
new file mode 100644
index 0000000..2efafa3
--- /dev/null
+++ b/WebCore/xml/XSLImportRule.cpp
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the XSL implementation.
+ *
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "XSLImportRule.h"
+
+#if ENABLE(XSLT)
+
+#include "CachedXSLStyleSheet.h"
+#include "DocLoader.h"
+#include "XSLStyleSheet.h"
+
+namespace WebCore {
+
+XSLImportRule::XSLImportRule(XSLStyleSheet* parent, const String& href)
+ : StyleBase(parent)
+ , m_strHref(href)
+ , m_cachedSheet(0)
+ , m_loading(false)
+{
+}
+
+XSLImportRule::~XSLImportRule()
+{
+ if (m_styleSheet)
+ m_styleSheet->setParent(0);
+
+ if (m_cachedSheet)
+ m_cachedSheet->removeClient(this);
+}
+
+XSLStyleSheet* XSLImportRule::parentStyleSheet() const
+{
+ return (parent() && parent()->isXSLStyleSheet()) ? static_cast<XSLStyleSheet*>(parent()) : 0;
+}
+
+void XSLImportRule::setXSLStyleSheet(const String& url, const String& sheet)
+{
+ if (m_styleSheet)
+ m_styleSheet->setParent(0);
+
+ m_styleSheet = XSLStyleSheet::create(this, url);
+
+ XSLStyleSheet* parent = parentStyleSheet();
+ if (parent)
+ m_styleSheet->setOwnerDocument(parent->ownerDocument());
+
+ m_styleSheet->parseString(sheet);
+ m_loading = false;
+
+ if (parent)
+ parent->checkLoaded();
+}
+
+bool XSLImportRule::isLoading()
+{
+ return (m_loading || (m_styleSheet && m_styleSheet->isLoading()));
+}
+
+void XSLImportRule::loadSheet()
+{
+ DocLoader* docLoader = 0;
+ StyleBase* root = this;
+ StyleBase* parent;
+ while ((parent = root->parent()))
+ root = parent;
+ if (root->isXSLStyleSheet())
+ docLoader = static_cast<XSLStyleSheet*>(root)->docLoader();
+
+ String absHref = m_strHref;
+ XSLStyleSheet* parentSheet = parentStyleSheet();
+ if (!parentSheet->href().isNull())
+ // use parent styleheet's URL as the base URL
+ absHref = KURL(KURL(parentSheet->href()), m_strHref).string();
+
+ // Check for a cycle in our import chain. If we encounter a stylesheet
+ // in our parent chain with the same URL, then just bail.
+ for (parent = this->parent(); parent; parent = parent->parent()) {
+ if (parent->isXSLStyleSheet() && absHref == static_cast<XSLStyleSheet*>(parent)->href())
+ return;
+ }
+
+ m_cachedSheet = docLoader->requestXSLStyleSheet(absHref);
+
+ if (m_cachedSheet) {
+ m_cachedSheet->addClient(this);
+
+ // If the imported sheet is in the cache, then setXSLStyleSheet gets called,
+ // and the sheet even gets parsed (via parseString). In this case we have
+ // loaded (even if our subresources haven't), so if we have a stylesheet after
+ // checking the cache, then we've clearly loaded.
+ if (!m_styleSheet)
+ m_loading = true;
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(XSLT)
diff --git a/WebCore/xml/XSLImportRule.h b/WebCore/xml/XSLImportRule.h
new file mode 100644
index 0000000..fc7a7f8
--- /dev/null
+++ b/WebCore/xml/XSLImportRule.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the XSL implementation.
+ *
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XSLImportRule_h
+#define XSLImportRule_h
+
+#if ENABLE(XSLT)
+
+#include "CachedResourceClient.h"
+#include "CachedResourceHandle.h"
+#include "StyleBase.h"
+#include "XSLStyleSheet.h"
+
+namespace WebCore {
+
+class CachedXSLStyleSheet;
+
+class XSLImportRule : public StyleBase, private CachedResourceClient {
+public:
+ static PassRefPtr<XSLImportRule> create(XSLStyleSheet* parentSheet, const String& href)
+ {
+ return adoptRef(new XSLImportRule(parentSheet, href));
+ }
+
+ virtual ~XSLImportRule();
+
+ const String& href() const { return m_strHref; }
+ XSLStyleSheet* styleSheet() const { return m_styleSheet.get(); }
+
+ XSLStyleSheet* parentStyleSheet() const;
+
+ bool isLoading();
+ void loadSheet();
+
+private:
+ XSLImportRule(XSLStyleSheet* parentSheet, const String& href);
+
+ virtual bool isImportRule() { return true; }
+
+ // from CachedResourceClient
+ virtual void setXSLStyleSheet(const String& url, const String& sheet);
+
+ String m_strHref;
+ RefPtr<XSLStyleSheet> m_styleSheet;
+ CachedResourceHandle<CachedXSLStyleSheet> m_cachedSheet;
+ bool m_loading;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(XSLT)
+
+#endif // XSLImportRule_h
diff --git a/WebCore/xml/XSLStyleSheet.cpp b/WebCore/xml/XSLStyleSheet.cpp
new file mode 100644
index 0000000..9443652
--- /dev/null
+++ b/WebCore/xml/XSLStyleSheet.cpp
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the XSL implementation.
+ *
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "XSLStyleSheet.h"
+
+#if ENABLE(XSLT)
+
+#include "CString.h"
+#include "Console.h"
+#include "DOMWindow.h"
+#include "DocLoader.h"
+#include "Document.h"
+#include "Frame.h"
+#include "loader.h"
+#include "Node.h"
+#include "XMLTokenizer.h"
+#include "XSLImportRule.h"
+#include "XSLTProcessor.h"
+
+#include <libxml/uri.h>
+#include <libxslt/xsltutils.h>
+
+#if PLATFORM(MAC)
+#include "SoftLinking.h"
+#endif
+
+#if PLATFORM(MAC)
+SOFT_LINK_LIBRARY(libxslt)
+SOFT_LINK(libxslt, xsltIsBlank, int, (xmlChar *str), (str))
+SOFT_LINK(libxslt, xsltGetNsProp, xmlChar *, (xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace), (node, name, nameSpace))
+SOFT_LINK(libxslt, xsltParseStylesheetDoc, xsltStylesheetPtr, (xmlDocPtr doc), (doc))
+SOFT_LINK(libxslt, xsltLoadStylesheetPI, xsltStylesheetPtr, (xmlDocPtr doc), (doc))
+#endif
+
+namespace WebCore {
+
+XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& href)
+ : StyleSheet(parentRule, href)
+ , m_ownerDocument(0)
+ , m_stylesheetDoc(0)
+ , m_embedded(false)
+ , m_processed(false) // Child sheets get marked as processed when the libxslt engine has finally seen them.
+ , m_stylesheetDocTaken(false)
+{
+}
+
+XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& href, bool embedded)
+ : StyleSheet(parentNode, href)
+ , m_ownerDocument(parentNode->document())
+ , m_stylesheetDoc(0)
+ , m_embedded(embedded)
+ , m_processed(true) // The root sheet starts off processed.
+ , m_stylesheetDocTaken(false)
+{
+}
+
+XSLStyleSheet::~XSLStyleSheet()
+{
+ if (!m_stylesheetDocTaken)
+ xmlFreeDoc(m_stylesheetDoc);
+}
+
+bool XSLStyleSheet::isLoading()
+{
+ unsigned len = length();
+ for (unsigned i = 0; i < len; ++i) {
+ StyleBase* rule = item(i);
+ if (rule->isImportRule()) {
+ XSLImportRule* import = static_cast<XSLImportRule*>(rule);
+ if (import->isLoading())
+ return true;
+ }
+ }
+ return false;
+}
+
+void XSLStyleSheet::checkLoaded()
+{
+ if (isLoading())
+ return;
+ if (parent())
+ parent()->checkLoaded();
+ if (ownerNode())
+ ownerNode()->sheetLoaded();
+}
+
+xmlDocPtr XSLStyleSheet::document()
+{
+ if (m_embedded && ownerDocument())
+ return (xmlDocPtr)ownerDocument()->transformSource();
+ return m_stylesheetDoc;
+}
+
+void XSLStyleSheet::clearDocuments()
+{
+ m_stylesheetDoc = 0;
+ unsigned len = length();
+ for (unsigned i = 0; i < len; ++i) {
+ StyleBase* rule = item(i);
+ if (rule->isImportRule()) {
+ XSLImportRule* import = static_cast<XSLImportRule*>(rule);
+ if (import->styleSheet())
+ import->styleSheet()->clearDocuments();
+ }
+ }
+}
+
+DocLoader* XSLStyleSheet::docLoader()
+{
+ if (!m_ownerDocument)
+ return 0;
+ return m_ownerDocument->docLoader();
+}
+
+bool XSLStyleSheet::parseString(const String& string, bool strict)
+{
+ // Parse in a single chunk into an xmlDocPtr
+ const UChar BOM = 0xFEFF;
+ const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
+ setLoaderForLibXMLCallbacks(docLoader());
+ if (!m_stylesheetDocTaken)
+ xmlFreeDoc(m_stylesheetDoc);
+ m_stylesheetDocTaken = false;
+
+ Console* console = 0;
+ if (Frame* frame = ownerDocument()->frame())
+ console = frame->domWindow()->console();
+ xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc);
+ xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc);
+
+ m_stylesheetDoc = xmlReadMemory(reinterpret_cast<const char*>(string.characters()), string.length() * sizeof(UChar),
+ href().utf8().data(),
+ BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE",
+ XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA);
+ loadChildSheets();
+
+ xmlSetStructuredErrorFunc(0, 0);
+ xmlSetGenericErrorFunc(0, 0);
+
+ setLoaderForLibXMLCallbacks(0);
+ return m_stylesheetDoc;
+}
+
+void XSLStyleSheet::loadChildSheets()
+{
+ if (!document())
+ return;
+
+ xmlNodePtr stylesheetRoot = document()->children;
+
+ // Top level children may include other things such as DTD nodes, we ignore those.
+ while (stylesheetRoot && stylesheetRoot->type != XML_ELEMENT_NODE)
+ stylesheetRoot = stylesheetRoot->next;
+
+ if (m_embedded) {
+ // We have to locate (by ID) the appropriate embedded stylesheet element, so that we can walk the
+ // import/include list.
+ xmlAttrPtr idNode = xmlGetID(document(), (const xmlChar*)(href().utf8().data()));
+ if (!idNode)
+ return;
+ stylesheetRoot = idNode->parent;
+ } else {
+ // FIXME: Need to handle an external URI with a # in it. This is a pretty minor edge case, so we'll deal
+ // with it later.
+ }
+
+ if (stylesheetRoot) {
+ // Walk the children of the root element and look for import/include elements.
+ // Imports must occur first.
+ xmlNodePtr curr = stylesheetRoot->children;
+ while (curr) {
+ if (curr->type != XML_ELEMENT_NODE) {
+ curr = curr->next;
+ continue;
+ }
+ if (IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "import")) {
+ xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
+ loadChildSheet(String::fromUTF8((const char*)uriRef));
+ xmlFree(uriRef);
+ } else
+ break;
+ curr = curr->next;
+ }
+
+ // Now handle includes.
+ while (curr) {
+ if (curr->type == XML_ELEMENT_NODE && IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "include")) {
+ xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
+ loadChildSheet(String::fromUTF8((const char*)uriRef));
+ xmlFree(uriRef);
+ }
+ curr = curr->next;
+ }
+ }
+}
+
+void XSLStyleSheet::loadChildSheet(const String& href)
+{
+ RefPtr<XSLImportRule> childRule = XSLImportRule::create(this, href);
+ append(childRule);
+ childRule->loadSheet();
+}
+
+xsltStylesheetPtr XSLStyleSheet::compileStyleSheet()
+{
+ // FIXME: Hook up error reporting for the stylesheet compilation process.
+ if (m_embedded)
+ return xsltLoadStylesheetPI(document());
+
+ // xsltParseStylesheetDoc makes the document part of the stylesheet
+ // so we have to release our pointer to it.
+ ASSERT(!m_stylesheetDocTaken);
+ xsltStylesheetPtr result = xsltParseStylesheetDoc(m_stylesheetDoc);
+ if (result)
+ m_stylesheetDocTaken = true;
+ return result;
+}
+
+xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri)
+{
+ bool matchedParent = (parentDoc == document());
+ unsigned len = length();
+ for (unsigned i = 0; i < len; ++i) {
+ StyleBase* rule = item(i);
+ if (rule->isImportRule()) {
+ XSLImportRule* import = static_cast<XSLImportRule*>(rule);
+ XSLStyleSheet* child = import->styleSheet();
+ if (!child)
+ continue;
+ if (matchedParent) {
+ if (child->processed())
+ continue; // libxslt has been given this sheet already.
+
+ // Check the URI of the child stylesheet against the doc URI.
+ // In order to ensure that libxml canonicalized both URLs, we get the original href
+ // string from the import rule and canonicalize it using libxml before comparing it
+ // with the URI argument.
+ CString importHref = import->href().utf8();
+ xmlChar* base = xmlNodeGetBase(parentDoc, (xmlNodePtr)parentDoc);
+ xmlChar* childURI = xmlBuildURI((const xmlChar*)importHref.data(), base);
+ bool equalURIs = xmlStrEqual(uri, childURI);
+ xmlFree(base);
+ xmlFree(childURI);
+ if (equalURIs) {
+ child->markAsProcessed();
+ return child->document();
+ }
+ } else {
+ xmlDocPtr result = import->styleSheet()->locateStylesheetSubResource(parentDoc, uri);
+ if (result)
+ return result;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void XSLStyleSheet::markAsProcessed()
+{
+ ASSERT(!m_processed);
+ ASSERT(!m_stylesheetDocTaken);
+ m_processed = true;
+ m_stylesheetDocTaken = true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(XSLT)
diff --git a/WebCore/xml/XSLStyleSheet.h b/WebCore/xml/XSLStyleSheet.h
new file mode 100644
index 0000000..8946529
--- /dev/null
+++ b/WebCore/xml/XSLStyleSheet.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the XSL implementation.
+ *
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XSLStyleSheet_h
+#define XSLStyleSheet_h
+
+#if ENABLE(XSLT)
+
+#include "StyleSheet.h"
+#include <libxml/parser.h>
+#include <libxslt/transform.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class DocLoader;
+class Document;
+class XSLImportRule;
+
+class XSLStyleSheet : public StyleSheet {
+public:
+ static PassRefPtr<XSLStyleSheet> create(XSLImportRule* parentImport, const String& href)
+ {
+ return adoptRef(new XSLStyleSheet(parentImport, href));
+ }
+ static PassRefPtr<XSLStyleSheet> create(Node* parentNode, const String& href)
+ {
+ return adoptRef(new XSLStyleSheet(parentNode, href, false));
+ }
+ static PassRefPtr<XSLStyleSheet> createEmbedded(Node* parentNode, const String& href)
+ {
+ return adoptRef(new XSLStyleSheet(parentNode, href, true));
+ }
+
+ virtual ~XSLStyleSheet();
+
+ virtual bool isXSLStyleSheet() const { return true; }
+
+ virtual String type() const { return "text/xml"; }
+
+ virtual bool parseString(const String &string, bool strict = true);
+
+ virtual bool isLoading();
+ virtual void checkLoaded();
+
+ void loadChildSheets();
+ void loadChildSheet(const String& href);
+
+ xsltStylesheetPtr compileStyleSheet();
+
+ DocLoader* docLoader();
+
+ Document* ownerDocument() { return m_ownerDocument; }
+ void setOwnerDocument(Document* doc) { m_ownerDocument = doc; }
+
+ xmlDocPtr document();
+
+ void clearDocuments();
+
+ xmlDocPtr locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri);
+
+ void markAsProcessed();
+ bool processed() const { return m_processed; }
+
+private:
+ XSLStyleSheet(Node* parentNode, const String& href, bool embedded);
+ XSLStyleSheet(XSLImportRule* parentImport, const String& href);
+
+ Document* m_ownerDocument;
+ xmlDocPtr m_stylesheetDoc;
+ bool m_embedded;
+ bool m_processed;
+ bool m_stylesheetDocTaken;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(XSLT)
+
+#endif // XSLStyleSheet_h
diff --git a/WebCore/xml/XSLTExtensions.cpp b/WebCore/xml/XSLTExtensions.cpp
new file mode 100644
index 0000000..d89f08b
--- /dev/null
+++ b/WebCore/xml/XSLTExtensions.cpp
@@ -0,0 +1,88 @@
+/**
+ * Copyright (C) 2001-2002 Thomas Broyer, Charlie Bozeman and Daniel Veillard.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is fur-
+ * nished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+ * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+ * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the authors shall not
+ * be used in advertising or otherwise to promote the sale, use or other deal-
+ * ings in this Software without prior written authorization from him.
+ */
+
+#include "config.h"
+
+#if ENABLE(XSLT)
+
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xsltutils.h>
+#include <libxslt/extensions.h>
+#include <libxslt/extra.h>
+
+#if PLATFORM(MAC)
+#include "SoftLinking.h"
+#endif
+
+#if PLATFORM(MAC)
+SOFT_LINK_LIBRARY(libxslt)
+SOFT_LINK(libxslt, xsltRegisterExtFunction, int, (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *URI, xmlXPathFunction function), (ctxt, name, URI, function))
+SOFT_LINK(libxslt, xsltFunctionNodeSet, void, (xmlXPathParserContextPtr ctxt, int nargs), (ctxt, nargs))
+#endif
+
+namespace WebCore {
+
+// FIXME: This code is taken from libexslt 1.1.11; should sync with newer versions.
+static void exsltNodeSetFunction(xmlXPathParserContextPtr ctxt, int nargs)
+{
+ xmlChar *strval;
+ xmlNodePtr retNode;
+ xmlXPathObjectPtr ret;
+
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (xmlXPathStackIsNodeSet(ctxt)) {
+ xsltFunctionNodeSet(ctxt, nargs);
+ return;
+ }
+
+ strval = xmlXPathPopString(ctxt);
+ retNode = xmlNewDocText(NULL, strval);
+ ret = xmlXPathNewValueTree(retNode);
+
+ // FIXME: It might be helpful to push any errors from xmlXPathNewValueTree
+ // up to the Javascript Console.
+ if (ret != NULL)
+ ret->type = XPATH_NODESET;
+
+ if (strval != NULL)
+ xmlFree(strval);
+
+ valuePush(ctxt, ret);
+}
+
+void registerXSLTExtensions(xsltTransformContextPtr ctxt)
+{
+ xsltRegisterExtFunction(ctxt, (const xmlChar*)"node-set", (const xmlChar*)"http://exslt.org/common", exsltNodeSetFunction);
+}
+
+}
+
+#endif
diff --git a/WebCore/xml/XSLTExtensions.h b/WebCore/xml/XSLTExtensions.h
new file mode 100644
index 0000000..4e4224f
--- /dev/null
+++ b/WebCore/xml/XSLTExtensions.h
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XSLTExtensions_h
+#define XSLTExtensions_h
+
+#if ENABLE(XSLT)
+
+#include <libxslt/xsltInternals.h>
+
+namespace WebCore {
+
+void registerXSLTExtensions(xsltTransformContextPtr ctxt);
+
+}
+
+#endif
+#endif
diff --git a/WebCore/xml/XSLTProcessor.cpp b/WebCore/xml/XSLTProcessor.cpp
new file mode 100644
index 0000000..ab554c4
--- /dev/null
+++ b/WebCore/xml/XSLTProcessor.cpp
@@ -0,0 +1,461 @@
+/*
+ * This file is part of the XSL implementation.
+ *
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple, Inc. All rights reserved.
+ * Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(XSLT)
+
+#include "XSLTProcessor.h"
+
+#include "CString.h"
+#include "Console.h"
+#include "DOMImplementation.h"
+#include "DOMWindow.h"
+#include "DocLoader.h"
+#include "DocumentFragment.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLDocument.h"
+#include "HTMLTokenizer.h"
+#include "Page.h"
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "Text.h"
+#include "TextResourceDecoder.h"
+#include "XMLTokenizer.h"
+#include "XSLTExtensions.h"
+#include "XSLTUnicodeSort.h"
+#include "loader.h"
+#include "markup.h"
+#include <libxslt/imports.h>
+#include <libxslt/variables.h>
+#include <libxslt/xsltutils.h>
+#include <wtf/Assertions.h>
+#include <wtf/Platform.h>
+#include <wtf/Vector.h>
+#if PLATFORM(MAC)
+#include "SoftLinking.h"
+#endif
+
+#if PLATFORM(MAC)
+SOFT_LINK_LIBRARY(libxslt);
+SOFT_LINK(libxslt, xsltFreeStylesheet, void, (xsltStylesheetPtr sheet), (sheet))
+SOFT_LINK(libxslt, xsltFreeTransformContext, void, (xsltTransformContextPtr ctxt), (ctxt))
+SOFT_LINK(libxslt, xsltNewTransformContext, xsltTransformContextPtr, (xsltStylesheetPtr style, xmlDocPtr doc), (style, doc))
+SOFT_LINK(libxslt, xsltApplyStylesheetUser, xmlDocPtr, (xsltStylesheetPtr style, xmlDocPtr doc, const char** params, const char* output, FILE* profile, xsltTransformContextPtr userCtxt), (style, doc, params, output, profile, userCtxt))
+SOFT_LINK(libxslt, xsltQuoteUserParams, int, (xsltTransformContextPtr ctxt, const char** params), (ctxt, params))
+SOFT_LINK(libxslt, xsltSetCtxtSortFunc, void, (xsltTransformContextPtr ctxt, xsltSortFunc handler), (ctxt, handler))
+SOFT_LINK(libxslt, xsltSetLoaderFunc, void, (xsltDocLoaderFunc f), (f))
+SOFT_LINK(libxslt, xsltSaveResultTo, int, (xmlOutputBufferPtr buf, xmlDocPtr result, xsltStylesheetPtr style), (buf, result, style))
+SOFT_LINK(libxslt, xsltNextImport, xsltStylesheetPtr, (xsltStylesheetPtr style), (style))
+#endif
+
+namespace WebCore {
+
+void XSLTProcessor::genericErrorFunc(void* userData, const char* msg, ...)
+{
+ // It would be nice to do something with this error message.
+}
+
+void XSLTProcessor::parseErrorFunc(void* userData, xmlError* error)
+{
+ Console* console = static_cast<Console*>(userData);
+ if (!console)
+ return;
+
+ MessageLevel level;
+ switch (error->level) {
+ case XML_ERR_NONE:
+ level = TipMessageLevel;
+ break;
+ case XML_ERR_WARNING:
+ level = WarningMessageLevel;
+ break;
+ case XML_ERR_ERROR:
+ case XML_ERR_FATAL:
+ default:
+ level = ErrorMessageLevel;
+ break;
+ }
+
+ console->addMessage(XMLMessageSource, level, error->message, error->line, error->file);
+}
+
+// FIXME: There seems to be no way to control the ctxt pointer for loading here, thus we have globals.
+static XSLTProcessor* globalProcessor = 0;
+static DocLoader* globalDocLoader = 0;
+static xmlDocPtr docLoaderFunc(const xmlChar* uri,
+ xmlDictPtr dict,
+ int options,
+ void* ctxt,
+ xsltLoadType type)
+{
+ if (!globalProcessor)
+ return 0;
+
+ switch (type) {
+ case XSLT_LOAD_DOCUMENT: {
+ xsltTransformContextPtr context = (xsltTransformContextPtr)ctxt;
+ xmlChar* base = xmlNodeGetBase(context->document->doc, context->node);
+ KURL url(KURL(reinterpret_cast<const char*>(base)), reinterpret_cast<const char*>(uri));
+ xmlFree(base);
+ ResourceError error;
+ ResourceResponse response;
+
+ Vector<char> data;
+
+ bool requestAllowed = globalDocLoader->frame() && globalDocLoader->doc()->securityOrigin()->canRequest(url);
+ if (requestAllowed) {
+ globalDocLoader->frame()->loader()->loadResourceSynchronously(url, error, response, data);
+ requestAllowed = globalDocLoader->doc()->securityOrigin()->canRequest(response.url());
+ }
+ if (!requestAllowed) {
+ data.clear();
+ globalDocLoader->printAccessDeniedMessage(url);
+ }
+
+ Console* console = 0;
+ if (Frame* frame = globalProcessor->xslStylesheet()->ownerDocument()->frame())
+ console = frame->domWindow()->console();
+ xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc);
+ xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc);
+
+ // We don't specify an encoding here. Neither Gecko nor WinIE respects
+ // the encoding specified in the HTTP headers.
+ xmlDocPtr doc = xmlReadMemory(data.data(), data.size(), (const char*)uri, 0, options);
+
+ xmlSetStructuredErrorFunc(0, 0);
+ xmlSetGenericErrorFunc(0, 0);
+
+ return doc;
+ }
+ case XSLT_LOAD_STYLESHEET:
+ return globalProcessor->xslStylesheet()->locateStylesheetSubResource(((xsltStylesheetPtr)ctxt)->doc, uri);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static inline void setXSLTLoadCallBack(xsltDocLoaderFunc func, XSLTProcessor* processor, DocLoader* loader)
+{
+ xsltSetLoaderFunc(func);
+ globalProcessor = processor;
+ globalDocLoader = loader;
+}
+
+static int writeToVector(void* context, const char* buffer, int len)
+{
+ Vector<UChar>& resultOutput = *static_cast<Vector<UChar>*>(context);
+ String decodedChunk = String::fromUTF8(buffer, len);
+ resultOutput.append(decodedChunk.characters(), decodedChunk.length());
+ return len;
+}
+
+static bool saveResultToString(xmlDocPtr resultDoc, xsltStylesheetPtr sheet, String& resultString)
+{
+ xmlOutputBufferPtr outputBuf = xmlAllocOutputBuffer(0);
+ if (!outputBuf)
+ return false;
+
+ Vector<UChar> resultVector;
+ outputBuf->context = &resultVector;
+ outputBuf->writecallback = writeToVector;
+
+ int retval = xsltSaveResultTo(outputBuf, resultDoc, sheet);
+ xmlOutputBufferClose(outputBuf);
+ if (retval < 0)
+ return false;
+
+ // Workaround for <http://bugzilla.gnome.org/show_bug.cgi?id=495668>: libxslt appends an extra line feed to the result.
+ if (resultVector.size() > 0 && resultVector[resultVector.size() - 1] == '\n')
+ resultVector.removeLast();
+
+ resultString = String::adopt(resultVector);
+
+ return true;
+}
+
+static inline void transformTextStringToXHTMLDocumentString(String& text)
+{
+ // Modify the output so that it is a well-formed XHTML document with a <pre> tag enclosing the text.
+ text.replace('&', "&amp;");
+ text.replace('<', "&lt;");
+ text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+ "<head><title/></head>\n"
+ "<body>\n"
+ "<pre>" + text + "</pre>\n"
+ "</body>\n"
+ "</html>\n";
+}
+
+static const char** xsltParamArrayFromParameterMap(XSLTProcessor::ParameterMap& parameters)
+{
+ if (parameters.isEmpty())
+ return 0;
+
+ const char** parameterArray = (const char**)fastMalloc(((parameters.size() * 2) + 1) * sizeof(char*));
+
+ XSLTProcessor::ParameterMap::iterator end = parameters.end();
+ unsigned index = 0;
+ for (XSLTProcessor::ParameterMap::iterator it = parameters.begin(); it != end; ++it) {
+ parameterArray[index++] = strdup(it->first.utf8().data());
+ parameterArray[index++] = strdup(it->second.utf8().data());
+ }
+ parameterArray[index] = 0;
+
+ return parameterArray;
+}
+
+static void freeXsltParamArray(const char** params)
+{
+ const char** temp = params;
+ if (!params)
+ return;
+
+ while (*temp) {
+ free((void*)*(temp++)); // strdup returns malloc'd blocks, so we have to use free() here
+ free((void*)*(temp++));
+ }
+ fastFree(params);
+}
+
+
+PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceString,
+ const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame)
+{
+ RefPtr<Document> ownerDocument = sourceNode->document();
+ bool sourceIsDocument = (sourceNode == ownerDocument.get());
+ String documentSource = sourceString;
+
+ RefPtr<Document> result;
+ if (sourceMIMEType == "text/plain") {
+ result = ownerDocument->implementation()->createDocument(frame);
+ transformTextStringToXHTMLDocumentString(documentSource);
+ } else
+ result = ownerDocument->implementation()->createDocument(sourceMIMEType, frame, false);
+
+ // Before parsing, we need to save & detach the old document and get the new document
+ // in place. We have to do this only if we're rendering the result document.
+ if (frame) {
+ if (FrameView* view = frame->view())
+ view->clear();
+ result->setTransformSourceDocument(frame->document());
+ frame->setDocument(result);
+ }
+
+ if (sourceIsDocument)
+ result->setURL(ownerDocument->url());
+ result->open();
+
+ RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(sourceMIMEType);
+ decoder->setEncoding(sourceEncoding.isEmpty() ? UTF8Encoding() : TextEncoding(sourceEncoding), TextResourceDecoder::EncodingFromXMLHeader);
+ result->setDecoder(decoder.release());
+
+ result->write(documentSource);
+ result->finishParsing();
+ result->close();
+
+ return result.release();
+}
+
+static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Node* sourceNode, Document* outputDoc)
+{
+ RefPtr<DocumentFragment> fragment = new DocumentFragment(outputDoc);
+
+ if (sourceMIMEType == "text/html")
+ parseHTMLDocumentFragment(sourceString, fragment.get());
+ else if (sourceMIMEType == "text/plain")
+ fragment->addChild(new Text(outputDoc, sourceString));
+ else {
+ bool successfulParse = parseXMLDocumentFragment(sourceString, fragment.get(), outputDoc->documentElement());
+ if (!successfulParse)
+ return 0;
+ }
+
+ // FIXME: Do we need to mess with URLs here?
+
+ return fragment;
+}
+
+static xsltStylesheetPtr xsltStylesheetPointer(RefPtr<XSLStyleSheet>& cachedStylesheet, Node* stylesheetRootNode)
+{
+ if (!cachedStylesheet && stylesheetRootNode) {
+ cachedStylesheet = XSLStyleSheet::create(stylesheetRootNode->parent() ? stylesheetRootNode->parent() : stylesheetRootNode,
+ stylesheetRootNode->document()->url().string());
+ cachedStylesheet->parseString(createMarkup(stylesheetRootNode));
+ }
+
+ if (!cachedStylesheet || !cachedStylesheet->document())
+ return 0;
+
+ return cachedStylesheet->compileStyleSheet();
+}
+
+static inline xmlDocPtr xmlDocPtrFromNode(Node* sourceNode, bool& shouldDelete)
+{
+ RefPtr<Document> ownerDocument = sourceNode->document();
+ bool sourceIsDocument = (sourceNode == ownerDocument.get());
+
+ xmlDocPtr sourceDoc = 0;
+ if (sourceIsDocument)
+ sourceDoc = (xmlDocPtr)ownerDocument->transformSource();
+ if (!sourceDoc) {
+ sourceDoc = (xmlDocPtr)xmlDocPtrForString(ownerDocument->docLoader(), createMarkup(sourceNode),
+ sourceIsDocument ? ownerDocument->url().string() : String());
+ shouldDelete = (sourceDoc != 0);
+ }
+ return sourceDoc;
+}
+
+static inline String resultMIMEType(xmlDocPtr resultDoc, xsltStylesheetPtr sheet)
+{
+ // There are three types of output we need to be able to deal with:
+ // HTML (create an HTML document), XML (create an XML document),
+ // and text (wrap in a <pre> and create an XML document).
+
+ const xmlChar* resultType = 0;
+ XSLT_GET_IMPORT_PTR(resultType, sheet, method);
+ if (resultType == 0 && resultDoc->type == XML_HTML_DOCUMENT_NODE)
+ resultType = (const xmlChar*)"html";
+
+ if (xmlStrEqual(resultType, (const xmlChar*)"html"))
+ return "text/html";
+ else if (xmlStrEqual(resultType, (const xmlChar*)"text"))
+ return "text/plain";
+
+ return "application/xml";
+}
+
+bool XSLTProcessor::transformToString(Node* sourceNode, String& mimeType, String& resultString, String& resultEncoding)
+{
+ RefPtr<Document> ownerDocument = sourceNode->document();
+
+ setXSLTLoadCallBack(docLoaderFunc, this, ownerDocument->docLoader());
+ xsltStylesheetPtr sheet = xsltStylesheetPointer(m_stylesheet, m_stylesheetRootNode.get());
+ if (!sheet) {
+ setXSLTLoadCallBack(0, 0, 0);
+ return false;
+ }
+ m_stylesheet->clearDocuments();
+
+ xmlChar* origMethod = sheet->method;
+ if (!origMethod && mimeType == "text/html")
+ sheet->method = (xmlChar*)"html";
+
+ bool success = false;
+ bool shouldFreeSourceDoc = false;
+ if (xmlDocPtr sourceDoc = xmlDocPtrFromNode(sourceNode, shouldFreeSourceDoc)) {
+ // The XML declaration would prevent parsing the result as a fragment, and it's not needed even for documents,
+ // as the result of this function is always immediately parsed.
+ sheet->omitXmlDeclaration = true;
+
+ xsltTransformContextPtr transformContext = xsltNewTransformContext(sheet, sourceDoc);
+ registerXSLTExtensions(transformContext);
+
+ // <http://bugs.webkit.org/show_bug.cgi?id=16077>: XSLT processor <xsl:sort> algorithm only compares by code point
+ xsltSetCtxtSortFunc(transformContext, xsltUnicodeSortFunction);
+
+ // This is a workaround for a bug in libxslt.
+ // The bug has been fixed in version 1.1.13, so once we ship that this can be removed.
+ if (transformContext->globalVars == NULL)
+ transformContext->globalVars = xmlHashCreate(20);
+
+ const char** params = xsltParamArrayFromParameterMap(m_parameters);
+ xsltQuoteUserParams(transformContext, params);
+ xmlDocPtr resultDoc = xsltApplyStylesheetUser(sheet, sourceDoc, 0, 0, 0, transformContext);
+
+ xsltFreeTransformContext(transformContext);
+ freeXsltParamArray(params);
+
+ if (shouldFreeSourceDoc)
+ xmlFreeDoc(sourceDoc);
+
+ if (success = saveResultToString(resultDoc, sheet, resultString)) {
+ mimeType = resultMIMEType(resultDoc, sheet);
+ resultEncoding = (char*)resultDoc->encoding;
+ }
+ xmlFreeDoc(resultDoc);
+ }
+
+ sheet->method = origMethod;
+ setXSLTLoadCallBack(0, 0, 0);
+ xsltFreeStylesheet(sheet);
+ m_stylesheet = 0;
+
+ return success;
+}
+
+PassRefPtr<Document> XSLTProcessor::transformToDocument(Node* sourceNode)
+{
+ String resultMIMEType;
+ String resultString;
+ String resultEncoding;
+ if (!transformToString(sourceNode, resultMIMEType, resultString, resultEncoding))
+ return 0;
+ return createDocumentFromSource(resultString, resultEncoding, resultMIMEType, sourceNode, 0);
+}
+
+PassRefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode, Document* outputDoc)
+{
+ String resultMIMEType;
+ String resultString;
+ String resultEncoding;
+
+ // If the output document is HTML, default to HTML method.
+ if (outputDoc->isHTMLDocument())
+ resultMIMEType = "text/html";
+
+ if (!transformToString(sourceNode, resultMIMEType, resultString, resultEncoding))
+ return 0;
+ return createFragmentFromSource(resultString, resultMIMEType, sourceNode, outputDoc);
+}
+
+void XSLTProcessor::setParameter(const String& namespaceURI, const String& localName, const String& value)
+{
+ // FIXME: namespace support?
+ // should make a QualifiedName here but we'd have to expose the impl
+ m_parameters.set(localName, value);
+}
+
+String XSLTProcessor::getParameter(const String& namespaceURI, const String& localName) const
+{
+ // FIXME: namespace support?
+ // should make a QualifiedName here but we'd have to expose the impl
+ return m_parameters.get(localName);
+}
+
+void XSLTProcessor::removeParameter(const String& namespaceURI, const String& localName)
+{
+ // FIXME: namespace support?
+ m_parameters.remove(localName);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(XSLT)
diff --git a/WebCore/xml/XSLTProcessor.h b/WebCore/xml/XSLTProcessor.h
new file mode 100644
index 0000000..9ee2aad
--- /dev/null
+++ b/WebCore/xml/XSLTProcessor.h
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the XSL implementation.
+ *
+ * Copyright (C) 2004, 2007, 2008 Apple, Inc. All rights reserved.
+ *
+ * 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; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XSLTProcessor_h
+#define XSLTProcessor_h
+
+#if ENABLE(XSLT)
+
+#include "Node.h"
+#include "StringHash.h"
+#include "XSLStyleSheet.h"
+#include <libxml/parserInternals.h>
+#include <libxslt/documents.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class Frame;
+class Document;
+class DocumentFragment;
+
+class XSLTProcessor : public RefCounted<XSLTProcessor> {
+public:
+ static PassRefPtr<XSLTProcessor> create() { return adoptRef(new XSLTProcessor); }
+
+ void setXSLStyleSheet(PassRefPtr<XSLStyleSheet> styleSheet) { m_stylesheet = styleSheet; }
+ bool transformToString(Node* source, String& resultMIMEType, String& resultString, String& resultEncoding);
+ PassRefPtr<Document> createDocumentFromSource(const String& source, const String& sourceEncoding, const String& sourceMIMEType, Node* sourceNode, Frame* frame);
+
+ // DOM methods
+ void importStylesheet(PassRefPtr<Node> style) { m_stylesheetRootNode = style; }
+ PassRefPtr<DocumentFragment> transformToFragment(Node* source, Document* ouputDoc);
+ PassRefPtr<Document> transformToDocument(Node* source);
+
+ void setParameter(const String& namespaceURI, const String& localName, const String& value);
+ String getParameter(const String& namespaceURI, const String& localName) const;
+ void removeParameter(const String& namespaceURI, const String& localName);
+ void clearParameters() { m_parameters.clear(); }
+
+ void reset() { m_stylesheet.clear(); m_stylesheetRootNode.clear(); m_parameters.clear(); }
+
+ static void parseErrorFunc(void* userData, xmlError*);
+ static void genericErrorFunc(void* userData, const char* msg, ...);
+
+public:
+ // Only for libXSLT callbacks
+ XSLStyleSheet* xslStylesheet() const { return m_stylesheet.get(); }
+
+ typedef HashMap<String, String> ParameterMap;
+
+private:
+ XSLTProcessor() { }
+
+ RefPtr<XSLStyleSheet> m_stylesheet;
+ RefPtr<Node> m_stylesheetRootNode;
+ ParameterMap m_parameters;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/xml/XSLTProcessor.idl b/WebCore/xml/XSLTProcessor.idl
new file mode 100644
index 0000000..0a6ff93
--- /dev/null
+++ b/WebCore/xml/XSLTProcessor.idl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module xml {
+
+ // Eventually we should implement XSLTException:
+ // http://lxr.mozilla.org/seamonkey/source/content/xsl/public/nsIXSLTException.idl
+ // http://bugs.webkit.org/show_bug.cgi?id=5446
+
+ interface [
+ Conditional=XSLT
+ ] XSLTProcessor {
+
+ [Custom] void importStylesheet(in Node stylesheet);
+ [Custom] DocumentFragment transformToFragment(in Node source, in Document docVal);
+ [Custom] Document transformToDocument(in Node source);
+
+ [Custom] void setParameter(in DOMString namespaceURI, in DOMString localName, in DOMString value);
+ [Custom, ConvertNullStringTo=Undefined] DOMString getParameter(in DOMString namespaceURI, in DOMString localName);
+ [Custom] void removeParameter(in DOMString namespaceURI, in DOMString localName);
+ void clearParameters();
+
+ void reset();
+
+ };
+
+}
diff --git a/WebCore/xml/XSLTUnicodeSort.cpp b/WebCore/xml/XSLTUnicodeSort.cpp
new file mode 100644
index 0000000..ed66112
--- /dev/null
+++ b/WebCore/xml/XSLTUnicodeSort.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XSLTUnicodeSort.h"
+
+#if ENABLE(XSLT)
+
+#include "PlatformString.h"
+
+#include <libxslt/templates.h>
+#include <libxslt/xsltutils.h>
+
+#include <wtf/unicode/Collator.h>
+
+#if PLATFORM(MAC)
+#include "SoftLinking.h"
+#endif
+
+#if PLATFORM(MAC)
+SOFT_LINK_LIBRARY(libxslt)
+SOFT_LINK(libxslt, xsltComputeSortResult, xmlXPathObjectPtr*, (xsltTransformContextPtr ctxt, xmlNodePtr sort), (ctxt, sort))
+SOFT_LINK(libxslt, xsltEvalAttrValueTemplate, xmlChar*, (xsltTransformContextPtr ctxt, xmlNodePtr node, const xmlChar *name, const xmlChar *ns), (ctxt, node, name, ns))
+
+static void init_xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
+static void (*softLink_xsltTransformError)(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *, ...) WTF_ATTRIBUTE_PRINTF(4, 5) = init_xsltTransformError;
+
+static void init_xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...)
+{
+ softLink_xsltTransformError = (void (*) (xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *, ...))dlsym(libxsltLibrary(), "xsltTransformError");
+ ASSERT(softLink_xsltTransformError);
+
+ va_list args;
+ va_start(args, msg);
+#if PLATFORM(WIN_OS)
+ char str[1024];
+ vsnprintf(str, sizeof(str) - 1, msg, args);
+#else
+ char* str;
+ vasprintf(&str, msg, args);
+#endif
+ va_end(args);
+
+ softLink_xsltTransformError(ctxt, style, node, "%s", str);
+
+#if !PLATFORM(WIN_OS)
+ free(str);
+#endif
+}
+
+inline void xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
+
+inline void xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+#if PLATFORM(WIN_OS)
+ char str[1024];
+ vsnprintf(str, sizeof(str) - 1, msg, args);
+#else
+ char* str;
+ vasprintf(&str, msg, args);
+#endif
+ va_end(args);
+
+ softLink_xsltTransformError(ctxt, style, node, "%s", str);
+
+#if !PLATFORM(WIN_OS)
+ free(str);
+#endif
+}
+
+#endif
+
+namespace WebCore {
+
+// Based on default implementation from libxslt 1.1.22 and xsltICUSort.c example.
+void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, int nbsorts)
+{
+#ifdef XSLT_REFACTORED
+ xsltStyleItemSortPtr comp;
+#else
+ xsltStylePreCompPtr comp;
+#endif
+ xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
+ xmlXPathObjectPtr *results = NULL, *res;
+ xmlNodeSetPtr list = NULL;
+ int descending, number, desc, numb;
+ int len = 0;
+ int i, j, incr;
+ int tst;
+ int depth;
+ xmlNodePtr node;
+ xmlXPathObjectPtr tmp;
+ int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
+
+ if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
+ (nbsorts >= XSLT_MAX_SORT))
+ return;
+ if (sorts[0] == NULL)
+ return;
+ comp = static_cast<xsltStylePreComp*>(sorts[0]->psvi);
+ if (comp == NULL)
+ return;
+
+ list = ctxt->nodeList;
+ if ((list == NULL) || (list->nodeNr <= 1))
+ return; /* nothing to do */
+
+ for (j = 0; j < nbsorts; j++) {
+ comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
+ tempstype[j] = 0;
+ if ((comp->stype == NULL) && (comp->has_stype != 0)) {
+ comp->stype =
+ xsltEvalAttrValueTemplate(ctxt, sorts[j],
+ (const xmlChar *) "data-type",
+ XSLT_NAMESPACE);
+ if (comp->stype != NULL) {
+ tempstype[j] = 1;
+ if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
+ comp->number = 0;
+ else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
+ comp->number = 1;
+ else {
+ xsltTransformError(ctxt, NULL, sorts[j],
+ "xsltDoSortFunction: no support for data-type = %s\n",
+ comp->stype);
+ comp->number = 0; /* use default */
+ }
+ }
+ }
+ temporder[j] = 0;
+ if ((comp->order == NULL) && (comp->has_order != 0)) {
+ comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
+ (const xmlChar *) "order",
+ XSLT_NAMESPACE);
+ if (comp->order != NULL) {
+ temporder[j] = 1;
+ if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
+ comp->descending = 0;
+ else if (xmlStrEqual(comp->order,
+ (const xmlChar *) "descending"))
+ comp->descending = 1;
+ else {
+ xsltTransformError(ctxt, NULL, sorts[j],
+ "xsltDoSortFunction: invalid value %s for order\n",
+ comp->order);
+ comp->descending = 0; /* use default */
+ }
+ }
+ }
+ }
+
+ len = list->nodeNr;
+
+ resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
+ for (i = 1;i < XSLT_MAX_SORT;i++)
+ resultsTab[i] = NULL;
+
+ results = resultsTab[0];
+
+ comp = static_cast<xsltStylePreComp*>(sorts[0]->psvi);
+ descending = comp->descending;
+ number = comp->number;
+ if (results == NULL)
+ return;
+
+ // We are passing a language identifier to a function that expects a locale identifier.
+ // The implementation of Collator should be lenient, and accept both "en-US" and "en_US", for example.
+ // This lets an author to really specify sorting rules, e.g. "de_DE@collation=phonebook", which isn't
+ // possible with language alone.
+ Collator collator(comp->has_lang ? (const char*)comp->lang : "en");
+ collator.setOrderLowerFirst(comp->lower_first);
+
+ /* Shell's sort of node-set */
+ for (incr = len / 2; incr > 0; incr /= 2) {
+ for (i = incr; i < len; i++) {
+ j = i - incr;
+ if (results[i] == NULL)
+ continue;
+
+ while (j >= 0) {
+ if (results[j] == NULL)
+ tst = 1;
+ else {
+ if (number) {
+ /* We make NaN smaller than number in accordance
+ with XSLT spec */
+ if (xmlXPathIsNaN(results[j]->floatval)) {
+ if (xmlXPathIsNaN(results[j + incr]->floatval))
+ tst = 0;
+ else
+ tst = -1;
+ } else if (xmlXPathIsNaN(results[j + incr]->floatval))
+ tst = 1;
+ else if (results[j]->floatval ==
+ results[j + incr]->floatval)
+ tst = 0;
+ else if (results[j]->floatval >
+ results[j + incr]->floatval)
+ tst = 1;
+ else tst = -1;
+ } else {
+ String str1 = String::fromUTF8((const char*)results[j]->stringval);
+ String str2 = String::fromUTF8((const char*)results[j + incr]->stringval);
+ tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
+ }
+ if (descending)
+ tst = -tst;
+ }
+ if (tst == 0) {
+ /*
+ * Okay we need to use multi level sorts
+ */
+ depth = 1;
+ while (depth < nbsorts) {
+ if (sorts[depth] == NULL)
+ break;
+ comp = static_cast<xsltStylePreComp*>(sorts[depth]->psvi);
+ if (comp == NULL)
+ break;
+ desc = comp->descending;
+ numb = comp->number;
+
+ /*
+ * Compute the result of the next level for the
+ * full set, this might be optimized ... or not
+ */
+ if (resultsTab[depth] == NULL)
+ resultsTab[depth] = xsltComputeSortResult(ctxt,
+ sorts[depth]);
+ res = resultsTab[depth];
+ if (res == NULL)
+ break;
+ if (res[j] == NULL) {
+ if (res[j+incr] != NULL)
+ tst = 1;
+ } else {
+ if (numb) {
+ /* We make NaN smaller than number in
+ accordance with XSLT spec */
+ if (xmlXPathIsNaN(res[j]->floatval)) {
+ if (xmlXPathIsNaN(res[j +
+ incr]->floatval))
+ tst = 0;
+ else
+ tst = -1;
+ } else if (xmlXPathIsNaN(res[j + incr]->
+ floatval))
+ tst = 1;
+ else if (res[j]->floatval == res[j + incr]->
+ floatval)
+ tst = 0;
+ else if (res[j]->floatval >
+ res[j + incr]->floatval)
+ tst = 1;
+ else tst = -1;
+ } else {
+ String str1 = String::fromUTF8((const char*)res[j]->stringval);
+ String str2 = String::fromUTF8((const char*)res[j + incr]->stringval);
+ tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
+ }
+ if (desc)
+ tst = -tst;
+ }
+
+ /*
+ * if we still can't differenciate at this level
+ * try one level deeper.
+ */
+ if (tst != 0)
+ break;
+ depth++;
+ }
+ }
+ if (tst == 0) {
+ tst = results[j]->index > results[j + incr]->index;
+ }
+ if (tst > 0) {
+ tmp = results[j];
+ results[j] = results[j + incr];
+ results[j + incr] = tmp;
+ node = list->nodeTab[j];
+ list->nodeTab[j] = list->nodeTab[j + incr];
+ list->nodeTab[j + incr] = node;
+ depth = 1;
+ while (depth < nbsorts) {
+ if (sorts[depth] == NULL)
+ break;
+ if (resultsTab[depth] == NULL)
+ break;
+ res = resultsTab[depth];
+ tmp = res[j];
+ res[j] = res[j + incr];
+ res[j + incr] = tmp;
+ depth++;
+ }
+ j -= incr;
+ } else
+ break;
+ }
+ }
+ }
+
+ for (j = 0; j < nbsorts; j++) {
+ comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
+ if (tempstype[j] == 1) {
+ /* The data-type needs to be recomputed each time */
+ xmlFree((void *)(comp->stype));
+ comp->stype = NULL;
+ }
+ if (temporder[j] == 1) {
+ /* The order needs to be recomputed each time */
+ xmlFree((void *)(comp->order));
+ comp->order = NULL;
+ }
+ if (resultsTab[j] != NULL) {
+ for (i = 0;i < len;i++)
+ xmlXPathFreeObject(resultsTab[j][i]);
+ xmlFree(resultsTab[j]);
+ }
+ }
+}
+
+}
+
+#endif
diff --git a/WebCore/xml/XSLTUnicodeSort.h b/WebCore/xml/XSLTUnicodeSort.h
new file mode 100644
index 0000000..c8d395b
--- /dev/null
+++ b/WebCore/xml/XSLTUnicodeSort.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef XSLTUnicodeSort_h
+#define XSLTUnicodeSort_h
+
+#if ENABLE(XSLT)
+
+#include <libxslt/xsltInternals.h>
+
+namespace WebCore {
+
+ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr* sorts, int nbsorts);
+
+}
+
+#endif
+#endif
diff --git a/WebCore/xml/xmlattrs.in b/WebCore/xml/xmlattrs.in
new file mode 100644
index 0000000..6cc47be
--- /dev/null
+++ b/WebCore/xml/xmlattrs.in
@@ -0,0 +1,6 @@
+namespace="XML"
+namespaceURI="http://www.w3.org/XML/1998/namespace"
+
+base
+lang
+space