Commit d69216d5 authored by darin@apple.com's avatar darin@apple.com

Reviewed by Antti.

        - fix <rdar://problem/3059610> VIP: links opened in new frame, window, or tab
          should be redrawn as visited immediately
        - fix <rdar://problem/4382809> Going "back" a page doesn't change the color of
          the visited URL at directory.umi
        - fix http://bugs.webkit.org/show_bug.cgi?id=4941
          Visited links should be marked as visited
        - fix http://bugs.webkit.org/show_bug.cgi?id=7960
          REGRESSION: Visited link color doesn't displayed after loading page from cache

        We now mark all links on a page as "changed" at the appropriate times.

        * WebCore.base.exp: Update since I made completeURL be a const member function.

        * css/CSSStyleSelector.cpp: Got rid of some unneeded globals that could be turned
        into locals. Also changed some static data members to file-scoped globals with
        internal linkage. Renamed the globals to get rid of the m_ prefix. Changed the
        prefix on m_styleNotYetAvailable to s_styleNotYetAvailable.
        (WebCore::CSSStyleSelector::CSSStyleSelector): Updated for name changes.
        (WebCore::parseUASheet): Tweak the comment.
        (WebCore::CSSStyleSelector::loadDefaultStyle): Updated for name changes and to
        use local variables instead of globals where possible.
        (WebCore::CSSStyleSelector::checkPseudoState): Made this a member function so
        it can store the link in a hash. Also changed it to have a return value instead
        of having it modify a global variable. Added code to put the hash into a set so
        we can tell later if this is one of the links that affects this page.
        (WebCore::CSSStyleSelector::canShareStyleWithElement): Updated for the change to
        checkPseudoState.
        (WebCore::CSSStyleSelector::matchUARules): Updated for name changes.
        (WebCore::CSSStyleSelector::styleForElement): Ditto.
        (WebCore::CSSStyleSelector::adjustRenderStyle): Ditto.
        (WebCore::CSSStyleSelector::pseudoStyleRulesForElement): Changed code to read
        the SVG style sheet to use a boolean global and put it right here in the function
        since this is the only code that needs to know about it.
        (WebCore::CSSStyleSelector::checkOneSelector): Updated for name changes.
        (WebCore::colorForCSSValue): Moved code inside the function that is not needed
        anywhere else.
        (WebCore::CSSStyleSelector::getColorFromPrimitiveValue): Updaed for the change
        to checkPseudoState.
        (WebCore::CSSStyleSelector::allVisitedStateChanged): Added. Calls setChanged on
        all links if there were any in the set.
        (WebCore::CSSStyleSelector::visitedStateChanged): Added. Calls setChanged on all
        links if the one that changed is in the set.

        * css/CSSStyleSelector.h: Removed unused StyleSelector class and State enum. Made
        CSSStyleSelector derive from Noncopyable. Made lots of member functions private that
        didn't need to be public, and removed others that could be made into non-member
        functions. Changed pseudoStyleRulesForElement to take a const String& instead of
        a StringImpl*. Added new allVisitedStateChanged and visitedStateChanged functions.
        Got rid of unneeded friend declarations.

        * dom/Document.cpp:
        (WebCore::Document::completeURL): Made const.
        (WebCore::findSlashDotDotSlash): Moved here from PageGroup.
        (WebCore::findSlashSlash): Ditto.
        (WebCore::findSlashDotSlash): Ditto.
        (WebCore::containsColonSlashSlash):
        (WebCore::cleanPath): Ditto.
        (WebCore::matchLetter): Ditto.
        (WebCore::needsTrailingSlash): Ditto.
        (WebCore::Document::visitedLinkHash): Moved this here from PageGroup. This is
        the poor-man's completeURL function. The idea of putting it here is that this
        way it can be alongside the real completeURL function. Later we should figure out
        a way to make this function share more code with the real thing and match behavior.

        * dom/Document.h: Marked completeURL function const. Added visitedLinkHash function.

        * page/DOMWindow.cpp:
        (WebCore::DOMWindow::getMatchedCSSRules): Updated for change to CSSStyleSelector.

        * page/Page.cpp:
        (WebCore::Page::allVisitedStateChanged): Added. Calls allVisitedStateChanged on all
        style selectors.
        (WebCore::Page::visitedStateChanged): Ditto.
        * page/Page.h: Added the above functions.

        * page/PageGroup.cpp:
        (WebCore::PageGroup::isLinkVisited): Changed to take a visitedLinkHash parameter.
        The CSSStyleSelector now handles actually computing the hash, and it does so by
        calling code in Document.
        (WebCore::PageGroup::addVisitedLink): Refactored so the two overloaded copies share
        a bit more code. Added code that calls visitedStateChanged if a new link was added.
        (WebCore::PageGroup::removeVisitedLinks): Added code to call allVisitedStateChanged
        if any visited links are removed.
        * page/PageGroup.h: Include StringHash.h instead of having the AlreadyHashed struct
        definition here.

        * platform/text/StringHash.h:
        (WebCore::CaseFoldingHash::hash): Tweaked to make this a bit more consistent with
        the StringImpl::computeHash function, using the same technique for avoiding 0.
        (WebCore::AlreadyHashed::hash): Added. Was formerly in PageGroup.h.
        (WebCore::AlreadyHashed::avoidDeletedValue): Added. Was formerly in PageGroup.cpp.

        * rendering/RenderStyle.cpp:
        (WebCore::RenderStyle::isStyleAvailable): Changed to use an inline function instead
        of getting directly at a data member so the data member could be made private.

        * loader/FrameLoader.cpp:
        (WebCore::FrameLoader::scrollToAnchor): Added call to updateHistoryForAnchorScroll.
        (WebCore::FrameLoader::updateHistoryForAnchorScroll): Added.
        * loader/FrameLoader.h: Added updateHistoryForAnchorScroll.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@30949 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent e0ab1916
2008-03-10 Darin Adler <darin@apple.com>
Reviewed by Antti.
- fix <rdar://problem/3059610> VIP: links opened in new frame, window, or tab
should be redrawn as visited immediately
- fix <rdar://problem/4382809> Going "back" a page doesn't change the color of
the visited URL at directory.umi
- fix http://bugs.webkit.org/show_bug.cgi?id=4941
Visited links should be marked as visited
- fix http://bugs.webkit.org/show_bug.cgi?id=7960
REGRESSION: Visited link color doesn't displayed after loading page from cache
We now mark all links on a page as "changed" at the appropriate times.
* WebCore.base.exp: Update since I made completeURL be a const member function.
* css/CSSStyleSelector.cpp: Got rid of some unneeded globals that could be turned
into locals. Also changed some static data members to file-scoped globals with
internal linkage. Renamed the globals to get rid of the m_ prefix. Changed the
prefix on m_styleNotYetAvailable to s_styleNotYetAvailable.
(WebCore::CSSStyleSelector::CSSStyleSelector): Updated for name changes.
(WebCore::parseUASheet): Tweak the comment.
(WebCore::CSSStyleSelector::loadDefaultStyle): Updated for name changes and to
use local variables instead of globals where possible.
(WebCore::CSSStyleSelector::checkPseudoState): Made this a member function so
it can store the link in a hash. Also changed it to have a return value instead
of having it modify a global variable. Added code to put the hash into a set so
we can tell later if this is one of the links that affects this page.
(WebCore::CSSStyleSelector::canShareStyleWithElement): Updated for the change to
checkPseudoState.
(WebCore::CSSStyleSelector::matchUARules): Updated for name changes.
(WebCore::CSSStyleSelector::styleForElement): Ditto.
(WebCore::CSSStyleSelector::adjustRenderStyle): Ditto.
(WebCore::CSSStyleSelector::pseudoStyleRulesForElement): Changed code to read
the SVG style sheet to use a boolean global and put it right here in the function
since this is the only code that needs to know about it.
(WebCore::CSSStyleSelector::checkOneSelector): Updated for name changes.
(WebCore::colorForCSSValue): Moved code inside the function that is not needed
anywhere else.
(WebCore::CSSStyleSelector::getColorFromPrimitiveValue): Updaed for the change
to checkPseudoState.
(WebCore::CSSStyleSelector::allVisitedStateChanged): Added. Calls setChanged on
all links if there were any in the set.
(WebCore::CSSStyleSelector::visitedStateChanged): Added. Calls setChanged on all
links if the one that changed is in the set.
* css/CSSStyleSelector.h: Removed unused StyleSelector class and State enum. Made
CSSStyleSelector derive from Noncopyable. Made lots of member functions private that
didn't need to be public, and removed others that could be made into non-member
functions. Changed pseudoStyleRulesForElement to take a const String& instead of
a StringImpl*. Added new allVisitedStateChanged and visitedStateChanged functions.
Got rid of unneeded friend declarations.
* dom/Document.cpp:
(WebCore::Document::completeURL): Made const.
(WebCore::findSlashDotDotSlash): Moved here from PageGroup.
(WebCore::findSlashSlash): Ditto.
(WebCore::findSlashDotSlash): Ditto.
(WebCore::containsColonSlashSlash):
(WebCore::cleanPath): Ditto.
(WebCore::matchLetter): Ditto.
(WebCore::needsTrailingSlash): Ditto.
(WebCore::Document::visitedLinkHash): Moved this here from PageGroup. This is
the poor-man's completeURL function. The idea of putting it here is that this
way it can be alongside the real completeURL function. Later we should figure out
a way to make this function share more code with the real thing and match behavior.
* dom/Document.h: Marked completeURL function const. Added visitedLinkHash function.
* page/DOMWindow.cpp:
(WebCore::DOMWindow::getMatchedCSSRules): Updated for change to CSSStyleSelector.
* page/Page.cpp:
(WebCore::Page::allVisitedStateChanged): Added. Calls allVisitedStateChanged on all
style selectors.
(WebCore::Page::visitedStateChanged): Ditto.
* page/Page.h: Added the above functions.
* page/PageGroup.cpp:
(WebCore::PageGroup::isLinkVisited): Changed to take a visitedLinkHash parameter.
The CSSStyleSelector now handles actually computing the hash, and it does so by
calling code in Document.
(WebCore::PageGroup::addVisitedLink): Refactored so the two overloaded copies share
a bit more code. Added code that calls visitedStateChanged if a new link was added.
(WebCore::PageGroup::removeVisitedLinks): Added code to call allVisitedStateChanged
if any visited links are removed.
* page/PageGroup.h: Include StringHash.h instead of having the AlreadyHashed struct
definition here.
* platform/text/StringHash.h:
(WebCore::CaseFoldingHash::hash): Tweaked to make this a bit more consistent with
the StringImpl::computeHash function, using the same technique for avoiding 0.
(WebCore::AlreadyHashed::hash): Added. Was formerly in PageGroup.h.
(WebCore::AlreadyHashed::avoidDeletedValue): Added. Was formerly in PageGroup.cpp.
* rendering/RenderStyle.cpp:
(WebCore::RenderStyle::isStyleAvailable): Changed to use an inline function instead
of getting directly at a data member so the data member could be made private.
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::scrollToAnchor): Added call to updateHistoryForAnchorScroll.
(WebCore::FrameLoader::updateHistoryForAnchorScroll): Added.
* loader/FrameLoader.h: Added updateHistoryForAnchorScroll.
2008-03-10 Adam Roben <aroben@apple.com>
Part of Bug 17224: DOM nodes/attributes should be editable
......@@ -465,7 +465,6 @@ __ZN7WebCore6WidgetC1EP6NSView
__ZN7WebCore6WidgetC1Ev
__ZN7WebCore7IntSizeC1ERK7_NSSize
__ZN7WebCore7nsColorERKNS_5ColorE
__ZN7WebCore8Document11completeURLERKNS_6StringE
__ZN7WebCore8Document13removeMarkersENS_14DocumentMarker10MarkerTypeE
__ZN7WebCore8Document14setFocusedNodeEN3WTF10PassRefPtrINS_4NodeEEE
__ZN7WebCore8Document4bodyEv
......@@ -705,6 +704,7 @@ __ZNK7WebCore6StringcvN3KJS7UStringEEv
__ZNK7WebCore6Widget7getViewEv
__ZNK7WebCore7Element12getAttributeERKNS_13QualifiedNameE
__ZNK7WebCore7IntRectcv7_NSRectEv
__ZNK7WebCore8Document11completeURLERKNS_6StringE
__ZNK7WebCore8Document11defaultViewEv
__ZNK7WebCore8IntPointcv8_NSPointEv
__ZNK7WebCore9FloatRectcv7_NSRectEv
......
This diff is collapsed.
......@@ -25,7 +25,9 @@
#include "CSSFontSelector.h"
#include "MediaQueryExp.h"
#include "RenderStyle.h"
#include "StringHash.h"
#include <wtf/HashSet.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
#include <wtf/RefPtr.h>
......@@ -56,64 +58,45 @@ class StyleSheet;
class StyleSheetList;
class StyledElement;
class MediaQueryResult
{
class MediaQueryResult {
public:
MediaQueryResult(const MediaQueryExp& expr, bool result)
: m_expression(expr)
, m_result(result)
{}
: m_expression(expr)
, m_result(result)
{
}
MediaQueryExp m_expression;
bool m_result;
};
/**
* this class selects a RenderStyle for a given Element based on the
* collection of styleshets it contains. This is just a vrtual base class
* for specific implementations of the Selector. At the moment only CSSStyleSelector
* exists, but someone may wish to implement XSL.
*/
class StyleSelector {
public:
enum State {
None = 0x00,
Hover = 0x01,
Focus = 0x02,
Active = 0x04,
Drag = 0x08
};
};
/**
* the StyleSelector implementation for CSS.
*/
class CSSStyleSelector : public StyleSelector {
// This class selects a RenderStyle for a given element based on a collection of stylesheets.
class CSSStyleSelector : Noncopyable {
public:
CSSStyleSelector(Document*, const String& userStyleSheet, StyleSheetList*, CSSStyleSheet*, bool strictParsing, bool matchAuthorAndUserStyles);
~CSSStyleSelector();
static void loadDefaultStyle();
void initElementAndPseudoState(Element*);
void initForStyleResolve(Element*, RenderStyle* parentStyle);
RenderStyle* styleForElement(Element*, RenderStyle* parentStyle = 0, bool allowSharing = true, bool resolveForRootDefault = false);
RenderStyle* pseudoStyleForElement(RenderStyle::PseudoId, Element*, RenderStyle* parentStyle = 0);
private:
RenderStyle* locateSharedStyle();
Node* locateCousinList(Element* parent, unsigned depth = 1);
bool canShareStyleWithElement(Node* n);
bool canShareStyleWithElement(Node*);
public:
// These methods will give back the set of rules that matched for a given element (or a pseudo-element).
RefPtr<CSSRuleList> styleRulesForElement(Element*, bool authorOnly);
RefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, StringImpl* pseudoStyle, bool authorOnly);
bool strictParsing;
RefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, const String& pseudoStyle, bool authorOnly);
// Given a CSS keyword in the range (xx-small to -webkit-xxx-large), this function will return
// the correct font size scaled relative to the user's default (medium).
float fontSizeForKeyword(int keyword, bool quirksMode, bool monospace) const;
private:
// When the CSS keyword "larger" is used, this function will attempt to match within the keyword
// table, and failing that, will simply multiply by 1.2.
float largerFontSize(float size, bool quirksMode) const;
......@@ -121,37 +104,38 @@ public:
// Like the previous function, but for the keyword "smaller".
float smallerFontSize(float size, bool quirksMode) const;
public:
void setFontSize(FontDescription&, float size);
private:
float getComputedSizeFromSpecifiedSize(bool isAbsoluteSize, float specifiedSize);
public:
Color getColorFromPrimitiveValue(CSSPrimitiveValue*);
bool hasSelectorForAttribute(const AtomicString&);
CSSFontSelector* fontSelector() { return m_fontSelector.get(); }
/* checks if a compound selector (which can consist of multiple simple selectors)
matches the given Element */
// Checks if a compound selector (which can consist of multiple simple selectors) matches the current element.
bool checkSelector(CSSSelector*);
void addViewportDependentMediaQueryResult(const MediaQueryExp*, bool result);
bool affectedByViewportChange() const;
protected:
enum SelectorMatch {
SelectorMatches = 0,
SelectorFailsLocally,
SelectorFailsCompletely
};
SelectorMatch checkSelector(CSSSelector*, Element *, bool isAncestor, bool isSubSelector);
void allVisitedStateChanged();
void visitedStateChanged(unsigned visitedHash);
private:
enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsCompletely };
SelectorMatch checkSelector(CSSSelector*, Element*, bool isAncestor, bool isSubSelector);
/* checks if the selector matches the given Element */
// Checks if the selector matches the given Element.
bool checkOneSelector(CSSSelector*, Element*, bool isAncestor, bool isSubSelector = false);
/* This function fixes up the default font size if it detects that the
current generic font family has changed. -dwh */
void checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle);
// This function fixes up the default font size if it detects that the current generic font family has changed. -dwh
void checkForGenericFamilyChange(RenderStyle*, RenderStyle* parentStyle);
void checkForTextSizeAdjust();
void adjustRenderStyle(RenderStyle*, Element*);
......@@ -160,22 +144,12 @@ public:
void addMatchedDeclaration(CSSMutableStyleDeclaration* decl) { m_matchedDecls.append(decl); }
void matchRules(CSSRuleSet*, int& firstRuleIndex, int& lastRuleIndex);
void matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex);
void matchRulesForList(CSSRuleDataList*, int& firstRuleIndex, int& lastRuleIndex);
void sortMatchedRules(unsigned start, unsigned end);
void applyDeclarations(bool firstPass, bool important, int startIndex, int endIndex);
static CSSStyleSheet* m_defaultSheet;
static CSSStyleSheet* m_quirksSheet;
static CSSStyleSheet* m_viewSourceSheet;
#if ENABLE(SVG)
static CSSStyleSheet* m_svgSheet;
#endif
static CSSRuleSet* m_defaultStyle;
static CSSRuleSet* m_defaultQuirksStyle;
static CSSRuleSet* m_defaultPrintStyle;
static CSSRuleSet* m_defaultViewSourceStyle;
bool m_strictParsing;
CSSRuleSet* m_authorStyle;
CSSRuleSet* m_userStyle;
......@@ -187,9 +161,11 @@ public:
Color m_backgroundColor;
public:
static RenderStyle* m_styleNotYetAvailable;
static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; }
private:
static RenderStyle* s_styleNotYetAvailable;
void init();
void matchUARules(int& firstUARule, int& lastUARule);
......@@ -211,6 +187,13 @@ public:
void mapTransitionTimingFunction(Transition*, CSSValue*);
void mapTransitionProperty(Transition*, CSSValue*);
void applyProperty(int id, CSSValue*);
#if ENABLE(SVG)
void applySVGProperty(int id, CSSValue*);
#endif
PseudoState checkPseudoState(Element*, bool checkVisited = true);
// We collect the set of decls that match in |m_matchedDecls|. We then walk the
// set of matched decls four times, once for those properties that others depend on (like font-size),
// and then a second time for all the remaining properties. We then do the same two passes
......@@ -246,14 +229,7 @@ public:
Vector<CSSMutableStyleDeclaration*> m_additionalAttributeStyleDecls;
Vector<MediaQueryResult*> m_viewportDependentMediaQueryResults;
void applyProperty(int id, CSSValue*);
#if ENABLE(SVG)
void applySVGProperty(int id, CSSValue*);
#endif
friend class CSSRuleSet;
friend class Node;
HashSet<unsigned, AlreadyHashed> m_linksCheckedForVisitedState;
};
class CSSRuleData {
......
......@@ -2785,7 +2785,7 @@ UChar Document::backslashAsCurrencySymbol() const
return m_decoder->encoding().backslashAsCurrencySymbol();
}
KURL Document::completeURL(const String& url)
KURL Document::completeURL(const String& url) const
{
// Always return a null URL when passed a null string.
// FIXME: Should we change the KURL constructor to have this behavior?
......@@ -3771,6 +3771,176 @@ 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)
......
......@@ -382,7 +382,9 @@ public:
const String& baseTarget() const { return m_baseTarget; }
void setBaseTarget(const String& baseTarget) { m_baseTarget = baseTarget; }
KURL completeURL(const String&);
KURL completeURL(const String&) const;
unsigned visitedLinkHash(const AtomicString& attributeURL) const;
// from cachedObjectClient
virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*);
......
......@@ -1807,13 +1807,13 @@ void FrameLoader::setPolicyBaseURL(const KURL& url)
child->loader()->setPolicyBaseURL(url);
}
// This does the same kind of work that FrameLoader::openURL does, except it relies on the fact
// This does the same kind of work that didOpenURL does, except it relies on the fact
// that a higher level already checked that the URLs match and the scrolling is the right thing to do.
void FrameLoader::scrollToAnchor(const KURL& url)
{
m_URL = url;
updateHistoryForAnchorScroll();
started();
gotoAnchor();
// It's important to model this as a load that starts and immediately finishes.
......@@ -4381,6 +4381,22 @@ void FrameLoader::updateHistoryForCommit()
}
}
void FrameLoader::updateHistoryForAnchorScroll()
{
if (m_URL.isEmpty())
return;
Settings* settings = m_frame->settings();
if (!settings || settings->privateBrowsingEnabled())
return;
Page* page = m_frame->page();
if (!page)
return;
page->group().addVisitedLink(m_URL);
}
// Walk the frame tree, telling all frames to save their form state into their current
// history item.
void FrameLoader::saveDocumentAndScrollState()
......
......@@ -455,6 +455,7 @@ namespace WebCore {
void updateHistoryForRedirectWithLockedHistory();
void updateHistoryForClientRedirect();
void updateHistoryForCommit();
void updateHistoryForAnchorScroll();
void redirectionTimerFired(Timer<FrameLoader>*);
void checkCompletedTimerFired(Timer<FrameLoader>*);
......
......@@ -616,7 +616,7 @@ PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String
return 0;
if (!pseudoElt.isEmpty())
return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt.impl(), authorOnly);
return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly);
return doc->styleSelector()->styleRulesForElement(elt, authorOnly);
}
......
......@@ -24,6 +24,7 @@
#include "ChromeClient.h"
#include "ContextMenuClient.h"
#include "ContextMenuController.h"
#include "CSSStyleSelector.h"
#include "EditorClient.h"
#include "DOMWindow.h"
#include "DragController.h"
......@@ -421,6 +422,38 @@ void Page::removeAllVisitedLinks()
(*it)->removeVisitedLinks();
}
void Page::allVisitedStateChanged(PageGroup* group)
{
ASSERT(group);
ASSERT(allPages);
HashSet<Page*>::iterator pagesEnd = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
Page* page = *it;
if (page->m_group != group)
continue;
for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
styleSelector->allVisitedStateChanged();
}
}
}
void Page::visitedStateChanged(PageGroup* group, unsigned visitedLinkHash)
{
ASSERT(group);
ASSERT(allPages);
HashSet<Page*>::iterator pagesEnd = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
Page* page = *it;
if (page->m_group != group)
continue;
for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
styleSelector->visitedStateChanged(visitedLinkHash);
}
}
}
void Page::setDebuggerForAllPages(KJS::Debugger* debugger)
{
ASSERT(allPages);
......
......@@ -153,6 +153,9 @@ namespace WebCore {
static void removeAllVisitedLinks();
static void allVisitedStateChanged(PageGroup*);
static void visitedStateChanged(PageGroup*, unsigned visitedHash);
private:
void initGroup();
......
......@@ -36,19 +36,6 @@ namespace WebCore {
static bool shouldTrackVisitedLinks;
// To use a hash value as a key for a hash table, we need to eliminate the
// "deleted" value, which is negative one. That could be done by changing
// the hash function to never generate negative one, but this works and is
// still relatively efficient.
static inline unsigned avoidDeletedValue(unsigned hash)
{
ASSERT(hash);
unsigned newHash = hash | (!(hash + 1) << 31);
ASSERT(newHash);
ASSERT(newHash != 0xFFFFFFFF);
return newHash;
}
PageGroup::PageGroup(Page* page)
: m_visitedLinksPopulated(false)
{
......@@ -70,182 +57,23 @@ void PageGroup::removePage(Page* page)
m_pages.remove(page);
}
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) {