- 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*);