Changeset 30949 in webkit


Ignore:
Timestamp:
Mar 10, 2008, 5:45:47 PM (17 years ago)
Author:
Darin Adler
Message:

Reviewed by Antti.

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.
Location:
trunk/WebCore
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r30947 r30949  
     12008-03-10  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by Antti.
     4
     5        - fix <rdar://problem/3059610> VIP: links opened in new frame, window, or tab
     6          should be redrawn as visited immediately
     7        - fix <rdar://problem/4382809> Going "back" a page doesn't change the color of
     8          the visited URL at directory.umi
     9        - fix http://bugs.webkit.org/show_bug.cgi?id=4941
     10          Visited links should be marked as visited
     11        - fix http://bugs.webkit.org/show_bug.cgi?id=7960
     12          REGRESSION: Visited link color doesn't displayed after loading page from cache
     13
     14        We now mark all links on a page as "changed" at the appropriate times.
     15
     16        * WebCore.base.exp: Update since I made completeURL be a const member function.
     17
     18        * css/CSSStyleSelector.cpp: Got rid of some unneeded globals that could be turned
     19        into locals. Also changed some static data members to file-scoped globals with
     20        internal linkage. Renamed the globals to get rid of the m_ prefix. Changed the
     21        prefix on m_styleNotYetAvailable to s_styleNotYetAvailable.
     22        (WebCore::CSSStyleSelector::CSSStyleSelector): Updated for name changes.
     23        (WebCore::parseUASheet): Tweak the comment.
     24        (WebCore::CSSStyleSelector::loadDefaultStyle): Updated for name changes and to
     25        use local variables instead of globals where possible.
     26        (WebCore::CSSStyleSelector::checkPseudoState): Made this a member function so
     27        it can store the link in a hash. Also changed it to have a return value instead
     28        of having it modify a global variable. Added code to put the hash into a set so
     29        we can tell later if this is one of the links that affects this page.
     30        (WebCore::CSSStyleSelector::canShareStyleWithElement): Updated for the change to
     31        checkPseudoState.
     32        (WebCore::CSSStyleSelector::matchUARules): Updated for name changes.
     33        (WebCore::CSSStyleSelector::styleForElement): Ditto.
     34        (WebCore::CSSStyleSelector::adjustRenderStyle): Ditto.
     35        (WebCore::CSSStyleSelector::pseudoStyleRulesForElement): Changed code to read
     36        the SVG style sheet to use a boolean global and put it right here in the function
     37        since this is the only code that needs to know about it.
     38        (WebCore::CSSStyleSelector::checkOneSelector): Updated for name changes.
     39        (WebCore::colorForCSSValue): Moved code inside the function that is not needed
     40        anywhere else.
     41        (WebCore::CSSStyleSelector::getColorFromPrimitiveValue): Updaed for the change
     42        to checkPseudoState.
     43        (WebCore::CSSStyleSelector::allVisitedStateChanged): Added. Calls setChanged on
     44        all links if there were any in the set.
     45        (WebCore::CSSStyleSelector::visitedStateChanged): Added. Calls setChanged on all
     46        links if the one that changed is in the set.
     47
     48        * css/CSSStyleSelector.h: Removed unused StyleSelector class and State enum. Made
     49        CSSStyleSelector derive from Noncopyable. Made lots of member functions private that
     50        didn't need to be public, and removed others that could be made into non-member
     51        functions. Changed pseudoStyleRulesForElement to take a const String& instead of
     52        a StringImpl*. Added new allVisitedStateChanged and visitedStateChanged functions.
     53        Got rid of unneeded friend declarations.
     54
     55        * dom/Document.cpp:
     56        (WebCore::Document::completeURL): Made const.
     57        (WebCore::findSlashDotDotSlash): Moved here from PageGroup.
     58        (WebCore::findSlashSlash): Ditto.
     59        (WebCore::findSlashDotSlash): Ditto.
     60        (WebCore::containsColonSlashSlash):
     61        (WebCore::cleanPath): Ditto.
     62        (WebCore::matchLetter): Ditto.
     63        (WebCore::needsTrailingSlash): Ditto.
     64        (WebCore::Document::visitedLinkHash): Moved this here from PageGroup. This is
     65        the poor-man's completeURL function. The idea of putting it here is that this
     66        way it can be alongside the real completeURL function. Later we should figure out
     67        a way to make this function share more code with the real thing and match behavior.
     68
     69        * dom/Document.h: Marked completeURL function const. Added visitedLinkHash function.
     70
     71        * page/DOMWindow.cpp:
     72        (WebCore::DOMWindow::getMatchedCSSRules): Updated for change to CSSStyleSelector.
     73
     74        * page/Page.cpp:
     75        (WebCore::Page::allVisitedStateChanged): Added. Calls allVisitedStateChanged on all
     76        style selectors.
     77        (WebCore::Page::visitedStateChanged): Ditto.
     78        * page/Page.h: Added the above functions.
     79
     80        * page/PageGroup.cpp:
     81        (WebCore::PageGroup::isLinkVisited): Changed to take a visitedLinkHash parameter.
     82        The CSSStyleSelector now handles actually computing the hash, and it does so by
     83        calling code in Document.
     84        (WebCore::PageGroup::addVisitedLink): Refactored so the two overloaded copies share
     85        a bit more code. Added code that calls visitedStateChanged if a new link was added.
     86        (WebCore::PageGroup::removeVisitedLinks): Added code to call allVisitedStateChanged
     87        if any visited links are removed.
     88        * page/PageGroup.h: Include StringHash.h instead of having the AlreadyHashed struct
     89        definition here.
     90
     91        * platform/text/StringHash.h:
     92        (WebCore::CaseFoldingHash::hash): Tweaked to make this a bit more consistent with
     93        the StringImpl::computeHash function, using the same technique for avoiding 0.
     94        (WebCore::AlreadyHashed::hash): Added. Was formerly in PageGroup.h.
     95        (WebCore::AlreadyHashed::avoidDeletedValue): Added. Was formerly in PageGroup.cpp.
     96
     97        * rendering/RenderStyle.cpp:
     98        (WebCore::RenderStyle::isStyleAvailable): Changed to use an inline function instead
     99        of getting directly at a data member so the data member could be made private.
     100
     101        * loader/FrameLoader.cpp:
     102        (WebCore::FrameLoader::scrollToAnchor): Added call to updateHistoryForAnchorScroll.
     103        (WebCore::FrameLoader::updateHistoryForAnchorScroll): Added.
     104        * loader/FrameLoader.h: Added updateHistoryForAnchorScroll.
     105
    11062008-03-10  Adam Roben  <aroben@apple.com>
    2107
  • trunk/WebCore/WebCore.base.exp

    r30897 r30949  
    466466__ZN7WebCore7IntSizeC1ERK7_NSSize
    467467__ZN7WebCore7nsColorERKNS_5ColorE
    468 __ZN7WebCore8Document11completeURLERKNS_6StringE
    469468__ZN7WebCore8Document13removeMarkersENS_14DocumentMarker10MarkerTypeE
    470469__ZN7WebCore8Document14setFocusedNodeEN3WTF10PassRefPtrINS_4NodeEEE
     
    706705__ZNK7WebCore7Element12getAttributeERKNS_13QualifiedNameE
    707706__ZNK7WebCore7IntRectcv7_NSRectEv
     707__ZNK7WebCore8Document11completeURLERKNS_6StringE
    708708__ZNK7WebCore8Document11defaultViewEv
    709709__ZNK7WebCore8IntPointcv8_NSPointEv
  • trunk/WebCore/css/CSSStyleSelector.cpp

    r30893 r30949  
    189189}
    190190
    191 class CSSRuleSet
    192 {
     191class CSSRuleSet {
    193192public:
    194193    CSSRuleSet();
     
    216215};
    217216
    218 CSSRuleSet* CSSStyleSelector::m_defaultStyle = 0;
    219 CSSRuleSet* CSSStyleSelector::m_defaultQuirksStyle = 0;
    220 CSSRuleSet* CSSStyleSelector::m_defaultPrintStyle = 0;
    221 CSSRuleSet* CSSStyleSelector::m_defaultViewSourceStyle = 0;
    222 
    223 CSSStyleSheet* CSSStyleSelector::m_defaultSheet = 0;
    224 RenderStyle* CSSStyleSelector::m_styleNotYetAvailable = 0;
    225 CSSStyleSheet* CSSStyleSelector::m_quirksSheet = 0;
    226 CSSStyleSheet* CSSStyleSelector::m_viewSourceSheet = 0;
    227 
    228 #if ENABLE(SVG)
    229 CSSStyleSheet *CSSStyleSelector::m_svgSheet = 0;
    230 #endif
     217static CSSRuleSet* defaultStyle;
     218static CSSRuleSet* defaultQuirksStyle;
     219static CSSRuleSet* defaultPrintStyle;
     220static CSSRuleSet* defaultViewSourceStyle;
     221
     222RenderStyle* CSSStyleSelector::s_styleNotYetAvailable;
    231223
    232224static PseudoState pseudoState;
     225
     226static void loadDefaultStyle();
    233227
    234228static const MediaQueryEvaluator& screenEval()
     
    244238}
    245239
    246 CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList *styleSheets, CSSStyleSheet* mappedElementSheet, bool _strictParsing, bool matchAuthorAndUserStyles)
     240CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet, bool strictParsing, bool matchAuthorAndUserStyles)
     241    : m_strictParsing(strictParsing)
    247242{
    248243    init();
     
    253248    m_matchAuthorAndUserStyles = matchAuthorAndUserStyles;
    254249
    255     strictParsing = _strictParsing;
    256     if (!m_defaultStyle)
     250    m_strictParsing = strictParsing;
     251    if (!defaultStyle)
    257252        loadDefaultStyle();
    258253
     
    325320    CSSStyleSheet* const parent = 0;
    326321    CSSStyleSheet* sheet = new CSSStyleSheet(parent);
    327     sheet->ref(); // leak the sheet on purpose since it will be stored in a global variable
     322    sheet->ref(); // leak the sheet on purpose
    328323    sheet->parseString(String(characters, size));
    329324    return sheet;
     
    335330}
    336331
    337 void CSSStyleSelector::loadDefaultStyle()
    338 {
    339     if (m_defaultStyle)
    340         return;
    341 
    342     m_defaultStyle = new CSSRuleSet;
    343     m_defaultPrintStyle = new CSSRuleSet;
    344     m_defaultQuirksStyle = new CSSRuleSet;
    345     m_defaultViewSourceStyle = new CSSRuleSet;
     332static void loadDefaultStyle()
     333{
     334    ASSERT(!defaultStyle);
     335
     336    defaultStyle = new CSSRuleSet;
     337    defaultPrintStyle = new CSSRuleSet;
     338    defaultQuirksStyle = new CSSRuleSet;
     339    defaultViewSourceStyle = new CSSRuleSet;
    346340
    347341    // Strict-mode rules.
    348     m_defaultSheet = parseUASheet(html4UserAgentStyleSheet);
    349     m_defaultStyle->addRulesFromSheet(m_defaultSheet, screenEval());
    350     m_defaultPrintStyle->addRulesFromSheet(m_defaultSheet, printEval());
     342    CSSStyleSheet* defaultSheet = parseUASheet(html4UserAgentStyleSheet);
     343    defaultStyle->addRulesFromSheet(defaultSheet, screenEval());
     344    defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval());
    351345
    352346    // Quirks-mode rules.
    353     m_quirksSheet = parseUASheet(quirksUserAgentStyleSheet);
    354     m_defaultQuirksStyle->addRulesFromSheet(m_quirksSheet, screenEval());
     347    defaultQuirksStyle->addRulesFromSheet(parseUASheet(quirksUserAgentStyleSheet), screenEval());
    355348   
    356349    // View source rules.
    357     m_viewSourceSheet = parseUASheet(sourceUserAgentStyleSheet);
    358     m_defaultViewSourceStyle->addRulesFromSheet(m_viewSourceSheet, screenEval());
     350    defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet), screenEval());
    359351}
    360352
     
    546538}
    547539
    548 static void checkPseudoState(Element* e, bool checkVisited = true)
    549 {
    550     if (!e->isLink()) {
    551         pseudoState = PseudoNone;
    552         return;
    553     }
    554 
    555     const AtomicString* attr;
    556     if (e->isHTMLElement())
    557         attr = &e->getAttribute(hrefAttr);
     540static inline const AtomicString* linkAttribute(Node* node)
     541{
     542    if (!node->isLink())
     543        return 0;
     544
     545    ASSERT(node->isElementNode());
     546    Element* element = static_cast<Element*>(node);
     547    if (element->isHTMLElement())
     548        return &element->getAttribute(hrefAttr);
    558549#if ENABLE(SVG)
    559     else if (e->isSVGElement())
    560         attr = &e->getAttribute(XLinkNames::hrefAttr);
     550    if (element->isSVGElement())
     551        return &element->getAttribute(XLinkNames::hrefAttr);
    561552#endif
    562     else {
    563         pseudoState = PseudoNone;
    564         return;
    565     }
    566 
    567     if (attr->isNull()) {
    568         pseudoState = PseudoNone;
    569         return;
    570     }
    571 
    572     if (!checkVisited) {
    573         pseudoState = PseudoAnyLink;
    574         return;
    575     }
    576 
    577     Document* document = e->document();
    578 
    579     Frame* frame = document->frame();
    580     if (!frame) {
    581         pseudoState = PseudoLink;
    582         return;
    583     }
     553    return 0;
     554}
     555
     556PseudoState CSSStyleSelector::checkPseudoState(Element* element, bool checkVisited)
     557{
     558    const AtomicString* attr = linkAttribute(element);
     559    if (!attr || attr->isNull())
     560        return PseudoNone;
     561
     562    if (!checkVisited)
     563        return PseudoAnyLink;
     564
     565    unsigned hash = m_document->visitedLinkHash(*attr);
     566    if (!hash)
     567        return PseudoLink;
     568
     569    Frame* frame = m_document->frame();
     570    if (!frame)
     571        return PseudoLink;
    584572
    585573    Page* page = frame->page();
    586     if (!page) {
    587         pseudoState = PseudoLink;
    588         return;
    589     }
    590 
    591     pseudoState = page->group().isLinkVisited(document, *attr) ? PseudoVisited : PseudoLink;
     574    if (!page)
     575        return PseudoLink;
     576
     577    m_linksCheckedForVisitedState.add(hash);
     578    return page->group().isLinkVisited(hash) ? PseudoVisited : PseudoLink;
    592579}
    593580
     
    734721                            const Color& linkColor = m_element->document()->linkColor();
    735722                            const Color& visitedColor = m_element->document()->visitedLinkColor();
    736                             checkPseudoState(m_element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor);
     723                            pseudoState = checkPseudoState(m_element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor);
    737724                        }
    738725                        linksMatch = (pseudoState == style->pseudoState());
     
    779766    // First we match rules from the user agent sheet.
    780767    CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
    781         ? m_defaultPrintStyle : m_defaultStyle;
     768        ? defaultPrintStyle : defaultStyle;
    782769    matchRules(userAgentStyleSheet, firstUARule, lastUARule);
    783770
    784771    // In quirks mode, we match rules from the quirks user agent sheet.
    785     if (!strictParsing)
    786         matchRules(m_defaultQuirksStyle, firstUARule, lastUARule);
     772    if (!m_strictParsing)
     773        matchRules(defaultQuirksStyle, firstUARule, lastUARule);
    787774       
    788775    // If we're in view source mode, then we match rules from the view source style sheet.
    789776    if (m_document->frame() && m_document->frame()->inViewSourceMode())
    790         matchRules(m_defaultViewSourceStyle, firstUARule, lastUARule);
     777        matchRules(defaultViewSourceStyle, firstUARule, lastUARule);
    791778}
    792779
     
    799786    // will vanish if a style recalc happens during loading.
    800787    if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) {
    801         if (!m_styleNotYetAvailable) {
    802             m_styleNotYetAvailable = ::new RenderStyle;
    803             m_styleNotYetAvailable->ref();
    804             m_styleNotYetAvailable->setDisplay(NONE);
    805             m_styleNotYetAvailable->font().update(m_fontSelector);
    806         }
    807         m_styleNotYetAvailable->ref();
     788        if (!s_styleNotYetAvailable) {
     789            s_styleNotYetAvailable = ::new RenderStyle;
     790            s_styleNotYetAvailable->ref();
     791            s_styleNotYetAvailable->setDisplay(NONE);
     792            s_styleNotYetAvailable->font().update(m_fontSelector);
     793        }
     794        s_styleNotYetAvailable->ref();
    808795        e->document()->setHasNodesWithPlaceholderStyle();
    809         return m_styleNotYetAvailable;
     796        return s_styleNotYetAvailable;
    810797    }
    811798   
     
    838825
    839826#if ENABLE(SVG)
    840     if (e->isSVGElement() && !m_svgSheet) {
     827    static bool loadedSVGUserAgentSheet;
     828    if (e->isSVGElement() && !loadedSVGUserAgentSheet) {
    841829        // SVG rules.
    842         m_svgSheet = parseUASheet(svgUserAgentStyleSheet);
    843         m_defaultStyle->addRulesFromSheet(m_svgSheet, screenEval());
    844         m_defaultPrintStyle->addRulesFromSheet(m_svgSheet, printEval());
     830        loadedSVGUserAgentSheet = true;
     831        CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet);
     832        defaultStyle->addRulesFromSheet(svgSheet, screenEval());
     833        defaultPrintStyle->addRulesFromSheet(svgSheet, printEval());
    845834    }
    846835#endif
     
    10621051        // Sites also commonly use display:inline/block on <td>s and <table>s.  In quirks mode we force
    10631052        // these tags to retain their display types.
    1064         if (!strictParsing && e) {
     1053        if (!m_strictParsing && e) {
    10651054            if (e->hasTagName(tdTag)) {
    10661055                style->setDisplay(TABLE_CELL);
     
    11001089                // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
    11011090                // but only in quirks mode.
    1102                 if (!strictParsing && style->floating() != FNONE)
     1091                if (!m_strictParsing && style->floating() != FNONE)
    11031092                    style->setDisplay(BLOCK);
    11041093            }
     
    12531242}
    12541243
    1255 RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, StringImpl* pseudoStyle, bool authorOnly)
     1244RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element*, const String& pseudoStyle, bool authorOnly)
    12561245{
    12571246    // FIXME: Implement this.
     
    18381827            case CSSSelector::PseudoAnyLink:
    18391828                if (pseudoState == PseudoUnknown)
    1840                     checkPseudoState(e, false);
     1829                    pseudoState = checkPseudoState(e, false);
    18411830                if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited)
    18421831                    return true;
     
    18481837            case CSSSelector::PseudoLink:
    18491838                if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
    1850                     checkPseudoState(e);
     1839                    pseudoState = checkPseudoState(e);
    18511840                if (pseudoState == PseudoLink)
    18521841                    return true;
     
    18541843            case CSSSelector::PseudoVisited:
    18551844                if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
    1856                     checkPseudoState(e);
     1845                    pseudoState = checkPseudoState(e);
    18571846                if (pseudoState == PseudoVisited)
    18581847                    return true;
     
    18741863                // If we're in quirks mode, then hover should never match anchors with no
    18751864                // href and *:hover should not match anything.  This is important for sites like wsj.com.
    1876                 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
     1865                if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
    18771866                    if (m_element == e && m_style)
    18781867                        m_style->setAffectedByHoverRules(true);
     
    18871876                // If we're in quirks mode, then :active should never match anchors with no
    18881877                // href and *:active should not match anything.
    1889                 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
     1878                if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
    18901879                    if (m_element == e && m_style)
    18911880                        m_style->setAffectedByActiveRules(true);
     
    49914980}
    49924981
    4993 struct ColorValue {
    4994     int cssValueId;
    4995     RGBA32 color;
    4996 };
    4997 
    4998 static const ColorValue colorValues[] = {
    4999     { CSS_VAL_AQUA, 0xFF00FFFF },
    5000     { CSS_VAL_BLACK, 0xFF000000 },
    5001     { CSS_VAL_BLUE, 0xFF0000FF },
    5002     { CSS_VAL_FUCHSIA, 0xFFFF00FF },
    5003     { CSS_VAL_GRAY, 0xFF808080 },
    5004     { CSS_VAL_GREEN, 0xFF008000  },
    5005     { CSS_VAL_LIME, 0xFF00FF00 },
    5006     { CSS_VAL_MAROON, 0xFF800000 },
    5007     { CSS_VAL_NAVY, 0xFF000080 },
    5008     { CSS_VAL_OLIVE, 0xFF808000  },
    5009     { CSS_VAL_ORANGE, 0xFFFFA500 },
    5010     { CSS_VAL_PURPLE, 0xFF800080 },
    5011     { CSS_VAL_RED, 0xFFFF0000 },
    5012     { CSS_VAL_SILVER, 0xFFC0C0C0 },
    5013     { CSS_VAL_TEAL, 0xFF008080  },
    5014     { CSS_VAL_WHITE, 0xFFFFFFFF },
    5015     { CSS_VAL_YELLOW, 0xFFFFFF00 },
    5016     { CSS_VAL_TRANSPARENT, 0x00000000 },
    5017     { CSS_VAL_GREY, 0xFF808080 },
    5018     { 0, 0 }
    5019 };
    5020 
    50214982static Color colorForCSSValue(int cssValueId)
    50224983{
    5023     for (const ColorValue* col = colorValues; col->cssValueId; ++col)
     4984    struct ColorValue {
     4985        int cssValueId;
     4986        RGBA32 color;
     4987    };
     4988
     4989    static const ColorValue colorValues[] = {
     4990        { CSS_VAL_AQUA, 0xFF00FFFF },
     4991        { CSS_VAL_BLACK, 0xFF000000 },
     4992        { CSS_VAL_BLUE, 0xFF0000FF },
     4993        { CSS_VAL_FUCHSIA, 0xFFFF00FF },
     4994        { CSS_VAL_GRAY, 0xFF808080 },
     4995        { CSS_VAL_GREEN, 0xFF008000  },
     4996        { CSS_VAL_GREY, 0xFF808080 },
     4997        { CSS_VAL_LIME, 0xFF00FF00 },
     4998        { CSS_VAL_MAROON, 0xFF800000 },
     4999        { CSS_VAL_NAVY, 0xFF000080 },
     5000        { CSS_VAL_OLIVE, 0xFF808000  },
     5001        { CSS_VAL_ORANGE, 0xFFFFA500 },
     5002        { CSS_VAL_PURPLE, 0xFF800080 },
     5003        { CSS_VAL_RED, 0xFFFF0000 },
     5004        { CSS_VAL_SILVER, 0xFFC0C0C0 },
     5005        { CSS_VAL_TEAL, 0xFF008080  },
     5006        { CSS_VAL_TRANSPARENT, 0x00000000 },
     5007        { CSS_VAL_WHITE, 0xFFFFFFFF },
     5008        { CSS_VAL_YELLOW, 0xFFFFFF00 },
     5009        { 0, 0 }
     5010    };
     5011
     5012    for (const ColorValue* col = colorValues; col->cssValueId; ++col) {
    50245013        if (col->cssValueId == cssValueId)
    50255014            return col->color;
     5015    }
    50265016    return theme()->systemColor(cssValueId);
    50275017}
     
    50415031            else {
    50425032                if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
    5043                     checkPseudoState(m_element);
     5033                    pseudoState = checkPseudoState(m_element);
    50445034                col = (pseudoState == PseudoLink) ? linkColor : visitedColor;
    50455035            }
     
    50755065}
    50765066
     5067void CSSStyleSelector::allVisitedStateChanged()
     5068{
     5069    if (m_linksCheckedForVisitedState.isEmpty())
     5070        return;
     5071    for (Node* node = m_document; node; node = node->traverseNextNode()) {
     5072        if (node->isLink())
     5073            node->setChanged();
     5074    }
     5075}
     5076
     5077void CSSStyleSelector::visitedStateChanged(unsigned visitedHash)
     5078{
     5079    if (!m_linksCheckedForVisitedState.contains(visitedHash))
     5080        return;
     5081    for (Node* node = m_document; node; node = node->traverseNextNode()) {
     5082        const AtomicString* attr = linkAttribute(node);
     5083        if (attr && m_document->visitedLinkHash(*attr) == visitedHash)
     5084            node->setChanged();
     5085    }
     5086}
     5087
    50775088} // namespace WebCore
  • trunk/WebCore/css/CSSStyleSelector.h

    r30840 r30949  
    2626#include "MediaQueryExp.h"
    2727#include "RenderStyle.h"
     28#include "StringHash.h"
    2829#include <wtf/HashSet.h>
     30#include <wtf/HashMap.h>
    2931#include <wtf/Vector.h>
    3032#include <wtf/RefPtr.h>
     
    5759class StyledElement;
    5860
    59 class MediaQueryResult
    60 {
     61class MediaQueryResult {
    6162public:
    6263    MediaQueryResult(const MediaQueryExp& expr, bool result)
    63     : m_expression(expr)
    64     , m_result(result)
    65     {}
     64        : m_expression(expr)
     65        , m_result(result)
     66    {
     67    }
    6668
    6769    MediaQueryExp m_expression;
     
    6971};
    7072
    71     /**
    72      * this class selects a RenderStyle for a given Element based on the
    73      * collection of styleshets it contains. This is just a vrtual base class
    74      * for specific implementations of the Selector. At the moment only CSSStyleSelector
    75      * exists, but someone may wish to implement XSL.
    76      */
    77     class StyleSelector {
    78     public:
    79         enum State {
    80             None = 0x00,
    81             Hover = 0x01,
    82             Focus = 0x02,
    83             Active = 0x04,
    84             Drag = 0x08
    85         };
    86     };
    87 
    88     /**
    89      * the StyleSelector implementation for CSS.
    90      */
    91     class CSSStyleSelector : public StyleSelector {
     73    // This class selects a RenderStyle for a given element based on a collection of stylesheets.
     74    class CSSStyleSelector : Noncopyable {
    9275    public:
    9376        CSSStyleSelector(Document*, const String& userStyleSheet, StyleSheetList*, CSSStyleSheet*, bool strictParsing, bool matchAuthorAndUserStyles);
    9477        ~CSSStyleSelector();
    95 
    96         static void loadDefaultStyle();
    9778
    9879        void initElementAndPseudoState(Element*);
    9980        void initForStyleResolve(Element*, RenderStyle* parentStyle);
    10081        RenderStyle* styleForElement(Element*, RenderStyle* parentStyle = 0, bool allowSharing = true, bool resolveForRootDefault = false);
     82
    10183        RenderStyle* pseudoStyleForElement(RenderStyle::PseudoId, Element*, RenderStyle* parentStyle = 0);
    10284
     85    private:
    10386        RenderStyle* locateSharedStyle();
    10487        Node* locateCousinList(Element* parent, unsigned depth = 1);
    105         bool canShareStyleWithElement(Node* n);
    106 
     88        bool canShareStyleWithElement(Node*);
     89
     90    public:
    10791        // These methods will give back the set of rules that matched for a given element (or a pseudo-element).
    10892        RefPtr<CSSRuleList> styleRulesForElement(Element*, bool authorOnly);
    109         RefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, StringImpl* pseudoStyle, bool authorOnly);
    110 
    111         bool strictParsing;
     93        RefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, const String& pseudoStyle, bool authorOnly);
    11294
    11395        // Given a CSS keyword in the range (xx-small to -webkit-xxx-large), this function will return
     
    11597        float fontSizeForKeyword(int keyword, bool quirksMode, bool monospace) const;
    11698
     99    private:
    117100        // When the CSS keyword "larger" is used, this function will attempt to match within the keyword
    118101        // table, and failing that, will simply multiply by 1.2.
     
    122105        float smallerFontSize(float size, bool quirksMode) const;
    123106
     107    public:
    124108        void setFontSize(FontDescription&, float size);
     109
     110    private:
    125111        float getComputedSizeFromSpecifiedSize(bool isAbsoluteSize, float specifiedSize);
    126112
     113    public:
    127114        Color getColorFromPrimitiveValue(CSSPrimitiveValue*);
    128115
     
    131118        CSSFontSelector* fontSelector() { return m_fontSelector.get(); }
    132119
    133         /* checks if a compound selector (which can consist of multiple simple selectors)
    134            matches the given Element */
     120        // Checks if a compound selector (which can consist of multiple simple selectors) matches the current element.
    135121        bool checkSelector(CSSSelector*);
    136122
    137123        void addViewportDependentMediaQueryResult(const MediaQueryExp*, bool result);
     124
    138125        bool affectedByViewportChange() const;
    139        
    140     protected:
    141         enum SelectorMatch {
    142             SelectorMatches = 0,
    143             SelectorFailsLocally,
    144             SelectorFailsCompletely
    145         };
    146 
    147         SelectorMatch checkSelector(CSSSelector*, Element *, bool isAncestor, bool isSubSelector);
    148 
    149         /* checks if the selector matches the given Element */
     126
     127        void allVisitedStateChanged();
     128        void visitedStateChanged(unsigned visitedHash);
     129
     130    private:
     131        enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsCompletely };
     132        SelectorMatch checkSelector(CSSSelector*, Element*, bool isAncestor, bool isSubSelector);
     133
     134        // Checks if the selector matches the given Element.
    150135        bool checkOneSelector(CSSSelector*, Element*, bool isAncestor, bool isSubSelector = false);
    151136
    152         /* This function fixes up the default font size if it detects that the
    153            current generic font family has changed. -dwh */
    154         void checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle);
     137        // This function fixes up the default font size if it detects that the current generic font family has changed. -dwh
     138        void checkForGenericFamilyChange(RenderStyle*, RenderStyle* parentStyle);
    155139        void checkForTextSizeAdjust();
    156140
     
    161145
    162146        void matchRules(CSSRuleSet*, int& firstRuleIndex, int& lastRuleIndex);
    163         void matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex);
     147        void matchRulesForList(CSSRuleDataList*, int& firstRuleIndex, int& lastRuleIndex);
    164148        void sortMatchedRules(unsigned start, unsigned end);
    165149
    166150        void applyDeclarations(bool firstPass, bool important, int startIndex, int endIndex);
    167151
    168         static CSSStyleSheet* m_defaultSheet;
    169         static CSSStyleSheet* m_quirksSheet;
    170         static CSSStyleSheet* m_viewSourceSheet;
    171 #if ENABLE(SVG)
    172         static CSSStyleSheet* m_svgSheet;
    173 #endif
    174 
    175         static CSSRuleSet* m_defaultStyle;
    176         static CSSRuleSet* m_defaultQuirksStyle;
    177         static CSSRuleSet* m_defaultPrintStyle;
    178         static CSSRuleSet* m_defaultViewSourceStyle;
     152        bool m_strictParsing;
    179153
    180154        CSSRuleSet* m_authorStyle;
     
    188162
    189163    public:
    190         static RenderStyle* m_styleNotYetAvailable;
    191 
    192     private:
     164        static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; }
     165
     166    private:
     167        static RenderStyle* s_styleNotYetAvailable;
     168
    193169        void init();
    194170
     
    211187        void mapTransitionTimingFunction(Transition*, CSSValue*);
    212188        void mapTransitionProperty(Transition*, CSSValue*);
     189
     190        void applyProperty(int id, CSSValue*);
     191#if ENABLE(SVG)
     192        void applySVGProperty(int id, CSSValue*);
     193#endif
     194
     195        PseudoState checkPseudoState(Element*, bool checkVisited = true);
    213196
    214197        // We collect the set of decls that match in |m_matchedDecls|.  We then walk the
     
    247230        Vector<MediaQueryResult*> m_viewportDependentMediaQueryResults;
    248231
    249         void applyProperty(int id, CSSValue*);
    250 
    251 #if ENABLE(SVG)
    252         void applySVGProperty(int id, CSSValue*);
    253 #endif
    254 
    255         friend class CSSRuleSet;
    256         friend class Node;
     232        HashSet<unsigned, AlreadyHashed> m_linksCheckedForVisitedState;
    257233    };
    258234
  • trunk/WebCore/dom/Document.cpp

    r30942 r30949  
    27862786}
    27872787
    2788 KURL Document::completeURL(const String& url)
     2788KURL Document::completeURL(const String& url) const
    27892789{
    27902790    // Always return a null URL when passed a null string.
     
    37723772}
    37733773
     3774static inline int findSlashDotDotSlash(const UChar* characters, size_t length)
     3775{
     3776    if (length < 4)
     3777        return -1;
     3778    unsigned loopLimit = length - 3;
     3779    for (unsigned i = 0; i < loopLimit; ++i) {
     3780        if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/')
     3781            return i;
     3782    }
     3783    return -1;
     3784}
     3785
     3786static inline int findSlashSlash(const UChar* characters, size_t length, int position)
     3787{
     3788    if (length < 2)
     3789        return -1;
     3790    unsigned loopLimit = length - 1;
     3791    for (unsigned i = position; i < loopLimit; ++i) {
     3792        if (characters[i] == '/' && characters[i + 1] == '/')
     3793            return i;
     3794    }
     3795    return -1;
     3796}
     3797
     3798static inline int findSlashDotSlash(const UChar* characters, size_t length)
     3799{
     3800    if (length < 3)
     3801        return -1;
     3802    unsigned loopLimit = length - 2;
     3803    for (unsigned i = 0; i < loopLimit; ++i) {
     3804        if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/')
     3805            return i;
     3806    }
     3807    return -1;
     3808}
     3809
     3810static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
     3811{
     3812    if (length < 3)
     3813        return false;
     3814    unsigned loopLimit = length - 2;
     3815    for (unsigned i = 0; i < loopLimit; ++i) {
     3816        if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
     3817            return true;
     3818    }
     3819    return false;
     3820}
     3821
     3822static inline void cleanPath(Vector<UChar, 512>& path)
     3823{
     3824    // FIXME: Shold not do this in the query or anchor part.
     3825    int pos;
     3826    while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) {
     3827        int prev = reverseFind(path.data(), path.size(), '/', pos - 1);
     3828        // don't remove the host, i.e. http://foo.org/../foo.html
     3829        if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/'))
     3830            path.remove(pos, 3);
     3831        else
     3832            path.remove(prev, pos - prev + 3);
     3833    }
     3834
     3835    // FIXME: Shold not do this in the query part.
     3836    // Set refPos to -2 to mean "I haven't looked for the anchor yet".
     3837    // We don't want to waste a function call on the search for the the anchor
     3838    // in the vast majority of cases where there is no "//" in the path.
     3839    pos = 0;
     3840    int refPos = -2;
     3841    while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) {
     3842        if (refPos == -2)
     3843            refPos = find(path.data(), path.size(), '#');
     3844        if (refPos > 0 && pos >= refPos)
     3845            break;
     3846
     3847        if (pos == 0 || path[pos - 1] != ':')
     3848            path.remove(pos);
     3849        else
     3850            pos += 2;
     3851    }
     3852
     3853    // FIXME: Shold not do this in the query or anchor part.
     3854    while ((pos = findSlashDotSlash(path.data(), path.size())) != -1)
     3855        path.remove(pos, 2);
     3856}
     3857
     3858static inline bool matchLetter(UChar c, UChar lowercaseLetter)
     3859{
     3860    return (c | 0x20) == lowercaseLetter;
     3861}
     3862
     3863static inline bool needsTrailingSlash(const UChar* characters, unsigned length)
     3864{
     3865    if (length < 6)
     3866        return false;
     3867    if (!matchLetter(characters[0], 'h')
     3868            || !matchLetter(characters[1], 't')
     3869            || !matchLetter(characters[2], 't')
     3870            || !matchLetter(characters[3], 'p'))
     3871        return false;
     3872    if (!(characters[4] == ':'
     3873            || (matchLetter(characters[4], 's') && characters[5] == ':')))
     3874        return false;
     3875
     3876    unsigned pos = characters[4] == ':' ? 5 : 6;
     3877
     3878    // Skip initial two slashes if present.
     3879    if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/')
     3880        pos += 2;
     3881
     3882    // Find next slash.
     3883    while (pos < length && characters[pos] != '/')
     3884        ++pos;
     3885
     3886    return pos == length;
     3887}
     3888
     3889unsigned Document::visitedLinkHash(const AtomicString& attributeURL) const
     3890{
     3891    const UChar* characters = attributeURL.characters();
     3892    unsigned length = attributeURL.length();
     3893    if (!length)
     3894        return 0;
     3895
     3896    // This is a poor man's completeURL. Faster with less memory allocation.
     3897    // FIXME: It's missing a lot of what completeURL does and a lot of what KURL does.
     3898    // For example, it does not handle international domain names properly.
     3899
     3900    // FIXME: It is wrong that we do not do further processing on strings that have "://" in them:
     3901    //    1) The "://" could be in the query or anchor.
     3902    //    2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it.
     3903
     3904    // FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does
     3905    // have a query or anchor.
     3906
     3907    bool hasColonSlashSlash = containsColonSlashSlash(characters, length);
     3908
     3909    if (hasColonSlashSlash && !needsTrailingSlash(characters, length))
     3910        return AlreadyHashed::avoidDeletedValue(attributeURL.string().impl()->hash());
     3911
     3912    Vector<UChar, 512> buffer;
     3913
     3914    if (hasColonSlashSlash) {
     3915        // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
     3916        // end of the path, *before* the query or anchor.
     3917        buffer.append(characters, length);
     3918        buffer.append('/');
     3919        return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()));
     3920    }
     3921
     3922    switch (characters[0]) {
     3923        case '/':
     3924            buffer.append(m_baseURL.string().characters(), m_baseURL.pathStart());
     3925            break;
     3926        case '#':
     3927            buffer.append(m_baseURL.string().characters(), m_baseURL.pathEnd());
     3928            break;
     3929        default:
     3930            buffer.append(m_baseURL.string().characters(), m_baseURL.pathAfterLastSlash());
     3931            break;
     3932    }
     3933    buffer.append(characters, length);
     3934    cleanPath(buffer);
     3935    if (needsTrailingSlash(buffer.data(), buffer.size())) {
     3936        // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
     3937        // end of the path, *before* the query or anchor.
     3938        buffer.append('/');
     3939    }
     3940
     3941    return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()));
     3942}
     3943
    37743944#if ENABLE(DATABASE)
    37753945
  • trunk/WebCore/dom/Document.h

    r30633 r30949  
    383383    void setBaseTarget(const String& baseTarget) { m_baseTarget = baseTarget; }
    384384
    385     KURL completeURL(const String&);
     385    KURL completeURL(const String&) const;
     386
     387    unsigned visitedLinkHash(const AtomicString& attributeURL) const;
    386388
    387389    // from cachedObjectClient
  • trunk/WebCore/loader/FrameLoader.cpp

    r30923 r30949  
    18081808}
    18091809
    1810 // This does the same kind of work that FrameLoader::openURL does, except it relies on the fact
     1810// This does the same kind of work that didOpenURL does, except it relies on the fact
    18111811// that a higher level already checked that the URLs match and the scrolling is the right thing to do.
    18121812void FrameLoader::scrollToAnchor(const KURL& url)
    18131813{
    18141814    m_URL = url;
     1815    updateHistoryForAnchorScroll();
    18151816    started();
    1816 
    18171817    gotoAnchor();
    18181818
     
    43824382}
    43834383
     4384void FrameLoader::updateHistoryForAnchorScroll()
     4385{
     4386    if (m_URL.isEmpty())
     4387        return;
     4388
     4389    Settings* settings = m_frame->settings();
     4390    if (!settings || settings->privateBrowsingEnabled())
     4391        return;
     4392
     4393    Page* page = m_frame->page();
     4394    if (!page)
     4395        return;
     4396
     4397    page->group().addVisitedLink(m_URL);
     4398}
     4399
    43844400// Walk the frame tree, telling all frames to save their form state into their current
    43854401// history item.
  • trunk/WebCore/loader/FrameLoader.h

    r30840 r30949  
    456456        void updateHistoryForClientRedirect();
    457457        void updateHistoryForCommit();
     458        void updateHistoryForAnchorScroll();
    458459   
    459460        void redirectionTimerFired(Timer<FrameLoader>*);
  • trunk/WebCore/page/DOMWindow.cpp

    r30923 r30949  
    617617
    618618    if (!pseudoElt.isEmpty())
    619         return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt.impl(), authorOnly);
     619        return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly);
    620620    return doc->styleSelector()->styleRulesForElement(elt, authorOnly);
    621621}
  • trunk/WebCore/page/Page.cpp

    r30923 r30949  
    2525#include "ContextMenuClient.h"
    2626#include "ContextMenuController.h"
     27#include "CSSStyleSelector.h"
    2728#include "EditorClient.h"
    2829#include "DOMWindow.h"
     
    422423}
    423424
     425void Page::allVisitedStateChanged(PageGroup* group)
     426{
     427    ASSERT(group);
     428    ASSERT(allPages);
     429    HashSet<Page*>::iterator pagesEnd = allPages->end();
     430    for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
     431        Page* page = *it;
     432        if (page->m_group != group)
     433            continue;
     434        for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
     435            if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
     436                styleSelector->allVisitedStateChanged();
     437        }
     438    }
     439}
     440
     441void Page::visitedStateChanged(PageGroup* group, unsigned visitedLinkHash)
     442{
     443    ASSERT(group);
     444    ASSERT(allPages);
     445    HashSet<Page*>::iterator pagesEnd = allPages->end();
     446    for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
     447        Page* page = *it;
     448        if (page->m_group != group)
     449            continue;
     450        for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
     451            if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
     452                styleSelector->visitedStateChanged(visitedLinkHash);
     453        }
     454    }
     455}
     456
    424457void Page::setDebuggerForAllPages(KJS::Debugger* debugger)
    425458{
  • trunk/WebCore/page/Page.h

    r30923 r30949  
    154154        static void removeAllVisitedLinks();
    155155
     156        static void allVisitedStateChanged(PageGroup*);
     157        static void visitedStateChanged(PageGroup*, unsigned visitedHash);
     158
    156159    private:
    157160        void initGroup();
  • trunk/WebCore/page/PageGroup.cpp

    r30873 r30949  
    3737static bool shouldTrackVisitedLinks;
    3838
    39 // To use a hash value as a key for a hash table, we need to eliminate the
    40 // "deleted" value, which is negative one. That could be done by changing
    41 // the hash function to never generate negative one, but this works and is
    42 // still relatively efficient.
    43 static inline unsigned avoidDeletedValue(unsigned hash)
    44 {
    45     ASSERT(hash);
    46     unsigned newHash = hash | (!(hash + 1) << 31);
    47     ASSERT(newHash);
    48     ASSERT(newHash != 0xFFFFFFFF);
    49     return newHash;
    50 }
    51 
    5239PageGroup::PageGroup(Page* page)
    5340    : m_visitedLinksPopulated(false)
     
    7158}
    7259
    73 static inline int findSlashDotDotSlash(const UChar* characters, size_t length)
    74 {
    75     if (length < 4)
    76         return -1;
    77     unsigned loopLimit = length - 3;
    78     for (unsigned i = 0; i < loopLimit; ++i) {
    79         if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/')
    80             return i;
    81     }
    82     return -1;
    83 }
    84 
    85 static inline int findSlashSlash(const UChar* characters, size_t length, int position)
    86 {
    87     if (length < 2)
    88         return -1;
    89     unsigned loopLimit = length - 1;
    90     for (unsigned i = position; i < loopLimit; ++i) {
    91         if (characters[i] == '/' && characters[i + 1] == '/')
    92             return i;
    93     }
    94     return -1;
    95 }
    96 
    97 static inline int findSlashDotSlash(const UChar* characters, size_t length)
    98 {
    99     if (length < 3)
    100         return -1;
    101     unsigned loopLimit = length - 2;
    102     for (unsigned i = 0; i < loopLimit; ++i) {
    103         if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/')
    104             return i;
    105     }
    106     return -1;
    107 }
    108 
    109 static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
    110 {
    111     if (length < 3)
    112         return false;
    113     unsigned loopLimit = length - 2;
    114     for (unsigned i = 0; i < loopLimit; ++i) {
    115         if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
    116             return true;
    117     }
    118     return false;
    119 }
    120 
    121 static inline void cleanPath(Vector<UChar, 512>& path)
    122 {
    123     // FIXME: Shold not do this in the query or anchor part.
    124     int pos;
    125     while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) {
    126         int prev = reverseFind(path.data(), path.size(), '/', pos - 1);
    127         // don't remove the host, i.e. http://foo.org/../foo.html
    128         if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/'))
    129             path.remove(pos, 3);
    130         else
    131             path.remove(prev, pos - prev + 3);
    132     }
    133 
    134     // FIXME: Shold not do this in the query part.
    135     // Set refPos to -2 to mean "I haven't looked for the anchor yet".
    136     // We don't want to waste a function call on the search for the the anchor
    137     // in the vast majority of cases where there is no "//" in the path.
    138     pos = 0;
    139     int refPos = -2;
    140     while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) {
    141         if (refPos == -2)
    142             refPos = find(path.data(), path.size(), '#');
    143         if (refPos > 0 && pos >= refPos)
    144             break;
    145 
    146         if (pos == 0 || path[pos - 1] != ':')
    147             path.remove(pos);
    148         else
    149             pos += 2;
    150     }
    151 
    152     // FIXME: Shold not do this in the query or anchor part.
    153     while ((pos = findSlashDotSlash(path.data(), path.size())) != -1)
    154         path.remove(pos, 2);
    155 }
    156 
    157 static inline bool matchLetter(UChar c, UChar lowercaseLetter)
    158 {
    159     return (c | 0x20) == lowercaseLetter;
    160 }
    161 
    162 static inline bool needsTrailingSlash(const UChar* characters, unsigned length)
    163 {
    164     if (length < 6)
    165         return false;
    166     if (!matchLetter(characters[0], 'h')
    167             || !matchLetter(characters[1], 't')
    168             || !matchLetter(characters[2], 't')
    169             || !matchLetter(characters[3], 'p'))
    170         return false;
    171     if (!(characters[4] == ':'
    172             || (matchLetter(characters[4], 's') && characters[5] == ':')))
    173         return false;
    174 
    175     unsigned pos = characters[4] == ':' ? 5 : 6;
    176 
    177     // Skip initial two slashes if present.
    178     if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/')
    179         pos += 2;
    180 
    181     // Find next slash.
    182     while (pos < length && characters[pos] != '/')
    183         ++pos;
    184 
    185     return pos == length;
    186 }
    187 
    188 bool PageGroup::isLinkVisited(Document* document, const AtomicString& attributeURL)
     60bool PageGroup::isLinkVisited(unsigned visitedLinkHash)
    18961{
    19062    if (!m_visitedLinksPopulated) {
     
    19365        (*m_pages.begin())->chrome()->client()->populateVisitedLinks();
    19466    }
     67    return m_visitedLinkHashes.contains(visitedLinkHash);
     68}
    19569
    196     const UChar* characters = attributeURL.characters();
    197     unsigned length = attributeURL.length();
    198     if (!length)
    199         return false;
    200 
    201     // FIXME: It is wrong that we do not do further processing on strings that have "://" in them:
    202     //    1) The "://" could be in the query or anchor.
    203     //    2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it.
    204 
    205     // FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does
    206     // have a query or anchor.
    207 
    208     bool hasColonSlashSlash = containsColonSlashSlash(characters, length);
    209 
    210     if (hasColonSlashSlash && !needsTrailingSlash(characters, length))
    211         return m_visitedLinkHashes.contains(avoidDeletedValue(attributeURL.string().impl()->hash()));
    212 
    213     Vector<UChar, 512> buffer;
    214 
    215     // This is a poor man's completeURL. Faster with less memory allocation.
    216     // FIXME: It's missing a lot of what completeURL does and what KURL does.
    217     // FIXME: Move this into KURL? Or Document? Even the fast version should be in the right place,
    218     // rather than here.
    219 
    220     if (hasColonSlashSlash) {
    221         // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
    222         // end of the path, *before* the query or anchor.
    223         buffer.append(characters, length);
    224         buffer.append('/');
    225         return m_visitedLinkHashes.contains(avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size())));
    226     }
    227 
    228     const KURL& baseURL = document->baseURL();
    229     switch (characters[0]) {
    230         case '/':
    231             buffer.append(baseURL.string().characters(), baseURL.pathStart());
    232             break;
    233         case '#':
    234             buffer.append(baseURL.string().characters(), baseURL.pathEnd());
    235             break;
    236         default:
    237             buffer.append(baseURL.string().characters(), baseURL.pathAfterLastSlash());
    238             break;
    239     }
    240     buffer.append(characters, length);
    241     cleanPath(buffer);
    242     if (needsTrailingSlash(buffer.data(), buffer.size())) {
    243         // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the
    244         // end of the path, *before* the query or anchor.
    245         buffer.append('/');
    246     }
    247 
    248     return m_visitedLinkHashes.contains(avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size())));
     70inline void PageGroup::addVisitedLink(unsigned stringHash)
     71{
     72    ASSERT(shouldTrackVisitedLinks);
     73    unsigned visitedLinkHash = AlreadyHashed::avoidDeletedValue(stringHash);
     74    if (!m_visitedLinkHashes.add(visitedLinkHash).second)
     75        return;
     76    Page::visitedStateChanged(this, visitedLinkHash);
    24977}
    25078
     
    25482        return;
    25583    ASSERT(!url.isEmpty());
    256     m_visitedLinkHashes.add(avoidDeletedValue(url.string().impl()->hash()));
     84    addVisitedLink(url.string().impl()->hash());
    25785}
    25886
     
    26189    if (!shouldTrackVisitedLinks)
    26290        return;
    263     m_visitedLinkHashes.add(avoidDeletedValue(StringImpl::computeHash(characters, length)));
     91    addVisitedLink(StringImpl::computeHash(characters, length));
    26492}
    26593
    26694void PageGroup::removeVisitedLinks()
    26795{
     96    m_visitedLinksPopulated = false;
     97    if (m_visitedLinkHashes.isEmpty())
     98        return;
    26899    m_visitedLinkHashes.clear();
    269     m_visitedLinksPopulated = false;
     100    Page::allVisitedStateChanged(this);
    270101}
    271102
  • trunk/WebCore/page/PageGroup.h

    r30873 r30949  
    2929#include <wtf/HashSet.h>
    3030#include <wtf/Noncopyable.h>
    31 #include <wtf/unicode/Unicode.h>
     31#include "StringHash.h"
    3232
    3333namespace WebCore {
    3434
    35     class AtomicString;
    36     class Document;
    3735    class KURL;
    3836    class Page;
    39 
    40     struct AlreadyHashed : IntHash<unsigned> {
    41         static unsigned hash(unsigned key) { return key; }
    42     };
    4337
    4438    class PageGroup : Noncopyable {
     
    5145        void removePage(Page*);
    5246
    53         bool isLinkVisited(Document*, const AtomicString& attributeValue);
     47        bool isLinkVisited(unsigned visitedLinkHash);
    5448
    5549        void addVisitedLink(const KURL&);
     
    6155
    6256    private:
     57        void addVisitedLink(unsigned stringHash);
     58
    6359        HashSet<Page*> m_pages;
    6460        HashSet<unsigned, AlreadyHashed> m_visitedLinkHashes;
  • trunk/WebCore/platform/text/StringHash.h

    r29098 r30949  
    11/*
    2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved
     2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    2828
    2929namespace WebCore {
     30
     31    // FIXME: We should really figure out a way to put the computeHash function that's
     32    // currently a member function of StringImpl into this file so we can be a little
     33    // cloer to having all the nearly-identical hash functions in one place.
    3034
    3135    struct StringHash {
     
    7983        // Paul Hsieh's SuperFastHash
    8084        // http://www.azillionmonkeys.com/qed/hash.html
     85        static unsigned hash(const UChar* data, unsigned length)
     86        {
     87            unsigned l = length;
     88            const UChar* s = data;
     89            uint32_t hash = PHI;
     90            uint32_t tmp;
     91           
     92            int rem = l & 1;
     93            l >>= 1;
     94           
     95            // Main loop.
     96            for (; l > 0; l--) {
     97                hash += WTF::Unicode::foldCase(s[0]);
     98                tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash;
     99                hash = (hash << 16) ^ tmp;
     100                s += 2;
     101                hash += hash >> 11;
     102            }
     103           
     104            // Handle end case.
     105            if (rem) {
     106                hash += WTF::Unicode::foldCase(s[0]);
     107                hash ^= hash << 11;
     108                hash += hash >> 17;
     109            }
     110           
     111            // Force "avalanching" of final 127 bits.
     112            hash ^= hash << 3;
     113            hash += hash >> 5;
     114            hash ^= hash << 2;
     115            hash += hash >> 15;
     116            hash ^= hash << 10;
     117           
     118            // This avoids ever returning a hash code of 0, since that is used to
     119            // signal "hash not computed yet", using a value that is likely to be
     120            // effectively the same as 0 when the low bits are masked.
     121            hash |= !hash << 31;
     122           
     123            return hash;
     124        }
     125
    81126        static unsigned hash(StringImpl* str)
    82127        {
    83             unsigned l = str->length();
    84             const UChar* s = str->characters();
     128            return hash(str->characters(), str->length());
     129        }
     130       
     131        static unsigned hash(const char* str, unsigned length)
     132        {
     133            // This hash is designed to work on 16-bit chunks at a time. But since the normal case
     134            // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
     135            // were 16-bit chunks, which will give matching results.
     136
     137            unsigned l = length;
     138            const char* s = str;
    85139            uint32_t hash = PHI;
    86140            uint32_t tmp;
     
    115169            // signal "hash not computed yet", using a value that is likely to be
    116170            // effectively the same as 0 when the low bits are masked
    117             if (hash == 0)
    118                 hash = 0x80000000;
    119            
    120             return hash;
    121         }
    122        
    123         static unsigned hash(const char* str, unsigned length)
    124         {
    125             // This hash is designed to work on 16-bit chunks at a time. But since the normal case
    126             // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
    127             // were 16-bit chunks, which will give matching results.
    128 
    129             unsigned l = length;
    130             const char* s = str;
    131             uint32_t hash = PHI;
    132             uint32_t tmp;
    133            
    134             int rem = l & 1;
    135             l >>= 1;
    136            
    137             // Main loop
    138             for (; l > 0; l--) {
    139                 hash += WTF::Unicode::foldCase(s[0]);
    140                 tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash;
    141                 hash = (hash << 16) ^ tmp;
    142                 s += 2;
    143                 hash += hash >> 11;
    144             }
    145            
    146             // Handle end case
    147             if (rem) {
    148                 hash += WTF::Unicode::foldCase(s[0]);
    149                 hash ^= hash << 11;
    150                 hash += hash >> 17;
    151             }
    152            
    153             // Force "avalanching" of final 127 bits
    154             hash ^= hash << 3;
    155             hash += hash >> 5;
    156             hash ^= hash << 2;
    157             hash += hash >> 15;
    158             hash ^= hash << 10;
    159            
    160             // this avoids ever returning a hash code of 0, since that is used to
    161             // signal "hash not computed yet", using a value that is likely to be
    162             // effectively the same as 0 when the low bits are masked
    163             if (hash == 0)
    164                 hash = 0x80000000;
     171            hash |= !hash << 31;
    165172           
    166173            return hash;
     
    199206
    200207        static const bool safeToCompareToEmptyOrDeleted = false;
     208    };
     209
     210    // This hash can be used in cases where the key is a hash of a string, but we don't
     211    // want to store the string. It's not really specific to string hashing, but all our
     212    // current uses of it are for strings.
     213    struct AlreadyHashed : IntHash<unsigned> {
     214        static unsigned hash(unsigned key) { return key; }
     215
     216        // To use a hash value as a key for a hash table, we need to eliminate the
     217        // "deleted" value, which is negative one. That could be done by changing
     218        // the string hash function to never generate negative one, but this works
     219        // and is still relatively efficient.
     220        static unsigned avoidDeletedValue(unsigned hash)
     221        {
     222            ASSERT(hash);
     223            unsigned newHash = hash | (!(hash + 1) << 31);
     224            ASSERT(newHash);
     225            ASSERT(newHash != 0xFFFFFFFF);
     226            return newHash;
     227        }
    201228    };
    202229
  • trunk/WebCore/rendering/RenderStyle.cpp

    r30667 r30949  
    10671067bool RenderStyle::isStyleAvailable() const
    10681068{
    1069     return this != CSSStyleSelector::m_styleNotYetAvailable;
     1069    return this != CSSStyleSelector::styleNotYetAvailable();
    10701070}
    10711071
Note: See TracChangeset for help on using the changeset viewer.