<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[244642] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/244642">244642</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2019-04-25 02:55:38 -0700 (Thu, 25 Apr 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Visited link hash should be computed only once
https://bugs.webkit.org/show_bug.cgi?id=197229
<rdar://problem/48438924>

Reviewed by Alex Christensen.

Source/WebCore:

Test: fast/history/visited-href-mutation.html

Visited link style is now based on the first target URL of the link element. Further href mutations don't affect styling.

* dom/Document.cpp:
(WebCore::Document::updateBaseURL):
* dom/VisitedLinkState.cpp:
(WebCore::linkAttribute):
(WebCore::linkHashForElement):

Visited link support is now limited to HTML and SVG <a> elements.

(WebCore::VisitedLinkState::invalidateStyleForLink):
(WebCore::VisitedLinkState::determineLinkStateSlowCase):
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::HTMLAnchorElement):
(WebCore::HTMLAnchorElement::parseAttribute):
* html/HTMLAnchorElement.h:
(WebCore::HTMLAnchorElement::visitedLinkHash const):
(WebCore::HTMLAnchorElement::invalidateCachedVisitedLinkHash): Deleted.
* svg/SVGAElement.cpp:
(WebCore::SVGAElement::visitedLinkHash const):
* svg/SVGAElement.h:

LayoutTests:

* fast/history/visited-href-mutation-expected.html: Added.
* fast/history/visited-href-mutation.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomDocumentcpp">trunk/Source/WebCore/dom/Document.cpp</a></li>
<li><a href="#trunkSourceWebCoredomVisitedLinkStatecpp">trunk/Source/WebCore/dom/VisitedLinkState.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLAnchorElementcpp">trunk/Source/WebCore/html/HTMLAnchorElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLAnchorElementh">trunk/Source/WebCore/html/HTMLAnchorElement.h</a></li>
<li><a href="#trunkSourceWebCoresvgSVGAElementcpp">trunk/Source/WebCore/svg/SVGAElement.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGAElementh">trunk/Source/WebCore/svg/SVGAElement.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfasthistoryvisitedhrefmutationexpectedhtml">trunk/LayoutTests/fast/history/visited-href-mutation-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasthistoryvisitedhrefmutationhtml">trunk/LayoutTests/fast/history/visited-href-mutation.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/LayoutTests/ChangeLog 2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2019-04-25  Antti Koivisto  <antti@apple.com>
+
+        Visited link hash should be computed only once
+        https://bugs.webkit.org/show_bug.cgi?id=197229
+        <rdar://problem/48438924>
+
+        Reviewed by Alex Christensen.
+
+        * fast/history/visited-href-mutation-expected.html: Added.
+        * fast/history/visited-href-mutation.html: Added.
+
</ins><span class="cx"> 2019-04-25  Philippe Normand  <pnormand@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         [GStreamer] gst_element_get_state: assertion 'GST_IS_ELEMENT (element)' failed in WebCore::MediaPlayerPrivateGStreamer::paused
</span></span></pre></div>
<a id="trunkLayoutTestsfasthistoryvisitedhrefmutationexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/history/visited-href-mutation-expected.html (0 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/history/visited-href-mutation-expected.html                               (rev 0)
+++ trunk/LayoutTests/fast/history/visited-href-mutation-expected.html  2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+<style>
+.expected-link { color:blue }
+.expected-visited { color:green }
+</style>
+<a href="dummy" class="expected-visited">Case 1</a>
+<a href="dummy" class="expected-visited">Case 2</a>
+<a href="dummy" class="expected-link">Case 3</a>
+<a href="dummy" class="expected-link">Case 4</a>
+<a href="dummy" class="expected-visited">Case 5</a>
+<a href="dummy" class="expected-visited">Case 6</a>
+<a href="dummy" class="expected-link">Case 7</a>
+<a href="dummy" class="expected-link">Case 8</a>
+<a class="">Case 9</a>
+<a href="dummy" class="expected-visited">Case 10</a>
+<a href="dummy" class="expected-link">Case 11</a>
</ins></span></pre></div>
<a id="trunkLayoutTestsfasthistoryvisitedhrefmutationhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/history/visited-href-mutation.html (0 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/history/visited-href-mutation.html                                (rev 0)
+++ trunk/LayoutTests/fast/history/visited-href-mutation.html   2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+<html>
+<head>
+<script>
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.keepWebHistory();
+}
+
+function setHref(testcase, url)
+{
+    testcase.style.display = "none";
+    testcase.href = url;
+    testcase.style.display = "inline";
+}
+
+function test()
+{
+    setHref(case2, "resources/not-visited.html");
+    setHref(case4, "resources/dummy.html");
+    setHref(case6, "resources/not-visited.html");
+    setHref(case8, "");
+    setHref(case10, "resources/dummy.html");
+    setHref(case11, "resources/not-visited.html");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+</script>
+<style>
+a:link { color: blue; }
+a:visited { color: green; }
+</style>
+</head>
+<body onload="test()">
+<div>
+<a id="case1" href="resources/dummy.html">Case 1</a>
+<a id="case2" href="resources/dummy.html">Case 2</a>
+<a id="case3" href="resources/not-visited.html">Case 3</a>
+<a id="case4" href="resources/not-visited.html">Case 4</a>
+<a id="case5" href="">Case 5</a>
+<a id="case6" href="">Case 6</a>
+<a id="case7" href="resources/not-visited.html">Case 7</a>
+<a id="case8" href="resources/not-visited.html">Case 8</a>
+<a id="case9">Case 9</a>
+<a id="case10">Case 10</a>
+<a id="case11">Case 11</a>
+</div>
+<iframe src="resources/dummy.html" style="visibility:hidden"></iframe>
+</body>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/ChangeLog      2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2019-04-25  Antti Koivisto  <antti@apple.com>
+
+        Visited link hash should be computed only once
+        https://bugs.webkit.org/show_bug.cgi?id=197229
+        <rdar://problem/48438924>
+
+        Reviewed by Alex Christensen.
+
+        Test: fast/history/visited-href-mutation.html
+
+        Visited link style is now based on the first target URL of the link element. Further href mutations don't affect styling.
+
+        * dom/Document.cpp:
+        (WebCore::Document::updateBaseURL):
+        * dom/VisitedLinkState.cpp:
+        (WebCore::linkAttribute):
+        (WebCore::linkHashForElement):
+
+        Visited link support is now limited to HTML and SVG <a> elements.
+
+        (WebCore::VisitedLinkState::invalidateStyleForLink):
+        (WebCore::VisitedLinkState::determineLinkStateSlowCase):
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::HTMLAnchorElement):
+        (WebCore::HTMLAnchorElement::parseAttribute):
+        * html/HTMLAnchorElement.h:
+        (WebCore::HTMLAnchorElement::visitedLinkHash const):
+        (WebCore::HTMLAnchorElement::invalidateCachedVisitedLinkHash): Deleted.
+        * svg/SVGAElement.cpp:
+        (WebCore::SVGAElement::visitedLinkHash const):
+        * svg/SVGAElement.h:
+
</ins><span class="cx"> 2019-04-25  Philippe Normand  <pnormand@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         [GStreamer] gst_element_get_state: assertion 'GST_IS_ELEMENT (element)' failed in WebCore::MediaPlayerPrivateGStreamer::paused
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.cpp (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.cpp    2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/dom/Document.cpp       2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -3184,13 +3184,6 @@
</span><span class="cx"> 
</span><span class="cx">     if (!m_baseURL.isValid())
</span><span class="cx">         m_baseURL = URL();
</span><del>-
-    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 (auto& anchor : descendantsOfType<HTMLAnchorElement>(*this))
-            anchor.invalidateCachedVisitedLinkHash();
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Document::setBaseURLOverride(const URL& url)
</span></span></pre></div>
<a id="trunkSourceWebCoredomVisitedLinkStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/VisitedLinkState.cpp (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/VisitedLinkState.cpp    2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/dom/VisitedLinkState.cpp       2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> #include "Frame.h"
</span><span class="cx"> #include "HTMLAnchorElement.h"
</span><span class="cx"> #include "Page.h"
</span><ins>+#include "SVGAElement.h"
</ins><span class="cx"> #include "SVGNames.h"
</span><span class="cx"> #include "VisitedLinkStore.h"
</span><span class="cx"> #include "XLinkNames.h"
</span><span class="lines">@@ -44,12 +45,12 @@
</span><span class="cx"> inline static const AtomicString* linkAttribute(const Element& element)
</span><span class="cx"> {
</span><span class="cx">     if (!element.isLink())
</span><del>-        return 0;
</del><ins>+        return nullptr;
</ins><span class="cx">     if (element.isHTMLElement())
</span><span class="cx">         return &element.attributeWithoutSynchronization(HTMLNames::hrefAttr);
</span><span class="cx">     if (element.isSVGElement())
</span><span class="cx">         return &element.getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr);
</span><del>-    return 0;
</del><ins>+    return nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> VisitedLinkState::VisitedLinkState(Document& document)
</span><span class="lines">@@ -67,13 +68,13 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline static SharedStringHash linkHashForElement(Document& document, const Element& element)
</del><ins>+inline static Optional<SharedStringHash> linkHashForElement(const Element& element)
</ins><span class="cx"> {
</span><span class="cx">     if (is<HTMLAnchorElement>(element))
</span><span class="cx">         return downcast<HTMLAnchorElement>(element).visitedLinkHash();
</span><del>-    if (const AtomicString* attribute = linkAttribute(element))
-        return computeVisitedLinkHash(document.baseURL(), *attribute);
-    return 0;
</del><ins>+    if (is<SVGAElement>(element))
+        return downcast<SVGAElement>(element).visitedLinkHash();
+    return WTF::nullopt;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void VisitedLinkState::invalidateStyleForLink(SharedStringHash linkHash)
</span><span class="lines">@@ -81,7 +82,7 @@
</span><span class="cx">     if (!m_linksCheckedForVisitedState.contains(linkHash))
</span><span class="cx">         return;
</span><span class="cx">     for (auto& element : descendantsOfType<Element>(m_document)) {
</span><del>-        if (linkHashForElement(m_document, element) == linkHash)
</del><ins>+        if (element.isLink() && linkHashForElement(element) == linkHash)
</ins><span class="cx">             element.invalidateStyleForSubtree();
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -94,19 +95,17 @@
</span><span class="cx">     if (!attribute || attribute->isNull())
</span><span class="cx">         return InsideLink::NotInside;
</span><span class="cx"> 
</span><del>-    // 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 (attribute->isEmpty())
-        return InsideLink::InsideVisited;
</del><ins>+    auto hashIfFound = linkHashForElement(element);
</ins><span class="cx"> 
</span><del>-    SharedStringHash hash;
-    if (is<HTMLAnchorElement>(element))
-        hash = downcast<HTMLAnchorElement>(element).visitedLinkHash();
-    else
-        hash = computeVisitedLinkHash(element.document().baseURL(), *attribute);
</del><ins>+    if (!hashIfFound)
+        return attribute->isEmpty() ? InsideLink::InsideVisited : InsideLink::InsideUnvisited;
</ins><span class="cx"> 
</span><ins>+    auto hash = *hashIfFound;
+
+    // An empty href (hash==0) 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.
</ins><span class="cx">     if (!hash)
</span><del>-        return InsideLink::InsideUnvisited;
</del><ins>+        return InsideLink::InsideVisited;
</ins><span class="cx"> 
</span><span class="cx">     Frame* frame = element.document().frame();
</span><span class="cx">     if (!frame)
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLAnchorElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp  2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp     2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -68,7 +68,6 @@
</span><span class="cx">     : HTMLElement(tagName, document)
</span><span class="cx">     , m_hasRootEditableElementForSelectionOnMouseDown(false)
</span><span class="cx">     , m_wasShiftKeyDownOnMouseDown(false)
</span><del>-    , m_cachedVisitedLinkHash(0)
</del><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -248,7 +247,6 @@
</span><span class="cx">                     document().frame()->loader().client().prefetchDNS(document().completeURL(parsedURL).host().toString());
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-        invalidateCachedVisitedLinkHash();
</del><span class="cx">     } else if (name == nameAttr || name == titleAttr) {
</span><span class="cx">         // Do nothing.
</span><span class="cx">     } else if (name == relAttr) {
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLAnchorElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLAnchorElement.h (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLAnchorElement.h    2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.h       2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -66,7 +66,6 @@
</span><span class="cx">     bool hasRel(Relation) const;
</span><span class="cx">     
</span><span class="cx">     SharedStringHash visitedLinkHash() const;
</span><del>-    void invalidateCachedVisitedLinkHash() { m_cachedVisitedLinkHash = 0; }
</del><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT DOMTokenList& relList() const;
</span><span class="cx"> 
</span><span class="lines">@@ -115,16 +114,19 @@
</span><span class="cx">     bool m_hasRootEditableElementForSelectionOnMouseDown;
</span><span class="cx">     bool m_wasShiftKeyDownOnMouseDown;
</span><span class="cx">     OptionSet<Relation> m_linkRelations;
</span><del>-    mutable SharedStringHash m_cachedVisitedLinkHash;
</del><span class="cx"> 
</span><ins>+    // This is computed only once and must not be affected by subsequent URL changes.
+    mutable Optional<SharedStringHash> m_storedVisitedLinkHash;
+
</ins><span class="cx">     mutable std::unique_ptr<DOMTokenList> m_relList;
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline SharedStringHash HTMLAnchorElement::visitedLinkHash() const
</span><span class="cx"> {
</span><del>-    if (!m_cachedVisitedLinkHash)
-        m_cachedVisitedLinkHash = computeVisitedLinkHash(document().baseURL(), attributeWithoutSynchronization(HTMLNames::hrefAttr));
-    return m_cachedVisitedLinkHash; 
</del><ins>+    ASSERT(isLink());
+    if (!m_storedVisitedLinkHash)
+        m_storedVisitedLinkHash = computeVisitedLinkHash(document().baseURL(), attributeWithoutSynchronization(HTMLNames::hrefAttr));
+    return *m_storedVisitedLinkHash;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Functions shared with the other anchor elements (i.e., SVG).
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGAElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGAElement.cpp (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGAElement.cpp 2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/svg/SVGAElement.cpp    2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -217,4 +217,12 @@
</span><span class="cx">     return isLink() || SVGGraphicsElement::willRespondToMouseClickEvents(); 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+SharedStringHash SVGAElement::visitedLinkHash() const
+{
+    ASSERT(isLink());
+    if (!m_storedVisitedLinkHash)
+        m_storedVisitedLinkHash = computeVisitedLinkHash(document().baseURL(), getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr));
+    return *m_storedVisitedLinkHash;
+}
+
</ins><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGAElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGAElement.h (244641 => 244642)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGAElement.h   2019-04-25 07:52:36 UTC (rev 244641)
+++ trunk/Source/WebCore/svg/SVGAElement.h      2019-04-25 09:55:38 UTC (rev 244642)
</span><span class="lines">@@ -25,6 +25,7 @@
</span><span class="cx"> #include "SVGExternalResourcesRequired.h"
</span><span class="cx"> #include "SVGGraphicsElement.h"
</span><span class="cx"> #include "SVGURIReference.h"
</span><ins>+#include "SharedStringHash.h"
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -36,6 +37,8 @@
</span><span class="cx">     String target() const final { return m_target->currentValue(); }
</span><span class="cx">     Ref<SVGAnimatedString>& targetAnimated() { return m_target; }
</span><span class="cx"> 
</span><ins>+    SharedStringHash visitedLinkHash() const;
+
</ins><span class="cx"> private:
</span><span class="cx">     SVGAElement(const QualifiedName&, Document&);
</span><span class="cx"> 
</span><span class="lines">@@ -63,6 +66,9 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyRegistry m_propertyRegistry { *this };
</span><span class="cx">     Ref<SVGAnimatedString> m_target { SVGAnimatedString::create(this) };
</span><ins>+
+    // This is computed only once and must not be affected by subsequent URL changes.
+    mutable Optional<SharedStringHash> m_storedVisitedLinkHash;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre>
</div>
</div>

</body>
</html>