Commit 696b4e17 authored by brettw@chromium.org's avatar brettw@chromium.org

Reviewed by Eric Seidel.

https://bugs.webkit.org/show_bug.cgi?id=22131

Factor out visited link hashing and types into a new file, LinkHash.
This also changes the hash type to 64 bits, but does not actually use
the extra bits yet.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@38661 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 727f5ef7
2008-11-20 Brett Wilson <brettw@chromium.org>
Reviewed by Eric Seidel.
https://bugs.webkit.org/show_bug.cgi?id=22131
Factor out visited link hashing and types into a new file, LinkHash.
This also changes the hash type to 64 bits, but does not actually use
the extra bits yet.
* WebCore.xcodeproj/project.pbxproj:
(WebCore::CSSStyleSelector::SelectorChecker::checkPseudoState):
(WebCore::CSSStyleSelector::SelectorChecker::visitedStateChanged):
* css/CSSStyleSelector.h:
(WebCore::CSSStyleSelector::visitedStateChanged):
* dom/Document.cpp:
* dom/Document.h:
* page/Page.cpp:
(WebCore::Page::visitedStateChanged):
* page/Page.h:
* page/PageGroup.cpp:
(WebCore::PageGroup::isLinkVisited):
(WebCore::PageGroup::addVisitedLink):
* page/PageGroup.h:
* platform/LinkHash.cpp: Added.
(WebCore::findSlashDotDotSlash):
(WebCore::findSlashSlash):
(WebCore::findSlashDotSlash):
(WebCore::containsColonSlashSlash):
(WebCore::cleanPath):
(WebCore::matchLetter):
(WebCore::needsTrailingSlash):
(WebCore::visitedLinkHash):
* platform/LinkHash.h: Added
(WebCore::LinkHashHash::hash):
(WebCore::LinkHashHash::equal):
(WebCore::LinkHashHash::avoidDeletedValue):
2008-11-21 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
Reviewed by Alexey Proskuryakov.
......@@ -1968,6 +1968,8 @@
A784941B0B5FE507001E237A /* Clipboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A784941A0B5FE507001E237A /* Clipboard.cpp */; };
A795463E0B5C4C80007B438F /* DragDataMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = A795463D0B5C4C80007B438F /* DragDataMac.mm */; };
A79546430B5C4CB4007B438F /* DragData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A79546420B5C4CB4007B438F /* DragData.cpp */; };
A7AD2F870EC89D07008AB002 /* LinkHash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2F850EC89D07008AB002 /* LinkHash.cpp */; };
A7AD2F880EC89D07008AB002 /* LinkHash.h in Headers */ = {isa = PBXBuildFile; fileRef = A7AD2F860EC89D07008AB002 /* LinkHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7B6E69F0B291A9600D0529F /* DragData.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B6E69D0B291A9600D0529F /* DragData.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7CA595D0B27BD9E00FA021D /* DragController.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA595B0B27BD9E00FA021D /* DragController.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7CA595E0B27BD9E00FA021D /* DragController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7CA595C0B27BD9E00FA021D /* DragController.cpp */; };
......@@ -6709,6 +6711,8 @@
A784941A0B5FE507001E237A /* Clipboard.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Clipboard.cpp; sourceTree = "<group>"; };
A795463D0B5C4C80007B438F /* DragDataMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = DragDataMac.mm; sourceTree = "<group>"; };
A79546420B5C4CB4007B438F /* DragData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DragData.cpp; sourceTree = "<group>"; };
A7AD2F850EC89D07008AB002 /* LinkHash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinkHash.cpp; sourceTree = "<group>"; };
A7AD2F860EC89D07008AB002 /* LinkHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinkHash.h; sourceTree = "<group>"; };
A7B6E69D0B291A9600D0529F /* DragData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DragData.h; sourceTree = "<group>"; };
A7CA595B0B27BD9E00FA021D /* DragController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DragController.h; sourceTree = "<group>"; };
A7CA595C0B27BD9E00FA021D /* DragController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DragController.cpp; sourceTree = "<group>"; };
......@@ -13438,6 +13442,8 @@
BCE65BE90EACDF16007E4533 /* Length.h */,
BCFF648F0EAD15C200C1D6F7 /* LengthBox.h */,
BCFF64900EAD15C200C1D6F7 /* LengthSize.h */,
A7AD2F850EC89D07008AB002 /* LinkHash.cpp */,
A7AD2F860EC89D07008AB002 /* LinkHash.h */,
935207BD09BD410A00F2038D /* LocalizedStrings.h */,
A8239DFE09B3CF8A00B60641 /* Logging.cpp */,
A8239DFF09B3CF8A00B60641 /* Logging.h */,
......@@ -16331,6 +16337,7 @@
08CD61BD0ED3929C002DDF51 /* WMLTaskElement.h in Headers */,
084DBAA20ED39D360038C226 /* WMLVariables.h in Headers */,
080081970ED3B2DD00C53BC0 /* WMLAnchorElement.h in Headers */,
A7AD2F880EC89D07008AB002 /* LinkHash.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -18256,6 +18263,7 @@
084DBAA10ED39D360038C226 /* WMLVariables.cpp in Sources */,
080081960ED3B2DD00C53BC0 /* WMLAnchorElement.cpp in Sources */,
934CC0E10ED39D6F00A658F2 /* ScriptValue.cpp in Sources */,
A7AD2F870EC89D07008AB002 /* LinkHash.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -62,6 +62,7 @@
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "HTMLTextAreaElement.h"
#include "LinkHash.h"
#include "MatrixTransformOperation.h"
#include "MediaList.h"
#include "MediaQueryEvaluator.h"
......@@ -852,7 +853,7 @@ PseudoState CSSStyleSelector::SelectorChecker::checkPseudoState(Element* element
if (!checkVisited)
return PseudoAnyLink;
unsigned hash = m_document->visitedLinkHash(*attr);
LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr);
if (!hash)
return PseudoLink;
......@@ -5690,13 +5691,13 @@ void CSSStyleSelector::SelectorChecker::allVisitedStateChanged()
}
}
void CSSStyleSelector::SelectorChecker::visitedStateChanged(unsigned visitedHash)
void CSSStyleSelector::SelectorChecker::visitedStateChanged(LinkHash visitedHash)
{
if (!m_linksCheckedForVisitedState.contains(visitedHash))
return;
for (Node* node = m_document; node; node = node->traverseNextNode()) {
const AtomicString* attr = linkAttribute(node);
if (attr && m_document->visitedLinkHash(*attr) == visitedHash)
if (attr && visitedLinkHash(m_document->baseURL(), *attr) == visitedHash)
node->setChanged();
}
}
......
......@@ -24,6 +24,7 @@
#include "CSSFontSelector.h"
#include "KeyframeList.h"
#include "LinkHash.h"
#include "MediaQueryExp.h"
#include "RenderStyle.h"
#include "StringHash.h"
......@@ -136,7 +137,7 @@ public:
bool affectedByViewportChange() const;
void allVisitedStateChanged() { m_checker.allVisitedStateChanged(); }
void visitedStateChanged(unsigned visitedHash) { m_checker.visitedStateChanged(visitedHash); }
void visitedStateChanged(LinkHash visitedHash) { m_checker.visitedStateChanged(visitedHash); }
void addVariables(CSSVariablesRule* variables);
CSSValue* resolveVariableDependentValue(CSSVariableDependentValue*);
......@@ -191,14 +192,14 @@ public:
bool checkScrollbarPseudoClass(CSSSelector*, RenderStyle::PseudoId& dynamicPseudo) const;
void allVisitedStateChanged();
void visitedStateChanged(unsigned visitedHash);
void visitedStateChanged(LinkHash visitedHash);
Document* m_document;
bool m_strictParsing;
bool m_collectRulesOnly;
RenderStyle::PseudoId m_pseudoStyle;
bool m_documentIsHTML;
mutable HashSet<unsigned, AlreadyHashed> m_linksCheckedForVisitedState;
mutable HashSet<LinkHash, LinkHashHash> m_linksCheckedForVisitedState;
};
private:
......
......@@ -99,7 +99,6 @@
#include "SegmentedString.h"
#include "SelectionController.h"
#include "Settings.h"
#include "StringHash.h"
#include "StyleSheetList.h"
#include "SystemTime.h"
#include "TextEvent.h"
......@@ -4123,176 +4122,6 @@ DOMSelection* Document::getSelection() const
return frame() ? frame()->domWindow()->getSelection() : 0;
}
static inline int findSlashDotDotSlash(const UChar* characters, size_t length)
{
if (length < 4)
return -1;
unsigned loopLimit = length - 3;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/')
return i;
}
return -1;
}
static inline int findSlashSlash(const UChar* characters, size_t length, int position)
{
if (length < 2)
return -1;
unsigned loopLimit = length - 1;
for (unsigned i = position; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '/')
return i;
}
return -1;
}
static inline int findSlashDotSlash(const UChar* characters, size_t length)
{
if (length < 3)
return -1;
unsigned loopLimit = length - 2;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/')
return i;
}
return -1;
}
static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
{
if (length < 3)
return false;
unsigned loopLimit = length - 2;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
return true;
}
return false;
}
static inline void cleanPath(Vector<UChar, 512>& path)
{
// FIXME: Shold not do this in the query or anchor part.
int pos;
while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) {
int prev = reverseFind(path.data(), path.size(), '/', pos - 1);
// don't remove the host, i.e. http://foo.org/../foo.html
if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/'))
path.remove(pos, 3);
else
path.remove(prev, pos - prev + 3);
}
// FIXME: Shold not do this in the query part.
// Set refPos to -2 to mean "I haven't looked for the anchor yet".
// We don't want to waste a function call on the search for the the anchor
// in the vast majority of cases where there is no "//" in the path.
pos = 0;
int refPos = -2;
while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) {
if (refPos == -2)
refPos = find(path.data(), path.size(), '#');
if (refPos > 0 && pos >= refPos)
break;
if (pos == 0 || path[pos - 1] != ':')
path.remove(pos);
else
pos += 2;
}
// FIXME: Shold not do this in the query or anchor part.
while ((pos = findSlashDotSlash(path.data(), path.size())) != -1)
path.remove(pos, 2);
}
static inline bool matchLetter(UChar c, UChar lowercaseLetter)
{
return (c | 0x20) == lowercaseLetter;
}
static inline bool needsTrailingSlash(const UChar* characters, unsigned length)
{
if (length < 6)
return false;
if (!matchLetter(characters[0], 'h')
|| !matchLetter(characters[1], 't')
|| !matchLetter(characters[2], 't')
|| !matchLetter(characters[3], 'p'))
return false;
if (!(characters[4] == ':'
|| (matchLetter(characters[4], 's') && characters[5] == ':')))
return false;
unsigned pos = characters[4] == ':' ? 5 : 6;
// Skip initial two slashes if present.
if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/')
pos += 2;
// Find next slash.
while (pos < length && characters[pos] != '/')
++pos;
return pos == length;
}
unsigned Document::visitedLinkHash(const AtomicString& attributeURL) const
{
const UChar* characters = attributeURL.characters();
unsigned length = attributeURL.length();
if (!length)
return 0;
// This is a poor man's completeURL. Faster with less memory allocation.
// FIXME: It's missing a lot of what completeURL does and a lot of what KURL does.
// For example, it does not handle international domain names properly.
// FIXME: It is wrong that we do not do further processing on strings that have "://" in them:
// 1) The "://" could be in the query or anchor.
// 2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it.
// FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does
// have a query or anchor.
bool hasColonSlashSlash = containsColonSlashSlash(characters, length);
if (hasColonSlashSlash && !needsTrailingSlash(characters, length))
return AlreadyHashed::avoidDeletedValue(attributeURL.string().impl()->hash());
Vector<UChar, 512> buffer;
if (hasColonSlashSlash) {
// FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
// end of the path, *before* the query or anchor.
buffer.append(characters, length);
buffer.append('/');
return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()));
}
switch (characters[0]) {
case '/':
buffer.append(m_baseURL.string().characters(), m_baseURL.pathStart());
break;
case '#':
buffer.append(m_baseURL.string().characters(), m_baseURL.pathEnd());
break;
default:
buffer.append(m_baseURL.string().characters(), m_baseURL.pathAfterLastSlash());
break;
}
buffer.append(characters, length);
cleanPath(buffer);
if (needsTrailingSlash(buffer.data(), buffer.size())) {
// FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
// end of the path, *before* the query or anchor.
buffer.append('/');
}
return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()));
}
#if ENABLE(DATABASE)
void Document::addOpenDatabase(Database* database)
......
......@@ -428,8 +428,6 @@ public:
KURL completeURL(const String&) const;
unsigned visitedLinkHash(const AtomicString& attributeURL) const;
// from cachedObjectClient
virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*);
......
......@@ -493,7 +493,7 @@ void Page::allVisitedStateChanged(PageGroup* group)
}
}
void Page::visitedStateChanged(PageGroup* group, unsigned visitedLinkHash)
void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
{
ASSERT(group);
ASSERT(allPages);
......
......@@ -26,6 +26,7 @@
#include "Chrome.h"
#include "ContextMenuController.h"
#include "FrameLoaderTypes.h"
#include "LinkHash.h"
#include "PlatformString.h"
#if PLATFORM(MAC)
#include "SchedulePair.h"
......@@ -171,7 +172,7 @@ namespace WebCore {
static void removeAllVisitedLinks();
static void allVisitedStateChanged(PageGroup*);
static void visitedStateChanged(PageGroup*, unsigned visitedHash);
static void visitedStateChanged(PageGroup*, LinkHash visitedHash);
#if ENABLE(DOM_STORAGE)
SessionStorage* sessionStorage(bool optionalCreate = true);
......
......@@ -117,7 +117,7 @@ void PageGroup::removePage(Page* page)
m_pages.remove(page);
}
bool PageGroup::isLinkVisited(unsigned visitedLinkHash)
bool PageGroup::isLinkVisited(LinkHash visitedLinkHash)
{
if (!m_visitedLinksPopulated) {
m_visitedLinksPopulated = true;
......@@ -127,10 +127,10 @@ bool PageGroup::isLinkVisited(unsigned visitedLinkHash)
return m_visitedLinkHashes.contains(visitedLinkHash);
}
inline void PageGroup::addVisitedLink(unsigned stringHash)
inline void PageGroup::addVisitedLink(LinkHash stringHash)
{
ASSERT(shouldTrackVisitedLinks);
unsigned visitedLinkHash = AlreadyHashed::avoidDeletedValue(stringHash);
LinkHash visitedLinkHash = LinkHashHash::avoidDeletedValue(stringHash);
if (!m_visitedLinkHashes.add(visitedLinkHash).second)
return;
Page::visitedStateChanged(this, visitedLinkHash);
......
......@@ -28,6 +28,7 @@
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include "LinkHash.h"
#include "StringHash.h"
namespace WebCore {
......@@ -49,7 +50,7 @@ namespace WebCore {
void addPage(Page*);
void removePage(Page*);
bool isLinkVisited(unsigned visitedLinkHash);
bool isLinkVisited(LinkHash);
void addVisitedLink(const KURL&);
void addVisitedLink(const UChar*, size_t);
......@@ -66,12 +67,13 @@ namespace WebCore {
#endif
private:
void addVisitedLink(unsigned stringHash);
void addVisitedLink(LinkHash stringHash);
String m_name;
HashSet<Page*> m_pages;
HashSet<unsigned, AlreadyHashed> m_visitedLinkHashes;
HashSet<LinkHash, LinkHashHash> m_visitedLinkHashes;
bool m_visitedLinksPopulated;
unsigned m_identifier;
......
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* (C) 2006 Alexey Proskuryakov (ap@webkit.org)
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "AtomicString.h"
#include "KURL.h"
#include "LinkHash.h"
#include "PlatformString.h"
#include "StringHash.h"
namespace WebCore {
static inline int findSlashDotDotSlash(const UChar* characters, size_t length)
{
if (length < 4)
return -1;
unsigned loopLimit = length - 3;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/')
return i;
}
return -1;
}
static inline int findSlashSlash(const UChar* characters, size_t length, int position)
{
if (length < 2)
return -1;
unsigned loopLimit = length - 1;
for (unsigned i = position; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '/')
return i;
}
return -1;
}
static inline int findSlashDotSlash(const UChar* characters, size_t length)
{
if (length < 3)
return -1;
unsigned loopLimit = length - 2;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/')
return i;
}
return -1;
}
static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
{
if (length < 3)
return false;
unsigned loopLimit = length - 2;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
return true;
}
return false;
}
static inline void cleanPath(Vector<UChar, 512>& path)
{
// FIXME: Shold not do this in the query or anchor part.
int pos;
while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) {
int prev = reverseFind(path.data(), path.size(), '/', pos - 1);
// don't remove the host, i.e. http://foo.org/../foo.html
if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/'))
path.remove(pos, 3);
else
path.remove(prev, pos - prev + 3);
}
// FIXME: Shold not do this in the query part.
// Set refPos to -2 to mean "I haven't looked for the anchor yet".
// We don't want to waste a function call on the search for the the anchor
// in the vast majority of cases where there is no "//" in the path.
pos = 0;
int refPos = -2;
while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) {
if (refPos == -2)
refPos = find(path.data(), path.size(), '#');
if (refPos > 0 && pos >= refPos)
break;
if (pos == 0 || path[pos - 1] != ':')
path.remove(pos);
else
pos += 2;
}
// FIXME: Shold not do this in the query or anchor part.
while ((pos = findSlashDotSlash(path.data(), path.size())) != -1)
path.remove(pos, 2);
}
static inline bool matchLetter(UChar c, UChar lowercaseLetter)
{
return (c | 0x20) == lowercaseLetter;
}
static inline bool needsTrailingSlash(const UChar* characters, unsigned length)
{
if (length < 6)
return false;
if (!matchLetter(characters[0], 'h')
|| !matchLetter(characters[1], 't')
|| !matchLetter(characters[2], 't')
|| !matchLetter(characters[3], 'p'))
return false;
if (!(characters[4] == ':'
|| (matchLetter(characters[4], 's') && characters[5] == ':')))
return false;
unsigned pos = characters[4] == ':' ? 5 : 6;
// Skip initial two slashes if present.
if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/')
pos += 2;
// Find next slash.
while (pos < length && characters[pos] != '/')
++pos;
return pos == length;
}
LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL)
{
const UChar* characters = attributeURL.characters();
unsigned length = attributeURL.length();
if (!length)
return 0;
// This is a poor man's completeURL. Faster with less memory allocation.
// FIXME: It's missing a lot of what completeURL does and a lot of what KURL does.
// For example, it does not handle international domain names properly.
// FIXME: It is wrong that we do not do further processing on strings that have "://" in them:
// 1) The "://" could be in the query or anchor.
// 2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it.
// FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does
// have a query or anchor.
bool hasColonSlashSlash = containsColonSlashSlash(characters, length);
if (hasColonSlashSlash && !needsTrailingSlash(characters, length))
return AlreadyHashed::avoidDeletedValue(attributeURL.string().impl()->hash());
Vector<UChar, 512> buffer;
if (hasColonSlashSlash) {
// FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
// end of the path, *before* the query or anchor.
buffer.append(characters, length);
buffer.append('/');
return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()));
}
switch (characters[0]) {
case '/':
buffer.append(base.string().characters(), base.pathStart());
break;
case '#':
buffer.append(base.string().characters(), base.pathEnd());
break;
default:
buffer.append(base.string().characters(), base.pathAfterLastSlash());
break;
}
buffer.append(characters, length);
cleanPath(buffer);
if (needsTrailingSlash(buffer.data(), buffer.size())) {
// FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
// end of the path, *before* the query or anchor.
buffer.append('/');
}
return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()));
}
} // namespace WebCore
/*
* Copyright (C) 2008 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LinkHash_h
#define LinkHash_h
#include "StringHash.h"
namespace WebCore {
class AtomicString;
class KURL;
typedef uint64_t LinkHash;
// Use the low 32-bits of the 64-bit LinkHash as the key for HashSets.
struct LinkHashHash {
static unsigned hash(LinkHash key) { return static_cast<unsigned>(key); }
static bool equal(LinkHash a, LinkHash b) { return a == b; }
static const bool safeToCompareToEmptyOrDeleted = true;
// See AlreadyHashed::avoidDeletedValue.