Title: [102606] trunk/Source/WebCore
Revision
102606
Author
an...@apple.com
Date
2011-12-12 10:56:20 -0800 (Mon, 12 Dec 2011)

Log Message

Cache visited link hash
https://bugs.webkit.org/show_bug.cgi?id=74095

Reviewed by Darin Adler.

Visited link hash is relatively expensive to compute. We can cache it for anchor elements
with minimal relative memory cost for faster style resolve.
        
On my machine this speeds up style matching on full HTML spec by ~100ms or ~1% of the total
CPU usage. It makes link elements 8 bytes larger, a relatively minor increase to their overall size.
        
Invalidate the hashes on base URL for completeness sake (lack of style invalidation means
that this scenario is not properly supported currently).

Covered by existing tests. No specific test for visited hash invalidation on dynamic base URL 
change as the effect is not testable due to lack of style invalidation.

* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::determineLinkStateSlowCase):
(WebCore::SelectorChecker::visitedStateChanged):
* html/Document.cpp:
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::HTMLAnchorElement):
(WebCore::HTMLAnchorElement::parseMappedAttribute):
* html/HTMLAnchorElement.h:
(WebCore::HTMLAnchorElement::visitedLinkHash):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (102605 => 102606)


--- trunk/Source/WebCore/ChangeLog	2011-12-12 18:48:43 UTC (rev 102605)
+++ trunk/Source/WebCore/ChangeLog	2011-12-12 18:56:20 UTC (rev 102606)
@@ -1,3 +1,32 @@
+2011-12-12  Antti Koivisto  <an...@apple.com>
+
+        Cache visited link hash
+        https://bugs.webkit.org/show_bug.cgi?id=74095
+
+        Reviewed by Darin Adler.
+
+        Visited link hash is relatively expensive to compute. We can cache it for anchor elements
+        with minimal relative memory cost for faster style resolve.
+        
+        On my machine this speeds up style matching on full HTML spec by ~100ms or ~1% of the total
+        CPU usage. It makes link elements 8 bytes larger, a relatively minor increase to their overall size.
+        
+        Invalidate the hashes on base URL for completeness sake (lack of style invalidation means
+        that this scenario is not properly supported currently).
+
+        Covered by existing tests. No specific test for visited hash invalidation on dynamic base URL 
+        change as the effect is not testable due to lack of style invalidation.
+
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::determineLinkStateSlowCase):
+        (WebCore::SelectorChecker::visitedStateChanged):
+        * html/Document.cpp:
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::HTMLAnchorElement):
+        (WebCore::HTMLAnchorElement::parseMappedAttribute):
+        * html/HTMLAnchorElement.h:
+        (WebCore::HTMLAnchorElement::visitedLinkHash):
+
 2011-12-12  Martin Robinson  <mrobin...@igalia.com>
 
         [GTK] gtk_widget_size_allocate for plugin widgets should happen in the WebView size-allocate method

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (102605 => 102606)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2011-12-12 18:48:43 UTC (rev 102605)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2011-12-12 18:56:20 UTC (rev 102606)
@@ -34,6 +34,7 @@
 #include "FocusController.h"
 #include "Frame.h"
 #include "FrameSelection.h"
+#include "HTMLAnchorElement.h"
 #include "HTMLFrameElementBase.h"
 #include "HTMLInputElement.h"
 #include "HTMLNames.h"
@@ -225,16 +226,21 @@
 {
     ASSERT(element->isLink());
 
-    const AtomicString* attr = linkAttribute(element);
-    if (!attr || attr->isNull())
+    const AtomicString* attribute = linkAttribute(element);
+    if (!attribute || attribute->isNull())
         return NotInsideLink;
 
     // An empty href refers to the document itself which is always visited. It is useful to check this explicitly so
     // that visited links can be tested in platform independent manner, without explicit support in the test harness.
-    if (attr->isEmpty())
+    if (attribute->isEmpty())
         return InsideVisitedLink;
+    
+    LinkHash hash;
+    if (element->hasTagName(aTag)) 
+        hash = static_cast<HTMLAnchorElement*>(element)->visitedLinkHash();
+    else
+        hash = visitedLinkHash(m_document->baseURL(), *attribute);
 
-    LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr);
     if (!hash)
         return InsideUnvisitedLink;
 
@@ -249,7 +255,7 @@
     m_linksCheckedForVisitedState.add(hash);
 
 #if USE(PLATFORM_STRATEGIES)
-    return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash, m_document->baseURL(), *attr) ? InsideVisitedLink : InsideUnvisitedLink;
+    return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash, m_document->baseURL(), *attribute) ? InsideVisitedLink : InsideUnvisitedLink;
 #else
     return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink;
 #endif
@@ -1308,8 +1314,12 @@
     if (!m_linksCheckedForVisitedState.contains(visitedHash))
         return;
     for (Node* node = m_document; node; node = node->traverseNextNode()) {
-        const AtomicString* attr = linkAttribute(node);
-        if (attr && visitedLinkHash(m_document->baseURL(), *attr) == visitedHash)
+        LinkHash hash = 0;
+        if (node->hasTagName(aTag))
+            hash = static_cast<HTMLAnchorElement*>(node)->visitedLinkHash();
+        else if (const AtomicString* attr = linkAttribute(node))
+            hash = visitedLinkHash(m_document->baseURL(), *attr);
+        if (hash == visitedHash)
             node->setNeedsStyleRecalc();
     }
 }

Modified: trunk/Source/WebCore/dom/Document.cpp (102605 => 102606)


--- trunk/Source/WebCore/dom/Document.cpp	2011-12-12 18:48:43 UTC (rev 102605)
+++ trunk/Source/WebCore/dom/Document.cpp	2011-12-12 18:56:20 UTC (rev 102606)
@@ -2432,6 +2432,7 @@
 
 void Document::updateBaseURL()
 {
+    KURL oldBaseURL = m_baseURL;
     // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using
     // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute
     // from the Document interface otherwise.
@@ -2452,6 +2453,15 @@
         m_elemSheet->setFinalURL(m_baseURL);
     if (m_mappedElementSheet)
         m_mappedElementSheet->setFinalURL(m_baseURL);
+    
+    if (!equalIgnoringFragmentIdentifier(oldBaseURL, m_baseURL)) {
+        // Base URL change changes any relative visited links.
+        // FIXME: There are other URLs in the tree that would need to be re-evaluated on dynamic base URL change. Style should be invalidated too.
+        for (Node* node = firstChild(); node; node = node->traverseNextNode()) {
+            if (node->hasTagName(aTag))
+                static_cast<HTMLAnchorElement*>(node)->invalidateCachedVisitedLinkHash();
+        }
+    }
 }
 
 void Document::setBaseURLOverride(const KURL& url)

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (102605 => 102606)


--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2011-12-12 18:48:43 UTC (rev 102605)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2011-12-12 18:56:20 UTC (rev 102606)
@@ -50,6 +50,7 @@
     : HTMLElement(tagName, document)
     , m_wasShiftKeyDownOnMouseDown(false)
     , m_linkRelations(0)
+    , m_cachedVisitedLinkHash(0)
 {
 }
 
@@ -221,6 +222,7 @@
                 attr->setValue(nullAtom);
             }
         }
+        invalidateCachedVisitedLinkHash();
     } else if (attr->name() == nameAttr) {
         invalidateNodeListsCacheAfterAttributeChanged();
     } else if (attr->name() == titleAttr) {

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.h (102605 => 102606)


--- trunk/Source/WebCore/html/HTMLAnchorElement.h	2011-12-12 18:48:43 UTC (rev 102605)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.h	2011-12-12 18:56:20 UTC (rev 102606)
@@ -25,6 +25,8 @@
 #define HTMLAnchorElement_h
 
 #include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "LinkHash.h"
 
 namespace WebCore {
 
@@ -92,6 +94,9 @@
 
     bool hasRel(uint32_t relation) const;
     void setRel(const String&);
+    
+    LinkHash visitedLinkHash() const;
+    void invalidateCachedVisitedLinkHash() { m_cachedVisitedLinkHash = 0; }
 
 protected:
     HTMLAnchorElement(const QualifiedName&, Document*);
@@ -131,8 +136,16 @@
     RefPtr<Element> m_rootEditableElementForSelectionOnMouseDown;
     bool m_wasShiftKeyDownOnMouseDown : 1;
     uint32_t m_linkRelations : 31;
+    mutable LinkHash m_cachedVisitedLinkHash;
 };
 
+inline LinkHash HTMLAnchorElement::visitedLinkHash() const
+{
+    if (!m_cachedVisitedLinkHash)
+        m_cachedVisitedLinkHash = WebCore::visitedLinkHash(document()->baseURL(), fastGetAttribute(HTMLNames::hrefAttr));
+    return m_cachedVisitedLinkHash; 
+}
+
 // Functions shared with the other anchor elements (i.e., SVG).
 
 bool isEnterKeyKeydownEvent(Event*);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to