diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2009-06-15 09:06:43 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-06-15 09:31:31 (GMT) |
commit | c411f16870f112c3407c28c22b617f613a82cff4 (patch) | |
tree | 29a1bcd590c8b31af2aab445bfe8a978dc5bf582 /src/3rdparty/webkit/WebCore/xml | |
parent | 3d77b56b32a0c53ec0bbfaa07236fedb900ff336 (diff) | |
download | Qt-c411f16870f112c3407c28c22b617f613a82cff4.zip Qt-c411f16870f112c3407c28c22b617f613a82cff4.tar.gz Qt-c411f16870f112c3407c28c22b617f613a82cff4.tar.bz2 |
Updated WebKit from /home/shausman/src/webkit/trunk to qtwebkit-4.6-snapshot-15062009 ( 65232bf00dc494ebfd978f998c88f58d18ecce1e )
Diffstat (limited to 'src/3rdparty/webkit/WebCore/xml')
32 files changed, 705 insertions, 778 deletions
diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.cpp b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.cpp index cc92c2a..a837c8c 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.cpp @@ -23,32 +23,27 @@ #include "XMLHttpRequest.h" #include "CString.h" -#include "Console.h" +#include "CrossOriginAccessControl.h" +#include "CrossOriginPreflightResultCache.h" #include "DOMImplementation.h" -#include "DOMWindow.h" +#include "Document.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 "KURL.h" -#include "KURLHash.h" -#include "Page.h" +#include "ResourceError.h" +#include "ResourceRequest.h" +#include "SecurityOrigin.h" #include "Settings.h" -#include "SubresourceLoader.h" -#include "SystemTime.h" #include "TextResourceDecoder.h" +#include "ThreadableLoader.h" #include "XMLHttpRequestException.h" #include "XMLHttpRequestProgressEvent.h" #include "XMLHttpRequestUpload.h" #include "markup.h" -#include <wtf/Noncopyable.h> #include <wtf/StdLibExtras.h> -#include <wtf/Threading.h> #if USE(JSC) #include "JSDOMWindow.h" @@ -56,14 +51,11 @@ namespace WebCore { -typedef HashSet<String, CaseFoldingHash> HeadersSet; - struct XMLHttpRequestStaticData { XMLHttpRequestStaticData(); String m_proxyHeaderPrefix; String m_secHeaderPrefix; HashSet<String, CaseFoldingHash> m_forbiddenRequestHeaders; - HashSet<String, CaseFoldingHash> m_allowedCrossSiteResponseHeaders; }; XMLHttpRequestStaticData::XMLHttpRequestStaticData() @@ -72,76 +64,25 @@ XMLHttpRequestStaticData::XMLHttpRequestStaticData() { m_forbiddenRequestHeaders.add("accept-charset"); m_forbiddenRequestHeaders.add("accept-encoding"); + m_forbiddenRequestHeaders.add("access-control-request-headers"); + m_forbiddenRequestHeaders.add("access-control-request-method"); m_forbiddenRequestHeaders.add("connection"); m_forbiddenRequestHeaders.add("content-length"); m_forbiddenRequestHeaders.add("content-transfer-encoding"); + m_forbiddenRequestHeaders.add("cookie"); + m_forbiddenRequestHeaders.add("cookie2"); m_forbiddenRequestHeaders.add("date"); m_forbiddenRequestHeaders.add("expect"); m_forbiddenRequestHeaders.add("host"); m_forbiddenRequestHeaders.add("keep-alive"); + m_forbiddenRequestHeaders.add("origin"); m_forbiddenRequestHeaders.add("referer"); m_forbiddenRequestHeaders.add("te"); m_forbiddenRequestHeaders.add("trailer"); m_forbiddenRequestHeaders.add("transfer-encoding"); m_forbiddenRequestHeaders.add("upgrade"); + m_forbiddenRequestHeaders.add("user-agent"); m_forbiddenRequestHeaders.add("via"); - - m_allowedCrossSiteResponseHeaders.add("cache-control"); - m_allowedCrossSiteResponseHeaders.add("content-language"); - m_allowedCrossSiteResponseHeaders.add("content-type"); - m_allowedCrossSiteResponseHeaders.add("expires"); - m_allowedCrossSiteResponseHeaders.add("last-modified"); - m_allowedCrossSiteResponseHeaders.add("pragma"); -} - -class PreflightResultCacheItem : Noncopyable { -public: - PreflightResultCacheItem(bool credentials) - : m_absoluteExpiryTime(0) - , m_credentials(credentials) - { - } - - bool parse(const ResourceResponse&); - bool allowsCrossSiteMethod(const String&) const; - bool allowsCrossSiteHeaders(const HTTPHeaderMap&) const; - bool allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const; - -private: - template<class HashType> - static void addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>&); - template<class HashType> - static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>&); - static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta); - - // 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; - HashSet<String> m_methods; - HeadersSet m_headers; -}; - -class PreflightResultCache : Noncopyable { -public: - static PreflightResultCache& shared(); - - void appendEntry(const String& origin, const KURL&, PreflightResultCacheItem*); - bool canSkipPreflight(const String& origin, const KURL&, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders); - -private: - PreflightResultCache() { } - - typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultHashMap; - - PreflightResultHashMap m_preflightHashMap; - Mutex m_mutex; -}; - -static bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name) -{ - return equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-type"); } // Determines if a string is a valid token, as defined by @@ -178,131 +119,6 @@ static bool isSetCookieHeader(const AtomicString& name) return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2"); } -template<class HashType> -void PreflightResultCacheItem::addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>& set) -{ - StringImpl* stringImpl = string.impl(); - if (!stringImpl) - return; - - // Skip white space from start. - while (start <= end && isSpaceOrNewline((*stringImpl)[start])) - start++; - - // only white space - if (start > end) - return; - - // Skip white space from end. - while (end && isSpaceOrNewline((*stringImpl)[end])) - end--; - - // substringCopy() is called on the strings because the cache is accessed on multiple threads. - set.add(string.substringCopy(start, end - start + 1)); -} - - -template<class HashType> -bool PreflightResultCacheItem::parseAccessControlAllowList(const String& string, HashSet<String, HashType>& set) -{ - int start = 0; - int end; - while ((end = string.find(',', start)) != -1) { - if (start == end) - return false; - - addToAccessControlAllowList(string, start, end - 1, set); - start = end + 1; - } - if (start != static_cast<int>(string.length())) - addToAccessControlAllowList(string, start, string.length() - 1, set); - - return true; -} - -bool PreflightResultCacheItem::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; -} - -bool PreflightResultCacheItem::parse(const ResourceResponse& response) -{ - m_methods.clear(); - if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods)) - return false; - - m_headers.clear(); - if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers)) - return false; - - unsigned expiryDelta = 0; - if (!parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta)) - expiryDelta = 5; - - m_absoluteExpiryTime = currentTime() + expiryDelta; - return true; -} - -bool PreflightResultCacheItem::allowsCrossSiteMethod(const String& method) const -{ - return m_methods.contains(method) || method == "GET" || method == "POST"; -} - -bool PreflightResultCacheItem::allowsCrossSiteHeaders(const HTTPHeaderMap& requestHeaders) const -{ - HTTPHeaderMap::const_iterator end = requestHeaders.end(); - for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) { - if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first)) - return false; - } - return true; -} - -bool PreflightResultCacheItem::allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const -{ - if (m_absoluteExpiryTime < currentTime()) - return false; - if (includeCredentials && !m_credentials) - return false; - if (!allowsCrossSiteMethod(method)) - return false; - if (!allowsCrossSiteHeaders(requestHeaders)) - return false; - return true; -} - -PreflightResultCache& PreflightResultCache::shared() -{ - AtomicallyInitializedStatic(PreflightResultCache&, cache = *new PreflightResultCache); - return cache; -} - -void PreflightResultCache::appendEntry(const String& origin, const KURL& url, PreflightResultCacheItem* preflightResult) -{ - MutexLocker lock(m_mutex); - // Note that the entry may already be present in the HashMap if another thread is accessing the same location. - m_preflightHashMap.set(std::make_pair(origin.copy(), url.copy()), preflightResult); -} - -bool PreflightResultCache::canSkipPreflight(const String& origin, const KURL& url, bool includeCredentials, - const String& method, const HTTPHeaderMap& requestHeaders) -{ - MutexLocker lock(m_mutex); - PreflightResultHashMap::iterator cacheIt = m_preflightHashMap.find(std::make_pair(origin, url)); - if (cacheIt == m_preflightHashMap.end()) - return false; - - if (cacheIt->second->allowsRequest(includeCredentials, method, requestHeaders)) - return true; - - delete cacheIt->second; - m_preflightHashMap.remove(cacheIt); - return false; -} - static const XMLHttpRequestStaticData* staticData = 0; static const XMLHttpRequestStaticData* createXMLHttpRequestStaticData() @@ -318,12 +134,11 @@ static const XMLHttpRequestStaticData* initializeXMLHttpRequestStaticData() return dummy; } -XMLHttpRequest::XMLHttpRequest(Document* doc) - : ActiveDOMObject(doc, this) +XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context) + : ActiveDOMObject(context, 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) @@ -332,8 +147,8 @@ XMLHttpRequest::XMLHttpRequest(Document* doc) , m_inPreflight(false) , m_receivedLength(0) , m_lastSendLineNumber(0) + , m_exceptionCode(0) { - ASSERT(document()); initializeXMLHttpRequestStaticData(); } @@ -349,6 +164,16 @@ Document* XMLHttpRequest::document() const return static_cast<Document*>(scriptExecutionContext()); } +#if ENABLE(DASHBOARD_SUPPORT) +bool XMLHttpRequest::usesDashboardBackwardCompatibilityMode() const +{ + if (scriptExecutionContext()->isWorkerContext()) + return false; + Settings* settings = document()->settings(); + return settings && settings->usesDashboardBackwardCompatibilityMode(); +} +#endif + XMLHttpRequest::State XMLHttpRequest::readyState() const { return m_state; @@ -372,7 +197,7 @@ Document* XMLHttpRequest::responseXML() const 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). + // FIXME: Set Last-Modified. m_responseXML->write(String(m_responseText)); m_responseXML->finishParsing(); m_responseXML->close(); @@ -458,10 +283,20 @@ void XMLHttpRequest::callReadyStateChangeListener() dispatchReadyStateChangeEvent(); - if (m_state == DONE) + if (m_state == DONE && !m_error) dispatchLoadEvent(); } +void XMLHttpRequest::setWithCredentials(bool value, ExceptionCode& ec) +{ + if (m_state != OPENED || m_loader) { + ec = INVALID_STATE_ERR; + return; + } + + m_includeCredentials = value; +} + void XMLHttpRequest::open(const String& method, const KURL& url, bool async, ExceptionCode& ec) { internalAbort(); @@ -555,12 +390,11 @@ void XMLHttpRequest::send(Document* document, ExceptionCode& ec) if (!initSend(ec)) return; - if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) { + if (m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) { String contentType = getRequestHeader("Content-Type"); if (contentType.isEmpty()) { #if ENABLE(DASHBOARD_SUPPORT) - Settings* settings = document->settings(); - if (settings && settings->usesDashboardBackwardCompatibilityMode()) + if (usesDashboardBackwardCompatibilityMode()) setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded"); else #endif @@ -587,12 +421,11 @@ 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"))) { + if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) { String contentType = getRequestHeader("Content-Type"); if (contentType.isEmpty()) { #if ENABLE(DASHBOARD_SUPPORT) - Settings* settings = document()->settings(); - if (settings && settings->usesDashboardBackwardCompatibilityMode()) + if (usesDashboardBackwardCompatibilityMode()) setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded"); else #endif @@ -612,7 +445,7 @@ 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"))) { + if (m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) { // FIXME: Should we set a Content-Type if one is not set. // FIXME: add support for uploading bundles. m_requestEntityBody = FormData::create(); @@ -624,19 +457,28 @@ void XMLHttpRequest::send(File* body, ExceptionCode& ec) void XMLHttpRequest::createRequest(ExceptionCode& ec) { + // Upload event listeners should be disallowed for simple cross-origin requests, because POSTing to an URL that does not + // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. If a listener exists + // when creating the request, it will force preflight. + // Also, only async requests support upload progress events. + m_uploadEventsAllowed = false; if (m_async) { dispatchLoadStartEvent(); - if (m_requestEntityBody && m_upload) + if (m_requestEntityBody && m_upload) { + m_uploadEventsAllowed = m_upload->hasListeners(); m_upload->dispatchLoadStartEvent(); + } } m_sameOriginRequest = scriptExecutionContext()->securityOrigin()->canRequest(m_url); if (!m_sameOriginRequest) { - makeCrossSiteAccessRequest(ec); + makeCrossOriginAccessRequest(ec); return; } + m_uploadEventsAllowed = true; + makeSameOriginRequest(ec); } @@ -649,6 +491,7 @@ void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec) if (m_requestEntityBody) { ASSERT(m_method != "GET"); + ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } @@ -661,38 +504,31 @@ void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec) 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) +void XMLHttpRequest::makeCrossOriginAccessRequest(ExceptionCode& ec) { ASSERT(!m_sameOriginRequest); - if (isSimpleCrossSiteAccessRequest()) - makeSimpleCrossSiteAccessRequest(ec); + if (!m_uploadEventsAllowed && isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders)) + makeSimpleCrossOriginAccessRequest(ec); else - makeCrossSiteAccessRequestWithPreflight(ec); + makeCrossOriginAccessRequestWithPreflight(ec); } -void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec) +void XMLHttpRequest::makeSimpleCrossOriginAccessRequest(ExceptionCode& ec) { - ASSERT(isSimpleCrossSiteAccessRequest()); + ASSERT(isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders)); + + // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. + if (!m_url.protocolInHTTPFamily()) { + ec = XMLHttpRequestException::NETWORK_ERR; + networkError(); + return; + } KURL url = m_url; url.setUser(String()); url.setPass(String()); - + ResourceRequest request(url); request.setHTTPMethod(m_method); request.setAllowHTTPCookies(m_includeCredentials); @@ -701,20 +537,26 @@ void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec) if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); + if (m_requestEntityBody) { + ASSERT(m_method != "GET"); + ASSERT(m_method != "HEAD"); + request.setHTTPBody(m_requestEntityBody.release()); + } + if (m_async) loadRequestAsynchronously(request); else loadRequestSynchronously(request, ec); } -void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec) +void XMLHttpRequest::makeCrossOriginAccessRequestWithPreflight(ExceptionCode& ec) { String origin = scriptExecutionContext()->securityOrigin()->toString(); KURL url = m_url; url.setUser(String()); url.setPass(String()); - if (!PreflightResultCache::shared().canSkipPreflight(origin, url, m_includeCredentials, m_method, m_requestHeaders)) { + if (!CrossOriginPreflightResultCache::shared().canSkipPreflight(origin, url, m_includeCredentials, m_method, m_requestHeaders)) { m_inPreflight = true; ResourceRequest preflightRequest(url); preflightRequest.setHTTPMethod("OPTIONS"); @@ -739,6 +581,7 @@ void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec) } if (m_async) { + m_uploadEventsAllowed = true; loadRequestAsynchronously(preflightRequest); return; } @@ -761,10 +604,12 @@ void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec) if (m_requestEntityBody) { ASSERT(m_method != "GET"); + ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_async) { + m_uploadEventsAllowed = true; loadRequestAsynchronously(request); return; } @@ -793,53 +638,43 @@ void XMLHttpRequest::handleAsynchronousPreflightResult() if (m_requestEntityBody) { ASSERT(m_method != "GET"); + ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } + m_uploadEventsAllowed = true; 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; + m_exceptionCode = 0; + StoredCredentials storedCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; - // 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; + ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, storedCredentials); + if (!m_exceptionCode && m_error) + m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; + ec = m_exceptionCode; } - void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request) { ASSERT(m_async); + m_exceptionCode = 0; // 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()); + LoadCallbacks callbacks = m_inPreflight ? DoNotSendLoadCallbacks : SendLoadCallbacks; + StoredCredentials storedCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; + + if (m_upload) + request.setReportUploadProgress(true); + + m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, callbacks, DoNotSniffContent, storedCredentials); if (m_loader) { // Neither this object nor the JavaScript wrapper should be deleted while @@ -863,7 +698,7 @@ void XMLHttpRequest::abort() if ((m_state <= OPENED && !sendFlag) || m_state == DONE) m_state = UNSENT; - else { + else { ASSERT(!m_loader); changeState(DONE); m_state = UNSENT; @@ -872,7 +707,7 @@ void XMLHttpRequest::abort() dispatchAbortEvent(); if (!m_uploadComplete) { m_uploadComplete = true; - if (m_upload) + if (m_upload && m_uploadEventsAllowed) m_upload->dispatchAbortEvent(); } } @@ -917,8 +752,7 @@ void XMLHttpRequest::genericError() 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. + changeState(DONE); } void XMLHttpRequest::networkError() @@ -927,9 +761,10 @@ void XMLHttpRequest::networkError() dispatchErrorEvent(); if (!m_uploadComplete) { m_uploadComplete = true; - if (m_upload) + if (m_upload && m_uploadEventsAllowed) m_upload->dispatchErrorEvent(); } + internalAbort(); } void XMLHttpRequest::abortError() @@ -938,7 +773,7 @@ void XMLHttpRequest::abortError() dispatchAbortEvent(); if (!m_uploadComplete) { m_uploadComplete = true; - if (m_upload) + if (m_upload && m_uploadEventsAllowed) m_upload->dispatchAbortEvent(); } } @@ -953,11 +788,9 @@ void XMLHttpRequest::dropProtection() // can't be recouped until the load is done, so only // report the extra cost at that point. - if (JSDOMWindow* window = toJSDOMWindow(document()->frame())) { - JSC::JSValuePtr wrapper = getCachedDOMObjectWrapper(*window->globalData(), this); - if (wrapper) - JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2); - } + if (JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext())) + if (DOMObject* wrapper = getCachedDOMObjectWrapper(*globalObject->globalData(), this)) + JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2); #endif unsetPendingActivity(this); @@ -968,24 +801,20 @@ void XMLHttpRequest::overrideMimeType(const String& override) m_mimeTypeOverride = override; } -static void reportUnsafeUsage(Document* document, const String& message) +static void reportUnsafeUsage(ScriptExecutionContext* context, const String& message) { - if (!document) - return; - Frame* frame = document->frame(); - if (!frame) + if (!context) return; - // It's not good to report the bad usage without indicating what source line it came from. + // FIXME: It's not good to report the bad usage without indicating what source line it came from. // We should pass additional parameters so we can tell the console where the mistake occurred. - frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String()); + context->addMessage(ConsoleDestination, JSMessageSource, ErrorMessageLevel, message, 1, String()); } void XMLHttpRequest::setRequestHeader(const AtomicString& 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()) + if (usesDashboardBackwardCompatibilityMode()) return; #endif @@ -1000,7 +829,7 @@ void XMLHttpRequest::setRequestHeader(const AtomicString& name, const String& va // A privileged script (e.g. a Dashboard widget) can set any headers. if (!scriptExecutionContext()->securityOrigin()->canLoadLocalResources() && !isSafeRequestHeader(name)) { - reportUnsafeUsage(document(), "Refused to set unsafe header \"" + name + "\""); + reportUnsafeUsage(scriptExecutionContext(), "Refused to set unsafe header \"" + name + "\""); return; } @@ -1071,23 +900,18 @@ String XMLHttpRequest::getResponseHeader(const AtomicString& name, ExceptionCode // See comment in getAllResponseHeaders above. if (isSetCookieHeader(name) && !scriptExecutionContext()->securityOrigin()->canLoadLocalResources()) { - reportUnsafeUsage(document(), "Refused to get unsafe header \"" + name + "\""); + reportUnsafeUsage(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\""); return ""; } if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name)) { - reportUnsafeUsage(document(), "Refused to get unsafe header \"" + name + "\""); + reportUnsafeUsage(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\""); return ""; } return m_response.httpHeaderField(name); } -bool XMLHttpRequest::isOnAccessControlResponseHeaderWhitelist(const String& name) const -{ - return staticData->m_allowedCrossSiteResponseHeaders.contains(name); -} - String XMLHttpRequest::responseMIMEType() const { String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride); @@ -1124,76 +948,56 @@ int XMLHttpRequest::status(ExceptionCode& ec) const 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_response.httpStatusText().isNull()) + return m_response.httpStatusText(); if (m_state == OPENED) { - // See comments in getStatus() above. + // See comments in status() above. ec = INVALID_STATE_ERR; } return String(); } -void XMLHttpRequest::processSyncLoadResults(const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec) -{ - if (m_sameOriginRequest && !scriptExecutionContext()->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*, const ResourceError& error) +void XMLHttpRequest::didFail(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()) { + m_exceptionCode = XMLHttpRequestException::ABORT_ERR; abortError(); return; } + m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; networkError(); - return; } -void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader) +void XMLHttpRequest::didFailRedirectCheck() +{ + networkError(); +} + +void XMLHttpRequest::didFinishLoading(unsigned long identifier) { if (m_error) return; if (m_inPreflight) { - didFinishLoadingPreflight(loader); + didFinishLoadingPreflight(); return; } - ASSERT(loader == m_loader); - if (m_state < HEADERS_RECEIVED) changeState(HEADERS_RECEIVED); 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); - } - } + scriptExecutionContext()->resourceRetrievedByXMLHttpRequest(identifier, m_responseText); + scriptExecutionContext()->addMessage(InspectorControllerDestination, JSMessageSource, LogMessageLevel, "XHR finished loading: \"" + m_url + "\".", m_lastSendLineNumber, m_lastSendURL); bool hadLoader = m_loader; m_loader = 0; @@ -1205,7 +1009,7 @@ void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader) dropProtection(); } -void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader*) +void XMLHttpRequest::didFinishLoadingPreflight() { ASSERT(m_inPreflight); ASSERT(!m_sameOriginRequest); @@ -1218,60 +1022,30 @@ void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader*) unsetPendingActivity(this); } -void XMLHttpRequest::willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse&) -{ - // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests. - if (!scriptExecutionContext()->securityOrigin()->canRequest(request.url())) { - internalAbort(); - networkError(); - } -} - -void XMLHttpRequest::didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) +void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) { if (!m_upload) return; - m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent); + if (m_uploadEventsAllowed) + m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent); if (bytesSent == totalBytesToBeSent && !m_uploadComplete) { m_uploadComplete = true; - m_upload->dispatchLoadEvent(); + if (m_uploadEventsAllowed) + 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(scriptExecutionContext()->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) +void XMLHttpRequest::didReceiveResponse(const ResourceResponse& response) { if (m_inPreflight) { - didReceiveResponsePreflight(loader, response); + didReceiveResponsePreflight(response); return; } if (!m_sameOriginRequest) { - if (!accessControlCheck(response)) { + if (!passesAccessControlCheck(response, m_includeCredentials, scriptExecutionContext()->securityOrigin())) { networkError(); return; } @@ -1283,43 +1057,35 @@ void XMLHttpRequest::didReceiveResponse(SubresourceLoader* loader, const Resourc m_responseEncoding = response.textEncodingName(); } -void XMLHttpRequest::didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse& response) +void XMLHttpRequest::didReceiveResponsePreflight(const ResourceResponse& response) { ASSERT(m_inPreflight); ASSERT(!m_sameOriginRequest); - if (!accessControlCheck(response)) { - networkError(); - return; - } - - OwnPtr<PreflightResultCacheItem> preflightResult(new PreflightResultCacheItem(m_includeCredentials)); - if (!preflightResult->parse(response)) { + if (!passesAccessControlCheck(response, m_includeCredentials, scriptExecutionContext()->securityOrigin())) { networkError(); return; } - if (!preflightResult->allowsCrossSiteMethod(m_method)) { + OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult(new CrossOriginPreflightResultCacheItem(m_includeCredentials)); + if (!preflightResult->parse(response) + || !preflightResult->allowsCrossOriginMethod(m_method) + || !preflightResult->allowsCrossOriginHeaders(m_requestHeaders)) { networkError(); return; } - if (!preflightResult->allowsCrossSiteHeaders(m_requestHeaders)) { - networkError(); - return; - } - - PreflightResultCache::shared().appendEntry(scriptExecutionContext()->securityOrigin()->toString(), m_url, preflightResult.release()); + CrossOriginPreflightResultCache::shared().appendEntry(scriptExecutionContext()->securityOrigin()->toString(), m_url, preflightResult.release()); } -void XMLHttpRequest::receivedCancellation(SubresourceLoader*, const AuthenticationChallenge& challenge) +void XMLHttpRequest::didReceiveAuthenticationCancellation(const ResourceResponse& failureResponse) { - m_response = challenge.failureResponse(); + m_response = failureResponse; } -void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int len) +void XMLHttpRequest::didReceiveData(const char* data, int len) { - if (m_inPreflight) + if (m_inPreflight || m_error) return; if (m_state < HEADERS_RECEIVED) @@ -1329,14 +1095,17 @@ void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int le 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()) + else if (responseIsXML()) { m_decoder = TextResourceDecoder::create("application/xml"); - else if (responseMIMEType() == "text/html") + // Don't stop on encoding errors, unlike it is done for other kinds of XML resources. This matches the behavior of previous WebKit versions, Firefox and Opera. + m_decoder->useLenientXMLDecoding(); + } 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) + + if (!len) return; if (len == -1) diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.h b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.h index 858f228..6955c11 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.h +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.h @@ -26,19 +26,21 @@ #include "EventTarget.h" #include "FormData.h" #include "ResourceResponse.h" -#include "SubresourceLoaderClient.h" #include "ScriptString.h" +#include "ThreadableLoaderClient.h" #include <wtf/OwnPtr.h> namespace WebCore { class Document; class File; +struct ResourceRequest; class TextResourceDecoder; +class ThreadableLoader; -class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private SubresourceLoaderClient, public ActiveDOMObject { +class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject { public: - static PassRefPtr<XMLHttpRequest> create(Document* document) { return adoptRef(new XMLHttpRequest(document)); } + static PassRefPtr<XMLHttpRequest> create(ScriptExecutionContext* context) { return adoptRef(new XMLHttpRequest(context)); } ~XMLHttpRequest(); // These exact numeric values are important because JS expects them. @@ -61,6 +63,8 @@ public: String statusText(ExceptionCode&) const; int status(ExceptionCode&) const; State readyState() const; + bool withCredentials() const { return m_includeCredentials; } + void setWithCredentials(bool, ExceptionCode&); 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&); @@ -112,26 +116,29 @@ public: using RefCounted<XMLHttpRequest>::deref; private: - XMLHttpRequest(Document*); + XMLHttpRequest(ScriptExecutionContext*); 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&); +#if ENABLE(DASHBOARD_SUPPORT) + bool usesDashboardBackwardCompatibilityMode() const; +#endif + + virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent); + virtual void didReceiveResponse(const ResourceResponse&); + virtual void didReceiveData(const char* data, int lengthReceived); + virtual void didFinishLoading(unsigned long identifier); + virtual void didFail(const ResourceError&); + virtual void didFailRedirectCheck(); + virtual void didReceiveAuthenticationCancellation(const ResourceResponse&); // Special versions for the preflight - void didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse&); - void didFinishLoadingPreflight(SubresourceLoader*); + void didReceiveResponsePreflight(const ResourceResponse&); + void didFinishLoadingPreflight(); - void processSyncLoadResults(const Vector<char>& data, const ResourceResponse&, ExceptionCode&); void updateAndDispatchOnProgress(unsigned int len); String responseMIMEType() const; @@ -153,21 +160,15 @@ private: void createRequest(ExceptionCode&); void makeSameOriginRequest(ExceptionCode&); - void makeCrossSiteAccessRequest(ExceptionCode&); + void makeCrossOriginAccessRequest(ExceptionCode&); - void makeSimpleCrossSiteAccessRequest(ExceptionCode&); - void makeCrossSiteAccessRequestWithPreflight(ExceptionCode&); + void makeSimpleCrossOriginAccessRequest(ExceptionCode&); + void makeCrossOriginAccessRequestWithPreflight(ExceptionCode&); void handleAsynchronousPreflightResult(); void loadRequestSynchronously(ResourceRequest&, ExceptionCode&); void loadRequestAsynchronously(ResourceRequest&); - bool isOnAccessControlResponseHeaderWhitelist(const String&) const; - - bool isSimpleCrossSiteAccessRequest() const; - String accessControlOrigin() const; - bool accessControlCheck(const ResourceResponse&); - void genericError(); void networkError(); void abortError(); @@ -198,16 +199,15 @@ private: bool m_async; bool m_includeCredentials; - RefPtr<SubresourceLoader> m_loader; + RefPtr<ThreadableLoader> 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. + // Unlike most strings in the DOM, we keep this as a ScriptString, 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. @@ -219,6 +219,7 @@ private: bool m_error; + bool m_uploadEventsAllowed; bool m_uploadComplete; bool m_sameOriginRequest; @@ -230,6 +231,7 @@ private: unsigned m_lastSendLineNumber; String m_lastSendURL; + ExceptionCode m_exceptionCode; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.idl b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.idl index 315d95c..79005e2 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.idl +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequest.idl @@ -29,7 +29,8 @@ module xml { interface [ - CustomMarkFunction + CustomMarkFunction, + NoStaticTables ] XMLHttpRequest { // From XMLHttpRequestEventTarget // event handler attributes @@ -52,6 +53,8 @@ module xml { readonly attribute unsigned short readyState; // request + attribute boolean withCredentials + setter raises(DOMException); // 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); diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestException.idl b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestException.idl index 2feb574..380e426 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestException.idl +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestException.idl @@ -29,14 +29,15 @@ module xml { interface [ - GenerateConstructor + GenerateConstructor, + NoStaticTables ] XMLHttpRequestException { readonly attribute unsigned short code; readonly attribute DOMString name; readonly attribute DOMString message; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT // Override in a Mozilla compatible format [DontEnum] DOMString toString(); #endif diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestProgressEvent.idl b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestProgressEvent.idl index 6de9690..549308b 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestProgressEvent.idl +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestProgressEvent.idl @@ -26,7 +26,8 @@ module events { interface [ - GenerateConstructor + GenerateConstructor, + NoStaticTables // We should also inherit from LSProgressEvent when the idl is added. ] XMLHttpRequestProgressEvent : ProgressEvent { readonly attribute unsigned long position; diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.cpp b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.cpp index a58c271..d8a76d5 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.cpp @@ -30,7 +30,6 @@ #include "Event.h" #include "EventException.h" #include "EventNames.h" -#include "Frame.h" #include "XMLHttpRequest.h" #include "XMLHttpRequestProgressEvent.h" #include <wtf/Assertions.h> @@ -42,6 +41,11 @@ XMLHttpRequestUpload::XMLHttpRequestUpload(XMLHttpRequest* xmlHttpRequest) { } +bool XMLHttpRequestUpload::hasListeners() const +{ + return m_onAbortListener || m_onErrorListener || m_onLoadListener || m_onLoadStartListener || m_onProgressListener || !m_eventListeners.isEmpty(); +} + ScriptExecutionContext* XMLHttpRequestUpload::scriptExecutionContext() const { XMLHttpRequest* xmlHttpRequest = associatedXMLHttpRequest(); diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.h b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.h index 93fa7f9..b4f40e0 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.h +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.h @@ -48,6 +48,8 @@ namespace WebCore { return adoptRef(new XMLHttpRequestUpload(xmlHttpRequest)); } + bool hasListeners() const; + virtual XMLHttpRequestUpload* toXMLHttpRequestUpload() { return this; } XMLHttpRequest* associatedXMLHttpRequest() const { return m_xmlHttpRequest; } diff --git a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.idl b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.idl index c066710..3172f68 100644 --- a/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.idl +++ b/src/3rdparty/webkit/WebCore/xml/XMLHttpRequestUpload.idl @@ -30,7 +30,8 @@ module xml { interface [ GenerateConstructor, - CustomMarkFunction + CustomMarkFunction, + NoStaticTables ] XMLHttpRequestUpload { // From XMLHttpRequestEventTarget // event handler attributes diff --git a/src/3rdparty/webkit/WebCore/xml/XPathException.idl b/src/3rdparty/webkit/WebCore/xml/XPathException.idl index 6e25514..c3c95e3 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathException.idl +++ b/src/3rdparty/webkit/WebCore/xml/XPathException.idl @@ -37,7 +37,7 @@ module xpath { readonly attribute DOMString name; readonly attribute DOMString message; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT // Override in a Mozilla compatible format [DontEnum] DOMString toString(); #endif diff --git a/src/3rdparty/webkit/WebCore/xml/XPathExpression.cpp b/src/3rdparty/webkit/WebCore/xml/XPathExpression.cpp index 446a7ad..6188426 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathExpression.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathExpression.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,9 +30,8 @@ #if ENABLE(XPATH) #include "Document.h" -#include "ExceptionCode.h" -#include "Node.h" #include "PlatformString.h" +#include "XPathException.h" #include "XPathExpressionNode.h" #include "XPathNSResolver.h" #include "XPathParser.h" @@ -67,17 +66,21 @@ PassRefPtr<XPathResult> XPathExpression::evaluate(Node* contextNode, unsigned sh 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.hadTypeConversionError = false; + RefPtr<XPathResult> result = XPathResult::create(contextNode->document(), 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 (evaluationContext.hadTypeConversionError) { + // It is not specified what to do if type conversion fails while evaluating an expression, and INVALID_EXPRESSION_ERR is not exactly right + // when the failure happens in an otherwise valid expression because of a variable. But XPathEvaluator does not support variables, so it's close enough. + ec = XPathException::INVALID_EXPRESSION_ERR; + return 0; + } + if (type != XPathResult::ANY_TYPE) { ec = 0; result->convertTo(type, ec); diff --git a/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.cpp b/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.cpp index 647c6af..4656f8d 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.cpp @@ -30,7 +30,6 @@ #if ENABLE(XPATH) #include "Node.h" -#include "XPathValue.h" #include <wtf/StdLibExtras.h> namespace WebCore { @@ -43,6 +42,9 @@ EvaluationContext& Expression::evaluationContext() } Expression::Expression() + : m_isContextNodeSensitive(false) + , m_isContextPositionSensitive(false) + , m_isContextSizeSensitive(false) { } diff --git a/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.h b/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.h index 9c5f79b..d12b451 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathExpressionNode.h @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,23 +31,21 @@ #include "StringHash.h" #include "Node.h" +#include "XPathValue.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; + bool hadTypeConversionError; }; class ParseNode { @@ -64,7 +62,22 @@ namespace WebCore { virtual Value evaluate() const = 0; - void addSubExpression(Expression* expr) { m_subExpressions.append(expr); } + void addSubExpression(Expression* expr) + { + m_subExpressions.append(expr); + m_isContextNodeSensitive |= expr->m_isContextNodeSensitive; + m_isContextPositionSensitive |= expr->m_isContextPositionSensitive; + m_isContextSizeSensitive |= expr->m_isContextSizeSensitive; + } + + bool isContextNodeSensitive() const { return m_isContextNodeSensitive; } + bool isContextPositionSensitive() const { return m_isContextPositionSensitive; } + bool isContextSizeSensitive() const { return m_isContextSizeSensitive; } + void setIsContextNodeSensitive(bool value) { m_isContextNodeSensitive = value; } + void setIsContextPositionSensitive(bool value) { m_isContextPositionSensitive = value; } + void setIsContextSizeSensitive(bool value) { m_isContextSizeSensitive = value; } + + virtual Value::Type resultType() const = 0; protected: unsigned subExprCount() const { return m_subExpressions.size(); } @@ -73,6 +86,11 @@ namespace WebCore { private: Vector<Expression*> m_subExpressions; + + // Evaluation details that can be used for optimization. + bool m_isContextNodeSensitive; + bool m_isContextPositionSensitive; + bool m_isContextSizeSensitive; }; } diff --git a/src/3rdparty/webkit/WebCore/xml/XPathFunctions.cpp b/src/3rdparty/webkit/WebCore/xml/XPathFunctions.cpp index 841b436..da39443 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathFunctions.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathFunctions.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> * * Redistribution and use in source and binary forms, with or without @@ -32,7 +32,8 @@ #include "Document.h" #include "Element.h" -#include "NamedAttrMap.h" +#include "NamedNodeMap.h" +#include "ProcessingInstruction.h" #include "XMLNames.h" #include "XPathUtil.h" #include "XPathValue.h" @@ -74,110 +75,157 @@ static HashMap<String, FunctionRec>* functionMap; class FunLast : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } +public: + FunLast() { setIsContextSizeSensitive(true); } }; class FunPosition : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } +public: + FunPosition() { setIsContextPositionSensitive(true); } }; class FunCount : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } }; class FunId : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NodeSetValue; } }; class FunLocalName : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } +public: + FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node. }; class FunNamespaceURI : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } +public: + FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node. }; class FunName : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } +public: + FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node. }; class FunString : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } +public: + FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node. }; class FunConcat : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } }; class FunStartsWith : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } }; class FunContains : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } }; class FunSubstringBefore : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } }; class FunSubstringAfter : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } }; class FunSubstring : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } }; class FunStringLength : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } +public: + FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node. }; class FunNormalizeSpace : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } +public: + FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node. }; class FunTranslate : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } }; class FunBoolean : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } }; class FunNot : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } }; class FunTrue : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } }; class FunFalse : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } }; class FunLang : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::BooleanValue; } +public: + FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node. }; class FunNumber : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } +public: + FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node. }; class FunSum : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } }; class FunFloor : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } }; class FunCeiling : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } }; class FunRound : public Function { virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } public: static double round(double); }; @@ -246,8 +294,13 @@ inline bool Interval::contains(int value) const void Function::setArguments(const Vector<Expression*>& args) { - Vector<Expression*>::const_iterator end = args.end(); + ASSERT(!subExprCount()); + + // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive. + if (m_name != "lang" && !args.isEmpty()) + setIsContextNodeSensitive(false); + Vector<Expression*>::const_iterator end = args.end(); for (Vector<Expression*>::const_iterator it = args.begin(); it != end; it++) addSubExpression(*it); } @@ -310,71 +363,67 @@ Value FunId::evaluate() const return Value(result, Value::adopt); } +static inline String expandedNameLocalPart(Node* node) +{ + // The local part of an XPath expanded-name matches DOM local name for most node types, except for namespace nodes and processing instruction nodes. + ASSERT(node->nodeType() != Node::XPATH_NAMESPACE_NODE); // Not supported yet. + if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) + return static_cast<ProcessingInstruction*>(node)->target(); + return node->localName().string(); +} + +static inline String expandedName(Node* node) +{ + const AtomicString& prefix = node->prefix(); + return prefix.isEmpty() ? expandedNameLocalPart(node) : prefix + ":" + expandedNameLocalPart(node); +} + 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 ""; + Node* node = a.toNodeSet().firstNode(); + return node ? expandedNameLocalPart(node) : ""; } - if (!node) - node = evaluationContext().node.get(); - - return node->localName().string(); + return expandedNameLocalPart(evaluationContext().node.get()); } 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 ""; + Node* node = a.toNodeSet().firstNode(); + return node ? node->namespaceURI().string() : ""; } - if (!node) - node = evaluationContext().node.get(); - - return node->namespaceURI().string(); + return evaluationContext().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 ""; + Node* node = a.toNodeSet().firstNode(); + return node ? expandedName(node) : ""; } - if (!node) - node = evaluationContext().node.get(); - - const AtomicString& prefix = node->prefix(); - return prefix.isEmpty() ? node->localName().string() : prefix + ":" + node->localName(); + return expandedName(evaluationContext().node.get()); } Value FunCount::evaluate() const { Value a = arg(0)->evaluate(); - if (!a.isNodeSet()) - return 0.0; - return double(a.toNodeSet().size()); } @@ -534,30 +583,30 @@ Value FunLang::evaluate() const { String lang = arg(0)->evaluate().toString(); - RefPtr<Node> langNode = 0; + Attribute* languageAttribute = 0; Node* node = evaluationContext().node.get(); while (node) { - NamedAttrMap* attrs = node->attributes(); + NamedNodeMap* attrs = node->attributes(); if (attrs) - langNode = attrs->getNamedItemNS(XMLNames::xmlNamespaceURI, "lang"); - if (langNode) + languageAttribute = attrs->getAttributeItem(XMLNames::langAttr); + if (languageAttribute) break; node = node->parentNode(); } - if (!langNode) + if (!languageAttribute) return false; - String langNodeValue = langNode->nodeValue(); + String langValue = languageAttribute->value(); while (true) { - if (equalIgnoringCase(langNodeValue, lang)) + if (equalIgnoringCase(langValue, lang)) return true; // Remove suffixes one by one. - int index = langNodeValue.reverseFind('-'); + int index = langValue.reverseFind('-'); if (index == -1) break; - langNodeValue = langNodeValue.left(index); + langValue = langValue.left(index); } return false; diff --git a/src/3rdparty/webkit/WebCore/xml/XPathFunctions.h b/src/3rdparty/webkit/WebCore/xml/XPathFunctions.h index f22d3ef..62d687f 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathFunctions.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathFunctions.h @@ -1,6 +1,6 @@ /* - * functions.h - Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,7 +39,6 @@ namespace WebCore { 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); } @@ -52,11 +51,10 @@ namespace WebCore { Function* createFunction(const String& name, const Vector<Expression*>& args = Vector<Expression*>()); - } + } // namespace XPath -} +} // namespace WebCore #endif // ENABLE(XPATH) -#endif // XPath_Functions_H - +#endif // XPathFunctions_h diff --git a/src/3rdparty/webkit/WebCore/xml/XPathGrammar.y b/src/3rdparty/webkit/WebCore/xml/XPathGrammar.y index 7b21038..15a859b 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathGrammar.y +++ b/src/3rdparty/webkit/WebCore/xml/XPathGrammar.y @@ -68,8 +68,8 @@ using namespace XPath; %{ -int xpathyylex(YYSTYPE* yylval) { return Parser::current()->lex(yylval); } -void xpathyyerror(const char*) { } +static int xpathyylex(YYSTYPE* yylval) { return Parser::current()->lex(yylval); } +static void xpathyyerror(const char*) { } %} diff --git a/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.cpp b/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.cpp index e29c096..ba9423e 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.cpp @@ -162,7 +162,7 @@ void NodeSet::sort() const // 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); + sortedNodes.reserveInitialCapacity(nodeCount); for (unsigned i = 0; i < nodeCount; ++i) sortedNodes.append(parentMatrix[i][0]); diff --git a/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.h b/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.h index 2ab6f1f..1130488 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathNodeSet.h @@ -39,17 +39,14 @@ namespace WebCore { 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; } + NodeSet() : m_isSorted(true), m_subtreesAreDisjoint(false) { } 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); } + void swap(NodeSet& other) { std::swap(m_isSorted, other.m_isSorted); std::swap(m_subtreesAreDisjoint, other.m_subtreesAreDisjoint); 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); } @@ -62,16 +59,21 @@ namespace WebCore { // 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. + // NodeSet itself doesn't check if it contains nodes in document order - the caller should tell it if it does not. void markSorted(bool isSorted) { m_isSorted = isSorted; } - bool isSorted() const { return m_isSorted; } + bool isSorted() const { return m_isSorted || m_nodes.size() < 2; } void sort() const; + // No node in the set is ancestor of another. Unlike m_isSorted, this is assumed to be false, unless the caller sets it to true. + void markSubtreesDisjoint(bool disjoint) { m_subtreesAreDisjoint = disjoint; } + bool subtreesAreDisjoint() const { return m_subtreesAreDisjoint || m_nodes.size() < 2; } + void reverse(); private: bool m_isSorted; + bool m_subtreesAreDisjoint; Vector<RefPtr<Node> > m_nodes; }; diff --git a/src/3rdparty/webkit/WebCore/xml/XPathPath.cpp b/src/3rdparty/webkit/WebCore/xml/XPathPath.cpp index bc7b153..1a7ed3f 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathPath.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathPath.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,9 @@ namespace XPath { Filter::Filter(Expression* expr, const Vector<Predicate*>& predicates) : m_expr(expr), m_predicates(predicates) { + setIsContextNodeSensitive(m_expr->isContextNodeSensitive()); + setIsContextPositionSensitive(m_expr->isContextPositionSensitive()); + setIsContextSizeSensitive(m_expr->isContextSizeSensitive()); } Filter::~Filter() @@ -53,9 +56,6 @@ Value Filter::evaluate() const { Value v = m_expr->evaluate(); - if (!v.isNodeSet()) - return v; - NodeSet& nodes = v.modifiableNodeSet(); nodes.sort(); @@ -83,6 +83,7 @@ Value Filter::evaluate() const LocationPath::LocationPath() : m_absolute(false) { + setIsContextNodeSensitive(true); } LocationPath::~LocationPath() @@ -94,9 +95,8 @@ 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. - */ + // 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(); @@ -111,18 +111,33 @@ Value LocationPath::evaluate() const void LocationPath::evaluate(NodeSet& nodes) const { + bool resultIsSorted = nodes.isSorted(); + for (unsigned i = 0; i < m_steps.size(); i++) { Step* step = m_steps[i]; NodeSet newNodes; HashSet<Node*> newNodesSet; + bool needToCheckForDuplicateNodes = !nodes.subtreesAreDisjoint() || (step->axis() != Step::ChildAxis && step->axis() != Step::SelfAxis + && step->axis() != Step::DescendantAxis && step->axis() != Step::DescendantOrSelfAxis && step->axis() != Step::AttributeAxis); + + if (needToCheckForDuplicateNodes) + resultIsSorted = false; + + // This is a simplified check that can be improved to handle more cases. + if (nodes.subtreesAreDisjoint() && (step->axis() == Step::ChildAxis || step->axis() == Step::SelfAxis)) + newNodes.markSubtreesDisjoint(true); + for (unsigned j = 0; j < nodes.size(); j++) { NodeSet matches; step->evaluate(nodes[j], matches); - + + if (!matches.isSorted()) + resultIsSorted = false; + for (size_t nodeIndex = 0; nodeIndex < matches.size(); ++nodeIndex) { Node* node = matches[nodeIndex]; - if (newNodesSet.add(node).second) + if (!needToCheckForDuplicateNodes || newNodesSet.add(node).second) newNodes.append(node); } } @@ -130,53 +145,46 @@ void LocationPath::evaluate(NodeSet& nodes) const nodes.swap(newNodes); } - nodes.markSorted(false); + nodes.markSorted(resultIsSorted); } -void LocationPath::optimizeStepPair(unsigned index) +void LocationPath::appendStep(Step* step) { - 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()); + unsigned stepCount = m_steps.size(); + if (stepCount) { + bool dropSecondStep; + optimizeStepPair(m_steps[stepCount - 1], step, dropSecondStep); + if (dropSecondStep) { + delete step; + return; } } -} - -void LocationPath::appendStep(Step* step) -{ + step->optimize(); m_steps.append(step); - - unsigned stepCount = m_steps.size(); - if (stepCount > 1) - optimizeStepPair(stepCount - 2); } void LocationPath::insertFirstStep(Step* step) { + if (m_steps.size()) { + bool dropSecondStep; + optimizeStepPair(step, m_steps[0], dropSecondStep); + if (dropSecondStep) { + delete m_steps[0]; + m_steps[0] = step; + return; + } + } + step->optimize(); m_steps.insert(0, step); - - if (m_steps.size() > 1) - optimizeStepPair(0); } Path::Path(Filter* filter, LocationPath* path) - : m_filter(filter), - m_path(path) + : m_filter(filter) + , m_path(path) { + setIsContextNodeSensitive(filter->isContextNodeSensitive()); + setIsContextPositionSensitive(filter->isContextPositionSensitive()); + setIsContextSizeSensitive(filter->isContextSizeSensitive()); } Path::~Path() diff --git a/src/3rdparty/webkit/WebCore/xml/XPathPath.h b/src/3rdparty/webkit/WebCore/xml/XPathPath.h index 97692b2..dc77971 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathPath.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathPath.h @@ -1,6 +1,6 @@ /* - * path.h - Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,8 +32,6 @@ #include "XPathExpressionNode.h" #include "XPathNodeSet.h" -int xpathyyparse(void*); - namespace WebCore { namespace XPath { @@ -49,6 +47,8 @@ namespace WebCore { virtual Value evaluate() const; private: + virtual Value::Type resultType() const { return Value::NodeSetValue; } + Expression* m_expr; Vector<Predicate*> m_predicates; }; @@ -57,7 +57,7 @@ namespace WebCore { public: LocationPath(); virtual ~LocationPath(); - void setAbsolute(bool value) { m_absolute = value; } + void setAbsolute(bool value) { m_absolute = value; setIsContextNodeSensitive(!m_absolute); } virtual Value evaluate() const; void evaluate(NodeSet& nodes) const; // nodes is an input/output parameter @@ -66,7 +66,7 @@ namespace WebCore { void insertFirstStep(Step* step); private: - void optimizeStepPair(unsigned index); + virtual Value::Type resultType() const { return Value::NodeSetValue; } Vector<Step*> m_steps; bool m_absolute; @@ -81,6 +81,8 @@ namespace WebCore { virtual Value evaluate() const; private: + virtual Value::Type resultType() const { return Value::NodeSetValue; } + Filter* m_filter; LocationPath* m_path; }; diff --git a/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp b/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp index 7b3e4d8..2a6482f 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp @@ -233,8 +233,6 @@ 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(); diff --git a/src/3rdparty/webkit/WebCore/xml/XPathPredicate.h b/src/3rdparty/webkit/WebCore/xml/XPathPredicate.h index 8d1b0d8..6c9d413 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathPredicate.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathPredicate.h @@ -41,6 +41,8 @@ namespace WebCore { Number(double); private: virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } + Value m_value; }; @@ -49,12 +51,15 @@ namespace WebCore { StringExpression(const String&); private: virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::StringValue; } + Value m_value; }; class Negative : public Expression { private: virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } }; class NumericOp : public Expression { @@ -65,6 +70,8 @@ namespace WebCore { NumericOp(Opcode, Expression* lhs, Expression* rhs); private: virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NumberValue; } + Opcode m_opcode; }; @@ -74,7 +81,9 @@ namespace WebCore { EqTestOp(Opcode, Expression* lhs, Expression* rhs); virtual Value evaluate() const; private: + virtual Value::Type resultType() const { return Value::BooleanValue; } bool compare(const Value&, const Value&) const; + Opcode m_opcode; }; @@ -83,14 +92,17 @@ namespace WebCore { enum Opcode { OP_And, OP_Or }; LogicalOp(Opcode, Expression* lhs, Expression* rhs); private: + virtual Value::Type resultType() const { return Value::BooleanValue; } bool shortCircuitOn() const; virtual Value evaluate() const; + Opcode m_opcode; }; class Union : public Expression { private: virtual Value evaluate() const; + virtual Value::Type resultType() const { return Value::NodeSetValue; } }; class Predicate : Noncopyable { @@ -98,6 +110,10 @@ namespace WebCore { Predicate(Expression*); ~Predicate(); bool evaluate() const; + + bool isContextPositionSensitive() const { return m_expr->isContextPositionSensitive() || m_expr->resultType() == Value::NumberValue; } + bool isContextSizeSensitive() const { return m_expr->isContextSizeSensitive(); } + private: Expression* m_expr; }; diff --git a/src/3rdparty/webkit/WebCore/xml/XPathResult.cpp b/src/3rdparty/webkit/WebCore/xml/XPathResult.cpp index 285350e..b608280 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathResult.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathResult.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,9 +29,8 @@ #if ENABLE(XPATH) -#include "EventListener.h" -#include "EventNames.h" -#include "EventTargetNode.h" +#include "Document.h" +#include "Node.h" #include "ExceptionCode.h" #include "XPathEvaluator.h" #include "XPathException.h" @@ -40,22 +39,9 @@ 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) +XPathResult::XPathResult(Document* document, 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; @@ -70,7 +56,8 @@ XPathResult::XPathResult(EventTargetNode* eventTarget, const Value& value) m_resultType = UNORDERED_NODE_ITERATOR_TYPE; m_nodeSetPosition = 0; m_nodeSet = m_value.toNodeSet(); - m_invalidIteratorState = false; + m_document = document; + m_domTreeVersion = document->domTreeVersion(); return; } ASSERT_NOT_REACHED(); @@ -78,8 +65,6 @@ XPathResult::XPathResult(EventTargetNode* eventTarget, const Value& value) XPathResult::~XPathResult() { - if (m_eventTarget) - m_eventTarget->removeEventListener(eventNames().DOMSubtreeModifiedEvent, m_eventListener.get(), false); } void XPathResult::convertTo(unsigned short type, ExceptionCode& ec) @@ -174,24 +159,13 @@ Node* XPathResult::singleNodeValue(ExceptionCode& ec) const 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; + + ASSERT(m_document); + return m_document->domTreeVersion() != m_domTreeVersion; } unsigned long XPathResult::snapshotLength(ExceptionCode& ec) const @@ -211,7 +185,7 @@ Node* XPathResult::iterateNext(ExceptionCode& ec) return 0; } - if (m_invalidIteratorState) { + if (invalidIteratorState()) { ec = INVALID_STATE_ERR; return 0; } diff --git a/src/3rdparty/webkit/WebCore/xml/XPathResult.h b/src/3rdparty/webkit/WebCore/xml/XPathResult.h index ecd5cac..3b91d66 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathResult.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathResult.h @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,15 +29,14 @@ #if ENABLE(XPATH) -#include <wtf/RefCounted.h> #include "XPathValue.h" +#include <wtf/RefCounted.h> namespace WebCore { typedef int ExceptionCode; - class EventListener; - class EventTargetNode; + class Document; class Node; class String; @@ -56,7 +55,7 @@ namespace WebCore { FIRST_ORDERED_NODE_TYPE = 9 }; - static PassRefPtr<XPathResult> create(EventTargetNode* eventTarget, const XPath::Value& value) { return adoptRef(new XPathResult(eventTarget, value)); } + static PassRefPtr<XPathResult> create(Document* document, const XPath::Value& value) { return adoptRef(new XPathResult(document, value)); } ~XPathResult(); void convertTo(unsigned short type, ExceptionCode&); @@ -73,21 +72,18 @@ namespace WebCore { Node* iterateNext(ExceptionCode&); Node* snapshotItem(unsigned long index, ExceptionCode&); - void invalidateIteratorState(); - private: - XPathResult(EventTargetNode*, const XPath::Value&); + XPathResult(Document*, 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; + RefPtr<Document> m_document; + unsigned m_domTreeVersion; }; -} +} // namespace WebCore #endif // ENABLE(XPATH) diff --git a/src/3rdparty/webkit/WebCore/xml/XPathStep.cpp b/src/3rdparty/webkit/WebCore/xml/XPathStep.cpp index abdcba5..411b616 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathStep.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathStep.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> * * Redistribution and use in source and binary forms, with or without @@ -30,10 +30,10 @@ #if ENABLE(XPATH) +#include "Attr.h" #include "Document.h" #include "Element.h" -#include "NamedAttrMap.h" -#include "XPathNSResolver.h" +#include "NamedNodeMap.h" #include "XPathParser.h" #include "XPathUtil.h" @@ -50,14 +50,74 @@ Step::Step(Axis axis, const NodeTest& nodeTest, const Vector<Predicate*>& predic Step::~Step() { deleteAllValues(m_predicates); + deleteAllValues(m_nodeTest.mergedPredicates()); +} + +void Step::optimize() +{ + // Evaluate predicates as part of node test if possible to avoid building unnecessary NodeSets. + // E.g., there is no need to build a set of all "foo" nodes to evaluate "foo[@bar]", we can check the predicate while enumerating. + // This optimization can be applied to predicates that are not context node list sensitive, or to first predicate that is only context position sensitive, e.g. foo[position() mod 2 = 0]. + Vector<Predicate*> remainingPredicates; + for (size_t i = 0; i < m_predicates.size(); ++i) { + Predicate* predicate = m_predicates[i]; + if ((!predicate->isContextPositionSensitive() || m_nodeTest.mergedPredicates().isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty()) { + m_nodeTest.mergedPredicates().append(predicate); + } else + remainingPredicates.append(predicate); + } + swap(remainingPredicates, m_predicates); +} + +void optimizeStepPair(Step* first, Step* second, bool& dropSecondStep) +{ + dropSecondStep = false; + + if (first->m_axis == Step::DescendantOrSelfAxis + && first->m_nodeTest.kind() == Step::NodeTest::AnyNodeTest + && !first->m_predicates.size() + && !first->m_nodeTest.mergedPredicates().size()) { + + ASSERT(first->m_nodeTest.data().isEmpty()); + ASSERT(first->m_nodeTest.namespaceURI().isEmpty()); + + // Optimize the common case of "//" AKA /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest. + if (second->m_axis == Step::ChildAxis && second->predicatesAreContextListInsensitive()) { + first->m_axis = Step::DescendantAxis; + first->m_nodeTest = Step::NodeTest(second->m_nodeTest.kind(), second->m_nodeTest.data(), second->m_nodeTest.namespaceURI()); + swap(second->m_nodeTest.mergedPredicates(), first->m_nodeTest.mergedPredicates()); + swap(second->m_predicates, first->m_predicates); + first->optimize(); + dropSecondStep = true; + } + } +} + +bool Step::predicatesAreContextListInsensitive() const +{ + for (size_t i = 0; i < m_predicates.size(); ++i) { + Predicate* predicate = m_predicates[i]; + if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive()) + return false; + } + + for (size_t i = 0; i < m_nodeTest.mergedPredicates().size(); ++i) { + Predicate* predicate = m_nodeTest.mergedPredicates()[i]; + if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive()) + return false; + } + + return true; } void Step::evaluate(Node* context, NodeSet& nodes) const { - nodesInAxis(context, nodes); - EvaluationContext& evaluationContext = Expression::evaluationContext(); - + evaluationContext.position = 0; + + nodesInAxis(context, nodes); + + // Check predicates that couldn't be merged into node test. for (unsigned i = 0; i < m_predicates.size(); i++) { Predicate* predicate = m_predicates[i]; @@ -68,7 +128,7 @@ void Step::evaluate(Node* context, NodeSet& nodes) const for (unsigned j = 0; j < nodes.size(); j++) { Node* node = nodes[j]; - Expression::evaluationContext().node = node; + evaluationContext.node = node; evaluationContext.size = nodes.size(); evaluationContext.position = j + 1; if (predicate->evaluate()) @@ -79,6 +139,95 @@ void Step::evaluate(Node* context, NodeSet& nodes) const } } +static inline Node::NodeType primaryNodeType(Step::Axis axis) +{ + switch (axis) { + case Step::AttributeAxis: + return Node::ATTRIBUTE_NODE; + case Step::NamespaceAxis: + return Node::XPATH_NAMESPACE_NODE; + default: + return Node::ELEMENT_NODE; + } +} + +// Evaluate NodeTest without considering merged predicates. +static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest) +{ + switch (nodeTest.kind()) { + case Step::NodeTest::TextNodeTest: + return node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE; + case Step::NodeTest::CommentNodeTest: + return node->nodeType() == Node::COMMENT_NODE; + case Step::NodeTest::ProcessingInstructionNodeTest: { + const AtomicString& name = nodeTest.data(); + return node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node->nodeName() == name); + } + case Step::NodeTest::AnyNodeTest: + return true; + case Step::NodeTest::NameTest: { + const AtomicString& name = nodeTest.data(); + const AtomicString& namespaceURI = nodeTest.namespaceURI(); + + if (axis == Step::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 == starAtom) + return namespaceURI.isEmpty() || node->namespaceURI() == namespaceURI; + + return node->localName() == name && node->namespaceURI() == namespaceURI; + } + + // Node test on the namespace axis is not implemented yet, the caller has a check for it. + ASSERT(axis != Step::NamespaceAxis); + + // For other axes, the principal node type is element. + ASSERT(primaryNodeType(axis) == Node::ELEMENT_NODE); + if (node->nodeType() != Node::ELEMENT_NODE) + return false; + + if (name == starAtom) + return namespaceURI.isEmpty() || namespaceURI == node->namespaceURI(); + + if (node->isHTMLElement() && node->document()->isHTMLDocument()) { + // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively. + return equalIgnoringCase(static_cast<Element*>(node)->localName(), name) && (namespaceURI.isNull() || namespaceURI == node->namespaceURI()); + } + return static_cast<Element*>(node)->hasLocalName(name) && namespaceURI == node->namespaceURI(); + } + } + ASSERT_NOT_REACHED(); + return false; +} + +static inline bool nodeMatches(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest) +{ + if (!nodeMatchesBasicTest(node, axis, nodeTest)) + return false; + + EvaluationContext& evaluationContext = Expression::evaluationContext(); + + // Only the first merged predicate may depend on position. + ++evaluationContext.position; + + const Vector<Predicate*>& mergedPredicates = nodeTest.mergedPredicates(); + for (unsigned i = 0; i < mergedPredicates.size(); i++) { + Predicate* predicate = mergedPredicates[i]; + + evaluationContext.node = node; + // No need to set context size - we only get here when evaluating predicates that do not depend on it. + if (!predicate->evaluate()) + return false; + } + + return true; +} + +// Result nodes are ordered in axis order. Node test (including merged predicates) is applied. void Step::nodesInAxis(Node* context, NodeSet& nodes) const { ASSERT(nodes.isEmpty()); @@ -88,7 +237,7 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const return; for (Node* n = context->firstChild(); n; n = n->nextSibling()) - if (nodeMatches(n)) + if (nodeMatches(n, ChildAxis, m_nodeTest)) nodes.append(n); return; case DescendantAxis: @@ -96,17 +245,17 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const return; for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context)) - if (nodeMatches(n)) + if (nodeMatches(n, DescendantAxis, m_nodeTest)) nodes.append(n); return; case ParentAxis: if (context->isAttributeNode()) { Node* n = static_cast<Attr*>(context)->ownerElement(); - if (nodeMatches(n)) + if (nodeMatches(n, ParentAxis, m_nodeTest)) nodes.append(n); } else { Node* n = context->parentNode(); - if (n && nodeMatches(n)) + if (n && nodeMatches(n, ParentAxis, m_nodeTest)) nodes.append(n); } return; @@ -114,11 +263,11 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const Node* n = context; if (context->isAttributeNode()) { n = static_cast<Attr*>(context)->ownerElement(); - if (nodeMatches(n)) + if (nodeMatches(n, AncestorAxis, m_nodeTest)) nodes.append(n); } for (n = n->parentNode(); n; n = n->parentNode()) - if (nodeMatches(n)) + if (nodeMatches(n, AncestorAxis, m_nodeTest)) nodes.append(n); nodes.markSorted(false); return; @@ -129,7 +278,7 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const return; for (Node* n = context->nextSibling(); n; n = n->nextSibling()) - if (nodeMatches(n)) + if (nodeMatches(n, FollowingSiblingAxis, m_nodeTest)) nodes.append(n); return; case PrecedingSiblingAxis: @@ -138,7 +287,7 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const return; for (Node* n = context->previousSibling(); n; n = n->previousSibling()) - if (nodeMatches(n)) + if (nodeMatches(n, PrecedingSiblingAxis, m_nodeTest)) nodes.append(n); nodes.markSorted(false); @@ -147,15 +296,15 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const if (context->isAttributeNode()) { Node* p = static_cast<Attr*>(context)->ownerElement(); while ((p = p->traverseNextNode())) - if (nodeMatches(p)) + if (nodeMatches(p, FollowingAxis, m_nodeTest)) 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)) + if (nodeMatches(n, FollowingAxis, m_nodeTest)) nodes.append(n); for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n)) - if (nodeMatches(c)) + if (nodeMatches(c, FollowingAxis, m_nodeTest)) nodes.append(c); } } @@ -168,7 +317,7 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const Node* n = context; while (Node* parent = n->parent()) { for (n = n->traversePreviousNode(); n != parent; n = n->traversePreviousNode()) - if (nodeMatches(n)) + if (nodeMatches(n, PrecedingAxis, m_nodeTest)) nodes.append(n); n = parent; } @@ -180,21 +329,23 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const return; // Avoid lazily creating attribute nodes for attributes that we do not need anyway. - if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != "*") { + if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) { 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()); + if (n && n->namespaceURI() != "http://www.w3.org/2000/xmlns/") { // In XPath land, namespace nodes are not accessible on the attribute axis. + if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates. + nodes.append(n.release()); + } return; } - NamedAttrMap* attrs = context->attributes(); + NamedNodeMap* 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()); + for (unsigned i = 0; i < attrs->length(); ++i) { + RefPtr<Attr> attr = attrs->attributeItem(i)->createAttrIfNeeded(static_cast<Element*>(context)); + if (nodeMatches(attr.get(), AttributeAxis, m_nodeTest)) + nodes.append(attr.release()); } return; } @@ -202,30 +353,30 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const // XPath namespace nodes are not implemented yet. return; case SelfAxis: - if (nodeMatches(context)) + if (nodeMatches(context, SelfAxis, m_nodeTest)) nodes.append(context); return; case DescendantOrSelfAxis: - if (nodeMatches(context)) + if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest)) 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)) + if (nodeMatches(n, DescendantOrSelfAxis, m_nodeTest)) nodes.append(n); return; case AncestorOrSelfAxis: { - if (nodeMatches(context)) + if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest)) nodes.append(context); Node* n = context; if (context->isAttributeNode()) { n = static_cast<Attr*>(context)->ownerElement(); - if (nodeMatches(n)) + if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest)) nodes.append(n); } for (n = n->parentNode(); n; n = n->parentNode()) - if (nodeMatches(n)) + if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest)) nodes.append(n); nodes.markSorted(false); @@ -236,70 +387,6 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const } -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; - } -} - } } diff --git a/src/3rdparty/webkit/WebCore/xml/XPathStep.h b/src/3rdparty/webkit/WebCore/xml/XPathStep.h index f1420d0..1c26327 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathStep.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathStep.h @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,8 +52,7 @@ namespace WebCore { class NodeTest { public: enum Kind { - TextNodeTest, CommentNodeTest, ProcessingInstructionNodeTest, AnyNodeTest, NameTest, - ElementNodeTest // XPath 2.0 + TextNodeTest, CommentNodeTest, ProcessingInstructionNodeTest, AnyNodeTest, NameTest }; NodeTest(Kind kind) : m_kind(kind) {} @@ -61,44 +60,48 @@ namespace WebCore { 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; } + const AtomicString& data() const { return m_data; } + const AtomicString& namespaceURI() const { return m_namespaceURI; } + Vector<Predicate*>& mergedPredicates() { return m_mergedPredicates; } + const Vector<Predicate*>& mergedPredicates() const { return m_mergedPredicates; } private: Kind m_kind; - String m_data; - String m_namespaceURI; + AtomicString m_data; + AtomicString m_namespaceURI; + + // When possible, we merge some or all predicates with node test for better performance. + Vector<Predicate*> m_mergedPredicates; }; Step(Axis, const NodeTest& nodeTest, const Vector<Predicate*>& predicates = Vector<Predicate*>()); ~Step(); + void optimize(); + 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; } - + const NodeTest& nodeTest() const { return m_nodeTest; } + private: + friend void optimizeStepPair(Step*, Step*, bool&); + bool predicatesAreContextListInsensitive() const; + 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; }; + void optimizeStepPair(Step*, Step*, bool& dropSecondStep); } } #endif // ENABLE(XPATH) -#endif // XPath_Step_H +#endif // XPathStep_h diff --git a/src/3rdparty/webkit/WebCore/xml/XPathUtil.cpp b/src/3rdparty/webkit/WebCore/xml/XPathUtil.cpp index ab4b1d4..0100bea 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathUtil.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathUtil.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2005 Frerich Raabe <raabe@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2005 Frerich Raabe <raabe@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,13 +51,17 @@ String stringValue(Node* 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(); + Vector<UChar> result; + result.reserveCapacity(1024); - return str; + for (Node* n = node->firstChild(); n; n = n->traverseNextNode(node)) { + if (n->isTextNode()) { + const String& nodeValue = n->nodeValue(); + result.append(nodeValue.characters(), nodeValue.length()); + } + } + + return String::adopt(result); } } diff --git a/src/3rdparty/webkit/WebCore/xml/XPathValue.cpp b/src/3rdparty/webkit/WebCore/xml/XPathValue.cpp index bac0e13..29e211e 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathValue.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XPathValue.cpp @@ -30,11 +30,11 @@ #if ENABLE(XPATH) #include "Node.h" +#include "XPathExpressionNode.h" #include "XPathUtil.h" - +#include <limits> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> -#include <limits> using std::numeric_limits; @@ -45,6 +45,9 @@ const Value::AdoptTag Value::adopt = {}; const NodeSet& Value::toNodeSet() const { + if (!isNodeSet()) + Expression::evaluationContext().hadTypeConversionError = true; + if (!m_data) { DEFINE_STATIC_LOCAL(NodeSet, emptyNodeSet, ()); return emptyNodeSet; @@ -55,6 +58,9 @@ const NodeSet& Value::toNodeSet() const NodeSet& Value::modifiableNodeSet() { + if (!isNodeSet()) + Expression::evaluationContext().hadTypeConversionError = true; + if (!m_data) m_data = ValueData::create(); @@ -86,8 +92,18 @@ double Value::toNumber() const case NumberValue: return m_number; case StringValue: { + const String& str = m_data->m_string.simplifyWhiteSpace(); + + // String::toDouble() supports exponential notation, which is not allowed in XPath. + unsigned len = str.length(); + for (unsigned i = 0; i < len; ++i) { + UChar c = str[i]; + if (!isASCIIDigit(c) && c != '.' && c != '-') + return numeric_limits<double>::quiet_NaN(); + } + bool canConvert; - double value = m_data->m_string.simplifyWhiteSpace().toDouble(&canConvert); + double value = str.toDouble(&canConvert); if (canConvert) return value; return numeric_limits<double>::quiet_NaN(); diff --git a/src/3rdparty/webkit/WebCore/xml/XPathVariableReference.h b/src/3rdparty/webkit/WebCore/xml/XPathVariableReference.h index 811176d..5e5a59a 100644 --- a/src/3rdparty/webkit/WebCore/xml/XPathVariableReference.h +++ b/src/3rdparty/webkit/WebCore/xml/XPathVariableReference.h @@ -33,12 +33,14 @@ namespace WebCore { namespace XPath { - + + // Variable references are not used with XPathEvaluator. class VariableReference : public Expression { public: VariableReference(const String& name); private: virtual Value evaluate() const; + virtual Value::Type resultType() const { ASSERT_NOT_REACHED(); return Value::NumberValue; } String m_name; }; diff --git a/src/3rdparty/webkit/WebCore/xml/XSLStyleSheet.cpp b/src/3rdparty/webkit/WebCore/xml/XSLStyleSheet.cpp index 0d112a5..b7d52f8 100644 --- a/src/3rdparty/webkit/WebCore/xml/XSLStyleSheet.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XSLStyleSheet.cpp @@ -30,11 +30,12 @@ #include "DocLoader.h" #include "Document.h" #include "Frame.h" -#include "loader.h" #include "Node.h" #include "XMLTokenizer.h" +#include "XMLTokenizerScope.h" #include "XSLImportRule.h" #include "XSLTProcessor.h" +#include "loader.h" #include <libxml/uri.h> #include <libxslt/xsltutils.h> @@ -138,7 +139,6 @@ bool XSLStyleSheet::parseString(const String& string, bool) // 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; @@ -146,8 +146,8 @@ bool XSLStyleSheet::parseString(const String& string, bool) Console* console = 0; if (Frame* frame = ownerDocument()->frame()) console = frame->domWindow()->console(); - xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc); - xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc); + + XMLTokenizerScope scope(docLoader(), XSLTProcessor::genericErrorFunc, XSLTProcessor::parseErrorFunc, console); const char* buffer = reinterpret_cast<const char*>(string.characters()); int size = string.length() * sizeof(UChar); @@ -171,13 +171,9 @@ bool XSLStyleSheet::parseString(const String& string, bool) BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA); xmlFreeParserCtxt(ctxt); - - loadChildSheets(); - xmlSetStructuredErrorFunc(0, 0); - xmlSetGenericErrorFunc(0, 0); + loadChildSheets(); - setLoaderForLibXMLCallbacks(0); return m_stylesheetDoc; } diff --git a/src/3rdparty/webkit/WebCore/xml/XSLTExtensions.cpp b/src/3rdparty/webkit/WebCore/xml/XSLTExtensions.cpp index d89f08b..069ddd8 100644 --- a/src/3rdparty/webkit/WebCore/xml/XSLTExtensions.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XSLTExtensions.cpp @@ -27,6 +27,7 @@ #include "config.h" #if ENABLE(XSLT) +#include "XSLTExtensions.h" #include <libxml/xpathInternals.h> diff --git a/src/3rdparty/webkit/WebCore/xml/XSLTProcessor.cpp b/src/3rdparty/webkit/WebCore/xml/XSLTProcessor.cpp index b644486..3865124 100644 --- a/src/3rdparty/webkit/WebCore/xml/XSLTProcessor.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XSLTProcessor.cpp @@ -55,11 +55,10 @@ #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)) @@ -128,7 +127,7 @@ static xmlDocPtr docLoaderFunc(const xmlChar* uri, bool requestAllowed = globalDocLoader->frame() && globalDocLoader->doc()->securityOrigin()->canRequest(url); if (requestAllowed) { - globalDocLoader->frame()->loader()->loadResourceSynchronously(url, error, response, data); + globalDocLoader->frame()->loader()->loadResourceSynchronously(url, AllowStoredCredentials, error, response, data); requestAllowed = globalDocLoader->doc()->securityOrigin()->canRequest(response.url()); } if (!requestAllowed) { @@ -284,7 +283,7 @@ PassRefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourc return result.release(); } -static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Node* sourceNode, Document* outputDoc) +static inline RefPtr<DocumentFragment> createFragmentFromSource(const String& sourceString, const String& sourceMIMEType, Document* outputDoc) { RefPtr<DocumentFragment> fragment = new DocumentFragment(outputDoc); @@ -433,7 +432,7 @@ PassRefPtr<DocumentFragment> XSLTProcessor::transformToFragment(Node* sourceNode if (!transformToString(sourceNode, resultMIMEType, resultString, resultEncoding)) return 0; - return createFragmentFromSource(resultString, resultMIMEType, sourceNode, outputDoc); + return createFragmentFromSource(resultString, resultMIMEType, outputDoc); } void XSLTProcessor::setParameter(const String& /*namespaceURI*/, const String& localName, const String& value) diff --git a/src/3rdparty/webkit/WebCore/xml/XSLTUnicodeSort.cpp b/src/3rdparty/webkit/WebCore/xml/XSLTUnicodeSort.cpp index ed66112..b0b9c72 100644 --- a/src/3rdparty/webkit/WebCore/xml/XSLTUnicodeSort.cpp +++ b/src/3rdparty/webkit/WebCore/xml/XSLTUnicodeSort.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,10 +32,8 @@ #if ENABLE(XSLT) #include "PlatformString.h" - #include <libxslt/templates.h> #include <libxslt/xsltutils.h> - #include <wtf/unicode/Collator.h> #if PLATFORM(MAC) @@ -43,57 +41,29 @@ #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 xsltTransformErrorTrampoline(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char* message, ...) WTF_ATTRIBUTE_PRINTF(4, 5); -static void init_xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char* msg, ...) +void xsltTransformErrorTrampoline(xsltTransformContextPtr context, xsltStylesheetPtr style, xmlNodePtr node, const char* message, ...) { - 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_start(args, message); + char* messageWithArgs; + vasprintf(&messageWithArgs, message, args); va_end(args); - softLink_xsltTransformError(ctxt, style, node, "%s", str); + static void (*xsltTransformErrorPointer)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...) WTF_ATTRIBUTE_PRINTF(4, 5) + = reinterpret_cast<void (*)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...)>(dlsym(libxsltLibrary(), "xsltTransformError")); + xsltTransformErrorPointer(context, style, node, "%s", messageWithArgs); -#if !PLATFORM(WIN_OS) - free(str); -#endif + free(messageWithArgs); } -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 -} +#define xsltTransformError xsltTransformErrorTrampoline #endif |